Skip to content

Commit 954ad5d

Browse files
committed
Fix: properly pass top frame info to callee.
1 parent 0db940b commit 954ad5d

File tree

1 file changed

+28
-8
lines changed

1 file changed

+28
-8
lines changed

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/ExecutionContext.java

Lines changed: 28 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@
4545
import com.oracle.graal.python.builtins.objects.frame.PFrame.Reference;
4646
import com.oracle.graal.python.builtins.objects.function.PArguments;
4747
import com.oracle.graal.python.nodes.PRootNode;
48+
import com.oracle.graal.python.nodes.control.TopLevelExceptionHandler;
4849
import com.oracle.graal.python.nodes.frame.MaterializeFrameNode;
4950
import com.oracle.graal.python.nodes.frame.MaterializeFrameNodeGen;
5051
import com.oracle.graal.python.nodes.frame.ReadCallerFrameNode;
@@ -58,6 +59,7 @@
5859
import com.oracle.truffle.api.frame.VirtualFrame;
5960
import com.oracle.truffle.api.nodes.Node;
6061
import com.oracle.truffle.api.profiles.BranchProfile;
62+
import com.oracle.truffle.api.profiles.ConditionProfile;
6163

6264
/**
6365
* An ExecutionContext ensures proper entry and exit for Python calls on both sides of the call, and
@@ -73,6 +75,8 @@ public static final class CallContext extends Node {
7375

7476
private final boolean adoptable;
7577

78+
@CompilationFinal private ConditionProfile isPythonFrameProfile;
79+
7680
private CallContext(boolean adoptable) {
7781
this.adoptable = adoptable;
7882
}
@@ -91,14 +95,20 @@ public void prepareCall(VirtualFrame frame, Object[] callArguments, RootCallTarg
9195
// must only be used when calling from Python to Python
9296
PRootNode calleeRootNode = (PRootNode) callTarget.getRootNode();
9397
if (calleeRootNode.needsCallerFrame()) {
94-
PFrame.Reference thisInfo = PArguments.getCurrentFrameInfo(frame);
95-
96-
// We are handing the PFrame of the current frame to the caller, i.e., it does not
97-
// 'escape' since it is still on the stack.
98-
// Also, force synchronization of values
99-
PFrame pyFrame = materialize(frame, callNode, false, true);
100-
assert thisInfo.getPyFrame() == pyFrame;
101-
assert pyFrame.getRef() == thisInfo;
98+
PFrame.Reference thisInfo;
99+
100+
if (isPythonFrame(frame, callNode)) {
101+
thisInfo = PArguments.getCurrentFrameInfo(frame);
102+
103+
// We are handing the PFrame of the current frame to the caller, i.e., it does
104+
// not 'escape' since it is still on the stack.Also, force synchronization of
105+
// values
106+
PFrame pyFrame = materialize(frame, callNode, false, true);
107+
assert thisInfo.getPyFrame() == pyFrame;
108+
assert pyFrame.getRef() == thisInfo;
109+
} else {
110+
thisInfo = PFrame.Reference.EMPTY;
111+
}
102112

103113
thisInfo.setCallNode(callNode);
104114
PArguments.setCallerFrameInfo(callArguments, thisInfo);
@@ -127,6 +137,16 @@ private PFrame materialize(VirtualFrame frame, Node callNode, boolean markAsEsca
127137
return MaterializeFrameNode.getUnadoptable().execute(frame, callNode, markAsEscaped, forceSync);
128138
}
129139

140+
private boolean isPythonFrame(VirtualFrame frame, Node callNode) {
141+
if (isPythonFrameProfile == null) {
142+
CompilerDirectives.transferToInterpreterAndInvalidate();
143+
isPythonFrameProfile = ConditionProfile.createBinaryProfile();
144+
}
145+
boolean result = isPythonFrameProfile.profile(PArguments.isPythonFrame(frame));
146+
assert result || callNode.getRootNode() instanceof TopLevelExceptionHandler : "calling from non-Python or non-top-level frame";
147+
return result;
148+
}
149+
130150
private MaterializeFrameNode ensureMaterializeNode() {
131151
if (materializeNode == null) {
132152
CompilerDirectives.transferToInterpreterAndInvalidate();

0 commit comments

Comments
 (0)