More fixes for new temps
authorDag Sverre Seljebotn <dagss@student.matnat.uio.no>
Mon, 1 Dec 2008 00:06:57 +0000 (01:06 +0100)
committerDag Sverre Seljebotn <dagss@student.matnat.uio.no>
Mon, 1 Dec 2008 00:06:57 +0000 (01:06 +0100)
Cython/Compiler/Code.py
Cython/Compiler/ExprNodes.py
Cython/Compiler/Nodes.py
Cython/Compiler/Optimize.py

index 07df8075637753a81d461ba7a70e0d81249a9910..d173acaf766b44ffdca19aa5dc79d4d500ec3169 100644 (file)
@@ -150,8 +150,9 @@ class FunctionState(object):
         freelist = self.temps_free.get((type, manage_ref))
         if freelist is None:
             freelist = []
-
             self.temps_free[(type, manage_ref)] = freelist
+        if name in freelist:
+            raise RuntimeError("Temp %s freed twice!" % name)
         freelist.append(name)
         if DebugFlags.debug_temp_code_comments:
             self.owner.putln("/* %s released */" % name)
index 79b991eeb62ff5d219ea308045771570e37adaf2..a3dee7179691f75fab63becb89bf0670b83ec897 100644 (file)
@@ -439,6 +439,7 @@ class ExprNode(Node):
         self.generate_result_code(code)
         if self.is_temp:
             self.generate_subexpr_disposal_code(code)
+            self.free_subexpr_temps(code)
 
     def generate_subexpr_evaluation_code(self, code):
         for node in self.subexpr_nodes():
@@ -487,6 +488,10 @@ class ExprNode(Node):
     def free_temps(self, code):
         pass
     
+    def free_subexpr_temps(self, code):
+        for sub in self.subexpr_nodes():
+            sub.free_temps(code)
+
     # ---------------- Annotation ---------------------
     
     def annotate(self, code):
@@ -582,12 +587,13 @@ class RemoveAllocateTemps(type):
 
 class NewTempExprNode(ExprNode):
     backwards_compatible_result = None
-
+    temp_code = None
+    
 #   Do not enable this unless you are trying to make all ExprNodes
 #   NewTempExprNodes (child nodes reached via recursion may not have
 #   transferred).
 #    __metaclass__ = RemoveAllocateTemps
-    
+
     def result(self):
         if self.is_temp:
             return self.temp_code
@@ -617,6 +623,8 @@ class NewTempExprNode(ExprNode):
             self.release_subexpr_temps(env)
 
     def allocate_temp_result(self, code):
+        if self.temp_code:
+            raise RuntimeError("Temp allocated multiple times")
         type = self.type
         if not type.is_void:
             if type.is_pyobject:
@@ -630,7 +638,11 @@ class NewTempExprNode(ExprNode):
             self.temp_code = None
 
     def release_temp_result(self, code):
+        if not self.temp_code:
+            raise RuntimeError("No temp (perhaps released multiple times? See self.old_temp)")
         code.funcstate.release_temp(self.temp_code)
+        self.old_temp = self.temp_code
+        self.temp_code = None
 
     def generate_evaluation_code(self, code):
         code.mark_pos(self.pos)
@@ -648,6 +660,7 @@ class NewTempExprNode(ExprNode):
             # If we are temp we do not need to wait until this node is disposed
             # before disposing children.
             self.generate_subexpr_disposal_code(code)
+            self.free_subexpr_temps(code)
 
     def generate_disposal_code(self, code):
         if self.is_temp:
@@ -658,16 +671,18 @@ class NewTempExprNode(ExprNode):
             self.generate_subexpr_disposal_code(code)
 
     def generate_post_assignment_code(self, code):
-        if self.is_temp and self.type.is_pyobject:
-            code.putln("%s = 0;" % self.result())
-        self.generate_subexpr_disposal_code(code)
+        if self.is_temp:
+            if self.type.is_pyobject:
+                code.putln("%s = 0;" % self.result())
+        else:
+            self.generate_subexpr_disposal_code(code)
 
     def free_temps(self, code):
         if self.is_temp:
