summaryrefslogtreecommitdiffstats
path: root/Python/bytecodes.c
diff options
context:
space:
mode:
authormpage <mpage@meta.com>2024-10-09 15:18:25 (GMT)
committerGitHub <noreply@github.com>2024-10-09 15:18:25 (GMT)
commitf978fb4f8d6eac0585057e463bb1701dc04a9900 (patch)
tree72dc60eb608119b7c6f9315788132b7bb1b8ff92 /Python/bytecodes.c
parentb9a8ca0a6aa9251cb798f34f0c9d2cc95107eec6 (diff)
downloadcpython-f978fb4f8d6eac0585057e463bb1701dc04a9900.zip
cpython-f978fb4f8d6eac0585057e463bb1701dc04a9900.tar.gz
cpython-f978fb4f8d6eac0585057e463bb1701dc04a9900.tar.bz2
gh-115999: Refactor `LOAD_GLOBAL` specializations to avoid reloading {globals, builtins} keys (gh-124953)
Each of the `LOAD_GLOBAL` specializations is implemented roughly as: 1. Load keys version. 2. Load cached keys version. 3. Deopt if (1) and (2) don't match. 4. Load keys. 5. Load cached index into keys. 6. Load object from (4) at offset from (5). This is not thread-safe in free-threaded builds; the keys object may be replaced in between steps (3) and (4). This change refactors the specializations to avoid reloading the keys object and instead pass the keys object from guards to be consumed by downstream uops.
Diffstat (limited to 'Python/bytecodes.c')
-rw-r--r--Python/bytecodes.c57
1 files changed, 45 insertions, 12 deletions
diff --git a/Python/bytecodes.c b/Python/bytecodes.c
index 228d821..87cca3f 100644
--- a/Python/bytecodes.c
+++ b/Python/bytecodes.c
@@ -1569,17 +1569,29 @@ dummy_func(
assert(DK_IS_UNICODE(dict->ma_keys));
}
- op(_GUARD_BUILTINS_VERSION, (version/1 --)) {
+ op(_GUARD_GLOBALS_VERSION_PUSH_KEYS, (version / 1 -- globals_keys: PyDictKeysObject *))
+ {
+ PyDictObject *dict = (PyDictObject *)GLOBALS();
+ DEOPT_IF(!PyDict_CheckExact(dict));
+ DEOPT_IF(dict->ma_keys->dk_version != version);
+ globals_keys = dict->ma_keys;
+ assert(DK_IS_UNICODE(globals_keys));
+ }
+
+ op(_GUARD_BUILTINS_VERSION_PUSH_KEYS, (version / 1 -- builtins_keys: PyDictKeysObject *))
+ {
PyDictObject *dict = (PyDictObject *)BUILTINS();
DEOPT_IF(!PyDict_CheckExact(dict));
DEOPT_IF(dict->ma_keys->dk_version != version);
- assert(DK_IS_UNICODE(dict->ma_keys));
+ builtins_keys = dict->ma_keys;
+ assert(DK_IS_UNICODE(builtins_keys));
}
- op(_LOAD_GLOBAL_MODULE, (index/1 -- res, null if (oparg & 1))) {
- PyDictObject *dict = (PyDictObject *)GLOBALS();
- PyDictUnicodeEntry *entries = DK_UNICODE_ENTRIES(dict->ma_keys);
+ op(_LOAD_GLOBAL_MODULE_FROM_KEYS, (index/1, globals_keys: PyDictKeysObject* -- res, null if (oparg & 1))) {
+ PyDictUnicodeEntry *entries = DK_UNICODE_ENTRIES(globals_keys);
PyObject *res_o = entries[index].me_value;
+ DEAD(globals_keys);
+ SYNC_SP();
DEOPT_IF(res_o == NULL);
Py_INCREF(res_o);
STAT_INC(LOAD_GLOBAL, hit);
@@ -1587,10 +1599,11 @@ dummy_func(
res = PyStackRef_FromPyObjectSteal(res_o);
}
- op(_LOAD_GLOBAL_BUILTINS, (index/1 -- res, null if (oparg & 1))) {
- PyDictObject *bdict = (PyDictObject *)BUILTINS();
- PyDictUnicodeEntry *entries = DK_UNICODE_ENTRIES(bdict->ma_keys);
+ op(_LOAD_GLOBAL_BUILTINS_FROM_KEYS, (index/1, builtins_keys: PyDictKeysObject* -- res, null if (oparg & 1))) {
+ PyDictUnicodeEntry *entries = DK_UNICODE_ENTRIES(builtins_keys);
PyObject *res_o = entries[index].me_value;
+ DEAD(builtins_keys);
+ SYNC_SP();
DEOPT_IF(res_o == NULL);
Py_INCREF(res_o);
STAT_INC(LOAD_GLOBAL, hit);
@@ -1600,15 +1613,15 @@ dummy_func(
macro(LOAD_GLOBAL_MODULE) =
unused/1 + // Skip over the counter
- _GUARD_GLOBALS_VERSION +
+ _GUARD_GLOBALS_VERSION_PUSH_KEYS +
unused/1 + // Skip over the builtins version
- _LOAD_GLOBAL_MODULE;
+ _LOAD_GLOBAL_MODULE_FROM_KEYS;
macro(LOAD_GLOBAL_BUILTIN) =
unused/1 + // Skip over the counter
_GUARD_GLOBALS_VERSION +
- _GUARD_BUILTINS_VERSION +
- _LOAD_GLOBAL_BUILTINS;
+ _GUARD_BUILTINS_VERSION_PUSH_KEYS +
+ _LOAD_GLOBAL_BUILTINS_FROM_KEYS;
inst(DELETE_FAST, (--)) {
_PyStackRef v = GETLOCAL(oparg);
@@ -4871,6 +4884,26 @@ dummy_func(
DEOPT_IF(func->func_version != func_version);
}
+ tier2 op(_LOAD_GLOBAL_MODULE, (index/1 -- res, null if (oparg & 1))) {
+ PyDictObject *dict = (PyDictObject *)GLOBALS();
+ PyDictUnicodeEntry *entries = DK_UNICODE_ENTRIES(dict->ma_keys);
+ PyObject *res_o = entries[index].me_value;
+ DEOPT_IF(res_o == NULL);
+ Py_INCREF(res_o);
+ res = PyStackRef_FromPyObjectSteal(res_o);
+ null = PyStackRef_NULL;
+ }
+
+ tier2 op(_LOAD_GLOBAL_BUILTINS, (index/1 -- res, null if (oparg & 1))) {
+ PyDictObject *dict = (PyDictObject *)BUILTINS();
+ PyDictUnicodeEntry *entries = DK_UNICODE_ENTRIES(dict->ma_keys);
+ PyObject *res_o = entries[index].me_value;
+ DEOPT_IF(res_o == NULL);
+ Py_INCREF(res_o);
+ res = PyStackRef_FromPyObjectSteal(res_o);
+ null = PyStackRef_NULL;
+ }
+
/* Internal -- for testing executors */
op(_INTERNAL_INCREMENT_OPT_COUNTER, (opt --)) {
_PyCounterOptimizerObject *exe = (_PyCounterOptimizerObject *)PyStackRef_AsPyObjectBorrow(opt);