Skip to content

Commit 4e3c20e

Browse files
committed
Create multiple call targets for generators
1 parent 45c7d73 commit 4e3c20e

File tree

6 files changed

+184
-42
lines changed

6 files changed

+184
-42
lines changed

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

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -142,7 +142,7 @@ abstract static class ResumeGeneratorNode extends Node {
142142
public abstract Object execute(VirtualFrame frame, PGenerator self, Object sendValue);
143143

144144
@Specialization(guards = "sameCallTarget(self.getCurrentCallTarget(), call.getCallTarget())", limit = "getCallSiteInlineCacheMaxDepth()")
145-
static Object cached(VirtualFrame frame, PGenerator self, Object sendValue,
145+
Object cached(VirtualFrame frame, PGenerator self, Object sendValue,
146146
@Cached("createDirectCall(self.getCurrentCallTarget())") CallTargetInvokeNode call,
147147
@Cached PRaiseNode raiseNode) {
148148
self.setRunning(true);
@@ -153,20 +153,25 @@ static Object cached(VirtualFrame frame, PGenerator self, Object sendValue,
153153
Object result;
154154
try {
155155
result = call.execute(frame, null, null, null, arguments);
156+
if (result == null) {
157+
self.markAsFinished();
158+
}
156159
} catch (PException e) {
157160
self.markAsFinished();
158161
throw e;
159162
} finally {
160163
self.setRunning(false);
161-
self.setNextCallTarget();
164+
if (!self.isFinished()) {
165+
self.setNextCallTarget(PythonLanguage.get(this));
166+
}
162167
}
163168
handleResult(self, result, raiseNode);
164169
return result;
165170
}
166171

167172
@Specialization(replaces = "cached")
168173
@Megamorphic
169-
static Object generic(VirtualFrame frame, PGenerator self, Object sendValue,
174+
Object generic(VirtualFrame frame, PGenerator self, Object sendValue,
170175
@Cached ConditionProfile hasFrameProfile,
171176
@Cached GenericInvokeNode call,
172177
@Cached PRaiseNode raiseNode) {
@@ -182,12 +187,17 @@ static Object generic(VirtualFrame frame, PGenerator self, Object sendValue,
182187
} else {
183188
result = call.execute(self.getCurrentCallTarget(), arguments);
184189
}
190+
if (result == null) {
191+
self.markAsFinished();
192+
}
185193
} catch (PException e) {
186194
self.markAsFinished();
187195
throw e;
188196
} finally {
189197
self.setRunning(false);
190-
self.setNextCallTarget();
198+
if (!self.isFinished()) {
199+
self.setNextCallTarget(PythonLanguage.get(this));
200+
}
191201
}
192202
handleResult(self, result, raiseNode);
193203
return result;

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

Lines changed: 46 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
import com.oracle.graal.python.builtins.objects.function.PArguments;
3535
import com.oracle.graal.python.builtins.objects.iterator.PIntRangeIterator;
3636
import com.oracle.graal.python.builtins.objects.object.PythonBuiltinObject;
37+
import com.oracle.graal.python.nodes.bytecode.PBytecodeGeneratorRootNode;
3738
import com.oracle.graal.python.nodes.bytecode.PBytecodeRootNode;
3839
import com.oracle.graal.python.nodes.generator.AbstractYieldNode;
3940
import com.oracle.graal.python.nodes.generator.YieldFromNode;
@@ -42,6 +43,7 @@
4243
import com.oracle.graal.python.runtime.object.PythonObjectFactory;
4344
import com.oracle.truffle.api.Assumption;
4445
import com.oracle.truffle.api.CompilerAsserts;
46+
import com.oracle.truffle.api.CompilerDirectives;
4547
import com.oracle.truffle.api.CompilerDirectives.CompilationFinal;
4648
import com.oracle.truffle.api.RootCallTarget;
4749
import com.oracle.truffle.api.Truffle;
@@ -54,7 +56,6 @@ public final class PGenerator extends PythonBuiltinObject {
5456

5557
private String name;
5658
private String qualname;
57-
private final boolean usesBytecode;
5859
/**
5960
* Call targets with copies of the generator's AST. Each call target corresponds to one possible
6061
* entry point into the generator: the first call, and continuation for each yield. Each AST can
@@ -71,6 +72,8 @@ public final class PGenerator extends PythonBuiltinObject {
7172
private final Object iterator;
7273
private final boolean isPRangeIterator;
7374
private final GeneratorInfo generatorInfo;
75+
private final PBytecodeRootNode bytecodeRootNode;
76+
private final PBytecodeRootNode.FrameInfo frameInfo;
7477
// running means it is currently on the stack, not just started
7578
private boolean running;
7679

@@ -106,12 +109,12 @@ public static PGenerator create(PythonLanguage lang, String name, String qualnam
106109
}
107110
assignCells(generatorFrame, cellVarSlots, cellVarAssumptions);
108111
PArguments.setGeneratorFrameLocals(generatorFrameArguments, factory.createDictLocals(generatorFrame));
109-
return new PGenerator(lang, name, qualname, callTargets, generatorInfo, arguments, closure, iterator, false);
112+
return new PGenerator(lang, name, qualname, callTargets, generatorInfo, arguments, closure, iterator);
110113
}
111114

112-
public static PGenerator create(PythonLanguage lang, String name, String qualname, PBytecodeRootNode rootNode, RootCallTarget bytecodeCallTarget, Object[] arguments) {
115+
public static PGenerator create(PythonLanguage lang, String name, String qualname, PBytecodeRootNode rootNode, RootCallTarget[] callTargets, Object[] arguments) {
113116
rootNode.createGeneratorFrame(arguments);
114-
return new PGenerator(lang, name, qualname, new RootCallTarget[]{bytecodeCallTarget}, null, arguments, null, null, true);
117+
return new PGenerator(lang, name, qualname, rootNode, callTargets, arguments);
115118
}
116119

117120
@ExplodeLoop
@@ -131,7 +134,7 @@ private static void assignClosure(PCell[] closure, MaterializedFrame generatorFr
131134
}
132135

133136
private PGenerator(PythonLanguage lang, String name, String qualname, RootCallTarget[] callTargets, GeneratorInfo generatorInfo, Object[] arguments,
134-
PCell[] closure, Object iterator, boolean usesBytecode) {
137+
PCell[] closure, Object iterator) {
135138
super(PythonBuiltinClassType.PGenerator, PythonBuiltinClassType.PGenerator.getInstanceShape(lang));
136139
this.name = name;
137140
this.qualname = qualname;
@@ -143,11 +146,35 @@ private PGenerator(PythonLanguage lang, String name, String qualname, RootCallTa
143146
this.finished = false;
144147
this.iterator = iterator;
145148
this.isPRangeIterator = iterator instanceof PIntRangeIterator;
146-
this.usesBytecode = usesBytecode;
149+
this.bytecodeRootNode = null;
150+
this.frameInfo = null;
147151
}
148152

149-
public void setNextCallTarget() {
150-
if (!usesBytecode) {
153+
private PGenerator(PythonLanguage lang, String name, String qualname, PBytecodeRootNode rootNode, RootCallTarget[] callTargets, Object[] arguments) {
154+
super(PythonBuiltinClassType.PGenerator, PythonBuiltinClassType.PGenerator.getInstanceShape(lang));
155+
this.name = name;
156+
this.qualname = qualname;
157+
this.callTargets = callTargets;
158+
this.currentCallTarget = 0;
159+
this.arguments = arguments;
160+
this.finished = false;
161+
this.bytecodeRootNode = rootNode;
162+
this.frameInfo = (PBytecodeRootNode.FrameInfo) rootNode.getFrameDescriptor().getInfo();
163+
this.iterator = null;
164+
this.isPRangeIterator = false;
165+
this.closure = null;
166+
this.generatorInfo = null;
167+
}
168+
169+
public void setNextCallTarget(PythonLanguage language) {
170+
if (usesBytecode()) {
171+
currentCallTarget = getBci();
172+
if (callTargets[currentCallTarget] == null) {
173+
CompilerDirectives.transferToInterpreterAndInvalidate();
174+
PBytecodeGeneratorRootNode rootNode = new PBytecodeGeneratorRootNode(language, bytecodeRootNode, currentCallTarget, getStackTop());
175+
callTargets[currentCallTarget] = rootNode.getCallTarget();
176+
}
177+
} else {
151178
currentCallTarget = PArguments.getControlDataFromGeneratorArguments(getArguments()).getLastYieldIndex();
152179
}
153180
}
@@ -162,6 +189,7 @@ public RootCallTarget getCurrentCallTarget() {
162189
}
163190

164191
public AbstractYieldNode getCurrentYieldNode() {
192+
assert !usesBytecode();
165193
if (currentCallTarget == 0 || running || finished) {
166194
// Not stopped on a yield
167195
return null;
@@ -171,38 +199,36 @@ public AbstractYieldNode getCurrentYieldNode() {
171199
}
172200

173201
public boolean usesBytecode() {
174-
return usesBytecode;
202+
return bytecodeRootNode != null;
175203
}
176204

177205
public Object getYieldFrom() {
178-
if (!usesBytecode) {
206+
if (!usesBytecode()) {
179207
AbstractYieldNode currentYield = getCurrentYieldNode();
180208
if (currentYield instanceof YieldFromNode) {
181209
int iteratorSlot = ((YieldFromNode) currentYield).getIteratorSlot();
182210
return PArguments.getControlDataFromGeneratorArguments(arguments).getIteratorAt(iteratorSlot);
183211
}
184212
return null;
185213
} else {
186-
MaterializedFrame generatorFrame = PArguments.getGeneratorFrame(arguments);
187-
PBytecodeRootNode.FrameInfo info = (PBytecodeRootNode.FrameInfo) generatorFrame.getFrameDescriptor().getInfo();
188-
return info.getYieldFrom(generatorFrame);
214+
return frameInfo.getYieldFrom(PArguments.getGeneratorFrame(arguments));
189215
}
190216
}
191217

192218
public boolean isStarted() {
193-
return (currentCallTarget != 0 || usesBytecode && getBci() > 0) && !running;
219+
return currentCallTarget != 0 && !running;
194220
}
195221

196222
public int getBci() {
197-
MaterializedFrame generatorFrame = PArguments.getGeneratorFrame(arguments);
198-
PBytecodeRootNode.FrameInfo info = (PBytecodeRootNode.FrameInfo) generatorFrame.getFrameDescriptor().getInfo();
199-
return info.getBci(generatorFrame);
223+
return frameInfo.getBci(PArguments.getGeneratorFrame(arguments));
224+
}
225+
226+
public int getStackTop() {
227+
return frameInfo.getGeneratorStackTop(PArguments.getGeneratorFrame(arguments));
200228
}
201229

202230
public Object getReturnValue() {
203-
MaterializedFrame generatorFrame = PArguments.getGeneratorFrame(arguments);
204-
PBytecodeRootNode.FrameInfo info = (PBytecodeRootNode.FrameInfo) generatorFrame.getFrameDescriptor().getInfo();
205-
return info.getGeneratorReturnValue(generatorFrame);
231+
return frameInfo.getGeneratorReturnValue(PArguments.getGeneratorFrame(arguments));
206232
}
207233

208234
public Object[] getArguments() {

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

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@
4747
import com.oracle.graal.python.nodes.PRootNode;
4848
import com.oracle.graal.python.runtime.object.PythonObjectFactory;
4949
import com.oracle.truffle.api.CompilerAsserts;
50+
import com.oracle.truffle.api.CompilerDirectives.CompilationFinal;
5051
import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
5152
import com.oracle.truffle.api.RootCallTarget;
5253
import com.oracle.truffle.api.frame.FrameDescriptor;
@@ -55,17 +56,20 @@
5556

5657
public class PBytecodeGeneratorFunctionRootNode extends PRootNode {
5758
private final PBytecodeRootNode rootNode;
58-
private final RootCallTarget callTarget;
5959
private final String originalName;
6060

61+
@CompilationFinal(dimensions = 1) private final RootCallTarget[] callTargets;
62+
6163
@Child private PythonObjectFactory factory = PythonObjectFactory.create();
6264

6365
@TruffleBoundary
6466
public PBytecodeGeneratorFunctionRootNode(PythonLanguage language, FrameDescriptor frameDescriptor, PBytecodeRootNode rootNode, String originalName) {
6567
super(language, frameDescriptor);
6668
this.rootNode = rootNode;
6769
this.originalName = originalName;
68-
this.callTarget = rootNode.getCallTarget();
70+
// TODO compress somehow
71+
this.callTargets = new RootCallTarget[rootNode.getCodeUnit().code.length];
72+
this.callTargets[0] = rootNode.getCallTarget();
6973
}
7074

7175
@Override
@@ -75,11 +79,7 @@ public Object execute(VirtualFrame frame) {
7579
// This is passed from InvokeNode node
7680
PFunction generatorFunction = PArguments.getGeneratorFunction(arguments);
7781
assert generatorFunction != null;
78-
return factory.createGenerator(generatorFunction.getName(), generatorFunction.getQualname(), rootNode, callTarget, arguments);
79-
}
80-
81-
public PBytecodeRootNode getFunctionRootNode() {
82-
return rootNode;
82+
return factory.createGenerator(generatorFunction.getName(), generatorFunction.getQualname(), rootNode, callTargets, arguments);
8383
}
8484

8585
@Override
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
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.PythonLanguage;
44+
import com.oracle.graal.python.builtins.objects.function.Signature;
45+
import com.oracle.graal.python.nodes.PRootNode;
46+
import com.oracle.graal.python.runtime.ExecutionContext;
47+
import com.oracle.truffle.api.CompilerAsserts;
48+
import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
49+
import com.oracle.truffle.api.frame.VirtualFrame;
50+
import com.oracle.truffle.api.source.SourceSection;
51+
52+
public class PBytecodeGeneratorRootNode extends PRootNode {
53+
private final PBytecodeRootNode rootNode;
54+
private final int resumeBci;
55+
private final int resumeStackTop;
56+
57+
@Child private ExecutionContext.CalleeContext calleeContext = ExecutionContext.CalleeContext.create();
58+
59+
@TruffleBoundary
60+
public PBytecodeGeneratorRootNode(PythonLanguage language, PBytecodeRootNode rootNode, int resumeBci, int resumeStackTop) {
61+
super(language, rootNode.getFrameDescriptor());
62+
this.rootNode = rootNode;
63+
this.resumeBci = resumeBci;
64+
this.resumeStackTop = resumeStackTop;
65+
}
66+
67+
@Override
68+
public Object execute(VirtualFrame frame) {
69+
calleeContext.enter(frame);
70+
try {
71+
return rootNode.executeFromBci(frame, resumeBci, resumeStackTop);
72+
} finally {
73+
calleeContext.exit(frame, this);
74+
}
75+
}
76+
77+
@Override
78+
public String getName() {
79+
return rootNode.getName();
80+
}
81+
82+
@Override
83+
public String toString() {
84+
CompilerAsserts.neverPartOfCompilation();
85+
return "<bytecode " + rootNode.getName() + ">";
86+
}
87+
88+
@Override
89+
public Signature getSignature() {
90+
return rootNode.getSignature();
91+
}
92+
93+
@Override
94+
public boolean isPythonInternal() {
95+
return rootNode.isPythonInternal();
96+
}
97+
98+
@Override
99+
public SourceSection getSourceSection() {
100+
return rootNode.getSourceSection();
101+
}
102+
}

0 commit comments

Comments
 (0)