From: Serhiy Storchaka Date: Fri, 30 Sep 2016 07:38:08 +0000 (+0300) Subject: Issue #27942: String constants now interned recursively in tuples and frozensets. X-Git-Tag: v2.7.13rc1~99 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=67edf73183b8bf0127456454747f596428cc28f6;p=python Issue #27942: String constants now interned recursively in tuples and frozensets. --- diff --git a/Lib/test/test_code.py b/Lib/test/test_code.py index c588999aad..9268bafd98 100644 --- a/Lib/test/test_code.py +++ b/Lib/test/test_code.py @@ -112,6 +112,37 @@ class CodeTest(unittest.TestCase): 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 @@ class CodeWeakRefTest(unittest.TestCase): 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 --git a/Misc/NEWS b/Misc/NEWS index 2b1738f323..7b4631a7c3 100644 --- a/Misc/NEWS +++ b/Misc/NEWS @@ -10,6 +10,8 @@ What's New in Python 2.7.13? 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 --git a/Objects/codeobject.c b/Objects/codeobject.c index 0643c3622c..827fafaf22 100644 --- a/Objects/codeobject.c +++ b/Objects/codeobject.c @@ -39,6 +39,50 @@ intern_strings(PyObject *tuple) } } +/* 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 @@ PyCode_New(int argcount, int nlocals, int stacksize, int flags, 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;