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