Author: Armin Rigo <[email protected]>
Branch:
Changeset: r91038:423026acc94c
Date: 2017-04-11 19:08 +0200
http://bitbucket.org/pypy/pypy/changeset/423026acc94c/
Log: Fix co_freevars and co_cellvars to always list variables in
alphabetical order. It seems that some bytecode hacks depend on it
(or at least getting a consistent order even between different
functions).
diff --git a/pypy/interpreter/astcompiler/assemble.py
b/pypy/interpreter/astcompiler/assemble.py
--- a/pypy/interpreter/astcompiler/assemble.py
+++ b/pypy/interpreter/astcompiler/assemble.py
@@ -7,6 +7,7 @@
from pypy.interpreter.astcompiler import ast, misc, symtable
from pypy.interpreter.error import OperationError
from pypy.interpreter.pycode import PyCode
+from pypy.interpreter.miscutils import string_sort
from pypy.tool import stdlib_opcode as ops
@@ -138,9 +139,12 @@
def _make_index_dict_filter(syms, flag):
+ names = syms.keys()
+ string_sort(names) # return cell vars in alphabetical order
i = 0
result = {}
- for name, scope in syms.iteritems():
+ for name in names:
+ scope = syms[name]
if scope == flag:
result[name] = i
i += 1
@@ -170,6 +174,7 @@
self.var_names = _list_to_dict(scope.varnames)
self.cell_vars = _make_index_dict_filter(scope.symbols,
symtable.SCOPE_CELL)
+ string_sort(scope.free_vars) # return free vars in alphabetical
order
self.free_vars = _list_to_dict(scope.free_vars, len(self.cell_vars))
self.w_consts = space.newdict()
self.argcount = 0
diff --git a/pypy/interpreter/astcompiler/symtable.py
b/pypy/interpreter/astcompiler/symtable.py
--- a/pypy/interpreter/astcompiler/symtable.py
+++ b/pypy/interpreter/astcompiler/symtable.py
@@ -36,7 +36,7 @@
self.roles = {}
self.varnames = []
self.children = []
- self.free_vars = []
+ self.free_vars = [] # a bag of names: the order doesn't matter here
self.temp_name_counter = 1
self.has_exec = False
self.has_free = False
diff --git a/pypy/interpreter/miscutils.py b/pypy/interpreter/miscutils.py
--- a/pypy/interpreter/miscutils.py
+++ b/pypy/interpreter/miscutils.py
@@ -2,6 +2,9 @@
Miscellaneous utilities.
"""
+from rpython.rlib.listsort import make_timsort_class
+
+
class ThreadLocals:
"""Pseudo thread-local storage, for 'space.threadlocals'.
This is not really thread-local at all; the intention is that the PyPy
@@ -53,3 +56,15 @@
def set(self, key, value):
self._dict[key] = value
return FakeWeakValueDict()
+
+
+_StringBaseTimSort = make_timsort_class()
+
+class StringSort(_StringBaseTimSort):
+ def lt(self, a, b):
+ return a < b
+
+def string_sort(lst):
+ """Sort a (resizable) list of strings."""
+ sorter = StringSort(lst, len(lst))
+ sorter.sort()
diff --git a/pypy/interpreter/test/test_compiler.py
b/pypy/interpreter/test/test_compiler.py
--- a/pypy/interpreter/test/test_compiler.py
+++ b/pypy/interpreter/test/test_compiler.py
@@ -787,6 +787,32 @@
else:
assert l1 == l2 == l3 == l4 == [1, 3, 2, 4]
+ def test_freevars_order(self):
+ # co_cellvars and co_freevars are guaranteed to appear in
+ # alphabetical order. See CPython Issue #15368 (which does
+ # not come with tests).
+ source = """if 1:
+ def f1(x1,x2,x3,x4,x5,x6,x7,x8,x9,x10,x11,x12,x13,x14,x15):
+ def g1():
+ return (x1,x2,x3,x4,x5,x6,x7,x8,x9,x10,x11,x12,x13,x14,x15)
+ return g1
+ def f2(x15,x14,x13,x12,x11,x10,x9,x8,x7,x6,x5,x4,x3,x2,x1):
+ def g2():
+ return (x15,x14,x13,x12,x11,x10,x9,x8,x7,x6,x5,x4,x3,x2,x1)
+ return g2
+ c1 = f1(*range(15)).__code__.co_freevars
+ c2 = f2(*range(15)).__code__.co_freevars
+ r1 = f1.__code__.co_cellvars
+ r2 = f2.__code__.co_cellvars
+ """
+ d = {}
+ exec(source, d)
+ assert d['c1'] == d['c2']
+ # the test above is important for a few bytecode hacks,
+ # but actually we get them in alphabetical order, so check that:
+ assert d['c1'] == tuple(sorted(d['c1']))
+ assert d['r1'] == d['r2'] == d['c1']
+
##class TestPythonAstCompiler(BaseTestCompiler):
## def setup_method(self, method):
diff --git a/pypy/objspace/std/listobject.py b/pypy/objspace/std/listobject.py
--- a/pypy/objspace/std/listobject.py
+++ b/pypy/objspace/std/listobject.py
@@ -23,6 +23,7 @@
WrappedDefault, applevel, interp2app, unwrap_spec)
from pypy.interpreter.signature import Signature
from pypy.interpreter.typedef import TypeDef
+from pypy.interpreter.miscutils import StringSort
from pypy.objspace.std.bytesobject import W_BytesObject
from pypy.objspace.std.floatobject import W_FloatObject
from pypy.objspace.std.intobject import W_IntObject
@@ -2060,7 +2061,6 @@
IntBaseTimSort = make_timsort_class()
FloatBaseTimSort = make_timsort_class()
IntOrFloatBaseTimSort = make_timsort_class()
-StringBaseTimSort = make_timsort_class()
UnicodeBaseTimSort = make_timsort_class()
@@ -2097,11 +2097,6 @@
return fa < fb
-class StringSort(StringBaseTimSort):
- def lt(self, a, b):
- return a < b
-
-
class UnicodeSort(UnicodeBaseTimSort):
def lt(self, a, b):
return a < b
diff --git a/pypy/objspace/std/typeobject.py b/pypy/objspace/std/typeobject.py
--- a/pypy/objspace/std/typeobject.py
+++ b/pypy/objspace/std/typeobject.py
@@ -1043,7 +1043,7 @@
def create_all_slots(w_self, hasoldstylebase, w_bestbase, force_new_layout):
- from pypy.objspace.std.listobject import StringSort
+ from pypy.interpreter.miscutils import string_sort
base_layout = w_bestbase.layout
index_next_extra_slot = base_layout.nslots
@@ -1077,8 +1077,7 @@
else:
newslotnames.append(slot_name)
# Sort the list of names collected so far
- sorter = StringSort(newslotnames, len(newslotnames))
- sorter.sort()
+ string_sort(newslotnames)
# Try to create all slots in order. The creation of some of
# them might silently fail; then we delete the name from the
# list. At the end, 'index_next_extra_slot' has been advanced
_______________________________________________
pypy-commit mailing list
[email protected]
https://mail.python.org/mailman/listinfo/pypy-commit