From 2f483f56a36b70c6dab60579841325fccad14939 Mon Sep 17 00:00:00 2001 From: Ken Jin Date: Sun, 19 Jun 2022 00:53:01 +0800 Subject: [PATCH 01/17] Specialize LOAD_ATTR for custom __getattr__ --- Include/cpython/object.h | 2 + Include/internal/pycore_opcode.h | 44 ++++----- Include/internal/pycore_typeobject.h | 3 + Include/opcode.h | 60 ++++++------ Lib/opcode.py | 2 + Objects/typeobject.c | 38 ++++---- Python/ceval.c | 92 +++++++++++++++++++ Python/opcode_targets.h | 38 ++++---- Python/specialize.c | 131 +++++++++++++++++++++++---- 9 files changed, 302 insertions(+), 108 deletions(-) diff --git a/Include/cpython/object.h b/Include/cpython/object.h index b018dabf9d862f..0bf543f3433007 100644 --- a/Include/cpython/object.h +++ b/Include/cpython/object.h @@ -234,6 +234,8 @@ struct _typeobject { * by code other than the specializer and interpreter. */ struct _specialization_cache { PyObject *getitem; + PyObject *getattribute; + PyObject *getattr; }; /* The *real* layout of a type object when allocated on the heap */ diff --git a/Include/internal/pycore_opcode.h b/Include/internal/pycore_opcode.h index f0edbc731a6eed..42442fb96d10ac 100644 --- a/Include/internal/pycore_opcode.h +++ b/Include/internal/pycore_opcode.h @@ -147,6 +147,8 @@ const uint8_t _PyOpcode_Deopt[256] = { [LOAD_ATTR] = LOAD_ATTR, [LOAD_ATTR_ADAPTIVE] = LOAD_ATTR, [LOAD_ATTR_CLASS] = LOAD_ATTR, + [LOAD_ATTR_GETATTRIBUTE_GETATTR_OVERRIDDEN] = LOAD_ATTR, + [LOAD_ATTR_GETATTRIBUTE_GETATTR_PY_OVERRIDDEN] = LOAD_ATTR, [LOAD_ATTR_INSTANCE_VALUE] = LOAD_ATTR, [LOAD_ATTR_METHOD_LAZY_DICT] = LOAD_ATTR, [LOAD_ATTR_METHOD_NO_DICT] = LOAD_ATTR, @@ -328,6 +330,8 @@ const uint8_t _PyOpcode_Original[256] = { [LOAD_ATTR] = LOAD_ATTR, [LOAD_ATTR_ADAPTIVE] = LOAD_ATTR, [LOAD_ATTR_CLASS] = LOAD_ATTR, + [LOAD_ATTR_GETATTRIBUTE_GETATTR_OVERRIDDEN] = LOAD_ATTR, + [LOAD_ATTR_GETATTRIBUTE_GETATTR_PY_OVERRIDDEN] = LOAD_ATTR, [LOAD_ATTR_INSTANCE_VALUE] = LOAD_ATTR, [LOAD_ATTR_METHOD_LAZY_DICT] = LOAD_ATTR, [LOAD_ATTR_METHOD_NO_DICT] = LOAD_ATTR, @@ -481,29 +485,29 @@ static const char *const _PyOpcode_OpName[256] = { [DELETE_SUBSCR] = "DELETE_SUBSCR", [LOAD_ATTR_ADAPTIVE] = "LOAD_ATTR_ADAPTIVE", [LOAD_ATTR_CLASS] = "LOAD_ATTR_CLASS", + [LOAD_ATTR_GETATTRIBUTE_GETATTR_OVERRIDDEN] = "LOAD_ATTR_GETATTRIBUTE_GETATTR_OVERRIDDEN", + [LOAD_ATTR_GETATTRIBUTE_GETATTR_PY_OVERRIDDEN] = "LOAD_ATTR_GETATTRIBUTE_GETATTR_PY_OVERRIDDEN", [LOAD_ATTR_INSTANCE_VALUE] = "LOAD_ATTR_INSTANCE_VALUE", [LOAD_ATTR_MODULE] = "LOAD_ATTR_MODULE", - [LOAD_ATTR_PROPERTY] = "LOAD_ATTR_PROPERTY", - [LOAD_ATTR_SLOT] = "LOAD_ATTR_SLOT", [GET_ITER] = "GET_ITER", [GET_YIELD_FROM_ITER] = "GET_YIELD_FROM_ITER", [PRINT_EXPR] = "PRINT_EXPR", [LOAD_BUILD_CLASS] = "LOAD_BUILD_CLASS", - [LOAD_ATTR_WITH_HINT] = "LOAD_ATTR_WITH_HINT", - [LOAD_ATTR_METHOD_LAZY_DICT] = "LOAD_ATTR_METHOD_LAZY_DICT", + [LOAD_ATTR_PROPERTY] = "LOAD_ATTR_PROPERTY", + [LOAD_ATTR_SLOT] = "LOAD_ATTR_SLOT", [LOAD_ASSERTION_ERROR] = "LOAD_ASSERTION_ERROR", [RETURN_GENERATOR] = "RETURN_GENERATOR", + [LOAD_ATTR_WITH_HINT] = "LOAD_ATTR_WITH_HINT", + [LOAD_ATTR_METHOD_LAZY_DICT] = "LOAD_ATTR_METHOD_LAZY_DICT", [LOAD_ATTR_METHOD_NO_DICT] = "LOAD_ATTR_METHOD_NO_DICT", [LOAD_ATTR_METHOD_WITH_DICT] = "LOAD_ATTR_METHOD_WITH_DICT", [LOAD_ATTR_METHOD_WITH_VALUES] = "LOAD_ATTR_METHOD_WITH_VALUES", [LOAD_CONST__LOAD_FAST] = "LOAD_CONST__LOAD_FAST", - [LOAD_FAST__LOAD_CONST] = "LOAD_FAST__LOAD_CONST", - [LOAD_FAST__LOAD_FAST] = "LOAD_FAST__LOAD_FAST", [LIST_TO_TUPLE] = "LIST_TO_TUPLE", [RETURN_VALUE] = "RETURN_VALUE", [IMPORT_STAR] = "IMPORT_STAR", [SETUP_ANNOTATIONS] = "SETUP_ANNOTATIONS", - [LOAD_GLOBAL_ADAPTIVE] = "LOAD_GLOBAL_ADAPTIVE", + [LOAD_FAST__LOAD_CONST] = "LOAD_FAST__LOAD_CONST", [ASYNC_GEN_WRAP] = "ASYNC_GEN_WRAP", [PREP_RERAISE_STAR] = "PREP_RERAISE_STAR", [POP_EXCEPT] = "POP_EXCEPT", @@ -530,7 +534,7 @@ static const char *const _PyOpcode_OpName[256] = { [JUMP_FORWARD] = "JUMP_FORWARD", [JUMP_IF_FALSE_OR_POP] = "JUMP_IF_FALSE_OR_POP", [JUMP_IF_TRUE_OR_POP] = "JUMP_IF_TRUE_OR_POP", - [LOAD_GLOBAL_BUILTIN] = "LOAD_GLOBAL_BUILTIN", + [LOAD_FAST__LOAD_FAST] = "LOAD_FAST__LOAD_FAST", [POP_JUMP_FORWARD_IF_FALSE] = "POP_JUMP_FORWARD_IF_FALSE", [POP_JUMP_FORWARD_IF_TRUE] = "POP_JUMP_FORWARD_IF_TRUE", [LOAD_GLOBAL] = "LOAD_GLOBAL", @@ -538,7 +542,7 @@ static const char *const _PyOpcode_OpName[256] = { [CONTAINS_OP] = "CONTAINS_OP", [RERAISE] = "RERAISE", [COPY] = "COPY", - [LOAD_GLOBAL_MODULE] = "LOAD_GLOBAL_MODULE", + [LOAD_GLOBAL_ADAPTIVE] = "LOAD_GLOBAL_ADAPTIVE", [BINARY_OP] = "BINARY_OP", [SEND] = "SEND", [LOAD_FAST] = "LOAD_FAST", @@ -558,9 +562,9 @@ static const char *const _PyOpcode_OpName[256] = { [STORE_DEREF] = "STORE_DEREF", [DELETE_DEREF] = "DELETE_DEREF", [JUMP_BACKWARD] = "JUMP_BACKWARD", - [RESUME_QUICK] = "RESUME_QUICK", + [LOAD_GLOBAL_BUILTIN] = "LOAD_GLOBAL_BUILTIN", [CALL_FUNCTION_EX] = "CALL_FUNCTION_EX", - [STORE_ATTR_ADAPTIVE] = "STORE_ATTR_ADAPTIVE", + [LOAD_GLOBAL_MODULE] = "LOAD_GLOBAL_MODULE", [EXTENDED_ARG] = "EXTENDED_ARG", [LIST_APPEND] = "LIST_APPEND", [SET_ADD] = "SET_ADD", @@ -570,33 +574,33 @@ static const char *const _PyOpcode_OpName[256] = { [YIELD_VALUE] = "YIELD_VALUE", [RESUME] = "RESUME", [MATCH_CLASS] = "MATCH_CLASS", - [STORE_ATTR_INSTANCE_VALUE] = "STORE_ATTR_INSTANCE_VALUE", - [STORE_ATTR_SLOT] = "STORE_ATTR_SLOT", + [RESUME_QUICK] = "RESUME_QUICK", + [STORE_ATTR_ADAPTIVE] = "STORE_ATTR_ADAPTIVE", [FORMAT_VALUE] = "FORMAT_VALUE", [BUILD_CONST_KEY_MAP] = "BUILD_CONST_KEY_MAP", [BUILD_STRING] = "BUILD_STRING", + [STORE_ATTR_INSTANCE_VALUE] = "STORE_ATTR_INSTANCE_VALUE", + [STORE_ATTR_SLOT] = "STORE_ATTR_SLOT", [STORE_ATTR_WITH_HINT] = "STORE_ATTR_WITH_HINT", [STORE_FAST__LOAD_FAST] = "STORE_FAST__LOAD_FAST", - [STORE_FAST__STORE_FAST] = "STORE_FAST__STORE_FAST", - [STORE_SUBSCR_ADAPTIVE] = "STORE_SUBSCR_ADAPTIVE", [LIST_EXTEND] = "LIST_EXTEND", [SET_UPDATE] = "SET_UPDATE", [DICT_MERGE] = "DICT_MERGE", [DICT_UPDATE] = "DICT_UPDATE", + [STORE_FAST__STORE_FAST] = "STORE_FAST__STORE_FAST", + [STORE_SUBSCR_ADAPTIVE] = "STORE_SUBSCR_ADAPTIVE", [STORE_SUBSCR_DICT] = "STORE_SUBSCR_DICT", [STORE_SUBSCR_LIST_INT] = "STORE_SUBSCR_LIST_INT", [UNPACK_SEQUENCE_ADAPTIVE] = "UNPACK_SEQUENCE_ADAPTIVE", - [UNPACK_SEQUENCE_LIST] = "UNPACK_SEQUENCE_LIST", - [UNPACK_SEQUENCE_TUPLE] = "UNPACK_SEQUENCE_TUPLE", [CALL] = "CALL", [KW_NAMES] = "KW_NAMES", [POP_JUMP_BACKWARD_IF_NOT_NONE] = "POP_JUMP_BACKWARD_IF_NOT_NONE", [POP_JUMP_BACKWARD_IF_NONE] = "POP_JUMP_BACKWARD_IF_NONE", [POP_JUMP_BACKWARD_IF_FALSE] = "POP_JUMP_BACKWARD_IF_FALSE", [POP_JUMP_BACKWARD_IF_TRUE] = "POP_JUMP_BACKWARD_IF_TRUE", + [UNPACK_SEQUENCE_LIST] = "UNPACK_SEQUENCE_LIST", + [UNPACK_SEQUENCE_TUPLE] = "UNPACK_SEQUENCE_TUPLE", [UNPACK_SEQUENCE_TWO_TUPLE] = "UNPACK_SEQUENCE_TWO_TUPLE", - [178] = "<178>", - [179] = "<179>", [180] = "<180>", [181] = "<181>", [182] = "<182>", @@ -677,8 +681,6 @@ static const char *const _PyOpcode_OpName[256] = { #endif #define EXTRA_CASES \ - case 178: \ - case 179: \ case 180: \ case 181: \ case 182: \ diff --git a/Include/internal/pycore_typeobject.h b/Include/internal/pycore_typeobject.h index c480a3a57b436c..d6ca4f7d2c5e0a 100644 --- a/Include/internal/pycore_typeobject.h +++ b/Include/internal/pycore_typeobject.h @@ -44,6 +44,9 @@ extern PyStatus _PyTypes_InitSlotDefs(void); extern void _PyStaticType_Dealloc(PyTypeObject *type); +extern PyObject *_Py_slot_tp_getattro(PyObject *self, PyObject *name); +extern PyObject *_Py_slot_tp_getattr_hook(PyObject *self, PyObject *name); +extern PyObject *_Py_call_attribute(PyObject *self, PyObject *attr, PyObject *name); #ifdef __cplusplus } #endif diff --git a/Include/opcode.h b/Include/opcode.h index b58b498bbcf941..e7fdbeb478e80c 100644 --- a/Include/opcode.h +++ b/Include/opcode.h @@ -158,35 +158,37 @@ extern "C" { #define JUMP_BACKWARD_QUICK 59 #define LOAD_ATTR_ADAPTIVE 62 #define LOAD_ATTR_CLASS 63 -#define LOAD_ATTR_INSTANCE_VALUE 64 -#define LOAD_ATTR_MODULE 65 -#define LOAD_ATTR_PROPERTY 66 -#define LOAD_ATTR_SLOT 67 -#define LOAD_ATTR_WITH_HINT 72 -#define LOAD_ATTR_METHOD_LAZY_DICT 73 -#define LOAD_ATTR_METHOD_NO_DICT 76 -#define LOAD_ATTR_METHOD_WITH_DICT 77 -#define LOAD_ATTR_METHOD_WITH_VALUES 78 -#define LOAD_CONST__LOAD_FAST 79 -#define LOAD_FAST__LOAD_CONST 80 -#define LOAD_FAST__LOAD_FAST 81 -#define LOAD_GLOBAL_ADAPTIVE 86 -#define LOAD_GLOBAL_BUILTIN 113 -#define LOAD_GLOBAL_MODULE 121 -#define RESUME_QUICK 141 -#define STORE_ATTR_ADAPTIVE 143 -#define STORE_ATTR_INSTANCE_VALUE 153 -#define STORE_ATTR_SLOT 154 -#define STORE_ATTR_WITH_HINT 158 -#define STORE_FAST__LOAD_FAST 159 -#define STORE_FAST__STORE_FAST 160 -#define STORE_SUBSCR_ADAPTIVE 161 -#define STORE_SUBSCR_DICT 166 -#define STORE_SUBSCR_LIST_INT 167 -#define UNPACK_SEQUENCE_ADAPTIVE 168 -#define UNPACK_SEQUENCE_LIST 169 -#define UNPACK_SEQUENCE_TUPLE 170 -#define UNPACK_SEQUENCE_TWO_TUPLE 177 +#define LOAD_ATTR_GETATTRIBUTE_GETATTR_OVERRIDDEN 64 +#define LOAD_ATTR_GETATTRIBUTE_GETATTR_PY_OVERRIDDEN 65 +#define LOAD_ATTR_INSTANCE_VALUE 66 +#define LOAD_ATTR_MODULE 67 +#define LOAD_ATTR_PROPERTY 72 +#define LOAD_ATTR_SLOT 73 +#define LOAD_ATTR_WITH_HINT 76 +#define LOAD_ATTR_METHOD_LAZY_DICT 77 +#define LOAD_ATTR_METHOD_NO_DICT 78 +#define LOAD_ATTR_METHOD_WITH_DICT 79 +#define LOAD_ATTR_METHOD_WITH_VALUES 80 +#define LOAD_CONST__LOAD_FAST 81 +#define LOAD_FAST__LOAD_CONST 86 +#define LOAD_FAST__LOAD_FAST 113 +#define LOAD_GLOBAL_ADAPTIVE 121 +#define LOAD_GLOBAL_BUILTIN 141 +#define LOAD_GLOBAL_MODULE 143 +#define RESUME_QUICK 153 +#define STORE_ATTR_ADAPTIVE 154 +#define STORE_ATTR_INSTANCE_VALUE 158 +#define STORE_ATTR_SLOT 159 +#define STORE_ATTR_WITH_HINT 160 +#define STORE_FAST__LOAD_FAST 161 +#define STORE_FAST__STORE_FAST 166 +#define STORE_SUBSCR_ADAPTIVE 167 +#define STORE_SUBSCR_DICT 168 +#define STORE_SUBSCR_LIST_INT 169 +#define UNPACK_SEQUENCE_ADAPTIVE 170 +#define UNPACK_SEQUENCE_LIST 177 +#define UNPACK_SEQUENCE_TUPLE 178 +#define UNPACK_SEQUENCE_TWO_TUPLE 179 #define DO_TRACING 255 #define HAS_CONST(op) (false\ diff --git a/Lib/opcode.py b/Lib/opcode.py index 7657a5158d729e..a31f328109afa8 100644 --- a/Lib/opcode.py +++ b/Lib/opcode.py @@ -285,6 +285,8 @@ def jabs_op(name, op): "LOAD_ATTR_ADAPTIVE", # These potentially push [NULL, bound method] onto the stack. "LOAD_ATTR_CLASS", + "LOAD_ATTR_GETATTRIBUTE_GETATTR_OVERRIDDEN", + "LOAD_ATTR_GETATTRIBUTE_GETATTR_PY_OVERRIDDEN", "LOAD_ATTR_INSTANCE_VALUE", "LOAD_ATTR_MODULE", "LOAD_ATTR_PROPERTY", diff --git a/Objects/typeobject.c b/Objects/typeobject.c index 513055168062f1..beacf8f27cc18b 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -7766,24 +7766,24 @@ slot_tp_call(PyObject *self, PyObject *args, PyObject *kwds) /* There are two slot dispatch functions for tp_getattro. - - slot_tp_getattro() is used when __getattribute__ is overridden + - _Py_slot_tp_getattro() is used when __getattribute__ is overridden but no __getattr__ hook is present; - - slot_tp_getattr_hook() is used when a __getattr__ hook is present. + - _Py_slot_tp_getattr_hook() is used when a __getattr__ hook is present. - The code in update_one_slot() always installs slot_tp_getattr_hook(); this - detects the absence of __getattr__ and then installs the simpler slot if - necessary. */ + The code in update_one_slot() always installs _Py_slot_tp_getattr_hook(); + this detects the absence of __getattr__ and then installs the simpler + slot if necessary. */ -static PyObject * -slot_tp_getattro(PyObject *self, PyObject *name) +PyObject * +_Py_slot_tp_getattro(PyObject *self, PyObject *name) { PyObject *stack[2] = {self, name}; return vectorcall_method(&_Py_ID(__getattribute__), stack, 2); } -static inline PyObject * -call_attribute(PyObject *self, PyObject *attr, PyObject *name) +PyObject * +_Py_call_attribute(PyObject *self, PyObject *attr, PyObject *name) { PyObject *res, *descr = NULL; @@ -7807,8 +7807,8 @@ call_attribute(PyObject *self, PyObject *attr, PyObject *name) return res; } -static PyObject * -slot_tp_getattr_hook(PyObject *self, PyObject *name) +PyObject * +_Py_slot_tp_getattr_hook(PyObject *self, PyObject *name) { PyTypeObject *tp = Py_TYPE(self); PyObject *getattr, *getattribute, *res; @@ -7817,19 +7817,19 @@ slot_tp_getattr_hook(PyObject *self, PyObject *name) method fully for each attribute lookup for classes with __getattr__, even when the attribute is present. So we use _PyType_Lookup and create the method only when needed, with - call_attribute. */ + _Py_call_attribute. */ getattr = _PyType_Lookup(tp, &_Py_ID(__getattr__)); if (getattr == NULL) { /* No __getattr__ hook: use a simpler dispatcher */ - tp->tp_getattro = slot_tp_getattro; - return slot_tp_getattro(self, name); + tp->tp_getattro = _Py_slot_tp_getattro; + return _Py_slot_tp_getattro(self, name); } Py_INCREF(getattr); /* speed hack: we could use lookup_maybe, but that would resolve the method fully for each attribute lookup for classes with __getattr__, even when self has the default __getattribute__ method. So we use _PyType_Lookup and create the method only when - needed, with call_attribute. */ + needed, with _Py_call_attribute. */ getattribute = _PyType_Lookup(tp, &_Py_ID(__getattribute__)); if (getattribute == NULL || (Py_IS_TYPE(getattribute, &PyWrapperDescr_Type) && @@ -7838,12 +7838,12 @@ slot_tp_getattr_hook(PyObject *self, PyObject *name) res = PyObject_GenericGetAttr(self, name); else { Py_INCREF(getattribute); - res = call_attribute(self, getattribute, name); + res = _Py_call_attribute(self, getattribute, name); Py_DECREF(getattribute); } if (res == NULL && PyErr_ExceptionMatches(PyExc_AttributeError)) { PyErr_Clear(); - res = call_attribute(self, getattr, name); + res = _Py_call_attribute(self, getattr, name); } Py_DECREF(getattr); return res; @@ -8182,10 +8182,10 @@ static slotdef slotdefs[] = { PyWrapperFlag_KEYWORDS), TPSLOT("__str__", tp_str, slot_tp_str, wrap_unaryfunc, "__str__($self, /)\n--\n\nReturn str(self)."), - TPSLOT("__getattribute__", tp_getattro, slot_tp_getattr_hook, + TPSLOT("__getattribute__", tp_getattro, _Py_slot_tp_getattr_hook, wrap_binaryfunc, "__getattribute__($self, name, /)\n--\n\nReturn getattr(self, name)."), - TPSLOT("__getattr__", tp_getattro, slot_tp_getattr_hook, NULL, ""), + TPSLOT("__getattr__", tp_getattro, _Py_slot_tp_getattr_hook, NULL, ""), TPSLOT("__setattr__", tp_setattro, slot_tp_setattro, wrap_setattr, "__setattr__($self, name, value, /)\n--\n\nImplement setattr(self, name, value)."), TPSLOT("__delattr__", tp_setattro, slot_tp_setattro, wrap_delattr, diff --git a/Python/ceval.c b/Python/ceval.c index 44e4ffecb5e3c4..de860c05c3ca1b 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -3659,6 +3659,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int DEOPT_IF(cls->tp_version_tag != type_version, LOAD_ATTR); assert(type_version != 0); PyObject *fget = read_obj(cache->descr); + assert(Py_IS_TYPE(fget, &PyFunction_Type)); PyFunctionObject *f = (PyFunctionObject *)fget; uint32_t func_version = read_u32(cache->keys_version); assert(func_version != 0); @@ -3688,6 +3689,97 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int goto start_frame; } + TARGET(LOAD_ATTR_GETATTRIBUTE_GETATTR_OVERRIDDEN) { + assert(cframe.use_tracing == 0); + _PyLoadMethodCache *cache = (_PyLoadMethodCache *)next_instr; + PyObject *owner = TOP(); + PyTypeObject *cls = Py_TYPE(owner); + uint32_t type_version = read_u32(cache->type_version); + DEOPT_IF(cls->tp_version_tag != type_version, LOAD_ATTR); + assert(type_version != 0); + STAT_INC(LOAD_ATTR, hit); + + PyObject *name = GETITEM(names, oparg >> 1); + PyObject *getattribute = ((PyHeapTypeObject *)cls)->_spec_cache.getattribute; + PyObject *getattr = ((PyHeapTypeObject *)cls)->_spec_cache.getattr; + PyObject *res = getattribute ? + _Py_call_attribute(owner, getattribute, name) + : PyObject_GenericGetAttr(owner, name); + if (res == NULL && + getattr && + PyErr_ExceptionMatches(PyExc_AttributeError)) { + PyErr_Clear(); + res = _Py_call_attribute(owner, getattr, name); + } + if (res == NULL) { + goto error; + } + SET_TOP(NULL); + STACK_GROW((oparg & 1)); + SET_TOP(res); + Py_DECREF(owner); + DISPATCH(); + } + + TARGET(LOAD_ATTR_GETATTRIBUTE_GETATTR_PY_OVERRIDDEN) { + assert(cframe.use_tracing == 0); + DEOPT_IF(tstate->interp->eval_frame, LOAD_ATTR); + _PyLoadMethodCache *cache = (_PyLoadMethodCache *)next_instr; + PyObject *owner = TOP(); + PyTypeObject *cls = Py_TYPE(owner); + uint32_t type_version = read_u32(cache->type_version); + DEOPT_IF(cls->tp_version_tag != type_version, LOAD_ATTR); + assert(type_version != 0); + PyObject *getattr = ((PyHeapTypeObject *)cls)->_spec_cache.getattr; + assert(Py_IS_TYPE(getattr, &PyFunction_Type)); + PyFunctionObject *f = (PyFunctionObject *)getattr; + uint32_t func_version = read_u32(cache->keys_version); + assert(func_version != 0); + DEOPT_IF(f->func_version != func_version, LOAD_ATTR); + PyCodeObject *code = (PyCodeObject *)f->func_code; + assert(code->co_argcount == 2); + STAT_INC(LOAD_ATTR, hit); + + PyObject *name = GETITEM(names, oparg >> 1); + PyObject *getattribute = ((PyHeapTypeObject *)cls)->_spec_cache.getattribute; + PyObject *res = getattribute ? + _Py_call_attribute(owner, getattribute, name) + : PyObject_GenericGetAttr(owner, name); + if (res) { + SET_TOP(NULL); + STACK_GROW((oparg & 1)); + SET_TOP(res); + Py_DECREF(owner); + JUMPBY(INLINE_CACHE_ENTRIES_LOAD_ATTR); + DISPATCH(); + } + if (!PyErr_ExceptionMatches(PyExc_AttributeError)) { + goto error; + } + PyErr_Clear(); + Py_INCREF(f); + _PyInterpreterFrame *new_frame = _PyFrame_Push(tstate, f); + if (new_frame == NULL) { + goto error; + } + SET_TOP(NULL); + int push_null = !(oparg & 1); + STACK_SHRINK(push_null); + Py_INCREF(name); + new_frame->localsplus[0] = owner; + new_frame->localsplus[1] = name; + for (int i = 2; i < code->co_nlocalsplus; i++) { + new_frame->localsplus[i] = NULL; + } + _PyFrame_SetStackPointer(frame, stack_pointer); + JUMPBY(INLINE_CACHE_ENTRIES_LOAD_ATTR); + frame->prev_instr = next_instr - 1; + new_frame->previous = frame; + frame = cframe.current_frame = new_frame; + CALL_STAT_INC(inlined_py_calls); + goto start_frame; + } + TARGET(STORE_ATTR_ADAPTIVE) { assert(cframe.use_tracing == 0); _PyAttrCache *cache = (_PyAttrCache *)next_instr; diff --git a/Python/opcode_targets.h b/Python/opcode_targets.h index 9193dd9c9cc107..20425f3554b22c 100644 --- a/Python/opcode_targets.h +++ b/Python/opcode_targets.h @@ -63,29 +63,29 @@ static void *opcode_targets[256] = { &&TARGET_DELETE_SUBSCR, &&TARGET_LOAD_ATTR_ADAPTIVE, &&TARGET_LOAD_ATTR_CLASS, + &&TARGET_LOAD_ATTR_GETATTRIBUTE_GETATTR_OVERRIDDEN, + &&TARGET_LOAD_ATTR_GETATTRIBUTE_GETATTR_PY_OVERRIDDEN, &&TARGET_LOAD_ATTR_INSTANCE_VALUE, &&TARGET_LOAD_ATTR_MODULE, - &&TARGET_LOAD_ATTR_PROPERTY, - &&TARGET_LOAD_ATTR_SLOT, &&TARGET_GET_ITER, &&TARGET_GET_YIELD_FROM_ITER, &&TARGET_PRINT_EXPR, &&TARGET_LOAD_BUILD_CLASS, - &&TARGET_LOAD_ATTR_WITH_HINT, - &&TARGET_LOAD_ATTR_METHOD_LAZY_DICT, + &&TARGET_LOAD_ATTR_PROPERTY, + &&TARGET_LOAD_ATTR_SLOT, &&TARGET_LOAD_ASSERTION_ERROR, &&TARGET_RETURN_GENERATOR, + &&TARGET_LOAD_ATTR_WITH_HINT, + &&TARGET_LOAD_ATTR_METHOD_LAZY_DICT, &&TARGET_LOAD_ATTR_METHOD_NO_DICT, &&TARGET_LOAD_ATTR_METHOD_WITH_DICT, &&TARGET_LOAD_ATTR_METHOD_WITH_VALUES, &&TARGET_LOAD_CONST__LOAD_FAST, - &&TARGET_LOAD_FAST__LOAD_CONST, - &&TARGET_LOAD_FAST__LOAD_FAST, &&TARGET_LIST_TO_TUPLE, &&TARGET_RETURN_VALUE, &&TARGET_IMPORT_STAR, &&TARGET_SETUP_ANNOTATIONS, - &&TARGET_LOAD_GLOBAL_ADAPTIVE, + &&TARGET_LOAD_FAST__LOAD_CONST, &&TARGET_ASYNC_GEN_WRAP, &&TARGET_PREP_RERAISE_STAR, &&TARGET_POP_EXCEPT, @@ -112,7 +112,7 @@ static void *opcode_targets[256] = { &&TARGET_JUMP_FORWARD, &&TARGET_JUMP_IF_FALSE_OR_POP, &&TARGET_JUMP_IF_TRUE_OR_POP, - &&TARGET_LOAD_GLOBAL_BUILTIN, + &&TARGET_LOAD_FAST__LOAD_FAST, &&TARGET_POP_JUMP_FORWARD_IF_FALSE, &&TARGET_POP_JUMP_FORWARD_IF_TRUE, &&TARGET_LOAD_GLOBAL, @@ -120,7 +120,7 @@ static void *opcode_targets[256] = { &&TARGET_CONTAINS_OP, &&TARGET_RERAISE, &&TARGET_COPY, - &&TARGET_LOAD_GLOBAL_MODULE, + &&TARGET_LOAD_GLOBAL_ADAPTIVE, &&TARGET_BINARY_OP, &&TARGET_SEND, &&TARGET_LOAD_FAST, @@ -140,9 +140,9 @@ static void *opcode_targets[256] = { &&TARGET_STORE_DEREF, &&TARGET_DELETE_DEREF, &&TARGET_JUMP_BACKWARD, - &&TARGET_RESUME_QUICK, + &&TARGET_LOAD_GLOBAL_BUILTIN, &&TARGET_CALL_FUNCTION_EX, - &&TARGET_STORE_ATTR_ADAPTIVE, + &&TARGET_LOAD_GLOBAL_MODULE, &&TARGET_EXTENDED_ARG, &&TARGET_LIST_APPEND, &&TARGET_SET_ADD, @@ -152,30 +152,32 @@ static void *opcode_targets[256] = { &&TARGET_YIELD_VALUE, &&TARGET_RESUME, &&TARGET_MATCH_CLASS, - &&TARGET_STORE_ATTR_INSTANCE_VALUE, - &&TARGET_STORE_ATTR_SLOT, + &&TARGET_RESUME_QUICK, + &&TARGET_STORE_ATTR_ADAPTIVE, &&TARGET_FORMAT_VALUE, &&TARGET_BUILD_CONST_KEY_MAP, &&TARGET_BUILD_STRING, + &&TARGET_STORE_ATTR_INSTANCE_VALUE, + &&TARGET_STORE_ATTR_SLOT, &&TARGET_STORE_ATTR_WITH_HINT, &&TARGET_STORE_FAST__LOAD_FAST, - &&TARGET_STORE_FAST__STORE_FAST, - &&TARGET_STORE_SUBSCR_ADAPTIVE, &&TARGET_LIST_EXTEND, &&TARGET_SET_UPDATE, &&TARGET_DICT_MERGE, &&TARGET_DICT_UPDATE, + &&TARGET_STORE_FAST__STORE_FAST, + &&TARGET_STORE_SUBSCR_ADAPTIVE, &&TARGET_STORE_SUBSCR_DICT, &&TARGET_STORE_SUBSCR_LIST_INT, &&TARGET_UNPACK_SEQUENCE_ADAPTIVE, - &&TARGET_UNPACK_SEQUENCE_LIST, - &&TARGET_UNPACK_SEQUENCE_TUPLE, &&TARGET_CALL, &&TARGET_KW_NAMES, &&TARGET_POP_JUMP_BACKWARD_IF_NOT_NONE, &&TARGET_POP_JUMP_BACKWARD_IF_NONE, &&TARGET_POP_JUMP_BACKWARD_IF_FALSE, &&TARGET_POP_JUMP_BACKWARD_IF_TRUE, + &&TARGET_UNPACK_SEQUENCE_LIST, + &&TARGET_UNPACK_SEQUENCE_TUPLE, &&TARGET_UNPACK_SEQUENCE_TWO_TUPLE, &&_unknown_opcode, &&_unknown_opcode, @@ -252,7 +254,5 @@ static void *opcode_targets[256] = { &&_unknown_opcode, &&_unknown_opcode, &&_unknown_opcode, - &&_unknown_opcode, - &&_unknown_opcode, &&TARGET_DO_TRACING }; diff --git a/Python/specialize.c b/Python/specialize.c index 70ccf68a117591..208242df21ac75 100644 --- a/Python/specialize.c +++ b/Python/specialize.c @@ -368,6 +368,8 @@ miss_counter_start(void) { #define SPEC_FAIL_ATTR_HAS_MANAGED_DICT 25 #define SPEC_FAIL_ATTR_INSTANCE_ATTRIBUTE 26 #define SPEC_FAIL_ATTR_METACLASS_ATTRIBUTE 27 +#define SPEC_FAIL_ATTR_GETATTRIBUTE_BUILTIN 28 +#define SPEC_FAIL_ATTR_NOT_HEAP_TYPE 29 /* Binary subscr and store subscr */ @@ -479,6 +481,8 @@ miss_counter_start(void) { #define SPEC_FAIL_UNPACK_SEQUENCE_ITERATOR 8 #define SPEC_FAIL_UNPACK_SEQUENCE_SEQUENCE 9 +static int function_kind(PyCodeObject *code); +static uint32_t maybe_function_get_version(PyObject *o, int expected_argcount, int opcode); static int specialize_module_load_attr(PyObject *owner, _Py_CODEUNIT *instr, @@ -521,6 +525,75 @@ specialize_module_load_attr(PyObject *owner, _Py_CODEUNIT *instr, return 0; } +static int +specialize_custom_getattribute(PyTypeObject *type, _Py_CODEUNIT *instr, + unsigned int tp_version_tag) +{ + if (type->tp_getattr != NULL && type->tp_getattro == NULL) { + goto fail; + } + getattrofunc getattro_slot = type->tp_getattro; + /* The following comment is copied from typeobject.c */ + /* There are two slot dispatch functions for tp_getattro. + + - _Py_slot_tp_getattro() is used when __getattribute__ is overridden + but no __getattr__ hook is present; + + - _Py_slot_tp_getattr_hook() is used when a __getattr__ hook is present. + + The code in update_one_slot() always installs + _Py_slot_tp_getattr_hook(); this detects the absence of + __getattr__ and then installs the simpler slot if necessary. */ + if (getattro_slot != _Py_slot_tp_getattro && + getattro_slot != _Py_slot_tp_getattr_hook) { + /* E.g. the custom getattro for super() objects */ + SPECIALIZATION_FAIL(LOAD_ATTR, SPEC_FAIL_ATTR_GETATTRIBUTE_BUILTIN); + goto fail; + } + if (!(type->tp_flags & Py_TPFLAGS_HEAPTYPE)) { + SPECIALIZATION_FAIL(LOAD_ATTR, SPEC_FAIL_ATTR_NOT_HEAP_TYPE); + goto fail; + } + _PyLoadMethodCache *lm_cache = (_PyLoadMethodCache *)(instr + 1); + PyObject *getattr = _PyType_Lookup(type, &_Py_ID(__getattr__)); + if (getattr == NULL && getattro_slot != _Py_slot_tp_getattro) { + /* According to typeobject rules, if getattr is NULL, + getattro_slot should be _Py_slot_tp_getattro */ + goto fail; + } + PyObject *getattribute = _PyType_Lookup(type, + &_Py_ID(__getattribute__)); + /* Whether to call PyObject_GenericGetAttr or getattribute + at runtime */ + bool custom_getattribute = !(getattribute == NULL || + (Py_IS_TYPE(getattribute, &PyWrapperDescr_Type) && + ((PyWrapperDescrObject *)getattribute)->d_wrapped == + (void *)PyObject_GenericGetAttr)); + + if (getattr || getattribute) { + PyHeapTypeObject *ht = (PyHeapTypeObject *)type; + /* borrowed */ + ht->_spec_cache.getattribute = custom_getattribute ? + getattribute : NULL; + + uint32_t func_version = 0; + if (getattr) { + func_version = maybe_function_get_version(getattr, 2, LOAD_ATTR); + } + /* func_version == 0 is OK if there's no __getattr__*/ + write_u32(lm_cache->keys_version, func_version); + /* borrowed */ + ((PyHeapTypeObject *)type)->_spec_cache.getattr = func_version ? getattr : NULL; + assert(tp_version_tag != 0); + write_u32(lm_cache->type_version, tp_version_tag); + _Py_SET_OPCODE(*instr, func_version ? LOAD_ATTR_GETATTRIBUTE_GETATTR_PY_OVERRIDDEN : LOAD_ATTR_GETATTRIBUTE_GETATTR_OVERRIDDEN); + goto success; + } +fail: + return 1; +success: + return 0; +} /* Attribute specialization */ @@ -655,7 +728,6 @@ specialize_dict_access( static int specialize_attr_loadmethod(PyObject* owner, _Py_CODEUNIT* instr, PyObject* name, PyObject* descr, DescriptorClassification kind); static int specialize_class_load_attr(PyObject* owner, _Py_CODEUNIT* instr, PyObject* name); -static int function_kind(PyCodeObject *code); int _Py_Specialize_LoadAttr(PyObject *owner, _Py_CODEUNIT *instr, PyObject *name) @@ -710,24 +782,9 @@ _Py_Specialize_LoadAttr(PyObject *owner, _Py_CODEUNIT *instr, PyObject *name) SPECIALIZATION_FAIL(LOAD_ATTR, SPEC_FAIL_EXPECTED_ERROR); goto fail; } - if (Py_TYPE(fget) != &PyFunction_Type) { - SPECIALIZATION_FAIL(LOAD_ATTR, SPEC_FAIL_ATTR_PROPERTY); - goto fail; - } - PyFunctionObject *func = (PyFunctionObject *)fget; - PyCodeObject *fcode = (PyCodeObject *)func->func_code; - int kind = function_kind(fcode); - if (kind != SIMPLE_FUNCTION) { - SPECIALIZATION_FAIL(LOAD_ATTR, kind); - goto fail; - } - if (fcode->co_argcount != 1) { - SPECIALIZATION_FAIL(LOAD_ATTR, SPEC_FAIL_WRONG_NUMBER_ARGUMENTS); - goto fail; - } - int version = _PyFunction_GetVersionForCurrentState(func); + uint32_t version = maybe_function_get_version(fget, + 1, LOAD_ATTR); if (version == 0) { - SPECIALIZATION_FAIL(LOAD_ATTR, SPEC_FAIL_OUT_OF_VERSIONS); goto fail; } write_u32(lm_cache->keys_version, version); @@ -774,8 +831,14 @@ _Py_Specialize_LoadAttr(PyObject *owner, _Py_CODEUNIT *instr, PyObject *name) SPECIALIZATION_FAIL(LOAD_ATTR, SPEC_FAIL_ATTR_MUTABLE_CLASS); goto fail; case GETSET_OVERRIDDEN: - SPECIALIZATION_FAIL(LOAD_ATTR, SPEC_FAIL_OVERRIDDEN); - goto fail; + { + int err = specialize_custom_getattribute(type, instr, + type->tp_version_tag); + if (err) { + goto fail; + } + goto success; + } case BUILTIN_CLASSMETHOD: case PYTHON_CLASSMETHOD: case NON_OVERRIDING: @@ -1197,6 +1260,34 @@ function_kind(PyCodeObject *code) { return SIMPLE_FUNCTION; } +static uint32_t +maybe_function_get_version(PyObject *o, int expected_argcount, int opcode) +{ + uint32_t version = 0; + if (!Py_IS_TYPE(o, &PyFunction_Type)) { + goto fail; + } + PyFunctionObject *func = (PyFunctionObject *)o; + PyCodeObject *fcode = (PyCodeObject *)func->func_code; + int kind = function_kind(fcode); + if (kind != SIMPLE_FUNCTION) { + SPECIALIZATION_FAIL(opcode, kind); + goto fail; + } + if (fcode->co_argcount != expected_argcount) { + SPECIALIZATION_FAIL(opcode, SPEC_FAIL_WRONG_NUMBER_ARGUMENTS); + goto fail; + } + version = _PyFunction_GetVersionForCurrentState(func); + if (version == 0) { + SPECIALIZATION_FAIL(opcode, SPEC_FAIL_OUT_OF_VERSIONS); + goto fail; + } + return version; +fail: + return 0; +} + int _Py_Specialize_BinarySubscr( PyObject *container, PyObject *sub, _Py_CODEUNIT *instr) From de5aab9f50e3b3f1b7cfae20efa8596aee8f4b63 Mon Sep 17 00:00:00 2001 From: Ken Jin Date: Sun, 19 Jun 2022 00:58:31 +0800 Subject: [PATCH 02/17] fix up comments --- Python/ceval.c | 2 ++ Python/specialize.c | 3 ++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/Python/ceval.c b/Python/ceval.c index de860c05c3ca1b..8844e40db8dbe6 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -3718,6 +3718,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int STACK_GROW((oparg & 1)); SET_TOP(res); Py_DECREF(owner); + JUMPBY(INLINE_CACHE_ENTRIES_LOAD_ATTR); DISPATCH(); } @@ -3742,6 +3743,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int PyObject *name = GETITEM(names, oparg >> 1); PyObject *getattribute = ((PyHeapTypeObject *)cls)->_spec_cache.getattribute; + /* Possible todo: inlining this call frame? */ PyObject *res = getattribute ? _Py_call_attribute(owner, getattribute, name) : PyObject_GenericGetAttr(owner, name); diff --git a/Python/specialize.c b/Python/specialize.c index 208242df21ac75..67d7cc72777732 100644 --- a/Python/specialize.c +++ b/Python/specialize.c @@ -580,7 +580,8 @@ specialize_custom_getattribute(PyTypeObject *type, _Py_CODEUNIT *instr, if (getattr) { func_version = maybe_function_get_version(getattr, 2, LOAD_ATTR); } - /* func_version == 0 is OK if there's no __getattr__*/ + /* func_version == 0 is OK if there's no __getattr__ + or __getattr__ isn't a Python function*/ write_u32(lm_cache->keys_version, func_version); /* borrowed */ ((PyHeapTypeObject *)type)->_spec_cache.getattr = func_version ? getattr : NULL; From a79560281eab0615ecd96948905e8519f7358c55 Mon Sep 17 00:00:00 2001 From: "blurb-it[bot]" <43283697+blurb-it[bot]@users.noreply.github.com> Date: Sat, 18 Jun 2022 17:00:34 +0000 Subject: [PATCH 03/17] =?UTF-8?q?=F0=9F=93=9C=F0=9F=A4=96=20Added=20by=20b?= =?UTF-8?q?lurb=5Fit.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../2022-06-18-17-00-33.gh-issue-93911.y286of.rst | 1 + 1 file changed, 1 insertion(+) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2022-06-18-17-00-33.gh-issue-93911.y286of.rst diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-06-18-17-00-33.gh-issue-93911.y286of.rst b/Misc/NEWS.d/next/Core and Builtins/2022-06-18-17-00-33.gh-issue-93911.y286of.rst new file mode 100644 index 00000000000000..e899b1dd0a40e9 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2022-06-18-17-00-33.gh-issue-93911.y286of.rst @@ -0,0 +1 @@ +Specialize ``LOAD_ATTR`` for objects with custom ``__getattr__`` and ``__getattribute__``. Patch by Ken Jin. From b1702049a984ee925414af45b8e4f095115ee24c Mon Sep 17 00:00:00 2001 From: Ken Jin Date: Sun, 19 Jun 2022 01:15:58 +0800 Subject: [PATCH 04/17] fix version tag issues --- Python/specialize.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Python/specialize.c b/Python/specialize.c index 67d7cc72777732..e11e3f1717fe40 100644 --- a/Python/specialize.c +++ b/Python/specialize.c @@ -585,8 +585,8 @@ specialize_custom_getattribute(PyTypeObject *type, _Py_CODEUNIT *instr, write_u32(lm_cache->keys_version, func_version); /* borrowed */ ((PyHeapTypeObject *)type)->_spec_cache.getattr = func_version ? getattr : NULL; - assert(tp_version_tag != 0); - write_u32(lm_cache->type_version, tp_version_tag); + assert(type->tp_version_tag != 0); + write_u32(lm_cache->type_version, type->tp_version_tag); _Py_SET_OPCODE(*instr, func_version ? LOAD_ATTR_GETATTRIBUTE_GETATTR_PY_OVERRIDDEN : LOAD_ATTR_GETATTRIBUTE_GETATTR_OVERRIDDEN); goto success; } From b4df543e2779eedd6b756b4de09756cce3b04e1e Mon Sep 17 00:00:00 2001 From: Ken Jin Date: Sun, 19 Jun 2022 01:31:39 +0800 Subject: [PATCH 05/17] update specialization failure name --- Python/specialize.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Python/specialize.c b/Python/specialize.c index e11e3f1717fe40..89a0e22a218170 100644 --- a/Python/specialize.c +++ b/Python/specialize.c @@ -368,7 +368,7 @@ miss_counter_start(void) { #define SPEC_FAIL_ATTR_HAS_MANAGED_DICT 25 #define SPEC_FAIL_ATTR_INSTANCE_ATTRIBUTE 26 #define SPEC_FAIL_ATTR_METACLASS_ATTRIBUTE 27 -#define SPEC_FAIL_ATTR_GETATTRIBUTE_BUILTIN 28 +#define SPEC_FAIL_ATTR_CUSTOM_GETATTRO 28 #define SPEC_FAIL_ATTR_NOT_HEAP_TYPE 29 /* Binary subscr and store subscr */ @@ -547,7 +547,7 @@ specialize_custom_getattribute(PyTypeObject *type, _Py_CODEUNIT *instr, if (getattro_slot != _Py_slot_tp_getattro && getattro_slot != _Py_slot_tp_getattr_hook) { /* E.g. the custom getattro for super() objects */ - SPECIALIZATION_FAIL(LOAD_ATTR, SPEC_FAIL_ATTR_GETATTRIBUTE_BUILTIN); + SPECIALIZATION_FAIL(LOAD_ATTR, SPEC_FAIL_ATTR_CUSTOM_GETATTRO); goto fail; } if (!(type->tp_flags & Py_TPFLAGS_HEAPTYPE)) { From cd81fa96402ffa54df3189ff16b28a0bd26b9c8b Mon Sep 17 00:00:00 2001 From: Ken Jin Date: Sun, 19 Jun 2022 02:58:53 +0800 Subject: [PATCH 06/17] fix getattr bug --- Python/specialize.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Python/specialize.c b/Python/specialize.c index 89a0e22a218170..039f17d92efc3d 100644 --- a/Python/specialize.c +++ b/Python/specialize.c @@ -584,7 +584,7 @@ specialize_custom_getattribute(PyTypeObject *type, _Py_CODEUNIT *instr, or __getattr__ isn't a Python function*/ write_u32(lm_cache->keys_version, func_version); /* borrowed */ - ((PyHeapTypeObject *)type)->_spec_cache.getattr = func_version ? getattr : NULL; + ((PyHeapTypeObject *)type)->_spec_cache.getattr = getattr; assert(type->tp_version_tag != 0); write_u32(lm_cache->type_version, type->tp_version_tag); _Py_SET_OPCODE(*instr, func_version ? LOAD_ATTR_GETATTRIBUTE_GETATTR_PY_OVERRIDDEN : LOAD_ATTR_GETATTRIBUTE_GETATTR_OVERRIDDEN); From a2b01210f5b11d6f8e920576c4511f2f10b56660 Mon Sep 17 00:00:00 2001 From: Ken Jin Date: Sun, 19 Jun 2022 03:45:50 +0800 Subject: [PATCH 07/17] Fix type size in test_sys --- Lib/test/test_sys.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Lib/test/test_sys.py b/Lib/test/test_sys.py index 1dc10d8b0a39ac..6c55624d481865 100644 --- a/Lib/test/test_sys.py +++ b/Lib/test/test_sys.py @@ -1518,7 +1518,7 @@ def delx(self): del self.__x '10P' # PySequenceMethods '2P' # PyBufferProcs '6P' - '1P' # Specializer cache + '3P' # Specializer cache ) class newstyleclass(object): pass # Separate block for PyDictKeysObject with 8 keys and 5 entries From 2a931a8faad07375af647f5ed0e8d3548bcb3d37 Mon Sep 17 00:00:00 2001 From: Ken Jin <28750310+Fidget-Spinner@users.noreply.github.com> Date: Mon, 27 Jun 2022 15:46:41 +0800 Subject: [PATCH 08/17] Use Mark's suggestions --- Include/cpython/object.h | 2 - Include/internal/pycore_opcode.h | 767 ++++++++++++++++++ Include/opcode.h | 237 ++++++ Lib/opcode.py | 3 +- ...2-06-18-17-00-33.gh-issue-93911.y286of.rst | 2 +- Python/ceval.c | 64 +- Python/opcode_targets.h | 258 ++++++ Python/specialize.c | 143 ++-- 8 files changed, 1335 insertions(+), 141 deletions(-) diff --git a/Include/cpython/object.h b/Include/cpython/object.h index dff238bbfcce0a..614d6c18ee0b4a 100644 --- a/Include/cpython/object.h +++ b/Include/cpython/object.h @@ -234,8 +234,6 @@ struct _typeobject { * by code other than the specializer and interpreter. */ struct _specialization_cache { PyObject *getitem; - PyObject *getattribute; - PyObject *getattr; }; /* The *real* layout of a type object when allocated on the heap */ diff --git a/Include/internal/pycore_opcode.h b/Include/internal/pycore_opcode.h index e69de29bb2d1d6..b4cc9ba02bf520 100644 --- a/Include/internal/pycore_opcode.h +++ b/Include/internal/pycore_opcode.h @@ -0,0 +1,767 @@ +// Auto-generated by Tools/scripts/generate_opcode_h.py from Lib/opcode.py + +#ifndef Py_INTERNAL_OPCODE_H +#define Py_INTERNAL_OPCODE_H +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef Py_BUILD_CORE +# error "this header requires Py_BUILD_CORE define" +#endif + +#include "opcode.h" + +extern const uint8_t _PyOpcode_Caches[256]; + +extern const uint8_t _PyOpcode_Deopt[256]; + +extern const uint8_t _PyOpcode_Original[256]; + +#ifdef NEED_OPCODE_TABLES +static const uint32_t _PyOpcode_RelativeJump[8] = { + 0U, + 0U, + 536870912U, + 135118848U, + 4163U, + 122880U, + 0U, + 0U, +}; +static const uint32_t _PyOpcode_Jump[8] = { + 0U, + 0U, + 536870912U, + 135118848U, + 4163U, + 122880U, + 0U, + 0U, +}; + +const uint8_t _PyOpcode_Caches[256] = { + [BINARY_SUBSCR] = 4, + [STORE_SUBSCR] = 1, + [UNPACK_SEQUENCE] = 1, + [FOR_ITER] = 1, + [STORE_ATTR] = 4, + [LOAD_ATTR] = 9, + [COMPARE_OP] = 2, + [LOAD_GLOBAL] = 5, + [BINARY_OP] = 1, + [CALL] = 4, +}; + +const uint8_t _PyOpcode_Deopt[256] = { + [ASYNC_GEN_WRAP] = ASYNC_GEN_WRAP, + [BEFORE_ASYNC_WITH] = BEFORE_ASYNC_WITH, + [BEFORE_WITH] = BEFORE_WITH, + [BINARY_OP] = BINARY_OP, + [BINARY_OP_ADAPTIVE] = BINARY_OP, + [BINARY_OP_ADD_FLOAT] = BINARY_OP, + [BINARY_OP_ADD_INT] = BINARY_OP, + [BINARY_OP_ADD_UNICODE] = BINARY_OP, + [BINARY_OP_INPLACE_ADD_UNICODE] = BINARY_OP, + [BINARY_OP_MULTIPLY_FLOAT] = BINARY_OP, + [BINARY_OP_MULTIPLY_INT] = BINARY_OP, + [BINARY_OP_SUBTRACT_FLOAT] = BINARY_OP, + [BINARY_OP_SUBTRACT_INT] = BINARY_OP, + [BINARY_SUBSCR] = BINARY_SUBSCR, + [BINARY_SUBSCR_ADAPTIVE] = BINARY_SUBSCR, + [BINARY_SUBSCR_DICT] = BINARY_SUBSCR, + [BINARY_SUBSCR_GETITEM] = BINARY_SUBSCR, + [BINARY_SUBSCR_LIST_INT] = BINARY_SUBSCR, + [BINARY_SUBSCR_TUPLE_INT] = BINARY_SUBSCR, + [BUILD_CONST_KEY_MAP] = BUILD_CONST_KEY_MAP, + [BUILD_LIST] = BUILD_LIST, + [BUILD_MAP] = BUILD_MAP, + [BUILD_SET] = BUILD_SET, + [BUILD_SLICE] = BUILD_SLICE, + [BUILD_STRING] = BUILD_STRING, + [BUILD_TUPLE] = BUILD_TUPLE, + [CACHE] = CACHE, + [CALL] = CALL, + [CALL_ADAPTIVE] = CALL, + [CALL_BOUND_METHOD_EXACT_ARGS] = CALL, + [CALL_BUILTIN_CLASS] = CALL, + [CALL_BUILTIN_FAST_WITH_KEYWORDS] = CALL, + [CALL_FUNCTION_EX] = CALL_FUNCTION_EX, + [CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS] = CALL, + [CALL_NO_KW_BUILTIN_FAST] = CALL, + [CALL_NO_KW_BUILTIN_O] = CALL, + [CALL_NO_KW_ISINSTANCE] = CALL, + [CALL_NO_KW_LEN] = CALL, + [CALL_NO_KW_LIST_APPEND] = CALL, + [CALL_NO_KW_METHOD_DESCRIPTOR_FAST] = CALL, + [CALL_NO_KW_METHOD_DESCRIPTOR_NOARGS] = CALL, + [CALL_NO_KW_METHOD_DESCRIPTOR_O] = CALL, + [CALL_NO_KW_STR_1] = CALL, + [CALL_NO_KW_TUPLE_1] = CALL, + [CALL_NO_KW_TYPE_1] = CALL, + [CALL_PY_EXACT_ARGS] = CALL, + [CALL_PY_WITH_DEFAULTS] = CALL, + [CHECK_EG_MATCH] = CHECK_EG_MATCH, + [CHECK_EXC_MATCH] = CHECK_EXC_MATCH, + [COMPARE_OP] = COMPARE_OP, + [COMPARE_OP_ADAPTIVE] = COMPARE_OP, + [COMPARE_OP_FLOAT_JUMP] = COMPARE_OP, + [COMPARE_OP_INT_JUMP] = COMPARE_OP, + [COMPARE_OP_STR_JUMP] = COMPARE_OP, + [CONTAINS_OP] = CONTAINS_OP, + [COPY] = COPY, + [COPY_FREE_VARS] = COPY_FREE_VARS, + [DELETE_ATTR] = DELETE_ATTR, + [DELETE_DEREF] = DELETE_DEREF, + [DELETE_FAST] = DELETE_FAST, + [DELETE_GLOBAL] = DELETE_GLOBAL, + [DELETE_NAME] = DELETE_NAME, + [DELETE_SUBSCR] = DELETE_SUBSCR, + [DICT_MERGE] = DICT_MERGE, + [DICT_UPDATE] = DICT_UPDATE, + [END_ASYNC_FOR] = END_ASYNC_FOR, + [EXTENDED_ARG] = EXTENDED_ARG, + [EXTENDED_ARG_QUICK] = EXTENDED_ARG, + [FORMAT_VALUE] = FORMAT_VALUE, + [FOR_ITER] = FOR_ITER, + [FOR_ITER_ADAPTIVE] = FOR_ITER, + [FOR_ITER_LIST] = FOR_ITER, + [FOR_ITER_RANGE] = FOR_ITER, + [GET_AITER] = GET_AITER, + [GET_ANEXT] = GET_ANEXT, + [GET_AWAITABLE] = GET_AWAITABLE, + [GET_ITER] = GET_ITER, + [GET_LEN] = GET_LEN, + [GET_YIELD_FROM_ITER] = GET_YIELD_FROM_ITER, + [IMPORT_FROM] = IMPORT_FROM, + [IMPORT_NAME] = IMPORT_NAME, + [IMPORT_STAR] = IMPORT_STAR, + [IS_OP] = IS_OP, + [JUMP_BACKWARD] = JUMP_BACKWARD, + [JUMP_BACKWARD_NO_INTERRUPT] = JUMP_BACKWARD_NO_INTERRUPT, + [JUMP_BACKWARD_QUICK] = JUMP_BACKWARD, + [JUMP_FORWARD] = JUMP_FORWARD, + [JUMP_IF_FALSE_OR_POP] = JUMP_IF_FALSE_OR_POP, + [JUMP_IF_TRUE_OR_POP] = JUMP_IF_TRUE_OR_POP, + [KW_NAMES] = KW_NAMES, + [LIST_APPEND] = LIST_APPEND, + [LIST_EXTEND] = LIST_EXTEND, + [LIST_TO_TUPLE] = LIST_TO_TUPLE, + [LOAD_ASSERTION_ERROR] = LOAD_ASSERTION_ERROR, + [LOAD_ATTR] = LOAD_ATTR, + [LOAD_ATTR_ADAPTIVE] = LOAD_ATTR, + [LOAD_ATTR_CLASS] = LOAD_ATTR, + [LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN] = LOAD_ATTR, + [LOAD_ATTR_INSTANCE_VALUE] = LOAD_ATTR, + [LOAD_ATTR_METHOD_LAZY_DICT] = LOAD_ATTR, + [LOAD_ATTR_METHOD_NO_DICT] = LOAD_ATTR, + [LOAD_ATTR_METHOD_WITH_DICT] = LOAD_ATTR, + [LOAD_ATTR_METHOD_WITH_VALUES] = LOAD_ATTR, + [LOAD_ATTR_MODULE] = LOAD_ATTR, + [LOAD_ATTR_PROPERTY] = LOAD_ATTR, + [LOAD_ATTR_SLOT] = LOAD_ATTR, + [LOAD_ATTR_WITH_HINT] = LOAD_ATTR, + [LOAD_BUILD_CLASS] = LOAD_BUILD_CLASS, + [LOAD_CLASSDEREF] = LOAD_CLASSDEREF, + [LOAD_CLOSURE] = LOAD_CLOSURE, + [LOAD_CONST] = LOAD_CONST, + [LOAD_CONST__LOAD_FAST] = LOAD_CONST, + [LOAD_DEREF] = LOAD_DEREF, + [LOAD_FAST] = LOAD_FAST, + [LOAD_FAST_CHECK] = LOAD_FAST_CHECK, + [LOAD_FAST__LOAD_CONST] = LOAD_FAST, + [LOAD_FAST__LOAD_FAST] = LOAD_FAST, + [LOAD_GLOBAL] = LOAD_GLOBAL, + [LOAD_GLOBAL_ADAPTIVE] = LOAD_GLOBAL, + [LOAD_GLOBAL_BUILTIN] = LOAD_GLOBAL, + [LOAD_GLOBAL_MODULE] = LOAD_GLOBAL, + [LOAD_NAME] = LOAD_NAME, + [MAKE_CELL] = MAKE_CELL, + [MAKE_FUNCTION] = MAKE_FUNCTION, + [MAP_ADD] = MAP_ADD, + [MATCH_CLASS] = MATCH_CLASS, + [MATCH_KEYS] = MATCH_KEYS, + [MATCH_MAPPING] = MATCH_MAPPING, + [MATCH_SEQUENCE] = MATCH_SEQUENCE, + [NOP] = NOP, + [POP_EXCEPT] = POP_EXCEPT, + [POP_JUMP_BACKWARD_IF_FALSE] = POP_JUMP_BACKWARD_IF_FALSE, + [POP_JUMP_BACKWARD_IF_NONE] = POP_JUMP_BACKWARD_IF_NONE, + [POP_JUMP_BACKWARD_IF_NOT_NONE] = POP_JUMP_BACKWARD_IF_NOT_NONE, + [POP_JUMP_BACKWARD_IF_TRUE] = POP_JUMP_BACKWARD_IF_TRUE, + [POP_JUMP_FORWARD_IF_FALSE] = POP_JUMP_FORWARD_IF_FALSE, + [POP_JUMP_FORWARD_IF_NONE] = POP_JUMP_FORWARD_IF_NONE, + [POP_JUMP_FORWARD_IF_NOT_NONE] = POP_JUMP_FORWARD_IF_NOT_NONE, + [POP_JUMP_FORWARD_IF_TRUE] = POP_JUMP_FORWARD_IF_TRUE, + [POP_TOP] = POP_TOP, + [PREP_RERAISE_STAR] = PREP_RERAISE_STAR, + [PRINT_EXPR] = PRINT_EXPR, + [PUSH_EXC_INFO] = PUSH_EXC_INFO, + [PUSH_NULL] = PUSH_NULL, + [RAISE_VARARGS] = RAISE_VARARGS, + [RERAISE] = RERAISE, + [RESUME] = RESUME, + [RESUME_QUICK] = RESUME, + [RETURN_GENERATOR] = RETURN_GENERATOR, + [RETURN_VALUE] = RETURN_VALUE, + [SEND] = SEND, + [SETUP_ANNOTATIONS] = SETUP_ANNOTATIONS, + [SET_ADD] = SET_ADD, + [SET_UPDATE] = SET_UPDATE, + [STORE_ATTR] = STORE_ATTR, + [STORE_ATTR_ADAPTIVE] = STORE_ATTR, + [STORE_ATTR_INSTANCE_VALUE] = STORE_ATTR, + [STORE_ATTR_SLOT] = STORE_ATTR, + [STORE_ATTR_WITH_HINT] = STORE_ATTR, + [STORE_DEREF] = STORE_DEREF, + [STORE_FAST] = STORE_FAST, + [STORE_FAST__LOAD_FAST] = STORE_FAST, + [STORE_FAST__STORE_FAST] = STORE_FAST, + [STORE_GLOBAL] = STORE_GLOBAL, + [STORE_NAME] = STORE_NAME, + [STORE_SUBSCR] = STORE_SUBSCR, + [STORE_SUBSCR_ADAPTIVE] = STORE_SUBSCR, + [STORE_SUBSCR_DICT] = STORE_SUBSCR, + [STORE_SUBSCR_LIST_INT] = STORE_SUBSCR, + [SWAP] = SWAP, + [UNARY_INVERT] = UNARY_INVERT, + [UNARY_NEGATIVE] = UNARY_NEGATIVE, + [UNARY_NOT] = UNARY_NOT, + [UNARY_POSITIVE] = UNARY_POSITIVE, + [UNPACK_EX] = UNPACK_EX, + [UNPACK_SEQUENCE] = UNPACK_SEQUENCE, + [UNPACK_SEQUENCE_ADAPTIVE] = UNPACK_SEQUENCE, + [UNPACK_SEQUENCE_LIST] = UNPACK_SEQUENCE, + [UNPACK_SEQUENCE_TUPLE] = UNPACK_SEQUENCE, + [UNPACK_SEQUENCE_TWO_TUPLE] = UNPACK_SEQUENCE, + [WITH_EXCEPT_START] = WITH_EXCEPT_START, + [YIELD_VALUE] = YIELD_VALUE, +}; + +const uint8_t _PyOpcode_Original[256] = { + [ASYNC_GEN_WRAP] = ASYNC_GEN_WRAP, + [BEFORE_ASYNC_WITH] = BEFORE_ASYNC_WITH, + [BEFORE_WITH] = BEFORE_WITH, + [BINARY_OP] = BINARY_OP, + [BINARY_OP_ADAPTIVE] = BINARY_OP, + [BINARY_OP_ADD_FLOAT] = BINARY_OP, + [BINARY_OP_ADD_INT] = BINARY_OP, + [BINARY_OP_ADD_UNICODE] = BINARY_OP, + [BINARY_OP_INPLACE_ADD_UNICODE] = BINARY_OP, + [BINARY_OP_MULTIPLY_FLOAT] = BINARY_OP, + [BINARY_OP_MULTIPLY_INT] = BINARY_OP, + [BINARY_OP_SUBTRACT_FLOAT] = BINARY_OP, + [BINARY_OP_SUBTRACT_INT] = BINARY_OP, + [BINARY_SUBSCR] = BINARY_SUBSCR, + [BINARY_SUBSCR_ADAPTIVE] = BINARY_SUBSCR, + [BINARY_SUBSCR_DICT] = BINARY_SUBSCR, + [BINARY_SUBSCR_GETITEM] = BINARY_SUBSCR, + [BINARY_SUBSCR_LIST_INT] = BINARY_SUBSCR, + [BINARY_SUBSCR_TUPLE_INT] = BINARY_SUBSCR, + [BUILD_CONST_KEY_MAP] = BUILD_CONST_KEY_MAP, + [BUILD_LIST] = BUILD_LIST, + [BUILD_MAP] = BUILD_MAP, + [BUILD_SET] = BUILD_SET, + [BUILD_SLICE] = BUILD_SLICE, + [BUILD_STRING] = BUILD_STRING, + [BUILD_TUPLE] = BUILD_TUPLE, + [CACHE] = CACHE, + [CALL] = CALL, + [CALL_ADAPTIVE] = CALL, + [CALL_BOUND_METHOD_EXACT_ARGS] = CALL, + [CALL_BUILTIN_CLASS] = CALL, + [CALL_BUILTIN_FAST_WITH_KEYWORDS] = CALL, + [CALL_FUNCTION_EX] = CALL_FUNCTION_EX, + [CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS] = CALL, + [CALL_NO_KW_BUILTIN_FAST] = CALL, + [CALL_NO_KW_BUILTIN_O] = CALL, + [CALL_NO_KW_ISINSTANCE] = CALL, + [CALL_NO_KW_LEN] = CALL, + [CALL_NO_KW_LIST_APPEND] = CALL, + [CALL_NO_KW_METHOD_DESCRIPTOR_FAST] = CALL, + [CALL_NO_KW_METHOD_DESCRIPTOR_NOARGS] = CALL, + [CALL_NO_KW_METHOD_DESCRIPTOR_O] = CALL, + [CALL_NO_KW_STR_1] = CALL, + [CALL_NO_KW_TUPLE_1] = CALL, + [CALL_NO_KW_TYPE_1] = CALL, + [CALL_PY_EXACT_ARGS] = CALL, + [CALL_PY_WITH_DEFAULTS] = CALL, + [CHECK_EG_MATCH] = CHECK_EG_MATCH, + [CHECK_EXC_MATCH] = CHECK_EXC_MATCH, + [COMPARE_OP] = COMPARE_OP, + [COMPARE_OP_ADAPTIVE] = COMPARE_OP, + [COMPARE_OP_FLOAT_JUMP] = COMPARE_OP, + [COMPARE_OP_INT_JUMP] = COMPARE_OP, + [COMPARE_OP_STR_JUMP] = COMPARE_OP, + [CONTAINS_OP] = CONTAINS_OP, + [COPY] = COPY, + [COPY_FREE_VARS] = COPY_FREE_VARS, + [DELETE_ATTR] = DELETE_ATTR, + [DELETE_DEREF] = DELETE_DEREF, + [DELETE_FAST] = DELETE_FAST, + [DELETE_GLOBAL] = DELETE_GLOBAL, + [DELETE_NAME] = DELETE_NAME, + [DELETE_SUBSCR] = DELETE_SUBSCR, + [DICT_MERGE] = DICT_MERGE, + [DICT_UPDATE] = DICT_UPDATE, + [END_ASYNC_FOR] = END_ASYNC_FOR, + [EXTENDED_ARG] = EXTENDED_ARG_QUICK, + [EXTENDED_ARG_QUICK] = EXTENDED_ARG_QUICK, + [FORMAT_VALUE] = FORMAT_VALUE, + [FOR_ITER] = FOR_ITER, + [FOR_ITER_ADAPTIVE] = FOR_ITER, + [FOR_ITER_LIST] = FOR_ITER, + [FOR_ITER_RANGE] = FOR_ITER, + [GET_AITER] = GET_AITER, + [GET_ANEXT] = GET_ANEXT, + [GET_AWAITABLE] = GET_AWAITABLE, + [GET_ITER] = GET_ITER, + [GET_LEN] = GET_LEN, + [GET_YIELD_FROM_ITER] = GET_YIELD_FROM_ITER, + [IMPORT_FROM] = IMPORT_FROM, + [IMPORT_NAME] = IMPORT_NAME, + [IMPORT_STAR] = IMPORT_STAR, + [IS_OP] = IS_OP, + [JUMP_BACKWARD] = JUMP_BACKWARD, + [JUMP_BACKWARD_NO_INTERRUPT] = JUMP_BACKWARD_NO_INTERRUPT, + [JUMP_BACKWARD_QUICK] = JUMP_BACKWARD, + [JUMP_FORWARD] = JUMP_FORWARD, + [JUMP_IF_FALSE_OR_POP] = JUMP_IF_FALSE_OR_POP, + [JUMP_IF_TRUE_OR_POP] = JUMP_IF_TRUE_OR_POP, + [KW_NAMES] = KW_NAMES, + [LIST_APPEND] = LIST_APPEND, + [LIST_EXTEND] = LIST_EXTEND, + [LIST_TO_TUPLE] = LIST_TO_TUPLE, + [LOAD_ASSERTION_ERROR] = LOAD_ASSERTION_ERROR, + [LOAD_ATTR] = LOAD_ATTR, + [LOAD_ATTR_ADAPTIVE] = LOAD_ATTR, + [LOAD_ATTR_CLASS] = LOAD_ATTR, + [LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN] = LOAD_ATTR, + [LOAD_ATTR_INSTANCE_VALUE] = LOAD_ATTR, + [LOAD_ATTR_METHOD_LAZY_DICT] = LOAD_ATTR, + [LOAD_ATTR_METHOD_NO_DICT] = LOAD_ATTR, + [LOAD_ATTR_METHOD_WITH_DICT] = LOAD_ATTR, + [LOAD_ATTR_METHOD_WITH_VALUES] = LOAD_ATTR, + [LOAD_ATTR_MODULE] = LOAD_ATTR, + [LOAD_ATTR_PROPERTY] = LOAD_ATTR, + [LOAD_ATTR_SLOT] = LOAD_ATTR, + [LOAD_ATTR_WITH_HINT] = LOAD_ATTR, + [LOAD_BUILD_CLASS] = LOAD_BUILD_CLASS, + [LOAD_CLASSDEREF] = LOAD_CLASSDEREF, + [LOAD_CLOSURE] = LOAD_CLOSURE, + [LOAD_CONST] = LOAD_CONST, + [LOAD_CONST__LOAD_FAST] = LOAD_CONST, + [LOAD_DEREF] = LOAD_DEREF, + [LOAD_FAST] = LOAD_FAST, + [LOAD_FAST_CHECK] = LOAD_FAST_CHECK, + [LOAD_FAST__LOAD_CONST] = LOAD_FAST, + [LOAD_FAST__LOAD_FAST] = LOAD_FAST, + [LOAD_GLOBAL] = LOAD_GLOBAL, + [LOAD_GLOBAL_ADAPTIVE] = LOAD_GLOBAL, + [LOAD_GLOBAL_BUILTIN] = LOAD_GLOBAL, + [LOAD_GLOBAL_MODULE] = LOAD_GLOBAL, + [LOAD_NAME] = LOAD_NAME, + [MAKE_CELL] = MAKE_CELL, + [MAKE_FUNCTION] = MAKE_FUNCTION, + [MAP_ADD] = MAP_ADD, + [MATCH_CLASS] = MATCH_CLASS, + [MATCH_KEYS] = MATCH_KEYS, + [MATCH_MAPPING] = MATCH_MAPPING, + [MATCH_SEQUENCE] = MATCH_SEQUENCE, + [NOP] = NOP, + [POP_EXCEPT] = POP_EXCEPT, + [POP_JUMP_BACKWARD_IF_FALSE] = POP_JUMP_BACKWARD_IF_FALSE, + [POP_JUMP_BACKWARD_IF_NONE] = POP_JUMP_BACKWARD_IF_NONE, + [POP_JUMP_BACKWARD_IF_NOT_NONE] = POP_JUMP_BACKWARD_IF_NOT_NONE, + [POP_JUMP_BACKWARD_IF_TRUE] = POP_JUMP_BACKWARD_IF_TRUE, + [POP_JUMP_FORWARD_IF_FALSE] = POP_JUMP_FORWARD_IF_FALSE, + [POP_JUMP_FORWARD_IF_NONE] = POP_JUMP_FORWARD_IF_NONE, + [POP_JUMP_FORWARD_IF_NOT_NONE] = POP_JUMP_FORWARD_IF_NOT_NONE, + [POP_JUMP_FORWARD_IF_TRUE] = POP_JUMP_FORWARD_IF_TRUE, + [POP_TOP] = POP_TOP, + [PREP_RERAISE_STAR] = PREP_RERAISE_STAR, + [PRINT_EXPR] = PRINT_EXPR, + [PUSH_EXC_INFO] = PUSH_EXC_INFO, + [PUSH_NULL] = PUSH_NULL, + [RAISE_VARARGS] = RAISE_VARARGS, + [RERAISE] = RERAISE, + [RESUME] = RESUME, + [RESUME_QUICK] = RESUME, + [RETURN_GENERATOR] = RETURN_GENERATOR, + [RETURN_VALUE] = RETURN_VALUE, + [SEND] = SEND, + [SETUP_ANNOTATIONS] = SETUP_ANNOTATIONS, + [SET_ADD] = SET_ADD, + [SET_UPDATE] = SET_UPDATE, + [STORE_ATTR] = STORE_ATTR, + [STORE_ATTR_ADAPTIVE] = STORE_ATTR, + [STORE_ATTR_INSTANCE_VALUE] = STORE_ATTR, + [STORE_ATTR_SLOT] = STORE_ATTR, + [STORE_ATTR_WITH_HINT] = STORE_ATTR, + [STORE_DEREF] = STORE_DEREF, + [STORE_FAST] = STORE_FAST, + [STORE_FAST__LOAD_FAST] = STORE_FAST, + [STORE_FAST__STORE_FAST] = STORE_FAST, + [STORE_GLOBAL] = STORE_GLOBAL, + [STORE_NAME] = STORE_NAME, + [STORE_SUBSCR] = STORE_SUBSCR, + [STORE_SUBSCR_ADAPTIVE] = STORE_SUBSCR, + [STORE_SUBSCR_DICT] = STORE_SUBSCR, + [STORE_SUBSCR_LIST_INT] = STORE_SUBSCR, + [SWAP] = SWAP, + [UNARY_INVERT] = UNARY_INVERT, + [UNARY_NEGATIVE] = UNARY_NEGATIVE, + [UNARY_NOT] = UNARY_NOT, + [UNARY_POSITIVE] = UNARY_POSITIVE, + [UNPACK_EX] = UNPACK_EX, + [UNPACK_SEQUENCE] = UNPACK_SEQUENCE, + [UNPACK_SEQUENCE_ADAPTIVE] = UNPACK_SEQUENCE, + [UNPACK_SEQUENCE_LIST] = UNPACK_SEQUENCE, + [UNPACK_SEQUENCE_TUPLE] = UNPACK_SEQUENCE, + [UNPACK_SEQUENCE_TWO_TUPLE] = UNPACK_SEQUENCE, + [WITH_EXCEPT_START] = WITH_EXCEPT_START, + [YIELD_VALUE] = YIELD_VALUE, +}; +#endif // NEED_OPCODE_TABLES + +#ifdef Py_DEBUG +static const char *const _PyOpcode_OpName[256] = { + [CACHE] = "CACHE", + [POP_TOP] = "POP_TOP", + [PUSH_NULL] = "PUSH_NULL", + [BINARY_OP_ADAPTIVE] = "BINARY_OP_ADAPTIVE", + [BINARY_OP_ADD_FLOAT] = "BINARY_OP_ADD_FLOAT", + [BINARY_OP_ADD_INT] = "BINARY_OP_ADD_INT", + [BINARY_OP_ADD_UNICODE] = "BINARY_OP_ADD_UNICODE", + [BINARY_OP_INPLACE_ADD_UNICODE] = "BINARY_OP_INPLACE_ADD_UNICODE", + [BINARY_OP_MULTIPLY_FLOAT] = "BINARY_OP_MULTIPLY_FLOAT", + [NOP] = "NOP", + [UNARY_POSITIVE] = "UNARY_POSITIVE", + [UNARY_NEGATIVE] = "UNARY_NEGATIVE", + [UNARY_NOT] = "UNARY_NOT", + [BINARY_OP_MULTIPLY_INT] = "BINARY_OP_MULTIPLY_INT", + [BINARY_OP_SUBTRACT_FLOAT] = "BINARY_OP_SUBTRACT_FLOAT", + [UNARY_INVERT] = "UNARY_INVERT", + [BINARY_OP_SUBTRACT_INT] = "BINARY_OP_SUBTRACT_INT", + [BINARY_SUBSCR_ADAPTIVE] = "BINARY_SUBSCR_ADAPTIVE", + [BINARY_SUBSCR_DICT] = "BINARY_SUBSCR_DICT", + [BINARY_SUBSCR_GETITEM] = "BINARY_SUBSCR_GETITEM", + [BINARY_SUBSCR_LIST_INT] = "BINARY_SUBSCR_LIST_INT", + [BINARY_SUBSCR_TUPLE_INT] = "BINARY_SUBSCR_TUPLE_INT", + [CALL_ADAPTIVE] = "CALL_ADAPTIVE", + [CALL_PY_EXACT_ARGS] = "CALL_PY_EXACT_ARGS", + [CALL_PY_WITH_DEFAULTS] = "CALL_PY_WITH_DEFAULTS", + [BINARY_SUBSCR] = "BINARY_SUBSCR", + [CALL_BOUND_METHOD_EXACT_ARGS] = "CALL_BOUND_METHOD_EXACT_ARGS", + [CALL_BUILTIN_CLASS] = "CALL_BUILTIN_CLASS", + [CALL_BUILTIN_FAST_WITH_KEYWORDS] = "CALL_BUILTIN_FAST_WITH_KEYWORDS", + [CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS] = "CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS", + [GET_LEN] = "GET_LEN", + [MATCH_MAPPING] = "MATCH_MAPPING", + [MATCH_SEQUENCE] = "MATCH_SEQUENCE", + [MATCH_KEYS] = "MATCH_KEYS", + [CALL_NO_KW_BUILTIN_FAST] = "CALL_NO_KW_BUILTIN_FAST", + [PUSH_EXC_INFO] = "PUSH_EXC_INFO", + [CHECK_EXC_MATCH] = "CHECK_EXC_MATCH", + [CHECK_EG_MATCH] = "CHECK_EG_MATCH", + [CALL_NO_KW_BUILTIN_O] = "CALL_NO_KW_BUILTIN_O", + [CALL_NO_KW_ISINSTANCE] = "CALL_NO_KW_ISINSTANCE", + [CALL_NO_KW_LEN] = "CALL_NO_KW_LEN", + [CALL_NO_KW_LIST_APPEND] = "CALL_NO_KW_LIST_APPEND", + [CALL_NO_KW_METHOD_DESCRIPTOR_FAST] = "CALL_NO_KW_METHOD_DESCRIPTOR_FAST", + [CALL_NO_KW_METHOD_DESCRIPTOR_NOARGS] = "CALL_NO_KW_METHOD_DESCRIPTOR_NOARGS", + [CALL_NO_KW_METHOD_DESCRIPTOR_O] = "CALL_NO_KW_METHOD_DESCRIPTOR_O", + [CALL_NO_KW_STR_1] = "CALL_NO_KW_STR_1", + [CALL_NO_KW_TUPLE_1] = "CALL_NO_KW_TUPLE_1", + [CALL_NO_KW_TYPE_1] = "CALL_NO_KW_TYPE_1", + [COMPARE_OP_ADAPTIVE] = "COMPARE_OP_ADAPTIVE", + [WITH_EXCEPT_START] = "WITH_EXCEPT_START", + [GET_AITER] = "GET_AITER", + [GET_ANEXT] = "GET_ANEXT", + [BEFORE_ASYNC_WITH] = "BEFORE_ASYNC_WITH", + [BEFORE_WITH] = "BEFORE_WITH", + [END_ASYNC_FOR] = "END_ASYNC_FOR", + [COMPARE_OP_FLOAT_JUMP] = "COMPARE_OP_FLOAT_JUMP", + [COMPARE_OP_INT_JUMP] = "COMPARE_OP_INT_JUMP", + [COMPARE_OP_STR_JUMP] = "COMPARE_OP_STR_JUMP", + [EXTENDED_ARG_QUICK] = "EXTENDED_ARG_QUICK", + [FOR_ITER_ADAPTIVE] = "FOR_ITER_ADAPTIVE", + [STORE_SUBSCR] = "STORE_SUBSCR", + [DELETE_SUBSCR] = "DELETE_SUBSCR", + [FOR_ITER_LIST] = "FOR_ITER_LIST", + [FOR_ITER_RANGE] = "FOR_ITER_RANGE", + [JUMP_BACKWARD_QUICK] = "JUMP_BACKWARD_QUICK", + [LOAD_ATTR_ADAPTIVE] = "LOAD_ATTR_ADAPTIVE", + [LOAD_ATTR_CLASS] = "LOAD_ATTR_CLASS", + [LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN] = "LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN", + [GET_ITER] = "GET_ITER", + [GET_YIELD_FROM_ITER] = "GET_YIELD_FROM_ITER", + [PRINT_EXPR] = "PRINT_EXPR", + [LOAD_BUILD_CLASS] = "LOAD_BUILD_CLASS", + [LOAD_ATTR_INSTANCE_VALUE] = "LOAD_ATTR_INSTANCE_VALUE", + [LOAD_ATTR_MODULE] = "LOAD_ATTR_MODULE", + [LOAD_ASSERTION_ERROR] = "LOAD_ASSERTION_ERROR", + [RETURN_GENERATOR] = "RETURN_GENERATOR", + [LOAD_ATTR_PROPERTY] = "LOAD_ATTR_PROPERTY", + [LOAD_ATTR_SLOT] = "LOAD_ATTR_SLOT", + [LOAD_ATTR_WITH_HINT] = "LOAD_ATTR_WITH_HINT", + [LOAD_ATTR_METHOD_LAZY_DICT] = "LOAD_ATTR_METHOD_LAZY_DICT", + [LOAD_ATTR_METHOD_NO_DICT] = "LOAD_ATTR_METHOD_NO_DICT", + [LOAD_ATTR_METHOD_WITH_DICT] = "LOAD_ATTR_METHOD_WITH_DICT", + [LIST_TO_TUPLE] = "LIST_TO_TUPLE", + [RETURN_VALUE] = "RETURN_VALUE", + [IMPORT_STAR] = "IMPORT_STAR", + [SETUP_ANNOTATIONS] = "SETUP_ANNOTATIONS", + [LOAD_ATTR_METHOD_WITH_VALUES] = "LOAD_ATTR_METHOD_WITH_VALUES", + [ASYNC_GEN_WRAP] = "ASYNC_GEN_WRAP", + [PREP_RERAISE_STAR] = "PREP_RERAISE_STAR", + [POP_EXCEPT] = "POP_EXCEPT", + [STORE_NAME] = "STORE_NAME", + [DELETE_NAME] = "DELETE_NAME", + [UNPACK_SEQUENCE] = "UNPACK_SEQUENCE", + [FOR_ITER] = "FOR_ITER", + [UNPACK_EX] = "UNPACK_EX", + [STORE_ATTR] = "STORE_ATTR", + [DELETE_ATTR] = "DELETE_ATTR", + [STORE_GLOBAL] = "STORE_GLOBAL", + [DELETE_GLOBAL] = "DELETE_GLOBAL", + [SWAP] = "SWAP", + [LOAD_CONST] = "LOAD_CONST", + [LOAD_NAME] = "LOAD_NAME", + [BUILD_TUPLE] = "BUILD_TUPLE", + [BUILD_LIST] = "BUILD_LIST", + [BUILD_SET] = "BUILD_SET", + [BUILD_MAP] = "BUILD_MAP", + [LOAD_ATTR] = "LOAD_ATTR", + [COMPARE_OP] = "COMPARE_OP", + [IMPORT_NAME] = "IMPORT_NAME", + [IMPORT_FROM] = "IMPORT_FROM", + [JUMP_FORWARD] = "JUMP_FORWARD", + [JUMP_IF_FALSE_OR_POP] = "JUMP_IF_FALSE_OR_POP", + [JUMP_IF_TRUE_OR_POP] = "JUMP_IF_TRUE_OR_POP", + [LOAD_CONST__LOAD_FAST] = "LOAD_CONST__LOAD_FAST", + [POP_JUMP_FORWARD_IF_FALSE] = "POP_JUMP_FORWARD_IF_FALSE", + [POP_JUMP_FORWARD_IF_TRUE] = "POP_JUMP_FORWARD_IF_TRUE", + [LOAD_GLOBAL] = "LOAD_GLOBAL", + [IS_OP] = "IS_OP", + [CONTAINS_OP] = "CONTAINS_OP", + [RERAISE] = "RERAISE", + [COPY] = "COPY", + [LOAD_FAST__LOAD_CONST] = "LOAD_FAST__LOAD_CONST", + [BINARY_OP] = "BINARY_OP", + [SEND] = "SEND", + [LOAD_FAST] = "LOAD_FAST", + [STORE_FAST] = "STORE_FAST", + [DELETE_FAST] = "DELETE_FAST", + [LOAD_FAST_CHECK] = "LOAD_FAST_CHECK", + [POP_JUMP_FORWARD_IF_NOT_NONE] = "POP_JUMP_FORWARD_IF_NOT_NONE", + [POP_JUMP_FORWARD_IF_NONE] = "POP_JUMP_FORWARD_IF_NONE", + [RAISE_VARARGS] = "RAISE_VARARGS", + [GET_AWAITABLE] = "GET_AWAITABLE", + [MAKE_FUNCTION] = "MAKE_FUNCTION", + [BUILD_SLICE] = "BUILD_SLICE", + [JUMP_BACKWARD_NO_INTERRUPT] = "JUMP_BACKWARD_NO_INTERRUPT", + [MAKE_CELL] = "MAKE_CELL", + [LOAD_CLOSURE] = "LOAD_CLOSURE", + [LOAD_DEREF] = "LOAD_DEREF", + [STORE_DEREF] = "STORE_DEREF", + [DELETE_DEREF] = "DELETE_DEREF", + [JUMP_BACKWARD] = "JUMP_BACKWARD", + [LOAD_FAST__LOAD_FAST] = "LOAD_FAST__LOAD_FAST", + [CALL_FUNCTION_EX] = "CALL_FUNCTION_EX", + [LOAD_GLOBAL_ADAPTIVE] = "LOAD_GLOBAL_ADAPTIVE", + [EXTENDED_ARG] = "EXTENDED_ARG", + [LIST_APPEND] = "LIST_APPEND", + [SET_ADD] = "SET_ADD", + [MAP_ADD] = "MAP_ADD", + [LOAD_CLASSDEREF] = "LOAD_CLASSDEREF", + [COPY_FREE_VARS] = "COPY_FREE_VARS", + [YIELD_VALUE] = "YIELD_VALUE", + [RESUME] = "RESUME", + [MATCH_CLASS] = "MATCH_CLASS", + [LOAD_GLOBAL_BUILTIN] = "LOAD_GLOBAL_BUILTIN", + [LOAD_GLOBAL_MODULE] = "LOAD_GLOBAL_MODULE", + [FORMAT_VALUE] = "FORMAT_VALUE", + [BUILD_CONST_KEY_MAP] = "BUILD_CONST_KEY_MAP", + [BUILD_STRING] = "BUILD_STRING", + [RESUME_QUICK] = "RESUME_QUICK", + [STORE_ATTR_ADAPTIVE] = "STORE_ATTR_ADAPTIVE", + [STORE_ATTR_INSTANCE_VALUE] = "STORE_ATTR_INSTANCE_VALUE", + [STORE_ATTR_SLOT] = "STORE_ATTR_SLOT", + [LIST_EXTEND] = "LIST_EXTEND", + [SET_UPDATE] = "SET_UPDATE", + [DICT_MERGE] = "DICT_MERGE", + [DICT_UPDATE] = "DICT_UPDATE", + [STORE_ATTR_WITH_HINT] = "STORE_ATTR_WITH_HINT", + [STORE_FAST__LOAD_FAST] = "STORE_FAST__LOAD_FAST", + [STORE_FAST__STORE_FAST] = "STORE_FAST__STORE_FAST", + [STORE_SUBSCR_ADAPTIVE] = "STORE_SUBSCR_ADAPTIVE", + [STORE_SUBSCR_DICT] = "STORE_SUBSCR_DICT", + [CALL] = "CALL", + [KW_NAMES] = "KW_NAMES", + [POP_JUMP_BACKWARD_IF_NOT_NONE] = "POP_JUMP_BACKWARD_IF_NOT_NONE", + [POP_JUMP_BACKWARD_IF_NONE] = "POP_JUMP_BACKWARD_IF_NONE", + [POP_JUMP_BACKWARD_IF_FALSE] = "POP_JUMP_BACKWARD_IF_FALSE", + [POP_JUMP_BACKWARD_IF_TRUE] = "POP_JUMP_BACKWARD_IF_TRUE", + [STORE_SUBSCR_LIST_INT] = "STORE_SUBSCR_LIST_INT", + [UNPACK_SEQUENCE_ADAPTIVE] = "UNPACK_SEQUENCE_ADAPTIVE", + [UNPACK_SEQUENCE_LIST] = "UNPACK_SEQUENCE_LIST", + [UNPACK_SEQUENCE_TUPLE] = "UNPACK_SEQUENCE_TUPLE", + [UNPACK_SEQUENCE_TWO_TUPLE] = "UNPACK_SEQUENCE_TWO_TUPLE", + [182] = "<182>", + [183] = "<183>", + [184] = "<184>", + [185] = "<185>", + [186] = "<186>", + [187] = "<187>", + [188] = "<188>", + [189] = "<189>", + [190] = "<190>", + [191] = "<191>", + [192] = "<192>", + [193] = "<193>", + [194] = "<194>", + [195] = "<195>", + [196] = "<196>", + [197] = "<197>", + [198] = "<198>", + [199] = "<199>", + [200] = "<200>", + [201] = "<201>", + [202] = "<202>", + [203] = "<203>", + [204] = "<204>", + [205] = "<205>", + [206] = "<206>", + [207] = "<207>", + [208] = "<208>", + [209] = "<209>", + [210] = "<210>", + [211] = "<211>", + [212] = "<212>", + [213] = "<213>", + [214] = "<214>", + [215] = "<215>", + [216] = "<216>", + [217] = "<217>", + [218] = "<218>", + [219] = "<219>", + [220] = "<220>", + [221] = "<221>", + [222] = "<222>", + [223] = "<223>", + [224] = "<224>", + [225] = "<225>", + [226] = "<226>", + [227] = "<227>", + [228] = "<228>", + [229] = "<229>", + [230] = "<230>", + [231] = "<231>", + [232] = "<232>", + [233] = "<233>", + [234] = "<234>", + [235] = "<235>", + [236] = "<236>", + [237] = "<237>", + [238] = "<238>", + [239] = "<239>", + [240] = "<240>", + [241] = "<241>", + [242] = "<242>", + [243] = "<243>", + [244] = "<244>", + [245] = "<245>", + [246] = "<246>", + [247] = "<247>", + [248] = "<248>", + [249] = "<249>", + [250] = "<250>", + [251] = "<251>", + [252] = "<252>", + [253] = "<253>", + [254] = "<254>", + [DO_TRACING] = "DO_TRACING", +}; +#endif + +#define EXTRA_CASES \ + case 182: \ + case 183: \ + case 184: \ + case 185: \ + case 186: \ + case 187: \ + case 188: \ + case 189: \ + case 190: \ + case 191: \ + case 192: \ + case 193: \ + case 194: \ + case 195: \ + case 196: \ + case 197: \ + case 198: \ + case 199: \ + case 200: \ + case 201: \ + case 202: \ + case 203: \ + case 204: \ + case 205: \ + case 206: \ + case 207: \ + case 208: \ + case 209: \ + case 210: \ + case 211: \ + case 212: \ + case 213: \ + case 214: \ + case 215: \ + case 216: \ + case 217: \ + case 218: \ + case 219: \ + case 220: \ + case 221: \ + case 222: \ + case 223: \ + case 224: \ + case 225: \ + case 226: \ + case 227: \ + case 228: \ + case 229: \ + case 230: \ + case 231: \ + case 232: \ + case 233: \ + case 234: \ + case 235: \ + case 236: \ + case 237: \ + case 238: \ + case 239: \ + case 240: \ + case 241: \ + case 242: \ + case 243: \ + case 244: \ + case 245: \ + case 246: \ + case 247: \ + case 248: \ + case 249: \ + case 250: \ + case 251: \ + case 252: \ + case 253: \ + case 254: \ + ; + +#ifdef __cplusplus +} +#endif +#endif // !Py_INTERNAL_OPCODE_H diff --git a/Include/opcode.h b/Include/opcode.h index e69de29bb2d1d6..57b1347b0ba3b6 100644 --- a/Include/opcode.h +++ b/Include/opcode.h @@ -0,0 +1,237 @@ +// Auto-generated by Tools/scripts/generate_opcode_h.py from Lib/opcode.py + +#ifndef Py_OPCODE_H +#define Py_OPCODE_H +#ifdef __cplusplus +extern "C" { +#endif + + +/* Instruction opcodes for compiled code */ +#define CACHE 0 +#define POP_TOP 1 +#define PUSH_NULL 2 +#define NOP 9 +#define UNARY_POSITIVE 10 +#define UNARY_NEGATIVE 11 +#define UNARY_NOT 12 +#define UNARY_INVERT 15 +#define BINARY_SUBSCR 25 +#define GET_LEN 30 +#define MATCH_MAPPING 31 +#define MATCH_SEQUENCE 32 +#define MATCH_KEYS 33 +#define PUSH_EXC_INFO 35 +#define CHECK_EXC_MATCH 36 +#define CHECK_EG_MATCH 37 +#define WITH_EXCEPT_START 49 +#define GET_AITER 50 +#define GET_ANEXT 51 +#define BEFORE_ASYNC_WITH 52 +#define BEFORE_WITH 53 +#define END_ASYNC_FOR 54 +#define STORE_SUBSCR 60 +#define DELETE_SUBSCR 61 +#define GET_ITER 68 +#define GET_YIELD_FROM_ITER 69 +#define PRINT_EXPR 70 +#define LOAD_BUILD_CLASS 71 +#define LOAD_ASSERTION_ERROR 74 +#define RETURN_GENERATOR 75 +#define LIST_TO_TUPLE 82 +#define RETURN_VALUE 83 +#define IMPORT_STAR 84 +#define SETUP_ANNOTATIONS 85 +#define ASYNC_GEN_WRAP 87 +#define PREP_RERAISE_STAR 88 +#define POP_EXCEPT 89 +#define HAVE_ARGUMENT 90 +#define STORE_NAME 90 +#define DELETE_NAME 91 +#define UNPACK_SEQUENCE 92 +#define FOR_ITER 93 +#define UNPACK_EX 94 +#define STORE_ATTR 95 +#define DELETE_ATTR 96 +#define STORE_GLOBAL 97 +#define DELETE_GLOBAL 98 +#define SWAP 99 +#define LOAD_CONST 100 +#define LOAD_NAME 101 +#define BUILD_TUPLE 102 +#define BUILD_LIST 103 +#define BUILD_SET 104 +#define BUILD_MAP 105 +#define LOAD_ATTR 106 +#define COMPARE_OP 107 +#define IMPORT_NAME 108 +#define IMPORT_FROM 109 +#define JUMP_FORWARD 110 +#define JUMP_IF_FALSE_OR_POP 111 +#define JUMP_IF_TRUE_OR_POP 112 +#define POP_JUMP_FORWARD_IF_FALSE 114 +#define POP_JUMP_FORWARD_IF_TRUE 115 +#define LOAD_GLOBAL 116 +#define IS_OP 117 +#define CONTAINS_OP 118 +#define RERAISE 119 +#define COPY 120 +#define BINARY_OP 122 +#define SEND 123 +#define LOAD_FAST 124 +#define STORE_FAST 125 +#define DELETE_FAST 126 +#define LOAD_FAST_CHECK 127 +#define POP_JUMP_FORWARD_IF_NOT_NONE 128 +#define POP_JUMP_FORWARD_IF_NONE 129 +#define RAISE_VARARGS 130 +#define GET_AWAITABLE 131 +#define MAKE_FUNCTION 132 +#define BUILD_SLICE 133 +#define JUMP_BACKWARD_NO_INTERRUPT 134 +#define MAKE_CELL 135 +#define LOAD_CLOSURE 136 +#define LOAD_DEREF 137 +#define STORE_DEREF 138 +#define DELETE_DEREF 139 +#define JUMP_BACKWARD 140 +#define CALL_FUNCTION_EX 142 +#define EXTENDED_ARG 144 +#define LIST_APPEND 145 +#define SET_ADD 146 +#define MAP_ADD 147 +#define LOAD_CLASSDEREF 148 +#define COPY_FREE_VARS 149 +#define YIELD_VALUE 150 +#define RESUME 151 +#define MATCH_CLASS 152 +#define FORMAT_VALUE 155 +#define BUILD_CONST_KEY_MAP 156 +#define BUILD_STRING 157 +#define LIST_EXTEND 162 +#define SET_UPDATE 163 +#define DICT_MERGE 164 +#define DICT_UPDATE 165 +#define CALL 171 +#define KW_NAMES 172 +#define POP_JUMP_BACKWARD_IF_NOT_NONE 173 +#define POP_JUMP_BACKWARD_IF_NONE 174 +#define POP_JUMP_BACKWARD_IF_FALSE 175 +#define POP_JUMP_BACKWARD_IF_TRUE 176 +#define BINARY_OP_ADAPTIVE 3 +#define BINARY_OP_ADD_FLOAT 4 +#define BINARY_OP_ADD_INT 5 +#define BINARY_OP_ADD_UNICODE 6 +#define BINARY_OP_INPLACE_ADD_UNICODE 7 +#define BINARY_OP_MULTIPLY_FLOAT 8 +#define BINARY_OP_MULTIPLY_INT 13 +#define BINARY_OP_SUBTRACT_FLOAT 14 +#define BINARY_OP_SUBTRACT_INT 16 +#define BINARY_SUBSCR_ADAPTIVE 17 +#define BINARY_SUBSCR_DICT 18 +#define BINARY_SUBSCR_GETITEM 19 +#define BINARY_SUBSCR_LIST_INT 20 +#define BINARY_SUBSCR_TUPLE_INT 21 +#define CALL_ADAPTIVE 22 +#define CALL_PY_EXACT_ARGS 23 +#define CALL_PY_WITH_DEFAULTS 24 +#define CALL_BOUND_METHOD_EXACT_ARGS 26 +#define CALL_BUILTIN_CLASS 27 +#define CALL_BUILTIN_FAST_WITH_KEYWORDS 28 +#define CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS 29 +#define CALL_NO_KW_BUILTIN_FAST 34 +#define CALL_NO_KW_BUILTIN_O 38 +#define CALL_NO_KW_ISINSTANCE 39 +#define CALL_NO_KW_LEN 40 +#define CALL_NO_KW_LIST_APPEND 41 +#define CALL_NO_KW_METHOD_DESCRIPTOR_FAST 42 +#define CALL_NO_KW_METHOD_DESCRIPTOR_NOARGS 43 +#define CALL_NO_KW_METHOD_DESCRIPTOR_O 44 +#define CALL_NO_KW_STR_1 45 +#define CALL_NO_KW_TUPLE_1 46 +#define CALL_NO_KW_TYPE_1 47 +#define COMPARE_OP_ADAPTIVE 48 +#define COMPARE_OP_FLOAT_JUMP 55 +#define COMPARE_OP_INT_JUMP 56 +#define COMPARE_OP_STR_JUMP 57 +#define EXTENDED_ARG_QUICK 58 +#define FOR_ITER_ADAPTIVE 59 +#define FOR_ITER_LIST 62 +#define FOR_ITER_RANGE 63 +#define JUMP_BACKWARD_QUICK 64 +#define LOAD_ATTR_ADAPTIVE 65 +#define LOAD_ATTR_CLASS 66 +#define LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN 67 +#define LOAD_ATTR_INSTANCE_VALUE 72 +#define LOAD_ATTR_MODULE 73 +#define LOAD_ATTR_PROPERTY 76 +#define LOAD_ATTR_SLOT 77 +#define LOAD_ATTR_WITH_HINT 78 +#define LOAD_ATTR_METHOD_LAZY_DICT 79 +#define LOAD_ATTR_METHOD_NO_DICT 80 +#define LOAD_ATTR_METHOD_WITH_DICT 81 +#define LOAD_ATTR_METHOD_WITH_VALUES 86 +#define LOAD_CONST__LOAD_FAST 113 +#define LOAD_FAST__LOAD_CONST 121 +#define LOAD_FAST__LOAD_FAST 141 +#define LOAD_GLOBAL_ADAPTIVE 143 +#define LOAD_GLOBAL_BUILTIN 153 +#define LOAD_GLOBAL_MODULE 154 +#define RESUME_QUICK 158 +#define STORE_ATTR_ADAPTIVE 159 +#define STORE_ATTR_INSTANCE_VALUE 160 +#define STORE_ATTR_SLOT 161 +#define STORE_ATTR_WITH_HINT 166 +#define STORE_FAST__LOAD_FAST 167 +#define STORE_FAST__STORE_FAST 168 +#define STORE_SUBSCR_ADAPTIVE 169 +#define STORE_SUBSCR_DICT 170 +#define STORE_SUBSCR_LIST_INT 177 +#define UNPACK_SEQUENCE_ADAPTIVE 178 +#define UNPACK_SEQUENCE_LIST 179 +#define UNPACK_SEQUENCE_TUPLE 180 +#define UNPACK_SEQUENCE_TWO_TUPLE 181 +#define DO_TRACING 255 + +#define HAS_CONST(op) (false\ + || ((op) == 100) \ + || ((op) == 172) \ + ) + +#define NB_ADD 0 +#define NB_AND 1 +#define NB_FLOOR_DIVIDE 2 +#define NB_LSHIFT 3 +#define NB_MATRIX_MULTIPLY 4 +#define NB_MULTIPLY 5 +#define NB_REMAINDER 6 +#define NB_OR 7 +#define NB_POWER 8 +#define NB_RSHIFT 9 +#define NB_SUBTRACT 10 +#define NB_TRUE_DIVIDE 11 +#define NB_XOR 12 +#define NB_INPLACE_ADD 13 +#define NB_INPLACE_AND 14 +#define NB_INPLACE_FLOOR_DIVIDE 15 +#define NB_INPLACE_LSHIFT 16 +#define NB_INPLACE_MATRIX_MULTIPLY 17 +#define NB_INPLACE_MULTIPLY 18 +#define NB_INPLACE_REMAINDER 19 +#define NB_INPLACE_OR 20 +#define NB_INPLACE_POWER 21 +#define NB_INPLACE_RSHIFT 22 +#define NB_INPLACE_SUBTRACT 23 +#define NB_INPLACE_TRUE_DIVIDE 24 +#define NB_INPLACE_XOR 25 + +#define HAS_ARG(op) ((op) >= HAVE_ARGUMENT) + +/* Reserve some bytecodes for internal use in the compiler. + * The value of 240 is arbitrary. */ +#define IS_ARTIFICIAL(op) ((op) > 240) + +#ifdef __cplusplus +} +#endif +#endif /* !Py_OPCODE_H */ diff --git a/Lib/opcode.py b/Lib/opcode.py index b917a095ddd107..b8e75427e3594a 100644 --- a/Lib/opcode.py +++ b/Lib/opcode.py @@ -290,8 +290,7 @@ def jabs_op(name, op): "LOAD_ATTR_ADAPTIVE", # These potentially push [NULL, bound method] onto the stack. "LOAD_ATTR_CLASS", - "LOAD_ATTR_GETATTRIBUTE_GETATTR_OVERRIDDEN", - "LOAD_ATTR_GETATTRIBUTE_GETATTR_PY_OVERRIDDEN", + "LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN", "LOAD_ATTR_INSTANCE_VALUE", "LOAD_ATTR_MODULE", "LOAD_ATTR_PROPERTY", diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-06-18-17-00-33.gh-issue-93911.y286of.rst b/Misc/NEWS.d/next/Core and Builtins/2022-06-18-17-00-33.gh-issue-93911.y286of.rst index e899b1dd0a40e9..9fc0df5266d0df 100644 --- a/Misc/NEWS.d/next/Core and Builtins/2022-06-18-17-00-33.gh-issue-93911.y286of.rst +++ b/Misc/NEWS.d/next/Core and Builtins/2022-06-18-17-00-33.gh-issue-93911.y286of.rst @@ -1 +1 @@ -Specialize ``LOAD_ATTR`` for objects with custom ``__getattr__`` and ``__getattribute__``. Patch by Ken Jin. +Specialize ``LOAD_ATTR`` for objects with custom ``__getattr__`` and ``__getattribute__``. diff --git a/Python/ceval.c b/Python/ceval.c index 32aaa34c9fd9dd..0f37ece6b4fbc5 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -3682,40 +3682,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int goto start_frame; } - TARGET(LOAD_ATTR_GETATTRIBUTE_GETATTR_OVERRIDDEN) { - assert(cframe.use_tracing == 0); - _PyLoadMethodCache *cache = (_PyLoadMethodCache *)next_instr; - PyObject *owner = TOP(); - PyTypeObject *cls = Py_TYPE(owner); - uint32_t type_version = read_u32(cache->type_version); - DEOPT_IF(cls->tp_version_tag != type_version, LOAD_ATTR); - assert(type_version != 0); - STAT_INC(LOAD_ATTR, hit); - - PyObject *name = GETITEM(names, oparg >> 1); - PyObject *getattribute = ((PyHeapTypeObject *)cls)->_spec_cache.getattribute; - PyObject *getattr = ((PyHeapTypeObject *)cls)->_spec_cache.getattr; - PyObject *res = getattribute ? - _Py_call_attribute(owner, getattribute, name) - : PyObject_GenericGetAttr(owner, name); - if (res == NULL && - getattr && - PyErr_ExceptionMatches(PyExc_AttributeError)) { - PyErr_Clear(); - res = _Py_call_attribute(owner, getattr, name); - } - if (res == NULL) { - goto error; - } - SET_TOP(NULL); - STACK_GROW((oparg & 1)); - SET_TOP(res); - Py_DECREF(owner); - JUMPBY(INLINE_CACHE_ENTRIES_LOAD_ATTR); - DISPATCH(); - } - - TARGET(LOAD_ATTR_GETATTRIBUTE_GETATTR_PY_OVERRIDDEN) { + TARGET(LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN) { assert(cframe.use_tracing == 0); DEOPT_IF(tstate->interp->eval_frame, LOAD_ATTR); _PyLoadMethodCache *cache = (_PyLoadMethodCache *)next_instr; @@ -3724,39 +3691,20 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int uint32_t type_version = read_u32(cache->type_version); DEOPT_IF(cls->tp_version_tag != type_version, LOAD_ATTR); assert(type_version != 0); - PyObject *getattr = ((PyHeapTypeObject *)cls)->_spec_cache.getattr; - assert(Py_IS_TYPE(getattr, &PyFunction_Type)); - PyFunctionObject *f = (PyFunctionObject *)getattr; + PyObject *getattribute = read_obj(cache->descr); + assert(Py_IS_TYPE(getattribute, &PyFunction_Type)); + PyFunctionObject *f = (PyFunctionObject *)getattribute; uint32_t func_version = read_u32(cache->keys_version); assert(func_version != 0); DEOPT_IF(f->func_version != func_version, LOAD_ATTR); PyCodeObject *code = (PyCodeObject *)f->func_code; assert(code->co_argcount == 2); + DEOPT_IF(!_PyThreadState_HasStackSpace(tstate, code->co_framesize), CALL); STAT_INC(LOAD_ATTR, hit); PyObject *name = GETITEM(names, oparg >> 1); - PyObject *getattribute = ((PyHeapTypeObject *)cls)->_spec_cache.getattribute; - /* Possible todo: inlining this call frame? */ - PyObject *res = getattribute ? - _Py_call_attribute(owner, getattribute, name) - : PyObject_GenericGetAttr(owner, name); - if (res) { - SET_TOP(NULL); - STACK_GROW((oparg & 1)); - SET_TOP(res); - Py_DECREF(owner); - JUMPBY(INLINE_CACHE_ENTRIES_LOAD_ATTR); - DISPATCH(); - } - if (!PyErr_ExceptionMatches(PyExc_AttributeError)) { - goto error; - } - PyErr_Clear(); Py_INCREF(f); - _PyInterpreterFrame *new_frame = _PyFrame_Push(tstate, f); - if (new_frame == NULL) { - goto error; - } + _PyInterpreterFrame *new_frame = _PyFrame_PushUnchecked(tstate, f); SET_TOP(NULL); int push_null = !(oparg & 1); STACK_SHRINK(push_null); diff --git a/Python/opcode_targets.h b/Python/opcode_targets.h index e69de29bb2d1d6..43c747d0e8ea40 100644 --- a/Python/opcode_targets.h +++ b/Python/opcode_targets.h @@ -0,0 +1,258 @@ +static void *opcode_targets[256] = { + &&TARGET_CACHE, + &&TARGET_POP_TOP, + &&TARGET_PUSH_NULL, + &&TARGET_BINARY_OP_ADAPTIVE, + &&TARGET_BINARY_OP_ADD_FLOAT, + &&TARGET_BINARY_OP_ADD_INT, + &&TARGET_BINARY_OP_ADD_UNICODE, + &&TARGET_BINARY_OP_INPLACE_ADD_UNICODE, + &&TARGET_BINARY_OP_MULTIPLY_FLOAT, + &&TARGET_NOP, + &&TARGET_UNARY_POSITIVE, + &&TARGET_UNARY_NEGATIVE, + &&TARGET_UNARY_NOT, + &&TARGET_BINARY_OP_MULTIPLY_INT, + &&TARGET_BINARY_OP_SUBTRACT_FLOAT, + &&TARGET_UNARY_INVERT, + &&TARGET_BINARY_OP_SUBTRACT_INT, + &&TARGET_BINARY_SUBSCR_ADAPTIVE, + &&TARGET_BINARY_SUBSCR_DICT, + &&TARGET_BINARY_SUBSCR_GETITEM, + &&TARGET_BINARY_SUBSCR_LIST_INT, + &&TARGET_BINARY_SUBSCR_TUPLE_INT, + &&TARGET_CALL_ADAPTIVE, + &&TARGET_CALL_PY_EXACT_ARGS, + &&TARGET_CALL_PY_WITH_DEFAULTS, + &&TARGET_BINARY_SUBSCR, + &&TARGET_CALL_BOUND_METHOD_EXACT_ARGS, + &&TARGET_CALL_BUILTIN_CLASS, + &&TARGET_CALL_BUILTIN_FAST_WITH_KEYWORDS, + &&TARGET_CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS, + &&TARGET_GET_LEN, + &&TARGET_MATCH_MAPPING, + &&TARGET_MATCH_SEQUENCE, + &&TARGET_MATCH_KEYS, + &&TARGET_CALL_NO_KW_BUILTIN_FAST, + &&TARGET_PUSH_EXC_INFO, + &&TARGET_CHECK_EXC_MATCH, + &&TARGET_CHECK_EG_MATCH, + &&TARGET_CALL_NO_KW_BUILTIN_O, + &&TARGET_CALL_NO_KW_ISINSTANCE, + &&TARGET_CALL_NO_KW_LEN, + &&TARGET_CALL_NO_KW_LIST_APPEND, + &&TARGET_CALL_NO_KW_METHOD_DESCRIPTOR_FAST, + &&TARGET_CALL_NO_KW_METHOD_DESCRIPTOR_NOARGS, + &&TARGET_CALL_NO_KW_METHOD_DESCRIPTOR_O, + &&TARGET_CALL_NO_KW_STR_1, + &&TARGET_CALL_NO_KW_TUPLE_1, + &&TARGET_CALL_NO_KW_TYPE_1, + &&TARGET_COMPARE_OP_ADAPTIVE, + &&TARGET_WITH_EXCEPT_START, + &&TARGET_GET_AITER, + &&TARGET_GET_ANEXT, + &&TARGET_BEFORE_ASYNC_WITH, + &&TARGET_BEFORE_WITH, + &&TARGET_END_ASYNC_FOR, + &&TARGET_COMPARE_OP_FLOAT_JUMP, + &&TARGET_COMPARE_OP_INT_JUMP, + &&TARGET_COMPARE_OP_STR_JUMP, + &&TARGET_EXTENDED_ARG_QUICK, + &&TARGET_FOR_ITER_ADAPTIVE, + &&TARGET_STORE_SUBSCR, + &&TARGET_DELETE_SUBSCR, + &&TARGET_FOR_ITER_LIST, + &&TARGET_FOR_ITER_RANGE, + &&TARGET_JUMP_BACKWARD_QUICK, + &&TARGET_LOAD_ATTR_ADAPTIVE, + &&TARGET_LOAD_ATTR_CLASS, + &&TARGET_LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN, + &&TARGET_GET_ITER, + &&TARGET_GET_YIELD_FROM_ITER, + &&TARGET_PRINT_EXPR, + &&TARGET_LOAD_BUILD_CLASS, + &&TARGET_LOAD_ATTR_INSTANCE_VALUE, + &&TARGET_LOAD_ATTR_MODULE, + &&TARGET_LOAD_ASSERTION_ERROR, + &&TARGET_RETURN_GENERATOR, + &&TARGET_LOAD_ATTR_PROPERTY, + &&TARGET_LOAD_ATTR_SLOT, + &&TARGET_LOAD_ATTR_WITH_HINT, + &&TARGET_LOAD_ATTR_METHOD_LAZY_DICT, + &&TARGET_LOAD_ATTR_METHOD_NO_DICT, + &&TARGET_LOAD_ATTR_METHOD_WITH_DICT, + &&TARGET_LIST_TO_TUPLE, + &&TARGET_RETURN_VALUE, + &&TARGET_IMPORT_STAR, + &&TARGET_SETUP_ANNOTATIONS, + &&TARGET_LOAD_ATTR_METHOD_WITH_VALUES, + &&TARGET_ASYNC_GEN_WRAP, + &&TARGET_PREP_RERAISE_STAR, + &&TARGET_POP_EXCEPT, + &&TARGET_STORE_NAME, + &&TARGET_DELETE_NAME, + &&TARGET_UNPACK_SEQUENCE, + &&TARGET_FOR_ITER, + &&TARGET_UNPACK_EX, + &&TARGET_STORE_ATTR, + &&TARGET_DELETE_ATTR, + &&TARGET_STORE_GLOBAL, + &&TARGET_DELETE_GLOBAL, + &&TARGET_SWAP, + &&TARGET_LOAD_CONST, + &&TARGET_LOAD_NAME, + &&TARGET_BUILD_TUPLE, + &&TARGET_BUILD_LIST, + &&TARGET_BUILD_SET, + &&TARGET_BUILD_MAP, + &&TARGET_LOAD_ATTR, + &&TARGET_COMPARE_OP, + &&TARGET_IMPORT_NAME, + &&TARGET_IMPORT_FROM, + &&TARGET_JUMP_FORWARD, + &&TARGET_JUMP_IF_FALSE_OR_POP, + &&TARGET_JUMP_IF_TRUE_OR_POP, + &&TARGET_LOAD_CONST__LOAD_FAST, + &&TARGET_POP_JUMP_FORWARD_IF_FALSE, + &&TARGET_POP_JUMP_FORWARD_IF_TRUE, + &&TARGET_LOAD_GLOBAL, + &&TARGET_IS_OP, + &&TARGET_CONTAINS_OP, + &&TARGET_RERAISE, + &&TARGET_COPY, + &&TARGET_LOAD_FAST__LOAD_CONST, + &&TARGET_BINARY_OP, + &&TARGET_SEND, + &&TARGET_LOAD_FAST, + &&TARGET_STORE_FAST, + &&TARGET_DELETE_FAST, + &&TARGET_LOAD_FAST_CHECK, + &&TARGET_POP_JUMP_FORWARD_IF_NOT_NONE, + &&TARGET_POP_JUMP_FORWARD_IF_NONE, + &&TARGET_RAISE_VARARGS, + &&TARGET_GET_AWAITABLE, + &&TARGET_MAKE_FUNCTION, + &&TARGET_BUILD_SLICE, + &&TARGET_JUMP_BACKWARD_NO_INTERRUPT, + &&TARGET_MAKE_CELL, + &&TARGET_LOAD_CLOSURE, + &&TARGET_LOAD_DEREF, + &&TARGET_STORE_DEREF, + &&TARGET_DELETE_DEREF, + &&TARGET_JUMP_BACKWARD, + &&TARGET_LOAD_FAST__LOAD_FAST, + &&TARGET_CALL_FUNCTION_EX, + &&TARGET_LOAD_GLOBAL_ADAPTIVE, + &&TARGET_EXTENDED_ARG, + &&TARGET_LIST_APPEND, + &&TARGET_SET_ADD, + &&TARGET_MAP_ADD, + &&TARGET_LOAD_CLASSDEREF, + &&TARGET_COPY_FREE_VARS, + &&TARGET_YIELD_VALUE, + &&TARGET_RESUME, + &&TARGET_MATCH_CLASS, + &&TARGET_LOAD_GLOBAL_BUILTIN, + &&TARGET_LOAD_GLOBAL_MODULE, + &&TARGET_FORMAT_VALUE, + &&TARGET_BUILD_CONST_KEY_MAP, + &&TARGET_BUILD_STRING, + &&TARGET_RESUME_QUICK, + &&TARGET_STORE_ATTR_ADAPTIVE, + &&TARGET_STORE_ATTR_INSTANCE_VALUE, + &&TARGET_STORE_ATTR_SLOT, + &&TARGET_LIST_EXTEND, + &&TARGET_SET_UPDATE, + &&TARGET_DICT_MERGE, + &&TARGET_DICT_UPDATE, + &&TARGET_STORE_ATTR_WITH_HINT, + &&TARGET_STORE_FAST__LOAD_FAST, + &&TARGET_STORE_FAST__STORE_FAST, + &&TARGET_STORE_SUBSCR_ADAPTIVE, + &&TARGET_STORE_SUBSCR_DICT, + &&TARGET_CALL, + &&TARGET_KW_NAMES, + &&TARGET_POP_JUMP_BACKWARD_IF_NOT_NONE, + &&TARGET_POP_JUMP_BACKWARD_IF_NONE, + &&TARGET_POP_JUMP_BACKWARD_IF_FALSE, + &&TARGET_POP_JUMP_BACKWARD_IF_TRUE, + &&TARGET_STORE_SUBSCR_LIST_INT, + &&TARGET_UNPACK_SEQUENCE_ADAPTIVE, + &&TARGET_UNPACK_SEQUENCE_LIST, + &&TARGET_UNPACK_SEQUENCE_TUPLE, + &&TARGET_UNPACK_SEQUENCE_TWO_TUPLE, + &&_unknown_opcode, + &&_unknown_opcode, + &&_unknown_opcode, + &&_unknown_opcode, + &&_unknown_opcode, + &&_unknown_opcode, + &&_unknown_opcode, + &&_unknown_opcode, + &&_unknown_opcode, + &&_unknown_opcode, + &&_unknown_opcode, + &&_unknown_opcode, + &&_unknown_opcode, + &&_unknown_opcode, + &&_unknown_opcode, + &&_unknown_opcode, + &&_unknown_opcode, + &&_unknown_opcode, + &&_unknown_opcode, + &&_unknown_opcode, + &&_unknown_opcode, + &&_unknown_opcode, + &&_unknown_opcode, + &&_unknown_opcode, + &&_unknown_opcode, + &&_unknown_opcode, + &&_unknown_opcode, + &&_unknown_opcode, + &&_unknown_opcode, + &&_unknown_opcode, + &&_unknown_opcode, + &&_unknown_opcode, + &&_unknown_opcode, + &&_unknown_opcode, + &&_unknown_opcode, + &&_unknown_opcode, + &&_unknown_opcode, + &&_unknown_opcode, + &&_unknown_opcode, + &&_unknown_opcode, + &&_unknown_opcode, + &&_unknown_opcode, + &&_unknown_opcode, + &&_unknown_opcode, + &&_unknown_opcode, + &&_unknown_opcode, + &&_unknown_opcode, + &&_unknown_opcode, + &&_unknown_opcode, + &&_unknown_opcode, + &&_unknown_opcode, + &&_unknown_opcode, + &&_unknown_opcode, + &&_unknown_opcode, + &&_unknown_opcode, + &&_unknown_opcode, + &&_unknown_opcode, + &&_unknown_opcode, + &&_unknown_opcode, + &&_unknown_opcode, + &&_unknown_opcode, + &&_unknown_opcode, + &&_unknown_opcode, + &&_unknown_opcode, + &&_unknown_opcode, + &&_unknown_opcode, + &&_unknown_opcode, + &&_unknown_opcode, + &&_unknown_opcode, + &&_unknown_opcode, + &&_unknown_opcode, + &&_unknown_opcode, + &&_unknown_opcode, + &&TARGET_DO_TRACING +}; diff --git a/Python/specialize.c b/Python/specialize.c index fb31aee7b0ef75..264e46a8177266 100644 --- a/Python/specialize.c +++ b/Python/specialize.c @@ -385,6 +385,7 @@ miss_counter_start(void) { #define SPEC_FAIL_ATTR_METACLASS_ATTRIBUTE 27 #define SPEC_FAIL_ATTR_CUSTOM_GETATTRO 28 #define SPEC_FAIL_ATTR_NOT_HEAP_TYPE 29 +#define SPEC_FAIL_ATTR_NOT_MATCHING_CUSTOM_GETATTRIBUTE 30 /* Binary subscr and store subscr */ @@ -540,77 +541,6 @@ specialize_module_load_attr(PyObject *owner, _Py_CODEUNIT *instr, return 0; } -static int -specialize_custom_getattribute(PyTypeObject *type, _Py_CODEUNIT *instr, - unsigned int tp_version_tag) -{ - if (type->tp_getattr != NULL && type->tp_getattro == NULL) { - goto fail; - } - getattrofunc getattro_slot = type->tp_getattro; - /* The following comment is copied from typeobject.c */ - /* There are two slot dispatch functions for tp_getattro. - - - _Py_slot_tp_getattro() is used when __getattribute__ is overridden - but no __getattr__ hook is present; - - - _Py_slot_tp_getattr_hook() is used when a __getattr__ hook is present. - - The code in update_one_slot() always installs - _Py_slot_tp_getattr_hook(); this detects the absence of - __getattr__ and then installs the simpler slot if necessary. */ - if (getattro_slot != _Py_slot_tp_getattro && - getattro_slot != _Py_slot_tp_getattr_hook) { - /* E.g. the custom getattro for super() objects */ - SPECIALIZATION_FAIL(LOAD_ATTR, SPEC_FAIL_ATTR_CUSTOM_GETATTRO); - goto fail; - } - if (!(type->tp_flags & Py_TPFLAGS_HEAPTYPE)) { - SPECIALIZATION_FAIL(LOAD_ATTR, SPEC_FAIL_ATTR_NOT_HEAP_TYPE); - goto fail; - } - _PyLoadMethodCache *lm_cache = (_PyLoadMethodCache *)(instr + 1); - PyObject *getattr = _PyType_Lookup(type, &_Py_ID(__getattr__)); - if (getattr == NULL && getattro_slot != _Py_slot_tp_getattro) { - /* According to typeobject rules, if getattr is NULL, - getattro_slot should be _Py_slot_tp_getattro */ - goto fail; - } - PyObject *getattribute = _PyType_Lookup(type, - &_Py_ID(__getattribute__)); - /* Whether to call PyObject_GenericGetAttr or getattribute - at runtime */ - bool custom_getattribute = !(getattribute == NULL || - (Py_IS_TYPE(getattribute, &PyWrapperDescr_Type) && - ((PyWrapperDescrObject *)getattribute)->d_wrapped == - (void *)PyObject_GenericGetAttr)); - - if (getattr || getattribute) { - PyHeapTypeObject *ht = (PyHeapTypeObject *)type; - /* borrowed */ - ht->_spec_cache.getattribute = custom_getattribute ? - getattribute : NULL; - - uint32_t func_version = 0; - if (getattr) { - func_version = maybe_function_get_version(getattr, 2, LOAD_ATTR); - } - /* func_version == 0 is OK if there's no __getattr__ - or __getattr__ isn't a Python function*/ - write_u32(lm_cache->keys_version, func_version); - /* borrowed */ - ((PyHeapTypeObject *)type)->_spec_cache.getattr = getattr; - assert(type->tp_version_tag != 0); - write_u32(lm_cache->type_version, type->tp_version_tag); - _Py_SET_OPCODE(*instr, func_version ? LOAD_ATTR_GETATTRIBUTE_GETATTR_PY_OVERRIDDEN : LOAD_ATTR_GETATTRIBUTE_GETATTR_OVERRIDDEN); - goto success; - } -fail: - return 1; -success: - return 0; -} - /* Attribute specialization */ @@ -627,13 +557,15 @@ typedef enum { MUTABLE, /* Instance of a mutable class; might, or might not, be a descriptor */ ABSENT, /* Attribute is not present on the class */ DUNDER_CLASS, /* __class__ attribute */ - GETSET_OVERRIDDEN /* __getattribute__ or __setattr__ has been overridden */ + GETSET_OVERRIDDEN, /* __getattribute__ or __setattr__ has been overridden */ + GET_CALL_GETATTRIBUTE /* Descriptor requires calling __getattribute__ */ } DescriptorClassification; static DescriptorClassification analyze_descriptor(PyTypeObject *type, PyObject *name, PyObject **descr, int store) { + int has_getattr = 0; if (store) { if (type->tp_setattro != PyObject_GenericSetAttr) { *descr = NULL; @@ -642,8 +574,47 @@ analyze_descriptor(PyTypeObject *type, PyObject *name, PyObject **descr, int sto } else { if (type->tp_getattro != PyObject_GenericGetAttr) { - *descr = NULL; - return GETSET_OVERRIDDEN; + getattrofunc getattro_slot = type->tp_getattro; + /* The following comment is copied from typeobject.c */ + /* There are two slot dispatch functions for tp_getattro. + + - _Py_slot_tp_getattro() is used when __getattribute__ is overridden + but no __getattr__ hook is present; + + - _Py_slot_tp_getattr_hook() is used when a __getattr__ hook is present. + + The code in update_one_slot() always installs + _Py_slot_tp_getattr_hook(); this detects the absence of + __getattr__ and then installs the simpler slot if necessary. */ + /* Using some custom tp_getattro, like super() objects */ + if (getattro_slot != _Py_slot_tp_getattr_hook && + getattro_slot != _Py_slot_tp_getattro) { + *descr = NULL; + return GETSET_OVERRIDDEN; + } + PyObject *getattribute = _PyType_Lookup(type, + &_Py_ID(__getattribute__)); + bool custom_getattribute = !(getattribute == NULL || + (Py_IS_TYPE(getattribute, &PyWrapperDescr_Type) && + ((PyWrapperDescrObject *)getattribute)->d_wrapped == + (void *)PyObject_GenericGetAttr)); + if (custom_getattribute) { + if (getattro_slot == _Py_slot_tp_getattro && + Py_IS_TYPE(getattribute, &PyFunction_Type)) { + *descr = getattribute; + return GET_CALL_GETATTRIBUTE; + } + *descr = NULL; + return GETSET_OVERRIDDEN; + } + /* Potentially has __getattr__ but no custom __getattribute__. + Fall through to usual descriptor analysis. + Usual attribute lookup should only be allowed at runtime + if we can guarantee that there is no way an exception can be + raised. This means some specializations, e.g. specializing + for property() isn't safe. + */ + has_getattr = (getattro_slot == _Py_slot_tp_getattr_hook); } } PyObject *descriptor = _PyType_Lookup(type, name); @@ -665,7 +636,10 @@ analyze_descriptor(PyTypeObject *type, PyObject *name, PyObject **descr, int sto return OTHER_SLOT; } if (desc_cls == &PyProperty_Type) { - return PROPERTY; + /* We can't detect at runtime whether an attribute exists + with property. So that means we may have to call + __getattr__. */ + return has_getattr ? GETSET_OVERRIDDEN : PROPERTY; } if (PyUnicode_CompareWithASCIIString(name, "__class__") == 0) { if (descriptor == _PyType_Lookup(&PyBaseObject_Type, name)) { @@ -847,12 +821,24 @@ _Py_Specialize_LoadAttr(PyObject *owner, _Py_CODEUNIT *instr, PyObject *name) SPECIALIZATION_FAIL(LOAD_ATTR, SPEC_FAIL_ATTR_MUTABLE_CLASS); goto fail; case GETSET_OVERRIDDEN: + SPECIALIZATION_FAIL(LOAD_ATTR, SPEC_FAIL_OVERRIDDEN); + goto fail; + case GET_CALL_GETATTRIBUTE: { - int err = specialize_custom_getattribute(type, instr, - type->tp_version_tag); - if (err) { + getattrofunc getattro_slot = type->tp_getattro; + assert(getattro_slot == _Py_slot_tp_getattro); + assert(Py_IS_TYPE(descr, &PyFunction_Type)); + _PyLoadMethodCache *lm_cache = (_PyLoadMethodCache *)(instr + 1); + uint32_t func_version = maybe_function_get_version(descr, 2, + LOAD_ATTR); + if (func_version == 0) { goto fail; } + /* borrowed */ + write_obj(lm_cache->descr, descr); + write_u32(lm_cache->keys_version, func_version); + write_u32(lm_cache->type_version, type->tp_version_tag); + _Py_SET_OPCODE(*instr, LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN); goto success; } case BUILTIN_CLASSMETHOD: @@ -933,6 +919,7 @@ _Py_Specialize_StoreAttr(PyObject *owner, _Py_CODEUNIT *instr, PyObject *name) case MUTABLE: SPECIALIZATION_FAIL(STORE_ATTR, SPEC_FAIL_ATTR_MUTABLE_CLASS); goto fail; + case GET_CALL_GETATTRIBUTE: case GETSET_OVERRIDDEN: SPECIALIZATION_FAIL(STORE_ATTR, SPEC_FAIL_OVERRIDDEN); goto fail; From dd89339fb1f04d558af46e9dddf2a7d203167f66 Mon Sep 17 00:00:00 2001 From: Ken Jin <28750310+Fidget-Spinner@users.noreply.github.com> Date: Mon, 27 Jun 2022 16:11:35 +0800 Subject: [PATCH 09/17] fix test_sys --- Lib/test/test_sys.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Lib/test/test_sys.py b/Lib/test/test_sys.py index 6c55624d481865..1dc10d8b0a39ac 100644 --- a/Lib/test/test_sys.py +++ b/Lib/test/test_sys.py @@ -1518,7 +1518,7 @@ def delx(self): del self.__x '10P' # PySequenceMethods '2P' # PyBufferProcs '6P' - '3P' # Specializer cache + '1P' # Specializer cache ) class newstyleclass(object): pass # Separate block for PyDictKeysObject with 8 keys and 5 entries From db132621596ecda2355d2042968b40e15b46b9b4 Mon Sep 17 00:00:00 2001 From: Ken Jin <28750310+Fidget-Spinner@users.noreply.github.com> Date: Thu, 30 Jun 2022 20:42:33 +0800 Subject: [PATCH 10/17] address review --- Include/internal/pycore_typeobject.h | 6 +++--- Python/ceval.c | 8 ++++---- Python/specialize.c | 15 +++++++++------ 3 files changed, 16 insertions(+), 13 deletions(-) diff --git a/Include/internal/pycore_typeobject.h b/Include/internal/pycore_typeobject.h index d6ca4f7d2c5e0a..f302e3cc6a5b04 100644 --- a/Include/internal/pycore_typeobject.h +++ b/Include/internal/pycore_typeobject.h @@ -44,9 +44,9 @@ extern PyStatus _PyTypes_InitSlotDefs(void); extern void _PyStaticType_Dealloc(PyTypeObject *type); -extern PyObject *_Py_slot_tp_getattro(PyObject *self, PyObject *name); -extern PyObject *_Py_slot_tp_getattr_hook(PyObject *self, PyObject *name); -extern PyObject *_Py_call_attribute(PyObject *self, PyObject *attr, PyObject *name); +PyObject *_Py_slot_tp_getattro(PyObject *self, PyObject *name); +PyObject *_Py_slot_tp_getattr_hook(PyObject *self, PyObject *name); +PyObject *_Py_call_attribute(PyObject *self, PyObject *attr, PyObject *name); #ifdef __cplusplus } #endif diff --git a/Python/ceval.c b/Python/ceval.c index 925fc57c653df4..0baa2f9986dc67 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -3708,8 +3708,8 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int Py_INCREF(fget); _PyInterpreterFrame *new_frame = _PyFrame_PushUnchecked(tstate, f); SET_TOP(NULL); - int push_null = !(oparg & 1); - STACK_SHRINK(push_null); + int shrink_stack = !(oparg & 1); + STACK_SHRINK(shrink_stack); new_frame->localsplus[0] = owner; for (int i = 1; i < code->co_nlocalsplus; i++) { new_frame->localsplus[i] = NULL; @@ -3747,8 +3747,8 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int Py_INCREF(f); _PyInterpreterFrame *new_frame = _PyFrame_PushUnchecked(tstate, f); SET_TOP(NULL); - int push_null = !(oparg & 1); - STACK_SHRINK(push_null); + int shrink_stack = !(oparg & 1); + STACK_SHRINK(shrink_stack); Py_INCREF(name); new_frame->localsplus[0] = owner; new_frame->localsplus[1] = name; diff --git a/Python/specialize.c b/Python/specialize.c index 19644b66eeb4a5..779688339eb72e 100644 --- a/Python/specialize.c +++ b/Python/specialize.c @@ -359,6 +359,8 @@ miss_counter_start(void) { #define SPEC_FAIL_OUT_OF_RANGE 4 #define SPEC_FAIL_EXPECTED_ERROR 5 #define SPEC_FAIL_WRONG_NUMBER_ARGUMENTS 6 +#define SPEC_FAIL_NOT_PY_FUNCTION 7 + #define SPEC_FAIL_LOAD_GLOBAL_NON_STRING_OR_SPLIT 18 @@ -499,7 +501,7 @@ miss_counter_start(void) { #define SPEC_FAIL_UNPACK_SEQUENCE_SEQUENCE 9 static int function_kind(PyCodeObject *code); -static uint32_t maybe_function_get_version(PyObject *o, int expected_argcount, int opcode); +static uint32_t function_get_version(PyObject *o, int expected_argcount, int opcode); static int specialize_module_load_attr(PyObject *owner, _Py_CODEUNIT *instr, @@ -773,7 +775,7 @@ _Py_Specialize_LoadAttr(PyObject *owner, _Py_CODEUNIT *instr, PyObject *name) SPECIALIZATION_FAIL(LOAD_ATTR, SPEC_FAIL_EXPECTED_ERROR); goto fail; } - uint32_t version = maybe_function_get_version(fget, + uint32_t version = function_get_version(fget, 1, LOAD_ATTR); if (version == 0) { goto fail; @@ -826,11 +828,10 @@ _Py_Specialize_LoadAttr(PyObject *owner, _Py_CODEUNIT *instr, PyObject *name) goto fail; case GET_CALL_GETATTRIBUTE: { - getattrofunc getattro_slot = type->tp_getattro; - assert(getattro_slot == _Py_slot_tp_getattro); + assert(type->tp_getattro == _Py_slot_tp_getattro); assert(Py_IS_TYPE(descr, &PyFunction_Type)); _PyLoadMethodCache *lm_cache = (_PyLoadMethodCache *)(instr + 1); - uint32_t func_version = maybe_function_get_version(descr, 2, + uint32_t func_version = function_get_version(descr, 2, LOAD_ATTR); if (func_version == 0) { goto fail; @@ -1264,11 +1265,13 @@ function_kind(PyCodeObject *code) { return SIMPLE_FUNCTION; } +/* Returning 0 indicates a failure. */ static uint32_t -maybe_function_get_version(PyObject *o, int expected_argcount, int opcode) +function_get_version(PyObject *o, int expected_argcount, int opcode) { uint32_t version = 0; if (!Py_IS_TYPE(o, &PyFunction_Type)) { + SPECIALIZATION_FAIL(opcode, SPEC_FAIL_NOT_PY_FUNCTION); goto fail; } PyFunctionObject *func = (PyFunctionObject *)o; From cab77d8e2965b454c53304fdb0d85c8f93f574d5 Mon Sep 17 00:00:00 2001 From: Ken Jin <28750310+Fidget-Spinner@users.noreply.github.com> Date: Wed, 20 Jul 2022 16:43:46 +0800 Subject: [PATCH 11/17] revert rename --- Include/internal/pycore_typeobject.h | 2 +- Objects/typeobject.c | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/Include/internal/pycore_typeobject.h b/Include/internal/pycore_typeobject.h index f302e3cc6a5b04..a94a0744225114 100644 --- a/Include/internal/pycore_typeobject.h +++ b/Include/internal/pycore_typeobject.h @@ -46,7 +46,7 @@ extern void _PyStaticType_Dealloc(PyTypeObject *type); PyObject *_Py_slot_tp_getattro(PyObject *self, PyObject *name); PyObject *_Py_slot_tp_getattr_hook(PyObject *self, PyObject *name); -PyObject *_Py_call_attribute(PyObject *self, PyObject *attr, PyObject *name); + #ifdef __cplusplus } #endif diff --git a/Objects/typeobject.c b/Objects/typeobject.c index 385e712734b58a..804ebb6578a6e2 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -7784,8 +7784,8 @@ _Py_slot_tp_getattro(PyObject *self, PyObject *name) return vectorcall_method(&_Py_ID(__getattribute__), stack, 2); } -PyObject * -_Py_call_attribute(PyObject *self, PyObject *attr, PyObject *name) +static inline PyObject * +call_attribute(PyObject *self, PyObject *attr, PyObject *name) { PyObject *res, *descr = NULL; @@ -7819,7 +7819,7 @@ _Py_slot_tp_getattr_hook(PyObject *self, PyObject *name) method fully for each attribute lookup for classes with __getattr__, even when the attribute is present. So we use _PyType_Lookup and create the method only when needed, with - _Py_call_attribute. */ + call_attribute. */ getattr = _PyType_Lookup(tp, &_Py_ID(__getattr__)); if (getattr == NULL) { /* No __getattr__ hook: use a simpler dispatcher */ @@ -7831,7 +7831,7 @@ _Py_slot_tp_getattr_hook(PyObject *self, PyObject *name) method fully for each attribute lookup for classes with __getattr__, even when self has the default __getattribute__ method. So we use _PyType_Lookup and create the method only when - needed, with _Py_call_attribute. */ + needed, with call_attribute. */ getattribute = _PyType_Lookup(tp, &_Py_ID(__getattribute__)); if (getattribute == NULL || (Py_IS_TYPE(getattribute, &PyWrapperDescr_Type) && @@ -7840,12 +7840,12 @@ _Py_slot_tp_getattr_hook(PyObject *self, PyObject *name) res = PyObject_GenericGetAttr(self, name); else { Py_INCREF(getattribute); - res = _Py_call_attribute(self, getattribute, name); + res = call_attribute(self, getattribute, name); Py_DECREF(getattribute); } if (res == NULL && PyErr_ExceptionMatches(PyExc_AttributeError)) { PyErr_Clear(); - res = _Py_call_attribute(self, getattr, name); + res = call_attribute(self, getattr, name); } Py_DECREF(getattr); return res; From 81adecb61d6ba3999bf3523025edfab6a9fb83cd Mon Sep 17 00:00:00 2001 From: Ken Jin <28750310+Fidget-Spinner@users.noreply.github.com> Date: Wed, 20 Jul 2022 16:46:48 +0800 Subject: [PATCH 12/17] remove unsued failures --- Python/specialize.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/Python/specialize.c b/Python/specialize.c index 948b0a223e4696..736818c6fbdec1 100644 --- a/Python/specialize.c +++ b/Python/specialize.c @@ -386,9 +386,6 @@ miss_counter_start(void) { #define SPEC_FAIL_ATTR_HAS_MANAGED_DICT 25 #define SPEC_FAIL_ATTR_INSTANCE_ATTRIBUTE 26 #define SPEC_FAIL_ATTR_METACLASS_ATTRIBUTE 27 -#define SPEC_FAIL_ATTR_CUSTOM_GETATTRO 28 -#define SPEC_FAIL_ATTR_NOT_HEAP_TYPE 29 -#define SPEC_FAIL_ATTR_NOT_MATCHING_CUSTOM_GETATTRIBUTE 30 /* Binary subscr and store subscr */ @@ -545,6 +542,7 @@ specialize_module_load_attr(PyObject *owner, _Py_CODEUNIT *instr, } + /* Attribute specialization */ typedef enum { From 68456561f305a3e108e928e316e4c3648be48d4a Mon Sep 17 00:00:00 2001 From: Ken Jin <28750310+Fidget-Spinner@users.noreply.github.com> Date: Wed, 20 Jul 2022 18:49:18 +0800 Subject: [PATCH 13/17] Address code review --- Python/ceval.c | 5 +--- Python/specialize.c | 62 ++++++++++++++++++++++++++------------------- 2 files changed, 37 insertions(+), 30 deletions(-) diff --git a/Python/ceval.c b/Python/ceval.c index 19207c43f9e37e..e25b50030e5d5f 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -3735,11 +3735,8 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int PyObject *getattribute = read_obj(cache->descr); assert(Py_IS_TYPE(getattribute, &PyFunction_Type)); PyFunctionObject *f = (PyFunctionObject *)getattribute; - uint32_t func_version = read_u32(cache->keys_version); - assert(func_version != 0); - DEOPT_IF(f->func_version != func_version, LOAD_ATTR); PyCodeObject *code = (PyCodeObject *)f->func_code; - assert(code->co_argcount == 2); + DEOPT_IF(((PyCodeObject *)f->func_code)->co_argcount != 2, LOAD_ATTR); DEOPT_IF(!_PyThreadState_HasStackSpace(tstate, code->co_framesize), CALL); STAT_INC(LOAD_ATTR, hit); diff --git a/Python/specialize.c b/Python/specialize.c index 736818c6fbdec1..2e884b9eec68ff 100644 --- a/Python/specialize.c +++ b/Python/specialize.c @@ -498,7 +498,8 @@ miss_counter_start(void) { #define SPEC_FAIL_UNPACK_SEQUENCE_SEQUENCE 9 static int function_kind(PyCodeObject *code); -static uint32_t function_get_version(PyObject *o, int expected_argcount, int opcode); +static bool function_check_args(PyObject *o, int expected_argcount, int opcode); +static uint32_t function_get_version(PyObject *o, int opcode); static int specialize_module_load_attr(PyObject *owner, _Py_CODEUNIT *instr, @@ -559,14 +560,15 @@ typedef enum { ABSENT, /* Attribute is not present on the class */ DUNDER_CLASS, /* __class__ attribute */ GETSET_OVERRIDDEN, /* __getattribute__ or __setattr__ has been overridden */ - GET_CALL_GETATTRIBUTE /* Descriptor requires calling __getattribute__ */ + GETATTRIBUTE_IS_PYTHON_FUNCTION /* Descriptor requires calling a Python __getattribute__ */ } DescriptorClassification; static DescriptorClassification analyze_descriptor(PyTypeObject *type, PyObject *name, PyObject **descr, int store) { - int has_getattr = 0; + bool has_getattr = false; + bool has_custom_getattribute = false; if (store) { if (type->tp_setattro != PyObject_GenericSetAttr) { *descr = NULL; @@ -595,15 +597,15 @@ analyze_descriptor(PyTypeObject *type, PyObject *name, PyObject **descr, int sto } PyObject *getattribute = _PyType_Lookup(type, &_Py_ID(__getattribute__)); - bool custom_getattribute = !(getattribute == NULL || - (Py_IS_TYPE(getattribute, &PyWrapperDescr_Type) && + has_custom_getattribute = getattribute != NULL && + !(Py_IS_TYPE(getattribute, &PyWrapperDescr_Type) && ((PyWrapperDescrObject *)getattribute)->d_wrapped == - (void *)PyObject_GenericGetAttr)); - if (custom_getattribute) { + (void *)PyObject_GenericGetAttr); + if (has_custom_getattribute) { if (getattro_slot == _Py_slot_tp_getattro && Py_IS_TYPE(getattribute, &PyFunction_Type)) { *descr = getattribute; - return GET_CALL_GETATTRIBUTE; + return GETATTRIBUTE_IS_PYTHON_FUNCTION; } *descr = NULL; return GETSET_OVERRIDDEN; @@ -773,8 +775,12 @@ _Py_Specialize_LoadAttr(PyObject *owner, _Py_CODEUNIT *instr, PyObject *name) SPECIALIZATION_FAIL(LOAD_ATTR, SPEC_FAIL_EXPECTED_ERROR); goto fail; } - uint32_t version = function_get_version(fget, - 1, LOAD_ATTR); + if (!Py_IS_TYPE(fget, &PyFunction_Type)) { + SPECIALIZATION_FAIL(LOAD_ATTR, SPEC_FAIL_NOT_PY_FUNCTION); + goto fail; + } + uint32_t version = function_check_args(fget, 1, LOAD_ATTR) && + function_get_version(fget, LOAD_ATTR); if (version == 0) { goto fail; } @@ -824,19 +830,18 @@ _Py_Specialize_LoadAttr(PyObject *owner, _Py_CODEUNIT *instr, PyObject *name) case GETSET_OVERRIDDEN: SPECIALIZATION_FAIL(LOAD_ATTR, SPEC_FAIL_OVERRIDDEN); goto fail; - case GET_CALL_GETATTRIBUTE: + case GETATTRIBUTE_IS_PYTHON_FUNCTION: { assert(type->tp_getattro == _Py_slot_tp_getattro); assert(Py_IS_TYPE(descr, &PyFunction_Type)); _PyLoadMethodCache *lm_cache = (_PyLoadMethodCache *)(instr + 1); - uint32_t func_version = function_get_version(descr, 2, - LOAD_ATTR); + uint32_t func_version = function_check_args(descr, 2, LOAD_ATTR) && + function_get_version(descr, LOAD_ATTR); if (func_version == 0) { goto fail; } /* borrowed */ write_obj(lm_cache->descr, descr); - write_u32(lm_cache->keys_version, func_version); write_u32(lm_cache->type_version, type->tp_version_tag); _Py_SET_OPCODE(*instr, LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN); goto success; @@ -919,7 +924,7 @@ _Py_Specialize_StoreAttr(PyObject *owner, _Py_CODEUNIT *instr, PyObject *name) case MUTABLE: SPECIALIZATION_FAIL(STORE_ATTR, SPEC_FAIL_ATTR_MUTABLE_CLASS); goto fail; - case GET_CALL_GETATTRIBUTE: + case GETATTRIBUTE_IS_PYTHON_FUNCTION: case GETSET_OVERRIDDEN: SPECIALIZATION_FAIL(STORE_ATTR, SPEC_FAIL_OVERRIDDEN); goto fail; @@ -1262,27 +1267,32 @@ function_kind(PyCodeObject *code) { return SIMPLE_FUNCTION; } -/* Returning 0 indicates a failure. */ -static uint32_t -function_get_version(PyObject *o, int expected_argcount, int opcode) +/* Returning false indicates a failure. */ +static bool +function_check_args(PyObject *o, int expected_argcount, int opcode) { - uint32_t version = 0; - if (!Py_IS_TYPE(o, &PyFunction_Type)) { - SPECIALIZATION_FAIL(opcode, SPEC_FAIL_NOT_PY_FUNCTION); - goto fail; - } + assert(Py_IS_TYPE(o, &PyFunction_Type)); PyFunctionObject *func = (PyFunctionObject *)o; PyCodeObject *fcode = (PyCodeObject *)func->func_code; int kind = function_kind(fcode); if (kind != SIMPLE_FUNCTION) { SPECIALIZATION_FAIL(opcode, kind); - goto fail; + return false; } if (fcode->co_argcount != expected_argcount) { SPECIALIZATION_FAIL(opcode, SPEC_FAIL_WRONG_NUMBER_ARGUMENTS); - goto fail; + return false; } - version = _PyFunction_GetVersionForCurrentState(func); + return true; +} + +/* Returning 0 indicates a failure. */ +static uint32_t +function_get_version(PyObject *o, int opcode) +{ + assert(Py_IS_TYPE(o, &PyFunction_Type)); + PyFunctionObject *func = (PyFunctionObject *)o; + uint32_t version = _PyFunction_GetVersionForCurrentState(func); if (version == 0) { SPECIALIZATION_FAIL(opcode, SPEC_FAIL_OUT_OF_VERSIONS); goto fail; From 9412f97e64185fafa6501e3174d741d2d1557ee3 Mon Sep 17 00:00:00 2001 From: Ken Jin <28750310+Fidget-Spinner@users.noreply.github.com> Date: Wed, 20 Jul 2022 23:34:26 +0800 Subject: [PATCH 14/17] Use Mark's code Co-Authored-By: Mark Shannon --- Include/internal/pycore_code.h | 1 + Python/pylifecycle.c | 3 +++ Python/specialize.c | 47 +++++++++++++++------------------- 3 files changed, 24 insertions(+), 27 deletions(-) diff --git a/Include/internal/pycore_code.h b/Include/internal/pycore_code.h index 61e40eb8a94c24..7d5fe941fcb4d0 100644 --- a/Include/internal/pycore_code.h +++ b/Include/internal/pycore_code.h @@ -118,6 +118,7 @@ struct callable_cache { PyObject *isinstance; PyObject *len; PyObject *list_append; + PyObject *object__getattribute__; }; /* "Locals plus" for a code object is the set of locals + cell vars + diff --git a/Python/pylifecycle.c b/Python/pylifecycle.c index 65e7f23e963b5f..6246da660035a8 100644 --- a/Python/pylifecycle.c +++ b/Python/pylifecycle.c @@ -787,6 +787,9 @@ pycore_init_builtins(PyThreadState *tstate) PyObject *list_append = _PyType_Lookup(&PyList_Type, &_Py_ID(append)); assert(list_append); interp->callable_cache.list_append = list_append; + PyObject *object__getattribute__ = _PyType_Lookup(&PyBaseObject_Type, &_Py_ID(__getattribute__)); + assert(object__getattribute__); + interp->callable_cache.object__getattribute__ = object__getattribute__; if (_PyBuiltins_AddExceptions(bimod) < 0) { return _PyStatus_ERR("failed to add exceptions to builtins"); diff --git a/Python/specialize.c b/Python/specialize.c index 2e884b9eec68ff..957a0cc23be3cd 100644 --- a/Python/specialize.c +++ b/Python/specialize.c @@ -568,7 +568,6 @@ static DescriptorClassification analyze_descriptor(PyTypeObject *type, PyObject *name, PyObject **descr, int store) { bool has_getattr = false; - bool has_custom_getattribute = false; if (store) { if (type->tp_setattro != PyObject_GenericSetAttr) { *descr = NULL; @@ -576,37 +575,28 @@ analyze_descriptor(PyTypeObject *type, PyObject *name, PyObject **descr, int sto } } else { - if (type->tp_getattro != PyObject_GenericGetAttr) { - getattrofunc getattro_slot = type->tp_getattro; - /* The following comment is copied from typeobject.c */ - /* There are two slot dispatch functions for tp_getattro. - - - _Py_slot_tp_getattro() is used when __getattribute__ is overridden - but no __getattr__ hook is present; - - - _Py_slot_tp_getattr_hook() is used when a __getattr__ hook is present. - - The code in update_one_slot() always installs - _Py_slot_tp_getattr_hook(); this detects the absence of - __getattr__ and then installs the simpler slot if necessary. */ - /* Using some custom tp_getattro, like super() objects */ - if (getattro_slot != _Py_slot_tp_getattr_hook && - getattro_slot != _Py_slot_tp_getattro) { - *descr = NULL; - return GETSET_OVERRIDDEN; - } + getattrofunc getattro_slot = type->tp_getattro; + if (getattro_slot == PyObject_GenericGetAttr) { + /* Normal attribute lookup; */ + has_getattr = false; + } + else if (getattro_slot == _Py_slot_tp_getattr_hook || + getattro_slot == _Py_slot_tp_getattro) { + /* One or both of __getattribute__ or __getattr__ may have been + overridden See typeobject.c for why these functions are special. */ PyObject *getattribute = _PyType_Lookup(type, &_Py_ID(__getattribute__)); - has_custom_getattribute = getattribute != NULL && - !(Py_IS_TYPE(getattribute, &PyWrapperDescr_Type) && - ((PyWrapperDescrObject *)getattribute)->d_wrapped == - (void *)PyObject_GenericGetAttr); + PyInterpreterState *interp = _PyInterpreterState_GET(); + bool has_custom_getattribute = getattribute != NULL && + getattribute != interp->callable_cache.object__getattribute__; + has_getattr = _PyType_Lookup(type, &_Py_ID(__getattr__)) != NULL; if (has_custom_getattribute) { - if (getattro_slot == _Py_slot_tp_getattro && - Py_IS_TYPE(getattribute, &PyFunction_Type)) { + if (!has_getattr && Py_IS_TYPE(getattribute, &PyFunction_Type)) { *descr = getattribute; return GETATTRIBUTE_IS_PYTHON_FUNCTION; } + /* Potentially both __getattr__ and __getattribute__ are set. + Too complicated */ *descr = NULL; return GETSET_OVERRIDDEN; } @@ -617,7 +607,10 @@ analyze_descriptor(PyTypeObject *type, PyObject *name, PyObject **descr, int sto raised. This means some specializations, e.g. specializing for property() isn't safe. */ - has_getattr = (getattro_slot == _Py_slot_tp_getattr_hook); + } + else { + *descr = NULL; + return GETSET_OVERRIDDEN; } } PyObject *descriptor = _PyType_Lookup(type, name); From c6f86107afb2f298d8f4aa9ceea8116b476f405a Mon Sep 17 00:00:00 2001 From: Ken Jin <28750310+Fidget-Spinner@users.noreply.github.com> Date: Wed, 20 Jul 2022 23:42:05 +0800 Subject: [PATCH 15/17] Clean up code a little --- Python/specialize.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/Python/specialize.c b/Python/specialize.c index 957a0cc23be3cd..73dfc774d0d9d1 100644 --- a/Python/specialize.c +++ b/Python/specialize.c @@ -1288,11 +1288,9 @@ function_get_version(PyObject *o, int opcode) uint32_t version = _PyFunction_GetVersionForCurrentState(func); if (version == 0) { SPECIALIZATION_FAIL(opcode, SPEC_FAIL_OUT_OF_VERSIONS); - goto fail; + return 0; } return version; -fail: - return 0; } int From cb7d01edfd5052f92f8fc47656bbf9539febf415 Mon Sep 17 00:00:00 2001 From: Ken Jin <28750310+Fidget-Spinner@users.noreply.github.com> Date: Sun, 14 Aug 2022 15:20:09 +0800 Subject: [PATCH 16/17] Update pycore_opcode.h --- Include/internal/pycore_opcode.h | 593 +++++++++++++++++++++++++++++++ 1 file changed, 593 insertions(+) diff --git a/Include/internal/pycore_opcode.h b/Include/internal/pycore_opcode.h index e69de29bb2d1d6..6906cd5c78810e 100644 --- a/Include/internal/pycore_opcode.h +++ b/Include/internal/pycore_opcode.h @@ -0,0 +1,593 @@ +// Auto-generated by Tools/scripts/generate_opcode_h.py from Lib/opcode.py + +#ifndef Py_INTERNAL_OPCODE_H +#define Py_INTERNAL_OPCODE_H +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef Py_BUILD_CORE +# error "this header requires Py_BUILD_CORE define" +#endif + +#include "opcode.h" + +extern const uint8_t _PyOpcode_Caches[256]; + +extern const uint8_t _PyOpcode_Deopt[256]; + +#ifdef NEED_OPCODE_TABLES +static const uint32_t _PyOpcode_RelativeJump[9] = { + 0U, + 0U, + 536870912U, + 135118848U, + 4163U, + 122880U, + 0U, + 0U, + 1008U, +}; +static const uint32_t _PyOpcode_Jump[9] = { + 0U, + 0U, + 536870912U, + 135118848U, + 4163U, + 122880U, + 0U, + 0U, + 1008U, +}; + +const uint8_t _PyOpcode_Caches[256] = { + [BINARY_SUBSCR] = 4, + [STORE_SUBSCR] = 1, + [UNPACK_SEQUENCE] = 1, + [FOR_ITER] = 1, + [STORE_ATTR] = 4, + [LOAD_ATTR] = 9, + [COMPARE_OP] = 2, + [LOAD_GLOBAL] = 5, + [BINARY_OP] = 1, + [CALL] = 4, +}; + +const uint8_t _PyOpcode_Deopt[256] = { + [ASYNC_GEN_WRAP] = ASYNC_GEN_WRAP, + [BEFORE_ASYNC_WITH] = BEFORE_ASYNC_WITH, + [BEFORE_WITH] = BEFORE_WITH, + [BINARY_OP] = BINARY_OP, + [BINARY_OP_ADAPTIVE] = BINARY_OP, + [BINARY_OP_ADD_FLOAT] = BINARY_OP, + [BINARY_OP_ADD_INT] = BINARY_OP, + [BINARY_OP_ADD_UNICODE] = BINARY_OP, + [BINARY_OP_INPLACE_ADD_UNICODE] = BINARY_OP, + [BINARY_OP_MULTIPLY_FLOAT] = BINARY_OP, + [BINARY_OP_MULTIPLY_INT] = BINARY_OP, + [BINARY_OP_SUBTRACT_FLOAT] = BINARY_OP, + [BINARY_OP_SUBTRACT_INT] = BINARY_OP, + [BINARY_SLICE] = BINARY_SLICE, + [BINARY_SUBSCR] = BINARY_SUBSCR, + [BINARY_SUBSCR_ADAPTIVE] = BINARY_SUBSCR, + [BINARY_SUBSCR_DICT] = BINARY_SUBSCR, + [BINARY_SUBSCR_GETITEM] = BINARY_SUBSCR, + [BINARY_SUBSCR_LIST_INT] = BINARY_SUBSCR, + [BINARY_SUBSCR_TUPLE_INT] = BINARY_SUBSCR, + [BUILD_CONST_KEY_MAP] = BUILD_CONST_KEY_MAP, + [BUILD_LIST] = BUILD_LIST, + [BUILD_MAP] = BUILD_MAP, + [BUILD_SET] = BUILD_SET, + [BUILD_SLICE] = BUILD_SLICE, + [BUILD_STRING] = BUILD_STRING, + [BUILD_TUPLE] = BUILD_TUPLE, + [CACHE] = CACHE, + [CALL] = CALL, + [CALL_ADAPTIVE] = CALL, + [CALL_BOUND_METHOD_EXACT_ARGS] = CALL, + [CALL_BUILTIN_CLASS] = CALL, + [CALL_BUILTIN_FAST_WITH_KEYWORDS] = CALL, + [CALL_FUNCTION_EX] = CALL_FUNCTION_EX, + [CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS] = CALL, + [CALL_NO_KW_BUILTIN_FAST] = CALL, + [CALL_NO_KW_BUILTIN_O] = CALL, + [CALL_NO_KW_ISINSTANCE] = CALL, + [CALL_NO_KW_LEN] = CALL, + [CALL_NO_KW_LIST_APPEND] = CALL, + [CALL_NO_KW_METHOD_DESCRIPTOR_FAST] = CALL, + [CALL_NO_KW_METHOD_DESCRIPTOR_NOARGS] = CALL, + [CALL_NO_KW_METHOD_DESCRIPTOR_O] = CALL, + [CALL_NO_KW_STR_1] = CALL, + [CALL_NO_KW_TUPLE_1] = CALL, + [CALL_NO_KW_TYPE_1] = CALL, + [CALL_PY_EXACT_ARGS] = CALL, + [CALL_PY_WITH_DEFAULTS] = CALL, + [CHECK_EG_MATCH] = CHECK_EG_MATCH, + [CHECK_EXC_MATCH] = CHECK_EXC_MATCH, + [COMPARE_OP] = COMPARE_OP, + [COMPARE_OP_ADAPTIVE] = COMPARE_OP, + [COMPARE_OP_FLOAT_JUMP] = COMPARE_OP, + [COMPARE_OP_INT_JUMP] = COMPARE_OP, + [COMPARE_OP_STR_JUMP] = COMPARE_OP, + [CONTAINS_OP] = CONTAINS_OP, + [COPY] = COPY, + [COPY_FREE_VARS] = COPY_FREE_VARS, + [DELETE_ATTR] = DELETE_ATTR, + [DELETE_DEREF] = DELETE_DEREF, + [DELETE_FAST] = DELETE_FAST, + [DELETE_GLOBAL] = DELETE_GLOBAL, + [DELETE_NAME] = DELETE_NAME, + [DELETE_SUBSCR] = DELETE_SUBSCR, + [DICT_MERGE] = DICT_MERGE, + [DICT_UPDATE] = DICT_UPDATE, + [END_ASYNC_FOR] = END_ASYNC_FOR, + [EXTENDED_ARG] = EXTENDED_ARG, + [EXTENDED_ARG_QUICK] = EXTENDED_ARG, + [FORMAT_VALUE] = FORMAT_VALUE, + [FOR_ITER] = FOR_ITER, + [FOR_ITER_ADAPTIVE] = FOR_ITER, + [FOR_ITER_LIST] = FOR_ITER, + [FOR_ITER_RANGE] = FOR_ITER, + [GET_AITER] = GET_AITER, + [GET_ANEXT] = GET_ANEXT, + [GET_AWAITABLE] = GET_AWAITABLE, + [GET_ITER] = GET_ITER, + [GET_LEN] = GET_LEN, + [GET_YIELD_FROM_ITER] = GET_YIELD_FROM_ITER, + [IMPORT_FROM] = IMPORT_FROM, + [IMPORT_NAME] = IMPORT_NAME, + [IMPORT_STAR] = IMPORT_STAR, + [IS_OP] = IS_OP, + [JUMP_BACKWARD] = JUMP_BACKWARD, + [JUMP_BACKWARD_NO_INTERRUPT] = JUMP_BACKWARD_NO_INTERRUPT, + [JUMP_BACKWARD_QUICK] = JUMP_BACKWARD, + [JUMP_FORWARD] = JUMP_FORWARD, + [JUMP_IF_FALSE_OR_POP] = JUMP_IF_FALSE_OR_POP, + [JUMP_IF_TRUE_OR_POP] = JUMP_IF_TRUE_OR_POP, + [KW_NAMES] = KW_NAMES, + [LIST_APPEND] = LIST_APPEND, + [LIST_EXTEND] = LIST_EXTEND, + [LIST_TO_TUPLE] = LIST_TO_TUPLE, + [LOAD_ASSERTION_ERROR] = LOAD_ASSERTION_ERROR, + [LOAD_ATTR] = LOAD_ATTR, + [LOAD_ATTR_ADAPTIVE] = LOAD_ATTR, + [LOAD_ATTR_CLASS] = LOAD_ATTR, + [LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN] = LOAD_ATTR, + [LOAD_ATTR_INSTANCE_VALUE] = LOAD_ATTR, + [LOAD_ATTR_METHOD_LAZY_DICT] = LOAD_ATTR, + [LOAD_ATTR_METHOD_NO_DICT] = LOAD_ATTR, + [LOAD_ATTR_METHOD_WITH_DICT] = LOAD_ATTR, + [LOAD_ATTR_METHOD_WITH_VALUES] = LOAD_ATTR, + [LOAD_ATTR_MODULE] = LOAD_ATTR, + [LOAD_ATTR_PROPERTY] = LOAD_ATTR, + [LOAD_ATTR_SLOT] = LOAD_ATTR, + [LOAD_ATTR_WITH_HINT] = LOAD_ATTR, + [LOAD_BUILD_CLASS] = LOAD_BUILD_CLASS, + [LOAD_CLASSDEREF] = LOAD_CLASSDEREF, + [LOAD_CLOSURE] = LOAD_CLOSURE, + [LOAD_CONST] = LOAD_CONST, + [LOAD_CONST__LOAD_FAST] = LOAD_CONST, + [LOAD_DEREF] = LOAD_DEREF, + [LOAD_FAST] = LOAD_FAST, + [LOAD_FAST_CHECK] = LOAD_FAST_CHECK, + [LOAD_FAST__LOAD_CONST] = LOAD_FAST, + [LOAD_FAST__LOAD_FAST] = LOAD_FAST, + [LOAD_GLOBAL] = LOAD_GLOBAL, + [LOAD_GLOBAL_ADAPTIVE] = LOAD_GLOBAL, + [LOAD_GLOBAL_BUILTIN] = LOAD_GLOBAL, + [LOAD_GLOBAL_MODULE] = LOAD_GLOBAL, + [LOAD_NAME] = LOAD_NAME, + [MAKE_CELL] = MAKE_CELL, + [MAKE_FUNCTION] = MAKE_FUNCTION, + [MAP_ADD] = MAP_ADD, + [MATCH_CLASS] = MATCH_CLASS, + [MATCH_KEYS] = MATCH_KEYS, + [MATCH_MAPPING] = MATCH_MAPPING, + [MATCH_SEQUENCE] = MATCH_SEQUENCE, + [NOP] = NOP, + [POP_EXCEPT] = POP_EXCEPT, + [POP_JUMP_BACKWARD_IF_FALSE] = POP_JUMP_BACKWARD_IF_FALSE, + [POP_JUMP_BACKWARD_IF_NONE] = POP_JUMP_BACKWARD_IF_NONE, + [POP_JUMP_BACKWARD_IF_NOT_NONE] = POP_JUMP_BACKWARD_IF_NOT_NONE, + [POP_JUMP_BACKWARD_IF_TRUE] = POP_JUMP_BACKWARD_IF_TRUE, + [POP_JUMP_FORWARD_IF_FALSE] = POP_JUMP_FORWARD_IF_FALSE, + [POP_JUMP_FORWARD_IF_NONE] = POP_JUMP_FORWARD_IF_NONE, + [POP_JUMP_FORWARD_IF_NOT_NONE] = POP_JUMP_FORWARD_IF_NOT_NONE, + [POP_JUMP_FORWARD_IF_TRUE] = POP_JUMP_FORWARD_IF_TRUE, + [POP_TOP] = POP_TOP, + [PREP_RERAISE_STAR] = PREP_RERAISE_STAR, + [PRINT_EXPR] = PRINT_EXPR, + [PUSH_EXC_INFO] = PUSH_EXC_INFO, + [PUSH_NULL] = PUSH_NULL, + [RAISE_VARARGS] = RAISE_VARARGS, + [RERAISE] = RERAISE, + [RESUME] = RESUME, + [RESUME_QUICK] = RESUME, + [RETURN_GENERATOR] = RETURN_GENERATOR, + [RETURN_VALUE] = RETURN_VALUE, + [SEND] = SEND, + [SETUP_ANNOTATIONS] = SETUP_ANNOTATIONS, + [SET_ADD] = SET_ADD, + [SET_UPDATE] = SET_UPDATE, + [STORE_ATTR] = STORE_ATTR, + [STORE_ATTR_ADAPTIVE] = STORE_ATTR, + [STORE_ATTR_INSTANCE_VALUE] = STORE_ATTR, + [STORE_ATTR_SLOT] = STORE_ATTR, + [STORE_ATTR_WITH_HINT] = STORE_ATTR, + [STORE_DEREF] = STORE_DEREF, + [STORE_FAST] = STORE_FAST, + [STORE_FAST__LOAD_FAST] = STORE_FAST, + [STORE_FAST__STORE_FAST] = STORE_FAST, + [STORE_GLOBAL] = STORE_GLOBAL, + [STORE_NAME] = STORE_NAME, + [STORE_SLICE] = STORE_SLICE, + [STORE_SUBSCR] = STORE_SUBSCR, + [STORE_SUBSCR_ADAPTIVE] = STORE_SUBSCR, + [STORE_SUBSCR_DICT] = STORE_SUBSCR, + [STORE_SUBSCR_LIST_INT] = STORE_SUBSCR, + [SWAP] = SWAP, + [UNARY_INVERT] = UNARY_INVERT, + [UNARY_NEGATIVE] = UNARY_NEGATIVE, + [UNARY_NOT] = UNARY_NOT, + [UNARY_POSITIVE] = UNARY_POSITIVE, + [UNPACK_EX] = UNPACK_EX, + [UNPACK_SEQUENCE] = UNPACK_SEQUENCE, + [UNPACK_SEQUENCE_ADAPTIVE] = UNPACK_SEQUENCE, + [UNPACK_SEQUENCE_LIST] = UNPACK_SEQUENCE, + [UNPACK_SEQUENCE_TUPLE] = UNPACK_SEQUENCE, + [UNPACK_SEQUENCE_TWO_TUPLE] = UNPACK_SEQUENCE, + [WITH_EXCEPT_START] = WITH_EXCEPT_START, + [YIELD_VALUE] = YIELD_VALUE, +}; +#endif // NEED_OPCODE_TABLES + +#ifdef Py_DEBUG +static const char *const _PyOpcode_OpName[267] = { + [CACHE] = "CACHE", + [POP_TOP] = "POP_TOP", + [PUSH_NULL] = "PUSH_NULL", + [BINARY_OP_ADAPTIVE] = "BINARY_OP_ADAPTIVE", + [BINARY_OP_ADD_FLOAT] = "BINARY_OP_ADD_FLOAT", + [BINARY_OP_ADD_INT] = "BINARY_OP_ADD_INT", + [BINARY_OP_ADD_UNICODE] = "BINARY_OP_ADD_UNICODE", + [BINARY_OP_INPLACE_ADD_UNICODE] = "BINARY_OP_INPLACE_ADD_UNICODE", + [BINARY_OP_MULTIPLY_FLOAT] = "BINARY_OP_MULTIPLY_FLOAT", + [NOP] = "NOP", + [UNARY_POSITIVE] = "UNARY_POSITIVE", + [UNARY_NEGATIVE] = "UNARY_NEGATIVE", + [UNARY_NOT] = "UNARY_NOT", + [BINARY_OP_MULTIPLY_INT] = "BINARY_OP_MULTIPLY_INT", + [BINARY_OP_SUBTRACT_FLOAT] = "BINARY_OP_SUBTRACT_FLOAT", + [UNARY_INVERT] = "UNARY_INVERT", + [BINARY_OP_SUBTRACT_INT] = "BINARY_OP_SUBTRACT_INT", + [BINARY_SUBSCR_ADAPTIVE] = "BINARY_SUBSCR_ADAPTIVE", + [BINARY_SUBSCR_DICT] = "BINARY_SUBSCR_DICT", + [BINARY_SUBSCR_GETITEM] = "BINARY_SUBSCR_GETITEM", + [BINARY_SUBSCR_LIST_INT] = "BINARY_SUBSCR_LIST_INT", + [BINARY_SUBSCR_TUPLE_INT] = "BINARY_SUBSCR_TUPLE_INT", + [CALL_ADAPTIVE] = "CALL_ADAPTIVE", + [CALL_PY_EXACT_ARGS] = "CALL_PY_EXACT_ARGS", + [CALL_PY_WITH_DEFAULTS] = "CALL_PY_WITH_DEFAULTS", + [BINARY_SUBSCR] = "BINARY_SUBSCR", + [BINARY_SLICE] = "BINARY_SLICE", + [STORE_SLICE] = "STORE_SLICE", + [CALL_BOUND_METHOD_EXACT_ARGS] = "CALL_BOUND_METHOD_EXACT_ARGS", + [CALL_BUILTIN_CLASS] = "CALL_BUILTIN_CLASS", + [GET_LEN] = "GET_LEN", + [MATCH_MAPPING] = "MATCH_MAPPING", + [MATCH_SEQUENCE] = "MATCH_SEQUENCE", + [MATCH_KEYS] = "MATCH_KEYS", + [CALL_BUILTIN_FAST_WITH_KEYWORDS] = "CALL_BUILTIN_FAST_WITH_KEYWORDS", + [PUSH_EXC_INFO] = "PUSH_EXC_INFO", + [CHECK_EXC_MATCH] = "CHECK_EXC_MATCH", + [CHECK_EG_MATCH] = "CHECK_EG_MATCH", + [CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS] = "CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS", + [CALL_NO_KW_BUILTIN_FAST] = "CALL_NO_KW_BUILTIN_FAST", + [CALL_NO_KW_BUILTIN_O] = "CALL_NO_KW_BUILTIN_O", + [CALL_NO_KW_ISINSTANCE] = "CALL_NO_KW_ISINSTANCE", + [CALL_NO_KW_LEN] = "CALL_NO_KW_LEN", + [CALL_NO_KW_LIST_APPEND] = "CALL_NO_KW_LIST_APPEND", + [CALL_NO_KW_METHOD_DESCRIPTOR_FAST] = "CALL_NO_KW_METHOD_DESCRIPTOR_FAST", + [CALL_NO_KW_METHOD_DESCRIPTOR_NOARGS] = "CALL_NO_KW_METHOD_DESCRIPTOR_NOARGS", + [CALL_NO_KW_METHOD_DESCRIPTOR_O] = "CALL_NO_KW_METHOD_DESCRIPTOR_O", + [CALL_NO_KW_STR_1] = "CALL_NO_KW_STR_1", + [CALL_NO_KW_TUPLE_1] = "CALL_NO_KW_TUPLE_1", + [WITH_EXCEPT_START] = "WITH_EXCEPT_START", + [GET_AITER] = "GET_AITER", + [GET_ANEXT] = "GET_ANEXT", + [BEFORE_ASYNC_WITH] = "BEFORE_ASYNC_WITH", + [BEFORE_WITH] = "BEFORE_WITH", + [END_ASYNC_FOR] = "END_ASYNC_FOR", + [CALL_NO_KW_TYPE_1] = "CALL_NO_KW_TYPE_1", + [COMPARE_OP_ADAPTIVE] = "COMPARE_OP_ADAPTIVE", + [COMPARE_OP_FLOAT_JUMP] = "COMPARE_OP_FLOAT_JUMP", + [COMPARE_OP_INT_JUMP] = "COMPARE_OP_INT_JUMP", + [COMPARE_OP_STR_JUMP] = "COMPARE_OP_STR_JUMP", + [STORE_SUBSCR] = "STORE_SUBSCR", + [DELETE_SUBSCR] = "DELETE_SUBSCR", + [EXTENDED_ARG_QUICK] = "EXTENDED_ARG_QUICK", + [FOR_ITER_ADAPTIVE] = "FOR_ITER_ADAPTIVE", + [FOR_ITER_LIST] = "FOR_ITER_LIST", + [FOR_ITER_RANGE] = "FOR_ITER_RANGE", + [JUMP_BACKWARD_QUICK] = "JUMP_BACKWARD_QUICK", + [LOAD_ATTR_ADAPTIVE] = "LOAD_ATTR_ADAPTIVE", + [GET_ITER] = "GET_ITER", + [GET_YIELD_FROM_ITER] = "GET_YIELD_FROM_ITER", + [PRINT_EXPR] = "PRINT_EXPR", + [LOAD_BUILD_CLASS] = "LOAD_BUILD_CLASS", + [LOAD_ATTR_CLASS] = "LOAD_ATTR_CLASS", + [LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN] = "LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN", + [LOAD_ASSERTION_ERROR] = "LOAD_ASSERTION_ERROR", + [RETURN_GENERATOR] = "RETURN_GENERATOR", + [LOAD_ATTR_INSTANCE_VALUE] = "LOAD_ATTR_INSTANCE_VALUE", + [LOAD_ATTR_MODULE] = "LOAD_ATTR_MODULE", + [LOAD_ATTR_PROPERTY] = "LOAD_ATTR_PROPERTY", + [LOAD_ATTR_SLOT] = "LOAD_ATTR_SLOT", + [LOAD_ATTR_WITH_HINT] = "LOAD_ATTR_WITH_HINT", + [LOAD_ATTR_METHOD_LAZY_DICT] = "LOAD_ATTR_METHOD_LAZY_DICT", + [LIST_TO_TUPLE] = "LIST_TO_TUPLE", + [RETURN_VALUE] = "RETURN_VALUE", + [IMPORT_STAR] = "IMPORT_STAR", + [SETUP_ANNOTATIONS] = "SETUP_ANNOTATIONS", + [LOAD_ATTR_METHOD_NO_DICT] = "LOAD_ATTR_METHOD_NO_DICT", + [ASYNC_GEN_WRAP] = "ASYNC_GEN_WRAP", + [PREP_RERAISE_STAR] = "PREP_RERAISE_STAR", + [POP_EXCEPT] = "POP_EXCEPT", + [STORE_NAME] = "STORE_NAME", + [DELETE_NAME] = "DELETE_NAME", + [UNPACK_SEQUENCE] = "UNPACK_SEQUENCE", + [FOR_ITER] = "FOR_ITER", + [UNPACK_EX] = "UNPACK_EX", + [STORE_ATTR] = "STORE_ATTR", + [DELETE_ATTR] = "DELETE_ATTR", + [STORE_GLOBAL] = "STORE_GLOBAL", + [DELETE_GLOBAL] = "DELETE_GLOBAL", + [SWAP] = "SWAP", + [LOAD_CONST] = "LOAD_CONST", + [LOAD_NAME] = "LOAD_NAME", + [BUILD_TUPLE] = "BUILD_TUPLE", + [BUILD_LIST] = "BUILD_LIST", + [BUILD_SET] = "BUILD_SET", + [BUILD_MAP] = "BUILD_MAP", + [LOAD_ATTR] = "LOAD_ATTR", + [COMPARE_OP] = "COMPARE_OP", + [IMPORT_NAME] = "IMPORT_NAME", + [IMPORT_FROM] = "IMPORT_FROM", + [JUMP_FORWARD] = "JUMP_FORWARD", + [JUMP_IF_FALSE_OR_POP] = "JUMP_IF_FALSE_OR_POP", + [JUMP_IF_TRUE_OR_POP] = "JUMP_IF_TRUE_OR_POP", + [LOAD_ATTR_METHOD_WITH_DICT] = "LOAD_ATTR_METHOD_WITH_DICT", + [POP_JUMP_FORWARD_IF_FALSE] = "POP_JUMP_FORWARD_IF_FALSE", + [POP_JUMP_FORWARD_IF_TRUE] = "POP_JUMP_FORWARD_IF_TRUE", + [LOAD_GLOBAL] = "LOAD_GLOBAL", + [IS_OP] = "IS_OP", + [CONTAINS_OP] = "CONTAINS_OP", + [RERAISE] = "RERAISE", + [COPY] = "COPY", + [LOAD_ATTR_METHOD_WITH_VALUES] = "LOAD_ATTR_METHOD_WITH_VALUES", + [BINARY_OP] = "BINARY_OP", + [SEND] = "SEND", + [LOAD_FAST] = "LOAD_FAST", + [STORE_FAST] = "STORE_FAST", + [DELETE_FAST] = "DELETE_FAST", + [LOAD_FAST_CHECK] = "LOAD_FAST_CHECK", + [POP_JUMP_FORWARD_IF_NOT_NONE] = "POP_JUMP_FORWARD_IF_NOT_NONE", + [POP_JUMP_FORWARD_IF_NONE] = "POP_JUMP_FORWARD_IF_NONE", + [RAISE_VARARGS] = "RAISE_VARARGS", + [GET_AWAITABLE] = "GET_AWAITABLE", + [MAKE_FUNCTION] = "MAKE_FUNCTION", + [BUILD_SLICE] = "BUILD_SLICE", + [JUMP_BACKWARD_NO_INTERRUPT] = "JUMP_BACKWARD_NO_INTERRUPT", + [MAKE_CELL] = "MAKE_CELL", + [LOAD_CLOSURE] = "LOAD_CLOSURE", + [LOAD_DEREF] = "LOAD_DEREF", + [STORE_DEREF] = "STORE_DEREF", + [DELETE_DEREF] = "DELETE_DEREF", + [JUMP_BACKWARD] = "JUMP_BACKWARD", + [LOAD_CONST__LOAD_FAST] = "LOAD_CONST__LOAD_FAST", + [CALL_FUNCTION_EX] = "CALL_FUNCTION_EX", + [LOAD_FAST__LOAD_CONST] = "LOAD_FAST__LOAD_CONST", + [EXTENDED_ARG] = "EXTENDED_ARG", + [LIST_APPEND] = "LIST_APPEND", + [SET_ADD] = "SET_ADD", + [MAP_ADD] = "MAP_ADD", + [LOAD_CLASSDEREF] = "LOAD_CLASSDEREF", + [COPY_FREE_VARS] = "COPY_FREE_VARS", + [YIELD_VALUE] = "YIELD_VALUE", + [RESUME] = "RESUME", + [MATCH_CLASS] = "MATCH_CLASS", + [LOAD_FAST__LOAD_FAST] = "LOAD_FAST__LOAD_FAST", + [LOAD_GLOBAL_ADAPTIVE] = "LOAD_GLOBAL_ADAPTIVE", + [FORMAT_VALUE] = "FORMAT_VALUE", + [BUILD_CONST_KEY_MAP] = "BUILD_CONST_KEY_MAP", + [BUILD_STRING] = "BUILD_STRING", + [LOAD_GLOBAL_BUILTIN] = "LOAD_GLOBAL_BUILTIN", + [LOAD_GLOBAL_MODULE] = "LOAD_GLOBAL_MODULE", + [RESUME_QUICK] = "RESUME_QUICK", + [STORE_ATTR_ADAPTIVE] = "STORE_ATTR_ADAPTIVE", + [LIST_EXTEND] = "LIST_EXTEND", + [SET_UPDATE] = "SET_UPDATE", + [DICT_MERGE] = "DICT_MERGE", + [DICT_UPDATE] = "DICT_UPDATE", + [STORE_ATTR_INSTANCE_VALUE] = "STORE_ATTR_INSTANCE_VALUE", + [STORE_ATTR_SLOT] = "STORE_ATTR_SLOT", + [STORE_ATTR_WITH_HINT] = "STORE_ATTR_WITH_HINT", + [STORE_FAST__LOAD_FAST] = "STORE_FAST__LOAD_FAST", + [STORE_FAST__STORE_FAST] = "STORE_FAST__STORE_FAST", + [CALL] = "CALL", + [KW_NAMES] = "KW_NAMES", + [POP_JUMP_BACKWARD_IF_NOT_NONE] = "POP_JUMP_BACKWARD_IF_NOT_NONE", + [POP_JUMP_BACKWARD_IF_NONE] = "POP_JUMP_BACKWARD_IF_NONE", + [POP_JUMP_BACKWARD_IF_FALSE] = "POP_JUMP_BACKWARD_IF_FALSE", + [POP_JUMP_BACKWARD_IF_TRUE] = "POP_JUMP_BACKWARD_IF_TRUE", + [STORE_SUBSCR_ADAPTIVE] = "STORE_SUBSCR_ADAPTIVE", + [STORE_SUBSCR_DICT] = "STORE_SUBSCR_DICT", + [STORE_SUBSCR_LIST_INT] = "STORE_SUBSCR_LIST_INT", + [UNPACK_SEQUENCE_ADAPTIVE] = "UNPACK_SEQUENCE_ADAPTIVE", + [UNPACK_SEQUENCE_LIST] = "UNPACK_SEQUENCE_LIST", + [UNPACK_SEQUENCE_TUPLE] = "UNPACK_SEQUENCE_TUPLE", + [UNPACK_SEQUENCE_TWO_TUPLE] = "UNPACK_SEQUENCE_TWO_TUPLE", + [184] = "<184>", + [185] = "<185>", + [186] = "<186>", + [187] = "<187>", + [188] = "<188>", + [189] = "<189>", + [190] = "<190>", + [191] = "<191>", + [192] = "<192>", + [193] = "<193>", + [194] = "<194>", + [195] = "<195>", + [196] = "<196>", + [197] = "<197>", + [198] = "<198>", + [199] = "<199>", + [200] = "<200>", + [201] = "<201>", + [202] = "<202>", + [203] = "<203>", + [204] = "<204>", + [205] = "<205>", + [206] = "<206>", + [207] = "<207>", + [208] = "<208>", + [209] = "<209>", + [210] = "<210>", + [211] = "<211>", + [212] = "<212>", + [213] = "<213>", + [214] = "<214>", + [215] = "<215>", + [216] = "<216>", + [217] = "<217>", + [218] = "<218>", + [219] = "<219>", + [220] = "<220>", + [221] = "<221>", + [222] = "<222>", + [223] = "<223>", + [224] = "<224>", + [225] = "<225>", + [226] = "<226>", + [227] = "<227>", + [228] = "<228>", + [229] = "<229>", + [230] = "<230>", + [231] = "<231>", + [232] = "<232>", + [233] = "<233>", + [234] = "<234>", + [235] = "<235>", + [236] = "<236>", + [237] = "<237>", + [238] = "<238>", + [239] = "<239>", + [240] = "<240>", + [241] = "<241>", + [242] = "<242>", + [243] = "<243>", + [244] = "<244>", + [245] = "<245>", + [246] = "<246>", + [247] = "<247>", + [248] = "<248>", + [249] = "<249>", + [250] = "<250>", + [251] = "<251>", + [252] = "<252>", + [253] = "<253>", + [254] = "<254>", + [DO_TRACING] = "DO_TRACING", + [SETUP_FINALLY] = "SETUP_FINALLY", + [SETUP_CLEANUP] = "SETUP_CLEANUP", + [SETUP_WITH] = "SETUP_WITH", + [POP_BLOCK] = "POP_BLOCK", + [JUMP] = "JUMP", + [JUMP_NO_INTERRUPT] = "JUMP_NO_INTERRUPT", + [POP_JUMP_IF_FALSE] = "POP_JUMP_IF_FALSE", + [POP_JUMP_IF_TRUE] = "POP_JUMP_IF_TRUE", + [POP_JUMP_IF_NONE] = "POP_JUMP_IF_NONE", + [POP_JUMP_IF_NOT_NONE] = "POP_JUMP_IF_NOT_NONE", + [LOAD_METHOD] = "LOAD_METHOD", +}; +#endif + +#define EXTRA_CASES \ + case 184: \ + case 185: \ + case 186: \ + case 187: \ + case 188: \ + case 189: \ + case 190: \ + case 191: \ + case 192: \ + case 193: \ + case 194: \ + case 195: \ + case 196: \ + case 197: \ + case 198: \ + case 199: \ + case 200: \ + case 201: \ + case 202: \ + case 203: \ + case 204: \ + case 205: \ + case 206: \ + case 207: \ + case 208: \ + case 209: \ + case 210: \ + case 211: \ + case 212: \ + case 213: \ + case 214: \ + case 215: \ + case 216: \ + case 217: \ + case 218: \ + case 219: \ + case 220: \ + case 221: \ + case 222: \ + case 223: \ + case 224: \ + case 225: \ + case 226: \ + case 227: \ + case 228: \ + case 229: \ + case 230: \ + case 231: \ + case 232: \ + case 233: \ + case 234: \ + case 235: \ + case 236: \ + case 237: \ + case 238: \ + case 239: \ + case 240: \ + case 241: \ + case 242: \ + case 243: \ + case 244: \ + case 245: \ + case 246: \ + case 247: \ + case 248: \ + case 249: \ + case 250: \ + case 251: \ + case 252: \ + case 253: \ + case 254: \ + ; + +#ifdef __cplusplus +} +#endif +#endif // !Py_INTERNAL_OPCODE_H From def326ef11321191e577c76adcb5fe3d6f2c82a6 Mon Sep 17 00:00:00 2001 From: Ken Jin <28750310+Fidget-Spinner@users.noreply.github.com> Date: Tue, 16 Aug 2022 21:22:56 +0800 Subject: [PATCH 17/17] Address review, make things more restrictive --- Python/specialize.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/Python/specialize.c b/Python/specialize.c index 9bf890ca24f404..2dc7495ec79658 100644 --- a/Python/specialize.c +++ b/Python/specialize.c @@ -389,6 +389,7 @@ miss_counter_start(void) { #define SPEC_FAIL_ATTR_HAS_MANAGED_DICT 25 #define SPEC_FAIL_ATTR_INSTANCE_ATTRIBUTE 26 #define SPEC_FAIL_ATTR_METACLASS_ATTRIBUTE 27 +#define SPEC_FAIL_ATTR_PROPERTY_NOT_PY_FUNCTION 28 /* Binary subscr and store subscr */ @@ -594,7 +595,9 @@ analyze_descriptor(PyTypeObject *type, PyObject *name, PyObject **descr, int sto getattribute != interp->callable_cache.object__getattribute__; has_getattr = _PyType_Lookup(type, &_Py_ID(__getattr__)) != NULL; if (has_custom_getattribute) { - if (!has_getattr && Py_IS_TYPE(getattribute, &PyFunction_Type)) { + if (getattro_slot == _Py_slot_tp_getattro && + !has_getattr && + Py_IS_TYPE(getattribute, &PyFunction_Type)) { *descr = getattribute; return GETATTRIBUTE_IS_PYTHON_FUNCTION; } @@ -772,7 +775,7 @@ _Py_Specialize_LoadAttr(PyObject *owner, _Py_CODEUNIT *instr, PyObject *name) goto fail; } if (!Py_IS_TYPE(fget, &PyFunction_Type)) { - SPECIALIZATION_FAIL(LOAD_ATTR, SPEC_FAIL_NOT_PY_FUNCTION); + SPECIALIZATION_FAIL(LOAD_ATTR, SPEC_FAIL_ATTR_PROPERTY_NOT_PY_FUNCTION); goto fail; } uint32_t version = function_check_args(fget, 1, LOAD_ATTR) &&