-            self.release_temp_result()
-        for sub in self.subexpr_nodes():
-            sub.free_temps(code)
-
+            self.release_temp_result(code)
+        else:
+            self.free_subexpr_temps(code)
+        
 # ExprNode = NewTempExprNode     
 
 class AtomicExprNode(ExprNode):
@@ -1238,7 +1253,7 @@ class NameNode(AtomicExprNode):
                     print("NameNode.generate_assignment_code:")
                     print("...generating disposal code for %s" % rhs)
                 rhs.generate_disposal_code(code)
-                
+                rhs.free_temps(code)
         else:
             if self.type.is_buffer:
                 # Generate code for doing the buffer release/acquisition.
@@ -1270,6 +1285,7 @@ class NameNode(AtomicExprNode):
                 print("NameNode.generate_assignment_code:")
                 print("...generating post-assignment code for %s" % rhs)
             rhs.generate_post_assignment_code(code)
+            rhs.free_temps(code)
 
     def generate_acquire_buffer(self, rhs, code):
         # rhstmp is only used in case the rhs is a complicated expression leading to
@@ -1708,6 +1724,14 @@ class IndexNode(ExprNode):
             for i in self.indices:
                 i.generate_disposal_code(code)
 
+    def free_subexpr_temps(self, code):
+        self.base.free_temps(code)
+        if not self.indices:
+            self.index.free_temps(code)
+        else:
+            for i in self.indices:
+                i.free_temps(code)
+
     def generate_result_code(self, code):
         if self.is_buffer_access:
             if code.globalstate.directives['nonecheck']:
@@ -1795,7 +1819,9 @@ class IndexNode(ExprNode):
                 "%s = %s;" % (
                     self.result(), rhs.result()))
         self.generate_subexpr_disposal_code(code)
+        self.free_subexpr_temps(code)
         rhs.generate_disposal_code(code)
+        rhs.free_temps(code)
     
     def generate_deletion_code(self, code):
         self.generate_subexpr_evaluation_code(code)
@@ -1935,6 +1961,7 @@ class SliceIndexNode(ExprNode):
                         rhs.result(), i))
         self.generate_subexpr_disposal_code(code)
         rhs.generate_disposal_code(code)
+        rhs.free_temps(code)
 
     def generate_deletion_code(self, code):
         if not self.type.is_pyobject:
@@ -2722,6 +2749,7 @@ class AttributeNode(ExprNode):
                     self.interned_attr_cname,
                     rhs.py_result()))
             rhs.generate_disposal_code(code)
+            rhs.free_temps(code)
         else:
             if (self.obj.type.is_extension_type
                   and self.needs_none_check
@@ -2738,7 +2766,9 @@ class AttributeNode(ExprNode):
                     rhs.result_as(self.ctype())))
                     #rhs.result()))
             rhs.generate_post_assignment_code(code)
+            rhs.free_temps(code)
         self.obj.generate_disposal_code(code)
+        self.obj.free_temps(code)
     
     def generate_deletion_code(self, code):
         self.obj.generate_evaluation_code(code)
@@ -2750,6 +2780,7 @@ class AttributeNode(ExprNode):
         else:
             error(self.pos, "Cannot delete C attribute of extension type")
         self.obj.generate_disposal_code(code)
+        self.obj.free_temps(code)
         
     def annotate(self, code):
         if self.is_py_attr:
@@ -2838,6 +2869,10 @@ class SequenceNode(NewTempExprNode):
         self.generate_operation_code(code)
     
     def generate_assignment_code(self, rhs, code):
