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

Reply via email to