TempNode to new temps (changes its interface was necesarry)
authorDag Sverre Seljebotn <dagss@student.matnat.uio.no>
Mon, 30 Mar 2009 18:58:40 +0000 (20:58 +0200)
committerDag Sverre Seljebotn <dagss@student.matnat.uio.no>
Mon, 30 Mar 2009 18:58:40 +0000 (20:58 +0200)
Cython/Compiler/ExprNodes.py
Cython/Compiler/Nodes.py

index ead7f838ff3f30e0cc6e3cfc2342744588f1e565..b775d4310eeaa254c87799df62e40bf814897bf1 100644 (file)
@@ -1627,9 +1627,14 @@ class ExcValueNode(AtomicNewTempExprNode):
         pass
 
 
-class TempNode(ExprNode):
-    #  Node created during analyse_types phase
-    #  of some nodes to hold a temporary value.
+class TempNode(NewTempExprNode):
+    # Node created during analyse_types phase
+    # of some nodes to hold a temporary value.
+    #
+    # Note: One must call "allocate" and "release" on
+    # the node during code generation to get/release the temp.
+    # This is because the temp result is often used outside of
+    # the regular cycle.
 
     subexprs = []
     
@@ -1646,6 +1651,26 @@ class TempNode(ExprNode):
     def generate_result_code(self, code):
         pass
 
+    def allocate(self, code):
+        self.temp_cname = code.funcstate.allocate_temp(self.type, manage_ref=True)
+
+    def release(self, code):
+        code.funcstate.release_temp(self.temp_cname)
+        self.temp_cname = None
+
+    def result(self):
+        try:
+            return self.temp_cname
+        except:
+            assert False, "Remember to call allocate/release on TempNode"
+            raise
+
+    # Do not participate in normal temp alloc/dealloc:
+    def allocate_temp_result(self, code):
+        pass
+    
+    def release_temp_result(self, code):
+        pass
 
 class PyTempNode(TempNode):
     #  TempNode holding a Python value.
@@ -3096,6 +3121,8 @@ class SequenceNode(NewTempExprNode):
                 rhs.py_result(), 
                 len(self.args)))
         code.putln("PyObject* tuple = %s;" % rhs.py_result())
+        for item in self.unpacked_items:
+            item.allocate(code)
         for i in range(len(self.args)):
             item = self.unpacked_items[i]
             code.put(
@@ -3119,6 +3146,7 @@ class SequenceNode(NewTempExprNode):
                         rhs.py_result(), len(self.args)))
             code.putln(code.error_goto(self.pos))
         else:
+            self.iterator.allocate(code)
             code.putln(
                 "%s = PyObject_GetIter(%s); %s" % (
                     self.iterator.result(),
@@ -3146,12 +3174,15 @@ class SequenceNode(NewTempExprNode):
                 print("...generating disposal code for %s" % self.iterator)
             self.iterator.generate_disposal_code(code)
             self.iterator.free_temps(code)
+            self.iterator.release(code)
 
             for i in range(len(self.args)):
                 self.args[i].generate_assignment_code(
                     self.coerced_unpacked_items[i], code)
 
         code.putln("}")
+        for item in self.unpacked_items:
+            item.release(code)
         rhs.free_temps(code)
         
     def annotate(self, code):
index 347fdbb4876dd985eb95a3b94624ba960e4e298c..2400fd789d5293849a649b17b6f1442a561461da 100644 (file)
@@ -2429,6 +2429,7 @@ class OverrideCheckNode(StatNode):
             code.putln("else {")
         else:
             code.putln("else if (unlikely(Py_TYPE(%s)->tp_dictoffset != 0)) {" % self_arg)
+        self.func_node.allocate(code)
         err = code.error_goto_if_null(self.func_node.result(), self.pos)
         # need to get attribute manually--scope would return cdef method
         code.putln("%s = PyObject_GetAttr(%s, %s); %s" % (
@@ -2442,6 +2443,7 @@ class OverrideCheckNode(StatNode):
         code.putln('}')
         code.put_decref_clear(self.func_node.result(), PyrexTypes.py_object_type)
         code.putln("}")
+        self.func_node.release(code)
 
 class ClassDefNode(StatNode, BlockNode):
     pass
@@ -3059,8 +3061,9 @@ class InPlaceAssignmentNode(AssignmentNode):
         elif self.rhs.type.is_pyobject:
             self.rhs = self.rhs.coerce_to(self.lhs.type, env)
         if self.lhs.type.is_pyobject:
-             self.result_value = ExprNodes.PyTempNode(self.pos, env).coerce_to(self.lhs.type, env)
-             self.result_value.allocate_temps(env)
+            self.result_value_temp = ExprNodes.PyTempNode(self.pos, env)
+            self.result_value = self.result_value_temp.coerce_to(self.lhs.type, env)
+            self.result_value.allocate_temps(env)
 #        if use_temp:
 #            self.rhs = self.rhs.coerce_to_temp(env)
         self.rhs.allocate_temps(env)
@@ -3094,6 +3097,7 @@ class InPlaceAssignmentNode(AssignmentNode):
             if isinstance(self.lhs, ExprNodes.IndexNode) and self.lhs.is_buffer_access:
                 error(self.pos, "In-place operators not allowed on object buffers in this release.")
             self.dup.generate_result_code(code)
+            self.result_value_temp.allocate(code)
             code.putln(
                 "%s = %s(%s, %s%s); %s" % (
                     self.result_value.result(), 
@@ -3109,6 +3113,7 @@ class InPlaceAssignmentNode(AssignmentNode):
             self.dup.generate_disposal_code(code)
             self.dup.free_temps(code)
             self.lhs.generate_assignment_code(self.result_value, code)
+            self.result_value_temp.release(code)
         else: 
             c_op = self.operator
             if c_op == "//":
@@ -3949,6 +3954,11 @@ class ForFromStatNode(LoopNode, StatNode):
             self.step.generate_evaluation_code(code)
             step = self.step.result()
             incop = "%s=%s" % (incop[0], step)
+        import ExprNodes
+        if isinstance(self.loopvar_node, ExprNodes.TempNode):
+            self.loopvar_node.allocate(code)
+        if isinstance(self.py_loopvar_node, ExprNodes.TempNode):
+            self.py_loopvar_node.allocate(code)
         if from_range:
             loopvar_name = code.funcstate.allocate_temp(self.target.type, False)
         else:
@@ -3991,6 +4001,10 @@ class ForFromStatNode(LoopNode, StatNode):
         self.bound1.free_temps(code)
         self.bound2.generate_disposal_code(code)
         self.bound2.free_temps(code)
+        if isinstance(self.loopvar_node, ExprNodes.TempNode):
+            self.loopvar_node.release(code)
+        if isinstance(self.py_loopvar_node, ExprNodes.TempNode):
+            self.py_loopvar_node.release(code)
         if self.step is not None:
             self.step.generate_disposal_code(code)
             self.step.free_temps(code)
@@ -4739,6 +4753,7 @@ class FromImportStatNode(StatNode):
                     Naming.import_star,
                     self.module.py_result(),
                     code.error_goto(self.pos)))
+        self.item.allocate(code)
         for name, target, coerced_item in self.interned_items:
             cname = code.intern_identifier(name)
             code.putln(
@@ -4756,6 +4771,7 @@ class FromImportStatNode(StatNode):
                 target.generate_assignment_code(coerced_item, code)
                 if self.item.result() != coerced_item.result():
                     code.put_decref_clear(self.item.result(), self.item.type)
+        self.item.release(code)
         self.module.generate_disposal_code(code)
         self.module.free_temps(code)