Skip to content

Commit 470d500

Browse files
committed
first implementation of yield..from node
1 parent e8dcb2d commit 470d500

File tree

7 files changed

+324
-16
lines changed

7 files changed

+324
-16
lines changed

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/NodeFactory.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,7 @@
7878
import com.oracle.graal.python.nodes.function.ClassBodyRootNode;
7979
import com.oracle.graal.python.nodes.function.FunctionRootNode;
8080
import com.oracle.graal.python.nodes.generator.DictConcatNode;
81+
import com.oracle.graal.python.nodes.generator.YieldFromNode;
8182
import com.oracle.graal.python.nodes.generator.YieldNode;
8283
import com.oracle.graal.python.nodes.literal.BooleanLiteralNode;
8384
import com.oracle.graal.python.nodes.literal.BuiltinsLiteralNode;
@@ -215,6 +216,10 @@ public YieldNode createYield(ExpressionNode right, FrameSlot returnSlot) {
215216
return new YieldNode(createWriteLocal(right, returnSlot));
216217
}
217218

219+
public YieldFromNode createYieldFrom(ExpressionNode right, FrameSlot returnSlot) {
220+
return new YieldFromNode(right, (WriteNode) createWriteLocal(null, returnSlot));
221+
}
222+
218223
public ExpressionNode createIntegerLiteral(int value) {
219224
return new IntegerLiteralNode(value);
220225
}

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/attributes/GetAttributeNode.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,12 @@ public final String getKey() {
7373
return key;
7474
}
7575

