Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -314,13 +314,21 @@ def target_inner():
frame = frames[worker_ident]
if frame is None:
return # we hit the timeout

def format_frame(frame):
code = frame.f_code
return f"{code.co_name}@{os.path.basename(code.co_filename)}"

seen_frames = []
while frame is not None and frame.f_code.co_name != "target_inner":
seen_frames.append(format_frame(frame))
frame = frame.f_back

assert frame is not None
assert frame.f_code.co_name == "target_inner", frame.f_code.co_name
assert "target_inner" in repr(frame)
assert "my_local_var" in frame.f_locals
message = f"test case: {test_case}; traversed frames: {', '.join(seen_frames) or '<none>'}"
assert frame is not None, message
assert frame.f_code.co_name == "target_inner", f"{frame.f_code.co_name=}; {message}"
assert "target_inner" in repr(frame), f"{repr(frame)=}; {message}"
assert "my_local_var" in frame.f_locals, f"{frame.f_locals.keys()=}; {message}"

frame = frame.f_back
assert frame is not None
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -935,8 +935,16 @@ private static EconomicMapStorage collectCurrentFrames(Node inliningTarget, Pyth
Future<Void> future = context.getEnv().submitThreadLocal(threadArray, new ThreadLocalAction(true, false) {
@Override
protected void perform(Access access) {
/*
* Force-escape the frame while we are still running in the target thread.
* Otherwise, the TLA can capture a frame after that frame has already
* checked info.isEscaped() in CalleeContext.exitImpl. Merely marking the
* returned PFrame as escaped would then be too late: the frame can unwind
* without exitEscaped filling in callerInfo, and f_back would be unable to
* recover the caller by stack-walking from the already-unwound frame.
*/
PFrame pyFrame = ReadFrameNode.readFrameInThreadLocal(access, null, FrameAccess.READ_ONLY, AllPythonFramesSelector.INSTANCE, 0, CallerFlags.NEEDS_PFRAME,
MaterializeFrameNode.getUncached());
MaterializeFrameNode.getUncached(), true);
frames.put(access.getThread(), escapedFrameOrPlaceholder(pyFrame));
}
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@
import com.oracle.graal.python.nodes.bytecode.PBytecodeRootNode;
import com.oracle.graal.python.nodes.bytecode_dsl.PBytecodeDSLRootNode;
import com.oracle.graal.python.runtime.CallerFlags;
import com.oracle.graal.python.runtime.ExecutionContext.CalleeContext;
import com.oracle.graal.python.runtime.GilNode;
import com.oracle.graal.python.runtime.IndirectCallData;
import com.oracle.graal.python.runtime.IndirectCallData.BoundaryCallData;
Expand Down Expand Up @@ -290,12 +291,20 @@ protected void perform(Access access) {

public static PFrame readFrameInThreadLocal(Access access, Reference startFrameInfo, FrameAccess frameAccess, FrameSelector selector, int level, int callerFlags,
MaterializeFrameNode materializeFrameNode) {
return readFrameInThreadLocal(access, startFrameInfo, frameAccess, selector, level, callerFlags, materializeFrameNode, false);
}

public static PFrame readFrameInThreadLocal(Access access, Reference startFrameInfo, FrameAccess frameAccess, FrameSelector selector, int level, int callerFlags,
MaterializeFrameNode materializeFrameNode, boolean forceEscape) {
Node location = access.getLocation();
if (location instanceof PBytecodeDSLRootNode) {
// See AsyncPythonAction#execute for explanation
location = PythonLanguage.get(null).unavailableSafepointLocation;
}
StackWalkResult result = ReadFrameNode.getFrame(location, startFrameInfo, frameAccess, selector, level, callerFlags);
if (forceEscape && result != null) {
CalleeContext.forceEscapeFrame(result.frame, getMaterializationLocation(result), PArguments.getCurrentFrameInfo(result.frame), materializeFrameNode);
}
return processStackWalkResult(materializeFrameNode, callerFlags, result);
}

Expand All @@ -308,19 +317,24 @@ private static Thread getFrameThread(PFrame.Reference startFrameInfo, Thread fra

private static PFrame processStackWalkResult(MaterializeFrameNode materializeFrameNode, int callerFlags, StackWalkResult callerFrameResult) {
if (callerFrameResult != null) {
Node location = callerFrameResult.callNode;
if (!(callerFrameResult.rootNode instanceof PBytecodeDSLRootNode) && location == null) {
/*
* We can fixup the location like this only for other root nodes, for Bytecode DSL
* we need the BytecodeNode
*/
location = callerFrameResult.rootNode;
}
Node location = getMaterializationLocation(callerFrameResult);
return materializeFrameNode.execute(location, false, CallerFlags.needsLocals(callerFlags), callerFrameResult.frame);
}
return null;
}

private static Node getMaterializationLocation(StackWalkResult callerFrameResult) {
Node location = callerFrameResult.callNode;
if (!(callerFrameResult.rootNode instanceof PBytecodeDSLRootNode) && location == null) {
/*
* We can fixup the location like this only for other root nodes, for Bytecode DSL we
* need the BytecodeNode
*/
location = callerFrameResult.rootNode;
}
return location;
}

/**
* Walk up the stack to find the currently top Python frame. This method is mostly useful for
* code that cannot accept a {@code VirtualFrame} parameter (e.g. library code). It is necessary
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -436,7 +436,10 @@ private void exitEscaped(VirtualFrame frame, PRootNode node, Node location, Refe
CompilerDirectives.transferToInterpreterAndInvalidate();
everEscaped = true;
}
// This assumption acts as our branch profile here
forceEscapeFrame(frame, location, info, ensureMaterializeNode());
}

public static void forceEscapeFrame(Frame frame, Node location, Reference info, MaterializeFrameNode materializeNode) {
Reference callerInfo = info.getCallerInfo();
if (callerInfo == null) {
// we didn't request the caller frame reference. now we need it.
Expand All @@ -460,11 +463,7 @@ private void exitEscaped(VirtualFrame frame, PRootNode node, Node location, Refe
// initializations (importing a module) from invalidating the assumption

// force the frame so that it can be accessed later
if (PythonOptions.ENABLE_BYTECODE_DSL_INTERPRETER && node instanceof PBytecodeDSLRootNode) {
ensureMaterializeNode().executeOnStack(frame, (BytecodeNode) location, false, true);
} else {
ensureMaterializeNode().executeOnStack(frame, node, false, true);
}
materializeNode.execute(location, false, true, frame);
// if this frame escaped we must ensure that also f_back does
callerInfo.markAsEscaped();
info.setCallerInfo(callerInfo);
Expand Down
Loading