Skip to content

Commit 31152ec

Browse files
author
Adam Hrbac
committed
Use new type for asyncgens and add athrow
1 parent 6436c27 commit 31152ec

File tree

16 files changed

+471
-73
lines changed

16 files changed

+471
-73
lines changed

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/Python3Core.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@
5656
import java.util.logging.Level;
5757

5858
import com.oracle.graal.python.builtins.objects.asyncio.AsyncGenSendBuiltins;
59+
import com.oracle.graal.python.builtins.objects.asyncio.AsyncGenThrowBuiltins;
5960
import com.oracle.graal.python.builtins.objects.asyncio.AsyncGeneratorBuiltins;
6061
import org.graalvm.nativeimage.ImageInfo;
6162

@@ -717,7 +718,8 @@ private static PythonBuiltins[] initializeBuiltins(boolean nativeAccessAllowed)
717718
// _asyncio
718719
new AsyncioModuleBuiltins(),
719720
new AsyncGeneratorBuiltins(),
720-
new AsyncGenSendBuiltins()));
721+
new AsyncGenSendBuiltins(),
722+
new AsyncGenThrowBuiltins()));
721723
if (hasProfilerTool) {
722724
builtins.add(new LsprofModuleBuiltins());
723725
builtins.add(LsprofModuleBuiltins.newProfilerBuiltins());

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/asyncio/AsyncGenSendBuiltins.java

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -53,14 +53,14 @@
5353
import com.oracle.graal.python.builtins.PythonBuiltins;
5454
import com.oracle.graal.python.builtins.objects.PNone;
5555
import com.oracle.graal.python.builtins.objects.generator.CommonGeneratorBuiltins;
56-
import com.oracle.graal.python.builtins.objects.generator.PGenerator;
5756
import com.oracle.graal.python.nodes.ErrorMessages;
5857
import com.oracle.graal.python.nodes.PRaiseNode;
5958
import com.oracle.graal.python.nodes.function.PythonBuiltinBaseNode;
6059
import com.oracle.graal.python.nodes.function.PythonBuiltinNode;
6160
import com.oracle.graal.python.nodes.function.builtins.PythonBinaryBuiltinNode;
6261
import com.oracle.graal.python.nodes.function.builtins.PythonUnaryBuiltinNode;
6362
import com.oracle.graal.python.nodes.object.BuiltinClassProfiles;
63+
import com.oracle.graal.python.runtime.PAsyncGen;
6464
import com.oracle.graal.python.runtime.exception.PException;
6565
import com.oracle.truffle.api.dsl.Bind;
6666
import com.oracle.truffle.api.dsl.Cached;
@@ -139,19 +139,25 @@ public Object send(VirtualFrame frame, PAsyncGenASend self, Object sent,
139139
}
140140
}
141141

