Skip to content

Commit a867068

Browse files
committed
[GR-40318] Fix boxing of generator yield values
PullRequest: graalpython/2389
2 parents aca12bd + 596b6e8 commit a867068

File tree

5 files changed

+99
-54
lines changed

5 files changed

+99
-54
lines changed

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

Lines changed: 37 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,8 @@
6565
import com.oracle.graal.python.nodes.PRaiseNode;
6666
import com.oracle.graal.python.nodes.SpecialMethodNames;
6767
import com.oracle.graal.python.nodes.bytecode.FrameInfo;
68-
import com.oracle.graal.python.nodes.bytecode.GeneratorResult;
68+
import com.oracle.graal.python.nodes.bytecode.GeneratorReturnException;
69+
import com.oracle.graal.python.nodes.bytecode.GeneratorYieldResult;
6970
import com.oracle.graal.python.nodes.call.CallTargetInvokeNode;
7071
import com.oracle.graal.python.nodes.call.GenericInvokeNode;
7172
import com.oracle.graal.python.nodes.call.special.LookupAndCallVarargsNode;
@@ -192,74 +193,79 @@ static Object genericAST(VirtualFrame frame, PGenerator self, Object sendValue,
192193
@Specialization(guards = {"self.usesBytecode()", "sameCallTarget(self.getCurrentCallTarget(), call.getCallTarget())"}, limit = "getCallSiteInlineCacheMaxDepth()")
193194
Object cached(VirtualFrame frame, PGenerator self, Object sendValue,
194195
@Cached("createDirectCall(self.getCurrentCallTarget())") CallTargetInvokeNode call,
195-
@Cached ConditionProfile returnProfile,
196+
@Cached BranchProfile returnProfile,
196197
@Cached IsBuiltinClassProfile errorProfile,
197198
@Cached PRaiseNode raiseNode) {
198199
self.setRunning(true);
199200
Object[] arguments = prepareArguments(self);
200201
if (sendValue != null) {
201202
PArguments.setSpecialArgument(arguments, sendValue);
202203
}
203-
GeneratorResult result;
204+
GeneratorYieldResult result;
204205
try {
205-
result = (GeneratorResult) call.execute(frame, null, null, null, arguments);
206+
result = (GeneratorYieldResult) call.execute(frame, null, null, null, arguments);
206207
} catch (PException e) {
207-
self.markAsFinished();
208-
// PEP 479 - StopIteration raised from generator body needs to be wrapped in
209-
// RuntimeError
210-
e.expectStopIteration(errorProfile);
211-
throw raiseNode.raise(RuntimeError, e.setCatchingFrameAndGetEscapedException(frame, this), ErrorMessages.GENERATOR_RAISED_STOPITER);
208+
throw handleException(frame, self, errorProfile, raiseNode, e);
209+
} catch (GeneratorReturnException e) {
210+
returnProfile.enter();
211+
throw handleReturn(self, e, raiseNode);
212212
} finally {
213213
self.setRunning(false);
214214
}
215-
return handleResult(self, result, returnProfile, raiseNode);
215+
return handleResult(self, result);
216216
}
217217

218218
@Specialization(guards = "self.usesBytecode()", replaces = "cached")
219219
@Megamorphic
220220
Object generic(VirtualFrame frame, PGenerator self, Object sendValue,
221221
@Cached ConditionProfile hasFrameProfile,
222222
@Cached GenericInvokeNode call,
223-
@Cached ConditionProfile returnProfile,
223+
@Cached BranchProfile returnProfile,
224224
@Cached IsBuiltinClassProfile errorProfile,
225225
@Cached PRaiseNode raiseNode) {
226226
self.setRunning(true);
227227
Object[] arguments = prepareArguments(self);
228228
if (sendValue != null) {
229229
PArguments.setSpecialArgument(arguments, sendValue);
230230
}
231-
GeneratorResult result;
231+
GeneratorYieldResult result;
232232
try {
233233
if (hasFrameProfile.profile(frame != null)) {
234-
result = (GeneratorResult) call.execute(frame, self.getCurrentCallTarget(), arguments);
234+
result = (GeneratorYieldResult) call.execute(frame, self.getCurrentCallTarget(), arguments);
235235
} else {
236-
result = (GeneratorResult) call.execute(self.getCurrentCallTarget(), arguments);
236+
result = (GeneratorYieldResult) call.execute(self.getCurrentCallTarget(), arguments);
237237
}
238238
} catch (PException e) {
239-
self.markAsFinished();
240-
// PEP 479 - StopIteration raised from generator body needs to be wrapped in
241-
// RuntimeError
242-
e.expectStopIteration(errorProfile);
243-
throw raiseNode.raise(RuntimeError, e.setCatchingFrameAndGetEscapedException(frame, this), ErrorMessages.GENERATOR_RAISED_STOPITER);
239+
throw handleException(frame, self, errorProfile, raiseNode, e);
240+
} catch (GeneratorReturnException e) {
241+
returnProfile.enter();
242+
throw handleReturn(self, e, raiseNode);
244243
} finally {
245244
self.setRunning(false);
246245
}
247-
return handleResult(self, result, returnProfile, raiseNode);
246+
return handleResult(self, result);
248247
}
249248

250-
private Object handleResult(PGenerator self, GeneratorResult result, ConditionProfile returnProfile, PRaiseNode raiseNode) {
251-
if (returnProfile.profile(result.isReturn)) {
252-
self.markAsFinished();
253-
Object returnValue = result.value;
254-
if (returnValue != PNone.NONE) {
255-
throw raiseNode.raise(StopIteration, new Object[]{returnValue});
256-
} else {
257-
throw raiseNode.raise(StopIteration);
258-
}
249+
private PException handleException(VirtualFrame frame, PGenerator self, IsBuiltinClassProfile errorProfile, PRaiseNode raiseNode, PException e) {
250+
self.markAsFinished();
251+
// PEP 479 - StopIteration raised from generator body needs to be wrapped in
252+
// RuntimeError
253+
e.expectStopIteration(errorProfile);
254+
throw raiseNode.raise(RuntimeError, e.setCatchingFrameAndGetEscapedException(frame, this), ErrorMessages.GENERATOR_RAISED_STOPITER);
255+
}
256+
257+
private Object handleResult(PGenerator self, GeneratorYieldResult result) {
258+
self.handleResult(PythonLanguage.get(this), result);
259+
return result.yieldValue;
260+
}
261+
262+
private static PException handleReturn(PGenerator self, GeneratorReturnException e, PRaiseNode raiseNode) {
263+
self.markAsFinished();
264+
if (e.value != PNone.NONE) {
265+
throw raiseNode.raise(StopIteration, new Object[]{e.value});
259266
} else {
260-
self.handleResult(PythonLanguage.get(this), result);
267+
throw raiseNode.raise(StopIteration);
261268
}
262-
return result.value;
263269
}
264270

265271
protected static CallTargetInvokeNode createDirectCall(CallTarget target) {

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

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@
3535
import com.oracle.graal.python.builtins.objects.iterator.PIntRangeIterator;
3636
import com.oracle.graal.python.builtins.objects.object.PythonBuiltinObject;
3737
import com.oracle.graal.python.nodes.bytecode.FrameInfo;
38-
import com.oracle.graal.python.nodes.bytecode.GeneratorResult;
38+
import com.oracle.graal.python.nodes.bytecode.GeneratorYieldResult;
3939
import com.oracle.graal.python.nodes.bytecode.PBytecodeGeneratorRootNode;
4040
import com.oracle.graal.python.nodes.bytecode.PBytecodeRootNode;
4141
import com.oracle.graal.python.nodes.generator.AbstractYieldNode;
@@ -170,12 +170,8 @@ private PGenerator(PythonLanguage lang, TruffleString name, TruffleString qualna
170170
this.generatorInfo = null;
171171
}
172172

173-
public void handleResult(PythonLanguage language, GeneratorResult result) {
173+
public void handleResult(PythonLanguage language, GeneratorYieldResult result) {
174174
assert usesBytecode();
175-
if (result.isReturn) {
176-
markAsFinished();
177-
return;
178-
}
179175
currentCallTarget = result.resumeBci;
180176
if (callTargets[currentCallTarget] == null) {
181177
CompilerDirectives.transferToInterpreterAndInvalidate();
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
/*
2+
* Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved.
3+
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+
*
5+
* The Universal Permissive License (UPL), Version 1.0
6+
*
7+
* Subject to the condition set forth below, permission is hereby granted to any
8+
* person obtaining a copy of this software, associated documentation and/or
9+
* data (collectively the "Software"), free of charge and under any and all
10+
* copyright rights in the Software, and any and all patent rights owned or
11+
* freely licensable by each licensor hereunder covering either (i) the
12+
* unmodified Software as contributed to or provided by such licensor, or (ii)
13+
* the Larger Works (as defined below), to deal in both
14+
*
15+
* (a) the Software, and
16+
*
17+
* (b) any piece of software and/or hardware listed in the lrgrwrks.txt file if
18+
* one is included with the Software each a "Larger Work" to which the Software
19+
* is contributed by such licensors),
20+
*
21+
* without restriction, including without limitation the rights to copy, create
22+
* derivative works of, display, perform, and distribute the Software and make,
23+
* use, sell, offer for sale, import, export, have made, and have sold the
24+
* Software and the Larger Work(s), and to sublicense the foregoing rights on
25+
* either these or other terms.
26+
*
27+
* This license is subject to the following condition:
28+
*
29+
* The above copyright notice and either this complete permission notice or at a
30+
* minimum a reference to the UPL must be included in all copies or substantial
31+
* portions of the Software.
32+
*
33+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
34+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
35+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
36+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
37+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
38+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
39+
* SOFTWARE.
40+
*/
41+
package com.oracle.graal.python.nodes.bytecode;
42+
43+
import com.oracle.graal.python.runtime.exception.PythonControlFlowException;
44+
45+
public final class GeneratorReturnException extends PythonControlFlowException {
46+
private static final long serialVersionUID = -7509673125893533425L;
47+
48+
public final Object value;
49+
50+
public GeneratorReturnException(Object value) {
51+
this.value = value;
52+
}
53+
}

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/bytecode/GeneratorResult.java renamed to graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/bytecode/GeneratorYieldResult.java

Lines changed: 4 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -43,24 +43,14 @@
4343
import com.oracle.truffle.api.CompilerDirectives.ValueType;
4444

4545
@ValueType
46-
public final class GeneratorResult {
46+
public final class GeneratorYieldResult {
4747
public final int resumeBci;
4848
public final int resumeStackTop;
49-
public final boolean isReturn;
50-
public final Object value;
49+
public final Object yieldValue;
5150

52-
private GeneratorResult(int resumeBci, int resumeStackTop, boolean isReturn, Object value) {
51+
public GeneratorYieldResult(int resumeBci, int resumeStackTop, Object yieldValue) {
5352
this.resumeBci = resumeBci;
5453
this.resumeStackTop = resumeStackTop;
55-
this.isReturn = isReturn;
56-
this.value = value;
57-
}
58-
59-
public static GeneratorResult createYield(int resumeBci, int resumeStackTop, Object value) {
60-
return new GeneratorResult(resumeBci, resumeStackTop, false, value);
61-
}
62-
63-
public static GeneratorResult createReturn(Object value) {
64-
return new GeneratorResult(-1, -1, true, value);
54+
this.yieldValue = yieldValue;
6555
}
6656
}

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

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -769,7 +769,7 @@ private boolean profileCondition(boolean value, byte[] localBC, int bci, boolean
769769
if (!useCachedNodes) {
770770
return value;
771771
}
772-
int index = Byte.toUnsignedInt(localBC[bci + 2]) & Byte.toUnsignedInt(localBC[bci + 3]) << 8;
772+
int index = Byte.toUnsignedInt(localBC[bci + 2]) | Byte.toUnsignedInt(localBC[bci + 3]) << 8;
773773
int t = conditionProfiles[index];
774774
int f = conditionProfiles[index + 1];
775775
boolean val = value;
@@ -1427,7 +1427,7 @@ private Object bytecodeLoop(VirtualFrame virtualFrame, Frame localFrame, Bytecod
14271427
}
14281428
Object value = virtualFrame.getObject(stackTop);
14291429
if (isGeneratorOrCoroutine) {
1430-
return GeneratorResult.createReturn(value);
1430+
throw new GeneratorReturnException(value);
14311431
} else {
14321432
return value;
14331433
}
@@ -1852,7 +1852,7 @@ private Object bytecodeLoop(VirtualFrame virtualFrame, Frame localFrame, Bytecod
18521852
// Clear slots that were popped (if any)
18531853
clearFrameSlots(localFrame, stackTop + 1, initialStackTop);
18541854
}
1855-
return GeneratorResult.createYield(bci + 1, stackTop, value);
1855+
return new GeneratorYieldResult(bci + 1, stackTop, value);
18561856
}
18571857
case OpCodesConstants.RESUME_YIELD: {
18581858
mutableData.localException = PArguments.getException(PArguments.getGeneratorFrame(arguments));

0 commit comments

Comments
 (0)