From c9966d19908cdeada6919df274acc14d042b0a7f Mon Sep 17 00:00:00 2001 From: Ken Jin <kenjin4096@gmail.com> Date: Thu, 16 Jun 2022 16:46:04 +0800 Subject: [PATCH 1/8] More LOAD_ATTR specializations --- Include/descrobject.h | 2 + Include/internal/pycore_opcode.h | 44 +++++++++--------- Include/opcode.h | 58 ++++++++++++------------ Lib/opcode.py | 2 + Objects/descrobject.c | 7 +++ Python/ceval.c | 77 ++++++++++++++++++++++++++++++-- Python/opcode_targets.h | 38 ++++++++-------- Python/specialize.c | 65 ++++++++++++++++++++++++--- 8 files changed, 214 insertions(+), 79 deletions(-) diff --git a/Include/descrobject.h b/Include/descrobject.h index 77f221df07714f..eb64564317b1c2 100644 --- a/Include/descrobject.h +++ b/Include/descrobject.h @@ -32,6 +32,8 @@ PyAPI_FUNC(PyObject *) PyDescr_NewGetSet(PyTypeObject *, PyGetSetDef *); PyAPI_FUNC(PyObject *) PyDictProxy_New(PyObject *); PyAPI_FUNC(PyObject *) PyWrapper_New(PyObject *, PyObject *); +PyObject *_PyProperty_PropGet(PyObject *prop); + #ifndef Py_LIMITED_API # define Py_CPYTHON_DESCROBJECT_H # include "cpython/descrobject.h" diff --git a/Include/internal/pycore_opcode.h b/Include/internal/pycore_opcode.h index 62db22f1952550..6436613c0aec67 100644 --- a/Include/internal/pycore_opcode.h +++ b/Include/internal/pycore_opcode.h @@ -147,12 +147,14 @@ const uint8_t _PyOpcode_Deopt[256] = { [LOAD_ATTR] = LOAD_ATTR, [LOAD_ATTR_ADAPTIVE] = LOAD_ATTR, [LOAD_ATTR_CLASS] = LOAD_ATTR, + [LOAD_ATTR_CLASS_MUTABLE_DESCRIPTOR] = 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, @@ -327,12 +329,14 @@ const uint8_t _PyOpcode_Original[256] = { [LOAD_ATTR] = LOAD_ATTR, [LOAD_ATTR_ADAPTIVE] = LOAD_ATTR, [LOAD_ATTR_CLASS] = LOAD_ATTR, + [LOAD_ATTR_CLASS_MUTABLE_DESCRIPTOR] = 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, @@ -479,29 +483,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_CLASS_MUTABLE_DESCRIPTOR] = "LOAD_ATTR_CLASS_MUTABLE_DESCRIPTOR", [LOAD_ATTR_INSTANCE_VALUE] = "LOAD_ATTR_INSTANCE_VALUE", [LOAD_ATTR_MODULE] = "LOAD_ATTR_MODULE", - [LOAD_ATTR_SLOT] = "LOAD_ATTR_SLOT", - [LOAD_ATTR_WITH_HINT] = "LOAD_ATTR_WITH_HINT", + [LOAD_ATTR_PROPERTY] = "LOAD_ATTR_PROPERTY", [GET_ITER] = "GET_ITER", [GET_YIELD_FROM_ITER] = "GET_YIELD_FROM_ITER", [PRINT_EXPR] = "PRINT_EXPR", [LOAD_BUILD_CLASS] = "LOAD_BUILD_CLASS", - [LOAD_ATTR_METHOD_LAZY_DICT] = "LOAD_ATTR_METHOD_LAZY_DICT", - [LOAD_ATTR_METHOD_NO_DICT] = "LOAD_ATTR_METHOD_NO_DICT", + [LOAD_ATTR_SLOT] = "LOAD_ATTR_SLOT", + [LOAD_ATTR_WITH_HINT] = "LOAD_ATTR_WITH_HINT", [LOAD_ASSERTION_ERROR] = "LOAD_ASSERTION_ERROR", [RETURN_GENERATOR] = "RETURN_GENERATOR", + [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", - [LOAD_GLOBAL_ADAPTIVE] = "LOAD_GLOBAL_ADAPTIVE", [LIST_TO_TUPLE] = "LIST_TO_TUPLE", [RETURN_VALUE] = "RETURN_VALUE", [IMPORT_STAR] = "IMPORT_STAR", [SETUP_ANNOTATIONS] = "SETUP_ANNOTATIONS", - [LOAD_GLOBAL_BUILTIN] = "LOAD_GLOBAL_BUILTIN", + [LOAD_FAST__LOAD_FAST] = "LOAD_FAST__LOAD_FAST", [ASYNC_GEN_WRAP] = "ASYNC_GEN_WRAP", [PREP_RERAISE_STAR] = "PREP_RERAISE_STAR", [POP_EXCEPT] = "POP_EXCEPT", @@ -528,7 +532,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_MODULE] = "LOAD_GLOBAL_MODULE", + [LOAD_GLOBAL_ADAPTIVE] = "LOAD_GLOBAL_ADAPTIVE", [POP_JUMP_FORWARD_IF_FALSE] = "POP_JUMP_FORWARD_IF_FALSE", [POP_JUMP_FORWARD_IF_TRUE] = "POP_JUMP_FORWARD_IF_TRUE", [LOAD_GLOBAL] = "LOAD_GLOBAL", @@ -536,7 +540,7 @@ static const char *const _PyOpcode_OpName[256] = { [CONTAINS_OP] = "CONTAINS_OP", [RERAISE] = "RERAISE", [COPY] = "COPY", - [RESUME_QUICK] = "RESUME_QUICK", + [LOAD_GLOBAL_BUILTIN] = "LOAD_GLOBAL_BUILTIN", [BINARY_OP] = "BINARY_OP", [SEND] = "SEND", [LOAD_FAST] = "LOAD_FAST", @@ -556,9 +560,9 @@ static const char *const _PyOpcode_OpName[256] = { [STORE_DEREF] = "STORE_DEREF", [DELETE_DEREF] = "DELETE_DEREF", [JUMP_BACKWARD] = "JUMP_BACKWARD", - [STORE_ATTR_ADAPTIVE] = "STORE_ATTR_ADAPTIVE", + [LOAD_GLOBAL_MODULE] = "LOAD_GLOBAL_MODULE", [CALL_FUNCTION_EX] = "CALL_FUNCTION_EX", - [STORE_ATTR_INSTANCE_VALUE] = "STORE_ATTR_INSTANCE_VALUE", + [RESUME_QUICK] = "RESUME_QUICK", [EXTENDED_ARG] = "EXTENDED_ARG", [LIST_APPEND] = "LIST_APPEND", [SET_ADD] = "SET_ADD", @@ -568,32 +572,32 @@ static const char *const _PyOpcode_OpName[256] = { [YIELD_VALUE] = "YIELD_VALUE", [RESUME] = "RESUME", [MATCH_CLASS] = "MATCH_CLASS", - [STORE_ATTR_SLOT] = "STORE_ATTR_SLOT", - [STORE_ATTR_WITH_HINT] = "STORE_ATTR_WITH_HINT", + [STORE_ATTR_ADAPTIVE] = "STORE_ATTR_ADAPTIVE", + [STORE_ATTR_INSTANCE_VALUE] = "STORE_ATTR_INSTANCE_VALUE", [FORMAT_VALUE] = "FORMAT_VALUE", [BUILD_CONST_KEY_MAP] = "BUILD_CONST_KEY_MAP", [BUILD_STRING] = "BUILD_STRING", + [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", - [STORE_SUBSCR_DICT] = "STORE_SUBSCR_DICT", [LIST_EXTEND] = "LIST_EXTEND", [SET_UPDATE] = "SET_UPDATE", [DICT_MERGE] = "DICT_MERGE", [DICT_UPDATE] = "DICT_UPDATE", + [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", [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", - [177] = "<177>", - [178] = "<178>", + [UNPACK_SEQUENCE_TUPLE] = "UNPACK_SEQUENCE_TUPLE", + [UNPACK_SEQUENCE_TWO_TUPLE] = "UNPACK_SEQUENCE_TWO_TUPLE", [179] = "<179>", [180] = "<180>", [181] = "<181>", @@ -675,8 +679,6 @@ static const char *const _PyOpcode_OpName[256] = { #endif #define EXTRA_CASES \ - case 177: \ - case 178: \ case 179: \ case 180: \ case 181: \ diff --git a/Include/opcode.h b/Include/opcode.h index 04e5bc8310ffb3..1aef2762a21efb 100644 --- a/Include/opcode.h +++ b/Include/opcode.h @@ -158,34 +158,36 @@ 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_SLOT 66 -#define LOAD_ATTR_WITH_HINT 67 -#define LOAD_ATTR_METHOD_LAZY_DICT 72 -#define LOAD_ATTR_METHOD_NO_DICT 73 -#define LOAD_ATTR_METHOD_WITH_DICT 76 -#define LOAD_ATTR_METHOD_WITH_VALUES 77 -#define LOAD_CONST__LOAD_FAST 78 -#define LOAD_FAST__LOAD_CONST 79 -#define LOAD_FAST__LOAD_FAST 80 -#define LOAD_GLOBAL_ADAPTIVE 81 -#define LOAD_GLOBAL_BUILTIN 86 -#define LOAD_GLOBAL_MODULE 113 -#define RESUME_QUICK 121 -#define STORE_ATTR_ADAPTIVE 141 -#define STORE_ATTR_INSTANCE_VALUE 143 -#define STORE_ATTR_SLOT 153 -#define STORE_ATTR_WITH_HINT 154 -#define STORE_FAST__LOAD_FAST 158 -#define STORE_FAST__STORE_FAST 159 -#define STORE_SUBSCR_ADAPTIVE 160 -#define STORE_SUBSCR_DICT 161 -#define STORE_SUBSCR_LIST_INT 166 -#define UNPACK_SEQUENCE_ADAPTIVE 167 -#define UNPACK_SEQUENCE_LIST 168 -#define UNPACK_SEQUENCE_TUPLE 169 -#define UNPACK_SEQUENCE_TWO_TUPLE 170 +#define LOAD_ATTR_CLASS_MUTABLE_DESCRIPTOR 64 +#define LOAD_ATTR_INSTANCE_VALUE 65 +#define LOAD_ATTR_MODULE 66 +#define LOAD_ATTR_PROPERTY 67 +#define LOAD_ATTR_SLOT 72 +#define LOAD_ATTR_WITH_HINT 73 +#define LOAD_ATTR_METHOD_LAZY_DICT 76 +#define LOAD_ATTR_METHOD_NO_DICT 77 +#define LOAD_ATTR_METHOD_WITH_DICT 78 +#define LOAD_ATTR_METHOD_WITH_VALUES 79 +#define LOAD_CONST__LOAD_FAST 80 +#define LOAD_FAST__LOAD_CONST 81 +#define LOAD_FAST__LOAD_FAST 86 +#define LOAD_GLOBAL_ADAPTIVE 113 +#define LOAD_GLOBAL_BUILTIN 121 +#define LOAD_GLOBAL_MODULE 141 +#define RESUME_QUICK 143 +#define STORE_ATTR_ADAPTIVE 153 +#define STORE_ATTR_INSTANCE_VALUE 154 +#define STORE_ATTR_SLOT 158 +#define STORE_ATTR_WITH_HINT 159 +#define STORE_FAST__LOAD_FAST 160 +#define STORE_FAST__STORE_FAST 161 +#define STORE_SUBSCR_ADAPTIVE 166 +#define STORE_SUBSCR_DICT 167 +#define STORE_SUBSCR_LIST_INT 168 +#define UNPACK_SEQUENCE_ADAPTIVE 169 +#define UNPACK_SEQUENCE_LIST 170 +#define UNPACK_SEQUENCE_TUPLE 177 +#define UNPACK_SEQUENCE_TWO_TUPLE 178 #define DO_TRACING 255 #define HAS_CONST(op) (false\ diff --git a/Lib/opcode.py b/Lib/opcode.py index 912b280c49b5bc..57c255e077faed 100644 --- a/Lib/opcode.py +++ b/Lib/opcode.py @@ -285,8 +285,10 @@ def jabs_op(name, op): "LOAD_ATTR_ADAPTIVE", # These potentially push [NULL, bound method] onto the stack. "LOAD_ATTR_CLASS", + "LOAD_ATTR_CLASS_MUTABLE_DESCRIPTOR", "LOAD_ATTR_INSTANCE_VALUE", "LOAD_ATTR_MODULE", + "LOAD_ATTR_PROPERTY", "LOAD_ATTR_SLOT", "LOAD_ATTR_WITH_HINT", # These will always push [unbound method, self] onto the stack. diff --git a/Objects/descrobject.c b/Objects/descrobject.c index 05797e72bcd41a..45e031f3b92cde 100644 --- a/Objects/descrobject.c +++ b/Objects/descrobject.c @@ -1893,6 +1893,13 @@ property_clear(PyObject *self) return 0; } +PyObject * +_PyProperty_PropGet(PyObject *self) +{ + propertyobject *pp = (propertyobject *)self; + return pp->prop_get; +} + #include "clinic/descrobject.c.h" PyTypeObject PyDictProxy_Type = { diff --git a/Python/ceval.c b/Python/ceval.c index f9ec640ef1722a..7450ef84c3047f 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -3627,7 +3627,6 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int } TARGET(LOAD_ATTR_CLASS) { - /* LOAD_METHOD, for class methods */ assert(cframe.use_tracing == 0); _PyLoadMethodCache *cache = (_PyLoadMethodCache *)next_instr; @@ -3650,6 +3649,76 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int NOTRACE_DISPATCH(); } + TARGET(LOAD_ATTR_CLASS_MUTABLE_DESCRIPTOR) { + assert(cframe.use_tracing == 0); + _PyLoadMethodCache *cache = (_PyLoadMethodCache *)next_instr; + + PyObject *cls = TOP(); + DEOPT_IF(!PyType_Check(cls), LOAD_ATTR); + uint32_t type_version = read_u32(cache->type_version); + DEOPT_IF(((PyTypeObject *)cls)->tp_version_tag != type_version, + LOAD_ATTR); + assert(type_version != 0); + PyObject *descr = read_obj(cache->descr); + descrgetfunc get = Py_TYPE(descr)->tp_descr_get; + DEOPT_IF(get == NULL, LOAD_ATTR); + STAT_INC(LOAD_ATTR, hit); + PyObject *res = get(descr, NULL, cls); + if (res == NULL) { + goto error; + } + assert(res != NULL); + SET_TOP(NULL); + STACK_GROW((oparg & 1)); + SET_TOP(res); + Py_DECREF(cls); + JUMPBY(INLINE_CACHE_ENTRIES_LOAD_ATTR); + NOTRACE_DISPATCH(); + } + + TARGET(LOAD_ATTR_PROPERTY) { + 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); + PyObject *prop = read_obj(cache->descr); + assert(Py_TYPE(prop) == &PyProperty_Type); + PyObject *fget = _PyProperty_PropGet(prop); + DEOPT_IF(!PyFunction_Check(fget), LOAD_ATTR); + PyFunctionObject *f = (PyFunctionObject *)fget; + DEOPT_IF(f->func_version != cache->keys_version[0], LOAD_ATTR); + PyCodeObject *code = (PyCodeObject *)f->func_code; + size_t size = code->co_nlocalsplus + code->co_stacksize + FRAME_SPECIALS_SIZE; + assert(code->co_argcount == 1); + STAT_INC(LOAD_ATTR, hit); + + _PyInterpreterFrame *new_frame = _PyThreadState_BumpFramePointer(tstate, size); + if (new_frame == NULL) { + goto error; + } + CALL_STAT_INC(frames_pushed); + Py_INCREF(f); + _PyFrame_InitializeSpecials(new_frame, f, + NULL, code->co_nlocalsplus); + SET_TOP(NULL); + STACK_SHRINK(!(oparg & 1)); + new_frame->localsplus[0] = owner; + for (int i = 1; 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; @@ -4549,7 +4618,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int } TARGET(LOAD_ATTR_METHOD_WITH_VALUES) { - /* LOAD_METHOD, with cached method object */ + /* Cached method object */ assert(cframe.use_tracing == 0); PyObject *self = TOP(); PyTypeObject *self_cls = Py_TYPE(self); @@ -4575,8 +4644,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int } TARGET(LOAD_ATTR_METHOD_WITH_DICT) { - /* LOAD_METHOD, with a dict - Can be either a managed dict, or a tp_dictoffset offset.*/ + /* Can be either a managed dict, or a tp_dictoffset offset.*/ assert(cframe.use_tracing == 0); PyObject *self = TOP(); PyTypeObject *self_cls = Py_TYPE(self); @@ -5527,6 +5595,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int } TARGET(CACHE) { + printf("cache\n"); Py_UNREACHABLE(); } diff --git a/Python/opcode_targets.h b/Python/opcode_targets.h index a6523d4af2b783..21421a8bcd4c13 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_CLASS_MUTABLE_DESCRIPTOR, &&TARGET_LOAD_ATTR_INSTANCE_VALUE, &&TARGET_LOAD_ATTR_MODULE, - &&TARGET_LOAD_ATTR_SLOT, - &&TARGET_LOAD_ATTR_WITH_HINT, + &&TARGET_LOAD_ATTR_PROPERTY, &&TARGET_GET_ITER, &&TARGET_GET_YIELD_FROM_ITER, &&TARGET_PRINT_EXPR, &&TARGET_LOAD_BUILD_CLASS, - &&TARGET_LOAD_ATTR_METHOD_LAZY_DICT, - &&TARGET_LOAD_ATTR_METHOD_NO_DICT, + &&TARGET_LOAD_ATTR_SLOT, + &&TARGET_LOAD_ATTR_WITH_HINT, &&TARGET_LOAD_ASSERTION_ERROR, &&TARGET_RETURN_GENERATOR, + &&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_LOAD_GLOBAL_ADAPTIVE, &&TARGET_LIST_TO_TUPLE, &&TARGET_RETURN_VALUE, &&TARGET_IMPORT_STAR, &&TARGET_SETUP_ANNOTATIONS, - &&TARGET_LOAD_GLOBAL_BUILTIN, + &&TARGET_LOAD_FAST__LOAD_FAST, &&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_MODULE, + &&TARGET_LOAD_GLOBAL_ADAPTIVE, &&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_RESUME_QUICK, + &&TARGET_LOAD_GLOBAL_BUILTIN, &&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_STORE_ATTR_ADAPTIVE, + &&TARGET_LOAD_GLOBAL_MODULE, &&TARGET_CALL_FUNCTION_EX, - &&TARGET_STORE_ATTR_INSTANCE_VALUE, + &&TARGET_RESUME_QUICK, &&TARGET_EXTENDED_ARG, &&TARGET_LIST_APPEND, &&TARGET_SET_ADD, @@ -152,32 +152,32 @@ static void *opcode_targets[256] = { &&TARGET_YIELD_VALUE, &&TARGET_RESUME, &&TARGET_MATCH_CLASS, - &&TARGET_STORE_ATTR_SLOT, - &&TARGET_STORE_ATTR_WITH_HINT, + &&TARGET_STORE_ATTR_ADAPTIVE, + &&TARGET_STORE_ATTR_INSTANCE_VALUE, &&TARGET_FORMAT_VALUE, &&TARGET_BUILD_CONST_KEY_MAP, &&TARGET_BUILD_STRING, + &&TARGET_STORE_ATTR_SLOT, + &&TARGET_STORE_ATTR_WITH_HINT, &&TARGET_STORE_FAST__LOAD_FAST, &&TARGET_STORE_FAST__STORE_FAST, - &&TARGET_STORE_SUBSCR_ADAPTIVE, - &&TARGET_STORE_SUBSCR_DICT, &&TARGET_LIST_EXTEND, &&TARGET_SET_UPDATE, &&TARGET_DICT_MERGE, &&TARGET_DICT_UPDATE, + &&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_UNPACK_SEQUENCE_TWO_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, - &&_unknown_opcode, - &&_unknown_opcode, + &&TARGET_UNPACK_SEQUENCE_TUPLE, + &&TARGET_UNPACK_SEQUENCE_TWO_TUPLE, &&_unknown_opcode, &&_unknown_opcode, &&_unknown_opcode, diff --git a/Python/specialize.c b/Python/specialize.c index a3be97d40dfb5b..a440d89d2fea6c 100644 --- a/Python/specialize.c +++ b/Python/specialize.c @@ -331,6 +331,8 @@ miss_counter_start(void) { return 53; } +#define SIMPLE_FUNCTION 0 + /* Common */ #define SPEC_FAIL_OTHER 0 @@ -532,7 +534,8 @@ typedef enum { BUILTIN_CLASSMETHOD, /* Builtin methods with METH_CLASS */ PYTHON_CLASSMETHOD, /* Python classmethod(func) object */ NON_DESCRIPTOR, /* Is not a descriptor, and is an instance of an immutable class */ - MUTABLE, /* Instance of a mutable class; might, or might not, be a descriptor */ + MUTABLE_DESCRIPTOR, /* Instance of a mutable class; with __set__/__get__ */ + MUTABLE, /* Instance of a mutable class, but the descriptor doesn't match the operation*/ ABSENT, /* Attribute is not present on the class */ DUNDER_CLASS, /* __class__ attribute */ GETSET_OVERRIDDEN /* __getattribute__ or __setattr__ has been overridden */ @@ -561,6 +564,12 @@ analyze_descriptor(PyTypeObject *type, PyObject *name, PyObject **descr, int sto } PyTypeObject *desc_cls = Py_TYPE(descriptor); if (!(desc_cls->tp_flags & Py_TPFLAGS_IMMUTABLETYPE)) { + if (!store && desc_cls->tp_descr_get) { + return MUTABLE_DESCRIPTOR; + } + if (store && desc_cls->tp_descr_set) { + return MUTABLE_DESCRIPTOR; + } return MUTABLE; } if (desc_cls->tp_descr_set) { @@ -580,7 +589,9 @@ analyze_descriptor(PyTypeObject *type, PyObject *name, PyObject **descr, int sto return DUNDER_CLASS; } } - return OVERRIDING; + if (store) { + return OVERRIDING; + } } if (desc_cls->tp_descr_get) { if (desc_cls->tp_flags & Py_TPFLAGS_METHOD_DESCRIPTOR) { @@ -650,6 +661,7 @@ 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) @@ -696,8 +708,38 @@ _Py_Specialize_LoadAttr(PyObject *owner, _Py_CODEUNIT *instr, PyObject *name) goto fail; } case PROPERTY: - SPECIALIZATION_FAIL(LOAD_ATTR, SPEC_FAIL_ATTR_PROPERTY); - goto fail; + { + _PyLoadMethodCache *cache = (_PyLoadMethodCache *)(instr + 1); + assert(Py_TYPE(descr) == &PyProperty_Type); + PyObject *fget = _PyProperty_PropGet(descr); + if (fget == NULL || Py_TYPE(fget) != &PyFunction_Type) { + SPECIALIZATION_FAIL(LOAD_ATTR, SPEC_FAIL_EXPECTED_ERROR); + 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); + if (version == 0 || version != (uint16_t)version) { + SPECIALIZATION_FAIL(LOAD_ATTR, SPEC_FAIL_OUT_OF_VERSIONS); + goto fail; + } + cache->keys_version[0] = version; + assert(type->tp_version_tag != 0); + write_u32(cache->type_version, type->tp_version_tag); + /* borrowed */ + write_obj(cache->descr, descr); + _Py_SET_OPCODE(*instr, LOAD_ATTR_PROPERTY); + goto success; + } case OBJECT_SLOT: { PyMemberDescrObject *member = (PyMemberDescrObject *)descr; @@ -731,6 +773,9 @@ _Py_Specialize_LoadAttr(PyObject *owner, _Py_CODEUNIT *instr, PyObject *name) SPECIALIZATION_FAIL(LOAD_ATTR, SPEC_FAIL_ATTR_NON_OBJECT_SLOT); goto fail; case MUTABLE: + case MUTABLE_DESCRIPTOR: + //_PyObject_Dump(owner); + //_PyObject_Dump(descr); SPECIALIZATION_FAIL(LOAD_ATTR, SPEC_FAIL_ATTR_MUTABLE_CLASS); goto fail; case GETSET_OVERRIDDEN: @@ -812,6 +857,7 @@ _Py_Specialize_StoreAttr(PyObject *owner, _Py_CODEUNIT *instr, PyObject *name) SPECIALIZATION_FAIL(STORE_ATTR, SPEC_FAIL_ATTR_NON_OBJECT_SLOT); goto fail; case MUTABLE: + case MUTABLE_DESCRIPTOR: SPECIALIZATION_FAIL(STORE_ATTR, SPEC_FAIL_ATTR_MUTABLE_CLASS); goto fail; case GETSET_OVERRIDDEN: @@ -866,6 +912,7 @@ load_attr_fail_kind(DescriptorClassification kind) case DUNDER_CLASS: return SPEC_FAIL_OTHER; case MUTABLE: + case MUTABLE_DESCRIPTOR: return SPEC_FAIL_ATTR_MUTABLE_CLASS; case GETSET_OVERRIDDEN: return SPEC_FAIL_OVERRIDDEN; @@ -895,10 +942,17 @@ specialize_class_load_attr(PyObject *owner, _Py_CODEUNIT *instr, switch (kind) { case METHOD: case NON_DESCRIPTOR: + case MUTABLE: write_u32(cache->type_version, ((PyTypeObject *)owner)->tp_version_tag); write_obj(cache->descr, descr); _Py_SET_OPCODE(*instr, LOAD_ATTR_CLASS); return 0; + case MUTABLE_DESCRIPTOR: + return -1; + write_u32(cache->type_version, ((PyTypeObject *)owner)->tp_version_tag); + write_obj(cache->descr, descr); + _Py_SET_OPCODE(*instr, LOAD_ATTR_CLASS_MUTABLE_DESCRIPTOR); + return 0; #ifdef Py_STATS case ABSENT: if (_PyType_Lookup(Py_TYPE(owner), name) != NULL) { @@ -1145,9 +1199,6 @@ binary_subscr_fail_kind(PyTypeObject *container_type, PyObject *sub) } #endif - -#define SIMPLE_FUNCTION 0 - static int function_kind(PyCodeObject *code) { int flags = code->co_flags; From e66782bf4f1e4024d0de0e5ef9b66c88470a3001 Mon Sep 17 00:00:00 2001 From: "blurb-it[bot]" <43283697+blurb-it[bot]@users.noreply.github.com> Date: Thu, 16 Jun 2022 08:56:26 +0000 Subject: [PATCH 2/8] =?UTF-8?q?=F0=9F=93=9C=F0=9F=A4=96=20Added=20by=20blu?= =?UTF-8?q?rb=5Fit.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../2022-06-16-08-56-26.gh-issue-93657.AZG2WT.rst | 1 + 1 file changed, 1 insertion(+) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2022-06-16-08-56-26.gh-issue-93657.AZG2WT.rst diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-06-16-08-56-26.gh-issue-93657.AZG2WT.rst b/Misc/NEWS.d/next/Core and Builtins/2022-06-16-08-56-26.gh-issue-93657.AZG2WT.rst new file mode 100644 index 00000000000000..e1cf651cd366e8 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2022-06-16-08-56-26.gh-issue-93657.AZG2WT.rst @@ -0,0 +1 @@ +Specialize `LOAD_ATTR` for mutable class attribute descriptors and ``property()`` attributes. From c7bde64a5c6cc62f58ae53b5e65fce875bcbf186 Mon Sep 17 00:00:00 2001 From: Ken Jin <kenjin@python.org> Date: Thu, 16 Jun 2022 17:39:25 +0800 Subject: [PATCH 3/8] fix compiler warnings --- Python/ceval.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/Python/ceval.c b/Python/ceval.c index 7450ef84c3047f..325f5fe3ee1c8a 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -1465,8 +1465,8 @@ eval_frame_handle_pending(PyThreadState *tstate) assert(STACK_LEVEL() <= STACK_SIZE()); \ } while (0) #define STACK_SHRINK(n) do { \ - assert(n >= 0); \ - assert(STACK_LEVEL() >= n); \ + assert((n) >= 0); \ + assert(STACK_LEVEL() >= (n)); \ BASIC_STACKADJ(-(n)); \ } while (0) #else @@ -5595,7 +5595,6 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int } TARGET(CACHE) { - printf("cache\n"); Py_UNREACHABLE(); } From 6a03dad976bcc74bd187e0f5dbf64011b3fc8622 Mon Sep 17 00:00:00 2001 From: Ken Jin <kenjin@python.org> Date: Thu, 16 Jun 2022 17:40:02 +0800 Subject: [PATCH 4/8] Fix double backticks --- .../2022-06-16-08-56-26.gh-issue-93657.AZG2WT.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-06-16-08-56-26.gh-issue-93657.AZG2WT.rst b/Misc/NEWS.d/next/Core and Builtins/2022-06-16-08-56-26.gh-issue-93657.AZG2WT.rst index e1cf651cd366e8..2c9747de327c8e 100644 --- a/Misc/NEWS.d/next/Core and Builtins/2022-06-16-08-56-26.gh-issue-93657.AZG2WT.rst +++ b/Misc/NEWS.d/next/Core and Builtins/2022-06-16-08-56-26.gh-issue-93657.AZG2WT.rst @@ -1 +1 @@ -Specialize `LOAD_ATTR` for mutable class attribute descriptors and ``property()`` attributes. +Specialize ``LOAD_ATTR`` for mutable class attribute descriptors and ``property()`` attributes. From c78831d54e452c13a4fce388f749b48cc8073698 Mon Sep 17 00:00:00 2001 From: Ken Jin <kenjin@python.org> Date: Thu, 16 Jun 2022 20:18:19 +0800 Subject: [PATCH 5/8] Apply Mark's suggestions --- Include/descrobject.h | 1 - Include/internal/pycore_descrobject.h | 26 ++++++++++++++++++++++++++ Makefile.pre.in | 1 + Objects/descrobject.c | 18 +----------------- PCbuild/pythoncore.vcxproj | 1 + PCbuild/pythoncore.vcxproj.filters | 3 +++ Python/ceval.c | 14 ++++---------- Python/specialize.c | 17 +++++++++-------- 8 files changed, 45 insertions(+), 36 deletions(-) create mode 100644 Include/internal/pycore_descrobject.h diff --git a/Include/descrobject.h b/Include/descrobject.h index eb64564317b1c2..8039b15576cc58 100644 --- a/Include/descrobject.h +++ b/Include/descrobject.h @@ -32,7 +32,6 @@ PyAPI_FUNC(PyObject *) PyDescr_NewGetSet(PyTypeObject *, PyGetSetDef *); PyAPI_FUNC(PyObject *) PyDictProxy_New(PyObject *); PyAPI_FUNC(PyObject *) PyWrapper_New(PyObject *, PyObject *); -PyObject *_PyProperty_PropGet(PyObject *prop); #ifndef Py_LIMITED_API # define Py_CPYTHON_DESCROBJECT_H diff --git a/Include/internal/pycore_descrobject.h b/Include/internal/pycore_descrobject.h new file mode 100644 index 00000000000000..76378569df90e3 --- /dev/null +++ b/Include/internal/pycore_descrobject.h @@ -0,0 +1,26 @@ +#ifndef Py_INTERNAL_DESCROBJECT_H +#define Py_INTERNAL_DESCROBJECT_H +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef Py_BUILD_CORE +# error "this header requires Py_BUILD_CORE define" +#endif + +typedef struct { + PyObject_HEAD + PyObject *prop_get; + PyObject *prop_set; + PyObject *prop_del; + PyObject *prop_doc; + PyObject *prop_name; + int getter_doc; +} propertyobject; + +typedef propertyobject _PyPropertyObject; + +#ifdef __cplusplus +} +#endif +#endif /* !Py_INTERNAL_DESCROBJECT_H */ diff --git a/Makefile.pre.in b/Makefile.pre.in index f3c70b99c9e221..ad0d09f913cea7 100644 --- a/Makefile.pre.in +++ b/Makefile.pre.in @@ -1595,6 +1595,7 @@ PYTHON_HEADERS= \ $(srcdir)/Include/internal/pycore_condvar.h \ $(srcdir)/Include/internal/pycore_context.h \ $(srcdir)/Include/internal/pycore_dict.h \ + $(srcdir)/Include/internal/pycore_descrobject.h \ $(srcdir)/Include/internal/pycore_dtoa.h \ $(srcdir)/Include/internal/pycore_exceptions.h \ $(srcdir)/Include/internal/pycore_fileutils.h \ diff --git a/Objects/descrobject.c b/Objects/descrobject.c index 45e031f3b92cde..8ef6a82d7c6d96 100644 --- a/Objects/descrobject.c +++ b/Objects/descrobject.c @@ -6,6 +6,7 @@ #include "pycore_pystate.h" // _PyThreadState_GET() #include "pycore_tuple.h" // _PyTuple_ITEMS() #include "structmember.h" // PyMemberDef +#include "pycore_descrobject.h" /*[clinic input] class mappingproxy "mappingproxyobject *" "&PyDictProxy_Type" @@ -1501,16 +1502,6 @@ class property(object): */ -typedef struct { - PyObject_HEAD - PyObject *prop_get; - PyObject *prop_set; - PyObject *prop_del; - PyObject *prop_doc; - PyObject *prop_name; - int getter_doc; -} propertyobject; - static PyObject * property_copy(PyObject *, PyObject *, PyObject *, PyObject *); @@ -1893,13 +1884,6 @@ property_clear(PyObject *self) return 0; } -PyObject * -_PyProperty_PropGet(PyObject *self) -{ - propertyobject *pp = (propertyobject *)self; - return pp->prop_get; -} - #include "clinic/descrobject.c.h" PyTypeObject PyDictProxy_Type = { diff --git a/PCbuild/pythoncore.vcxproj b/PCbuild/pythoncore.vcxproj index be76f1bc55859a..2e00fa9a7735c2 100644 --- a/PCbuild/pythoncore.vcxproj +++ b/PCbuild/pythoncore.vcxproj @@ -207,6 +207,7 @@ <ClInclude Include="..\Include\internal\pycore_compile.h" /> <ClInclude Include="..\Include\internal\pycore_condvar.h" /> <ClInclude Include="..\Include\internal\pycore_context.h" /> + <ClInclude Include="..\Include\internal\pycore_descrobject.h" /> <ClInclude Include="..\Include\internal\pycore_dtoa.h" /> <ClInclude Include="..\Include\internal\pycore_exceptions.h" /> <ClInclude Include="..\Include\internal\pycore_fileutils.h" /> diff --git a/PCbuild/pythoncore.vcxproj.filters b/PCbuild/pythoncore.vcxproj.filters index 5573e0020491a6..9c2920cf2bd505 100644 --- a/PCbuild/pythoncore.vcxproj.filters +++ b/PCbuild/pythoncore.vcxproj.filters @@ -528,6 +528,9 @@ <ClInclude Include="..\Include\internal\pycore_context.h"> <Filter>Include\internal</Filter> </ClInclude> + <ClInclude Include="..\Include\internal\pycore_descrobject.h"> + <Filter>Include\internal</Filter> + </ClInclude> <ClInclude Include="..\Include\internal\pycore_dtoa.h"> <Filter>Include\internal</Filter> </ClInclude> diff --git a/Python/ceval.c b/Python/ceval.c index 325f5fe3ee1c8a..f7e39590a68bc2 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -3685,25 +3685,19 @@ _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 *prop = read_obj(cache->descr); - assert(Py_TYPE(prop) == &PyProperty_Type); - PyObject *fget = _PyProperty_PropGet(prop); - DEOPT_IF(!PyFunction_Check(fget), LOAD_ATTR); + PyObject *fget = read_obj(cache->descr); PyFunctionObject *f = (PyFunctionObject *)fget; DEOPT_IF(f->func_version != cache->keys_version[0], LOAD_ATTR); PyCodeObject *code = (PyCodeObject *)f->func_code; - size_t size = code->co_nlocalsplus + code->co_stacksize + FRAME_SPECIALS_SIZE; assert(code->co_argcount == 1); STAT_INC(LOAD_ATTR, hit); - _PyInterpreterFrame *new_frame = _PyThreadState_BumpFramePointer(tstate, size); + Py_INCREF(fget); + _PyInterpreterFrame *new_frame = _PyFrame_Push(tstate, f); if (new_frame == NULL) { goto error; } - CALL_STAT_INC(frames_pushed); - Py_INCREF(f); - _PyFrame_InitializeSpecials(new_frame, f, - NULL, code->co_nlocalsplus); + CALL_STAT_INC(inlined_py_calls); SET_TOP(NULL); STACK_SHRINK(!(oparg & 1)); new_frame->localsplus[0] = owner; diff --git a/Python/specialize.c b/Python/specialize.c index a440d89d2fea6c..24d192137444b4 100644 --- a/Python/specialize.c +++ b/Python/specialize.c @@ -8,6 +8,7 @@ #include "pycore_object.h" #include "pycore_opcode.h" // _PyOpcode_Caches #include "structmember.h" // struct PyMemberDef, T_OFFSET_EX +#include "pycore_descrobject.h" #include <stdlib.h> // rand() @@ -709,9 +710,9 @@ _Py_Specialize_LoadAttr(PyObject *owner, _Py_CODEUNIT *instr, PyObject *name) } case PROPERTY: { - _PyLoadMethodCache *cache = (_PyLoadMethodCache *)(instr + 1); + _PyLoadMethodCache *lm_cache = (_PyLoadMethodCache *)(instr + 1); assert(Py_TYPE(descr) == &PyProperty_Type); - PyObject *fget = _PyProperty_PropGet(descr); + PyObject *fget = ((_PyPropertyObject *)descr)->prop_get; if (fget == NULL || Py_TYPE(fget) != &PyFunction_Type) { SPECIALIZATION_FAIL(LOAD_ATTR, SPEC_FAIL_EXPECTED_ERROR); goto fail; @@ -729,14 +730,16 @@ _Py_Specialize_LoadAttr(PyObject *owner, _Py_CODEUNIT *instr, PyObject *name) } int version = _PyFunction_GetVersionForCurrentState(func); if (version == 0 || version != (uint16_t)version) { - SPECIALIZATION_FAIL(LOAD_ATTR, SPEC_FAIL_OUT_OF_VERSIONS); + SPECIALIZATION_FAIL(LOAD_ATTR, + version == 0 ? + SPEC_FAIL_OUT_OF_VERSIONS : SPEC_FAIL_OUT_OF_RANGE); goto fail; } - cache->keys_version[0] = version; + lm_cache->keys_version[0] = version; assert(type->tp_version_tag != 0); - write_u32(cache->type_version, type->tp_version_tag); + write_u32(lm_cache->type_version, type->tp_version_tag); /* borrowed */ - write_obj(cache->descr, descr); + write_obj(lm_cache->descr, fget); _Py_SET_OPCODE(*instr, LOAD_ATTR_PROPERTY); goto success; } @@ -774,8 +777,6 @@ _Py_Specialize_LoadAttr(PyObject *owner, _Py_CODEUNIT *instr, PyObject *name) goto fail; case MUTABLE: case MUTABLE_DESCRIPTOR: - //_PyObject_Dump(owner); - //_PyObject_Dump(descr); SPECIALIZATION_FAIL(LOAD_ATTR, SPEC_FAIL_ATTR_MUTABLE_CLASS); goto fail; case GETSET_OVERRIDDEN: From d03cc611aad100f638ace01ffb1ee44f45f0d967 Mon Sep 17 00:00:00 2001 From: Ken Jin <kenjin@python.org> Date: Thu, 16 Jun 2022 21:39:09 +0800 Subject: [PATCH 6/8] try to fix compiler warnings --- Include/descrobject.h | 1 - Python/ceval.c | 7 ++++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Include/descrobject.h b/Include/descrobject.h index 8039b15576cc58..77f221df07714f 100644 --- a/Include/descrobject.h +++ b/Include/descrobject.h @@ -32,7 +32,6 @@ PyAPI_FUNC(PyObject *) PyDescr_NewGetSet(PyTypeObject *, PyGetSetDef *); PyAPI_FUNC(PyObject *) PyDictProxy_New(PyObject *); PyAPI_FUNC(PyObject *) PyWrapper_New(PyObject *, PyObject *); - #ifndef Py_LIMITED_API # define Py_CPYTHON_DESCROBJECT_H # include "cpython/descrobject.h" diff --git a/Python/ceval.c b/Python/ceval.c index f7e39590a68bc2..5f22a6fef9319a 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -1465,8 +1465,8 @@ eval_frame_handle_pending(PyThreadState *tstate) assert(STACK_LEVEL() <= STACK_SIZE()); \ } while (0) #define STACK_SHRINK(n) do { \ - assert((n) >= 0); \ - assert(STACK_LEVEL() >= (n)); \ + assert(n >= 0); \ + assert(STACK_LEVEL() >= n); \ BASIC_STACKADJ(-(n)); \ } while (0) #else @@ -3699,7 +3699,8 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int } CALL_STAT_INC(inlined_py_calls); SET_TOP(NULL); - STACK_SHRINK(!(oparg & 1)); + int push_null = !(oparg & 1); + STACK_SHRINK(push_null); new_frame->localsplus[0] = owner; for (int i = 1; i < code->co_nlocalsplus; i++) { new_frame->localsplus[i] = NULL; From 36af644bb3a1847d1d84e81f7126a0b2adea2260 Mon Sep 17 00:00:00 2001 From: Ken Jin <kenjin@python.org> Date: Thu, 16 Jun 2022 21:47:42 +0800 Subject: [PATCH 7/8] re-enable LOAD_ATTR_CLASS_MUTABLE_DESCRIPTOR --- Python/specialize.c | 1 - 1 file changed, 1 deletion(-) diff --git a/Python/specialize.c b/Python/specialize.c index 24d192137444b4..9ec5b2c5edbe90 100644 --- a/Python/specialize.c +++ b/Python/specialize.c @@ -949,7 +949,6 @@ specialize_class_load_attr(PyObject *owner, _Py_CODEUNIT *instr, _Py_SET_OPCODE(*instr, LOAD_ATTR_CLASS); return 0; case MUTABLE_DESCRIPTOR: - return -1; write_u32(cache->type_version, ((PyTypeObject *)owner)->tp_version_tag); write_obj(cache->descr, descr); _Py_SET_OPCODE(*instr, LOAD_ATTR_CLASS_MUTABLE_DESCRIPTOR); From c20af47e67670d0ea857b8a634010834d8d68acb Mon Sep 17 00:00:00 2001 From: Ken Jin <kenjin@python.org> Date: Thu, 16 Jun 2022 22:06:19 +0800 Subject: [PATCH 8/8] Remove double stat count --- Python/ceval.c | 1 - 1 file changed, 1 deletion(-) diff --git a/Python/ceval.c b/Python/ceval.c index 5f22a6fef9319a..d75743f88cdb39 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -3697,7 +3697,6 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int if (new_frame == NULL) { goto error; } - CALL_STAT_INC(inlined_py_calls); SET_TOP(NULL); int push_null = !(oparg & 1); STACK_SHRINK(push_null);