Check out the new USENIX Web site. next up previous
Next: Threading and Synchronization Up: System Components and Implementation Previous: Java Call Stack

   
Bytecode Interpretation

The ExecutionEngine decodes the bytecode and performs the actions necessary to implement each instruction. Its interface is quite simple, consisting of a single function that takes a Context as an argument, and executes the method whose frame is on top of the Context's call stack.

Since Jupiter's design delegates much of the execution responsibility to other parts of the system, not much remains to be done by the ExecutionEngine itself. The current interpreter implementation divides the functionality into three modules, which are shown along with the ExecutionEngine interface in Figure 10. These modules are each responsible for implementing a portion of the ExecutionEngine functionality:

 


  
Figure 10: The bytecode execution modules.
\includegraphics[scale=0.8]{execution-modules.ps}

The current ExecutionEngine implementation is a threaded interpreter, meaning that, after executing one opcode, it branches directly to the code for executing the next opcode [7]. This stands in contrast to the typical scheme, which uses a switch statement inside a loop to jump to the appropriate code. The threaded scheme eliminates the branch to the top of the loop, whose overhead can be substantial in an optimized interpreter like Jupiter's, as will be shown in Section 4.2. The current ExecutionEngine also does bytecode substitution to improve the performance of getfield, putfield, invokevirtual by dynamically replacing them with faster versions, as will be described in Section 4.2.


next up previous
Next: Threading and Synchronization Up: System Components and Implementation Previous: Java Call Stack
Tarek S. Abdelrahman
2002-05-27