Shu-yu Guo

Making SpiderMonkey’s Debugger Just-in-Time

Previously, I recounted the manner in which frame surgery of on-stack frames is performed in SpiderMonkey to support turning on the Debugger with live frames. In the current post, I will describe how the Debugger API was made faster with that capability. The technical details of the debug mode on-stack replacement are not prerequisite for our current exposition, which I hope is simple and intuitive, but should you, dear reader, wish to reacquaint yourself with the details of our methodology, please follow the link above. Most of the implementation described below occurred in bug 1032869.

Debugger Hooks & Observability

The Debugger makes all aspects of JS execution observable by way of a set of hooks which may be assigned with user-defined callbacks. The execution-observing hooks and the observability requirements they admit are described below. Execution observability is a property of frames, though I abuse language below and refer to scripts as observable as well. An observable script is a script that always pushes observable frames.

Just-in-Time Debugging

For the hooks enumerated above to fire, instrumentation code must be inserted in JIT code to invoke them. Recall that SpiderMonkey is 3-tiered: interpreter, Baseline, Ion, in order of speed of compiled code. Code running in the interpreter and Baseline may be debugged, and code running in Ion must be made to bail out into Baseline to be debugged. Before the current state of affairs, entire globals are marked as being in “debug mode”, which prohibited Ion execution and caused all Baseline code compiled to be compiled with instrumentation.

What on-stack replacement of debuggee JS frames enables is, in a happy extension of the just-in-time philosophy, to delay the insertion of such instrumentation until the last moment, and to only insert them into the scripts that need them. That is, to delay the invalidation of scripts’ Ion code (discarding their Ion code as well as their inliners’ Ion code) and the recompilation of instrumentation-laden Baseline code until the last moment. Scripts may then execute free of instrumentation in Baseline and Ion until a Debugger hook needs to be fired.

For each hook above, the when and how of ensuring their observability requirements are thus made surgical:

Conclusion

Debugger is faster.