diff options
Diffstat (limited to 'Python')
-rw-r--r-- | Python/ceval.c | 46 | ||||
-rw-r--r-- | Python/opcode_targets.h | 24 | ||||
-rw-r--r-- | Python/specialize.c | 49 |
3 files changed, 97 insertions, 22 deletions
diff --git a/Python/ceval.c b/Python/ceval.c index 0d6855e..44e4ffe 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -3626,7 +3626,6 @@ handle_eval_breaker: } TARGET(LOAD_ATTR_CLASS) { - /* LOAD_METHOD, for class methods */ assert(cframe.use_tracing == 0); _PyLoadMethodCache *cache = (_PyLoadMethodCache *)next_instr; @@ -3649,6 +3648,46 @@ handle_eval_breaker: NOTRACE_DISPATCH(); } + TARGET(LOAD_ATTR_PROPERTY) { + 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 *fget = read_obj(cache->descr); + PyFunctionObject *f = (PyFunctionObject *)fget; + 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 == 1); + STAT_INC(LOAD_ATTR, hit); + + Py_INCREF(fget); + _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); + 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; @@ -4548,7 +4587,7 @@ handle_eval_breaker: } 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); @@ -4574,8 +4613,7 @@ handle_eval_breaker: } 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); diff --git a/Python/opcode_targets.h b/Python/opcode_targets.h index a6523d4..9193dd9 100644 --- a/Python/opcode_targets.h +++ b/Python/opcode_targets.h @@ -65,27 +65,27 @@ static void *opcode_targets[256] = { &&TARGET_LOAD_ATTR_CLASS, &&TARGET_LOAD_ATTR_INSTANCE_VALUE, &&TARGET_LOAD_ATTR_MODULE, + &&TARGET_LOAD_ATTR_PROPERTY, &&TARGET_LOAD_ATTR_SLOT, - &&TARGET_LOAD_ATTR_WITH_HINT, &&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_METHOD_NO_DICT, &&TARGET_LOAD_ASSERTION_ERROR, &&TARGET_RETURN_GENERATOR, + &&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_GLOBAL_ADAPTIVE, &&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_BUILTIN, &&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_MODULE, &&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_RESUME_QUICK, &&TARGET_CALL_FUNCTION_EX, - &&TARGET_STORE_ATTR_INSTANCE_VALUE, + &&TARGET_STORE_ATTR_ADAPTIVE, &&TARGET_EXTENDED_ARG, &&TARGET_LIST_APPEND, &&TARGET_SET_ADD, @@ -152,31 +152,31 @@ static void *opcode_targets[256] = { &&TARGET_YIELD_VALUE, &&TARGET_RESUME, &&TARGET_MATCH_CLASS, + &&TARGET_STORE_ATTR_INSTANCE_VALUE, &&TARGET_STORE_ATTR_SLOT, - &&TARGET_STORE_ATTR_WITH_HINT, &&TARGET_FORMAT_VALUE, &&TARGET_BUILD_CONST_KEY_MAP, &&TARGET_BUILD_STRING, + &&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_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, + &&TARGET_UNPACK_SEQUENCE_TWO_TUPLE, &&_unknown_opcode, &&_unknown_opcode, &&_unknown_opcode, diff --git a/Python/specialize.c b/Python/specialize.c index 24fbe2f..70ccf68 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() @@ -331,6 +332,8 @@ miss_counter_start(void) { return 53; } +#define SIMPLE_FUNCTION 0 + /* Common */ #define SPEC_FAIL_OTHER 0 @@ -580,7 +583,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 +655,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 +702,42 @@ _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 *lm_cache = (_PyLoadMethodCache *)(instr + 1); + assert(Py_TYPE(descr) == &PyProperty_Type); + PyObject *fget = ((_PyPropertyObject *)descr)->prop_get; + if (fget == NULL) { + 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); + if (version == 0) { + SPECIALIZATION_FAIL(LOAD_ATTR, SPEC_FAIL_OUT_OF_VERSIONS); + goto fail; + } + write_u32(lm_cache->keys_version, version); + assert(type->tp_version_tag != 0); + write_u32(lm_cache->type_version, type->tp_version_tag); + /* borrowed */ + write_obj(lm_cache->descr, fget); + _Py_SET_OPCODE(*instr, LOAD_ATTR_PROPERTY); + goto success; + } case OBJECT_SLOT: { PyMemberDescrObject *member = (PyMemberDescrObject *)descr; @@ -1145,9 +1185,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; |