User:Kvijayan/IonMonkey/OnStackInvalidation
Overview
On-Stack invalidation in IonMonkey is the mechanism by which the following situation is handled:
- Ion JITcode is entered.
- The JITcode calls a C++ function
- The C++ code does something that causes the Ion JITcode to become invalid.
- The C++ code returns to an invalid JITcode return address.
When the C++ code returns to the JITcode, it cannot continue executing as normal. It must immediately jump to a handler that bails out from the JITcode and returns execution to the C++ code that called the JITcode.
To handle this, whenever Ion JITcode calls out to C++ code, it reserves some space after the point in the JITcode where the call is made. When an IonScript is invalidated while active (i.e. it's on the stack), the patch address corresponding to the current active return address must be calculated, and it must be patched to jump to an invalidation epilogue to perform the bailout.
The invalidation epilogue needs to have access to the register state at the time of the invalidation, as well as a Snapshot describing which registers and stack locations corresponding to which values in the virtual interpreter stack. It then uses this information to re-create the proper javascript interpreter frames corresponding to the point in the jitcode where the on-stack invalidation was entered.
The following documents the major touchpoints in the code which implement the behaviour necessary to do this.
Invalidating an IonScript
When any IonScript (active or not) is invalidated from within C++ code, it has setInvalidated() (ion/IonCode.h) called on it, and one of the ion::Invalidate (ion/Ion.cpp) handlers gets called with the CompilerOutputs corresponding to one or more such IonScripts.
This function then iterates through all current IonActivations (active Ion-compiled JITcode on the callstack), and calls ion::InvalidateActivation (ion/Ion.cpp) for each activation.
InvalidateActivation
ion::InvalidateActivation iterates through each IonFrame within the activation. Every ion frame contains a CalleeToken that identifies either the script or the function corresponding to that Ion frame.
This token is used to retreive the JSScript corresponding to the frame, and the JSScript's corresponding IonScript is retreived and checked to see if it's been marked invalidated. If so, the script's active return point needs to be patched to jump to the invalidation epilogue.
Every call that can lead to an OSI is associated with a Safepoint (created at compile time). This safepoint is indexed to the return address of the specific call that it corresponds to. This return address is available as the address returned to by the callee frame of the active invalidated ion frame.
The return address is used to lookup the SafepointIndex for the call from the IonScript. The safepoint index contains the location in the code that needs to be patched.
This location is retrieved, and patched with a jump to the IonScript's invalidateEpilogue code.
That covers the actions necessary when an IonScript gets invalidated.
InvalidateEpilogue
Once the C++ code that caused the invalidation finishes execution and returns to Ion JITcode, it will immediately jump to the invalidateEpilogue. This epilogue needs to figure out the stack layout, re-create the proper JS interpreter stack corresponding to the JITcode, and enter the interpreter at that location.