mirror of
https://github.com/python/cpython.git
synced 2025-08-03 16:39:00 +00:00
gh-93911: Specialize LOAD_ATTR_PROPERTY
(GH-93912)
This commit is contained in:
parent
0ff626f210
commit
a51742ab82
12 changed files with 172 additions and 71 deletions
|
@ -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);
|
||||
|
|
24
Python/opcode_targets.h
generated
24
Python/opcode_targets.h
generated
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue