Skip to content

Commit 50a5a89

Browse files
committed
Fix saving generator exception state
1 parent 823cde7 commit 50a5a89

File tree

2 files changed

+22
-4
lines changed

2 files changed

+22
-4
lines changed

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/bytecode/PBytecodeGeneratorRootNode.java

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,15 @@ public PBytecodeGeneratorRootNode(PythonLanguage language, PBytecodeRootNode roo
8383
@Override
8484
public Object execute(VirtualFrame frame) {
8585
calleeContext.enter(frame);
86+
MaterializedFrame generatorFrame = PArguments.getGeneratorFrame(frame);
87+
/*
88+
* This copying of exceptions is necessary because we need to remember the exception state
89+
* in the generator, but we don't want to remember the state that is "inherited" from the
90+
* outer frame as that can change with each invocation.
91+
*/
92+
PException localException = PArguments.getException(generatorFrame);
93+
PException outerException = PArguments.getException(frame);
94+
PArguments.setException(frame, localException == null ? outerException : localException);
8695
Object result;
8796
try {
8897
result = rootNode.executeFromBci(frame, resumeBci, resumeStackTop);
@@ -93,10 +102,13 @@ public Object execute(VirtualFrame frame) {
93102
throw raise.raise(RuntimeError, pe.setCatchingFrameAndGetEscapedException(frame, this), ErrorMessages.GENERATOR_RAISED_STOPITER);
94103
} finally {
95104
calleeContext.exit(frame, this);
105+
PException exception = PArguments.getException(frame);
106+
if (exception != outerException && exception != PException.NO_EXCEPTION) {
107+
PArguments.setException(generatorFrame, exception);
108+
}
96109
}
97110
if (returnProfile.profile(result == null)) {
98111
// Null result indicates a generator return
99-
MaterializedFrame generatorFrame = PArguments.getGeneratorFrame(frame);
100112
PBytecodeRootNode.FrameInfo info = (PBytecodeRootNode.FrameInfo) generatorFrame.getFrameDescriptor().getInfo();
101113
Object returnValue = info.getGeneratorReturnValue(generatorFrame);
102114
if (returnValue != PNone.NONE) {

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/util/ExceptionStateNodes.java

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2019, 2021, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2019, 2022, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* The Universal Permissive License (UPL), Version 1.0
@@ -109,8 +109,14 @@ public PException execute(VirtualFrame frame) {
109109
if (e == null) {
110110
e = PException.NO_EXCEPTION;
111111
}
112-
// Set into frame to avoid doing the stack walk again
113-
PArguments.setException(frame, e);
112+
/*
113+
* Set into frame to avoid doing the stack walk again. We cannot do this for
114+
* generators because exception state inherited from outer frame needs to be treated
115+
* differently from local exception state.
116+
*/
117+
if (PArguments.getGeneratorFrame(frame) == null) {
118+
PArguments.setException(frame, e);
119+
}
114120
}
115121
return ensure(e);
116122
}

0 commit comments

Comments
 (0)