69
69
import com .oracle .graal .python .builtins .objects .dict .PDict ;
70
70
import com .oracle .graal .python .builtins .objects .ellipsis .PEllipsis ;
71
71
import com .oracle .graal .python .builtins .objects .exception .GetExceptionTracebackNode ;
72
- import com .oracle .graal .python .builtins .objects .exception .GetExceptionTracebackNodeGen ;
73
72
import com .oracle .graal .python .builtins .objects .exception .PBaseException ;
74
73
import com .oracle .graal .python .builtins .objects .frame .PFrame ;
75
74
import com .oracle .graal .python .builtins .objects .function .PArguments ;
151
150
import com .oracle .graal .python .nodes .frame .DeleteGlobalNode ;
152
151
import com .oracle .graal .python .nodes .frame .DeleteGlobalNodeGen ;
153
152
import com .oracle .graal .python .nodes .frame .MaterializeFrameNode ;
154
- import com .oracle .graal .python .nodes .frame .MaterializeFrameNodeGen ;
155
153
import com .oracle .graal .python .nodes .frame .ReadGlobalOrBuiltinNode ;
156
154
import com .oracle .graal .python .nodes .frame .ReadGlobalOrBuiltinNodeGen ;
157
155
import com .oracle .graal .python .nodes .frame .ReadNameNode ;
@@ -498,6 +496,9 @@ public final class PBytecodeRootNode extends PRootNode implements BytecodeOSRNod
498
496
@ Child private CalleeContext calleeContext = CalleeContext .create ();
499
497
@ Child private PythonObjectFactory factory = PythonObjectFactory .create ();
500
498
@ Child private ExceptionStateNodes .GetCaughtExceptionNode getCaughtExceptionNode ;
499
+ @ Child private GetExceptionTracebackNode traceGetExceptionTracebackNode = null ;
500
+ @ Child private MaterializeFrameNode traceMaterializeFrameNode = null ;
501
+ @ Child private CallTernaryMethodNode traceCallTernaryMethodNode = null ;
501
502
502
503
private final LoopConditionProfile exceptionChainProfile1 = LoopConditionProfile .createCountingProfile ();
503
504
private final LoopConditionProfile exceptionChainProfile2 = LoopConditionProfile .createCountingProfile ();
@@ -1096,10 +1097,9 @@ private Object bytecodeLoop(VirtualFrame virtualFrame, Frame localFrame, Bytecod
1096
1097
1097
1098
int pastLine = -1 ;
1098
1099
if (threadState .getTraceFun () != null && !threadState .isTracing ()) {
1099
- MaterializeFrameNode fr = insertChildNode (localNodes , bci , MaterializeFrameNode .getUncached (), MaterializeFrameNodeGen .class , MaterializeFrameNode ::create , useCachedNodes );
1100
- pyFrame = fr .execute (virtualFrame , this , true , true );
1100
+ pyFrame = ensurePyFrame (virtualFrame , null );
1101
1101
if (initialBci == 0 || isGeneratorOrCoroutine ) {
1102
- pyFrame .setLocalTraceFun (invokeTraceFunction (threadState .getTraceFun (), null , threadState , virtualFrame , pyFrame , 0 , localNodes , PythonContext .TraceEvent .CALL , useCachedNodes ,
1102
+ pyFrame .setLocalTraceFun (invokeTraceFunction (threadState .getTraceFun (), null , threadState , virtualFrame , pyFrame , PythonContext .TraceEvent .CALL ,
1103
1103
initialBci == 0 ? getFirstLineno () : (pastLine = bciToLine (initialBci ))));
1104
1104
}
1105
1105
} else {
@@ -1114,15 +1114,44 @@ private Object bytecodeLoop(VirtualFrame virtualFrame, Frame localFrame, Bytecod
1114
1114
final byte bc = localBC [bci ];
1115
1115
final int beginBci = bci ;
1116
1116
if (threadState .getTraceFun () != null && !threadState .isTracing ()) {
1117
- pyFrame = ensurePyFrame (virtualFrame , localNodes , bci , useCachedNodes , pyFrame );
1118
- boolean onANewLine = bciToLine (bci ) != pastLine ;
1119
- pastLine = bciToLine (bci );
1117
+ pyFrame = ensurePyFrame (virtualFrame , pyFrame );
1118
+ int thisLine = bciToLine (bci );
1119
+ boolean onANewLine = thisLine != pastLine ;
1120
+ pastLine = thisLine ;
1120
1121
OpCodes c = OpCodes .fromOpCode (localBC [pastBci ]);
1121
- if (pyFrame .getLocalTraceFun () != null && pyFrame .getTraceLine () && (pastBci > bci || (onANewLine && (pastBci + c .length () >= bci || bciToLine (bci - 1 ) != bciToLine (bci ))))) {
1122
+ /*
1123
+ * normally, we trace a line every time the previous bytecode instruction was on a
1124
+ * different line than the current one. There are a number of exceptions to this,
1125
+ * notably around jumps:
1126
+ *
1127
+ * - When a backward jumps happens, a line is traced, even if it is the same as the
1128
+ * previous one.
1129
+ *
1130
+ * - When a forward jump happens to the first bytecode instruction of a line, a line
1131
+ * is traced.
1132
+ *
1133
+ * - When a forward jump happens to the middle of a line, a line is not traced.
1134
+ *
1135
+ * see
1136
+ * https://github.com/python/cpython/blob/main/Objects/lnotab_notes.txt#L210-L215
1137
+ * for more details
1138
+ */
1139
+ boolean shouldTrace = pyFrame .getLocalTraceFun () != null && pyFrame .getTraceLine ();
1140
+ if (shouldTrace ) {
1141
+ shouldTrace = pastBci > bci ; // is a backward jump
1142
+ if (!shouldTrace ) {
1143
+ shouldTrace = onANewLine &&
1144
+ // is not a forward jump
1145
+ (pastBci + c .length () >= bci ||
1146
+ // is a forward jump to the start of line
1147
+ bciToLine (bci - 1 ) != thisLine );
1148
+ }
1149
+ }
1150
+ if (shouldTrace ) {
1122
1151
returnLine = pastLine ;
1123
1152
pyFrame .setLocalTraceFun (
1124
- invokeTraceFunction (pyFrame .getLocalTraceFun (), null , threadState , virtualFrame , pyFrame , bci , localNodes , PythonContext .TraceEvent .LINE ,
1125
- useCachedNodes , pastLine ));
1153
+ invokeTraceFunction (pyFrame .getLocalTraceFun (), null , threadState , virtualFrame , pyFrame , PythonContext .TraceEvent .LINE ,
1154
+ pastLine ));
1126
1155
}
1127
1156
}
1128
1157
if (threadState .getTraceFun () != null ) {
@@ -1583,9 +1612,9 @@ private Object bytecodeLoop(VirtualFrame virtualFrame, Frame localFrame, Bytecod
1583
1612
}
1584
1613
Object value = virtualFrame .getObject (stackTop );
1585
1614
if (threadState .getTraceFun () != null && !threadState .isTracing ()) {
1586
- pyFrame = ensurePyFrame (virtualFrame , localNodes , bci , useCachedNodes , pyFrame );
1615
+ pyFrame = ensurePyFrame (virtualFrame , pyFrame );
1587
1616
if (pyFrame .getLocalTraceFun () != null ) {
1588
- invokeTraceFunction (pyFrame .getLocalTraceFun (), value , threadState , virtualFrame , pyFrame , bci , localNodes , PythonContext .TraceEvent .RETURN , useCachedNodes ,
1617
+ invokeTraceFunction (pyFrame .getLocalTraceFun (), value , threadState , virtualFrame , pyFrame , PythonContext .TraceEvent .RETURN ,
1589
1618
pyFrame .getTraceLine () ? returnLine : bciToLine (bci ));
1590
1619
}
1591
1620
}
@@ -1863,17 +1892,6 @@ private Object bytecodeLoop(VirtualFrame virtualFrame, Frame localFrame, Bytecod
1863
1892
stackTop ++;
1864
1893
bci ++;
1865
1894
} else {
1866
- if (threadState .getTraceFun () != null && !threadState .isTracing ()) {
1867
- pyFrame = ensurePyFrame (virtualFrame , localNodes , bci , useCachedNodes , pyFrame );
1868
- if (pyFrame .getLocalTraceFun () != null ) {
1869
- pyFrame .setLocalTraceFun (invokeTraceFunction (pyFrame .getLocalTraceFun (),
1870
- factory .createTuple (
1871
- new Object []{PythonBuiltinClassType .StopIteration , factory .createBaseException (PythonBuiltinClassType .StopIteration ), PNone .NONE }),
1872
- threadState , virtualFrame , pyFrame , bci ,
1873
- localNodes ,
1874
- PythonContext .TraceEvent .EXCEPTION , useCachedNodes , -1 ));
1875
- }
1876
- }
1877
1895
virtualFrame .setObject (stackTop --, null );
1878
1896
oparg |= Byte .toUnsignedInt (localBC [bci + 1 ]);
1879
1897
bci += oparg ;
@@ -1900,17 +1918,6 @@ private Object bytecodeLoop(VirtualFrame virtualFrame, Frame localFrame, Bytecod
1900
1918
stackTop ++;
1901
1919
bci ++;
1902
1920
} else {
1903
- if (threadState .getTraceFun () != null && !threadState .isTracing ()) {
1904
- pyFrame = ensurePyFrame (virtualFrame , localNodes , bci , useCachedNodes , pyFrame );
1905
- if (pyFrame .getLocalTraceFun () != null ) {
1906
- pyFrame .setLocalTraceFun (invokeTraceFunction (pyFrame .getLocalTraceFun (),
1907
- factory .createTuple (new Object []{PythonBuiltinClassType .StopIteration , factory .createBaseException (PythonBuiltinClassType .StopIteration ),
1908
- PNone .NONE }),
1909
- threadState , virtualFrame , pyFrame , bci ,
1910
- localNodes ,
1911
- PythonContext .TraceEvent .EXCEPTION , useCachedNodes , -1 ));
1912
- }
1913
- }
1914
1921
virtualFrame .setObject (stackTop --, null );
1915
1922
oparg |= Byte .toUnsignedInt (localBC [bci + 1 ]);
1916
1923
bci += oparg ;
@@ -2050,10 +2057,10 @@ private Object bytecodeLoop(VirtualFrame virtualFrame, Frame localFrame, Bytecod
2050
2057
clearFrameSlots (localFrame , stackTop + 1 , initialStackTop );
2051
2058
}
2052
2059
if (threadState .getTraceFun () != null && !threadState .isTracing ()) {
2053
- pyFrame = ensurePyFrame (virtualFrame , localNodes , bci , useCachedNodes , pyFrame );
2060
+ pyFrame = ensurePyFrame (virtualFrame , pyFrame );
2054
2061
if (pyFrame .getLocalTraceFun () != null ) {
2055
- invokeTraceFunction (pyFrame .getLocalTraceFun (), value , threadState , virtualFrame , pyFrame , bci , localNodes , PythonContext .TraceEvent .RETURN ,
2056
- useCachedNodes , pyFrame .getTraceLine () ? returnLine : bciToLine (bci ));
2062
+ invokeTraceFunction (pyFrame .getLocalTraceFun (), value , threadState , virtualFrame , pyFrame , PythonContext .TraceEvent .RETURN ,
2063
+ pyFrame .getTraceLine () ? returnLine : bciToLine (bci ));
2057
2064
}
2058
2065
}
2059
2066
return new GeneratorYieldResult (bci + 1 , stackTop , value );
@@ -2144,14 +2151,15 @@ private Object bytecodeLoop(VirtualFrame virtualFrame, Frame localFrame, Bytecod
2144
2151
}
2145
2152
2146
2153
if (threadState .getTraceFun () != null && !threadState .isTracing () && pe != null ) {
2147
- pyFrame = ensurePyFrame (virtualFrame , localNodes , bci , useCachedNodes , pyFrame );
2154
+ pyFrame = ensurePyFrame (virtualFrame , pyFrame );
2148
2155
if (pyFrame .getLocalTraceFun () != null ) {
2149
- GetExceptionTracebackNode tbn = insertChildNode (localNodes , bci , GetExceptionTracebackNode .getUncached (), GetExceptionTracebackNodeGen .class , GetExceptionTracebackNode ::create , useCachedNodes );
2150
- Object tb = tbn .execute (pe );
2156
+ if (traceGetExceptionTracebackNode == null ) {
2157
+ traceGetExceptionTracebackNode = GetExceptionTracebackNode .create ();
2158
+ }
2159
+ Object traceback = traceGetExceptionTracebackNode .execute (pe );
2151
2160
pyFrame .setLocalTraceFun (invokeTraceFunction (pyFrame .getLocalTraceFun (),
2152
- factory .createTuple (new Object []{pe .getClass (), pe .setCatchingFrameAndGetEscapedException (virtualFrame , this ), tb }), threadState , virtualFrame , pyFrame , bci ,
2153
- localNodes ,
2154
- PythonContext .TraceEvent .EXCEPTION , useCachedNodes , -1 ));
2161
+ factory .createTuple (new Object []{pe .getClass (), pe .setCatchingFrameAndGetEscapedException (virtualFrame , this ), traceback }), threadState , virtualFrame , pyFrame ,
2162
+ PythonContext .TraceEvent .EXCEPTION , -1 ));
2155
2163
}
2156
2164
}
2157
2165
@@ -2184,9 +2192,9 @@ private Object bytecodeLoop(VirtualFrame virtualFrame, Frame localFrame, Bytecod
2184
2192
LoopNode .reportLoopCount (this , mutableData .loopCount );
2185
2193
}
2186
2194
if (threadState .getTraceFun () != null ) {
2187
- pyFrame = ensurePyFrame (virtualFrame , localNodes , bci , useCachedNodes , pyFrame );
2195
+ pyFrame = ensurePyFrame (virtualFrame , pyFrame );
2188
2196
if (pyFrame .getLocalTraceFun () != null ) {
2189
- invokeTraceFunction (pyFrame .getLocalTraceFun (), PNone .NONE , threadState , virtualFrame , pyFrame , bci , localNodes , PythonContext .TraceEvent .RETURN , useCachedNodes ,
2197
+ invokeTraceFunction (pyFrame .getLocalTraceFun (), PNone .NONE , threadState , virtualFrame , pyFrame , PythonContext .TraceEvent .RETURN ,
2190
2198
pyFrame .getTraceLine () ? returnLine : bciToLine (bci ));
2191
2199
}
2192
2200
}
@@ -2214,24 +2222,29 @@ private Object bytecodeLoop(VirtualFrame virtualFrame, Frame localFrame, Bytecod
2214
2222
}
2215
2223
}
2216
2224
2217
- private PFrame ensurePyFrame (VirtualFrame virtualFrame , Node [] localNodes , int bci , boolean useCachedNodes , PFrame pyFrame ) {
2225
+ private PFrame ensurePyFrame (VirtualFrame virtualFrame , PFrame pyFrame ) {
2226
+ if (traceMaterializeFrameNode == null ) {
2227
+ traceMaterializeFrameNode = MaterializeFrameNode .create ();
2228
+ }
2218
2229
if (pyFrame == null ) {
2219
- MaterializeFrameNode fr = insertChildNode (localNodes , bci , MaterializeFrameNode .getUncached (), MaterializeFrameNodeGen .class , MaterializeFrameNode ::create , useCachedNodes );
2220
- return fr .execute (virtualFrame , this , true , true );
2230
+ return traceMaterializeFrameNode .execute (virtualFrame , this , true , true );
2221
2231
}
2222
2232
return pyFrame ;
2223
2233
}
2234
+ // TODO: trace with OSR in a generator will create extraneous call events
2224
2235
2225
- private Object invokeTraceFunction (Object traceFn , Object arg , PythonContext .PythonThreadState threadState , VirtualFrame virtualFrame , PFrame tracing , int bci ,
2226
- Node [] localNodes , PythonContext .TraceEvent ev , boolean useCachedNodes , int line ) {
2227
- threadState .tracingStart (ev );
2228
- CallTernaryMethodNode callNode = insertChildNode (localNodes , bci , UNCACHED_CALL_TERNARY_METHOD , CallTernaryMethodNodeGen .class , NODE_CALL_TERNARY_METHOD , useCachedNodes );
2236
+ private Object invokeTraceFunction (Object traceFn , Object arg , PythonContext .PythonThreadState threadState , VirtualFrame virtualFrame , PFrame tracing ,
2237
+ PythonContext .TraceEvent event , int line ) {
2238
+ threadState .tracingStart (event );
2229
2239
Object nonNullArg = arg == null ? PNone .NONE : arg ;
2240
+ if (traceCallTernaryMethodNode == null ) {
2241
+ traceCallTernaryMethodNode = CallTernaryMethodNode .create ();
2242
+ }
2230
2243
try {
2231
2244
if (line != -1 ) {
2232
2245
tracing .setLineLock (line );
2233
2246
}
2234
- Object result = callNode .execute (virtualFrame , traceFn , tracing , ev .pythonName , nonNullArg );
2247
+ Object result = traceCallTernaryMethodNode .execute (virtualFrame , traceFn , tracing , event .pythonName , nonNullArg );
2235
2248
return result == PNone .NONE ? null : result ;
2236
2249
} catch (Throwable e ) {
2237
2250
threadState .setTraceFun (null );
0 commit comments