@@ -130,18 +130,64 @@ private static Object[] prepareArguments(PGenerator self) {
130130 return arguments ;
131131 }
132132
133- private static Object resumeGenerator (PGenerator self , Object sendValue ) {
134- try {
133+ public static void checkResumable (PythonBuiltinBaseNode node , PGenerator self ) {
134+ if (self .isFinished ()) {
135+ throw node .raise (StopIteration );
136+ }
137+ if (self .isRunning ()) {
138+ throw node .raise (ValueError , ErrorMessages .GENERATOR_ALREADY_EXECUTING );
139+ }
140+ }
141+
142+ @ ImportStatic ({PGuards .class , PythonOptions .class })
143+ @ ReportPolymorphism
144+ abstract static class ResumeGeneratorNode extends Node {
145+ public abstract Object execute (VirtualFrame frame , PGenerator self , Object sendValue );
146+
147+ @ Specialization (guards = "sameCallTarget(self.getCurrentCallTarget(), call.getCallTarget())" , limit = "getCallSiteInlineCacheMaxDepth()" )
148+ public Object cached (VirtualFrame frame , PGenerator self , Object sendValue ,
149+ @ Cached ("createDirectCall(self.getCurrentCallTarget())" ) CallTargetInvokeNode call ) {
150+ self .setRunning (true );
151+ Object [] arguments = prepareArguments (self );
152+ if (sendValue != null ) {
153+ PArguments .setSpecialArgument (arguments , sendValue );
154+ }
155+ try {
156+ return call .execute (frame , null , null , arguments );
157+ } catch (PException e ) {
158+ self .markAsFinished ();
159+ throw e ;
160+ } finally {
161+ self .setRunning (false );
162+ self .setNextCallTarget ();
163+ }
164+ }
165+
166+ @ Specialization (replaces = "cached" )
167+ public Object generic (VirtualFrame frame , PGenerator self , Object sendValue ,
168+ @ Cached GenericInvokeNode call ) {
135169 self .setRunning (true );
136- PArguments .setSpecialArgument (self .getArguments (), sendValue );
137- return self .getCurrentCallTarget ().call (prepareArguments (self ));
138- } catch (PException e ) {
139- self .markAsFinished ();
140- throw e ;
141- } finally {
142- self .setRunning (false );
143- self .setNextCallTarget ();
144- PArguments .setSpecialArgument (self .getArguments (), null );
170+ Object [] arguments = prepareArguments (self );
171+ if (sendValue != null ) {
172+ PArguments .setSpecialArgument (arguments , sendValue );
173+ }
174+ try {
175+ return call .execute (frame , self .getCurrentCallTarget (), arguments );
176+ } catch (PException e ) {
177+ self .markAsFinished ();
178+ throw e ;
179+ } finally {
180+ self .setRunning (false );
181+ self .setNextCallTarget ();
182+ }
183+ }
184+
185+ protected static CallTargetInvokeNode createDirectCall (CallTarget target ) {
186+ return CallTargetInvokeNode .create (target , false , true );
187+ }
188+
189+ protected static boolean sameCallTarget (RootCallTarget target1 , CallTarget target2 ) {
190+ return target1 == target2 ;
145191 }
146192 }
147193
@@ -204,65 +250,12 @@ public Object iter(PGenerator self) {
204250
205251 @ Builtin (name = __NEXT__ , minNumOfPositionalArgs = 1 )
206252 @ GenerateNodeFactory
207- @ ReportPolymorphism
208253 public abstract static class NextNode extends PythonUnaryBuiltinNode {
209-
210- protected static CallTargetInvokeNode createDirectCall (CallTarget target ) {
211- return CallTargetInvokeNode .create (target , false , true );
212- }
213-
214- protected static GenericInvokeNode createIndirectCall () {
215- return GenericInvokeNode .create ();
216- }
217-
218- protected static boolean sameCallTarget (RootCallTarget target1 , CallTarget target2 ) {
219- return target1 == target2 ;
220- }
221-
222- @ Specialization (guards = "sameCallTarget(self.getCurrentCallTarget(), call.getCallTarget())" , limit = "getCallSiteInlineCacheMaxDepth()" )
223- public Object nextCached (VirtualFrame frame , PGenerator self ,
224- @ Cached ("createDirectCall(self.getCurrentCallTarget())" ) CallTargetInvokeNode call ,
225- @ Cached BranchProfile alreadyRunning ) {
226- if (self .isFinished ()) {
227- throw raise (StopIteration );
228- }
229- if (self .isRunning ()) {
230- alreadyRunning .enter ();
231- throw raise (ValueError , ErrorMessages .GENERATOR_ALREADY_EXECUTING );
232- }
233- try {
234- self .setRunning (true );
235- return call .execute (frame , null , null , prepareArguments (self ));
236- } catch (PException e ) {
237- self .markAsFinished ();
238- throw e ;
239- } finally {
240- self .setRunning (false );
241- self .setNextCallTarget ();
242- }
243- }
244-
245- @ Specialization (replaces = "nextCached" )
254+ @ Specialization
246255 public Object next (VirtualFrame frame , PGenerator self ,
247- @ Cached ("createIndirectCall()" ) GenericInvokeNode call ,
248- @ Cached BranchProfile alreadyRunning ) {
249- if (self .isFinished ()) {
250- throw raise (StopIteration );
251- }
252- if (self .isRunning ()) {
253- alreadyRunning .enter ();
254- throw raise (ValueError , ErrorMessages .GENERATOR_ALREADY_EXECUTING );
255- }
256- try {
257- self .setRunning (true );
258- return call .execute (frame , self .getCurrentCallTarget (), prepareArguments (self ));
259- } catch (PException e ) {
260- self .markAsFinished ();
261- throw e ;
262- } finally {
263- self .setRunning (false );
264- self .setNextCallTarget ();
265- }
256+ @ Cached ResumeGeneratorNode resumeGeneratorNode ) {
257+ checkResumable (this , self );
258+ return resumeGeneratorNode .execute (frame , self , null );
266259 }
267260 }
268261
@@ -271,13 +264,10 @@ public Object next(VirtualFrame frame, PGenerator self,
271264 public abstract static class SendNode extends PythonBuiltinNode {
272265
273266 @ Specialization
274- public Object send (PGenerator self , Object value ,
275- @ Cached BranchProfile alreadyRunning ) {
276- if (self .isRunning ()) {
277- alreadyRunning .enter ();
278- throw raise (ValueError , ErrorMessages .GENERATOR_ALREADY_EXECUTING );
279- }
280- return resumeGenerator (self , value );
267+ public Object send (VirtualFrame frame , PGenerator self , Object value ,
268+ @ Cached ResumeGeneratorNode resumeGeneratorNode ) {
269+ checkResumable (this , self );
270+ return resumeGeneratorNode .execute (frame , self , value );
281271 }
282272 }
283273
@@ -393,38 +383,32 @@ private void checkExceptionClass(Object type) {
393383 @ Specialization
394384 Object sendThrow (VirtualFrame frame , PGenerator self , Object typ , Object val , @ SuppressWarnings ("unused" ) PNone tb ,
395385 @ Cached PrepareExceptionNode prepareExceptionNode ,
396- @ Cached BranchProfile alreadyRunning ,
386+ @ Cached ResumeGeneratorNode resumeGeneratorNode ,
397387 @ Shared ("language" ) @ CachedLanguage PythonLanguage language ) {
398- if (self .isRunning ()) {
399- alreadyRunning .enter ();
400- throw raise (ValueError , ErrorMessages .GENERATOR_ALREADY_EXECUTING );
401- }
388+ checkResumable (this , self );
402389 PBaseException instance = prepareExceptionNode .execute (frame , typ , val );
403- return doThrow (self , instance , language );
390+ return doThrow (frame , resumeGeneratorNode , self , instance , language );
404391 }
405392
406393 @ Specialization
407394 Object sendThrow (VirtualFrame frame , PGenerator self , Object typ , Object val , PTraceback tb ,
408395 @ Cached PrepareExceptionNode prepareExceptionNode ,
409- @ Cached BranchProfile alreadyRunning ,
396+ @ Cached ResumeGeneratorNode resumeGeneratorNode ,
410397 @ Shared ("language" ) @ CachedLanguage PythonLanguage language ) {
411- if (self .isRunning ()) {
412- alreadyRunning .enter ();
413- throw raise (ValueError , ErrorMessages .GENERATOR_ALREADY_EXECUTING );
414- }
398+ checkResumable (this , self );
415399 PBaseException instance = prepareExceptionNode .execute (frame , typ , val );
416400 instance .setTraceback (tb );
417- return doThrow (self , instance , language );
401+ return doThrow (frame , resumeGeneratorNode , self , instance , language );
418402 }
419403
420- private Object doThrow (PGenerator self , PBaseException instance , PythonLanguage language ) {
404+ private Object doThrow (VirtualFrame frame , ResumeGeneratorNode resumeGeneratorNode , PGenerator self , PBaseException instance , PythonLanguage language ) {
421405 instance .setContext (null ); // Will be filled when caught
422406 if (self .isStarted ()) {
423407 instance .ensureReified ();
424408 // Pass it to the generator where it will be thrown by the last yield, the location
425409 // will be filled there
426410 PException pException = PException .fromObject (instance , null , PythonOptions .isPExceptionWithJavaStacktrace (language ));
427- return resumeGenerator ( self , pException );
411+ return resumeGeneratorNode . execute ( frame , self , pException );
428412 } else {
429413 // Unstarted generator, we cannot pass the exception into the generator as there is
430414 // nothing that would handle it.
@@ -470,24 +454,24 @@ private GetTracebackNode ensureGetTracebackNode() {
470454 @ GenerateNodeFactory
471455 public abstract static class CloseNode extends PythonUnaryBuiltinNode {
472456 @ Specialization
473- Object close (PGenerator self ,
457+ Object close (VirtualFrame frame , PGenerator self ,
474458 @ CachedLibrary (limit = "3" ) PythonObjectLibrary lib ,
475459 @ Cached IsBuiltinClassProfile isGeneratorExit ,
476460 @ Cached IsBuiltinClassProfile isStopIteration ,
477- @ Cached BranchProfile alreadyRunning ,
461+ @ Cached ResumeGeneratorNode resumeGeneratorNode ,
462+ @ Cached ConditionProfile isStartedPorfile ,
478463 @ CachedLanguage PythonLanguage language ) {
479464 if (self .isRunning ()) {
480- alreadyRunning .enter ();
481465 throw raise (ValueError , ErrorMessages .GENERATOR_ALREADY_EXECUTING );
482466 }
483- if (self .isStarted ()) {
467+ if (isStartedPorfile . profile ( self .isStarted () )) {
484468 PBaseException pythonException = factory ().createBaseException (GeneratorExit );
485469 // Pass it to the generator where it will be thrown by the last yield, the location
486470 // will be filled there
487471 boolean withJavaStacktrace = PythonOptions .isPExceptionWithJavaStacktrace (language );
488472 PException pException = PException .fromObject (pythonException , null , withJavaStacktrace );
489473 try {
490- resumeGenerator ( self , pException );
474+ resumeGeneratorNode . execute ( frame , self , pException );
491475 } catch (PException pe ) {
492476 if (isGeneratorExit .profileException (pe , GeneratorExit , lib ) || isStopIteration .profileException (pe , StopIteration , lib )) {
493477 // This is the "success" path
0 commit comments