[pypy-commit] pypy default: (cfbolz, arigo giving the idea) to construct gigantic tuples in constant stack
cfbolz
pypy.commits at gmail.com
Wed Mar 27 18:01:23 EDT 2019
Author: Carl Friedrich Bolz-Tereick <cfbolz at gmx.de>
Branch:
Changeset: r96369:f6a9c3de9c7d
Date: 2019-03-27 22:51 +0100
http://bitbucket.org/pypy/pypy/changeset/f6a9c3de9c7d/
Log: (cfbolz, arigo giving the idea) to construct gigantic tuples in
constant stack space, first build a list, then use
().__class__(list) to turn it into a tuple. bit of a hack, but
calling 'tuple' doesn't work if somebody overrides the global name
'tuple'
diff --git a/pypy/interpreter/astcompiler/codegen.py b/pypy/interpreter/astcompiler/codegen.py
--- a/pypy/interpreter/astcompiler/codegen.py
+++ b/pypy/interpreter/astcompiler/codegen.py
@@ -912,6 +912,20 @@
elt_count = len(tup.elts) if tup.elts is not None else 0
if tup.ctx == ast.Store:
self.emit_op_arg(ops.UNPACK_SEQUENCE, elt_count)
+ if tup.ctx == ast.Load and elt_count > MAX_STACKDEPTH_CONTAINERS:
+ # we need a complete hack to build a new tuple from the list
+ # ().__class__(l)
+ empty_index = self.add_const(self.space.newtuple([]))
+ self.emit_op_arg(ops.LOAD_CONST, empty_index)
+ self.emit_op_name(ops.LOAD_ATTR, self.names, '__class__')
+
+ self.emit_op_arg(ops.BUILD_LIST, 0)
+ for element in tup.elts:
+ element.walkabout(self)
+ self.emit_op_arg(ops.LIST_APPEND, 1)
+
+ self.emit_op_arg(ops.CALL_FUNCTION, 1)
+ return
self.visit_sequence(tup.elts)
if tup.ctx == ast.Load:
self.emit_op_arg(ops.BUILD_TUPLE, elt_count)
diff --git a/pypy/interpreter/astcompiler/test/test_compiler.py b/pypy/interpreter/astcompiler/test/test_compiler.py
--- a/pypy/interpreter/astcompiler/test/test_compiler.py
+++ b/pypy/interpreter/astcompiler/test/test_compiler.py
@@ -1220,22 +1220,27 @@
class TestHugeStackDepths:
- def test_list(self):
+ def run_and_check_stacksize(self, source):
space = self.space
- source = "a = [" + ",".join([str(i) for i in range(200)]) + "]\n"
- code = compile_with_astcompiler(source, 'exec', space)
+ code = compile_with_astcompiler("a = " + source, 'exec', space)
assert code.co_stacksize < 100
w_dict = space.newdict()
code.exec_code(space, w_dict, w_dict)
- assert space.unwrap(space.getitem(w_dict, space.newtext("a"))) == range(200)
+ return space.getitem(w_dict, space.newtext("a"))
+
+ def test_tuple(self):
+ source = "(" + ",".join([str(i) for i in range(200)]) + ")\n"
+ w_res = self.run_and_check_stacksize(source)
+ assert self.space.unwrap(w_res) == tuple(range(200))
+
+ def test_list(self):
+ source = "a = [" + ",".join([str(i) for i in range(200)]) + "]\n"
+ w_res = self.run_and_check_stacksize(source)
+ assert self.space.unwrap(w_res) == range(200)
def test_set(self):
+ source = "a = {" + ",".join([str(i) for i in range(200)]) + "}\n"
+ w_res = self.run_and_check_stacksize(source)
space = self.space
- source = "a = {" + ",".join([str(i) for i in range(200)]) + "}\n"
- code = compile_with_astcompiler(source, 'exec', space)
- assert code.co_stacksize < 100
- w_dict = space.newdict()
- code.exec_code(space, w_dict, w_dict)
assert [space.int_w(w_x)
- for w_x in space.unpackiterable(space.getitem(w_dict, space.newtext("a")))] == range(200)
-
+ for w_x in space.unpackiterable(w_res)] == range(200)
More information about the pypy-commit
mailing list