changeset: 104178:7cea3bf44acb branch: 2.7 parent: 104171:5f788ad057ca user: Serhiy Storchaka date: Fri Sep 30 10:38:08 2016 +0300 files: Lib/test/test_code.py Misc/NEWS Objects/codeobject.c description: Issue #27942: String constants now interned recursively in tuples and frozensets. diff -r 5f788ad057ca -r 7cea3bf44acb Lib/test/test_code.py --- a/Lib/test/test_code.py Fri Sep 30 02:53:33 2016 -0400 +++ b/Lib/test/test_code.py Fri Sep 30 10:38:08 2016 +0300 @@ -112,6 +112,37 @@ self.assertEqual(co.co_name, "funcname") self.assertEqual(co.co_firstlineno, 15) +class CodeConstsTest(unittest.TestCase): + + def find_const(self, consts, value): + for v in consts: + if v == value: + return v + self.assertIn(value, consts) # rises an exception + self.fail('Should be never reached') + + def assertIsInterned(self, s): + if s is not intern(s): + self.fail('String %r is not interned' % (s,)) + + @cpython_only + def test_interned_string(self): + co = compile('res = "str_value"', '?', 'exec') + v = self.find_const(co.co_consts, 'str_value') + self.assertIsInterned(v) + + @cpython_only + def test_interned_string_in_tuple(self): + co = compile('res = ("str_value",)', '?', 'exec') + v = self.find_const(co.co_consts, ('str_value',)) + self.assertIsInterned(v[0]) + + @cpython_only + def test_interned_string_default(self): + def f(a='str_value'): + return a + self.assertIsInterned(f()) + class CodeWeakRefTest(unittest.TestCase): @@ -141,7 +172,7 @@ def test_main(verbose=None): from test import test_code run_doctest(test_code, verbose) - run_unittest(CodeTest, CodeWeakRefTest) + run_unittest(CodeTest, CodeConstsTest, CodeWeakRefTest) if __name__ == "__main__": diff -r 5f788ad057ca -r 7cea3bf44acb Misc/NEWS --- a/Misc/NEWS Fri Sep 30 02:53:33 2016 -0400 +++ b/Misc/NEWS Fri Sep 30 10:38:08 2016 +0300 @@ -10,6 +10,8 @@ Core and Builtins ----------------- +- Issue #27942: String constants now interned recursively in tuples and frozensets. + - Issue #15578: Correctly incref the parent module while importing. - Issue #26307: The profile-opt build now applys PGO to the built-in modules. diff -r 5f788ad057ca -r 7cea3bf44acb Objects/codeobject.c --- a/Objects/codeobject.c Fri Sep 30 02:53:33 2016 -0400 +++ b/Objects/codeobject.c Fri Sep 30 10:38:08 2016 +0300 @@ -39,6 +39,50 @@ } } +/* Intern selected string constants */ +static int +intern_string_constants(PyObject *tuple) +{ + int modified = 0; + Py_ssize_t i; + + for (i = PyTuple_GET_SIZE(tuple); --i >= 0; ) { + PyObject *v = PyTuple_GET_ITEM(tuple, i); + if (PyString_CheckExact(v)) { + if (all_name_chars((unsigned char *)PyString_AS_STRING(v))) { + PyObject *w = v; + PyString_InternInPlace(&v); + if (w != v) { + PyTuple_SET_ITEM(tuple, i, v); + modified = 1; + } + } + } + else if (PyTuple_CheckExact(v)) { + intern_string_constants(v); + } + else if (PyFrozenSet_CheckExact(v)) { + PyObject *tmp = PySequence_Tuple(v); + if (tmp == NULL) { + PyErr_Clear(); + continue; + } + if (intern_string_constants(tmp)) { + v = PyFrozenSet_New(tmp); + if (v == NULL) { + PyErr_Clear(); + } + else { + PyTuple_SET_ITEM(tuple, i, v); + modified = 1; + } + } + Py_DECREF(tmp); + } + } + return modified; +} + PyCodeObject * PyCode_New(int argcount, int nlocals, int stacksize, int flags, @@ -68,15 +112,7 @@ intern_strings(varnames); intern_strings(freevars); intern_strings(cellvars); - /* Intern selected string constants */ - for (i = PyTuple_Size(consts); --i >= 0; ) { - PyObject *v = PyTuple_GetItem(consts, i); - if (!PyString_Check(v)) - continue; - if (!all_name_chars((unsigned char *)PyString_AS_STRING(v))) - continue; - PyString_InternInPlace(&PyTuple_GET_ITEM(consts, i)); - } + intern_string_constants(consts); co = PyObject_NEW(PyCodeObject, &PyCode_Type); if (co != NULL) { co->co_argcount = argcount;