cython-devel

changeset 1447:36de07933246

merge
author Stefan Behnel <scoder@users.berlios.de>
date Tue Dec 02 20:27:40 2008 +0100 (20 months ago)
parents 07a018cdcdd8 6dbd25167239
children 34f96dba6feb
files Cython/Compiler/Optimize.py
line diff
1.1 --- a/Cython/Compiler/Code.py Tue Dec 02 20:24:44 2008 +0100 1.2 +++ b/Cython/Compiler/Code.py Tue Dec 02 20:27:40 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 Tue Dec 02 20:24:44 2008 +0100 2.2 +++ b/Cython/Compiler/ExprNodes.py Tue Dec 02 20:27:40 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 @@ -447,17 +448,14 @@ 2.12 def generate_result_code(self, code): 2.13 self.not_implemented("generate_result_code") 2.14 2.15 - def generate_disposal_code(self, code, free_temp=True, decref=True): 2.16 + def generate_disposal_code(self, code): 2.17 # If necessary, generate code to dispose of 2.18 # temporary Python reference. 2.19 - if not decref: 2.20 - self.generate_post_assignment_code(code) 2.21 - else: 2.22 - if self.is_temp: 2.23 - if self.type.is_pyobject: 2.24 - code.put_decref_clear(self.result(), self.ctype()) 2.25 - else: 2.26 - self.generate_subexpr_disposal_code(code) 2.27 + if self.is_temp: 2.28 + if self.type.is_pyobject: 2.29 + code.put_decref_clear(self.result(), self.ctype()) 2.30 + else: 2.31 + self.generate_subexpr_disposal_code(code) 2.32 2.33 def generate_subexpr_disposal_code(self, code): 2.34 # Generate code to dispose of temporary results 2.35 @@ -486,7 +484,14 @@ 2.36 # the argument of a del statement. An error 2.37 # will have been reported earlier. 2.38 pass 2.39 - 2.40 + 2.41 + def free_temps(self, code): 2.42 + pass 2.43 + 2.44 + def free_subexpr_temps(self, code): 2.45 + for sub in self.subexpr_nodes(): 2.46 + sub.free_temps(code) 2.47 + 2.48 # ---------------- Annotation --------------------- 2.49 2.50 def annotate(self, code): 2.51 @@ -578,17 +583,17 @@ 2.52 def noop(self, env): pass 2.53 setattr(cls, 'allocate_temps', noop) 2.54 setattr(cls, 'allocate_temp', noop) 2.55 - setattr(cls, 'release_temps', noop) 2.56 setattr(cls, 'release_temp', noop) 2.57 2.58 class NewTempExprNode(ExprNode): 2.59 backwards_compatible_result = None 2.60 - 2.61 + temp_code = None 2.62 + 2.63 # Do not enable this unless you are trying to make all ExprNodes 2.64 # NewTempExprNodes (child nodes reached via recursion may not have 2.65 # transferred). 2.66 # __metaclass__ = RemoveAllocateTemps 2.67 - 2.68 + 2.69 def result(self): 2.70 if self.is_temp: 2.71 return self.temp_code 2.72 @@ -618,6 +623,8 @@ 2.73 self.release_subexpr_temps(env) 2.74 2.75 def allocate_temp_result(self, code): 2.76 + if self.temp_code: 2.77 + raise RuntimeError("Temp allocated multiple times") 2.78 type = self.type 2.79 if not type.is_void: 2.80 if type.is_pyobject: 2.81 @@ -631,7 +638,11 @@ 2.82 self.temp_code = None 2.83 2.84 def release_temp_result(self, code): 2.85 + if not self.temp_code: 2.86 + raise RuntimeError("No temp (perhaps released multiple times? See self.old_temp)") 2.87 code.funcstate.release_temp(self.temp_code) 2.88 + self.old_temp = self.temp_code 2.89 + self.temp_code = None 2.90 2.91 def generate_evaluation_code(self, code): 2.92 code.mark_pos(self.pos) 2.93 @@ -646,25 +657,32 @@ 2.94 2.95 self.generate_result_code(code) 2.96 if self.is_temp: 2.97 - # If we are temp, need to wait until this node is disposed 2.98 + # If we are temp we do not need to wait until this node is disposed 2.99 # before disposing children. 2.100 self.generate_subexpr_disposal_code(code) 2.101 - 2.102 - def generate_disposal_code(self, code, free_temp=True, decref=True): 2.103 - if self.is_temp: 2.104 - if self.type.is_pyobject: 2.105 - if decref: 2.106 - code.put_decref_clear(self.result(), self.ctype()) 2.107 - elif free_temp and not self.backwards_compatible_result: 2.108 - code.putln("%s = 0;" % self.result()) 2.109 - if free_temp and not self.backwards_compatible_result: 2.110 - self.release_temp_result(code) 2.111 - else: 2.112 + self.free_subexpr_temps(code) 2.113 + 2.114 + def generate_disposal_code(self, code): 2.115 + if self.is_temp: 2.116 + if self.type.is_pyobject: 2.117 + code.put_decref_clear(self.result(), self.ctype()) 2.118 + else: 2.119 + # Already done if self.is_temp 2.120 self.generate_subexpr_disposal_code(code) 2.121 2.122 def generate_post_assignment_code(self, code): 2.123 - self.generate_disposal_code(code, free_temp=True, decref=False) 2.124 - 2.125 + if self.is_temp: 2.126 + if self.type.is_pyobject: 2.127 + code.putln("%s = 0;" % self.result()) 2.128 + else: 2.129 + self.generate_subexpr_disposal_code(code) 2.130 + 2.131 + def free_temps(self, code): 2.132 + if self.is_temp: 2.133 + self.release_temp_result(code) 2.134 + else: 2.135 + self.free_subexpr_temps(code) 2.136 + 2.137 # ExprNode = NewTempExprNode 2.138 2.139 class AtomicExprNode(ExprNode): 2.140 @@ -1235,7 +1253,7 @@ 2.141 print("NameNode.generate_assignment_code:") 2.142 print("...generating disposal code for %s" % rhs) 2.143 rhs.generate_disposal_code(code) 2.144 - 2.145 + rhs.free_temps(code) 2.146 else: 2.147 if self.type.is_buffer: 2.148 # Generate code for doing the buffer release/acquisition. 2.149 @@ -1267,6 +1285,7 @@ 2.150 print("NameNode.generate_assignment_code:") 2.151 print("...generating post-assignment code for %s" % rhs) 2.152 rhs.generate_post_assignment_code(code) 2.153 + rhs.free_temps(code) 2.154 2.155 def generate_acquire_buffer(self, rhs, code): 2.156 # rhstmp is only used in case the rhs is a complicated expression leading to 2.157 @@ -1705,6 +1724,14 @@ 2.158 for i in self.indices: 2.159 i.generate_disposal_code(code) 2.160 2.161 + def free_subexpr_temps(self, code): 2.162 + self.base.free_temps(code) 2.163 + if not self.indices: 2.164 + self.index.free_temps(code) 2.165 + else: 2.166 + for i in self.indices: 2.167 + i.free_temps(code) 2.168 + 2.169 def generate_result_code(self, code): 2.170 if self.is_buffer_access: 2.171 if code.globalstate.directives['nonecheck']: 2.172 @@ -1792,7 +1819,9 @@ 2.173 "%s = %s;" % ( 2.174 self.result(), rhs.result())) 2.175 self.generate_subexpr_disposal_code(code) 2.176 + self.free_subexpr_temps(code) 2.177 rhs.generate_disposal_code(code) 2.178 + rhs.free_temps(code) 2.179 2.180 def generate_deletion_code(self, code): 2.181 self.generate_subexpr_evaluation_code(code) 2.182 @@ -1932,6 +1961,7 @@ 2.183 rhs.result(), i)) 2.184 self.generate_subexpr_disposal_code(code) 2.185 rhs.generate_disposal_code(code) 2.186 + rhs.free_temps(code) 2.187 2.188 def generate_deletion_code(self, code): 2.189 if not self.type.is_pyobject: 2.190 @@ -2719,6 +2749,7 @@ 2.191 self.interned_attr_cname, 2.192 rhs.py_result())) 2.193 rhs.generate_disposal_code(code) 2.194 + rhs.free_temps(code) 2.195 else: 2.196 if (self.obj.type.is_extension_type 2.197 and self.needs_none_check 2.198 @@ -2735,7 +2766,9 @@ 2.199 rhs.result_as(self.ctype()))) 2.200 #rhs.result())) 2.201 rhs.generate_post_assignment_code(code) 2.202 + rhs.free_temps(code) 2.203 self.obj.generate_disposal_code(code) 2.204 + self.obj.free_temps(code) 2.205 2.206 def generate_deletion_code(self, code): 2.207 self.obj.generate_evaluation_code(code) 2.208 @@ -2747,6 +2780,7 @@ 2.209 else: 2.210 error(self.pos, "Cannot delete C attribute of extension type") 2.211 self.obj.generate_disposal_code(code) 2.212 + self.obj.free_temps(code) 2.213 2.214 def annotate(self, code): 2.215 if self.is_py_attr: 2.216 @@ -2835,6 +2869,10 @@ 2.217 self.generate_operation_code(code) 2.218 2.219 def generate_assignment_code(self, rhs, code): 2.220 + # Need to work around the fact that generate_evaluation_code 2.221 + # allocates the temps in a rather hacky way -- the assignment 2.222 + # is evaluated twice, within each if-block. 2.223 + 2.224 code.putln( 2.225 "if (PyTuple_CheckExact(%s) && PyTuple_GET_SIZE(%s) == %s) {" % ( 2.226 rhs.py_result(), 2.227 @@ -2850,8 +2888,12 @@ 2.228 code.put_incref(item.result(), item.ctype()) 2.229 value_node = self.coerced_unpacked_items[i] 2.230 value_node.generate_evaluation_code(code) 2.231 - rhs.generate_disposal_code(code, free_temp=False) 2.232 - 2.233 + rhs.generate_disposal_code(code) 2.234 + 2.235 + for i in range(len(self.args)): 2.236 + self.args[i].generate_assignment_code( 2.237 + self.coerced_unpacked_items[i], code) 2.238 + 2.239 code.putln("} else {") 2.240 2.241 code.putln( 2.242 @@ -2859,7 +2901,7 @@ 2.243 self.iterator.result(), 2.244 rhs.py_result(), 2.245 code.error_goto_if_null(self.iterator.result(), self.pos))) 2.246 - rhs.generate_disposal_code(code, free_temp=False) 2.247 + rhs.generate_disposal_code(code) 2.248 for i in range(len(self.args)): 2.249 item = self.unpacked_items[i] 2.250 unpack_code = "__Pyx_UnpackItem(%s, %d)" % ( 2.251 @@ -2878,12 +2920,13 @@ 2.252 print("UnpackNode.generate_assignment_code:") 2.253 print("...generating disposal code for %s" % self.iterator) 2.254 self.iterator.generate_disposal_code(code) 2.255 - 2.256 - code.putln("}") 2.257 - rhs.generate_disposal_code(code, free_temp=True, decref=False) 2.258 + self.iterator.free_temps(code) 2.259 + 2.260 for i in range(len(self.args)): 2.261 self.args[i].generate_assignment_code( 2.262 self.coerced_unpacked_items[i], code) 2.263 + code.putln("}") 2.264 + rhs.free_temps(code) 2.265 2.266 def annotate(self, code): 2.267 for arg in self.args: 2.268 @@ -2945,7 +2988,9 @@ 2.269 # of generate_disposal_code, because values were stored 2.270 # in the tuple using a reference-stealing operation. 2.271 for arg in self.args: 2.272 - arg.generate_post_assignment_code(code) 2.273 + arg.generate_post_assignment_code(code) 2.274 + # Should NOT call free_temps -- this is invoked by the default 2.275 + # generate_evaluation_code which will do that. 2.276 2.277 2.278 class ListNode(SequenceNode): 2.279 @@ -3047,7 +3092,9 @@ 2.280 # of generate_disposal_code, because values were stored 2.281 # in the list using a reference-stealing operation. 2.282 for arg in self.args: 2.283 - arg.generate_post_assignment_code(code) 2.284 + arg.generate_post_assignment_code(code) 2.285 + # Should NOT call free_temps -- this is invoked by the default 2.286 + # generate_evaluation_code which will do that. 2.287 2.288 2.289 class ListComprehensionNode(SequenceNode): 2.290 @@ -3199,6 +3246,7 @@ 2.291 item.key.value, 2.292 item.value.result())) 2.293 item.generate_disposal_code(code) 2.294 + item.free_temps(code) 2.295 2.296 def annotate(self, code): 2.297 for item in self.key_value_pairs: 2.298 @@ -3221,11 +3269,13 @@ 2.299 self.key.generate_evaluation_code(code) 2.300 self.value.generate_evaluation_code(code) 2.301 2.302 - def generate_disposal_code(self, code, free_temp=True, decref=True): 2.303 - self.key.generate_disposal_code( 2.304 - code, free_temp=free_temp, decref=decref) 2.305 - self.value.generate_disposal_code( 2.306 - code, free_temp=free_temp, decref=decref) 2.307 + def generate_disposal_code(self, code): 2.308 + self.key.generate_disposal_code(code) 2.309 + self.value.generate_disposal_code(code) 2.310 + 2.311 + def free_temps(self, code): 2.312 + self.key.free_temps(code) 2.313 + self.value.free_temps(code) 2.314 2.315 def __iter__(self): 2.316 return iter([self.key, self.value]) 2.317 @@ -4063,16 +4113,16 @@ 2.318 test_result)) 2.319 if uses_temp: 2.320 code.funcstate.release_temp(test_result) 2.321 - self.operand1.generate_disposal_code(code, free_temp=False) 2.322 + self.operand1.generate_disposal_code(code) 2.323 self.operand2.generate_evaluation_code(code) 2.324 - 2.325 self.allocate_temp_result(code) 2.326 - 2.327 code.putln("%s = %s;" % (self.result(), self.operand2.result())) 2.328 - self.operand2.generate_disposal_code(code, decref=False) 2.329 + self.operand2.generate_post_assignment_code(code) 2.330 + self.operand2.free_temps(code) 2.331 code.putln("} else {") 2.332 code.putln("%s = %s;" % (self.result(), self.operand1.result())) 2.333 - self.operand1.generate_disposal_code(code, decref=False) 2.334 + self.operand1.generate_post_assignment_code(code) 2.335 + self.operand1.free_temps(code) 2.336 code.putln("}") 2.337 2.338 def generate_operand1_test(self, code): 2.339 @@ -4175,6 +4225,7 @@ 2.340 self.false_val.generate_evaluation_code(code) 2.341 code.putln("}") 2.342 self.test.generate_disposal_code(code) 2.343 + self.test.free_temps(code) 2.344 2.345 richcmp_constants = { 2.346 "<" : "Py_LT", 2.347 @@ -4402,13 +4453,21 @@ 2.348 self.result(), self.operand2) 2.349 self.operand1.generate_disposal_code(code) 2.350 self.operand2.generate_disposal_code(code) 2.351 - 2.352 + self.operand1.free_temps(code) 2.353 + self.operand2.free_temps(code) 2.354 + 2.355 def generate_subexpr_disposal_code(self, code): 2.356 # If this is called, it is a non-cascaded cmp, 2.357 # so only need to dispose of the two main operands. 2.358 self.operand1.generate_disposal_code(code) 2.359 self.operand2.generate_disposal_code(code) 2.360 2.361 + def free_subexpr_temps(self, code): 2.362 + # If this is called, it is a non-cascaded cmp, 2.363 + # so only need to dispose of the two main operands. 2.364 + self.operand1.free_temps(code) 2.365 + self.operand2.free_temps(code) 2.366 + 2.367 def annotate(self, code): 2.368 self.operand1.annotate(code) 2.369 self.operand2.annotate(code) 2.370 @@ -4485,6 +4544,7 @@ 2.371 code, result, self.operand2) 2.372 # Cascaded cmp result is always temp 2.373 self.operand2.generate_disposal_code(code) 2.374 + self.operand2.free_temps(code) 2.375 code.putln("}") 2.376 2.377 def annotate(self, code): 2.378 @@ -4605,6 +4665,9 @@ 2.379 2.380 def generate_post_assignment_code(self, code): 2.381 self.arg.generate_post_assignment_code(code) 2.382 + 2.383 + def free_temps(self, code): 2.384 + self.arg.free_temps(code) 2.385 2.386 2.387 class CoerceToPyTypeNode(CoercionNode): 2.388 @@ -4768,7 +4831,7 @@ 2.389 def generate_result_code(self, code): 2.390 pass 2.391 2.392 - def generate_disposal_code(self, code, free_temp=True, decref=True): 2.393 + def generate_disposal_code(self, code): 2.394 pass 2.395 2.396 def allocate_temps(self, env): 2.397 @@ -4776,8 +4839,12 @@ 2.398 2.399 def release_temp(self, env): 2.400 pass 2.401 - 2.402 -class PersistentNode(ExprNode): 2.403 + 2.404 + def free_temps(self, code): 2.405 + pass 2.406 + 2.407 + 2.408 +class DISABLED_PersistentNode(ExprNode): 2.409 # A PersistentNode is like a CloneNode except it handles the temporary 2.410 # allocation itself by keeping track of the number of times it has been 2.411 # used. 2.412 @@ -4814,9 +4881,9 @@ 2.413 self.arg.generate_disposal_code(code) 2.414 self.generate_counter += 1 2.415 2.416 - def generate_disposal_code(self, code, free_temp=True, decref=True): 2.417 + def generate_disposal_code(self, code): 2.418 if self.generate_counter == self.uses: 2.419 - if self.type.is_pyobject and decref: 2.420 + if self.type.is_pyobject: 2.421 code.put_decref_clear(self.result(), self.ctype()) 2.422 2.423 def allocate_temps(self, env, result=None):
3.1 --- a/Cython/Compiler/Nodes.py Tue Dec 02 20:24:44 2008 +0100 3.2 +++ b/Cython/Compiler/Nodes.py Tue Dec 02 20:27:40 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 Tue Dec 02 20:24:44 2008 +0100 4.2 +++ b/Cython/Compiler/Optimize.py Tue Dec 02 20:27:40 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):