From: Dag Sverre Seljebotn Date: Sun, 30 Nov 2008 11:38:21 +0000 (+0100) Subject: BoolBinopNode converted, introduced parameters to generate_disposal_code X-Git-Tag: 0.11-beta~178 X-Git-Url: http://git.tremily.us/?a=commitdiff_plain;h=154da8bcc7b495ac377bb00180f2c8c5afdb3bb1;p=cython.git BoolBinopNode converted, introduced parameters to generate_disposal_code --- diff --git a/Cython/Compiler/Code.py b/Cython/Compiler/Code.py index 10558f16..07df8075 100644 --- a/Cython/Compiler/Code.py +++ b/Cython/Compiler/Code.py @@ -14,6 +14,7 @@ try: set except NameError: from sets import Set as set +import DebugFlags class FunctionState(object): # return_label string function return point label @@ -26,8 +27,9 @@ class FunctionState(object): # exc_vars (string * 3) exception variables for reraise, or None # Not used for now, perhaps later - def __init__(self, names_taken=set()): + def __init__(self, owner, names_taken=set()): self.names_taken = names_taken + self.owner = owner self.error_label = None self.label_counter = 0 @@ -135,6 +137,8 @@ class FunctionState(object): if not result in self.names_taken: break self.temps_allocated.append((result, type, manage_ref)) self.temps_used_type[result] = (type, manage_ref) + if DebugFlags.debug_temp_code_comments: + self.owner.putln("/* %s allocated */" % result) return result def release_temp(self, name): @@ -149,6 +153,8 @@ class FunctionState(object): self.temps_free[(type, manage_ref)] = freelist freelist.append(name) + if DebugFlags.debug_temp_code_comments: + self.owner.putln("/* %s released */" % name) def temps_in_use(self): """Return a list of (cname,type,manage_ref) tuples of temp names and their type @@ -567,7 +573,7 @@ class CCodeWriter(object): def enter_cfunc_scope(self): - self.funcstate = FunctionState() + self.funcstate = FunctionState(self) def exit_cfunc_scope(self): self.funcstate = None diff --git a/Cython/Compiler/DebugFlags.py b/Cython/Compiler/DebugFlags.py index e36e0bd2..aaa040b9 100644 --- a/Cython/Compiler/DebugFlags.py +++ b/Cython/Compiler/DebugFlags.py @@ -2,3 +2,4 @@ debug_disposal_code = 0 debug_temp_alloc = 0 debug_coercion = 0 +debug_temp_code_comments = 1 diff --git a/Cython/Compiler/ExprNodes.py b/Cython/Compiler/ExprNodes.py index 5ebc8f55..e734b3fa 100644 --- a/Cython/Compiler/ExprNodes.py +++ b/Cython/Compiler/ExprNodes.py @@ -447,14 +447,17 @@ class ExprNode(Node): def generate_result_code(self, code): self.not_implemented("generate_result_code") - def generate_disposal_code(self, code): + def generate_disposal_code(self, code, free_temp=True, decref=True): # If necessary, generate code to dispose of # temporary Python reference. - if self.is_temp: - if self.type.is_pyobject: - code.put_decref_clear(self.result(), self.ctype()) + if not decref: + self.generate_post_assignment_code(code) else: - self.generate_subexpr_disposal_code(code) + if self.is_temp: + if self.type.is_pyobject: + code.put_decref_clear(self.result(), self.ctype()) + else: + self.generate_subexpr_disposal_code(code) def generate_subexpr_disposal_code(self, code): # Generate code to dispose of temporary results @@ -647,23 +650,20 @@ class NewTempExprNode(ExprNode): # before disposing children. self.generate_subexpr_disposal_code(code) - def generate_disposal_code(self, code): + def generate_disposal_code(self, code, free_temp=True, decref=True): if self.is_temp: if self.type.is_pyobject: - code.put_decref_clear(self.result(), self.ctype()) - if not self.backwards_compatible_result: + if decref: + code.put_decref_clear(self.result(), self.ctype()) + elif free_temp and not self.backwards_compatible_result: + code.putln("%s = 0;" % self.result()) + if free_temp and not self.backwards_compatible_result: self.release_temp_result(code) else: self.generate_subexpr_disposal_code(code) def generate_post_assignment_code(self, code): - if self.is_temp: - if self.type.is_pyobject: - code.putln("%s = 0;" % self.temp_code) - if not self.backwards_compatible_result: - code.funcstate.release_temp(self.temp_code) - else: - self.generate_subexpr_disposal_code(code) + self.generate_disposal_code(code, free_temp=True, decref=False) # ExprNode = NewTempExprNode @@ -685,17 +685,10 @@ class AtomicNewTempExprNode(NewTempExprNode): subexprs = [] # Override to optimize -- we know we have no children - def generate_evaluation_code(self, code): - if self.is_temp: - self.allocate_temp_result(code) - self.generate_result_code(code) - - def generate_disposal_code(self, code): - if self.is_temp: - if self.type.is_pyobject: - code.put_decref_clear(self.result(), self.ctype()) - if not self.backwards_compatible_result: - self.release_temp_result(code) + def generate_subexpr_evaluation_code(self, code): + pass + def generate_subexpr_disposal_code(self, code): + pass class PyConstNode(AtomicNewTempExprNode): # Abstract base class for constant Python values. @@ -3968,7 +3961,14 @@ class PowNode(NumBinopNode): self.operand1.result(), self.operand2.result()) -class BoolBinopNode(ExprNode): +# Note: This class is temporary "shut down" into an ineffective mode temp +# allocation mode. +# +# More sophisticated temp reuse was going on before, +# one could have a look at adding this again after /all/ classes +# are converted to the new temp scheme. (The temp juggling cannot work +# otherwise). +class BoolBinopNode(NewTempExprNode): # Short-circuiting boolean operation. # # operator string @@ -4004,32 +4004,35 @@ class BoolBinopNode(ExprNode): self.operand1 = self.operand1.coerce_to_boolean(env) self.operand2 = self.operand2.coerce_to_boolean(env) self.type = PyrexTypes.c_bint_type + + # Below disabled for + # For what we're about to do, it's vital that # both operands be temp nodes. - self.operand1 = self.operand1.coerce_to_temp(env) #CTT - self.operand2 = self.operand2.coerce_to_temp(env) +# self.operand1 = self.operand1.coerce_to_temp(env) #CTT +# self.operand2 = self.operand2.coerce_to_temp(env) self.is_temp = 1 gil_message = "Truth-testing Python object" - def allocate_temps(self, env, result_code = None): - # We don't need both operands at the same time, and - # one of the operands will also be our result. So we - # use an allocation strategy here which results in - # this node and both its operands sharing the same - # result variable. This allows us to avoid some - # assignments and increfs/decrefs that would otherwise - # be necessary. - self.allocate_temp(env, result_code) - self.operand1.allocate_temps(env, self.result()) - self.operand2.allocate_temps(env, self.result()) - # We haven't called release_temp on either operand, - # because although they are temp nodes, they don't own - # their result variable. And because they are temp - # nodes, any temps in their subnodes will have been - # released before their allocate_temps returned. - # Therefore, they contain no temp vars that need to - # be released. +## def allocate_temps(self, env, result_code = None): +## # We don't need both operands at the same time, and +## # one of the operands will also be our result. So we +## # use an allocation strategy here which results in +## # this node and both its operands sharing the same +## # result variable. This allows us to avoid some +## # assignments and increfs/decrefs that would otherwise +## # be necessary. +## self.allocate_temp(env, result_code) +## self.operand1.allocate_temps(env, self.result()) +## self.operand2.allocate_temps(env, self.result()) +## # We haven't called release_temp on either operand, +## # because although they are temp nodes, they don't own +## # their result variable. And because they are temp +## # nodes, any temps in their subnodes will have been +## # released before their allocate_temps returned. +## # Therefore, they contain no temp vars that need to +## # be released. def check_const(self): self.operand1.check_const() @@ -4044,6 +4047,8 @@ class BoolBinopNode(ExprNode): py_to_c_op = {'and': "&&", 'or': "||"} def generate_evaluation_code(self, code): + code.mark_pos(self.pos) + self.allocate_temp_result(code) self.operand1.generate_evaluation_code(code) test_result, uses_temp = self.generate_operand1_test(code) if self.operator == 'and': @@ -4056,10 +4061,14 @@ class BoolBinopNode(ExprNode): test_result)) if uses_temp: code.funcstate.release_temp(test_result) - self.operand1.generate_disposal_code(code) + self.operand1.generate_disposal_code(code, free_temp=False) self.operand2.generate_evaluation_code(code) - code.putln( - "}") + code.putln("%s = %s;" % (self.result(), self.operand2.result())) + self.operand2.generate_disposal_code(code, decref=False) + code.putln("} else {") + code.putln("%s = %s;" % (self.result(), self.operand1.result())) + self.operand1.generate_disposal_code(code, decref=False) + code.putln("}") def generate_operand1_test(self, code): # Generate code to test the truth of the first operand. diff --git a/tests/errors/nogil.pyx b/tests/errors/nogil.pyx index 9dfbc8cd..f22b98dd 100644 --- a/tests/errors/nogil.pyx +++ b/tests/errors/nogil.pyx @@ -105,9 +105,7 @@ _ERRORS = u""" 39: 9: Constructing Python tuple not allowed without gil 40: 8: Constructing Python list not allowed without gil 41: 8: Constructing Python dict not allowed without gil -42:12: Creating temporary Python reference not allowed without gil 42:12: Truth-testing Python object not allowed without gil -42:17: Creating temporary Python reference not allowed without gil 43:13: Python type test not allowed without gil #44: 4: Converting to Python object not allowed without gil 45:10: Operation not allowed without gil