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):
