summaryrefslogtreecommitdiffstats
path: root/Objects
diff options
context:
space:
mode:
authorPablo Galindo <Pablogsal@gmail.com>2020-10-20 05:22:44 (GMT)
committerGitHub <noreply@github.com>2020-10-20 05:22:44 (GMT)
commit109826c8508dd02e06ae0f1784f1d202495a8680 (patch)
tree75b1dd3041d325b379cf50d2ebc5f6ce968fc151 /Objects
parent871934d4cf00687b3d1411c6e344af311646c1ae (diff)
downloadcpython-109826c8508dd02e06ae0f1784f1d202495a8680.zip
cpython-109826c8508dd02e06ae0f1784f1d202495a8680.tar.gz
cpython-109826c8508dd02e06ae0f1784f1d202495a8680.tar.bz2
bpo-42093: Add opcode cache for LOAD_ATTR (GH-22803)
Diffstat (limited to 'Objects')
-rw-r--r--Objects/codeobject.c4
-rw-r--r--Objects/dictobject.c65
2 files changed, 67 insertions, 2 deletions
diff --git a/Objects/codeobject.c b/Objects/codeobject.c
index 4ca22fc..c86d0e1 100644
--- a/Objects/codeobject.c
+++ b/Objects/codeobject.c
@@ -301,8 +301,8 @@ _PyCode_InitOpcache(PyCodeObject *co)
unsigned char opcode = _Py_OPCODE(opcodes[i]);
i++; // 'i' is now aligned to (next_instr - first_instr)
- // TODO: LOAD_METHOD, LOAD_ATTR
- if (opcode == LOAD_GLOBAL) {
+ // TODO: LOAD_METHOD
+ if (opcode == LOAD_GLOBAL || opcode == LOAD_ATTR) {
opts++;
co->co_opcache_map[i] = (unsigned char)opts;
if (opts > 254) {
diff --git a/Objects/dictobject.c b/Objects/dictobject.c
index 6c3fc62..8e74962 100644
--- a/Objects/dictobject.c
+++ b/Objects/dictobject.c
@@ -1437,6 +1437,71 @@ PyDict_GetItem(PyObject *op, PyObject *key)
return value;
}
+Py_ssize_t
+_PyDict_GetItemHint(PyDictObject *mp, PyObject *key,
+ Py_ssize_t hint, PyObject **value)
+{
+ Py_hash_t hash;
+ PyThreadState *tstate;
+
+ assert(*value == NULL);
+ assert(PyDict_CheckExact((PyObject*)mp));
+ assert(PyUnicode_CheckExact(key));
+
+ if (hint >= 0 && hint < _PyDict_KeysSize(mp->ma_keys)) {
+ PyObject *res = NULL;
+
+ PyDictKeyEntry *ep = DK_ENTRIES(mp->ma_keys) + (size_t)hint;
+ if (ep->me_key == key) {
+ if (mp->ma_keys->dk_lookup == lookdict_split) {
+ assert(mp->ma_values != NULL);
+ res = mp->ma_values[(size_t)hint];
+ }
+ else {
+ res = ep->me_value;
+ }
+ if (res != NULL) {
+ *value = res;
+ return hint;
+ }
+ }
+ }
+
+ if ((hash = ((PyASCIIObject *) key)->hash) == -1)
+ {
+ hash = PyObject_Hash(key);
+ if (hash == -1) {
+ PyErr_Clear();
+ return -1;
+ }
+ }
+
+ // We can arrive here with a NULL tstate during initialization: try
+ // running "python -Wi" for an example related to string interning
+ tstate = _PyThreadState_UncheckedGet();
+ Py_ssize_t ix = 0;
+ if (tstate != NULL && tstate->curexc_type != NULL) {
+ /* preserve the existing exception */
+ PyObject *err_type, *err_value, *err_tb;
+ PyErr_Fetch(&err_type, &err_value, &err_tb);
+ ix = (mp->ma_keys->dk_lookup)(mp, key, hash, value);
+ /* ignore errors */
+ PyErr_Restore(err_type, err_value, err_tb);
+ if (ix < 0) {
+ return -1;
+ }
+ }
+ else {
+ ix = (mp->ma_keys->dk_lookup)(mp, key, hash, value);
+ if (ix < 0) {
+ PyErr_Clear();
+ return -1;
+ }
+ }
+
+ return ix;
+}
+
/* Same as PyDict_GetItemWithError() but with hash supplied by caller.
This returns NULL *with* an exception set if an exception occurred.
It returns NULL *without* an exception set if the key wasn't present.