summaryrefslogtreecommitdiffstats
path: root/Python/specialize.c
diff options
context:
space:
mode:
authorMark Shannon <mark@hotpy.org>2021-06-14 10:04:09 (GMT)
committerGitHub <noreply@github.com>2021-06-14 10:04:09 (GMT)
commiteecbc7c3900a7f40d8498b151db543a202c72f74 (patch)
tree6be5d67366f8df3e24c3dbed0786ec3c4a29bf1b /Python/specialize.c
parentfafcfff9262ae9dee03a00006638dfcbcfc23a7b (diff)
downloadcpython-eecbc7c3900a7f40d8498b151db543a202c72f74.zip
cpython-eecbc7c3900a7f40d8498b151db543a202c72f74.tar.gz
cpython-eecbc7c3900a7f40d8498b151db543a202c72f74.tar.bz2
bpo-44338: Port LOAD_GLOBAL to PEP 659 adaptive interpreter (GH-26638)
* Add specializations of LOAD_GLOBAL. * Add more stats. * Remove old opcache; it is no longer used. * Add NEWS
Diffstat (limited to 'Python/specialize.c')
-rw-r--r--Python/specialize.c100
1 files changed, 89 insertions, 11 deletions
diff --git a/Python/specialize.c b/Python/specialize.c
index d82122d..d98433b 100644
--- a/Python/specialize.c
+++ b/Python/specialize.c
@@ -33,18 +33,27 @@
Py_ssize_t _Py_QuickenedCount = 0;
#if SPECIALIZATION_STATS
-SpecializationStats _specialization_stats = { 0 };
+SpecializationStats _specialization_stats[256] = { 0 };
+
+#define PRINT_STAT(name, field) fprintf(stderr, " %s." #field " : %" PRIu64 "\n", name, stats->field);
+
+static void
+print_stats(SpecializationStats *stats, const char *name)
+{
+ PRINT_STAT(name, specialization_success);
+ PRINT_STAT(name, specialization_failure);
+ PRINT_STAT(name, hit);
+ PRINT_STAT(name, deferred);
+ PRINT_STAT(name, miss);
+ PRINT_STAT(name, deopt);
+}
-#define PRINT_STAT(name) fprintf(stderr, #name " : %" PRIu64" \n", _specialization_stats.name);
void
_Py_PrintSpecializationStats(void)
{
- PRINT_STAT(specialization_success);
- PRINT_STAT(specialization_failure);
- PRINT_STAT(loadattr_hit);
- PRINT_STAT(loadattr_deferred);
- PRINT_STAT(loadattr_miss);
- PRINT_STAT(loadattr_deopt);
+ printf("Specialization stats:\n");
+ print_stats(&_specialization_stats[LOAD_ATTR], "load_attr");
+ print_stats(&_specialization_stats[LOAD_GLOBAL], "load_global");
}
#endif
@@ -77,11 +86,13 @@ get_cache_count(SpecializedCacheOrInstruction *quickened) {
Values of zero are ignored. */
static uint8_t adaptive_opcodes[256] = {
[LOAD_ATTR] = LOAD_ATTR_ADAPTIVE,
+ [LOAD_GLOBAL] = LOAD_GLOBAL_ADAPTIVE,
};
/* The number of cache entries required for a "family" of instructions. */
static uint8_t cache_requirements[256] = {
- [LOAD_ATTR] = 2,
+ [LOAD_ATTR] = 2, /* _PyAdaptiveEntry and _PyLoadAttrCache */
+ [LOAD_GLOBAL] = 2, /* _PyAdaptiveEntry and _PyLoadGlobalCache */
};
/* Return the oparg for the cache_offset and instruction index.
@@ -357,14 +368,81 @@ _Py_Specialize_LoadAttr(PyObject *owner, _Py_CODEUNIT *instr, PyObject *name, Sp
}
fail:
- STAT_INC(specialization_failure);
+ STAT_INC(LOAD_ATTR, specialization_failure);
assert(!PyErr_Occurred());
cache_backoff(cache0);
return 0;
success:
- STAT_INC(specialization_success);
+ STAT_INC(LOAD_ATTR, specialization_success);
assert(!PyErr_Occurred());
cache0->counter = saturating_start();
return 0;
}
+
+int
+_Py_Specialize_LoadGlobal(
+ PyObject *globals, PyObject *builtins,
+ _Py_CODEUNIT *instr, PyObject *name,
+ SpecializedCacheEntry *cache)
+{
+ _PyAdaptiveEntry *cache0 = &cache->adaptive;
+ _PyLoadGlobalCache *cache1 = &cache[-1].load_global;
+ assert(PyUnicode_CheckExact(name));
+ if (!PyDict_CheckExact(globals)) {
+ goto fail;
+ }
+ if (((PyDictObject *)globals)->ma_keys->dk_kind != DICT_KEYS_UNICODE) {
+ goto fail;
+ }
+ PyObject *value = NULL;
+ Py_ssize_t index = _PyDict_GetItemHint((PyDictObject *)globals, name, -1, &value);
+ assert (index != DKIX_ERROR);
+ if (index != DKIX_EMPTY) {
+ if (index != (uint16_t)index) {
+ goto fail;
+ }
+ uint32_t keys_version = _PyDictKeys_GetVersionForCurrentState((PyDictObject *)globals);
+ if (keys_version == 0) {
+ goto fail;
+ }
+ cache1->module_keys_version = keys_version;
+ cache0->index = (uint16_t)index;
+ *instr = _Py_MAKECODEUNIT(LOAD_GLOBAL_MODULE, _Py_OPARG(*instr));
+ goto success;
+ }
+ if (!PyDict_CheckExact(builtins)) {
+ goto fail;
+ }
+ if (((PyDictObject *)builtins)->ma_keys->dk_kind != DICT_KEYS_UNICODE) {
+ goto fail;
+ }
+ index = _PyDict_GetItemHint((PyDictObject *)builtins, name, -1, &value);
+ assert (index != DKIX_ERROR);
+ if (index != (uint16_t)index) {
+ goto fail;
+ }
+ uint32_t globals_version = _PyDictKeys_GetVersionForCurrentState((PyDictObject *)globals);
+ if (globals_version == 0) {
+ goto fail;
+ }
+ uint32_t builtins_version = _PyDictKeys_GetVersionForCurrentState((PyDictObject *)builtins);
+ if (builtins_version == 0) {
+ goto fail;
+ }
+ cache1->module_keys_version = globals_version;
+ cache1->builtin_keys_version = builtins_version;
+ cache0->index = (uint16_t)index;
+ *instr = _Py_MAKECODEUNIT(LOAD_GLOBAL_BUILTIN, _Py_OPARG(*instr));
+ goto success;
+fail:
+ STAT_INC(LOAD_GLOBAL, specialization_failure);
+ assert(!PyErr_Occurred());
+ cache_backoff(cache0);
+ return 0;
+success:
+ STAT_INC(LOAD_GLOBAL, specialization_success);
+ assert(!PyErr_Occurred());
+ cache0->counter = saturating_start();
+ return 0;
+}