From c87e8bd0f377c049f9f8448b2f047cf4798dc6df Mon Sep 17 00:00:00 2001 From: Brandt Bucher Date: Wed, 22 Mar 2023 18:29:12 -0700 Subject: [PATCH 1/5] Stick a small, resizable cache on all types --- Doc/includes/typestruct.h | 4 + Include/cpython/object.h | 4 + Include/internal/pycore_code.h | 2 +- Include/internal/pycore_opcode.h | 2 +- Lib/importlib/_bootstrap_external.py | 3 +- Lib/opcode.py | 2 +- Lib/test/test_dis.py | 8 +- Lib/test/test_sys.py | 2 +- Objects/typeobject.c | 8 + Programs/test_frozenmain.h | 63 ++--- Python/bytecodes.c | 29 +- Python/generated_cases.c.h | 405 ++++++++++++++------------- Python/opcode_metadata.h | 24 +- Python/specialize.c | 53 +++- 14 files changed, 340 insertions(+), 269 deletions(-) diff --git a/Doc/includes/typestruct.h b/Doc/includes/typestruct.h index f0ad1e47cb0d86..41a5dd582382f9 100644 --- a/Doc/includes/typestruct.h +++ b/Doc/includes/typestruct.h @@ -81,6 +81,10 @@ typedef struct _typeobject { destructor tp_finalize; vectorcallfunc tp_vectorcall; + unsigned int _tp_cache_size; + unsigned int _tp_cache_used; + PyObject **_tp_cache; + /* bitset of which type-watchers care about this type */ char tp_watched; } PyTypeObject; diff --git a/Include/cpython/object.h b/Include/cpython/object.h index 859ffb91e223dc..98633fb17a7a80 100644 --- a/Include/cpython/object.h +++ b/Include/cpython/object.h @@ -226,6 +226,10 @@ struct _typeobject { destructor tp_finalize; vectorcallfunc tp_vectorcall; + unsigned int _tp_cache_size; + unsigned int _tp_cache_used; + PyObject **_tp_cache; + /* bitset of which type-watchers care about this type */ char tp_watched; }; diff --git a/Include/internal/pycore_code.h b/Include/internal/pycore_code.h index 6bd212dd42c6f2..d407f983beba3d 100644 --- a/Include/internal/pycore_code.h +++ b/Include/internal/pycore_code.h @@ -63,7 +63,7 @@ typedef struct { uint16_t counter; uint16_t type_version[2]; uint16_t keys_version[2]; - uint16_t descr[4]; + uint16_t index; } _PyLoadMethodCache; diff --git a/Include/internal/pycore_opcode.h b/Include/internal/pycore_opcode.h index edcf4476ff3e74..3e34836c74036e 100644 --- a/Include/internal/pycore_opcode.h +++ b/Include/internal/pycore_opcode.h @@ -46,7 +46,7 @@ const uint8_t _PyOpcode_Caches[256] = { [UNPACK_SEQUENCE] = 1, [FOR_ITER] = 1, [STORE_ATTR] = 4, - [LOAD_ATTR] = 9, + [LOAD_ATTR] = 6, [COMPARE_OP] = 1, [LOAD_GLOBAL] = 4, [BINARY_OP] = 1, diff --git a/Lib/importlib/_bootstrap_external.py b/Lib/importlib/_bootstrap_external.py index 3f78300c226345..4531d71140671c 100644 --- a/Lib/importlib/_bootstrap_external.py +++ b/Lib/importlib/_bootstrap_external.py @@ -436,6 +436,7 @@ def _write_atomic(path, data, mode=0o666): # Python 3.12a6 3520 (Remove PREP_RERAISE_STAR, add CALL_INTRINSIC_2) # Python 3.12a7 3521 (Shrink the LOAD_GLOBAL caches) # Python 3.12a7 3522 (Removed JUMP_IF_FALSE_OR_POP/JUMP_IF_TRUE_OR_POP) +# Python 3.12a7 3523 (Shrink the LOAD_ATTR caches)) # Python 3.13 will start with 3550 @@ -452,7 +453,7 @@ def _write_atomic(path, data, mode=0o666): # Whenever MAGIC_NUMBER is changed, the ranges in the magic_values array # in PC/launcher.c must also be updated. -MAGIC_NUMBER = (3522).to_bytes(2, 'little') + b'\r\n' +MAGIC_NUMBER = (3523).to_bytes(2, 'little') + b'\r\n' _RAW_MAGIC_NUMBER = int.from_bytes(MAGIC_NUMBER, 'little') # For import.c diff --git a/Lib/opcode.py b/Lib/opcode.py index f37d00e5014aec..e1481e5c3b1f33 100644 --- a/Lib/opcode.py +++ b/Lib/opcode.py @@ -407,7 +407,7 @@ def pseudo_op(name, op, real_ops): "counter": 1, "version": 2, "keys_version": 2, - "descr": 4, + "index": 1, }, "STORE_ATTR": { "counter": 1, diff --git a/Lib/test/test_dis.py b/Lib/test/test_dis.py index fa1de1c7ded1b3..c1e55a3f6fffdd 100644 --- a/Lib/test/test_dis.py +++ b/Lib/test/test_dis.py @@ -354,7 +354,7 @@ def bug42562(): %3d LOAD_GLOBAL 0 (Exception) CHECK_EXC_MATCH - POP_JUMP_IF_FALSE 23 (to 80) + POP_JUMP_IF_FALSE 20 (to 74) STORE_FAST 0 (e) %3d LOAD_FAST 0 (e) @@ -1128,7 +1128,7 @@ def test_load_attr_specialize(self): 1 2 LOAD_CONST 0 ('a') 4 LOAD_ATTR_SLOT 0 (__class__) - 24 RETURN_VALUE + 18 RETURN_VALUE """ co = compile("'a'.__class__", "", "eval") self.code_quicken(lambda: exec(co, {}, {})) @@ -1193,8 +1193,8 @@ def test_show_caches(self): caches = list(self.get_cached_values(quickened, adaptive)) for cache in caches: self.assertRegex(cache, pattern) - total_caches = 22 - empty_caches = 7 + total_caches = 19 + empty_caches = 4 self.assertEqual(caches.count(""), empty_caches) self.assertEqual(len(caches), total_caches) diff --git a/Lib/test/test_sys.py b/Lib/test/test_sys.py index fb578c5ae6e5d5..50b92214414dea 100644 --- a/Lib/test/test_sys.py +++ b/Lib/test/test_sys.py @@ -1545,7 +1545,7 @@ def delx(self): del self.__x check((1,2,3), vsize('') + 3*self.P) # type # static type: PyTypeObject - fmt = 'P2nPI13Pl4Pn9Pn12PIPc' + fmt = 'P2nPI13Pl4Pn9Pn12PIPIIPc' s = vsize('2P' + fmt) check(int, s) # class diff --git a/Objects/typeobject.c b/Objects/typeobject.c index 69e84743f13aac..eef0d006338a8f 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -510,6 +510,7 @@ PyType_Modified(PyTypeObject *type) type->tp_flags &= ~Py_TPFLAGS_VALID_VERSION_TAG; type->tp_version_tag = 0; /* 0 is not a valid version tag */ + type->_tp_cache_used = 0; } static void @@ -563,6 +564,7 @@ type_mro_modified(PyTypeObject *type, PyObject *bases) { clear: type->tp_flags &= ~Py_TPFLAGS_VALID_VERSION_TAG; type->tp_version_tag = 0; /* 0 is not a valid version tag */ + type->_tp_cache_used = 0; } static int @@ -586,6 +588,7 @@ assign_version_tag(PyTypeObject *type) } type->tp_version_tag = next_version_tag++; assert (type->tp_version_tag != 0); + assert(type->_tp_cache_used == 0); PyObject *bases = type->tp_bases; Py_ssize_t n = PyTuple_GET_SIZE(bases); @@ -4493,6 +4496,10 @@ _PyStaticType_Dealloc(PyTypeObject *type) static_builtin_state_clear(type); /* We leave _Py_TPFLAGS_STATIC_BUILTIN set on tp_flags. */ } + type->_tp_cache_size = 0; + type->_tp_cache_used = 0; + PyMem_Free(type->_tp_cache); + type->_tp_cache = NULL; } @@ -4516,6 +4523,7 @@ type_dealloc(PyTypeObject *type) Py_XDECREF(type->tp_mro); Py_XDECREF(type->tp_cache); clear_subclasses(type); + PyMem_Free(type->_tp_cache); /* A type's tp_doc is heap allocated, unlike the tp_doc slots * of most other objects. It's okay to cast it to char *. diff --git a/Programs/test_frozenmain.h b/Programs/test_frozenmain.h index 8e5055bd7bceb1..205f4e605df1f6 100644 --- a/Programs/test_frozenmain.h +++ b/Programs/test_frozenmain.h @@ -1,39 +1,38 @@ // Auto-generated by Programs/freeze_test_frozenmain.py unsigned char M_test_frozenmain[] = { 227,0,0,0,0,0,0,0,0,0,0,0,0,8,0,0, - 0,0,0,0,0,243,182,0,0,0,151,0,100,0,100,1, + 0,0,0,0,0,243,170,0,0,0,151,0,100,0,100,1, 108,0,90,0,100,0,100,1,108,1,90,1,2,0,101,2, 100,2,171,1,0,0,0,0,0,0,0,0,1,0,2,0, 101,2,100,3,101,0,106,6,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,171,2,0,0,0,0, - 0,0,0,0,1,0,2,0,101,1,106,8,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,171,0, - 0,0,0,0,0,0,0,0,100,4,25,0,0,0,0,0, - 0,0,0,0,90,5,100,5,68,0,93,23,0,0,90,6, - 2,0,101,2,100,6,101,6,155,0,100,7,101,5,101,6, - 25,0,0,0,0,0,0,0,0,0,155,0,157,4,171,1, - 0,0,0,0,0,0,0,0,1,0,140,25,4,0,121,1, - 41,8,233,0,0,0,0,78,122,18,70,114,111,122,101,110, - 32,72,101,108,108,111,32,87,111,114,108,100,122,8,115,121, - 115,46,97,114,103,118,218,6,99,111,110,102,105,103,41,5, - 218,12,112,114,111,103,114,97,109,95,110,97,109,101,218,10, - 101,120,101,99,117,116,97,98,108,101,218,15,117,115,101,95, - 101,110,118,105,114,111,110,109,101,110,116,218,17,99,111,110, - 102,105,103,117,114,101,95,99,95,115,116,100,105,111,218,14, - 98,117,102,102,101,114,101,100,95,115,116,100,105,111,122,7, - 99,111,110,102,105,103,32,122,2,58,32,41,7,218,3,115, - 121,115,218,17,95,116,101,115,116,105,110,116,101,114,110,97, - 108,99,97,112,105,218,5,112,114,105,110,116,218,4,97,114, - 103,118,218,11,103,101,116,95,99,111,110,102,105,103,115,114, - 3,0,0,0,218,3,107,101,121,169,0,243,0,0,0,0, - 250,18,116,101,115,116,95,102,114,111,122,101,110,109,97,105, - 110,46,112,121,250,8,60,109,111,100,117,108,101,62,114,18, - 0,0,0,1,0,0,0,115,100,0,0,0,240,3,1,1, - 1,243,8,0,1,11,219,0,24,225,0,5,208,6,26,213, - 0,27,217,0,5,128,106,144,35,151,40,145,40,213,0,27, - 216,9,38,208,9,26,215,9,38,209,9,38,212,9,40,168, - 24,212,9,50,128,6,240,2,6,12,2,242,0,7,1,42, - 128,67,241,14,0,5,10,208,10,40,144,67,209,10,40,152, - 54,160,35,156,59,209,10,40,214,4,41,241,15,7,1,42, - 114,16,0,0,0, + 0,0,0,0,171,2,0,0,0,0,0,0,0,0,1,0, + 2,0,101,1,106,8,0,0,0,0,0,0,0,0,0,0, + 0,0,171,0,0,0,0,0,0,0,0,0,100,4,25,0, + 0,0,0,0,0,0,0,0,90,5,100,5,68,0,93,23, + 0,0,90,6,2,0,101,2,100,6,101,6,155,0,100,7, + 101,5,101,6,25,0,0,0,0,0,0,0,0,0,155,0, + 157,4,171,1,0,0,0,0,0,0,0,0,1,0,140,25, + 4,0,121,1,41,8,233,0,0,0,0,78,122,18,70,114, + 111,122,101,110,32,72,101,108,108,111,32,87,111,114,108,100, + 122,8,115,121,115,46,97,114,103,118,218,6,99,111,110,102, + 105,103,41,5,218,12,112,114,111,103,114,97,109,95,110,97, + 109,101,218,10,101,120,101,99,117,116,97,98,108,101,218,15, + 117,115,101,95,101,110,118,105,114,111,110,109,101,110,116,218, + 17,99,111,110,102,105,103,117,114,101,95,99,95,115,116,100, + 105,111,218,14,98,117,102,102,101,114,101,100,95,115,116,100, + 105,111,122,7,99,111,110,102,105,103,32,122,2,58,32,41, + 7,218,3,115,121,115,218,17,95,116,101,115,116,105,110,116, + 101,114,110,97,108,99,97,112,105,218,5,112,114,105,110,116, + 218,4,97,114,103,118,218,11,103,101,116,95,99,111,110,102, + 105,103,115,114,3,0,0,0,218,3,107,101,121,169,0,243, + 0,0,0,0,250,18,116,101,115,116,95,102,114,111,122,101, + 110,109,97,105,110,46,112,121,250,8,60,109,111,100,117,108, + 101,62,114,18,0,0,0,1,0,0,0,115,95,0,0,0, + 240,3,1,1,1,243,8,0,1,11,219,0,24,225,0,5, + 208,6,26,213,0,27,217,0,5,128,106,144,35,150,40,213, + 0,27,216,9,38,208,9,26,214,9,38,212,9,40,168,24, + 212,9,50,128,6,240,2,6,12,2,242,0,7,1,42,128, + 67,241,14,0,5,10,208,10,40,144,67,209,10,40,152,54, + 160,35,156,59,209,10,40,214,4,41,241,15,7,1,42,114, + 16,0,0,0, }; diff --git a/Python/bytecodes.c b/Python/bytecodes.c index b5ead16d3f1bb2..c25ddaa876a8fb 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -1413,7 +1413,7 @@ dummy_func( LOAD_ATTR_METHOD_LAZY_DICT, }; - inst(LOAD_ATTR, (unused/9, owner -- res2 if (oparg & 1), res)) { + inst(LOAD_ATTR, (unused/6, owner -- res2 if (oparg & 1), res)) { #if ENABLE_SPECIALIZATION _PyAttrCache *cache = (_PyAttrCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { @@ -1462,7 +1462,7 @@ dummy_func( } } - inst(LOAD_ATTR_INSTANCE_VALUE, (unused/1, type_version/2, index/1, unused/5, owner -- res2 if (oparg & 1), res)) { + inst(LOAD_ATTR_INSTANCE_VALUE, (unused/1, type_version/2, index/1, unused/2, owner -- res2 if (oparg & 1), res)) { assert(cframe.use_tracing == 0); PyTypeObject *tp = Py_TYPE(owner); assert(type_version != 0); @@ -1479,7 +1479,7 @@ dummy_func( DECREF_INPUTS(); } - inst(LOAD_ATTR_MODULE, (unused/1, type_version/2, index/1, unused/5, owner -- res2 if (oparg & 1), res)) { + inst(LOAD_ATTR_MODULE, (unused/1, type_version/2, index/1, unused/2, owner -- res2 if (oparg & 1), res)) { assert(cframe.use_tracing == 0); DEOPT_IF(!PyModule_CheckExact(owner), LOAD_ATTR); PyDictObject *dict = (PyDictObject *)((PyModuleObject *)owner)->md_dict; @@ -1496,7 +1496,7 @@ dummy_func( DECREF_INPUTS(); } - inst(LOAD_ATTR_WITH_HINT, (unused/1, type_version/2, index/1, unused/5, owner -- res2 if (oparg & 1), res)) { + inst(LOAD_ATTR_WITH_HINT, (unused/1, type_version/2, index/1, unused/2, owner -- res2 if (oparg & 1), res)) { assert(cframe.use_tracing == 0); PyTypeObject *tp = Py_TYPE(owner); assert(type_version != 0); @@ -1527,7 +1527,7 @@ dummy_func( DECREF_INPUTS(); } - inst(LOAD_ATTR_SLOT, (unused/1, type_version/2, index/1, unused/5, owner -- res2 if (oparg & 1), res)) { + inst(LOAD_ATTR_SLOT, (unused/1, type_version/2, index/1, unused/2, owner -- res2 if (oparg & 1), res)) { assert(cframe.use_tracing == 0); PyTypeObject *tp = Py_TYPE(owner); assert(type_version != 0); @@ -1541,7 +1541,7 @@ dummy_func( DECREF_INPUTS(); } - inst(LOAD_ATTR_CLASS, (unused/1, type_version/2, unused/2, descr/4, cls -- res2 if (oparg & 1), res)) { + inst(LOAD_ATTR_CLASS, (unused/1, type_version/2, unused/2, index/1, cls -- res2 if (oparg & 1), res)) { assert(cframe.use_tracing == 0); DEOPT_IF(!PyType_Check(cls), LOAD_ATTR); @@ -1551,19 +1551,20 @@ dummy_func( STAT_INC(LOAD_ATTR, hit); res2 = NULL; - res = descr; + res = ((PyTypeObject *)cls)->_tp_cache[index]; assert(res != NULL); Py_INCREF(res); DECREF_INPUTS(); } - inst(LOAD_ATTR_PROPERTY, (unused/1, type_version/2, func_version/2, fget/4, owner -- unused if (oparg & 1), unused)) { + inst(LOAD_ATTR_PROPERTY, (unused/1, type_version/2, func_version/2, index/1, owner -- unused if (oparg & 1), unused)) { assert(cframe.use_tracing == 0); DEOPT_IF(tstate->interp->eval_frame, LOAD_ATTR); PyTypeObject *cls = Py_TYPE(owner); DEOPT_IF(cls->tp_version_tag != type_version, LOAD_ATTR); assert(type_version != 0); + PyObject *fget = cls->_tp_cache[index]; assert(Py_IS_TYPE(fget, &PyFunction_Type)); PyFunctionObject *f = (PyFunctionObject *)fget; assert(func_version != 0); @@ -1583,12 +1584,13 @@ dummy_func( DISPATCH_INLINED(new_frame); } - inst(LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN, (unused/1, type_version/2, func_version/2, getattribute/4, owner -- unused if (oparg & 1), unused)) { + inst(LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN, (unused/1, type_version/2, func_version/2, index/1, owner -- unused if (oparg & 1), unused)) { assert(cframe.use_tracing == 0); DEOPT_IF(tstate->interp->eval_frame, LOAD_ATTR); PyTypeObject *cls = Py_TYPE(owner); DEOPT_IF(cls->tp_version_tag != type_version, LOAD_ATTR); assert(type_version != 0); + PyObject *getattribute = cls->_tp_cache[index]; assert(Py_IS_TYPE(getattribute, &PyFunction_Type)); PyFunctionObject *f = (PyFunctionObject *)getattribute; assert(func_version != 0); @@ -2239,7 +2241,7 @@ dummy_func( exc_info->exc_value = Py_NewRef(new_exc); } - inst(LOAD_ATTR_METHOD_WITH_VALUES, (unused/1, type_version/2, keys_version/2, descr/4, self -- res2 if (oparg & 1), res)) { + inst(LOAD_ATTR_METHOD_WITH_VALUES, (unused/1, type_version/2, keys_version/2, index/1, self -- res2 if (oparg & 1), res)) { /* Cached method object */ assert(cframe.use_tracing == 0); PyTypeObject *self_cls = Py_TYPE(self); @@ -2252,6 +2254,7 @@ dummy_func( DEOPT_IF(self_heap_type->ht_cached_keys->dk_version != keys_version, LOAD_ATTR); STAT_INC(LOAD_ATTR, hit); + PyObject *descr = self_cls->_tp_cache[index]; assert(descr != NULL); res2 = Py_NewRef(descr); assert(_PyType_HasFeature(Py_TYPE(res2), Py_TPFLAGS_METHOD_DESCRIPTOR)); @@ -2259,12 +2262,13 @@ dummy_func( assert(oparg & 1); } - inst(LOAD_ATTR_METHOD_NO_DICT, (unused/1, type_version/2, unused/2, descr/4, self -- res2 if (oparg & 1), res)) { + inst(LOAD_ATTR_METHOD_NO_DICT, (unused/1, type_version/2, unused/2, index/1, self -- res2 if (oparg & 1), res)) { assert(cframe.use_tracing == 0); PyTypeObject *self_cls = Py_TYPE(self); DEOPT_IF(self_cls->tp_version_tag != type_version, LOAD_ATTR); assert(self_cls->tp_dictoffset == 0); STAT_INC(LOAD_ATTR, hit); + PyObject *descr = self_cls->_tp_cache[index]; assert(descr != NULL); assert(_PyType_HasFeature(Py_TYPE(descr), Py_TPFLAGS_METHOD_DESCRIPTOR)); res2 = Py_NewRef(descr); @@ -2272,7 +2276,7 @@ dummy_func( assert(oparg & 1); } - inst(LOAD_ATTR_METHOD_LAZY_DICT, (unused/1, type_version/2, unused/2, descr/4, self -- res2 if (oparg & 1), res)) { + inst(LOAD_ATTR_METHOD_LAZY_DICT, (unused/1, type_version/2, unused/2, index/1, self -- res2 if (oparg & 1), res)) { assert(cframe.use_tracing == 0); PyTypeObject *self_cls = Py_TYPE(self); DEOPT_IF(self_cls->tp_version_tag != type_version, LOAD_ATTR); @@ -2282,6 +2286,7 @@ dummy_func( /* This object has a __dict__, just not yet created */ DEOPT_IF(dict != NULL, LOAD_ATTR); STAT_INC(LOAD_ATTR, hit); + PyObject *descr = self_cls->_tp_cache[index]; assert(descr != NULL); assert(_PyType_HasFeature(Py_TYPE(descr), Py_TPFLAGS_METHOD_DESCRIPTOR)); res2 = Py_NewRef(descr); diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h index c59042dad66c1a..2267f90814749f 100644 --- a/Python/generated_cases.c.h +++ b/Python/generated_cases.c.h @@ -2032,7 +2032,7 @@ TARGET(LOAD_ATTR) { PREDICTED(LOAD_ATTR); - static_assert(INLINE_CACHE_ENTRIES_LOAD_ATTR == 9, "incorrect cache size"); + static_assert(INLINE_CACHE_ENTRIES_LOAD_ATTR == 6, "incorrect cache size"); PyObject *owner = stack_pointer[-1]; PyObject *res2 = NULL; PyObject *res; @@ -2091,7 +2091,7 @@ STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; if (oparg & 1) { stack_pointer[-(1 + ((oparg & 1) ? 1 : 0))] = res2; } - next_instr += 9; + next_instr += 6; DISPATCH(); } @@ -2120,7 +2120,7 @@ STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; if (oparg & 1) { stack_pointer[-(1 + ((oparg & 1) ? 1 : 0))] = res2; } - next_instr += 9; + next_instr += 6; DISPATCH(); } @@ -2149,7 +2149,7 @@ STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; if (oparg & 1) { stack_pointer[-(1 + ((oparg & 1) ? 1 : 0))] = res2; } - next_instr += 9; + next_instr += 6; DISPATCH(); } @@ -2192,7 +2192,7 @@ STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; if (oparg & 1) { stack_pointer[-(1 + ((oparg & 1) ? 1 : 0))] = res2; } - next_instr += 9; + next_instr += 6; DISPATCH(); } @@ -2218,7 +2218,7 @@ STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; if (oparg & 1) { stack_pointer[-(1 + ((oparg & 1) ? 1 : 0))] = res2; } - next_instr += 9; + next_instr += 6; DISPATCH(); } @@ -2227,7 +2227,7 @@ PyObject *res2 = NULL; PyObject *res; uint32_t type_version = read_u32(&next_instr[1].cache); - PyObject *descr = read_obj(&next_instr[5].cache); + uint16_t index = read_u16(&next_instr[5].cache); #line 1545 "Python/bytecodes.c" assert(cframe.use_tracing == 0); @@ -2238,7 +2238,7 @@ STAT_INC(LOAD_ATTR, hit); res2 = NULL; - res = descr; + res = ((PyTypeObject *)cls)->_tp_cache[index]; assert(res != NULL); Py_INCREF(res); #line 2245 "Python/generated_cases.c.h" @@ -2246,7 +2246,7 @@ STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; if (oparg & 1) { stack_pointer[-(1 + ((oparg & 1) ? 1 : 0))] = res2; } - next_instr += 9; + next_instr += 6; DISPATCH(); } @@ -2254,7 +2254,7 @@ PyObject *owner = stack_pointer[-1]; uint32_t type_version = read_u32(&next_instr[1].cache); uint32_t func_version = read_u32(&next_instr[3].cache); - PyObject *fget = read_obj(&next_instr[5].cache); + uint16_t index = read_u16(&next_instr[5].cache); #line 1561 "Python/bytecodes.c" assert(cframe.use_tracing == 0); DEOPT_IF(tstate->interp->eval_frame, LOAD_ATTR); @@ -2262,6 +2262,7 @@ PyTypeObject *cls = Py_TYPE(owner); DEOPT_IF(cls->tp_version_tag != type_version, LOAD_ATTR); assert(type_version != 0); + PyObject *fget = cls->_tp_cache[index]; assert(Py_IS_TYPE(fget, &PyFunction_Type)); PyFunctionObject *f = (PyFunctionObject *)fget; assert(func_version != 0); @@ -2279,20 +2280,21 @@ new_frame->localsplus[0] = owner; JUMPBY(INLINE_CACHE_ENTRIES_LOAD_ATTR); DISPATCH_INLINED(new_frame); - #line 2283 "Python/generated_cases.c.h" + #line 2284 "Python/generated_cases.c.h" } TARGET(LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN) { PyObject *owner = stack_pointer[-1]; uint32_t type_version = read_u32(&next_instr[1].cache); uint32_t func_version = read_u32(&next_instr[3].cache); - PyObject *getattribute = read_obj(&next_instr[5].cache); - #line 1587 "Python/bytecodes.c" + uint16_t index = read_u16(&next_instr[5].cache); + #line 1588 "Python/bytecodes.c" assert(cframe.use_tracing == 0); DEOPT_IF(tstate->interp->eval_frame, LOAD_ATTR); PyTypeObject *cls = Py_TYPE(owner); DEOPT_IF(cls->tp_version_tag != type_version, LOAD_ATTR); assert(type_version != 0); + PyObject *getattribute = cls->_tp_cache[index]; assert(Py_IS_TYPE(getattribute, &PyFunction_Type)); PyFunctionObject *f = (PyFunctionObject *)getattribute; assert(func_version != 0); @@ -2313,7 +2315,7 @@ new_frame->localsplus[1] = Py_NewRef(name); JUMPBY(INLINE_CACHE_ENTRIES_LOAD_ATTR); DISPATCH_INLINED(new_frame); - #line 2317 "Python/generated_cases.c.h" + #line 2319 "Python/generated_cases.c.h" } TARGET(STORE_ATTR_INSTANCE_VALUE) { @@ -2321,7 +2323,7 @@ PyObject *value = stack_pointer[-2]; uint32_t type_version = read_u32(&next_instr[1].cache); uint16_t index = read_u16(&next_instr[3].cache); - #line 1615 "Python/bytecodes.c" + #line 1617 "Python/bytecodes.c" assert(cframe.use_tracing == 0); PyTypeObject *tp = Py_TYPE(owner); assert(type_version != 0); @@ -2340,7 +2342,7 @@ Py_DECREF(old_value); } Py_DECREF(owner); - #line 2344 "Python/generated_cases.c.h" + #line 2346 "Python/generated_cases.c.h" STACK_SHRINK(2); next_instr += 4; DISPATCH(); @@ -2351,7 +2353,7 @@ PyObject *value = stack_pointer[-2]; uint32_t type_version = read_u32(&next_instr[1].cache); uint16_t hint = read_u16(&next_instr[3].cache); - #line 1636 "Python/bytecodes.c" + #line 1638 "Python/bytecodes.c" assert(cframe.use_tracing == 0); PyTypeObject *tp = Py_TYPE(owner); assert(type_version != 0); @@ -2391,7 +2393,7 @@ /* PEP 509 */ dict->ma_version_tag = new_version; Py_DECREF(owner); - #line 2395 "Python/generated_cases.c.h" + #line 2397 "Python/generated_cases.c.h" STACK_SHRINK(2); next_instr += 4; DISPATCH(); @@ -2402,7 +2404,7 @@ PyObject *value = stack_pointer[-2]; uint32_t type_version = read_u32(&next_instr[1].cache); uint16_t index = read_u16(&next_instr[3].cache); - #line 1678 "Python/bytecodes.c" + #line 1680 "Python/bytecodes.c" assert(cframe.use_tracing == 0); PyTypeObject *tp = Py_TYPE(owner); assert(type_version != 0); @@ -2413,7 +2415,7 @@ *(PyObject **)addr = value; Py_XDECREF(old_value); Py_DECREF(owner); - #line 2417 "Python/generated_cases.c.h" + #line 2419 "Python/generated_cases.c.h" STACK_SHRINK(2); next_instr += 4; DISPATCH(); @@ -2423,16 +2425,16 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *res; - #line 1691 "Python/bytecodes.c" + #line 1693 "Python/bytecodes.c" STAT_INC(COMPARE_OP, deferred); assert((oparg >> 4) <= Py_GE); res = PyObject_RichCompare(left, right, oparg>>4); - #line 2431 "Python/generated_cases.c.h" + #line 2433 "Python/generated_cases.c.h" Py_DECREF(left); Py_DECREF(right); - #line 1695 "Python/bytecodes.c" + #line 1697 "Python/bytecodes.c" if (res == NULL) goto pop_2_error; - #line 2436 "Python/generated_cases.c.h" + #line 2438 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; next_instr += 1; @@ -2443,7 +2445,7 @@ PREDICTED(COMPARE_AND_BRANCH); PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; - #line 1707 "Python/bytecodes.c" + #line 1709 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION _PyCompareOpCache *cache = (_PyCompareOpCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { @@ -2457,10 +2459,10 @@ #endif /* ENABLE_SPECIALIZATION */ assert((oparg >> 4) <= Py_GE); PyObject *cond = PyObject_RichCompare(left, right, oparg>>4); - #line 2461 "Python/generated_cases.c.h" + #line 2463 "Python/generated_cases.c.h" Py_DECREF(left); Py_DECREF(right); - #line 1721 "Python/bytecodes.c" + #line 1723 "Python/bytecodes.c" if (cond == NULL) goto pop_2_error; assert(next_instr[1].op.code == POP_JUMP_IF_FALSE || next_instr[1].op.code == POP_JUMP_IF_TRUE); @@ -2472,7 +2474,7 @@ if (jump_on_true == (err != 0)) { JUMPBY(offset); } - #line 2476 "Python/generated_cases.c.h" + #line 2478 "Python/generated_cases.c.h" STACK_SHRINK(2); next_instr += 2; DISPATCH(); @@ -2481,7 +2483,7 @@ TARGET(COMPARE_AND_BRANCH_FLOAT) { PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; - #line 1735 "Python/bytecodes.c" + #line 1737 "Python/bytecodes.c" assert(cframe.use_tracing == 0); DEOPT_IF(!PyFloat_CheckExact(left), COMPARE_AND_BRANCH); DEOPT_IF(!PyFloat_CheckExact(right), COMPARE_AND_BRANCH); @@ -2496,7 +2498,7 @@ int offset = next_instr[1].op.arg; JUMPBY(offset); } - #line 2500 "Python/generated_cases.c.h" + #line 2502 "Python/generated_cases.c.h" STACK_SHRINK(2); next_instr += 2; DISPATCH(); @@ -2505,7 +2507,7 @@ TARGET(COMPARE_AND_BRANCH_INT) { PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; - #line 1753 "Python/bytecodes.c" + #line 1755 "Python/bytecodes.c" assert(cframe.use_tracing == 0); DEOPT_IF(!PyLong_CheckExact(left), COMPARE_AND_BRANCH); DEOPT_IF(!PyLong_CheckExact(right), COMPARE_AND_BRANCH); @@ -2524,7 +2526,7 @@ int offset = next_instr[1].op.arg; JUMPBY(offset); } - #line 2528 "Python/generated_cases.c.h" + #line 2530 "Python/generated_cases.c.h" STACK_SHRINK(2); next_instr += 2; DISPATCH(); @@ -2533,7 +2535,7 @@ TARGET(COMPARE_AND_BRANCH_STR) { PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; - #line 1775 "Python/bytecodes.c" + #line 1777 "Python/bytecodes.c" assert(cframe.use_tracing == 0); DEOPT_IF(!PyUnicode_CheckExact(left), COMPARE_AND_BRANCH); DEOPT_IF(!PyUnicode_CheckExact(right), COMPARE_AND_BRANCH); @@ -2549,7 +2551,7 @@ int offset = next_instr[1].op.arg; JUMPBY(offset); } - #line 2553 "Python/generated_cases.c.h" + #line 2555 "Python/generated_cases.c.h" STACK_SHRINK(2); next_instr += 2; DISPATCH(); @@ -2559,14 +2561,14 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *b; - #line 1793 "Python/bytecodes.c" + #line 1795 "Python/bytecodes.c" int res = Py_Is(left, right) ^ oparg; - #line 2565 "Python/generated_cases.c.h" + #line 2567 "Python/generated_cases.c.h" Py_DECREF(left); Py_DECREF(right); - #line 1795 "Python/bytecodes.c" + #line 1797 "Python/bytecodes.c" b = Py_NewRef(res ? Py_True : Py_False); - #line 2570 "Python/generated_cases.c.h" + #line 2572 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = b; DISPATCH(); @@ -2576,15 +2578,15 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *b; - #line 1799 "Python/bytecodes.c" + #line 1801 "Python/bytecodes.c" int res = PySequence_Contains(right, left); - #line 2582 "Python/generated_cases.c.h" + #line 2584 "Python/generated_cases.c.h" Py_DECREF(left); Py_DECREF(right); - #line 1801 "Python/bytecodes.c" + #line 1803 "Python/bytecodes.c" if (res < 0) goto pop_2_error; b = Py_NewRef((res^oparg) ? Py_True : Py_False); - #line 2588 "Python/generated_cases.c.h" + #line 2590 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = b; DISPATCH(); @@ -2595,12 +2597,12 @@ PyObject *exc_value = stack_pointer[-2]; PyObject *rest; PyObject *match; - #line 1806 "Python/bytecodes.c" + #line 1808 "Python/bytecodes.c" if (check_except_star_type_valid(tstate, match_type) < 0) { - #line 2601 "Python/generated_cases.c.h" + #line 2603 "Python/generated_cases.c.h" Py_DECREF(exc_value); Py_DECREF(match_type); - #line 1808 "Python/bytecodes.c" + #line 1810 "Python/bytecodes.c" if (true) goto pop_2_error; } @@ -2608,10 +2610,10 @@ rest = NULL; int res = exception_group_match(exc_value, match_type, &match, &rest); - #line 2612 "Python/generated_cases.c.h" + #line 2614 "Python/generated_cases.c.h" Py_DECREF(exc_value); Py_DECREF(match_type); - #line 1816 "Python/bytecodes.c" + #line 1818 "Python/bytecodes.c" if (res < 0) goto pop_2_error; assert((match == NULL) == (rest == NULL)); @@ -2620,7 +2622,7 @@ if (!Py_IsNone(match)) { PyErr_SetExcInfo(NULL, Py_NewRef(match), NULL); } - #line 2624 "Python/generated_cases.c.h" + #line 2626 "Python/generated_cases.c.h" stack_pointer[-1] = match; stack_pointer[-2] = rest; DISPATCH(); @@ -2630,21 +2632,21 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *b; - #line 1827 "Python/bytecodes.c" + #line 1829 "Python/bytecodes.c" assert(PyExceptionInstance_Check(left)); if (check_except_type_valid(tstate, right) < 0) { - #line 2637 "Python/generated_cases.c.h" + #line 2639 "Python/generated_cases.c.h" Py_DECREF(right); - #line 1830 "Python/bytecodes.c" + #line 1832 "Python/bytecodes.c" if (true) goto pop_1_error; } int res = PyErr_GivenExceptionMatches(left, right); - #line 2644 "Python/generated_cases.c.h" + #line 2646 "Python/generated_cases.c.h" Py_DECREF(right); - #line 1835 "Python/bytecodes.c" + #line 1837 "Python/bytecodes.c" b = Py_NewRef(res ? Py_True : Py_False); - #line 2648 "Python/generated_cases.c.h" + #line 2650 "Python/generated_cases.c.h" stack_pointer[-1] = b; DISPATCH(); } @@ -2653,15 +2655,15 @@ PyObject *fromlist = stack_pointer[-1]; PyObject *level = stack_pointer[-2]; PyObject *res; - #line 1839 "Python/bytecodes.c" + #line 1841 "Python/bytecodes.c" PyObject *name = GETITEM(frame->f_code->co_names, oparg); res = import_name(tstate, frame, name, fromlist, level); - #line 2660 "Python/generated_cases.c.h" + #line 2662 "Python/generated_cases.c.h" Py_DECREF(level); Py_DECREF(fromlist); - #line 1842 "Python/bytecodes.c" + #line 1844 "Python/bytecodes.c" if (res == NULL) goto pop_2_error; - #line 2665 "Python/generated_cases.c.h" + #line 2667 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; DISPATCH(); @@ -2670,29 +2672,29 @@ TARGET(IMPORT_FROM) { PyObject *from = stack_pointer[-1]; PyObject *res; - #line 1846 "Python/bytecodes.c" + #line 1848 "Python/bytecodes.c" PyObject *name = GETITEM(frame->f_code->co_names, oparg); res = import_from(tstate, from, name); if (res == NULL) goto error; - #line 2678 "Python/generated_cases.c.h" + #line 2680 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = res; DISPATCH(); } TARGET(JUMP_FORWARD) { - #line 1852 "Python/bytecodes.c" + #line 1854 "Python/bytecodes.c" JUMPBY(oparg); - #line 2687 "Python/generated_cases.c.h" + #line 2689 "Python/generated_cases.c.h" DISPATCH(); } TARGET(JUMP_BACKWARD) { PREDICTED(JUMP_BACKWARD); - #line 1856 "Python/bytecodes.c" + #line 1858 "Python/bytecodes.c" assert(oparg < INSTR_OFFSET()); JUMPBY(-oparg); - #line 2696 "Python/generated_cases.c.h" + #line 2698 "Python/generated_cases.c.h" CHECK_EVAL_BREAKER(); DISPATCH(); } @@ -2700,7 +2702,7 @@ TARGET(POP_JUMP_IF_FALSE) { PREDICTED(POP_JUMP_IF_FALSE); PyObject *cond = stack_pointer[-1]; - #line 1862 "Python/bytecodes.c" + #line 1864 "Python/bytecodes.c" if (Py_IsTrue(cond)) { _Py_DECREF_NO_DEALLOC(cond); } @@ -2710,9 +2712,9 @@ } else { int err = PyObject_IsTrue(cond); - #line 2714 "Python/generated_cases.c.h" + #line 2716 "Python/generated_cases.c.h" Py_DECREF(cond); - #line 1872 "Python/bytecodes.c" + #line 1874 "Python/bytecodes.c" if (err == 0) { JUMPBY(oparg); } @@ -2720,14 +2722,14 @@ if (err < 0) goto pop_1_error; } } - #line 2724 "Python/generated_cases.c.h" + #line 2726 "Python/generated_cases.c.h" STACK_SHRINK(1); DISPATCH(); } TARGET(POP_JUMP_IF_TRUE) { PyObject *cond = stack_pointer[-1]; - #line 1882 "Python/bytecodes.c" + #line 1884 "Python/bytecodes.c" if (Py_IsFalse(cond)) { _Py_DECREF_NO_DEALLOC(cond); } @@ -2737,9 +2739,9 @@ } else { int err = PyObject_IsTrue(cond); - #line 2741 "Python/generated_cases.c.h" + #line 2743 "Python/generated_cases.c.h" Py_DECREF(cond); - #line 1892 "Python/bytecodes.c" + #line 1894 "Python/bytecodes.c" if (err > 0) { JUMPBY(oparg); } @@ -2747,67 +2749,67 @@ if (err < 0) goto pop_1_error; } } - #line 2751 "Python/generated_cases.c.h" + #line 2753 "Python/generated_cases.c.h" STACK_SHRINK(1); DISPATCH(); } TARGET(POP_JUMP_IF_NOT_NONE) { PyObject *value = stack_pointer[-1]; - #line 1902 "Python/bytecodes.c" + #line 1904 "Python/bytecodes.c" if (!Py_IsNone(value)) { - #line 2760 "Python/generated_cases.c.h" + #line 2762 "Python/generated_cases.c.h" Py_DECREF(value); - #line 1904 "Python/bytecodes.c" + #line 1906 "Python/bytecodes.c" JUMPBY(oparg); } else { _Py_DECREF_NO_DEALLOC(value); } - #line 2768 "Python/generated_cases.c.h" + #line 2770 "Python/generated_cases.c.h" STACK_SHRINK(1); DISPATCH(); } TARGET(POP_JUMP_IF_NONE) { PyObject *value = stack_pointer[-1]; - #line 1912 "Python/bytecodes.c" + #line 1914 "Python/bytecodes.c" if (Py_IsNone(value)) { _Py_DECREF_NO_DEALLOC(value); JUMPBY(oparg); } else { - #line 2781 "Python/generated_cases.c.h" + #line 2783 "Python/generated_cases.c.h" Py_DECREF(value); - #line 1918 "Python/bytecodes.c" + #line 1920 "Python/bytecodes.c" } - #line 2785 "Python/generated_cases.c.h" + #line 2787 "Python/generated_cases.c.h" STACK_SHRINK(1); DISPATCH(); } TARGET(JUMP_BACKWARD_NO_INTERRUPT) { - #line 1922 "Python/bytecodes.c" + #line 1924 "Python/bytecodes.c" /* This bytecode is used in the `yield from` or `await` loop. * If there is an interrupt, we want it handled in the innermost * generator or coroutine, so we deliberately do not check it here. * (see bpo-30039). */ JUMPBY(-oparg); - #line 2798 "Python/generated_cases.c.h" + #line 2800 "Python/generated_cases.c.h" DISPATCH(); } TARGET(GET_LEN) { PyObject *obj = stack_pointer[-1]; PyObject *len_o; - #line 1931 "Python/bytecodes.c" + #line 1933 "Python/bytecodes.c" // PUSH(len(TOS)) Py_ssize_t len_i = PyObject_Length(obj); if (len_i < 0) goto error; len_o = PyLong_FromSsize_t(len_i); if (len_o == NULL) goto error; - #line 2811 "Python/generated_cases.c.h" + #line 2813 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = len_o; DISPATCH(); @@ -2818,16 +2820,16 @@ PyObject *type = stack_pointer[-2]; PyObject *subject = stack_pointer[-3]; PyObject *attrs; - #line 1939 "Python/bytecodes.c" + #line 1941 "Python/bytecodes.c" // Pop TOS and TOS1. Set TOS to a tuple of attributes on success, or // None on failure. assert(PyTuple_CheckExact(names)); attrs = match_class(tstate, subject, type, oparg, names); - #line 2827 "Python/generated_cases.c.h" + #line 2829 "Python/generated_cases.c.h" Py_DECREF(subject); Py_DECREF(type); Py_DECREF(names); - #line 1944 "Python/bytecodes.c" + #line 1946 "Python/bytecodes.c" if (attrs) { assert(PyTuple_CheckExact(attrs)); // Success! } @@ -2835,7 +2837,7 @@ if (_PyErr_Occurred(tstate)) goto pop_3_error; attrs = Py_NewRef(Py_None); // Failure! } - #line 2839 "Python/generated_cases.c.h" + #line 2841 "Python/generated_cases.c.h" STACK_SHRINK(2); stack_pointer[-1] = attrs; DISPATCH(); @@ -2844,10 +2846,10 @@ TARGET(MATCH_MAPPING) { PyObject *subject = stack_pointer[-1]; PyObject *res; - #line 1954 "Python/bytecodes.c" + #line 1956 "Python/bytecodes.c" int match = Py_TYPE(subject)->tp_flags & Py_TPFLAGS_MAPPING; res = Py_NewRef(match ? Py_True : Py_False); - #line 2851 "Python/generated_cases.c.h" + #line 2853 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = res; PREDICT(POP_JUMP_IF_FALSE); @@ -2857,10 +2859,10 @@ TARGET(MATCH_SEQUENCE) { PyObject *subject = stack_pointer[-1]; PyObject *res; - #line 1960 "Python/bytecodes.c" + #line 1962 "Python/bytecodes.c" int match = Py_TYPE(subject)->tp_flags & Py_TPFLAGS_SEQUENCE; res = Py_NewRef(match ? Py_True : Py_False); - #line 2864 "Python/generated_cases.c.h" + #line 2866 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = res; PREDICT(POP_JUMP_IF_FALSE); @@ -2871,11 +2873,11 @@ PyObject *keys = stack_pointer[-1]; PyObject *subject = stack_pointer[-2]; PyObject *values_or_none; - #line 1966 "Python/bytecodes.c" + #line 1968 "Python/bytecodes.c" // On successful match, PUSH(values). Otherwise, PUSH(None). values_or_none = match_keys(tstate, subject, keys); if (values_or_none == NULL) goto error; - #line 2879 "Python/generated_cases.c.h" + #line 2881 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = values_or_none; DISPATCH(); @@ -2884,14 +2886,14 @@ TARGET(GET_ITER) { PyObject *iterable = stack_pointer[-1]; PyObject *iter; - #line 1972 "Python/bytecodes.c" + #line 1974 "Python/bytecodes.c" /* before: [obj]; after [getiter(obj)] */ iter = PyObject_GetIter(iterable); - #line 2891 "Python/generated_cases.c.h" + #line 2893 "Python/generated_cases.c.h" Py_DECREF(iterable); - #line 1975 "Python/bytecodes.c" + #line 1977 "Python/bytecodes.c" if (iter == NULL) goto pop_1_error; - #line 2895 "Python/generated_cases.c.h" + #line 2897 "Python/generated_cases.c.h" stack_pointer[-1] = iter; DISPATCH(); } @@ -2899,7 +2901,7 @@ TARGET(GET_YIELD_FROM_ITER) { PyObject *iterable = stack_pointer[-1]; PyObject *iter; - #line 1979 "Python/bytecodes.c" + #line 1981 "Python/bytecodes.c" /* before: [obj]; after [getiter(obj)] */ if (PyCoro_CheckExact(iterable)) { /* `iterable` is a coroutine */ @@ -2922,11 +2924,11 @@ if (iter == NULL) { goto error; } - #line 2926 "Python/generated_cases.c.h" + #line 2928 "Python/generated_cases.c.h" Py_DECREF(iterable); - #line 2002 "Python/bytecodes.c" + #line 2004 "Python/bytecodes.c" } - #line 2930 "Python/generated_cases.c.h" + #line 2932 "Python/generated_cases.c.h" stack_pointer[-1] = iter; PREDICT(LOAD_CONST); DISPATCH(); @@ -2937,7 +2939,7 @@ static_assert(INLINE_CACHE_ENTRIES_FOR_ITER == 1, "incorrect cache size"); PyObject *iter = stack_pointer[-1]; PyObject *next; - #line 2021 "Python/bytecodes.c" + #line 2023 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION _PyForIterCache *cache = (_PyForIterCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { @@ -2970,7 +2972,7 @@ DISPATCH(); } // Common case: no jump, leave it to the code generator - #line 2974 "Python/generated_cases.c.h" + #line 2976 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = next; next_instr += 1; @@ -2980,7 +2982,7 @@ TARGET(FOR_ITER_LIST) { PyObject *iter = stack_pointer[-1]; PyObject *next; - #line 2056 "Python/bytecodes.c" + #line 2058 "Python/bytecodes.c" assert(cframe.use_tracing == 0); DEOPT_IF(Py_TYPE(iter) != &PyListIter_Type, FOR_ITER); _PyListIterObject *it = (_PyListIterObject *)iter; @@ -3001,7 +3003,7 @@ DISPATCH(); end_for_iter_list: // Common case: no jump, leave it to the code generator - #line 3005 "Python/generated_cases.c.h" + #line 3007 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = next; next_instr += 1; @@ -3011,7 +3013,7 @@ TARGET(FOR_ITER_TUPLE) { PyObject *iter = stack_pointer[-1]; PyObject *next; - #line 2079 "Python/bytecodes.c" + #line 2081 "Python/bytecodes.c" assert(cframe.use_tracing == 0); _PyTupleIterObject *it = (_PyTupleIterObject *)iter; DEOPT_IF(Py_TYPE(it) != &PyTupleIter_Type, FOR_ITER); @@ -3032,7 +3034,7 @@ DISPATCH(); end_for_iter_tuple: // Common case: no jump, leave it to the code generator - #line 3036 "Python/generated_cases.c.h" + #line 3038 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = next; next_instr += 1; @@ -3042,7 +3044,7 @@ TARGET(FOR_ITER_RANGE) { PyObject *iter = stack_pointer[-1]; PyObject *next; - #line 2102 "Python/bytecodes.c" + #line 2104 "Python/bytecodes.c" assert(cframe.use_tracing == 0); _PyRangeIterObject *r = (_PyRangeIterObject *)iter; DEOPT_IF(Py_TYPE(r) != &PyRangeIter_Type, FOR_ITER); @@ -3061,7 +3063,7 @@ if (next == NULL) { goto error; } - #line 3065 "Python/generated_cases.c.h" + #line 3067 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = next; next_instr += 1; @@ -3070,7 +3072,7 @@ TARGET(FOR_ITER_GEN) { PyObject *iter = stack_pointer[-1]; - #line 2123 "Python/bytecodes.c" + #line 2125 "Python/bytecodes.c" assert(cframe.use_tracing == 0); PyGenObject *gen = (PyGenObject *)iter; DEOPT_IF(Py_TYPE(gen) != &PyGen_Type, FOR_ITER); @@ -3085,14 +3087,14 @@ JUMPBY(INLINE_CACHE_ENTRIES_FOR_ITER + oparg); assert(next_instr->op.code == END_FOR); DISPATCH_INLINED(gen_frame); - #line 3089 "Python/generated_cases.c.h" + #line 3091 "Python/generated_cases.c.h" } TARGET(BEFORE_ASYNC_WITH) { PyObject *mgr = stack_pointer[-1]; PyObject *exit; PyObject *res; - #line 2140 "Python/bytecodes.c" + #line 2142 "Python/bytecodes.c" PyObject *enter = _PyObject_LookupSpecial(mgr, &_Py_ID(__aenter__)); if (enter == NULL) { if (!_PyErr_Occurred(tstate)) { @@ -3115,16 +3117,16 @@ Py_DECREF(enter); goto error; } - #line 3119 "Python/generated_cases.c.h" + #line 3121 "Python/generated_cases.c.h" Py_DECREF(mgr); - #line 2163 "Python/bytecodes.c" + #line 2165 "Python/bytecodes.c" res = _PyObject_CallNoArgs(enter); Py_DECREF(enter); if (res == NULL) { Py_DECREF(exit); if (true) goto pop_1_error; } - #line 3128 "Python/generated_cases.c.h" + #line 3130 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = res; stack_pointer[-2] = exit; @@ -3136,7 +3138,7 @@ PyObject *mgr = stack_pointer[-1]; PyObject *exit; PyObject *res; - #line 2173 "Python/bytecodes.c" + #line 2175 "Python/bytecodes.c" /* pop the context manager, push its __exit__ and the * value returned from calling its __enter__ */ @@ -3162,16 +3164,16 @@ Py_DECREF(enter); goto error; } - #line 3166 "Python/generated_cases.c.h" + #line 3168 "Python/generated_cases.c.h" Py_DECREF(mgr); - #line 2199 "Python/bytecodes.c" + #line 2201 "Python/bytecodes.c" res = _PyObject_CallNoArgs(enter); Py_DECREF(enter); if (res == NULL) { Py_DECREF(exit); if (true) goto pop_1_error; } - #line 3175 "Python/generated_cases.c.h" + #line 3177 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = res; stack_pointer[-2] = exit; @@ -3183,7 +3185,7 @@ PyObject *lasti = stack_pointer[-3]; PyObject *exit_func = stack_pointer[-4]; PyObject *res; - #line 2208 "Python/bytecodes.c" + #line 2210 "Python/bytecodes.c" /* At the top of the stack are 4 values: - val: TOP = exc_info() - unused: SECOND = previous exception @@ -3204,7 +3206,7 @@ res = PyObject_Vectorcall(exit_func, stack + 1, 3 | PY_VECTORCALL_ARGUMENTS_OFFSET, NULL); if (res == NULL) goto error; - #line 3208 "Python/generated_cases.c.h" + #line 3210 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = res; DISPATCH(); @@ -3213,7 +3215,7 @@ TARGET(PUSH_EXC_INFO) { PyObject *new_exc = stack_pointer[-1]; PyObject *prev_exc; - #line 2231 "Python/bytecodes.c" + #line 2233 "Python/bytecodes.c" _PyErr_StackItem *exc_info = tstate->exc_info; if (exc_info->exc_value != NULL) { prev_exc = exc_info->exc_value; @@ -3223,7 +3225,7 @@ } assert(PyExceptionInstance_Check(new_exc)); exc_info->exc_value = Py_NewRef(new_exc); - #line 3227 "Python/generated_cases.c.h" + #line 3229 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = new_exc; stack_pointer[-2] = prev_exc; @@ -3236,8 +3238,8 @@ PyObject *res; uint32_t type_version = read_u32(&next_instr[1].cache); uint32_t keys_version = read_u32(&next_instr[3].cache); - PyObject *descr = read_obj(&next_instr[5].cache); - #line 2243 "Python/bytecodes.c" + uint16_t index = read_u16(&next_instr[5].cache); + #line 2245 "Python/bytecodes.c" /* Cached method object */ assert(cframe.use_tracing == 0); PyTypeObject *self_cls = Py_TYPE(self); @@ -3250,16 +3252,17 @@ DEOPT_IF(self_heap_type->ht_cached_keys->dk_version != keys_version, LOAD_ATTR); STAT_INC(LOAD_ATTR, hit); + PyObject *descr = self_cls->_tp_cache[index]; assert(descr != NULL); res2 = Py_NewRef(descr); assert(_PyType_HasFeature(Py_TYPE(res2), Py_TPFLAGS_METHOD_DESCRIPTOR)); res = self; assert(oparg & 1); - #line 3259 "Python/generated_cases.c.h" + #line 3262 "Python/generated_cases.c.h" STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; if (oparg & 1) { stack_pointer[-(1 + ((oparg & 1) ? 1 : 0))] = res2; } - next_instr += 9; + next_instr += 6; DISPATCH(); } @@ -3268,23 +3271,24 @@ PyObject *res2 = NULL; PyObject *res; uint32_t type_version = read_u32(&next_instr[1].cache); - PyObject *descr = read_obj(&next_instr[5].cache); - #line 2263 "Python/bytecodes.c" + uint16_t index = read_u16(&next_instr[5].cache); + #line 2266 "Python/bytecodes.c" assert(cframe.use_tracing == 0); PyTypeObject *self_cls = Py_TYPE(self); DEOPT_IF(self_cls->tp_version_tag != type_version, LOAD_ATTR); assert(self_cls->tp_dictoffset == 0); STAT_INC(LOAD_ATTR, hit); + PyObject *descr = self_cls->_tp_cache[index]; assert(descr != NULL); assert(_PyType_HasFeature(Py_TYPE(descr), Py_TPFLAGS_METHOD_DESCRIPTOR)); res2 = Py_NewRef(descr); res = self; assert(oparg & 1); - #line 3284 "Python/generated_cases.c.h" + #line 3288 "Python/generated_cases.c.h" STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; if (oparg & 1) { stack_pointer[-(1 + ((oparg & 1) ? 1 : 0))] = res2; } - next_instr += 9; + next_instr += 6; DISPATCH(); } @@ -3293,8 +3297,8 @@ PyObject *res2 = NULL; PyObject *res; uint32_t type_version = read_u32(&next_instr[1].cache); - PyObject *descr = read_obj(&next_instr[5].cache); - #line 2276 "Python/bytecodes.c" + uint16_t index = read_u16(&next_instr[5].cache); + #line 2280 "Python/bytecodes.c" assert(cframe.use_tracing == 0); PyTypeObject *self_cls = Py_TYPE(self); DEOPT_IF(self_cls->tp_version_tag != type_version, LOAD_ATTR); @@ -3304,25 +3308,26 @@ /* This object has a __dict__, just not yet created */ DEOPT_IF(dict != NULL, LOAD_ATTR); STAT_INC(LOAD_ATTR, hit); + PyObject *descr = self_cls->_tp_cache[index]; assert(descr != NULL); assert(_PyType_HasFeature(Py_TYPE(descr), Py_TPFLAGS_METHOD_DESCRIPTOR)); res2 = Py_NewRef(descr); res = self; assert(oparg & 1); - #line 3313 "Python/generated_cases.c.h" + #line 3318 "Python/generated_cases.c.h" STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; if (oparg & 1) { stack_pointer[-(1 + ((oparg & 1) ? 1 : 0))] = res2; } - next_instr += 9; + next_instr += 6; DISPATCH(); } TARGET(KW_NAMES) { - #line 2293 "Python/bytecodes.c" + #line 2298 "Python/bytecodes.c" assert(kwnames == NULL); assert(oparg < PyTuple_GET_SIZE(frame->f_code->co_consts)); kwnames = GETITEM(frame->f_code->co_consts, oparg); - #line 3326 "Python/generated_cases.c.h" + #line 3331 "Python/generated_cases.c.h" DISPATCH(); } @@ -3333,7 +3338,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2329 "Python/bytecodes.c" + #line 2334 "Python/bytecodes.c" int is_meth = method != NULL; int total_args = oparg; if (is_meth) { @@ -3405,7 +3410,7 @@ Py_DECREF(args[i]); } if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 3409 "Python/generated_cases.c.h" + #line 3414 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -3417,7 +3422,7 @@ TARGET(CALL_BOUND_METHOD_EXACT_ARGS) { PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; - #line 2407 "Python/bytecodes.c" + #line 2412 "Python/bytecodes.c" DEOPT_IF(method != NULL, CALL); DEOPT_IF(Py_TYPE(callable) != &PyMethod_Type, CALL); STAT_INC(CALL, hit); @@ -3427,7 +3432,7 @@ PEEK(oparg + 2) = Py_NewRef(meth); // method Py_DECREF(callable); GO_TO_INSTRUCTION(CALL_PY_EXACT_ARGS); - #line 3431 "Python/generated_cases.c.h" + #line 3436 "Python/generated_cases.c.h" } TARGET(CALL_PY_EXACT_ARGS) { @@ -3436,7 +3441,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; uint32_t func_version = read_u32(&next_instr[1].cache); - #line 2419 "Python/bytecodes.c" + #line 2424 "Python/bytecodes.c" assert(kwnames == NULL); DEOPT_IF(tstate->interp->eval_frame, CALL); int is_meth = method != NULL; @@ -3461,7 +3466,7 @@ STACK_SHRINK(oparg + 2); JUMPBY(INLINE_CACHE_ENTRIES_CALL); DISPATCH_INLINED(new_frame); - #line 3465 "Python/generated_cases.c.h" + #line 3470 "Python/generated_cases.c.h" } TARGET(CALL_PY_WITH_DEFAULTS) { @@ -3470,7 +3475,7 @@ PyObject *method = stack_pointer[-(2 + oparg)]; uint32_t func_version = read_u32(&next_instr[1].cache); uint16_t min_args = read_u16(&next_instr[3].cache); - #line 2446 "Python/bytecodes.c" + #line 2451 "Python/bytecodes.c" assert(kwnames == NULL); DEOPT_IF(tstate->interp->eval_frame, CALL); int is_meth = method != NULL; @@ -3500,7 +3505,7 @@ STACK_SHRINK(oparg + 2); JUMPBY(INLINE_CACHE_ENTRIES_CALL); DISPATCH_INLINED(new_frame); - #line 3504 "Python/generated_cases.c.h" + #line 3509 "Python/generated_cases.c.h" } TARGET(CALL_NO_KW_TYPE_1) { @@ -3508,7 +3513,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *null = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2478 "Python/bytecodes.c" + #line 2483 "Python/bytecodes.c" assert(kwnames == NULL); assert(cframe.use_tracing == 0); assert(oparg == 1); @@ -3519,7 +3524,7 @@ res = Py_NewRef(Py_TYPE(obj)); Py_DECREF(obj); Py_DECREF(&PyType_Type); // I.e., callable - #line 3523 "Python/generated_cases.c.h" + #line 3528 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -3532,7 +3537,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *null = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2491 "Python/bytecodes.c" + #line 2496 "Python/bytecodes.c" assert(kwnames == NULL); assert(cframe.use_tracing == 0); assert(oparg == 1); @@ -3544,7 +3549,7 @@ Py_DECREF(arg); Py_DECREF(&PyUnicode_Type); // I.e., callable if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 3548 "Python/generated_cases.c.h" + #line 3553 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -3558,7 +3563,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *null = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2506 "Python/bytecodes.c" + #line 2511 "Python/bytecodes.c" assert(kwnames == NULL); assert(oparg == 1); DEOPT_IF(null != NULL, CALL); @@ -3569,7 +3574,7 @@ Py_DECREF(arg); Py_DECREF(&PyTuple_Type); // I.e., tuple if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 3573 "Python/generated_cases.c.h" + #line 3578 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -3583,7 +3588,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2520 "Python/bytecodes.c" + #line 2525 "Python/bytecodes.c" int is_meth = method != NULL; int total_args = oparg; if (is_meth) { @@ -3605,7 +3610,7 @@ } Py_DECREF(tp); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 3609 "Python/generated_cases.c.h" + #line 3614 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -3619,7 +3624,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2545 "Python/bytecodes.c" + #line 2550 "Python/bytecodes.c" assert(cframe.use_tracing == 0); /* Builtin METH_O functions */ assert(kwnames == NULL); @@ -3648,7 +3653,7 @@ Py_DECREF(arg); Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 3652 "Python/generated_cases.c.h" + #line 3657 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -3662,7 +3667,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2577 "Python/bytecodes.c" + #line 2582 "Python/bytecodes.c" assert(cframe.use_tracing == 0); /* Builtin METH_FASTCALL functions, without keywords */ assert(kwnames == NULL); @@ -3695,7 +3700,7 @@ 'invalid'). In those cases an exception is set, so we must handle it. */ - #line 3699 "Python/generated_cases.c.h" + #line 3704 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -3709,7 +3714,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2613 "Python/bytecodes.c" + #line 2618 "Python/bytecodes.c" assert(cframe.use_tracing == 0); /* Builtin METH_FASTCALL | METH_KEYWORDS functions */ int is_meth = method != NULL; @@ -3742,7 +3747,7 @@ } Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 3746 "Python/generated_cases.c.h" + #line 3751 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -3756,7 +3761,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2649 "Python/bytecodes.c" + #line 2654 "Python/bytecodes.c" assert(cframe.use_tracing == 0); assert(kwnames == NULL); /* len(o) */ @@ -3782,7 +3787,7 @@ Py_DECREF(callable); Py_DECREF(arg); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 3786 "Python/generated_cases.c.h" + #line 3791 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -3795,7 +3800,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2677 "Python/bytecodes.c" + #line 2682 "Python/bytecodes.c" assert(cframe.use_tracing == 0); assert(kwnames == NULL); /* isinstance(o, o2) */ @@ -3823,7 +3828,7 @@ Py_DECREF(cls); Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 3827 "Python/generated_cases.c.h" + #line 3832 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -3835,7 +3840,7 @@ PyObject **args = (stack_pointer - oparg); PyObject *self = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; - #line 2708 "Python/bytecodes.c" + #line 2713 "Python/bytecodes.c" assert(cframe.use_tracing == 0); assert(kwnames == NULL); assert(oparg == 1); @@ -3854,14 +3859,14 @@ JUMPBY(INLINE_CACHE_ENTRIES_CALL + 1); assert(next_instr[-1].op.code == POP_TOP); DISPATCH(); - #line 3858 "Python/generated_cases.c.h" + #line 3863 "Python/generated_cases.c.h" } TARGET(CALL_NO_KW_METHOD_DESCRIPTOR_O) { PyObject **args = (stack_pointer - oparg); PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2729 "Python/bytecodes.c" + #line 2734 "Python/bytecodes.c" assert(kwnames == NULL); int is_meth = method != NULL; int total_args = oparg; @@ -3892,7 +3897,7 @@ Py_DECREF(arg); Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 3896 "Python/generated_cases.c.h" + #line 3901 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -3905,7 +3910,7 @@ PyObject **args = (stack_pointer - oparg); PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2763 "Python/bytecodes.c" + #line 2768 "Python/bytecodes.c" int is_meth = method != NULL; int total_args = oparg; if (is_meth) { @@ -3934,7 +3939,7 @@ } Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 3938 "Python/generated_cases.c.h" + #line 3943 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -3947,7 +3952,7 @@ PyObject **args = (stack_pointer - oparg); PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2795 "Python/bytecodes.c" + #line 2800 "Python/bytecodes.c" assert(kwnames == NULL); assert(oparg == 0 || oparg == 1); int is_meth = method != NULL; @@ -3976,7 +3981,7 @@ Py_DECREF(self); Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 3980 "Python/generated_cases.c.h" + #line 3985 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -3989,7 +3994,7 @@ PyObject **args = (stack_pointer - oparg); PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2827 "Python/bytecodes.c" + #line 2832 "Python/bytecodes.c" assert(kwnames == NULL); int is_meth = method != NULL; int total_args = oparg; @@ -4017,7 +4022,7 @@ } Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4021 "Python/generated_cases.c.h" + #line 4026 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4032,7 +4037,7 @@ PyObject *callargs = stack_pointer[-(1 + ((oparg & 1) ? 1 : 0))]; PyObject *func = stack_pointer[-(2 + ((oparg & 1) ? 1 : 0))]; PyObject *result; - #line 2858 "Python/bytecodes.c" + #line 2863 "Python/bytecodes.c" if (oparg & 1) { // DICT_MERGE is called before this opcode if there are kwargs. // It converts all dict subtypes in kwargs into regular dicts. @@ -4051,15 +4056,15 @@ assert(PyTuple_CheckExact(callargs)); result = do_call_core(tstate, func, callargs, kwargs, cframe.use_tracing); - #line 4055 "Python/generated_cases.c.h" + #line 4060 "Python/generated_cases.c.h" Py_DECREF(func); Py_DECREF(callargs); Py_XDECREF(kwargs); - #line 2877 "Python/bytecodes.c" + #line 2882 "Python/bytecodes.c" assert(PEEK(3 + (oparg & 1)) == NULL); if (result == NULL) { STACK_SHRINK(((oparg & 1) ? 1 : 0)); goto pop_3_error; } - #line 4063 "Python/generated_cases.c.h" + #line 4068 "Python/generated_cases.c.h" STACK_SHRINK(((oparg & 1) ? 1 : 0)); STACK_SHRINK(2); stack_pointer[-1] = result; @@ -4074,7 +4079,7 @@ PyObject *kwdefaults = (oparg & 0x02) ? stack_pointer[-(1 + ((oparg & 0x08) ? 1 : 0) + ((oparg & 0x04) ? 1 : 0) + ((oparg & 0x02) ? 1 : 0))] : NULL; PyObject *defaults = (oparg & 0x01) ? stack_pointer[-(1 + ((oparg & 0x08) ? 1 : 0) + ((oparg & 0x04) ? 1 : 0) + ((oparg & 0x02) ? 1 : 0) + ((oparg & 0x01) ? 1 : 0))] : NULL; PyObject *func; - #line 2888 "Python/bytecodes.c" + #line 2893 "Python/bytecodes.c" PyFunctionObject *func_obj = (PyFunctionObject *) PyFunction_New(codeobj, GLOBALS()); @@ -4103,14 +4108,14 @@ func_obj->func_version = ((PyCodeObject *)codeobj)->co_version; func = (PyObject *)func_obj; - #line 4107 "Python/generated_cases.c.h" + #line 4112 "Python/generated_cases.c.h" STACK_SHRINK(((oparg & 0x01) ? 1 : 0) + ((oparg & 0x02) ? 1 : 0) + ((oparg & 0x04) ? 1 : 0) + ((oparg & 0x08) ? 1 : 0)); stack_pointer[-1] = func; DISPATCH(); } TARGET(RETURN_GENERATOR) { - #line 2919 "Python/bytecodes.c" + #line 2924 "Python/bytecodes.c" assert(PyFunction_Check(frame->f_funcobj)); PyFunctionObject *func = (PyFunctionObject *)frame->f_funcobj; PyGenObject *gen = (PyGenObject *)_Py_MakeCoro(func); @@ -4131,7 +4136,7 @@ frame = cframe.current_frame = prev; _PyFrame_StackPush(frame, (PyObject *)gen); goto resume_frame; - #line 4135 "Python/generated_cases.c.h" + #line 4140 "Python/generated_cases.c.h" } TARGET(BUILD_SLICE) { @@ -4139,15 +4144,15 @@ PyObject *stop = stack_pointer[-(1 + ((oparg == 3) ? 1 : 0))]; PyObject *start = stack_pointer[-(2 + ((oparg == 3) ? 1 : 0))]; PyObject *slice; - #line 2942 "Python/bytecodes.c" + #line 2947 "Python/bytecodes.c" slice = PySlice_New(start, stop, step); - #line 4145 "Python/generated_cases.c.h" + #line 4150 "Python/generated_cases.c.h" Py_DECREF(start); Py_DECREF(stop); Py_XDECREF(step); - #line 2944 "Python/bytecodes.c" + #line 2949 "Python/bytecodes.c" if (slice == NULL) { STACK_SHRINK(((oparg == 3) ? 1 : 0)); goto pop_2_error; } - #line 4151 "Python/generated_cases.c.h" + #line 4156 "Python/generated_cases.c.h" STACK_SHRINK(((oparg == 3) ? 1 : 0)); STACK_SHRINK(1); stack_pointer[-1] = slice; @@ -4158,7 +4163,7 @@ PyObject *fmt_spec = ((oparg & FVS_MASK) == FVS_HAVE_SPEC) ? stack_pointer[-((((oparg & FVS_MASK) == FVS_HAVE_SPEC) ? 1 : 0))] : NULL; PyObject *value = stack_pointer[-(1 + (((oparg & FVS_MASK) == FVS_HAVE_SPEC) ? 1 : 0))]; PyObject *result; - #line 2948 "Python/bytecodes.c" + #line 2953 "Python/bytecodes.c" /* Handles f-string value formatting. */ PyObject *(*conv_fn)(PyObject *); int which_conversion = oparg & FVC_MASK; @@ -4193,7 +4198,7 @@ Py_DECREF(value); Py_XDECREF(fmt_spec); if (result == NULL) { STACK_SHRINK((((oparg & FVS_MASK) == FVS_HAVE_SPEC) ? 1 : 0)); goto pop_1_error; } - #line 4197 "Python/generated_cases.c.h" + #line 4202 "Python/generated_cases.c.h" STACK_SHRINK((((oparg & FVS_MASK) == FVS_HAVE_SPEC) ? 1 : 0)); stack_pointer[-1] = result; DISPATCH(); @@ -4202,10 +4207,10 @@ TARGET(COPY) { PyObject *bottom = stack_pointer[-(1 + (oparg-1))]; PyObject *top; - #line 2985 "Python/bytecodes.c" + #line 2990 "Python/bytecodes.c" assert(oparg > 0); top = Py_NewRef(bottom); - #line 4209 "Python/generated_cases.c.h" + #line 4214 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = top; DISPATCH(); @@ -4217,7 +4222,7 @@ PyObject *rhs = stack_pointer[-1]; PyObject *lhs = stack_pointer[-2]; PyObject *res; - #line 2990 "Python/bytecodes.c" + #line 2995 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION _PyBinaryOpCache *cache = (_PyBinaryOpCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { @@ -4233,12 +4238,12 @@ assert((unsigned)oparg < Py_ARRAY_LENGTH(binary_ops)); assert(binary_ops[oparg]); res = binary_ops[oparg](lhs, rhs); - #line 4237 "Python/generated_cases.c.h" + #line 4242 "Python/generated_cases.c.h" Py_DECREF(lhs); Py_DECREF(rhs); - #line 3006 "Python/bytecodes.c" + #line 3011 "Python/bytecodes.c" if (res == NULL) goto pop_2_error; - #line 4242 "Python/generated_cases.c.h" + #line 4247 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; next_instr += 1; @@ -4248,27 +4253,27 @@ TARGET(SWAP) { PyObject *top = stack_pointer[-1]; PyObject *bottom = stack_pointer[-(2 + (oparg-2))]; - #line 3011 "Python/bytecodes.c" + #line 3016 "Python/bytecodes.c" assert(oparg >= 2); - #line 4254 "Python/generated_cases.c.h" + #line 4259 "Python/generated_cases.c.h" stack_pointer[-1] = bottom; stack_pointer[-(2 + (oparg-2))] = top; DISPATCH(); } TARGET(EXTENDED_ARG) { - #line 3015 "Python/bytecodes.c" + #line 3020 "Python/bytecodes.c" assert(oparg); assert(cframe.use_tracing == 0); opcode = next_instr->op.code; oparg = oparg << 8 | next_instr->op.arg; PRE_DISPATCH_GOTO(); DISPATCH_GOTO(); - #line 4268 "Python/generated_cases.c.h" + #line 4273 "Python/generated_cases.c.h" } TARGET(CACHE) { - #line 3024 "Python/bytecodes.c" + #line 3029 "Python/bytecodes.c" Py_UNREACHABLE(); - #line 4274 "Python/generated_cases.c.h" + #line 4279 "Python/generated_cases.c.h" } diff --git a/Python/opcode_metadata.h b/Python/opcode_metadata.h index 920b7595484d53..9d382d66cc6912 100644 --- a/Python/opcode_metadata.h +++ b/Python/opcode_metadata.h @@ -699,7 +699,7 @@ _PyOpcode_num_pushed(int opcode, int oparg, bool jump) { } #endif -enum InstructionFormat { INSTR_FMT_IB, INSTR_FMT_IBC, INSTR_FMT_IBC0, INSTR_FMT_IBC000, INSTR_FMT_IBC00000000, INSTR_FMT_IBIB, INSTR_FMT_IX, INSTR_FMT_IXC, INSTR_FMT_IXC000 }; +enum InstructionFormat { INSTR_FMT_IB, INSTR_FMT_IBC, INSTR_FMT_IBC0, INSTR_FMT_IBC000, INSTR_FMT_IBC00000, INSTR_FMT_IBIB, INSTR_FMT_IX, INSTR_FMT_IXC, INSTR_FMT_IXC000 }; struct opcode_metadata { bool valid_entry; enum InstructionFormat instr_format; @@ -800,14 +800,14 @@ const struct opcode_metadata _PyOpcode_opcode_metadata[256] = { [DICT_UPDATE] = { true, INSTR_FMT_IB }, [DICT_MERGE] = { true, INSTR_FMT_IB }, [MAP_ADD] = { true, INSTR_FMT_IB }, - [LOAD_ATTR] = { true, INSTR_FMT_IBC00000000 }, - [LOAD_ATTR_INSTANCE_VALUE] = { true, INSTR_FMT_IBC00000000 }, - [LOAD_ATTR_MODULE] = { true, INSTR_FMT_IBC00000000 }, - [LOAD_ATTR_WITH_HINT] = { true, INSTR_FMT_IBC00000000 }, - [LOAD_ATTR_SLOT] = { true, INSTR_FMT_IBC00000000 }, - [LOAD_ATTR_CLASS] = { true, INSTR_FMT_IBC00000000 }, - [LOAD_ATTR_PROPERTY] = { true, INSTR_FMT_IBC00000000 }, - [LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN] = { true, INSTR_FMT_IBC00000000 }, + [LOAD_ATTR] = { true, INSTR_FMT_IBC00000 }, + [LOAD_ATTR_INSTANCE_VALUE] = { true, INSTR_FMT_IBC00000 }, + [LOAD_ATTR_MODULE] = { true, INSTR_FMT_IBC00000 }, + [LOAD_ATTR_WITH_HINT] = { true, INSTR_FMT_IBC00000 }, + [LOAD_ATTR_SLOT] = { true, INSTR_FMT_IBC00000 }, + [LOAD_ATTR_CLASS] = { true, INSTR_FMT_IBC00000 }, + [LOAD_ATTR_PROPERTY] = { true, INSTR_FMT_IBC00000 }, + [LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN] = { true, INSTR_FMT_IBC00000 }, [STORE_ATTR_INSTANCE_VALUE] = { true, INSTR_FMT_IXC000 }, [STORE_ATTR_WITH_HINT] = { true, INSTR_FMT_IBC000 }, [STORE_ATTR_SLOT] = { true, INSTR_FMT_IXC000 }, @@ -845,9 +845,9 @@ const struct opcode_metadata _PyOpcode_opcode_metadata[256] = { [BEFORE_WITH] = { true, INSTR_FMT_IX }, [WITH_EXCEPT_START] = { true, INSTR_FMT_IX }, [PUSH_EXC_INFO] = { true, INSTR_FMT_IX }, - [LOAD_ATTR_METHOD_WITH_VALUES] = { true, INSTR_FMT_IBC00000000 }, - [LOAD_ATTR_METHOD_NO_DICT] = { true, INSTR_FMT_IBC00000000 }, - [LOAD_ATTR_METHOD_LAZY_DICT] = { true, INSTR_FMT_IBC00000000 }, + [LOAD_ATTR_METHOD_WITH_VALUES] = { true, INSTR_FMT_IBC00000 }, + [LOAD_ATTR_METHOD_NO_DICT] = { true, INSTR_FMT_IBC00000 }, + [LOAD_ATTR_METHOD_LAZY_DICT] = { true, INSTR_FMT_IBC00000 }, [KW_NAMES] = { true, INSTR_FMT_IB }, [CALL] = { true, INSTR_FMT_IBC000 }, [CALL_BOUND_METHOD_EXACT_ARGS] = { true, INSTR_FMT_IBC000 }, diff --git a/Python/specialize.c b/Python/specialize.c index 2e93ab193990a1..ba15abd3cba727 100644 --- a/Python/specialize.c +++ b/Python/specialize.c @@ -481,6 +481,27 @@ static int function_kind(PyCodeObject *code); static bool function_check_args(PyObject *o, int expected_argcount, int opcode); static uint32_t function_get_version(PyObject *o, int opcode); +static int +insert_into_cache(PyTypeObject *type, PyObject *descr) +{ + for (unsigned int i = 0; i < type->_tp_cache_used; i++) { + if (type->_tp_cache[i] == descr) { + return i; + } + } + if (type->_tp_cache_used == type->_tp_cache_size) { + type->_tp_cache_size = Py_MAX(type->_tp_cache_size << 1, (1 << 2)); + PyMem_Resize(type->_tp_cache, PyObject *, type->_tp_cache_size); + if (type->_tp_cache == NULL) { + type->_tp_cache_size = 0; + type->_tp_cache_used = 0; + return -1; + } + } + type->_tp_cache[type->_tp_cache_used] = descr; + return type->_tp_cache_used++; +} + static int specialize_module_load_attr( PyObject *owner, _Py_CODEUNIT *instr, PyObject *name @@ -775,7 +796,13 @@ _Py_Specialize_LoadAttr(PyObject *owner, _Py_CODEUNIT *instr, PyObject *name) assert(type->tp_version_tag != 0); write_u32(lm_cache->type_version, type->tp_version_tag); /* borrowed */ - write_obj(lm_cache->descr, fget); + int index = insert_into_cache(type, fget); + if (index < 0) { + SPECIALIZATION_FAIL(LOAD_ATTR, SPEC_FAIL_OUT_OF_RANGE); + goto fail; + } + assert(index <= UINT16_MAX); + lm_cache->index = index; instr->op.code = LOAD_ATTR_PROPERTY; goto success; } @@ -835,7 +862,13 @@ _Py_Specialize_LoadAttr(PyObject *owner, _Py_CODEUNIT *instr, PyObject *name) } write_u32(lm_cache->keys_version, version); /* borrowed */ - write_obj(lm_cache->descr, descr); + int index = insert_into_cache(type, descr); + if (index < 0) { + SPECIALIZATION_FAIL(LOAD_ATTR, SPEC_FAIL_OUT_OF_RANGE); + goto fail; + } + assert(index <= UINT16_MAX); + lm_cache->index = index; write_u32(lm_cache->type_version, type->tp_version_tag); instr->op.code = LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN; goto success; @@ -1027,7 +1060,13 @@ specialize_class_load_attr(PyObject *owner, _Py_CODEUNIT *instr, case METHOD: case NON_DESCRIPTOR: write_u32(cache->type_version, ((PyTypeObject *)owner)->tp_version_tag); - write_obj(cache->descr, descr); + int index = insert_into_cache((PyTypeObject *)owner, descr); + if (index < 0) { + SPECIALIZATION_FAIL(LOAD_ATTR, SPEC_FAIL_OUT_OF_RANGE); + return -1; + } + assert(index <= UINT16_MAX); + cache->index = index; instr->op.code = LOAD_ATTR_CLASS; return 0; #ifdef Py_STATS @@ -1108,7 +1147,13 @@ PyObject *descr, DescriptorClassification kind) * working since Python 2.6 and it's battle-tested. */ write_u32(cache->type_version, owner_cls->tp_version_tag); - write_obj(cache->descr, descr); + int index = insert_into_cache(owner_cls, descr); + if (index < 0) { + SPECIALIZATION_FAIL(LOAD_ATTR, SPEC_FAIL_OUT_OF_RANGE); + return 0; + } + assert(index <= UINT16_MAX); + cache->index = index; return 1; } From 0e21f47cc8f6943ee7f53bee5b5e43faec814e03 Mon Sep 17 00:00:00 2001 From: Brandt Bucher Date: Thu, 23 Mar 2023 04:15:02 -0700 Subject: [PATCH 2/5] Try a bigger starting cache size (8 instead of 1) --- Python/specialize.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Python/specialize.c b/Python/specialize.c index ba15abd3cba727..a93660ab47ab7c 100644 --- a/Python/specialize.c +++ b/Python/specialize.c @@ -490,7 +490,7 @@ insert_into_cache(PyTypeObject *type, PyObject *descr) } } if (type->_tp_cache_used == type->_tp_cache_size) { - type->_tp_cache_size = Py_MAX(type->_tp_cache_size << 1, (1 << 2)); + type->_tp_cache_size = Py_MAX(type->_tp_cache_size << 1, 8); PyMem_Resize(type->_tp_cache, PyObject *, type->_tp_cache_size); if (type->_tp_cache == NULL) { type->_tp_cache_size = 0; From bde6bec49a139ad2ea6f78790c9b9cd0889777af Mon Sep 17 00:00:00 2001 From: Brandt Bucher Date: Thu, 23 Mar 2023 04:35:15 -0700 Subject: [PATCH 3/5] Try a fixed cache size --- Doc/includes/typestruct.h | 3 +-- Include/cpython/object.h | 5 +++-- Lib/test/test_sys.py | 2 +- Objects/typeobject.c | 4 ---- Python/specialize.c | 14 ++++---------- 5 files changed, 9 insertions(+), 19 deletions(-) diff --git a/Doc/includes/typestruct.h b/Doc/includes/typestruct.h index 41a5dd582382f9..41b1dd62590bf7 100644 --- a/Doc/includes/typestruct.h +++ b/Doc/includes/typestruct.h @@ -81,9 +81,8 @@ typedef struct _typeobject { destructor tp_finalize; vectorcallfunc tp_vectorcall; - unsigned int _tp_cache_size; unsigned int _tp_cache_used; - PyObject **_tp_cache; + PyObject *_tp_cache[_TP_CACHE_SIZE]; /* bitset of which type-watchers care about this type */ char tp_watched; diff --git a/Include/cpython/object.h b/Include/cpython/object.h index 98633fb17a7a80..7877dc417ca6be 100644 --- a/Include/cpython/object.h +++ b/Include/cpython/object.h @@ -141,6 +141,8 @@ typedef struct { * backwards-compatibility */ typedef Py_ssize_t printfunc; +#define _TP_CACHE_SIZE (1 << 3) + // If this structure is modified, Doc/includes/typestruct.h should be updated // as well. struct _typeobject { @@ -226,9 +228,8 @@ struct _typeobject { destructor tp_finalize; vectorcallfunc tp_vectorcall; - unsigned int _tp_cache_size; unsigned int _tp_cache_used; - PyObject **_tp_cache; + PyObject *_tp_cache[_TP_CACHE_SIZE]; /* bitset of which type-watchers care about this type */ char tp_watched; diff --git a/Lib/test/test_sys.py b/Lib/test/test_sys.py index 50b92214414dea..fd18a56d19ef5e 100644 --- a/Lib/test/test_sys.py +++ b/Lib/test/test_sys.py @@ -1545,7 +1545,7 @@ def delx(self): del self.__x check((1,2,3), vsize('') + 3*self.P) # type # static type: PyTypeObject - fmt = 'P2nPI13Pl4Pn9Pn12PIPIIPc' + fmt = 'P2nPI13Pl4Pn9Pn12PIPI8Pc' s = vsize('2P' + fmt) check(int, s) # class diff --git a/Objects/typeobject.c b/Objects/typeobject.c index eef0d006338a8f..9dc3ace419f88b 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -4496,10 +4496,7 @@ _PyStaticType_Dealloc(PyTypeObject *type) static_builtin_state_clear(type); /* We leave _Py_TPFLAGS_STATIC_BUILTIN set on tp_flags. */ } - type->_tp_cache_size = 0; type->_tp_cache_used = 0; - PyMem_Free(type->_tp_cache); - type->_tp_cache = NULL; } @@ -4523,7 +4520,6 @@ type_dealloc(PyTypeObject *type) Py_XDECREF(type->tp_mro); Py_XDECREF(type->tp_cache); clear_subclasses(type); - PyMem_Free(type->_tp_cache); /* A type's tp_doc is heap allocated, unlike the tp_doc slots * of most other objects. It's okay to cast it to char *. diff --git a/Python/specialize.c b/Python/specialize.c index a93660ab47ab7c..8e753bffc74744 100644 --- a/Python/specialize.c +++ b/Python/specialize.c @@ -489,17 +489,11 @@ insert_into_cache(PyTypeObject *type, PyObject *descr) return i; } } - if (type->_tp_cache_used == type->_tp_cache_size) { - type->_tp_cache_size = Py_MAX(type->_tp_cache_size << 1, 8); - PyMem_Resize(type->_tp_cache, PyObject *, type->_tp_cache_size); - if (type->_tp_cache == NULL) { - type->_tp_cache_size = 0; - type->_tp_cache_used = 0; - return -1; - } + if (type->_tp_cache_used < _TP_CACHE_SIZE) { + type->_tp_cache[type->_tp_cache_used] = descr; + return type->_tp_cache_used++; } - type->_tp_cache[type->_tp_cache_used] = descr; - return type->_tp_cache_used++; + return -1; } static int From 212046ce2f6fa3e76a46d84cba3fdf81d933cc5c Mon Sep 17 00:00:00 2001 From: Brandt Bucher Date: Thu, 23 Mar 2023 11:27:23 -0700 Subject: [PATCH 4/5] Bump the size to 16 --- Include/cpython/object.h | 2 +- Lib/test/test_sys.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Include/cpython/object.h b/Include/cpython/object.h index 7877dc417ca6be..9870e7d8436b1b 100644 --- a/Include/cpython/object.h +++ b/Include/cpython/object.h @@ -141,7 +141,7 @@ typedef struct { * backwards-compatibility */ typedef Py_ssize_t printfunc; -#define _TP_CACHE_SIZE (1 << 3) +#define _TP_CACHE_SIZE (1 << 4) // If this structure is modified, Doc/includes/typestruct.h should be updated // as well. diff --git a/Lib/test/test_sys.py b/Lib/test/test_sys.py index fd18a56d19ef5e..88611790268c75 100644 --- a/Lib/test/test_sys.py +++ b/Lib/test/test_sys.py @@ -1545,7 +1545,7 @@ def delx(self): del self.__x check((1,2,3), vsize('') + 3*self.P) # type # static type: PyTypeObject - fmt = 'P2nPI13Pl4Pn9Pn12PIPI8Pc' + fmt = 'P2nPI13Pl4Pn9Pn12PIPI16Pc' s = vsize('2P' + fmt) check(int, s) # class From cdc31897f9e1b584b2ebe12cf80e551e1dba0df2 Mon Sep 17 00:00:00 2001 From: Brandt Bucher Date: Thu, 23 Mar 2023 22:31:25 -0700 Subject: [PATCH 5/5] Blurb add --- .../2023-03-23-22-31-15.gh-issue-93533.RyrB_g.rst | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2023-03-23-22-31-15.gh-issue-93533.RyrB_g.rst diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-03-23-22-31-15.gh-issue-93533.RyrB_g.rst b/Misc/NEWS.d/next/Core and Builtins/2023-03-23-22-31-15.gh-issue-93533.RyrB_g.rst new file mode 100644 index 00000000000000..2e07ae75752599 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2023-03-23-22-31-15.gh-issue-93533.RyrB_g.rst @@ -0,0 +1,3 @@ +Reduce the number of inline :opcode:`CACHE` entries for :opcode:`LOAD_ATTR` +instructions by adding a shared array of cached methods to the +:c:type:`PyTypeObject` struct.