BoolBinopNode converted, introduced parameters to generate_disposal_code
authorDag Sverre Seljebotn <dagss@student.matnat.uio.no>
Sun, 30 Nov 2008 11:38:21 +0000 (12:38 +0100)
committerDag Sverre Seljebotn <dagss@student.matnat.uio.no>
Sun, 30 Nov 2008 11:38:21 +0000 (12:38 +0100)
Cython/Compiler/Code.py
Cython/Compiler/DebugFlags.py
Cython/Compiler/ExprNodes.py
tests/errors/nogil.pyx

index 10558f16d24dba60a7f1bc97b147728da95e06bd..07df8075637753a81d461ba7a70e0d81249a9910 100644 (file)
@@ -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
index e36e0bd2686caab74064ebd8dd9bd5fea23a6dbf..aaa040b93f69263ba9cf7c6ef3a1da21162add36 100644 (file)
@@ -2,3 +2,4 @@ debug_disposal_code = 0
 debug_temp_alloc = 0
 debug_coercion = 0
 
+debug_temp_code_comments = 1
index 5ebc8f55f128f0bdc5609413fb07939365ad956a..e734b3fa2d89513ccb7c049a7a1afc64d3856bf3 100644 (file)
@@ -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.
index 9dfbc8cd889437f61fbd34cdbf54d9075142b9b7..f22b98dd5406e14f110ac4b0ec32cdc9c3ed2f5b 100644 (file)
@@ -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