4545import com .oracle .graal .python .builtins .objects .frame .PFrame .Reference ;
4646import com .oracle .graal .python .builtins .objects .function .PArguments ;
4747import com .oracle .graal .python .nodes .PRootNode ;
48+ import com .oracle .graal .python .nodes .control .TopLevelExceptionHandler ;
4849import com .oracle .graal .python .nodes .frame .MaterializeFrameNode ;
4950import com .oracle .graal .python .nodes .frame .MaterializeFrameNodeGen ;
5051import com .oracle .graal .python .nodes .frame .ReadCallerFrameNode ;
5859import com .oracle .truffle .api .frame .VirtualFrame ;
5960import com .oracle .truffle .api .nodes .Node ;
6061import 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