So today will be splitting the code generation portion of the JIT and binary output portion of the JIT into two separated parts.
So what could be done is that
ExecutableOutput can be modified to work in
this new fashion, it would have an ELF output for UNIX-like systems. I can
also do a kind of prelinking step for example. So I can make the core
SquirrelJME binary as static as possible. If everything is prelinked and
ready to go, the only thing that would be needed is to load or access that
portion in memory.
Ok so, JITConfig could really go into the base of the JIT. The only thing that
would have to be removed from it is the cache of
JITOutputFactory but the
way the code is, that would be a simple task.
So my goal would be so that the executable output is handled by the JIT
itself. This means jit depends on exe (where exe depends on jit-base).
The EXE would be given the
JITConfig so it knows how to work with it. There
would be factories for specific formats. So the config would get the factory
class which the JIT will use as a binary container. Then the existing basic
code generating work will be spliced off. So
jit-basic does not care much
about the layout of namespaces or the constant pool, it will just handle the
native code portion. Then this way, the actual code generator code will be
far simpler with namespaces split off. It would more easily be reused.
I should rename
ExecutableOutput so I can claim its class name.
So this means that for the namespace processor, it will need an executable output. There would have to be two kinds of things, a major output namespace and a minor one. The major one would construct the executable early while the minor one would create it later. This way it can output all namespaces to a single binary or multiple ones, depending on the situation.
Ok, so I thought about it. I will not do it at the jit level but at the level of jit-basic. If I have a language target then it would be a bit pointless to have an executable ouput. So for traditional CPU targets jit-basic handles it.
Also thought about merging
JITNamespaceProcessor since it would
make much more sense there for the most part.
Since I plan for shared executables,
JITOutput can now be closed along with
the namespace processor. This way any final things can be managed as needed.
I would say that
JITNamespaceBrowser loses output and it is instead placed
in another interface.
Actually since I made a new class called
JITNamespaceOutputSingle I can
remove the key for shared output and imply it based on the namespace
Since I am going to output the distribution ZIP directly, I actually need to use a temporary output ZIP file, which I then move over.
So in reality I do not even need an executable or a linking step if it not needed for the native target. So this in general makes it much better than before.
Actually, I could keep
ELFOutput since I already have all of it. I can
undeprecate it then move the JIT part of it to
Well actually, the executable output system is tied to the JIT for the most part. So for simplicity, I will just move the bulk of the code over. However for ELFs I will need three sections for the most part which would be referenced in memory. I would guess that the output support internal relocations where pointers are set on write for the most part. But the major thing I need to do is reorganization of the code generation. I still do have to handle the call stack management however.
The initial things that would need to be modified would be mostly the
BasicNamespaceWriter. If the executable output can handle multiple streams
then I can have data and other such things in their own self contained
So the generic executable output interface would have the ability to create new output sections regardless of the output type. Then one thing I should do for the ELF code is decouple the part used by the JIT and the underlying ELF code. This way, the sections and such can more freely changed without being tied to a single class. The structures and such would mostly be the same for the most part and the executable output wrapper would handle such things. Then when it comes to machine code generation, it will write to another stream but be mostly based on the native code writer. However they both would be standalone so that there would be no intermixing of them. So the code description stream should purely operate for the most part via the native code writer. One consideration I have been thinking of is call stack setup. I am very much thinking of preallocated variable slot data. However that could potentially waste space. So I suppose what can be done for the code writer output would be the ability to have future data be able to be set. Then the code writer can eventually be output to a byte array or some type of stream. If I allow this rather than having a direct code output then I can allocate on the stack as I need from the base of it or similar (perhaps via the frame pointer). This future referencing of data would reduce some of the complexity required during code generation. So then this way, all management of the stack is seemingly static in the output code. For the most part generated methods would be small in size, so the instructions for the entire method would not have a high cost on memory usage.