diff -r 965109e81ffa Include/dictobject.h --- a/Include/dictobject.h Wed Nov 04 22:38:40 2015 +0200 +++ b/Include/dictobject.h Thu Nov 05 11:07:31 2015 +0100 @@ -143,6 +143,8 @@ PyAPI_FUNC(void) _PyDict_DebugMallocStat int _PyObjectDict_SetItem(PyTypeObject *tp, PyObject **dictptr, PyObject *name, PyObject *value); PyObject *_PyDict_LoadGlobal(PyDictObject *, PyDictObject *, PyObject *); +PyObject *_PyDict_LoadName(PyDictObject *, PyDictObject *, PyDictObject *, + PyObject *); #endif #ifdef __cplusplus diff -r 965109e81ffa Objects/dictobject.c --- a/Objects/dictobject.c Wed Nov 04 22:38:40 2015 +0200 +++ b/Objects/dictobject.c Thu Nov 05 11:07:31 2015 +0100 @@ -1165,39 +1165,88 @@ PyObject * return PyDict_GetItemWithError(dp, kv); } -/* Fast version of global value lookup. +/* Fast version of global value lookup (LOAD_GLOBAL). * Lookup in globals, then builtins. + * + * Raise an exception and return NULL if an error occurred (ex: computing the + * key hash failed, key comparison failed, ...). Return NULL if the key doesn't + * exist. Return the value if the key exists. */ PyObject * _PyDict_LoadGlobal(PyDictObject *globals, PyDictObject *builtins, PyObject *key) { + Py_hash_t hash; + PyObject **value_addr; + PyDictKeyEntry *e; PyObject *x; - if (PyUnicode_CheckExact(key)) { - PyObject **value_addr; - Py_hash_t hash = ((PyASCIIObject *)key)->hash; - if (hash != -1) { - PyDictKeyEntry *e; - e = globals->ma_keys->dk_lookup(globals, key, hash, &value_addr); - if (e == NULL) { - return NULL; - } - x = *value_addr; - if (x != NULL) - return x; - e = builtins->ma_keys->dk_lookup(builtins, key, hash, &value_addr); - if (e == NULL) { - return NULL; - } - x = *value_addr; - return x; + + if (!PyUnicode_CheckExact(key) || + (hash = ((PyASCIIObject *) key)->hash) == -1) + { + hash = PyObject_Hash(key); + if (hash == -1) { + return NULL; } } - x = PyDict_GetItemWithError((PyObject *)globals, key); + + e = globals->ma_keys->dk_lookup(globals, key, hash, &value_addr); + if (e == NULL) + return NULL; + x = *value_addr; if (x != NULL) return x; - if (PyErr_Occurred()) + + e = builtins->ma_keys->dk_lookup(builtins, key, hash, &value_addr); + if (e == NULL) return NULL; - return PyDict_GetItemWithError((PyObject *)builtins, key); + x = *value_addr; + return x; +} + +/* Fast version of name lookup (LOAD_NAME). + * Lookup in locals, globals, then builtins. + * + * Raise an exception and return NULL if an error occurred (ex: computing the + * key hash failed, key comparison failed, ...). Return NULL if the key doesn't + * exist. Return the value if the key exists. + */ +PyObject * +_PyDict_LoadName(PyDictObject *locals, PyDictObject *globals, + PyDictObject *builtins, PyObject *key) +{ + Py_hash_t hash; + PyObject **value_addr; + PyDictKeyEntry *e; + PyObject *x; + + if (!PyUnicode_CheckExact(key) || + (hash = ((PyASCIIObject *) key)->hash) == -1) + { + hash = PyObject_Hash(key); + if (hash == -1) { + return NULL; + } + } + + e = locals->ma_keys->dk_lookup(locals, key, hash, &value_addr); + if (e == NULL) + return NULL; + x = *value_addr; + if (x != NULL) + return x; + + e = globals->ma_keys->dk_lookup(globals, key, hash, &value_addr); + if (e == NULL) + return NULL; + x = *value_addr; + if (x != NULL) + return x; + + e = builtins->ma_keys->dk_lookup(builtins, key, hash, &value_addr); + if (e == NULL) + return NULL; + x = *value_addr; + return x; } /* CAUTION: PyDict_SetItem() must guarantee that it won't resize the diff -r 965109e81ffa Python/ceval.c --- a/Python/ceval.c Wed Nov 04 22:38:40 2015 +0200 +++ b/Python/ceval.c Thu Nov 05 11:07:31 2015 +0100 @@ -2301,33 +2301,44 @@ PyEval_EvalFrameEx(PyFrameObject *f, int "no locals when loading %R", name); goto error; } - if (PyDict_CheckExact(locals)) { - v = PyDict_GetItem(locals, name); - Py_XINCREF(v); + + if (PyDict_CheckExact(locals) + && PyDict_CheckExact(f->f_globals) + && PyDict_CheckExact(f->f_builtins)) + { + v = _PyDict_LoadName((PyDictObject *)locals, + (PyDictObject *)f->f_globals, + (PyDictObject *)f->f_builtins, + name); + if (v == NULL) { + if (!_PyErr_OCCURRED()) { + /* _PyDict_LoadName() returns NULL without raising + * an exception if the key doesn't exist */ + format_exc_check_arg(PyExc_NameError, + NAME_ERROR_MSG, name); + } + goto error; + } + Py_INCREF(v); } else { + /* namespace 1: locals */ v = PyObject_GetItem(locals, name); - if (v == NULL && _PyErr_OCCURRED()) { + if (v == NULL) { if (!PyErr_ExceptionMatches(PyExc_KeyError)) goto error; PyErr_Clear(); } - } - if (v == NULL) { - v = PyDict_GetItem(f->f_globals, name); - Py_XINCREF(v); + if (v == NULL) { - if (PyDict_CheckExact(f->f_builtins)) { - v = PyDict_GetItem(f->f_builtins, name); - if (v == NULL) { - format_exc_check_arg( - PyExc_NameError, - NAME_ERROR_MSG, name); + /* namespace 2: globals */ + v = PyObject_GetItem(f->f_globals, name); + if (v == NULL) { + if (!PyErr_ExceptionMatches(PyExc_KeyError)) goto error; - } - Py_INCREF(v); - } - else { + PyErr_Clear(); + + /* namespace 3: builtins */ v = PyObject_GetItem(f->f_builtins, name); if (v == NULL) { if (PyErr_ExceptionMatches(PyExc_KeyError)) @@ -2347,22 +2358,33 @@ PyEval_EvalFrameEx(PyFrameObject *f, int PyObject *name = GETITEM(names, oparg); PyObject *v; if (PyDict_CheckExact(f->f_globals) - && PyDict_CheckExact(f->f_builtins)) { + && PyDict_CheckExact(f->f_builtins)) + { v = _PyDict_LoadGlobal((PyDictObject *)f->f_globals, (PyDictObject *)f->f_builtins, name); if (v == NULL) { - if (!_PyErr_OCCURRED()) + if (!_PyErr_OCCURRED()) { + /* _PyDict_LoadGlobal() returns NULL without raising + * an exception if the key doesn't exist */ format_exc_check_arg(PyExc_NameError, NAME_ERROR_MSG, name); + } goto error; } Py_INCREF(v); } else { /* Slow-path if globals or builtins is not a dict */ + + /* namespace 1: globals */ v = PyObject_GetItem(f->f_globals, name); if (v == NULL) { + if (!PyErr_ExceptionMatches(PyExc_KeyError)) + goto error; + PyErr_Clear(); + + /* namespace 2: builtins */ v = PyObject_GetItem(f->f_builtins, name); if (v == NULL) { if (PyErr_ExceptionMatches(PyExc_KeyError))