Interface BytecodeOSRNode
- All Superinterfaces:
NodeInterface
There are a few restrictions Bytecode OSR nodes must satisfy in order for OSR to work correctly:
- The node must extend
Nodeor a subclass ofNode. - The node must provide storage for the OSR metadata maintained by the runtime using an
instance field. The field must be
@CompilationFinal, and thegetOSRMetadata()andsetOSRMetadata(Object)methods must proxy accesses to it. - The node should call
pollOSRBackEdge(BytecodeOSRNode)andtryOSR(BytecodeOSRNode, int, Object, Runnable, VirtualFrame)as described by their documentation. - The node should implement either
executeOSR(VirtualFrame, int, Object)orexecuteOSR(VirtualFrame, long, Object)(see note below).
For performance reasons, the parent frame may be copied into a new frame used for OSR. If this
happens, copyIntoOSRFrame(VirtualFrame, VirtualFrame, int, Object) is
used to perform the copy, and restoreParentFrame(VirtualFrame, VirtualFrame) is used to copy the OSR
frame contents back into the parent frame after OSR. A node may override these methods; by
default, they perform slot-wise copies.
A node may also wish to override prepareOSR(int) to perform initialization.
This method will be called before compilation, and can be useful to avoid deoptimizing inside
compiled code.
Starting in 24.2, Bytecode OSR supports long values for target dispatch
locations. An interpreter can use long targets by invoking
tryOSR(BytecodeOSRNode, long, Object, Runnable, VirtualFrame) (instead of
tryOSR(BytecodeOSRNode, int, Object, Runnable, VirtualFrame)). Refer to the
documentation for the long overload for more details.
- Since:
- 21.3
-
Method Summary
Modifier and TypeMethodDescriptiondefault voidcopyIntoOSRFrame(VirtualFrame osrFrame, VirtualFrame parentFrame, int target, Object targetMetadata) Copies the contents of theparentFrameinto theosrFrameused to execute OSR.default voidcopyIntoOSRFrame(VirtualFrame osrFrame, VirtualFrame parentFrame, long target, Object targetMetadata) Overload ofcopyIntoOSRFrame(VirtualFrame, VirtualFrame, int, Object)with alongtarget.default ObjectexecuteOSR(VirtualFrame osrFrame, int target, Object interpreterState) Entrypoint to invoke this node through OSR.default ObjectexecuteOSR(VirtualFrame osrFrame, long target, Object interpreterState) Overload ofexecuteOSR(VirtualFrame, int, Object)with alongtarget.Gets the OSR metadata for this instance.static booleanpollOSRBackEdge(BytecodeOSRNode osrNode) Deprecated.static booleanpollOSRBackEdge(BytecodeOSRNode osrNode, int loopCountIncrement) Reports a back edge, returning whether to try performing OSR.default voidprepareOSR(int target) Initialization hook which will be invoked before OSR compilation.default voidprepareOSR(long target) Overload ofprepareOSR(int)with alongtarget.default voidrestoreParentFrame(VirtualFrame osrFrame, VirtualFrame parentFrame) Restores the contents of theosrFrameback into theparentFrameafter OSR.default FramerestoreParentFrameFromArguments(Object[] arguments) Return the parent frame that was stored in an arguments array by a previous call tostoreParentFrameInArguments(VirtualFrame).voidsetOSRMetadata(Object osrMetadata) Sets the OSR metadata for this instance.default Object[]storeParentFrameInArguments(VirtualFrame parentFrame) Produce the arguments that will be used to perform the call to the new OSR root.default voidtransferOSRFrame(VirtualFrame osrFrame, VirtualFrame parentFrame, long target, Object targetMetadata) Helper method that can be called by implementations ofcopyIntoOSRFrame(VirtualFrame, VirtualFrame, long, Object).static ObjecttryOSR(BytecodeOSRNode osrNode, int target, Object interpreterState, Runnable beforeTransfer, VirtualFrame parentFrame) Tries to perform OSR.static ObjecttryOSR(BytecodeOSRNode osrNode, long target, Object interpreterState, Runnable beforeTransfer, VirtualFrame parentFrame) Overload oftryOSR(BytecodeOSRNode, int, Object, Runnable, VirtualFrame)with alongtarget.
-
Method Details
-
executeOSR
Entrypoint to invoke this node through OSR. Implementers must override this method (or itslong overload). The implementation should execute bytecode starting from the giventargetlocation (e.g., bytecode index).The
osrFramemay be the parent frame, but for performance reasons could also be a new frame. In case a new frame is created, the frame'sargumentswill be provided bystoreParentFrameInArguments(VirtualFrame).Typically, a bytecode node's
execute(VirtualFrame)method already contains a dispatch loop. This loop can be extracted into a separate method which can also be used by this method. For example:Object execute(VirtualFrame frame) { return dispatchFromBCI(frame, 0); } Object executeOSR(VirtualFrame osrFrame, int target, Object interpreterState) { return dispatchFromBCI(osrFrame, target); } Object dispatchFromBCI(VirtualFrame frame, int bci) { // main dispatch loop while(true) { switch(instructions[bci]) { ... } } }- Parameters:
osrFrame- the frame to use for OSR.target- the target location to execute from (e.g., bytecode index).interpreterState- other interpreter state used to resume execution. SeetryOSR(BytecodeOSRNode, int, Object, Runnable, VirtualFrame)for more details.- Returns:
- the result of execution.
- Since:
- 21.3
- See Also:
-
executeOSR
Overload ofexecuteOSR(VirtualFrame, int, Object)with alongtarget. An interpreter that useslongtargets must override this method.- Since:
- 24.2
- See Also:
-
getOSRMetadata
Object getOSRMetadata()Gets the OSR metadata for this instance.The metadata must be stored on a
@CompilationFinalinstance field. Refer to the documentation for this interface for a more complete description.- Returns:
- the OSR metadata.
- Since:
- 21.3
-
setOSRMetadata
Sets the OSR metadata for this instance.The metadata must be stored on a
@CompilationFinalinstance field. Refer to the documentation for this interface for a more complete description.- Parameters:
osrMetadata- the OSR metadata.- Since:
- 21.3
-
copyIntoOSRFrame
default void copyIntoOSRFrame(VirtualFrame osrFrame, VirtualFrame parentFrame, int target, Object targetMetadata) Copies the contents of theparentFrameinto theosrFrameused to execute OSR. By default, performs a slot-wise copy of the frame.NOTE: This method is only used if the Truffle runtime decides to copy the frame. OSR may also reuse the parent frame directly.
- Parameters:
osrFrame- the frame to use for OSR.parentFrame- the frame used before performing OSR.target- the target location OSR will execute from (e.g., bytecode index).targetMetadata- Additional metadata associated with thistargetfor the default frame transfer behavior.- Since:
- 22.2
- See Also:
-
copyIntoOSRFrame
default void copyIntoOSRFrame(VirtualFrame osrFrame, VirtualFrame parentFrame, long target, Object targetMetadata) Overload ofcopyIntoOSRFrame(VirtualFrame, VirtualFrame, int, Object)with alongtarget. An interpreter that useslongtargets must override this method.- Since:
- 24.2
- See Also:
-
transferOSRFrame
default void transferOSRFrame(VirtualFrame osrFrame, VirtualFrame parentFrame, long target, Object targetMetadata) Helper method that can be called by implementations ofcopyIntoOSRFrame(VirtualFrame, VirtualFrame, long, Object). Should not be overridden.- Since:
- 24.2
- See Also:
-
restoreParentFrame
Restores the contents of theosrFrameback into theparentFrameafter OSR. By default, performs a slot-wise copy of the frame.Though a bytecode interpreter might not explicitly use
parentFrameafter OSR, it is necessary to restore the state intoparentFrameif it may be accessed through instrumentation.NOTE: This method is only used if the Truffle runtime decided to copy the frame using
copyIntoOSRFrame(VirtualFrame, VirtualFrame, int, Object).- Parameters:
osrFrame- the frame which was used for OSR.parentFrame- the frame which will be used by the parent after returning from OSR.- Since:
- 21.3
-
prepareOSR
default void prepareOSR(int target) Initialization hook which will be invoked before OSR compilation. This hook can be used to perform any necessary initialization before compilation happens.For example, consider a field which must be initialized in the interpreter:
@CompilationFinal Object field; Object getField() { if (field == null) { CompilerDirectives.transferToInterpreterAndInvalidate(); field = new Object(); } return field; }If the field is accessed from compiled OSR code, it may trigger a deoptimization in order to initialize the field. Using
prepareOSR(int)to initialize the field can prevent this.- Parameters:
target- the target location OSR will execute from (e.g., bytecode index).- Since:
- 21.3
- See Also:
-
prepareOSR
default void prepareOSR(long target) Overload ofprepareOSR(int)with alongtarget. An interpreter that useslongtargets must override this method.- Since:
- 24.2
- See Also:
-
pollOSRBackEdge
Deprecated.usepollOSRBackEdge(BytecodeOSRNode, int)instead. It is recommended to batch up polls in the interpreter implementation. Important note:pollOSRBackEdge(BytecodeOSRNode)did implicitlypollTruffle safepoints. The new method is no longer doing that. Make sure your bytecode interpreter contains a call toTruffleSafepoint.poll(Node)on loop back-edges when migrating.Reports a back edge, returning whether to try performing OSR.An interpreter must ensure this method returns
trueimmediately before callingtryOSR(BytecodeOSRNode, int, Object, Runnable, VirtualFrame). For example:if (BytecodeOSRNode.pollOSRBackEdge(this)) { Object osrResult = BytecodeOSRNode.tryOSR(...); ... }- Parameters:
osrNode- the node to report a back-edge for.- Returns:
- whether to try OSR.
- Since:
- 21.3
-
pollOSRBackEdge
Reports a back edge, returning whether to try performing OSR.An interpreter must ensure this method returns
trueimmediately before callingtryOSR(BytecodeOSRNode, int, Object, Runnable, VirtualFrame). For example:if (BytecodeOSRNode.pollOSRBackEdge(this, 1)) { Object osrResult = BytecodeOSRNode.tryOSR(...); ... }- Parameters:
osrNode- the node to report a back-edge for.loopCountIncrement- the number iterations incremented. Value must be > 0.- Returns:
- whether to try OSR.
- Since:
- 25.0
-
tryOSR
static Object tryOSR(BytecodeOSRNode osrNode, int target, Object interpreterState, Runnable beforeTransfer, VirtualFrame parentFrame) Tries to perform OSR. This method must only be called immediately after atrueresult frompollOSRBackEdge(BytecodeOSRNode).Depending on the Truffle runtime, this method can trigger OSR compilation and then (typically in a subsequent call) transfer to OSR code. If OSR occurs, this method returns the result of OSR execution. The caller of this method can forward the result back to its caller rather than continuing execution from the
target. For example:if (BytecodeOSRNode.pollOSRBackEdge(this)) { Object osrResult = BytecodeOSRNode.tryOSR(...); if (osrResult != null) return osrResult; }The optional
interpreterStateparameter will be forwarded toexecuteOSR(VirtualFrame, int, Object)when OSR is performed. It should consist of additional interpreter state (e.g., data pointers) needed to resume execution fromtarget. The state should be fixed (i.e., final) for the giventarget. For example:// class definition class InterpreterState { final int dataPtr; InterpreterState(int dataPtr) { ... } } // call site Object osrResult = BytecodeOSRNode.tryOSR(this, target, new InterpreterState(dataPtr), ...); // executeOSR Object executeOSR(VirtualFrame osrFrame, int target, Object interpreterState) { InterpreterState state = (InterpreterState) interpreterState; return dispatchFromBCI(osrFrame, target, interpreterState.dataPtr); }The optional
beforeTransfercallback will be called before transferring control to the OSR target. Since this method may or may not perform a transfer, it is a way to ensure certain actions (e.g., instrumentation events) occur before transferring to OSR code. For example:// call site Object osrResult = BytecodeNode.tryOSR(this, target, ..., () -> { instrument.notify(current, target); });- Parameters:
osrNode- the node to try OSR for.target- the target location OSR will execute from (e.g., bytecode index).interpreterState- other interpreter state used to resume execution.beforeTransfer- a callback invoked before OSR. Can benull.parentFrame- frame at the current point of execution.- Returns:
- the result if OSR was performed, or
nullotherwise. - Since:
- 21.3
- See Also:
-
tryOSR
static Object tryOSR(BytecodeOSRNode osrNode, long target, Object interpreterState, Runnable beforeTransfer, VirtualFrame parentFrame) Overload oftryOSR(BytecodeOSRNode, int, Object, Runnable, VirtualFrame)with alongtarget. An interpreter that useslongtargets should call this method.If an interpreter uses a
longrepresentation, it must override the hooks that definelongoverloads, namelyexecuteOSR(VirtualFrame, long, Object),copyIntoOSRFrame(VirtualFrame, VirtualFrame, long, Object), andprepareOSR(long). Overriding is necessary because the defaultlongoverloads call theirintoverloads for backwards compatibility, and these calls will fail forlong-sized targets.- Since:
- 24.2
- See Also:
-
storeParentFrameInArguments
Produce the arguments that will be used to perform the call to the new OSR root. It will become the arguments array of the frame passed intoexecuteOSR(VirtualFrame, int, Object)in case a new frame is generated for the call for performance reasons. The contents are up to language, Truffle only requires that a subsequent call torestoreParentFrame(VirtualFrame, VirtualFrame)with the arguments array will return the same object as was passed into theparentFrameargument. By default, this method creates a new one-element array, which discards the original frame arguments. Override this method to be able to preserve a subset of the original frame arguments. It is permitted to modify arguments array ofparentFrameand return it. This is called only in the interpreter, therefore the frame is not virtual and it is safe to store it into the arguments array.- Parameters:
parentFrame- the frame object to be stored in the resulting arguments array- Returns:
- arguments array containing
parentFrame - Since:
- 22.2
-
restoreParentFrameFromArguments
Return the parent frame that was stored in an arguments array by a previous call tostoreParentFrameInArguments(VirtualFrame).- Parameters:
arguments- frame arguments originally produced bystoreParentFrameInArguments(VirtualFrame).- Returns:
- stored parent frame
- Since:
- 22.2
-
pollOSRBackEdge(BytecodeOSRNode, int)instead.