Skip to content

Commit dbcabf4

Browse files
committed
Move generator StopIteration creation to resume
1 parent 238f616 commit dbcabf4

File tree

3 files changed

+88
-48
lines changed

3 files changed

+88
-48
lines changed

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/generator/GeneratorBuiltins.java

Lines changed: 82 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -141,34 +141,95 @@ private static void checkResumable(PythonBuiltinBaseNode node, PGenerator self)
141141
abstract static class ResumeGeneratorNode extends Node {
142142
public abstract Object execute(VirtualFrame frame, PGenerator self, Object sendValue);
143143

144-
@Specialization(guards = "sameCallTarget(self.getCurrentCallTarget(), call.getCallTarget())", limit = "getCallSiteInlineCacheMaxDepth()")
145-
Object cached(VirtualFrame frame, PGenerator self, Object sendValue,
144+
@Specialization(guards = {"!self.usesBytecode()", "sameCallTarget(self.getCurrentCallTarget(), call.getCallTarget())"}, limit = "getCallSiteInlineCacheMaxDepth()")
145+
Object cachedAST(VirtualFrame frame, PGenerator self, Object sendValue,
146146
@Cached("createDirectCall(self.getCurrentCallTarget())") CallTargetInvokeNode call) {
147147
self.setRunning(true);
148148
Object[] arguments = prepareArguments(self);
149149
if (sendValue != null) {
150150
PArguments.setSpecialArgument(arguments, sendValue);
151151
}
152+
try {
153+
return call.execute(frame, null, null, null, arguments);
154+
} catch (PException e) {
155+
self.markAsFinished();
156+
throw e;
157+
} finally {
158+
self.setRunning(false);
159+
self.setNextCallTarget(PythonLanguage.get(this));
160+
}
161+
}
162+
163+
@Specialization(guards = "!self.usesBytecode()", replaces = "cachedAST")
164+
@Megamorphic
165+
Object genericAST(VirtualFrame frame, PGenerator self, Object sendValue,
166+
@Cached ConditionProfile hasFrameProfile,
167+
@Cached GenericInvokeNode call) {
168+
self.setRunning(true);
169+
Object[] arguments = prepareArguments(self);
170+
if (sendValue != null) {
171+
PArguments.setSpecialArgument(arguments, sendValue);
172+
}
173+
try {
174+
if (hasFrameProfile.profile(frame != null)) {
175+
return call.execute(frame, self.getCurrentCallTarget(), arguments);
176+
} else {
177+
return call.execute(self.getCurrentCallTarget(), arguments);
178+
}
179+
} catch (PException e) {
180+
self.markAsFinished();
181+
throw e;
182+
} finally {
183+
self.setRunning(false);
184+
self.setNextCallTarget(PythonLanguage.get(this));
185+
}
186+
}
187+
188+
@Specialization(guards = {"self.usesBytecode()", "sameCallTarget(self.getCurrentCallTarget(), call.getCallTarget())"}, limit = "getCallSiteInlineCacheMaxDepth()")
189+
Object cached(VirtualFrame frame, PGenerator self, Object sendValue,
190+
@Cached("createDirectCall(self.getCurrentCallTarget())") CallTargetInvokeNode call,
191+
@Cached ConditionProfile returnProfile,
192+
@Cached IsBuiltinClassProfile errorProfile,
193+
@Cached PRaiseNode raiseNode) {
194+
self.setRunning(true);
195+
Object[] arguments = prepareArguments(self);
196+
if (sendValue != null) {
197+
PArguments.setSpecialArgument(arguments, sendValue);
198+
}
152199
Object result;
153200
try {
154201
result = call.execute(frame, null, null, null, arguments);
155202
} catch (PException e) {
156203
self.markAsFinished();
157-
throw e;
204+
// PEP 479 - StopIteration raised from generator body needs to be wrapped in
205+
// RuntimeError
206+
e.expectStopIteration(errorProfile);
207+
throw raiseNode.raise(RuntimeError, e.setCatchingFrameAndGetEscapedException(frame, this), ErrorMessages.GENERATOR_RAISED_STOPITER);
158208
} finally {
159209
self.setRunning(false);
160-
if (!self.isFinished()) {
161-
self.setNextCallTarget(PythonLanguage.get(this));
210+
}
211+
if (returnProfile.profile(result == null)) {
212+
// Null result indicates a generator return
213+
Object returnValue = self.getReturnValue();
214+
if (returnValue != PNone.NONE) {
215+
throw raiseNode.raise(StopIteration, returnValue);
216+
} else {
217+
throw raiseNode.raise(StopIteration);
162218
}
219+
} else {
220+
self.setNextCallTarget(PythonLanguage.get(this));
163221
}
164222
return result;
165223
}
166224

167-
@Specialization(replaces = "cached")
225+
@Specialization(guards = "self.usesBytecode()", replaces = "cached")
168226
@Megamorphic
169227
Object generic(VirtualFrame frame, PGenerator self, Object sendValue,
170228
@Cached ConditionProfile hasFrameProfile,
171-
@Cached GenericInvokeNode call) {
229+
@Cached GenericInvokeNode call,
230+
@Cached ConditionProfile returnProfile,
231+
@Cached IsBuiltinClassProfile errorProfile,
232+
@Cached PRaiseNode raiseNode) {
172233
self.setRunning(true);
173234
Object[] arguments = prepareArguments(self);
174235
if (sendValue != null) {
@@ -183,12 +244,23 @@ Object generic(VirtualFrame frame, PGenerator self, Object sendValue,
183244
}
184245
} catch (PException e) {
185246
self.markAsFinished();
186-
throw e;
247+
// PEP 479 - StopIteration raised from generator body needs to be wrapped in
248+
// RuntimeError
249+
e.expectStopIteration(errorProfile);
250+
throw raiseNode.raise(RuntimeError, e.setCatchingFrameAndGetEscapedException(frame, this), ErrorMessages.GENERATOR_RAISED_STOPITER);
187251
} finally {
188252
self.setRunning(false);
189-
if (!self.isFinished()) {
190-
self.setNextCallTarget(PythonLanguage.get(this));
253+
}
254+
if (returnProfile.profile(result == null)) {
255+
// Null result indicates a generator return
256+
Object returnValue = self.getReturnValue();
257+
if (returnValue != PNone.NONE) {
258+
throw raiseNode.raise(StopIteration, returnValue);
259+
} else {
260+
throw raiseNode.raise(StopIteration);
191261
}
262+
} else {
263+
self.setNextCallTarget(PythonLanguage.get(this));
192264
}
193265
return result;
194266
}

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/generator/PGenerator.java

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ public final class PGenerator extends PythonBuiltinObject {
6262
* entry point into the generator: the first call, and continuation for each yield. Each AST can
6363
* then specialize towards which nodes are executed when starting from that particular entry
6464
* point. When yielding, the next index to the next call target to continue from is updated via
65-
* {@link #setNextCallTarget()}.
65+
* {@link #setNextCallTarget}.
6666
*/
6767
@CompilationFinal(dimensions = 1) protected final RootCallTarget[] callTargets;
6868
protected final Object[] arguments;
@@ -231,6 +231,10 @@ public int getStackTop() {
231231
return frameInfo.getGeneratorStackTop(PArguments.getGeneratorFrame(arguments));
232232
}
233233

234+
public Object getReturnValue() {
235+
return frameInfo.getGeneratorReturnValue(PArguments.getGeneratorFrame(arguments));
236+
}
237+
234238
public Object[] getArguments() {
235239
return arguments;
236240
}

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

Lines changed: 1 addition & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -40,17 +40,10 @@
4040
*/
4141
package com.oracle.graal.python.nodes.bytecode;
4242

43-
import static com.oracle.graal.python.builtins.PythonBuiltinClassType.RuntimeError;
44-
import static com.oracle.graal.python.runtime.exception.PythonErrorType.StopIteration;
45-
4643
import com.oracle.graal.python.PythonLanguage;
47-
import com.oracle.graal.python.builtins.objects.PNone;
4844
import com.oracle.graal.python.builtins.objects.function.PArguments;
4945
import com.oracle.graal.python.builtins.objects.function.Signature;
50-
import com.oracle.graal.python.nodes.ErrorMessages;
51-
import com.oracle.graal.python.nodes.PRaiseNode;
5246
import com.oracle.graal.python.nodes.PRootNode;
53-
import com.oracle.graal.python.nodes.object.IsBuiltinClassProfile;
5447
import com.oracle.graal.python.runtime.ExecutionContext;
5548
import com.oracle.graal.python.runtime.exception.PException;
5649
import com.oracle.truffle.api.CompilerAsserts;
@@ -62,7 +55,6 @@
6255
import com.oracle.truffle.api.frame.VirtualFrame;
6356
import com.oracle.truffle.api.nodes.BytecodeOSRNode;
6457
import com.oracle.truffle.api.nodes.ExplodeLoop;
65-
import com.oracle.truffle.api.profiles.ConditionProfile;
6658
import com.oracle.truffle.api.source.SourceSection;
6759

6860
public class PBytecodeGeneratorRootNode extends PRootNode implements BytecodeOSRNode {
@@ -71,9 +63,6 @@ public class PBytecodeGeneratorRootNode extends PRootNode implements BytecodeOSR
7163
private final int resumeStackTop;
7264

7365
@Child private ExecutionContext.CalleeContext calleeContext = ExecutionContext.CalleeContext.create();
74-
@Child private IsBuiltinClassProfile errorProfile;
75-
@Child private PRaiseNode raise = PRaiseNode.create();
76-
private final ConditionProfile returnProfile = ConditionProfile.create();
7766

7867
@CompilationFinal private Object osrMetadata;
7968
@CompilationFinal(dimensions = 1) private FrameSlotType[] frameSlotTypes;
@@ -229,7 +218,6 @@ public Object execute(VirtualFrame frame) {
229218
PException localException = PArguments.getException(generatorFrame);
230219
PException outerException = PArguments.getException(frame);
231220
PArguments.setException(frame, localException == null ? outerException : localException);
232-
Object result;
233221
Frame localFrame;
234222
boolean usingMaterializedFrame = CompilerDirectives.inInterpreter();
235223
if (usingMaterializedFrame) {
@@ -240,12 +228,7 @@ public Object execute(VirtualFrame frame) {
240228
localFrame = frame;
241229
}
242230
try {
243-
result = rootNode.executeFromBci(frame, localFrame, this, resumeBci, resumeStackTop);
244-
} catch (PException pe) {
245-
// PEP 479 - StopIteration raised from generator body needs to be wrapped in
246-
// RuntimeError
247-
pe.expectStopIteration(getErrorProfile());
248-
throw raise.raise(RuntimeError, pe.setCatchingFrameAndGetEscapedException(frame, this), ErrorMessages.GENERATOR_RAISED_STOPITER);
231+
return rootNode.executeFromBci(frame, generatorFrame, this, resumeBci, resumeStackTop);
249232
} finally {
250233
if (!usingMaterializedFrame) {
251234
copyFrameSlotsToGeneratorFrame(frame, generatorFrame);
@@ -256,17 +239,6 @@ public Object execute(VirtualFrame frame) {
256239
PArguments.setException(generatorFrame, exception);
257240
}
258241
}
259-
if (returnProfile.profile(result == null)) {
260-
// Null result indicates a generator return
261-
FrameInfo info = (FrameInfo) generatorFrame.getFrameDescriptor().getInfo();
262-
Object returnValue = info.getGeneratorReturnValue(generatorFrame);
263-
if (returnValue != PNone.NONE) {
264-
throw raise.raise(StopIteration, returnValue);
265-
} else {
266-
throw raise.raise(StopIteration);
267-
}
268-
}
269-
return result;
270242
}
271243

272244
@Override
@@ -314,12 +286,4 @@ public boolean isPythonInternal() {
314286
public SourceSection getSourceSection() {
315287
return rootNode.getSourceSection();
316288
}
317-
318-
private IsBuiltinClassProfile getErrorProfile() {
319-
if (errorProfile == null) {
320-
CompilerDirectives.transferToInterpreterAndInvalidate();
321-
errorProfile = insert(IsBuiltinClassProfile.create());
322-
}
323-
return errorProfile;
324-
}
325289
}

0 commit comments

Comments
 (0)