+        # Need to work around the fact that generate_evaluation_code
+        # allocates the temps in a rather hacky way -- the assignment
+        # is evaluated twice, within each if-block.
+
         code.putln(
             "if (PyTuple_CheckExact(%s) && PyTuple_GET_SIZE(%s) == %s) {" % (
                 rhs.py_result(), 
@@ -2855,6 +2890,10 @@ class SequenceNode(NewTempExprNode):
             value_node.generate_evaluation_code(code)
         rhs.generate_disposal_code(code)
 
+        for i in range(len(self.args)):
+            self.args[i].generate_assignment_code(
+                self.coerced_unpacked_items[i], code)
+                 
         code.putln("} else {")
 
         code.putln(
@@ -2881,12 +2920,13 @@ class SequenceNode(NewTempExprNode):
             print("UnpackNode.generate_assignment_code:")
             print("...generating disposal code for %s" % self.iterator)
         self.iterator.generate_disposal_code(code)
+        self.iterator.free_temps(code)
 
-        code.putln("}")
-        rhs.free_temps()
         for i in range(len(self.args)):
             self.args[i].generate_assignment_code(
                 self.coerced_unpacked_items[i], code)
+        code.putln("}")
+        rhs.free_temps(code)
         
     def annotate(self, code):
         for arg in self.args:
@@ -2948,7 +2988,9 @@ class TupleNode(SequenceNode):
         # of generate_disposal_code, because values were stored
         # in the tuple using a reference-stealing operation.
         for arg in self.args:
-            arg.generate_post_assignment_code(code)    
+            arg.generate_post_assignment_code(code)
+            # Should NOT call free_temps -- this is invoked by the default
+            # generate_evaluation_code which will do that.
 
 
 class ListNode(SequenceNode):
@@ -3050,7 +3092,9 @@ class ListNode(SequenceNode):
         # of generate_disposal_code, because values were stored
         # in the list using a reference-stealing operation.
         for arg in self.args:
-            arg.generate_post_assignment_code(code)            
+            arg.generate_post_assignment_code(code)
+            # Should NOT call free_temps -- this is invoked by the default
+            # generate_evaluation_code which will do that.
 
             
 class ListComprehensionNode(SequenceNode):
@@ -3202,6 +3246,7 @@ class DictNode(ExprNode):
                         item.key.value,
                         item.value.result()))
             item.generate_disposal_code(code)
+            item.free_temps(code)
             
     def annotate(self, code):
         for item in self.key_value_pairs:
@@ -3227,6 +3272,10 @@ class DictItemNode(ExprNode):
     def generate_disposal_code(self, code):
         self.key.generate_disposal_code(code)
         self.value.generate_disposal_code(code)
+
+    def free_temps(self, code):
+        self.key.free_temps(code)
+        self.value.free_temps(code)
         
     def __iter__(self):
         return iter([self.key, self.value])
@@ -4068,10 +4117,12 @@ class BoolBinopNode(NewTempExprNode):
         self.operand2.generate_evaluation_code(code)
         self.allocate_temp_result(code)
         code.putln("%s = %s;" % (self.result(), self.operand2.result()))
-        self.operand2.free_temps()
+        self.operand2.generate_post_assignment_code(code)
+        self.operand2.free_temps(code)
         code.putln("} else {")
         code.putln("%s = %s;" % (self.result(), self.operand1.result()))
-        self.operand1.free_temps()
+        self.operand1.generate_post_assignment_code(code)
+        self.operand1.free_temps(code)
         code.putln("}")
     
     def generate_operand1_test(self, code):
@@ -4174,6 +4225,7 @@ class CondExprNode(ExprNode):
         self.false_val.generate_evaluation_code(code)
         code.putln("}")
         self.test.generate_disposal_code(code)
+        self.test.free_temps(code)
 
 richcmp_constants = {
     "<" : "Py_LT",
@@ -4401,13 +4453,21 @@ class PrimaryCmpNode(NewTempExprNode, CmpNode):
                     self.result(), self.operand2)
             self.operand1.generate_disposal_code(code)
             self.operand2.generate_disposal_code(code)
-    
+        self.operand1.free_temps(code)
+        self.operand2.free_temps(code)
+
     def generate_subexpr_disposal_code(self, code):
         #  If this is called, it is a non-cascaded cmp,
         #  so only need to dispose of the two main operands.
         self.operand1.generate_disposal_code(code)
         self.operand2.generate_disposal_code(code)
         
+    def free_subexpr_temps(self, code):
+        #  If this is called, it is a non-cascaded cmp,
+        #  so only need to dispose of the two main operands.
+        self.operand1.free_temps(code)
+        self.operand2.free_temps(code)
+        
     def annotate(self, code):
         self.operand1.annotate(code)
         self.operand2.annotate(code)
@@ -4484,6 +4544,7 @@ class CascadedCmpNode(Node, CmpNode):
                 code, result, self.operand2)
         # Cascaded cmp result is always temp
         self.operand2.generate_disposal_code(code)
