For most programming tasks we do not need to understand the execution of a program at the bytecode level. However, when building tools like compilers looking at the execution of a piece of code at the bytecode level is a must.
While the debugger allows us to control the execution of a program, the default debugger from Pharo shows the execution of a program at the level of its textual representation. This is of little use when what we care about are individual bytecode instructions.
To improve this we created using the Moldable Debugger framework a debugger that allows us to interact with the execution of a program at the bytecode level:
Instead of textual source code this debugger shows by default the bytecodes of the currently executing method. It further provides actions for stepping into bytecodes representing message sends, stepping over individual bytecodes and stepping to a selected bytecode.
The debugger further shows the stack of temporary variables for the selected stack frame (method activation). In the previous screenshot the stack contains six temporary variables: three method parameters, one local variable and two intermediary values needed by the following instructions.
Apart from temporary variables the debugger also show object attributes labeled with the index used to access them in the bytecodes and local parameters declared but not active in the current stack frame:
While it still can be improved this debugger took just 200 lines of code to create, on top of what’s already available in Pharo for inspecting bytecodes. With the right infrastructure in place creating custom debugger can actually become an affordable activity.
This debugger is available in the latest Moose image (from the stack toolbar menu of the default debugger select ‘Available Debuggers’->’Bytecode Debugger’). For more information about what makes this possible visit the Glamorous Toolkit page.