Commit fa2cfc80 authored by Stefan Behnel's avatar Stefan Behnel

reduce code overhead for tuple constants by using PyTuple_Pack() instead of...

reduce code overhead for tuple constants by using PyTuple_Pack() instead of step-by-step tuple construction code
parent 8c00a0c7
...@@ -4986,68 +4986,78 @@ class SequenceNode(ExprNode): ...@@ -4986,68 +4986,78 @@ class SequenceNode(ExprNode):
def generate_sequence_packing_code(self, code, target=None, plain=False): def generate_sequence_packing_code(self, code, target=None, plain=False):
if target is None: if target is None:
target = self.result() target = self.result()
py_multiply = self.mult_factor and not self.mult_factor.type.is_int size_factor = c_mult = ''
if plain or py_multiply: mult_factor = None
mult_factor = None
else: if self.mult_factor and not plain:
mult_factor = self.mult_factor mult_factor = self.mult_factor
if mult_factor: if mult_factor.type.is_int:
mult = mult_factor.result() c_mult = mult_factor.result()
if isinstance(mult_factor.constant_result, (int,long)) \ if isinstance(mult_factor.constant_result, (int,long)) \
and mult_factor.constant_result > 0: and mult_factor.constant_result > 0:
size_factor = ' * %s' % mult_factor.constant_result size_factor = ' * %s' % mult_factor.constant_result
else:
size_factor = ' * ((%s<0) ? 0:%s)' % (c_mult, c_mult)
if self.type is Builtin.tuple_type and self.is_literal and not c_mult:
# use PyTuple_Pack() to avoid generating huge amounts of one-time code
code.putln('%s = PyTuple_Pack(%d, %s); %s' % (
target,
len(self.args),
', '.join([ arg.py_result() for arg in self.args ]),
code.error_goto_if_null(target, self.pos)))
code.put_gotref(target)
else:
# build the tuple/list step by step, potentially multiplying it as we go
if self.type is Builtin.list_type:
create_func, set_item_func = 'PyList_New', 'PyList_SET_ITEM'
elif self.type is Builtin.tuple_type:
create_func, set_item_func = 'PyTuple_New', 'PyTuple_SET_ITEM'
else: else:
size_factor = ' * ((%s<0) ? 0:%s)' % (mult, mult) raise InternalError("sequence packing for unexpected type %s" % self.type)
else: arg_count = len(self.args)
size_factor = '' code.putln("%s = %s(%s%s); %s" % (
mult = '' target, create_func, arg_count, size_factor,
code.error_goto_if_null(target, self.pos)))
if self.type is Builtin.list_type: code.put_gotref(target)
create_func, set_item_func = 'PyList_New', 'PyList_SET_ITEM'
elif self.type is Builtin.tuple_type: if c_mult:
create_func, set_item_func = 'PyTuple_New', 'PyTuple_SET_ITEM' # FIXME: can't use a temp variable here as the code may
else: # end up in the constant building function. Temps
raise InternalError("sequence packing for unexpected type %s" % self.type) # currently don't work there.
arg_count = len(self.args)
code.putln("%s = %s(%s%s); %s" % ( #counter = code.funcstate.allocate_temp(mult_factor.type, manage_ref=False)
target, create_func, arg_count, size_factor, counter = Naming.quick_temp_cname
code.error_goto_if_null(target, self.pos))) code.putln('{ Py_ssize_t %s;' % counter)
code.put_gotref(target) if arg_count == 1:
offset = counter
if mult: else:
# FIXME: can't use a temp variable here as the code may offset = '%s * %s' % (counter, arg_count)
# end up in the constant building function. Temps code.putln('for (%s=0; %s < %s; %s++) {' % (
# currently don't work there. counter, counter, c_mult, counter
))
#counter = code.funcstate.allocate_temp(mult_factor.type, manage_ref=False)
counter = Naming.quick_temp_cname
code.putln('{ Py_ssize_t %s;' % counter)
if arg_count == 1:
offset = counter
else: else:
offset = '%s * %s' % (counter, arg_count) offset = ''
code.putln('for (%s=0; %s < %s; %s++) {' % (
counter, counter, mult, counter for i in xrange(arg_count):
)) arg = self.args[i]
else: if c_mult or not arg.result_in_temp():
offset = '' code.put_incref(arg.result(), arg.ctype())
for i in xrange(arg_count): code.putln("%s(%s, %s, %s);" % (
arg = self.args[i] set_item_func,
if mult or not arg.result_in_temp(): target,
code.put_incref(arg.result(), arg.ctype()) (offset and i) and ('%s + %s' % (offset, i)) or (offset or i),
code.putln("%s(%s, %s, %s);" % ( arg.py_result()))
set_item_func, code.put_giveref(arg.py_result())
target,
(offset and i) and ('%s + %s' % (offset, i)) or (offset or i), if c_mult:
arg.py_result())) code.putln('}')
code.put_giveref(arg.py_result()) #code.funcstate.release_temp(counter)
if mult: code.putln('}')
code.putln('}')
#code.funcstate.release_temp(counter) if mult_factor is not None and mult_factor.type.is_pyobject:
code.putln('}')
elif py_multiply and not plain:
code.putln('{ PyObject* %s = PyNumber_InPlaceMultiply(%s, %s); %s' % ( code.putln('{ PyObject* %s = PyNumber_InPlaceMultiply(%s, %s); %s' % (
Naming.quick_temp_cname, target, self.mult_factor.py_result(), Naming.quick_temp_cname, target, mult_factor.py_result(),
code.error_goto_if_null(Naming.quick_temp_cname, self.pos) code.error_goto_if_null(Naming.quick_temp_cname, self.pos)
)) ))
code.put_gotref(Naming.quick_temp_cname) code.put_gotref(Naming.quick_temp_cname)
......
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