+        self.operand2.free_temps(code)
         code.putln("}")
 
     def annotate(self, code):
@@ -4604,6 +4665,9 @@ class PyTypeTestNode(CoercionNode):
                 
     def generate_post_assignment_code(self, code):
         self.arg.generate_post_assignment_code(code)
+
+    def free_temps(self, code):
+        self.arg.free_temps(code)
                 
 
 class CoerceToPyTypeNode(CoercionNode):
@@ -4775,8 +4839,12 @@ class CloneNode(CoercionNode):
         
     def release_temp(self, env):
         pass
+
+    def free_temps(self, code):
+        pass
+    
         
-class PersistentNode(ExprNode):
+class DISABLED_PersistentNode(ExprNode):
     # A PersistentNode is like a CloneNode except it handles the temporary
     # allocation itself by keeping track of the number of times it has been 
     # used. 
index 01ad7b84dc18ae72cb0e1b73721a6f6bdf6da3a0..139432f26eae38752ad5626ea6d1ffd1da432ea0 100644 (file)
@@ -2444,6 +2444,7 @@ class PyClassDefNode(ClassDefNode):
         self.body.generate_execution_code(code)
         self.target.generate_assignment_code(self.classobj, code)
         self.dict.generate_disposal_code(code)
+        self.dict.free_temps(code)
 
 
 class CClassDefNode(ClassDefNode):
@@ -2659,6 +2660,7 @@ class ExprStatNode(StatNode):
         if not self.expr.is_temp and self.expr.result():
             code.putln("%s;" % self.expr.result())
         self.expr.generate_disposal_code(code)
+        self.expr.free_temps(code)
 
     def annotate(self, code):
         self.expr.annotate(code)
@@ -2884,6 +2886,7 @@ class CascadedAssignmentNode(AssignmentNode):
             lhs.generate_assignment_code(rhs, code)
             # Assignment has disposed of the cloned RHS
         self.rhs.generate_disposal_code(code)
+        self.rhs.free_temps(code)
 
     def annotate(self, code):
         for i in range(len(self.lhs_list)):
@@ -3016,7 +3019,9 @@ class InPlaceAssignmentNode(AssignmentNode):
                     code.error_goto_if_null(self.result_value.py_result(), self.pos)))
             self.result_value.generate_evaluation_code(code) # May be a type check...
             self.rhs.generate_disposal_code(code)
+            self.rhs.free_temps(code)
             self.dup.generate_disposal_code(code)
+            self.dup.free_temps(code)
             self.lhs.generate_assignment_code(self.result_value, code)
         else: 
             c_op = self.operator
@@ -3034,8 +3039,10 @@ class InPlaceAssignmentNode(AssignmentNode):
                 self.dup.generate_result_code(code)
                 code.putln("%s %s= %s;" % (self.lhs.result(), c_op, self.rhs.result()) )
             self.rhs.generate_disposal_code(code)
+            self.rhs.free_temps(code)
         if self.dup.is_temp:
             self.dup.generate_subexpr_disposal_code(code)
+            self.dup.free_subexpr_temps(code)
             
     def create_dup_node(self, env): 
         import ExprNodes
@@ -3065,6 +3072,8 @@ class InPlaceAssignmentNode(AssignmentNode):
                                              index = index,
                                              indices = indices,
                                              is_temp = self.dup.is_temp)
+        else:
+            assert False
         self.lhs = target_lhs
         return self.dup
     
@@ -3117,6 +3126,7 @@ class PrintStatNode(StatNode):
                 self.append_newline,
                 code.error_goto(self.pos)))
         self.arg_tuple.generate_disposal_code(code)
+        self.arg_tuple.free_temps(code)
 
     def annotate(self, code):
         self.arg_tuple.annotate(code)
@@ -3152,6 +3162,7 @@ class ExecStatNode(StatNode):
                 (self.temp_result,) + args))
         for arg in self.args:
             arg.generate_disposal_code(code)
+            arg.free_temps(code)
         code.putln(
             code.error_goto_if_null(self.temp_result, self.pos))
         code.put_decref_clear(self.temp_result, py_object_type)
@@ -3287,6 +3298,7 @@ class ReturnStatNode(StatNode):
                     Naming.retval_cname,
                     self.value.result_as(self.return_type)))
             self.value.generate_post_assignment_code(code)
+            self.value.free_temps(code)
         else:
             if self.return_type.is_pyobject:
                 code.put_init_to_py_none(Naming.retval_cname, self.return_type)
@@ -3372,10 +3384,13 @@ class RaiseStatNode(StatNode):
                 "__Pyx_ReRaise();")
         if self.exc_type:
             self.exc_type.generate_disposal_code(code)
+            self.exc_type.free_temps(code)
         if self.exc_value:
             self.exc_value.generate_disposal_code(code)
+            self.exc_value.free_temps(code)
         if self.exc_tb:
             self.exc_tb.generate_disposal_code(code)
+            self.exc_tb.free_temps(code)
         code.putln(
             code.error_goto(self.pos))
 
@@ -3442,6 +3457,7 @@ class AssertStatNode(StatNode):
                 "PyErr_SetObject(PyExc_AssertionError, %s);" %
                     self.value.py_result())
             self.value.generate_disposal_code(code)
+            self.value.free_temps(code)
         else:
             code.putln(
                 "PyErr_SetNone(PyExc_AssertionError);")
@@ -3450,6 +3466,7 @@ class AssertStatNode(StatNode):
         code.putln(
             "}")
         self.cond.generate_disposal_code(code)
+        self.cond.free_temps(code)
         code.putln("#endif")
 
     def annotate(self, code):
@@ -3756,6 +3773,7 @@ class ForInStatNode(LoopNode, StatNode):
         code.put_label(break_label)
         self.iterator.release_counter_temp(code)
         self.iterator.generate_disposal_code(code)
+        self.iterator.free_temps(code)
 
     def annotate(self, code):
         self.target.annotate(code)
@@ -3878,9 +3896,12 @@ class ForFromStatNode(LoopNode, StatNode):
             code.putln("}")
         code.put_label(break_label)
         self.bound1.generate_disposal_code(code)
+        self.bound1.free_temps(code)
         self.bound2.generate_disposal_code(code)
+        self.bound2.free_temps(code)
         if self.step is not None:
             self.step.generate_disposal_code(code)
+            self.step.free_temps(code)
     
     relation_table = {
         # {relop : (initial offset, increment op)}
@@ -4103,6 +4124,7 @@ class ExceptClauseNode(Node):
                     self.match_flag,
                     self.pattern.py_result()))
             self.pattern.generate_disposal_code(code)
+            self.pattern.free_temps(code)
             code.putln(
                 "if (%s) {" %
                     self.match_flag)
@@ -4539,6 +4561,7 @@ class FromImportStatNode(StatNode):
                     code.error_goto_if_null(self.item.result(), self.pos)))
             target.generate_assignment_code(self.item, code)
         self.module.generate_disposal_code(code)
+        self.module.free_temps(code)
 
 
 
index a9021662bb1710d104299cb42b99b69f640c2539..64aef0837e4b1193fd7a358abf1aec66e742e776 100644 (file)
@@ -8,9 +8,13 @@ import TypeSlots
 import Symtab
 from StringEncoding import EncodedString
 
+#def unwrap_node(node):
+#    while isinstance(node, ExprNodes.PersistentNode):
+#        node = node.arg
+#    return node
+
+# Temporary hack while PersistentNode is out of order
 def unwrap_node(node):
-    while isinstance(node, ExprNodes.PersistentNode):
-        node = node.arg
     return node
 
 def is_common_value(a, b):