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):
self.new_error_label()
self.continue_label = None
self.break_label = None
self.yield_labels = []
self.in_try_finally = 0
self.exc_vars = None
......@@ -537,6 +538,12 @@ class FunctionState(object):
label += '_' + name
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):
old_err_lbl = self.error_label
self.error_label = self.new_label('error')
......@@ -1474,10 +1481,12 @@ class CCodeWriter(object):
continue_label = funccontext_property("continue_label")
break_label = funccontext_property("break_label")
return_from_error_cleanup_label = funccontext_property("return_from_error_cleanup_label")
yield_labels = funccontext_property("yield_labels")
# Functions delegated to function scope
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_yield_label(self): return self.funcstate.new_yield_label()
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 new_loop_labels(self): return self.funcstate.new_loop_labels()
......
......@@ -7750,7 +7750,6 @@ class YieldExprNode(ExprNode):
# Yield expression node
#
# 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
# is_yield_from boolean is a YieldFromExprNode to delegate to another generator
......@@ -7791,8 +7790,8 @@ class YieldExprNode(ExprNode):
Generate the code to return the argument in 'Naming.retval_cname'
and to continue at the yield label.
"""
self.label_name = code.new_label('resume_from_yield')
code.use_label(self.label_name)
label_num, label_name = code.new_yield_label()
code.use_label(label_name)
saved = []
code.funcstate.closure_temps.reset()
......@@ -7807,10 +7806,10 @@ class YieldExprNode(ExprNode):
code.put_finish_refcount_context()
code.putln("/* return from generator, yielding value */")
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.put_label(self.label_name)
code.put_label(label_name)
for cname, save_cname, type in saved:
code.putln('%s = %s->%s;' % (cname, Naming.cur_scope_cname, save_cname))
if type.is_pyobject:
......
......@@ -3828,12 +3828,8 @@ class GeneratorBodyDefNode(DefNode):
Naming.generator_cname))
resume_code.putln("case 0: goto %s;" % first_run_label)
from ParseTreeTransforms import YieldNodeCollector
collector = YieldNodeCollector()
collector.visitchildren(self)
for yield_expr in collector.yields:
resume_code.putln("case %d: goto %s;" % (
yield_expr.label_num, yield_expr.label_name))
for i, label in code.yield_labels:
resume_code.putln("case %d: goto %s;" % (i, label))
resume_code.putln("default: /* CPython raises the right error here */")
resume_code.put_finish_refcount_context()
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