cython-devel
changeset 1445:6dbd25167239
More fixes for new temps
| author | Dag Sverre Seljebotn <dagss@student.matnat.uio.no> |
|---|---|
| date | Mon Dec 01 01:06:57 2008 +0100 (3 years ago) |
| parents | dbcb1b2a2fce |
| children | 36de07933246 |
| files | Cython/Compiler/Code.py Cython/Compiler/ExprNodes.py Cython/Compiler/Nodes.py Cython/Compiler/Optimize.py |
line diff
1.1 --- a/Cython/Compiler/Code.py Sun Nov 30 16:09:44 2008 +0100
1.2 +++ b/Cython/Compiler/Code.py Mon Dec 01 01:06:57 2008 +0100
1.3 @@ -150,8 +150,9 @@
1.4 freelist = self.temps_free.get((type, manage_ref))
1.5 if freelist is None:
1.6 freelist = []
1.7 -
1.8 self.temps_free[(type, manage_ref)] = freelist
1.9 + if name in freelist:
1.10 + raise RuntimeError("Temp %s freed twice!" % name)
1.11 freelist.append(name)
1.12 if DebugFlags.debug_temp_code_comments:
1.13 self.owner.putln("/* %s released */" % name)
2.1 --- a/Cython/Compiler/ExprNodes.py Sun Nov 30 16:09:44 2008 +0100
2.2 +++ b/Cython/Compiler/ExprNodes.py Mon Dec 01 01:06:57 2008 +0100
2.3 @@ -439,6 +439,7 @@
2.4 self.generate_result_code(code)
2.5 if self.is_temp:
2.6 self.generate_subexpr_disposal_code(code)
2.7 + self.free_subexpr_temps(code)
2.8
2.9 def generate_subexpr_evaluation_code(self, code):
2.10 for node in self.subexpr_nodes():
2.11 @@ -487,6 +488,10 @@
2.12 def free_temps(self, code):
2.13 pass
2.14
2.15 + def free_subexpr_temps(self, code):
2.16 + for sub in self.subexpr_nodes():
2.17 + sub.free_temps(code)
2.18 +
2.19 # ---------------- Annotation ---------------------
2.20
2.21 def annotate(self, code):
2.22 @@ -582,12 +587,13 @@
2.23
2.24 class NewTempExprNode(ExprNode):
2.25 backwards_compatible_result = None
2.26 -
2.27 + temp_code = None
2.28 +
2.29 # Do not enable this unless you are trying to make all ExprNodes
2.30 # NewTempExprNodes (child nodes reached via recursion may not have
2.31 # transferred).
2.32 # __metaclass__ = RemoveAllocateTemps
2.33 -
2.34 +
2.35 def result(self):
2.36 if self.is_temp:
2.37 return self.temp_code
2.38 @@ -617,6 +623,8 @@
2.39 self.release_subexpr_temps(env)
2.40
2.41 def allocate_temp_result(self, code):
2.42 + if self.temp_code:
2.43 + raise RuntimeError("Temp allocated multiple times")
2.44 type = self.type
2.45 if not type.is_void:
2.46 if type.is_pyobject:
2.47 @@ -630,7 +638,11 @@
2.48 self.temp_code = None
2.49
2.50 def release_temp_result(self, code):
2.51 + if not self.temp_code:
2.52 + raise RuntimeError("No temp (perhaps released multiple times? See self.old_temp)")
2.53 code.funcstate.release_temp(self.temp_code)
2.54 + self.old_temp = self.temp_code
2.55 + self.temp_code = None
2.56
2.57 def generate_evaluation_code(self, code):
2.58 code.mark_pos(self.pos)
2.59 @@ -648,6 +660,7 @@
2.60 # If we are temp we do not need to wait until this node is disposed
2.61 # before disposing children.
2.62 self.generate_subexpr_disposal_code(code)
2.63 + self.free_subexpr_temps(code)
2.64
2.65 def generate_disposal_code(self, code):
2.66 if self.is_temp:
2.67 @@ -658,16 +671,18 @@
2.68 self.generate_subexpr_disposal_code(code)
2.69
2.70 def generate_post_assignment_code(self, code):
2.71 - if self.is_temp and self.type.is_pyobject:
2.72 - code.putln("%s = 0;" % self.result())
2.73 - self.generate_subexpr_disposal_code(code)
2.74 + if self.is_temp:
2.75 + if self.type.is_pyobject:
2.76 + code.putln("%s = 0;" % self.result())
2.77 + else:
2.78 + self.generate_subexpr_disposal_code(code)
2.79
2.80 def free_temps(self, code):
2.81 if self.is_temp:
2.82 - self.release_temp_result()
2.83 - for sub in self.subexpr_nodes():
2.84 - sub.free_temps(code)
2.85 -
2.86 + self.release_temp_result(code)
2.87 + else:
2.88 + self.free_subexpr_temps(code)
2.89 +
2.90 # ExprNode = NewTempExprNode
2.91
2.92 class AtomicExprNode(ExprNode):
2.93 @@ -1238,7 +1253,7 @@
2.94 print("NameNode.generate_assignment_code:")
2.95 print("...generating disposal code for %s" % rhs)
2.96 rhs.generate_disposal_code(code)
2.97 -
2.98 + rhs.free_temps(code)
2.99 else:
2.100 if self.type.is_buffer:
2.101 # Generate code for doing the buffer release/acquisition.
2.102 @@ -1270,6 +1285,7 @@
2.103 print("NameNode.generate_assignment_code:")
2.104 print("...generating post-assignment code for %s" % rhs)
2.105 rhs.generate_post_assignment_code(code)
2.106 + rhs.free_temps(code)
2.107
2.108 def generate_acquire_buffer(self, rhs, code):
2.109 # rhstmp is only used in case the rhs is a complicated expression leading to
2.110 @@ -1708,6 +1724,14 @@
2.111 for i in self.indices:
2.112 i.generate_disposal_code(code)
2.113
2.114 + def free_subexpr_temps(self, code):
2.115 + self.base.free_temps(code)
2.116 + if not self.indices:
2.117 + self.index.free_temps(code)
2.118 + else:
2.119 + for i in self.indices:
2.120 + i.free_temps(code)
2.121 +
2.122 def generate_result_code(self, code):
2.123 if self.is_buffer_access:
2.124 if code.globalstate.directives['nonecheck']:
2.125 @@ -1795,7 +1819,9 @@
2.126 "%s = %s;" % (
2.127 self.result(), rhs.result()))
2.128 self.generate_subexpr_disposal_code(code)
2.129 + self.free_subexpr_temps(code)
2.130 rhs.generate_disposal_code(code)
2.131 + rhs.free_temps(code)
2.132
2.133 def generate_deletion_code(self, code):
2.134 self.generate_subexpr_evaluation_code(code)
2.135 @@ -1935,6 +1961,7 @@
2.136 rhs.result(), i))
2.137 self.generate_subexpr_disposal_code(code)
2.138 rhs.generate_disposal_code(code)
2.139 + rhs.free_temps(code)
2.140
2.141 def generate_deletion_code(self, code):
2.142 if not self.type.is_pyobject:
2.143 @@ -2722,6 +2749,7 @@
2.144 self.interned_attr_cname,
2.145 rhs.py_result()))
2.146 rhs.generate_disposal_code(code)
2.147 + rhs.free_temps(code)
2.148 else:
2.149 if (self.obj.type.is_extension_type
2.150 and self.needs_none_check
2.151 @@ -2738,7 +2766,9 @@
2.152 rhs.result_as(self.ctype())))
2.153 #rhs.result()))
2.154 rhs.generate_post_assignment_code(code)
2.155 + rhs.free_temps(code)
2.156 self.obj.generate_disposal_code(code)
2.157 + self.obj.free_temps(code)
2.158
2.159 def generate_deletion_code(self, code):
2.160 self.obj.generate_evaluation_code(code)
2.161 @@ -2750,6 +2780,7 @@
2.162 else:
2.163 error(self.pos, "Cannot delete C attribute of extension type")
2.164 self.obj.generate_disposal_code(code)
2.165 + self.obj.free_temps(code)
2.166
2.167 def annotate(self, code):
2.168 if self.is_py_attr:
2.169 @@ -2838,6 +2869,10 @@
2.170 self.generate_operation_code(code)
2.171
2.172 def generate_assignment_code(self, rhs, code):
2.173 + # Need to work around the fact that generate_evaluation_code
2.174 + # allocates the temps in a rather hacky way -- the assignment
2.175 + # is evaluated twice, within each if-block.
2.176 +
2.177 code.putln(
2.178 "if (PyTuple_CheckExact(%s) && PyTuple_GET_SIZE(%s) == %s) {" % (
2.179 rhs.py_result(),
2.180 @@ -2855,6 +2890,10 @@
2.181 value_node.generate_evaluation_code(code)
2.182 rhs.generate_disposal_code(code)
2.183
2.184 + for i in range(len(self.args)):
2.185 + self.args[i].generate_assignment_code(
2.186 + self.coerced_unpacked_items[i], code)
2.187 +
2.188 code.putln("} else {")
2.189
2.190 code.putln(
2.191 @@ -2881,12 +2920,13 @@
2.192 print("UnpackNode.generate_assignment_code:")
2.193 print("...generating disposal code for %s" % self.iterator)
2.194 self.iterator.generate_disposal_code(code)
2.195 -
2.196 - code.putln("}")
2.197 - rhs.free_temps()
2.198 + self.iterator.free_temps(code)
2.199 +
2.200 for i in range(len(self.args)):
2.201 self.args[i].generate_assignment_code(
2.202 self.coerced_unpacked_items[i], code)
2.203 + code.putln("}")
2.204 + rhs.free_temps(code)
2.205
2.206 def annotate(self, code):
2.207 for arg in self.args:
2.208 @@ -2948,7 +2988,9 @@
2.209 # of generate_disposal_code, because values were stored
2.210 # in the tuple using a reference-stealing operation.
2.211 for arg in self.args:
2.212 - arg.generate_post_assignment_code(code)
2.213 + arg.generate_post_assignment_code(code)
2.214 + # Should NOT call free_temps -- this is invoked by the default
2.215 + # generate_evaluation_code which will do that.
2.216
2.217
2.218 class ListNode(SequenceNode):
2.219 @@ -3050,7 +3092,9 @@
2.220 # of generate_disposal_code, because values were stored
2.221 # in the list using a reference-stealing operation.
2.222 for arg in self.args:
2.223 - arg.generate_post_assignment_code(code)
2.224 + arg.generate_post_assignment_code(code)
2.225 + # Should NOT call free_temps -- this is invoked by the default
2.226 + # generate_evaluation_code which will do that.
2.227
2.228
2.229 class ListComprehensionNode(SequenceNode):
2.230 @@ -3202,6 +3246,7 @@
2.231 item.key.value,
2.232 item.value.result()))
2.233 item.generate_disposal_code(code)
2.234 + item.free_temps(code)
2.235
2.236 def annotate(self, code):
2.237 for item in self.key_value_pairs:
2.238 @@ -3227,6 +3272,10 @@
2.239 def generate_disposal_code(self, code):
2.240 self.key.generate_disposal_code(code)
2.241 self.value.generate_disposal_code(code)
2.242 +
2.243 + def free_temps(self, code):
2.244 + self.key.free_temps(code)
2.245 + self.value.free_temps(code)
2.246
2.247 def __iter__(self):
2.248 return iter([self.key, self.value])
2.249 @@ -4068,10 +4117,12 @@
2.250 self.operand2.generate_evaluation_code(code)
2.251 self.allocate_temp_result(code)
2.252 code.putln("%s = %s;" % (self.result(), self.operand2.result()))
2.253 - self.operand2.free_temps()
2.254 + self.operand2.generate_post_assignment_code(code)
2.255 + self.operand2.free_temps(code)
2.256 code.putln("} else {")
2.257 code.putln("%s = %s;" % (self.result(), self.operand1.result()))
2.258 - self.operand1.free_temps()
2.259 + self.operand1.generate_post_assignment_code(code)
2.260 + self.operand1.free_temps(code)
2.261 code.putln("}")
2.262
2.263 def generate_operand1_test(self, code):
2.264 @@ -4174,6 +4225,7 @@
2.265 self.false_val.generate_evaluation_code(code)
2.266 code.putln("}")
2.267 self.test.generate_disposal_code(code)
2.268 + self.test.free_temps(code)
2.269
2.270 richcmp_constants = {
2.271 "<" : "Py_LT",
2.272 @@ -4401,13 +4453,21 @@
2.273 self.result(), self.operand2)
2.274 self.operand1.generate_disposal_code(code)
2.275 self.operand2.generate_disposal_code(code)
2.276 -
2.277 + self.operand1.free_temps(code)
2.278 + self.operand2.free_temps(code)
2.279 +
2.280 def generate_subexpr_disposal_code(self, code):
2.281 # If this is called, it is a non-cascaded cmp,
2.282 # so only need to dispose of the two main operands.
2.283 self.operand1.generate_disposal_code(code)
2.284 self.operand2.generate_disposal_code(code)
2.285
2.286 + def free_subexpr_temps(self, code):
2.287 + # If this is called, it is a non-cascaded cmp,
2.288 + # so only need to dispose of the two main operands.
2.289 + self.operand1.free_temps(code)
2.290 + self.operand2.free_temps(code)
2.291 +
2.292 def annotate(self, code):
2.293 self.operand1.annotate(code)
2.294 self.operand2.annotate(code)
2.295 @@ -4484,6 +4544,7 @@
2.296 code, result, self.operand2)
2.297 # Cascaded cmp result is always temp
2.298 self.operand2.generate_disposal_code(code)
2.299 + self.operand2.free_temps(code)
2.300 code.putln("}")
2.301
2.302 def annotate(self, code):
2.303 @@ -4604,6 +4665,9 @@
2.304
2.305 def generate_post_assignment_code(self, code):
2.306 self.arg.generate_post_assignment_code(code)
2.307 +
2.308 + def free_temps(self, code):
2.309 + self.arg.free_temps(code)
2.310
2.311
2.312 class CoerceToPyTypeNode(CoercionNode):
2.313 @@ -4775,8 +4839,12 @@
2.314
2.315 def release_temp(self, env):
2.316 pass
2.317 -
2.318 -class PersistentNode(ExprNode):
2.319 +
2.320 + def free_temps(self, code):
2.321 + pass
2.322 +
2.323 +
2.324 +class DISABLED_PersistentNode(ExprNode):
2.325 # A PersistentNode is like a CloneNode except it handles the temporary
2.326 # allocation itself by keeping track of the number of times it has been
2.327 # used.
3.1 --- a/Cython/Compiler/Nodes.py Sun Nov 30 16:09:44 2008 +0100
3.2 +++ b/Cython/Compiler/Nodes.py Mon Dec 01 01:06:57 2008 +0100
3.3 @@ -2444,6 +2444,7 @@
3.4 self.body.generate_execution_code(code)
3.5 self.target.generate_assignment_code(self.classobj, code)
3.6 self.dict.generate_disposal_code(code)
3.7 + self.dict.free_temps(code)
3.8
3.9
3.10 class CClassDefNode(ClassDefNode):
3.11 @@ -2659,6 +2660,7 @@
3.12 if not self.expr.is_temp and self.expr.result():
3.13 code.putln("%s;" % self.expr.result())
3.14 self.expr.generate_disposal_code(code)
3.15 + self.expr.free_temps(code)
3.16
3.17 def annotate(self, code):
3.18 self.expr.annotate(code)
3.19 @@ -2884,6 +2886,7 @@
3.20 lhs.generate_assignment_code(rhs, code)
3.21 # Assignment has disposed of the cloned RHS
3.22 self.rhs.generate_disposal_code(code)
3.23 + self.rhs.free_temps(code)
3.24
3.25 def annotate(self, code):
3.26 for i in range(len(self.lhs_list)):
3.27 @@ -3016,7 +3019,9 @@
3.28 code.error_goto_if_null(self.result_value.py_result(), self.pos)))
3.29 self.result_value.generate_evaluation_code(code) # May be a type check...
3.30 self.rhs.generate_disposal_code(code)
3.31 + self.rhs.free_temps(code)
3.32 self.dup.generate_disposal_code(code)
3.33 + self.dup.free_temps(code)
3.34 self.lhs.generate_assignment_code(self.result_value, code)
3.35 else:
3.36 c_op = self.operator
3.37 @@ -3034,8 +3039,10 @@
3.38 self.dup.generate_result_code(code)
3.39 code.putln("%s %s= %s;" % (self.lhs.result(), c_op, self.rhs.result()) )
3.40 self.rhs.generate_disposal_code(code)
3.41 + self.rhs.free_temps(code)
3.42 if self.dup.is_temp:
3.43 self.dup.generate_subexpr_disposal_code(code)
3.44 + self.dup.free_subexpr_temps(code)
3.45
3.46 def create_dup_node(self, env):
3.47 import ExprNodes
3.48 @@ -3065,6 +3072,8 @@
3.49 index = index,
3.50 indices = indices,
3.51 is_temp = self.dup.is_temp)
3.52 + else:
3.53 + assert False
3.54 self.lhs = target_lhs
3.55 return self.dup
3.56
3.57 @@ -3117,6 +3126,7 @@
3.58 self.append_newline,
3.59 code.error_goto(self.pos)))
3.60 self.arg_tuple.generate_disposal_code(code)
3.61 + self.arg_tuple.free_temps(code)
3.62
3.63 def annotate(self, code):
3.64 self.arg_tuple.annotate(code)
3.65 @@ -3152,6 +3162,7 @@
3.66 (self.temp_result,) + args))
3.67 for arg in self.args:
3.68 arg.generate_disposal_code(code)
3.69 + arg.free_temps(code)
3.70 code.putln(
3.71 code.error_goto_if_null(self.temp_result, self.pos))
3.72 code.put_decref_clear(self.temp_result, py_object_type)
3.73 @@ -3287,6 +3298,7 @@
3.74 Naming.retval_cname,
3.75 self.value.result_as(self.return_type)))
3.76 self.value.generate_post_assignment_code(code)
3.77 + self.value.free_temps(code)
3.78 else:
3.79 if self.return_type.is_pyobject:
3.80 code.put_init_to_py_none(Naming.retval_cname, self.return_type)
3.81 @@ -3372,10 +3384,13 @@
3.82 "__Pyx_ReRaise();")
3.83 if self.exc_type:
3.84 self.exc_type.generate_disposal_code(code)
3.85 + self.exc_type.free_temps(code)
3.86 if self.exc_value:
3.87 self.exc_value.generate_disposal_code(code)
3.88 + self.exc_value.free_temps(code)
3.89 if self.exc_tb:
3.90 self.exc_tb.generate_disposal_code(code)
3.91 + self.exc_tb.free_temps(code)
3.92 code.putln(
3.93 code.error_goto(self.pos))
3.94
3.95 @@ -3442,6 +3457,7 @@
3.96 "PyErr_SetObject(PyExc_AssertionError, %s);" %
3.97 self.value.py_result())
3.98 self.value.generate_disposal_code(code)
3.99 + self.value.free_temps(code)
3.100 else:
3.101 code.putln(
3.102 "PyErr_SetNone(PyExc_AssertionError);")
3.103 @@ -3450,6 +3466,7 @@
3.104 code.putln(
3.105 "}")
3.106 self.cond.generate_disposal_code(code)
3.107 + self.cond.free_temps(code)
3.108 code.putln("#endif")
3.109
3.110 def annotate(self, code):
3.111 @@ -3756,6 +3773,7 @@
3.112 code.put_label(break_label)
3.113 self.iterator.release_counter_temp(code)
3.114 self.iterator.generate_disposal_code(code)
3.115 + self.iterator.free_temps(code)
3.116
3.117 def annotate(self, code):
3.118 self.target.annotate(code)
3.119 @@ -3878,9 +3896,12 @@
3.120 code.putln("}")
3.121 code.put_label(break_label)
3.122 self.bound1.generate_disposal_code(code)
3.123 + self.bound1.free_temps(code)
3.124 self.bound2.generate_disposal_code(code)
3.125 + self.bound2.free_temps(code)
3.126 if self.step is not None:
3.127 self.step.generate_disposal_code(code)
3.128 + self.step.free_temps(code)
3.129
3.130 relation_table = {
3.131 # {relop : (initial offset, increment op)}
3.132 @@ -4103,6 +4124,7 @@
3.133 self.match_flag,
3.134 self.pattern.py_result()))
3.135 self.pattern.generate_disposal_code(code)
3.136 + self.pattern.free_temps(code)
3.137 code.putln(
3.138 "if (%s) {" %
3.139 self.match_flag)
3.140 @@ -4539,6 +4561,7 @@
3.141 code.error_goto_if_null(self.item.result(), self.pos)))
3.142 target.generate_assignment_code(self.item, code)
3.143 self.module.generate_disposal_code(code)
3.144 + self.module.free_temps(code)
3.145
3.146
3.147
4.1 --- a/Cython/Compiler/Optimize.py Sun Nov 30 16:09:44 2008 +0100
4.2 +++ b/Cython/Compiler/Optimize.py Mon Dec 01 01:06:57 2008 +0100
4.3 @@ -8,9 +8,13 @@
4.4 import Symtab
4.5 from StringEncoding import EncodedString
4.6
4.7 +#def unwrap_node(node):
4.8 +# while isinstance(node, ExprNodes.PersistentNode):
4.9 +# node = node.arg
4.10 +# return node
4.11 +
4.12 +# Temporary hack while PersistentNode is out of order
4.13 def unwrap_node(node):
4.14 - while isinstance(node, ExprNodes.PersistentNode):
4.15 - node = node.arg
4.16 return node
4.17
4.18 def is_common_value(a, b):
