Author: Carl Friedrich Bolz-Tereick <cfb...@gmx.de> Branch: Changeset: r96362:c46e92cbc2f9 Date: 2019-03-27 14:41 +0100 http://bitbucket.org/pypy/pypy/changeset/c46e92cbc2f9/
Log: issue2980: stop using arbitrarily much stack for building constant lists and sets. do it element by element instead. otherwise the JIT cannot produce any code for any of the loops in the same scope, because it runs into limitations. 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 @@ -19,6 +19,7 @@ symbols = symtable.SymtableBuilder(space, module, info) return TopLevelCodeGenerator(space, module, symbols, info).assemble() +MAX_STACKDEPTH_CONTAINERS = 100 name_ops_default = misc.dict_to_switch({ ast.Load: ops.LOAD_NAME, @@ -920,9 +921,17 @@ elt_count = len(l.elts) if l.elts is not None else 0 if l.ctx == ast.Store: self.emit_op_arg(ops.UNPACK_SEQUENCE, elt_count) - self.visit_sequence(l.elts) - if l.ctx == ast.Load: - self.emit_op_arg(ops.BUILD_LIST, elt_count) + if elt_count > MAX_STACKDEPTH_CONTAINERS: + # pushing all the elements would make the stack depth gigantic. + # build the list incrementally instead + self.emit_op_arg(ops.BUILD_LIST, 0) + for element in l.elts: + element.walkabout(self) + self.emit_op_arg(ops.LIST_APPEND, 1) + else: + self.visit_sequence(l.elts) + if l.ctx == ast.Load: + self.emit_op_arg(ops.BUILD_LIST, elt_count) def visit_Dict(self, d): self.update_position(d.lineno) @@ -936,8 +945,15 @@ def visit_Set(self, s): self.update_position(s.lineno) elt_count = len(s.elts) if s.elts is not None else 0 - self.visit_sequence(s.elts) - self.emit_op_arg(ops.BUILD_SET, elt_count) + if elt_count > MAX_STACKDEPTH_CONTAINERS: + self.emit_op_arg(ops.BUILD_SET, 0) + for element in s.elts: + element.walkabout(self) + self.emit_op_arg(ops.SET_ADD, 1) + else: + self.visit_sequence(s.elts) + self.emit_op_arg(ops.BUILD_SET, elt_count) + def visit_Name(self, name): self.update_position(name.lineno) 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 @@ -1218,3 +1218,24 @@ counts = self.count_instructions(source) assert ops.BUILD_TUPLE not in counts + +class TestHugeStackDepths: + def test_list(self): + 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.unwrap(space.getitem(w_dict, space.newtext("a"))) == range(200) + + def test_set(self): + 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) + _______________________________________________ pypy-commit mailing list pypy-commit@python.org https://mail.python.org/mailman/listinfo/pypy-commit