Commit 8190d6b3 authored by Stefan Behnel's avatar Stefan Behnel

create yield labels purely during code generation instead of counting them upfront

parent c445411f
...@@ -505,6 +505,7 @@ class FunctionState(object): ...@@ -505,6 +505,7 @@ class FunctionState(object):
self.new_error_label() self.new_error_label()
self.continue_label = None self.continue_label = None
self.break_label = None self.break_label = None
self.yield_labels = []
self.in_try_finally = 0 self.in_try_finally = 0
self.exc_vars = None self.exc_vars = None
...@@ -537,6 +538,12 @@ class FunctionState(object): ...@@ -537,6 +538,12 @@ class FunctionState(object):
label += '_' + name label += '_' + name
return label return label
def new_yield_label(self):
label = self.new_label('resume_from_yield')
num_and_label = (len(self.yield_labels) + 1, label)
self.yield_labels.append(num_and_label)
return num_and_label
def new_error_label(self): def new_error_label(self):
old_err_lbl = self.error_label old_err_lbl = self.error_label
self.error_label = self.new_label('error') self.error_label = self.new_label('error')
...@@ -1474,10 +1481,12 @@ class CCodeWriter(object): ...@@ -1474,10 +1481,12 @@ class CCodeWriter(object):
continue_label = funccontext_property("continue_label") continue_label = funccontext_property("continue_label")
break_label = funccontext_property("break_label") break_label = funccontext_property("break_label")
return_from_error_cleanup_label = funccontext_property("return_from_error_cleanup_label") return_from_error_cleanup_label = funccontext_property("return_from_error_cleanup_label")
yield_labels = funccontext_property("yield_labels")
# Functions delegated to function scope # Functions delegated to function scope
def new_label(self, name=None): return self.funcstate.new_label(name) def new_label(self, name=None): return self.funcstate.new_label(name)
def new_error_label(self): return self.funcstate.new_error_label() def new_error_label(self): return self.funcstate.new_error_label()
def new_yield_label(self): return self.funcstate.new_yield_label()
def get_loop_labels(self): return self.funcstate.get_loop_labels() def get_loop_labels(self): return self.funcstate.get_loop_labels()
def set_loop_labels(self, labels): return self.funcstate.set_loop_labels(labels) def set_loop_labels(self, labels): return self.funcstate.set_loop_labels(labels)
def new_loop_labels(self): return self.funcstate.new_loop_labels() def new_loop_labels(self): return self.funcstate.new_loop_labels()
......
...@@ -7750,7 +7750,6 @@ class YieldExprNode(ExprNode): ...@@ -7750,7 +7750,6 @@ class YieldExprNode(ExprNode):
# Yield expression node # Yield expression node
# #
# arg ExprNode the value to return from the generator # arg ExprNode the value to return from the generator
# label_name string name of the C label used for this yield
# label_num integer yield label number # label_num integer yield label number
# is_yield_from boolean is a YieldFromExprNode to delegate to another generator # is_yield_from boolean is a YieldFromExprNode to delegate to another generator
...@@ -7791,8 +7790,8 @@ class YieldExprNode(ExprNode): ...@@ -7791,8 +7790,8 @@ class YieldExprNode(ExprNode):
Generate the code to return the argument in 'Naming.retval_cname' Generate the code to return the argument in 'Naming.retval_cname'
and to continue at the yield label. and to continue at the yield label.
""" """
self.label_name = code.new_label('resume_from_yield') label_num, label_name = code.new_yield_label()
code.use_label(self.label_name) code.use_label(label_name)
saved = [] saved = []
code.funcstate.closure_temps.reset() code.funcstate.closure_temps.reset()
...@@ -7807,10 +7806,10 @@ class YieldExprNode(ExprNode): ...@@ -7807,10 +7806,10 @@ class YieldExprNode(ExprNode):
code.put_finish_refcount_context() code.put_finish_refcount_context()
code.putln("/* return from generator, yielding value */") code.putln("/* return from generator, yielding value */")
code.putln("%s->resume_label = %d;" % ( code.putln("%s->resume_label = %d;" % (
Naming.generator_cname, self.label_num)) Naming.generator_cname, label_num))
code.putln("return %s;" % Naming.retval_cname) code.putln("return %s;" % Naming.retval_cname)
code.put_label(self.label_name) code.put_label(label_name)
for cname, save_cname, type in saved: for cname, save_cname, type in saved:
code.putln('%s = %s->%s;' % (cname, Naming.cur_scope_cname, save_cname)) code.putln('%s = %s->%s;' % (cname, Naming.cur_scope_cname, save_cname))
if type.is_pyobject: if type.is_pyobject:
......
...@@ -3828,12 +3828,8 @@ class GeneratorBodyDefNode(DefNode): ...@@ -3828,12 +3828,8 @@ class GeneratorBodyDefNode(DefNode):
Naming.generator_cname)) Naming.generator_cname))
resume_code.putln("case 0: goto %s;" % first_run_label) resume_code.putln("case 0: goto %s;" % first_run_label)
from ParseTreeTransforms import YieldNodeCollector for i, label in code.yield_labels:
collector = YieldNodeCollector() resume_code.putln("case %d: goto %s;" % (i, label))
collector.visitchildren(self)
for yield_expr in collector.yields:
resume_code.putln("case %d: goto %s;" % (
yield_expr.label_num, yield_expr.label_name))
resume_code.putln("default: /* CPython raises the right error here */") resume_code.putln("default: /* CPython raises the right error here */")
resume_code.put_finish_refcount_context() resume_code.put_finish_refcount_context()
resume_code.putln("return NULL;") resume_code.putln("return NULL;")
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment