It would probably be best to split off the string table from the constant pool.
The pool should probably become a visible map of sorts, potentially. I can use the sorted tree classes I made, although all of the indices will be off.
The generic JIT is getting a bit unweildy. I believe it needs to be split off a bit. One thing I would split off is the machine code related stuff, things which are used by the compiler such as logic generators and register allocation. Then after that, what is left is the result of the standard JIT, that is anything layered on top of that. However, one consideration is that the standard JIT can use the same base machine code generators also. Although I would still have to decide on that. If however, they do use the same interfaces then there could be a simpler bridging of output logic although it would not have register allocation and it would basically be providing a byte code representation of the program.
Another thing I can do is merge together some of the generic and JIT pool related stuff. Perhaps remove the representation of the constant pool entirely so to speak.
For the most part, the native code pieces can be reused by every implementation of the JIT for the most part. One thing I can have though is that the register allocator could potentially be replaced rather than using the default. This could be used when a slightly difference scheme is desired. If I can remove the bulk of the native code generated stuff from the generic JIT then that package would be much lighter. The generic JIT just has to pass information for the most part to the native code generators. Then the native code generators could be used in the future to generate bootstrap code such as if I need to have some kind of raw initialization process.
Then another plan would be a merging of the constant system, right now there are some constant pool entries that are generic only that could be useful in the JIT, these would be the call types and such. One thing I can do is to remove the constant pool from the JIT and make it completely hidden. In most cases the pool could become a burden as at least in the case of the generic JIT, most of the pool would go unused. The generic JIT also virtualizes all of the entries also. Also the base JIT code has an inclusion system so that entries are marked as being used. Since I am doing that, it would be best to just completely remove passing the pool and let the JIT implementation handle such things.
So right now I have:
- Move native code off to its own stand-alone project.
- Hide the constant pool from the JIT interfaces and have a unified simple constant system.
So what I could do as I thought of before is that I could move the program
representation around also. Then this could be reused by code such as a
hypothetical interpreter or
javap. The JIT interfaces can then take this
information and pass it to the JIT implementation. So that project would
contain just a class representation that can be piped into the JIT for usage.
So the end result of all of this should be much smaller and simpler JITs along with reusable native code generators and class representations. I would suppose that the hiding of the constant pool can be done by the class representation code. And that representation code can use directly the stack and local variables also. Then the JIT would handle stack caching so that it is not in that representation code. Then once the JIT caches stack items and such it will send that to the implementing JIT. The implementing JIT then generates native code via the native code generator classes. Then this means that the base JIT will get all of the stack and pool entry representations moved out making it far simpler.
Then I can move forward with implementing the JIT and I would then be less likely to step over anything, since the current rather large set of classes can be difficult to navigate especially when they will only increase in size.
- Anything that represents the class file format goes here.
- Make class streamers the JIT can use.
- Hide the constant pool.
- Merge pool entries
- Move any register stuff and other interfaces related to target code generation.
And some notes:
- Keep a simplified and merged pool, hide the details of it and use only what is used.
- Does not handle stack caching.
- Performs stack caching then passes that to JIT implementations.
- Anything related to native code generate goes here.
It may be possible to even remove
So the Java stuff needs to be removed from the native allocator and placed in the JIT.
What the native code allocator needs is a kind of state that can be used. It either specifies that a register is used or some stack space was allocated. I can then move the Java allocation state to use these markers. This would be more effective than keeping variable states somewhere and using raw register or stack values. Then the allocator state can be what is currently allocated. The allocations should be immutable so they can be shared with the state, otherwise it can get a bit messy.
Going to need a
native-code-base which is dependend on by
the floating point type is moved there. Then also with this native code being
split off, the allocator could handle cases where registers are 8-bit. So in
a way, in the future, it can help me when I write the small target JIT if the
current JIT does not become a part of it.
One thing I need to adjust is how the generic JIT allocates variables. I
believe I should follow a similar route and have it be based on allocations.
That is instead of register and stack it is just
Currently stuck on moving the generic stuff over, I suppose what I should do
then is move over the MIPS/PowerPC stuff such as ABIs and other things to the
native-code roots. Then from there I can work out how I want to access the
stuff from the generic JIT.
This means that the generic JIT becomes essentially final and provides the service itself.
So the only thing I have to in the generic JIT code for this move is to make
the initial argument allocation with argument priming. However this should be
easy as I can have an input argument request that fills parts of the state. So
some of the generic code moves back and it becomes just a wrapped
NativeAllocation which is bound to the general allocator state.
So the moving of the native code generator is partly complete as my code now compiles, I just need to reimplement that behavior now.
The generic output needs a factory that can create native compilers as needed when methods are to be output.
I will need another tread for locals to store copied stack values since the native allocator will not allow values to be duplicated, only spliced in registers and stack. I can continue the reimplementation of the register allocator code in the future. Now one thing I need to do is move the class format decoding code into its own project and out of the JIT. Basically it would operate as a kind of class reader where the constant pool is hidden away.
This means the class decode is rid of the JIT details.
And that is a good thing since it makes the class decoder code much simpler as the decoder no longer has to juggle JIT details at all.
The stack map parser state needs a partial and then a locked state. One thing
to consider though is that the information could be hidden again. I may want to
go for it being hidden as before. Except for
The operation parsing part of the class decoder is a bit ugly. However now that that code compiled, I must now rework the JIT itself. Then after the JIT is reworked I would then go into the generic JIT code again and refix that due to the changes. However, the benefit now is that I can refactor the class parsing code also. The class parsing code as I said is ugly and I will want to rework that a bit, especially the operation decoding part. However the description streams will allow me to easily refactor without changing much. One intended goal that I have is to make the stack and local references a bit more stable. That is, the Class code will give me what I need. However, the Class prefix before the class format code is quite annoying and I should remove that before I continue on to the JIT.
So now all my code compiles again. I spent the entire day refactoring. However, my refactor is not yet complete. I must reimplement the code I removed and perform a refactor of the class parsing code, especially the operation handlers.
Seems that this split off code will work rather nice. Although the class writer bridge will be very empty, it would definitely be a bit more clean compared to the old code.
The class writers for the JIT does not need the pool index numbers.
So today, I got much work done. Now I shall go to sleep since I am rather tired. Tomorrow I will work on reimplementing the removed parts of the code so that I get back to where I was. Then I suppose I will refactor the byte code handling so it is a much cleaner. Then after that, hopefully I can then get to emitting actual instructions and such.