self.generate_result_code(code)
if self.is_temp:
self.generate_subexpr_disposal_code(code)
+ self.free_subexpr_temps(code)
def generate_subexpr_evaluation_code(self, code):
for node in self.subexpr_nodes():
def free_temps(self, code):
pass
+ def free_subexpr_temps(self, code):
+ for sub in self.subexpr_nodes():
+ sub.free_temps(code)
+
# ---------------- Annotation ---------------------
def annotate(self, code):
class NewTempExprNode(ExprNode):
backwards_compatible_result = None
-
+ temp_code = None
+
# Do not enable this unless you are trying to make all ExprNodes
# NewTempExprNodes (child nodes reached via recursion may not have
# transferred).
# __metaclass__ = RemoveAllocateTemps
-
+
def result(self):
if self.is_temp:
return self.temp_code
self.release_subexpr_temps(env)
def allocate_temp_result(self, code):
+ if self.temp_code:
+ raise RuntimeError("Temp allocated multiple times")
type = self.type
if not type.is_void:
if type.is_pyobject:
self.temp_code = None
def release_temp_result(self, code):
+ if not self.temp_code:
+ raise RuntimeError("No temp (perhaps released multiple times? See self.old_temp)")
code.funcstate.release_temp(self.temp_code)
+ self.old_temp = self.temp_code
+ self.temp_code = None
def generate_evaluation_code(self, code):
code.mark_pos(self.pos)
# If we are temp we do not need to wait until this node is disposed
# before disposing children.
self.generate_subexpr_disposal_code(code)
+ self.free_subexpr_temps(code)
def generate_disposal_code(self, code):
if self.is_temp:
self.generate_subexpr_disposal_code(code)
def generate_post_assignment_code(self, code):
- if self.is_temp and self.type.is_pyobject:
- code.putln("%s = 0;" % self.result())
- self.generate_subexpr_disposal_code(code)
+ if self.is_temp:
+ if self.type.is_pyobject:
+ code.putln("%s = 0;" % self.result())
+ else:
+ self.generate_subexpr_disposal_code(code)
def free_temps(self, code):
if self.is_temp:
- self.release_temp_result()
- for sub in self.subexpr_nodes():
- sub.free_temps(code)
-
+ self.release_temp_result(code)
+ else:
+ self.free_subexpr_temps(code)
+
# ExprNode = NewTempExprNode
class AtomicExprNode(ExprNode):
print("NameNode.generate_assignment_code:")
print("...generating disposal code for %s" % rhs)
rhs.generate_disposal_code(code)
-
+ rhs.free_temps(code)
else:
if self.type.is_buffer:
# Generate code for doing the buffer release/acquisition.
print("NameNode.generate_assignment_code:")
print("...generating post-assignment code for %s" % rhs)
rhs.generate_post_assignment_code(code)
+ rhs.free_temps(code)
def generate_acquire_buffer(self, rhs, code):
# rhstmp is only used in case the rhs is a complicated expression leading to
for i in self.indices:
i.generate_disposal_code(code)
+ def free_subexpr_temps(self, code):
+ self.base.free_temps(code)
+ if not self.indices:
+ self.index.free_temps(code)
+ else:
+ for i in self.indices:
+ i.free_temps(code)
+
def generate_result_code(self, code):
if self.is_buffer_access:
if code.globalstate.directives['nonecheck']:
"%s = %s;" % (
self.result(), rhs.result()))
self.generate_subexpr_disposal_code(code)
+ self.free_subexpr_temps(code)
rhs.generate_disposal_code(code)
+ rhs.free_temps(code)
def generate_deletion_code(self, code):
self.generate_subexpr_evaluation_code(code)
rhs.result(), i))
self.generate_subexpr_disposal_code(code)
rhs.generate_disposal_code(code)
+ rhs.free_temps(code)
def generate_deletion_code(self, code):
if not self.type.is_pyobject:
self.interned_attr_cname,
rhs.py_result()))
rhs.generate_disposal_code(code)
+ rhs.free_temps(code)
else:
if (self.obj.type.is_extension_type
and self.needs_none_check
rhs.result_as(self.ctype())))
#rhs.result()))
rhs.generate_post_assignment_code(code)
+ rhs.free_temps(code)
self.obj.generate_disposal_code(code)
+ self.obj.free_temps(code)
def generate_deletion_code(self, code):
self.obj.generate_evaluation_code(code)
else:
error(self.pos, "Cannot delete C attribute of extension type")
self.obj.generate_disposal_code(code)
+ self.obj.free_temps(code)
def annotate(self, code):
if self.is_py_attr:
self.generate_operation_code(code)
def generate_assignment_code(self, rhs, code):
+ # Need to work around the fact that generate_evaluation_code
+ # allocates the temps in a rather hacky way -- the assignment
+ # is evaluated twice, within each if-block.
+
code.putln(
"if (PyTuple_CheckExact(%s) && PyTuple_GET_SIZE(%s) == %s) {" % (
rhs.py_result(),
value_node.generate_evaluation_code(code)
rhs.generate_disposal_code(code)
+ for i in range(len(self.args)):
+ self.args[i].generate_assignment_code(
+ self.coerced_unpacked_items[i], code)
+
code.putln("} else {")
code.putln(
print("UnpackNode.generate_assignment_code:")
print("...generating disposal code for %s" % self.iterator)
self.iterator.generate_disposal_code(code)
+ self.iterator.free_temps(code)
- code.putln("}")
- rhs.free_temps()
for i in range(len(self.args)):
self.args[i].generate_assignment_code(
self.coerced_unpacked_items[i], code)
+ code.putln("}")
+ rhs.free_temps(code)
def annotate(self, code):
for arg in self.args:
# of generate_disposal_code, because values were stored
# in the tuple using a reference-stealing operation.
for arg in self.args:
- arg.generate_post_assignment_code(code)
+ arg.generate_post_assignment_code(code)
+ # Should NOT call free_temps -- this is invoked by the default
+ # generate_evaluation_code which will do that.
class ListNode(SequenceNode):
# of generate_disposal_code, because values were stored
# in the list using a reference-stealing operation.
for arg in self.args:
- arg.generate_post_assignment_code(code)
+ arg.generate_post_assignment_code(code)
+ # Should NOT call free_temps -- this is invoked by the default
+ # generate_evaluation_code which will do that.
class ListComprehensionNode(SequenceNode):
item.key.value,
item.value.result()))
item.generate_disposal_code(code)
+ item.free_temps(code)
def annotate(self, code):
for item in self.key_value_pairs:
def generate_disposal_code(self, code):
self.key.generate_disposal_code(code)
self.value.generate_disposal_code(code)
+
+ def free_temps(self, code):
+ self.key.free_temps(code)
+ self.value.free_temps(code)
def __iter__(self):
return iter([self.key, self.value])
self.operand2.generate_evaluation_code(code)
self.allocate_temp_result(code)
code.putln("%s = %s;" % (self.result(), self.operand2.result()))
- self.operand2.free_temps()
+ self.operand2.generate_post_assignment_code(code)
+ self.operand2.free_temps(code)
code.putln("} else {")
code.putln("%s = %s;" % (self.result(), self.operand1.result()))
- self.operand1.free_temps()
+ self.operand1.generate_post_assignment_code(code)
+ self.operand1.free_temps(code)
code.putln("}")
def generate_operand1_test(self, code):
self.false_val.generate_evaluation_code(code)
code.putln("}")
self.test.generate_disposal_code(code)
+ self.test.free_temps(code)
richcmp_constants = {
"<" : "Py_LT",
self.result(), self.operand2)
self.operand1.generate_disposal_code(code)
self.operand2.generate_disposal_code(code)
-
+ self.operand1.free_temps(code)
+ self.operand2.free_temps(code)
+
def generate_subexpr_disposal_code(self, code):
# If this is called, it is a non-cascaded cmp,
# so only need to dispose of the two main operands.
self.operand1.generate_disposal_code(code)
self.operand2.generate_disposal_code(code)
+ def free_subexpr_temps(self, code):
+ # If this is called, it is a non-cascaded cmp,
+ # so only need to dispose of the two main operands.
+ self.operand1.free_temps(code)
+ self.operand2.free_temps(code)
+
def annotate(self, code):
self.operand1.annotate(code)
self.operand2.annotate(code)
code, result, self.operand2)
# Cascaded cmp result is always temp
self.operand2.generate_disposal_code(code)
+ self.operand2.free_temps(code)
code.putln("}")
def annotate(self, code):
def generate_post_assignment_code(self, code):
self.arg.generate_post_assignment_code(code)
+
+ def free_temps(self, code):
+ self.arg.free_temps(code)
class CoerceToPyTypeNode(CoercionNode):
def release_temp(self, env):
pass
+
+ def free_temps(self, code):
+ pass
+
-class PersistentNode(ExprNode):
+class DISABLED_PersistentNode(ExprNode):
# A PersistentNode is like a CloneNode except it handles the temporary
# allocation itself by keeping track of the number of times it has been
# used.
self.body.generate_execution_code(code)
self.target.generate_assignment_code(self.classobj, code)
self.dict.generate_disposal_code(code)
+ self.dict.free_temps(code)
class CClassDefNode(ClassDefNode):
if not self.expr.is_temp and self.expr.result():
code.putln("%s;" % self.expr.result())
self.expr.generate_disposal_code(code)
+ self.expr.free_temps(code)
def annotate(self, code):
self.expr.annotate(code)
lhs.generate_assignment_code(rhs, code)
# Assignment has disposed of the cloned RHS
self.rhs.generate_disposal_code(code)
+ self.rhs.free_temps(code)
def annotate(self, code):
for i in range(len(self.lhs_list)):
code.error_goto_if_null(self.result_value.py_result(), self.pos)))
self.result_value.generate_evaluation_code(code) # May be a type check...
self.rhs.generate_disposal_code(code)
+ self.rhs.free_temps(code)
self.dup.generate_disposal_code(code)
+ self.dup.free_temps(code)
self.lhs.generate_assignment_code(self.result_value, code)
else:
c_op = self.operator
self.dup.generate_result_code(code)
code.putln("%s %s= %s;" % (self.lhs.result(), c_op, self.rhs.result()) )
self.rhs.generate_disposal_code(code)
+ self.rhs.free_temps(code)
if self.dup.is_temp:
self.dup.generate_subexpr_disposal_code(code)
+ self.dup.free_subexpr_temps(code)
def create_dup_node(self, env):
import ExprNodes
index = index,
indices = indices,
is_temp = self.dup.is_temp)
+ else:
+ assert False
self.lhs = target_lhs
return self.dup
self.append_newline,
code.error_goto(self.pos)))
self.arg_tuple.generate_disposal_code(code)
+ self.arg_tuple.free_temps(code)
def annotate(self, code):
self.arg_tuple.annotate(code)
(self.temp_result,) + args))
for arg in self.args:
arg.generate_disposal_code(code)
+ arg.free_temps(code)
code.putln(
code.error_goto_if_null(self.temp_result, self.pos))
code.put_decref_clear(self.temp_result, py_object_type)
Naming.retval_cname,
self.value.result_as(self.return_type)))
self.value.generate_post_assignment_code(code)
+ self.value.free_temps(code)
else:
if self.return_type.is_pyobject:
code.put_init_to_py_none(Naming.retval_cname, self.return_type)
"__Pyx_ReRaise();")
if self.exc_type:
self.exc_type.generate_disposal_code(code)
+ self.exc_type.free_temps(code)
if self.exc_value:
self.exc_value.generate_disposal_code(code)
+ self.exc_value.free_temps(code)
if self.exc_tb:
self.exc_tb.generate_disposal_code(code)
+ self.exc_tb.free_temps(code)
code.putln(
code.error_goto(self.pos))
"PyErr_SetObject(PyExc_AssertionError, %s);" %
self.value.py_result())
self.value.generate_disposal_code(code)
+ self.value.free_temps(code)
else:
code.putln(
"PyErr_SetNone(PyExc_AssertionError);")
code.putln(
"}")
self.cond.generate_disposal_code(code)
+ self.cond.free_temps(code)
code.putln("#endif")
def annotate(self, code):
code.put_label(break_label)
self.iterator.release_counter_temp(code)
self.iterator.generate_disposal_code(code)
+ self.iterator.free_temps(code)
def annotate(self, code):
self.target.annotate(code)
code.putln("}")
code.put_label(break_label)
self.bound1.generate_disposal_code(code)
+ self.bound1.free_temps(code)
self.bound2.generate_disposal_code(code)
+ self.bound2.free_temps(code)
if self.step is not None:
self.step.generate_disposal_code(code)
+ self.step.free_temps(code)
relation_table = {
# {relop : (initial offset, increment op)}
self.match_flag,
self.pattern.py_result()))
self.pattern.generate_disposal_code(code)
+ self.pattern.free_temps(code)
code.putln(
"if (%s) {" %
self.match_flag)
code.error_goto_if_null(self.item.result(), self.pos)))
target.generate_assignment_code(self.item, code)
self.module.generate_disposal_code(code)
+ self.module.free_temps(code)