Some comments about your JIT compiler (hope I don't write things "delnan" already wrote):
General comments
I am sure that the "real" JIT compilers work similarly to yours. However, you can do some optimization (for example: "mov eax, nnn" and "push eax" can be replaced with "push nnn").
You must store local variables on the stack; usually "ebp" is used as a local pointer:
push ebx push ebp sub esp, 8 // 2 variables with 4 bytes each mov ebp, esp // Now local variables are addressed using [ebp+0] and [ebp+4] ... pop ebp pop ebx ret
This is necessary because functions can be recursive. Storing a variable in a fixed location (relative to EIP) will cause the variables to behave as βstaticβ. (I assume that you will not compile the function several times in the case of a recursive function.)
Try / Catch
To implement Try / Catch, your JIT compiler must not only look at Java Bytecode, but also at Try / Catch information, which is stored in a separate attribute in the Java class. Try / catch can be implemented as follows:
// push all useful registers (= the ones, that must not be destroyed) push eax push ebp ... // push the "catch" pointers push dword ptr catch_pointer push dword ptr catch_stack // set the "catch" pointers mov catch_stack,esp mov dword ptr catch_pointer, my_catch ... // some code // Here some "throw" instruction... push exception jmp dword ptr catch_pointer ... //some code // End of the "try" section: Pop all registers pop dword_ptr catch_stack ... pop eax ... // The "catch" block my_catch: pop ecx // pop the Exception from the stack mov esp, catch_stack // restore the stack // Now restore all registers (same as at the end of the "try" section) pop dword_ptr catch_stack ... pop eax push ecx // push the Exception to the stack
In a multi-threaded environment, each thread requires its own variable catch_stack and catch_pointer!
Specific exception types can be handled with "instanceof" as follows:
try { // some code } catch(MyException1 ex) { // code 1 } catch(MyException2 ex) { // code 2 }
... actually compiled as follows:
try { // some code } catch(Throwable ex) { if(ex instanceof MyException1) { // code 1 } else if(ex instanceof MyException2) { // code 2 } else throw(ex); // not handled! }
The objects
The JIT compiler of a simplified Java virtual machine that does not support objects (and arrays) will be quite simple, but objects in Java make the virtual machine very complex.
Objects are simply stored as pointers to an object on the stack or in local variables. Typically, JIT compilers will be implemented as follows: for each class, there is a piece of memory that contains information about the class (for example, what methods exist and with what address the assembler code of the method is located, etc.). An object is a piece of memory containing all the instance variables and a pointer to a memory containing information about the class.
"Instanceof" and "checkcast" can be implemented by looking at a pointer to a memory containing class information. This information may contain a list of all parent classes and implemented interfaces.
The main problem with objects is memory management in Java: unlike C ++, there is a βnewβ, but no. You should check how often the object is used. If the object is no longer in use, it must be deleted from memory and the destructor must be called.
The problems here are local variables (the same local variable may contain an object or number) and try / catch blocks (the catch block must take care of local variables and the stack (!) Containing objects before restoring the stack pointer).