Commit 137545fd authored by Stefan Behnel's avatar Stefan Behnel

handle simple swap assignments without ref-counting

parent 166ffcdb
......@@ -61,11 +61,13 @@ class ExprNode(Node):
# saved_subexpr_nodes
# [ExprNode or [ExprNode or None] or None]
# Cached result of subexpr_nodes()
# use_managed_ref boolean use ref-counted temps/assignments/etc.
result_ctype = None
type = None
temp_code = None
old_temp = None # error checker for multiple frees etc.
use_managed_ref = True # can be set by optimisation transforms
# The Analyse Expressions phase for expressions is split
# into two sub-phases:
......@@ -419,7 +421,7 @@ class ExprNode(Node):
if type.is_pyobject:
type = PyrexTypes.py_object_type
self.temp_code = code.funcstate.allocate_temp(
type, manage_ref=True)
type, manage_ref=self.use_managed_ref)
else:
self.temp_code = None
......@@ -1346,14 +1348,15 @@ class NameNode(AtomicExprNode):
self.generate_acquire_buffer(rhs, code)
if self.type.is_pyobject:
rhs.make_owned_reference(code)
#print "NameNode.generate_assignment_code: to", self.name ###
#print "...from", rhs ###
#print "...LHS type", self.type, "ctype", self.ctype() ###
#print "...RHS type", rhs.type, "ctype", rhs.ctype() ###
if self.use_managed_ref:
rhs.make_owned_reference(code)
if entry.is_cglobal:
code.put_gotref(self.py_result())
if not self.lhs_of_first_assignment:
if self.use_managed_ref and not self.lhs_of_first_assignment:
if entry.is_local and not Options.init_local_none:
initalized = entry.scope.control_flow.get_state((entry.name, 'initalized'), self.pos)
if initalized is True:
......@@ -1362,6 +1365,7 @@ class NameNode(AtomicExprNode):
code.put_xdecref(self.result(), self.ctype())
else:
code.put_decref(self.result(), self.ctype())
if self.use_managed_ref:
if entry.is_cglobal:
code.put_giveref(rhs.py_result())
code.putln('%s = %s;' % (self.result(), rhs.result_as(self.ctype())))
......@@ -5784,7 +5788,7 @@ class CoerceToTempNode(CoercionNode):
# by generic generate_subexpr_evaluation_code!
code.putln("%s = %s;" % (
self.result(), self.arg.result_as(self.ctype())))
if self.type.is_pyobject:
if self.type.is_pyobject and self.use_managed_ref:
code.put_incref(self.result(), self.ctype())
......
......@@ -20,6 +20,11 @@ try:
except NameError:
from functools import reduce
try:
set
except NameError:
from sets import Set as set
def unwrap_node(node):
while isinstance(node, UtilNodes.ResultRefNode):
node = node.expression
......@@ -517,6 +522,46 @@ class FlattenInListTransform(Visitor.VisitorTransform, SkipDeclarations):
visit_Node = Visitor.VisitorTransform.recurse_to_children
class DropRefcountingTransform(Visitor.VisitorTransform):
"""Drop ref-counting in safe places.
"""
visit_Node = Visitor.VisitorTransform.recurse_to_children
def visit_ParallelAssignmentNode(self, node):
left, right, temps = [], [], []
for stat in node.stats:
if isinstance(stat, Nodes.SingleAssignmentNode):
lhs = unwrap_node(stat.lhs)
if not isinstance(lhs, ExprNodes.NameNode):
return node
left.append(lhs)
rhs = unwrap_node(stat.rhs)
if isinstance(rhs, ExprNodes.CoerceToTempNode):
temps.append(rhs)
rhs = rhs.arg
if not isinstance(rhs, ExprNodes.NameNode):
return node
right.append(rhs)
else:
return node
for name_node in left + right:
if name_node.entry.is_builtin or name_node.entry.is_pyglobal:
return node
left_names = [n.name for n in left]
right_names = [n.name for n in right]
if set(left_names) != set(right_names):
return node
if len(set(left_names)) != len(right):
return node
for name_node in left + right + temps:
name_node.use_managed_ref = False
return node
class OptimizeBuiltinCalls(Visitor.VisitorTransform):
"""Optimize some common methods calls and instantiation patterns
for builtin types.
......
__doc__ = u"""
>>> swap(1,2)
(2, 1)
"""
def swap(a,b):
a,b = b,a
return a,b
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment