Interpreting intermediate code allows the same program to run on different computer systems, but every executed instruction incurs the overhead of the interpreter loop. In this thesis, we developed a simple just-in-time compiler for the stack-based Pins25 virtual machine. The existing Pins25 compiler and virtual machine are implemented in Java. We extended the compiler to store intermediate code and data in a binary object file, and implemented a loader, interpreter, profiling infrastructure, and runtime support for generated machine code in C. On every function call, the runtime records the call count and, during function execution, the number of backward jumps. When either counter reaches a selected threshold, the runtime analyses the function and directly translates its instructions into x86-64 machine code. Interpreted and compiled functions share the same memory, stack, and call-frame representation, allowing arbitrary and recursive calls between both execution modes. The prototype supports the complete Pins25 instruction set. The evaluation shows that just-in-time compilation primarily benefits longer-running programs, whereas for short programs the profiling and compilation overhead largely offsets the resulting speedup. Performance also depends on call patterns, control flow, and transitions into the runtime.
|