76+
public abstract int executeInt(Object object);
77+
78+
public abstract boolean executeBoolean(Object object);
79+
80+
public abstract Object executeObject(Object object);
81+
7682
public final StatementNode makeWriteNode(ExpressionNode rhs) {
7783
return SetAttributeNode.create(key, getObject(), rhs);
7884
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
package com.oracle.graal.python.nodes.generator;
2+
3+
import com.oracle.graal.python.nodes.expression.ExpressionNode;
4+
import com.oracle.truffle.api.CompilerDirectives.CompilationFinal;
5+
import com.oracle.truffle.api.profiles.BranchProfile;
6+
7+
public abstract class AbstractYieldNode extends ExpressionNode {
8+
@CompilationFinal protected int flagSlot;
9+
10+
protected final BranchProfile gotException = BranchProfile.create();
11+
protected final BranchProfile gotValue = BranchProfile.create();
12+
protected final BranchProfile gotNothing = BranchProfile.create();
13+
14+
public void setFlagSlot(int slot) {
15+
this.flagSlot = slot;
16+
}
17+
18+
public AbstractYieldNode() {
19+
super();
20+
}
21+
22+
}
Lines changed: 249 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,249 @@
1+
/*
2+
* Copyright (c) 2017, 2018, Oracle and/or its affiliates.
3+
* Copyright (c) 2013, Regents of the University of California
4+
*
5+
* All rights reserved.
6+
*
7+
* Redistribution and use in source and binary forms, with or without modification, are
8+
* permitted provided that the following conditions are met:
9+
*
10+
* 1. Redistributions of source code must retain the above copyright notice, this list of
11+
* conditions and the following disclaimer.
12+
* 2. Redistributions in binary form must reproduce the above copyright notice, this list of
13+
* conditions and the following disclaimer in the documentation and/or other materials provided
14+
* with the distribution.
15+
*
16+
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS
17+
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18+
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
19+
* COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
20+
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
21+
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
22+
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
23+
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
24+
* OF THE POSSIBILITY OF SUCH DAMAGE.
25+
*/
26+
package com.oracle.graal.python.nodes.generator;
27+
28+
import com.oracle.graal.python.builtins.PythonBuiltinClassType;
29+
import com.oracle.graal.python.builtins.objects.PNone;
30+
import com.oracle.graal.python.builtins.objects.function.PArguments;
31+
import com.oracle.graal.python.builtins.objects.function.PKeyword;
32+
import com.oracle.graal.python.nodes.attributes.GetAttributeNode;
33+
import com.oracle.graal.python.nodes.attributes.LookupInheritedAttributeNode;
34+
import com.oracle.graal.python.nodes.call.CallNode;
35+
import com.oracle.graal.python.nodes.call.special.LookupAndCallBinaryNode;
36+
import com.oracle.graal.python.nodes.control.GetIteratorNode;
37+
import com.oracle.graal.python.nodes.control.GetNextNode;
38+
import com.oracle.graal.python.nodes.expression.ExpressionNode;
39+
import com.oracle.graal.python.nodes.frame.WriteNode;
40+
import com.oracle.graal.python.nodes.object.GetClassNode;
41+
import com.oracle.graal.python.nodes.object.IsBuiltinClassProfile;
42+
import com.oracle.graal.python.runtime.exception.PException;
43+
import com.oracle.graal.python.runtime.exception.YieldException;
44+
import com.oracle.truffle.api.CompilerDirectives;
45+
import com.oracle.truffle.api.CompilerDirectives.CompilationFinal;
46+
import com.oracle.truffle.api.frame.VirtualFrame;
47+
import com.oracle.truffle.api.profiles.BranchProfile;
48+
49+
public class YieldFromNode extends AbstractYieldNode implements GeneratorControlNode {
50+
@Child private GetIteratorNode iter = GetIteratorNode.create();
51+
@Child private GetNextNode next = GetNextNode.create();
52+
@Child private GeneratorAccessNode access = GeneratorAccessNode.create();
53+
54+
@Child private GetAttributeNode getValue;
55+
56+
@Child private LookupInheritedAttributeNode getCloseNode;
57+
@Child private CallNode callCloseNode;
58+
59+
@Child private LookupInheritedAttributeNode getThrowNode;
60+
@Child private CallNode callThrowNode;
61+
@Child private GetClassNode getExceptionClassNode;
62+
63+
@Child private LookupAndCallBinaryNode callSendNode;
64+
65+
private final IsBuiltinClassProfile stopIterProfile1 = IsBuiltinClassProfile.create();
66+
private final IsBuiltinClassProfile stopIterProfile2 = IsBuiltinClassProfile.create();
67+
private final IsBuiltinClassProfile stopIterProfile3 = IsBuiltinClassProfile.create();
68+
private final IsBuiltinClassProfile genExitProfile = IsBuiltinClassProfile.create();
69+
70+
@CompilationFinal private int iteratorSlot;
71+
72+
private final BranchProfile noThrow = BranchProfile.create();
73+
74+
@Child private ExpressionNode right;
75+
@Child private WriteNode yieldWriteNode;
76+
77+
public YieldFromNode(ExpressionNode right, WriteNode yieldSlot) {
78+
this.right = right;
79+
this.yieldWriteNode = yieldSlot;
80+
}
81+
82+
@Override
83+
public Object execute(VirtualFrame frame) {
84+
Object _i = access.getIterator(frame, iteratorSlot);
85+
Object _y = null;
86+
if (_i == null) {
87+
// _i = iter(EXPR)
88+
// ....try:
89+
// ........_y = next(_i)
90+
// ....except StopIteration as _e:
91+
// ........_r = _e.value
92+
_i = iter.executeWith(right.execute(frame));
93+
try {
94+
_y = next.execute(_i);
95+
} catch (PException e) {
96+
e.expectStopIteration(stopIterProfile1);
97+
return getGetValue().executeObject(e.getExceptionObject());
98+
}
99+
access.setIterator(frame, iteratorSlot, _i);
100+
}
101+
// else:
102+
// ....while 1:
103+
// ........try:
104+
// ............_s = yield _y
105+
while (true) {
106+
if (!access.isActive(frame, flagSlot)) {
107+
access.setActive(frame, flagSlot, true);
108+
yieldWriteNode.doWrite(frame, _y);
109+
throw YieldException.INSTANCE;
110+
} else {
111+
access.setActive(frame, flagSlot, false);
112+
_y = null;
113+
// resuming from yield, write _s
114+
Object _s = PArguments.getSpecialArgument(frame);
115+
if (_s instanceof PException) {
116+
gotException.enter();
117+
PException _e = (PException) _s;
118+
// except GeneratorExit as _e:
119+
// ....try:
120+
// ........_m = _i.close
121+
// ....except AttributeError:
122+
// ........pass
123+
// ....else:
124+
// ........_m()
125+
// ....raise _e
126+
if (genExitProfile.profileException(_e, PythonBuiltinClassType.GeneratorExit)) {
127+
access.setIterator(frame, iteratorSlot, null);
128+
Object close = getGetCloseNode().execute(_i);
129+
if (close != PNone.NO_VALUE) {
130+
getCallCloseNode().execute(frame, close, new Object[]{_i}, PKeyword.EMPTY_KEYWORDS);
131+
}
132+
throw _e;
133+
}
134+
// except BaseException as _e:
135+
// ...._x = sys.exc_info()
136+
// ....try:
137+
// ........_m = _i.throw
138+
// ....except AttributeError:
139+
// ........raise _e
140+
// ....else:
141+
// ........try:
142+
// ............_y = _m(*_x)
143+
// ........except StopIteration as _e:
144+
// ............_r = _e.value
145+
// ............break
146+
Object _m = getGetThrowNode().execute(_i);
147+
if (_m == PNone.NO_VALUE) {
148+
noThrow.enter();
149+
access.setIterator(frame, iteratorSlot, null);
150+
throw _e;
151+
} else {
152+
try {
153+
_y = getCallThrowNode().execute(frame, _m,
154+
new Object[]{_i, getExceptionClassNode().execute(_s), ((PException) _s).getExceptionObject(),
155+
((PException) _s).getExceptionObject().getTraceback(factory())},
156+
PKeyword.EMPTY_KEYWORDS);
157+
} catch (PException _e2) {
158+
access.setIterator(frame, iteratorSlot, null);
159+
_e2.expectStopIteration(stopIterProfile2);
160+
return getGetValue().executeObject(_e2.getExceptionObject());
161+
}
162+
}
163+
} else {
164+
// else:
165+
// ....try:
166+
// ........if _s is None:
167+
// ............_y = next(_i)
168+
// ........else:
169+
// ............_y = _i.send(_s)
170+
// ........except StopIteration as _e:
171+
// ............_r = _e.value
172+
// ............break
173+
try {
174+
if (_s == null) {
175+
gotNothing.enter();
176+
_y = next.execute(_i);
177+
} else {
178+
_y = getCallSendNode().executeObject(_i, _s);
179+
}
180+
} catch (PException _e) {
181+
access.setIterator(frame, iteratorSlot, null);
182+
_e.expectStopIteration(stopIterProfile3);
183+
return getGetValue().executeObject(_e.getExceptionObject());
184+
}
185+
}
186+
}
187+
}
188+
}
189+
190+
private GetAttributeNode getGetValue() {
191+
if (getValue == null) {
192+
CompilerDirectives.transferToInterpreterAndInvalidate();
193+
getValue = insert(GetAttributeNode.create("value", null));
194+
}
195+
return getValue;
196+
}
197+
198+
private GetClassNode getExceptionClassNode() {
199+
if (getExceptionClassNode == null) {
200+
CompilerDirectives.transferToInterpreterAndInvalidate();
201+
getExceptionClassNode = insert(GetClassNode.create());
202+
}
203+
return getExceptionClassNode;
204+
}
205+
206+
private LookupInheritedAttributeNode getGetCloseNode() {
207+
if (getCloseNode == null) {
208+
CompilerDirectives.transferToInterpreterAndInvalidate();
209+
getCloseNode = insert(LookupInheritedAttributeNode.create("close"));
210+
}
211+
return getCloseNode;
212+
}
213+
214+
private CallNode getCallCloseNode() {
215+
if (callCloseNode == null) {
216+
CompilerDirectives.transferToInterpreterAndInvalidate();
217+
callCloseNode = insert(CallNode.create());
218+
}
219+
return callCloseNode;
220+
}
221+
222+
private LookupInheritedAttributeNode getGetThrowNode() {
223+
if (getThrowNode == null) {
224+
CompilerDirectives.transferToInterpreterAndInvalidate();
225+
getThrowNode = insert(LookupInheritedAttributeNode.create("throw"));
226+
}
227+
return getThrowNode;
228+
}
229+
230+
private CallNode getCallThrowNode() {
231+
if (callThrowNode == null) {
232+
CompilerDirectives.transferToInterpreterAndInvalidate();
233+
callThrowNode = insert(CallNode.create());
234+
}
235+
return callThrowNode;
236+
}
237+
238+
private LookupAndCallBinaryNode getCallSendNode() {
239+
if (callSendNode == null) {
240+
CompilerDirectives.transferToInterpreterAndInvalidate();
241+
callSendNode = insert(LookupAndCallBinaryNode.create("send"));
242+
}
243+
return callSendNode;
244+
}
245+
246+
public void setIteratorSlot(int slot) {
247+
this.iteratorSlot = slot;
248+
}
249+
}

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/generator/YieldNode.java

Lines changed: 1 addition & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -28,25 +28,16 @@
2828
import com.oracle.graal.python.builtins.objects.PNone;
2929
import com.oracle.graal.python.builtins.objects.function.PArguments;
3030
import com.oracle.graal.python.nodes.PNode;
31-
import com.oracle.graal.python.nodes.expression.ExpressionNode;
3231
import com.oracle.graal.python.nodes.statement.StatementNode;
3332
import com.oracle.graal.python.runtime.exception.PException;
3433
import com.oracle.graal.python.runtime.exception.YieldException;
35-
import com.oracle.truffle.api.CompilerDirectives.CompilationFinal;
3634
import com.oracle.truffle.api.frame.VirtualFrame;
37-
import com.oracle.truffle.api.profiles.BranchProfile;
3835

39-
public class YieldNode extends ExpressionNode implements GeneratorControlNode {
36+
public class YieldNode extends AbstractYieldNode implements GeneratorControlNode {
4037

4138
@Child private StatementNode right;
4239
@Child private GeneratorAccessNode access = GeneratorAccessNode.create();
4340

44-
@CompilationFinal private int flagSlot;
45-
46-
private final BranchProfile gotException = BranchProfile.create();
47-
private final BranchProfile gotValue = BranchProfile.create();
48-
private final BranchProfile gotNothing = BranchProfile.create();
49-
5041
public YieldNode(StatementNode right) {
5142
this.right = right;
5243
}
@@ -77,8 +68,4 @@ public Object execute(VirtualFrame frame) {
7768
throw YieldException.INSTANCE;
7869
}
7970
}
80-
81-
public void setFlagSlot(int slot) {
82-
this.flagSlot = slot;
83-
}
8471
}

0 commit comments

Comments
 (0)