45
45
import com .oracle .graal .python .builtins .objects .frame .PFrame .Reference ;
46
46
import com .oracle .graal .python .builtins .objects .function .PArguments ;
47
47
import com .oracle .graal .python .nodes .PRootNode ;
48
+ import com .oracle .graal .python .nodes .control .TopLevelExceptionHandler ;
48
49
import com .oracle .graal .python .nodes .frame .MaterializeFrameNode ;
49
50
import com .oracle .graal .python .nodes .frame .MaterializeFrameNodeGen ;
50
51
import com .oracle .graal .python .nodes .frame .ReadCallerFrameNode ;
58
59
import com .oracle .truffle .api .frame .VirtualFrame ;
59
60
import com .oracle .truffle .api .nodes .Node ;
60
61
import com .oracle .truffle .api .profiles .BranchProfile ;
62
+ import com .oracle .truffle .api .profiles .ConditionProfile ;
61
63
62
64
/**
63
65
* 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 {
73
75
74
76
private final boolean adoptable ;
75
77
78
+ @ CompilationFinal private ConditionProfile isPythonFrameProfile ;
79
+
76
80
private CallContext (boolean adoptable ) {
77
81
this .adoptable = adoptable ;
78
82
}
@@ -91,14 +95,20 @@ public void prepareCall(VirtualFrame frame, Object[] callArguments, RootCallTarg
91
95
// must only be used when calling from Python to Python
92
96
PRootNode calleeRootNode = (PRootNode ) callTarget .getRootNode ();
93
97
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
+ }
102
112
103
113
thisInfo .setCallNode (callNode );
104
114
PArguments .setCallerFrameInfo (callArguments , thisInfo );
@@ -127,6 +137,16 @@ private PFrame materialize(VirtualFrame frame, Node callNode, boolean markAsEsca
127
137
return MaterializeFrameNode .getUnadoptable ().execute (frame , callNode , markAsEscaped , forceSync );
128
138
}
129
139
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
+
130
150
private MaterializeFrameNode ensureMaterializeNode () {
131
151
if (materializeNode == null ) {
132
152
CompilerDirectives .transferToInterpreterAndInvalidate ();
0 commit comments