aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/Python/bytecodes.c
diff options
context:
space:
mode:
authormpage <mpage@meta.com>2024-10-09 08:18:25 -0700
committerGitHub <noreply@github.com>2024-10-09 15:18:25 +0000
commitf978fb4f8d6eac0585057e463bb1701dc04a9900 (patch)
tree72dc60eb608119b7c6f9315788132b7bb1b8ff92 /Python/bytecodes.c
parentb9a8ca0a6aa9251cb798f34f0c9d2cc95107eec6 (diff)
downloadcpython-f978fb4f8d6eac0585057e463bb1701dc04a9900.tar.gz
cpython-f978fb4f8d6eac0585057e463bb1701dc04a9900.zip
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 228d82173e6..87cca3fc1d3 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);