Skip to content

Commit f575979

Browse files
committed
[GR-34771] Prevent repeated stack walks for exception state when entering Python.
PullRequest: graalpython/2026
2 parents edc6e76 + d78ac12 commit f575979

File tree

8 files changed

+35
-31
lines changed

8 files changed

+35
-31
lines changed

graalpython/com.oracle.graal.python.test/src/com/oracle/graal/python/builtins/modules/ConversionNodeTests.java

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,6 @@
4444
import org.junit.rules.ExpectedException;
4545

4646
import com.oracle.graal.python.PythonLanguage;
47-
import com.oracle.graal.python.builtins.objects.frame.PFrame;
4847
import com.oracle.graal.python.builtins.objects.function.PArguments;
4948
import com.oracle.graal.python.builtins.objects.function.Signature;
5049
import com.oracle.graal.python.nodes.PRootNode;
@@ -100,11 +99,11 @@ public boolean isPythonInternal() {
10099
PArguments.setException(arguments, PException.NO_EXCEPTION);
101100
PArguments.setArgument(arguments, 0, arg);
102101
PythonThreadState threadState = pythonContext.getThreadState(language);
103-
PFrame.Reference frameInfo = IndirectCalleeContext.enter(threadState, arguments, callTarget);
102+
Object state = IndirectCalleeContext.enter(threadState, arguments, callTarget);
104103
try {
105104
return CallTargetInvokeNode.invokeUncached(callTarget, arguments);
106105
} finally {
107-
IndirectCalleeContext.exit(threadState, frameInfo);
106+
IndirectCalleeContext.exit(threadState, state);
108107
}
109108
} catch (PException e) {
110109
// materialize PException's error message since we are leaving Python

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/common/SortNodes.java

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,6 @@
4545

4646
import com.oracle.graal.python.PythonLanguage;
4747
import com.oracle.graal.python.builtins.objects.PNone;
48-
import com.oracle.graal.python.builtins.objects.frame.PFrame;
4948
import com.oracle.graal.python.builtins.objects.function.PArguments;
5049
import com.oracle.graal.python.builtins.objects.function.Signature;
5150
import com.oracle.graal.python.builtins.objects.str.StringUtils;
@@ -289,11 +288,11 @@ private void sortWithoutKey(VirtualFrame frame, Object[] array, int len, boolean
289288
final RootCallTarget callTarget = getComparatorCallTarget(language);
290289
if (frame == null) {
291290
PythonThreadState threadState = PythonContext.get(this).getThreadState(language);
292-
PFrame.Reference frameInfo = IndirectCalleeContext.enter(threadState, arguments, callTarget);
291+
Object state = IndirectCalleeContext.enter(threadState, arguments, callTarget);
293292
try {
294293
callSortWithoutKey(array, len, callTarget, arguments);
295294
} finally {
296-
IndirectCalleeContext.exit(threadState, frameInfo);
295+
IndirectCalleeContext.exit(threadState, state);
297296
}
298297
} else {
299298
callContext.prepareCall(frame, arguments, callTarget, this);
@@ -386,11 +385,11 @@ private void sortWithKey(VirtualFrame frame, Object[] array, int len, Object key
386385
final RootCallTarget callTarget = getComparatorCallTarget(language);
387386
if (frame == null) {
388387
PythonThreadState threadState = PythonContext.get(this).getThreadState(language);
389-
PFrame.Reference frameInfo = IndirectCalleeContext.enter(threadState, arguments, callTarget);
388+
Object state = IndirectCalleeContext.enter(threadState, arguments, callTarget);
390389
try {
391390
callSortWithKey(pairArray, len, callTarget, arguments);
392391
} finally {
393-
IndirectCalleeContext.exit(threadState, frameInfo);
392+
IndirectCalleeContext.exit(threadState, state);
394393
}
395394
} else {
396395
callContext.prepareCall(frame, arguments, callTarget, this);

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/call/CallTargetInvokeNode.java

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,6 @@
4242

4343
import com.oracle.graal.python.PythonLanguage;
4444
import com.oracle.graal.python.builtins.objects.cell.PCell;
45-
import com.oracle.graal.python.builtins.objects.frame.PFrame;
4645
import com.oracle.graal.python.builtins.objects.function.PArguments;
4746
import com.oracle.graal.python.builtins.objects.function.PBuiltinFunction;
4847
import com.oracle.graal.python.builtins.objects.function.PFunction;
@@ -117,11 +116,11 @@ protected Object doNoClosure(VirtualFrame frame, PFunction callee, @SuppressWarn
117116
// This is preferably prepared using 'IndirectCallContext.enter'.
118117
if (profileIsNullFrame(frame == null)) {
119118
PythonThreadState threadState = PythonContext.get(this).getThreadState(PythonLanguage.get(this));
120-
PFrame.Reference frameInfo = IndirectCalleeContext.enter(threadState, arguments, ct);
119+
Object state = IndirectCalleeContext.enter(threadState, arguments, ct);
121120
try {
122121
return callNode.call(arguments);
123122
} finally {
124-
IndirectCalleeContext.exit(threadState, frameInfo);
123+
IndirectCalleeContext.exit(threadState, state);
125124
}
126125
} else {
127126
callContext.prepareCall(frame, arguments, ct, this);

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/call/FunctionInvokeNode.java

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,6 @@
4242

4343
import com.oracle.graal.python.PythonLanguage;
4444
import com.oracle.graal.python.builtins.objects.cell.PCell;
45-
import com.oracle.graal.python.builtins.objects.frame.PFrame;
4645
import com.oracle.graal.python.builtins.objects.function.PArguments;
4746
import com.oracle.graal.python.builtins.objects.function.PBuiltinFunction;
4847
import com.oracle.graal.python.builtins.objects.function.PFunction;
@@ -99,11 +98,11 @@ protected Object doDirect(VirtualFrame frame, Object[] arguments,
9998
optionallySetGeneratorFunction(arguments, ct, isGeneratorFunctionProfile, callee);
10099
if (profileIsNullFrame(frame == null)) {
101100
PythonThreadState threadState = PythonContext.get(this).getThreadState(PythonLanguage.get(this));
102-
PFrame.Reference frameInfo = IndirectCalleeContext.enter(threadState, arguments, ct);
101+
Object state = IndirectCalleeContext.enter(threadState, arguments, ct);
103102
try {
104103
return callNode.call(arguments);
105104
} finally {
106-
IndirectCalleeContext.exit(threadState, frameInfo);
105+
IndirectCalleeContext.exit(threadState, state);
107106
}
108107
} else {
109108
callContext.prepareCall(frame, arguments, ct, this);

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/call/GenericInvokeNode.java

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,6 @@
4141
package com.oracle.graal.python.nodes.call;
4242

4343
import com.oracle.graal.python.PythonLanguage;
44-
import com.oracle.graal.python.builtins.objects.frame.PFrame;
4544
import com.oracle.graal.python.builtins.objects.function.PArguments;
4645
import com.oracle.graal.python.builtins.objects.function.PBuiltinFunction;
4746
import com.oracle.graal.python.builtins.objects.function.PFunction;
@@ -119,11 +118,11 @@ private Object doCall(Frame frame, PFunction callee, RootCallTarget callTarget,
119118
optionallySetGeneratorFunction(arguments, callTarget, isGeneratorFunctionProfile, callee);
120119
if (isNullFrameProfile.profile(frame == null)) {
121120
PythonThreadState threadState = context.getThreadState(language);
122-
PFrame.Reference frameInfo = IndirectCalleeContext.enterIndirect(threadState, arguments);
121+
Object state = IndirectCalleeContext.enterIndirect(threadState, arguments);
123122
try {
124123
return callNode.call(callTarget, arguments);
125124
} finally {
126-
IndirectCalleeContext.exit(threadState, frameInfo);
125+
IndirectCalleeContext.exit(threadState, state);
127126
}
128127
} else {
129128
assert frame instanceof VirtualFrame : "GenericInvokeNode should not be executed with non-virtual frames";

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/control/TopLevelExceptionHandler.java

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,6 @@
4949
import com.oracle.graal.python.builtins.objects.dict.PDict;
5050
import com.oracle.graal.python.builtins.objects.exception.GetExceptionTracebackNode;
5151
import com.oracle.graal.python.builtins.objects.exception.PBaseException;
52-
import com.oracle.graal.python.builtins.objects.frame.PFrame;
5352
import com.oracle.graal.python.builtins.objects.function.PArguments;
5453
import com.oracle.graal.python.builtins.objects.module.PythonModule;
5554
import com.oracle.graal.python.builtins.objects.traceback.PTraceback;
@@ -287,11 +286,11 @@ private Object run(VirtualFrame frame) {
287286
PArguments.setCustomLocals(arguments, mainDict);
288287
PArguments.setException(arguments, PException.NO_EXCEPTION);
289288
}
290-
PFrame.Reference frameInfo = IndirectCalleeContext.enter(getPythonLanguage(), pythonContext, arguments, innerCallTarget);
289+
Object state = IndirectCalleeContext.enterIndirect(getPythonLanguage(), pythonContext, arguments);
291290
try {
292291
return innerCallTarget.call(arguments);
293292
} finally {
294-
IndirectCalleeContext.exit(getPythonLanguage(), pythonContext, frameInfo);
293+
IndirectCalleeContext.exit(getPythonLanguage(), pythonContext, state);
295294
}
296295
}
297296

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

Lines changed: 20 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -142,7 +142,7 @@ private void prepareCall(VirtualFrame frame, Object[] callArguments, Node callNo
142142
CompilerDirectives.transferToInterpreterAndInvalidate();
143143
neededExceptionState = true;
144144
}
145-
PException curExc = null;
145+
PException curExc;
146146
if (isPythonFrame(frame, callNode)) {
147147
curExc = PArguments.getException(frame);
148148
if (curExc == null) {
@@ -449,55 +449,65 @@ public abstract static class IndirectCalleeContext {
449449
/**
450450
* Prepare an indirect call from a foreign frame to a Python function.
451451
*/
452-
public static PFrame.Reference enterIndirect(PythonLanguage language, PythonContext context, Object[] pArguments) {
452+
public static Object enterIndirect(PythonLanguage language, PythonContext context, Object[] pArguments) {
453453
return enter(context.getThreadState(language), pArguments, true);
454454
}
455455

456456
/**
457457
* @see #enterIndirect(PythonLanguage, PythonContext, Object[])
458458
*/
459-
public static PFrame.Reference enterIndirect(PythonThreadState threadState, Object[] pArguments) {
459+
public static Object enterIndirect(PythonThreadState threadState, Object[] pArguments) {
460460
return enter(threadState, pArguments, true);
461461
}
462462

463463
/**
464464
* @see #enter(PythonThreadState, Object[], RootCallTarget)
465465
*/
466-
public static PFrame.Reference enter(PythonLanguage language, PythonContext context, Object[] pArguments, RootCallTarget callTarget) {
466+
public static Object enter(PythonLanguage language, PythonContext context, Object[] pArguments, RootCallTarget callTarget) {
467467
PRootNode calleeRootNode = (PRootNode) callTarget.getRootNode();
468468
return enter(context.getThreadState(language), pArguments, calleeRootNode.needsExceptionState());
469469
}
470470

471471
/**
472472
* Prepare a call from a foreign frame to a Python function.
473473
*/
474-
public static PFrame.Reference enter(PythonThreadState threadState, Object[] pArguments, RootCallTarget callTarget) {
474+
public static Object enter(PythonThreadState threadState, Object[] pArguments, RootCallTarget callTarget) {
475475
PRootNode calleeRootNode = (PRootNode) callTarget.getRootNode();
476476
return enter(threadState, pArguments, calleeRootNode.needsExceptionState());
477477
}
478478

479-
private static PFrame.Reference enter(PythonThreadState threadState, Object[] pArguments, boolean needsExceptionState) {
479+
private static Object enter(PythonThreadState threadState, Object[] pArguments, boolean needsExceptionState) {
480480
Reference popTopFrameInfo = threadState.popTopFrameInfo();
481481
PArguments.setCallerFrameInfo(pArguments, popTopFrameInfo);
482482

483483
if (needsExceptionState) {
484484
PException curExc = threadState.getCaughtException();
485+
if (curExc != null) {
486+
threadState.setCaughtException(null);
487+
}
485488
PArguments.setException(pArguments, curExc);
489+
return new IndirectCallState(popTopFrameInfo, curExc);
486490
}
487491
return popTopFrameInfo;
488492
}
489493

490-
public static void exit(PythonLanguage language, PythonContext context, PFrame.Reference frameInfo) {
491-
exit(context.getThreadState(language), frameInfo);
494+
public static void exit(PythonLanguage language, PythonContext context, Object state) {
495+
exit(context.getThreadState(language), state);
492496
}
493497

494-
public static void exit(PythonThreadState threadState, PFrame.Reference frameInfo) {
498+
public static void exit(PythonThreadState threadState, Object state) {
495499
/*
496500
* Note that the Python callee, if it escaped, has already been materialized due to a
497501
* CalleeContext in its RootNode. If this topframeref was marked as escaped, it'll be
498502
* materialized at the latest needed time
499503
*/
500-
threadState.setTopFrameInfo(frameInfo);
504+
if (state instanceof IndirectCallState) {
505+
IndirectCallState indirectCallState = (IndirectCallState) state;
506+
threadState.setTopFrameInfo(indirectCallState.info);
507+
threadState.setCaughtException(indirectCallState.curExc);
508+
} else {
509+
threadState.setTopFrameInfo((Reference) state);
510+
}
501511
}
502512
}
503513
}

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -170,7 +170,7 @@ public static final class PythonThreadState {
170170
PException currentException;
171171

172172
/* corresponds to 'PyThreadState.exc_*' */
173-
PException caughtException;
173+
PException caughtException = PException.NO_EXCEPTION;
174174

175175
/* set to emulate Py_ReprEnter/Leave */
176176
HashSet<Object> reprObjectSet;

0 commit comments

Comments
 (0)