public interface BytecodeOSRNode extends NodeInterface
Node or a subclass of Node.@CompilationFinal, and the
BytecodeOSRNode.getOSRMetadata() and BytecodeOSRNode.setOSRMetadata(java.lang.Object) methods must
proxy accesses to it.BytecodeOSRNode.pollOSRBackEdge(com.oracle.truffle.api.nodes.BytecodeOSRNode) and
BytecodeOSRNode.tryOSR(com.oracle.truffle.api.nodes.BytecodeOSRNode, int, java.lang.Object, java.lang.Runnable, com.oracle.truffle.api.frame.VirtualFrame) as described by their documentation.
For performance reasons, the parent frame may be copied into a new frame used for OSR. If this
happens, BytecodeOSRNode.copyIntoOSRFrame(com.oracle.truffle.api.frame.VirtualFrame, com.oracle.truffle.api.frame.VirtualFrame, int) is used to perform the copy, and
BytecodeOSRNode.restoreParentFrame(com.oracle.truffle.api.frame.VirtualFrame, com.oracle.truffle.api.frame.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 BytecodeOSRNode.prepareOSR(int) to perform initialization.
This method will be called before compilation, and can be useful to avoid deoptimizing inside
compiled code.
| Modifier and Type | Method and Description |
|---|---|
default void |
copyIntoOSRFrame(VirtualFrame osrFrame,
VirtualFrame parentFrame,
int target)
Copies the contents of the
parentFrame into the osrFrame used to execute OSR. |
Object |
executeOSR(VirtualFrame osrFrame,
int target,
Object interpreterState)
Entrypoint to invoke this node through OSR.
|
Object |
getOSRMetadata()
Gets the OSR metadata for this instance.
|
static boolean |
pollOSRBackEdge(BytecodeOSRNode osrNode)
Reports a back edge, returning whether to try performing OSR.
|
default void |
prepareOSR(int target)
Initialization hook which will be invoked before OSR compilation.
|
default void |
restoreParentFrame(VirtualFrame osrFrame,
VirtualFrame parentFrame)
Restores the contents of the
osrFrame back into the parentFrame after OSR. |
void |
setOSRMetadata(Object osrMetadata)
Sets the OSR metadata for this instance.
|
static Object |
tryOSR(BytecodeOSRNode osrNode,
int target,
Object interpreterState,
Runnable beforeTransfer,
VirtualFrame parentFrame)
Tries to perform OSR.
|
Object executeOSR(VirtualFrame osrFrame, int target, Object interpreterState)
target location.
The osrFrame may be the parent frame, but for performance reasons could also be a new
frame. The frame's arguments are undefined and should not be
used directly.
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]) {
...
}
}
}
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. See
BytecodeOSRNode.tryOSR(com.oracle.truffle.api.nodes.BytecodeOSRNode, int, java.lang.Object, java.lang.Runnable, com.oracle.truffle.api.frame.VirtualFrame) for more details.Object getOSRMetadata()
@CompilationFinal instance
field. Refer to the documentation for this interface for a more complete description.void setOSRMetadata(Object osrMetadata)
@CompilationFinal instance
field. Refer to the documentation for this interface for a more complete description.osrMetadata - the OSR metadata.default void copyIntoOSRFrame(VirtualFrame osrFrame, VirtualFrame parentFrame, int target)
parentFrame into the osrFrame used 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.
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).default void restoreParentFrame(VirtualFrame osrFrame, VirtualFrame parentFrame)
osrFrame back into the parentFrame after OSR. By
default, performs a slot-wise copy of the frame.
Though a bytecode interpreter might not explicitly use parentFrame after OSR, it is
necessary to restore the state into parentFrame if it may be accessed through
instrumentation.
NOTE: This method is only used if the Truffle runtime decided to copy the frame using
BytecodeOSRNode.copyIntoOSRFrame(com.oracle.truffle.api.frame.VirtualFrame, com.oracle.truffle.api.frame.VirtualFrame, int).
osrFrame - the frame which was used for OSR.parentFrame - the frame which will be used by the parent after returning from OSR.default void prepareOSR(int target)
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 BytecodeOSRNode.prepareOSR(int) to initialize the field can
prevent this.target - the target location OSR will execute from (e.g., bytecode index).static boolean pollOSRBackEdge(BytecodeOSRNode osrNode)
An interpreter must ensure this method returns true immediately before calling
BytecodeOSRNode.tryOSR(com.oracle.truffle.api.nodes.BytecodeOSRNode, int, java.lang.Object, java.lang.Runnable, com.oracle.truffle.api.frame.VirtualFrame). For example:
if (BytecodeOSRNode.pollOSRBackEdge(this)) {
Object osrResult = BytecodeOSRNode.tryOSR(...);
...
}
osrNode - the node to report a back-edge for.static Object tryOSR(BytecodeOSRNode osrNode, int target, Object interpreterState, Runnable beforeTransfer, VirtualFrame parentFrame)
true result
from BytecodeOSRNode.pollOSRBackEdge(com.oracle.truffle.api.nodes.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 interpreterState parameter will be forwarded to
BytecodeOSRNode.executeOSR(com.oracle.truffle.api.frame.VirtualFrame, int, java.lang.Object) when OSR is performed. It should consist of additional
interpreter state (e.g., data pointers) needed to resume execution from target. The
state should be fixed (i.e., final) for the given target. 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 beforeTransfer callback 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);
});
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 be null.parentFrame - frame at the current point of execution.null otherwise.