142-
private static PException handleAGError(PGenerator self, PException exception,
143-
Node inliningTarget,
144-
BuiltinClassProfiles.IsBuiltinObjectProfile isStopAsyncIteration,
145-
BuiltinClassProfiles.IsBuiltinObjectProfile isGeneratorExit) {
142+
/*
143+
* The following two functions are the equivalent of async_gen_unwrap_value. The assumption made
144+
* is that gen_send and throw of CPython will not return NULL unless they also set an error. If
145+
* a PException happens, handleAGError is used, otherwise, unwrapAGYield is used.
146+
*/
147+
148+
static PException handleAGError(PAsyncGen self, PException exception,
149+
Node inliningTarget,
150+
BuiltinClassProfiles.IsBuiltinObjectProfile isStopAsyncIteration,
151+
BuiltinClassProfiles.IsBuiltinObjectProfile isGeneratorExit) {
146152
if (isStopAsyncIteration.profileException(inliningTarget, exception, PythonBuiltinClassType.StopAsyncIteration) ||
147153
isGeneratorExit.profileException(inliningTarget, exception, PythonBuiltinClassType.GeneratorExit)) {
148-
self.markAsFinished();
154+
self.markClosed();
149155
}
150156
self.setRunningAsync(false);
151157
return exception;
152158
}
153159

154-
private static Object unwrapAGYield(PGenerator self, Object result,
160+
static Object unwrapAGYield(PAsyncGen self, Object result,
155161
Node inliningTarget,
156162
BuiltinClassProfiles.IsBuiltinObjectProfile isAGWrappedValue,
157163
PRaiseNode raise) {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,253 @@
1+
package com.oracle.graal.python.builtins.objects.asyncio;
2+
3+
import static com.oracle.graal.python.builtins.objects.asyncio.PAsyncGenASend.AwaitableState;
4+
import static com.oracle.graal.python.nodes.ErrorMessages.GENERATOR_IGNORED_EXIT;
5+
import static com.oracle.graal.python.nodes.ErrorMessages.SEND_NON_NONE_TO_UNSTARTED_GENERATOR;
6+
import static com.oracle.graal.python.nodes.SpecialMethodNames.J___AWAIT__;
7+
import static com.oracle.graal.python.nodes.SpecialMethodNames.J___ITER__;
8+
import static com.oracle.graal.python.nodes.SpecialMethodNames.J___NEXT__;
9+
10+
import java.util.List;
11+
12+
import com.oracle.graal.python.builtins.Builtin;
13+
import com.oracle.graal.python.builtins.CoreFunctions;
14+
import com.oracle.graal.python.builtins.PythonBuiltinClassType;
15+
import com.oracle.graal.python.builtins.PythonBuiltins;
16+
import com.oracle.graal.python.builtins.objects.PNone;
17+
import com.oracle.graal.python.builtins.objects.generator.CommonGeneratorBuiltins;
18+
import com.oracle.graal.python.nodes.ErrorMessages;
19+
import com.oracle.graal.python.nodes.PRaiseNode;
20+
import com.oracle.graal.python.nodes.function.PythonBuiltinBaseNode;
21+
import com.oracle.graal.python.nodes.function.PythonBuiltinNode;
22+
import com.oracle.graal.python.nodes.function.builtins.PythonBinaryBuiltinNode;
23+
import com.oracle.graal.python.nodes.function.builtins.PythonUnaryBuiltinNode;
24+
import com.oracle.graal.python.nodes.object.BuiltinClassProfiles;
25+
import com.oracle.graal.python.runtime.PAsyncGen;
26+
import com.oracle.graal.python.runtime.exception.PException;
27+
import com.oracle.truffle.api.dsl.Bind;
28+
import com.oracle.truffle.api.dsl.Cached;
29+
import com.oracle.truffle.api.dsl.GenerateNodeFactory;
30+
import com.oracle.truffle.api.dsl.NeverDefault;
31+
import com.oracle.truffle.api.dsl.NodeFactory;
32+
import com.oracle.truffle.api.dsl.Specialization;
33+
import com.oracle.truffle.api.frame.VirtualFrame;
34+
import com.oracle.truffle.api.nodes.Node;
35+
36+
@CoreFunctions(extendClasses = PythonBuiltinClassType.PAsyncGenAThrow)
37+
public class AsyncGenThrowBuiltins extends PythonBuiltins {
38+
@Override
39+
protected List<? extends NodeFactory<? extends PythonBuiltinBaseNode>> getNodeFactories() {
40+
return AsyncGenThrowBuiltinsFactory.getFactories();
41+
}
42+
43+
@Builtin(name = J___AWAIT__, minNumOfPositionalArgs = 1, declaresExplicitSelf = true)
44+
@GenerateNodeFactory
45+
public abstract static class Await extends PythonUnaryBuiltinNode {
46+
@Specialization
47+
public Object doAwait(PAsyncGenAThrow self) {
48+
return self;
49+
}
50+
}
51+
52+
@Builtin(name = J___ITER__, minNumOfPositionalArgs = 1, declaresExplicitSelf = true)
53+
@GenerateNodeFactory
54+
public abstract static class Iter extends PythonUnaryBuiltinNode {
55+
@Specialization
56+
public Object doIter(PAsyncGenAThrow self) {
57+
return self;
58+
}
59+
}
60+
61+
@Builtin(name = J___NEXT__, minNumOfPositionalArgs = 1, declaresExplicitSelf = true)
62+
@GenerateNodeFactory
63+
public abstract static class Next extends PythonUnaryBuiltinNode {
64+
@Specialization
65+
public Object doSend(VirtualFrame frame, PAsyncGenAThrow self,
66+
@Cached Send send) {
67+
return send.execute(frame, self, PNone.NONE);
68+
}
69+
}
70+
71+
@Builtin(name = "send", minNumOfPositionalArgs = 2, declaresExplicitSelf = true)
72+
@GenerateNodeFactory
73+
public abstract static class Send extends PythonBinaryBuiltinNode {
74+
@Specialization
75+
public Object send(VirtualFrame frame, PAsyncGenAThrow self, Object sent,
76+
@Bind("this") Node inliningTarget,
77+
@Cached PRaiseNode raiseReuse,
78+
@Cached PRaiseNode raiseAlreadyRunning,
79+
@Cached PRaiseNode raiseStopAsyncIteraion,
80+
@Cached PRaiseNode raiseNonNodeToNewCoro,
81+
@Cached CommonGeneratorBuiltins.ThrowNode throwNode,
82+
@Cached BuiltinClassProfiles.IsBuiltinObjectProfile isAGWrappedValue,
83+
@Cached BuiltinClassProfiles.IsBuiltinObjectProfile isStopAsyncIter,
84+
@Cached BuiltinClassProfiles.IsBuiltinObjectProfile isGeneratorExit,
85+
@Cached PRaiseNode raiseIgnoreExit,
86+
@Cached PRaiseNode raiseStopIteration,
87+
@Cached CommonGeneratorBuiltins.SendNode sendNode) {
88+
PAsyncGen gen = self.receiver;
89+
Object retval;
90+
91+
if (self.getState() == AwaitableState.CLOSED) {
92+
throw raiseReuse.raise(PythonBuiltinClassType.RuntimeError, ErrorMessages.CANNOT_REUSE_ATHROW);
93+
}
94+
95+
// CPython checks for gi_frame_state here, but we don't have gi_frame_state.
96+
// This works for any testcase I could come up with.
97+
// https://github.com/python/cpython/blob/main/Objects/genobject.c#L2082-L2086
98+
if (self.receiver.isFinished()) {
99+
self.setState(AwaitableState.CLOSED);
100+
throw raiseStopIteration.raise(PythonBuiltinClassType.StopIteration);
101+
}
102+
103+
if (self.getState() == AwaitableState.INIT) {
104+
if (gen.isRunningAsync()) {
105+
self.setState(AwaitableState.CLOSED);
106+
throw raiseAlreadyRunning.raise(PythonBuiltinClassType.RuntimeError); // todo
107+
// error
108+
// msg
109+
}
110+
111+
if (gen.isClosed()) {
112+
self.setState(AwaitableState.CLOSED);
113+
throw raiseStopAsyncIteraion.raise(PythonBuiltinClassType.StopAsyncIteration);
114+
}
115+
116+
if (sent != PNone.NONE) {
117+
throw raiseNonNodeToNewCoro.raise(PythonBuiltinClassType.RuntimeError, SEND_NON_NONE_TO_UNSTARTED_GENERATOR);
118+
}
119+
120+
self.setState(AwaitableState.ITER);
121+
gen.setRunningAsync(true);
122+
123+
if (self.arg1 == null) {
124+
// aclose() mode
125+
gen.markClosed();
126+
127+
try {
128+
retval = throwNode.execute(frame, gen, PythonBuiltinClassType.GeneratorExit, PNone.NO_VALUE, PNone.NO_VALUE);
129+
} catch (PException e) {
130+
throw checkError(self, gen, e, inliningTarget, isStopAsyncIter, isGeneratorExit, raiseStopIteration);
131+
}
132+
if (isAGWrappedValue.profileObject(inliningTarget, retval, PythonBuiltinClassType.PAsyncGenAWrappedValue)) {
133+
throw yieldClose(self, gen, raiseIgnoreExit);
134+
}
135+
} else {
136+
// athrow mode
137+
try {
138+
retval = throwNode.execute(frame, gen, self.arg1, self.arg2, self.arg3);
139+
} catch (PException e) {
140+
PException exception = AsyncGenSendBuiltins.handleAGError(gen, e, inliningTarget, isStopAsyncIter, isGeneratorExit);
141+
throw checkError(self, gen, exception, inliningTarget, isStopAsyncIter, isGeneratorExit, raiseStopIteration);
142+
}
143+
return AsyncGenSendBuiltins.unwrapAGYield(gen, retval, inliningTarget, isAGWrappedValue, raiseStopIteration);
144+
}
145+
}
146+
147+
// getState() == ITER
148+
try {
149+
retval = sendNode.execute(frame, gen, sent);
150+
} catch (PException e) {
151+
if (self.arg1 != null) {
152+
throw AsyncGenSendBuiltins.handleAGError(gen, e, inliningTarget, isStopAsyncIter, isGeneratorExit);
153+
} else {
154+
// aclose
155+
throw checkError(self, gen, e, inliningTarget, isStopAsyncIter, isGeneratorExit, raiseStopIteration);
156+
}
157+
}
158+
if (self.arg1 != null) {
159+
return AsyncGenSendBuiltins.unwrapAGYield(gen, retval, inliningTarget, isAGWrappedValue, raiseStopIteration);
160+
} else {
161+
// aclose
162+
if (isAGWrappedValue.profileObject(inliningTarget, retval, PythonBuiltinClassType.PAsyncGenAWrappedValue)) {
163+
throw yieldClose(self, gen, raiseIgnoreExit);
164+
} else {
165+
return retval;
166+
}
167+
}
168+
}
169+
170+
static PException yieldClose(PAsyncGenAThrow athrow, PAsyncGen gen,
171+
PRaiseNode raiseIgnoreExit) {
172+
gen.setRunningAsync(false);
173+
athrow.setState(AwaitableState.CLOSED);
174+
return raiseIgnoreExit.raise(PythonBuiltinClassType.RuntimeError, GENERATOR_IGNORED_EXIT);
175+
}
176+
177+
static PException checkError(PAsyncGenAThrow athrow, PAsyncGen gen, PException exception,
178+
Node inliningTarget,
179+
BuiltinClassProfiles.IsBuiltinObjectProfile isStopAsyncIter,
180+
BuiltinClassProfiles.IsBuiltinObjectProfile isGenExit,
181+
PRaiseNode raiseStopIteration) {
182+
gen.setRunningAsync(false);
183+
athrow.setState(AwaitableState.CLOSED);
184+
if (athrow.arg1 == null && (isStopAsyncIter.profileException(inliningTarget, exception, PythonBuiltinClassType.StopAsyncIteration) ||
185+
isGenExit.profileException(inliningTarget, exception, PythonBuiltinClassType.GeneratorExit))) {
186+
return raiseStopIteration.raise(PythonBuiltinClassType.StopIteration);
187+
}
188+
return exception;
189+
}
190+
}
191+
192+
@Builtin(name = "throw", minNumOfPositionalArgs = 2, maxNumOfPositionalArgs = 4, declaresExplicitSelf = true)
193+
@GenerateNodeFactory
194+
public abstract static class Throw extends PythonBuiltinNode {
195+
public abstract Object execute(VirtualFrame frame, PAsyncGenAThrow self, Object arg1, Object arg2, Object arg3);
196+
197+
@NeverDefault
198+
public static Throw create() {
199+
return AsyncGenThrowBuiltinsFactory.ThrowFactory.create(null);
200+
}
201+
202+
@Specialization
203+
public Object doThrow(VirtualFrame frame, PAsyncGenAThrow self, Object arg1, Object arg2, Object arg3,
204+
@Bind("this") Node inliningTarget,
205+
@Cached PRaiseNode raiseReuse,
206+
@Cached CommonGeneratorBuiltins.ThrowNode throwNode,
207+
@Cached BuiltinClassProfiles.IsBuiltinObjectProfile isStopAsyncIteration,
208+
@Cached BuiltinClassProfiles.IsBuiltinObjectProfile isGeneratorExit,
209+
@Cached BuiltinClassProfiles.IsBuiltinObjectProfile isAGWrappedValue,
210+
@Cached PRaiseNode raiseStopIteration,
211+
@Cached PRaiseNode raiseIgnoredExit) {
212+
Object retval;
213+
214+
if (self.getState() == AwaitableState.CLOSED) {
215+
throw raiseReuse.raise(PythonBuiltinClassType.RuntimeError, ErrorMessages.CANNOT_REUSE_ATHROW);
216+
}
217+
218+
try {
219+
retval = throwNode.execute(frame, self.receiver, arg1, arg2, arg3);
220+
} catch (PException e) {
221+
if (self.arg1 != null) {
222+
throw AsyncGenSendBuiltins.handleAGError(self.receiver, e, inliningTarget, isStopAsyncIteration, isGeneratorExit);
223+
} else {
224+
// aclose()
225+
if (isStopAsyncIteration.profileException(inliningTarget, e, PythonBuiltinClassType.StopAsyncIteration) ||
226+
isGeneratorExit.profileException(inliningTarget, e, PythonBuiltinClassType.GeneratorExit)) {
227+
throw raiseStopIteration.raise(PythonBuiltinClassType.StopIteration);
228+
}
229+
throw e;
230+
}
231+
}
232+
if (self.arg1 != null) {
233+
return AsyncGenSendBuiltins.unwrapAGYield(self.receiver, retval, inliningTarget, isAGWrappedValue, raiseStopIteration);
234+
} else {
235+
if (isAGWrappedValue.profileObject(inliningTarget, retval, PythonBuiltinClassType.PAsyncGenAWrappedValue)) {
236+
throw Send.yieldClose(self, self.receiver, raiseIgnoredExit);
237+
}
238+
return retval;
239+
}
240+
}
241+
}
242+
243+
@Builtin(name = "close", minNumOfPositionalArgs = 1, declaresExplicitSelf = true)
244+
@GenerateNodeFactory
245+
public abstract static class Close extends PythonUnaryBuiltinNode {
246+
@Specialization
247+
public static Object close(VirtualFrame frame, PAsyncGenAThrow self,
248+
@Cached Throw throwNode) {
249+
// TODO check on this
250+
return throwNode.execute(frame, self, PNone.NONE, PNone.NO_VALUE, PNone.NO_VALUE);
251+
}
252+
}
253+
}

0 commit comments

Comments
 (0)