mirror of
https://github.com/python/cpython.git
synced 2024-11-23 18:04:37 +08:00
bpo-46823: Implement LOAD_FAST__LOAD_ATTR_INSTANCE_VALUE superinstruction (GH-31484)
This commit is contained in:
parent
4fccf91073
commit
a52d2528a4
1
Include/opcode.h
generated
1
Include/opcode.h
generated
@ -181,6 +181,7 @@ extern "C" {
|
||||
#define LOAD_FAST__LOAD_CONST 169
|
||||
#define LOAD_CONST__LOAD_FAST 170
|
||||
#define STORE_FAST__STORE_FAST 173
|
||||
#define LOAD_FAST__LOAD_ATTR_INSTANCE_VALUE 174
|
||||
#define DO_TRACING 255
|
||||
#ifdef NEED_OPCODE_JUMP_TABLES
|
||||
static uint32_t _PyOpcode_RelativeJump[8] = {
|
||||
|
@ -295,6 +295,7 @@ _specialized_instructions = [
|
||||
"LOAD_FAST__LOAD_CONST",
|
||||
"LOAD_CONST__LOAD_FAST",
|
||||
"STORE_FAST__STORE_FAST",
|
||||
"LOAD_FAST__LOAD_ATTR_INSTANCE_VALUE",
|
||||
]
|
||||
_specialization_stats = [
|
||||
"success",
|
||||
|
@ -0,0 +1 @@
|
||||
Implement a specialized combined opcode ``LOAD_FAST__LOAD_ATTR_INSTANCE_VALUE``. Patch by Dennis Sweeney.
|
@ -3444,6 +3444,34 @@ handle_eval_breaker:
|
||||
}
|
||||
}
|
||||
|
||||
TARGET(LOAD_FAST__LOAD_ATTR_INSTANCE_VALUE) {
|
||||
assert(cframe.use_tracing == 0);
|
||||
PyObject *owner = GETLOCAL(oparg); // borrowed
|
||||
if (owner == NULL) {
|
||||
goto unbound_local_error;
|
||||
}
|
||||
// GET_CACHE(), but for the following opcode
|
||||
assert(_Py_OPCODE(*next_instr) == LOAD_ATTR_INSTANCE_VALUE);
|
||||
SpecializedCacheEntry *caches = _GetSpecializedCacheEntryForInstruction(
|
||||
first_instr, INSTR_OFFSET() + 1, _Py_OPARG(*next_instr));
|
||||
_PyAdaptiveEntry *cache0 = &caches[0].adaptive;
|
||||
assert(cache0->version != 0);
|
||||
PyTypeObject *tp = Py_TYPE(owner);
|
||||
// These DEOPT_IF miss branches do PUSH(Py_NewRef(owner)).
|
||||
DEOPT_IF(tp->tp_version_tag != cache0->version,
|
||||
LOAD_FAST__LOAD_ATTR_INSTANCE_VALUE);
|
||||
assert(tp->tp_dictoffset < 0);
|
||||
assert(tp->tp_flags & Py_TPFLAGS_MANAGED_DICT);
|
||||
PyDictValues *values = *_PyObject_ValuesPointer(owner);
|
||||
DEOPT_IF(values == NULL, LOAD_FAST__LOAD_ATTR_INSTANCE_VALUE);
|
||||
PyObject *res = values->values[cache0->index];
|
||||
DEOPT_IF(res == NULL, LOAD_FAST__LOAD_ATTR_INSTANCE_VALUE);
|
||||
STAT_INC(LOAD_ATTR, hit);
|
||||
PUSH(Py_NewRef(res));
|
||||
next_instr++;
|
||||
NOTRACE_DISPATCH();
|
||||
}
|
||||
|
||||
TARGET(LOAD_ATTR_INSTANCE_VALUE) {
|
||||
assert(cframe.use_tracing == 0);
|
||||
PyObject *owner = TOP();
|
||||
@ -3452,13 +3480,13 @@ handle_eval_breaker:
|
||||
SpecializedCacheEntry *caches = GET_CACHE();
|
||||
_PyAdaptiveEntry *cache0 = &caches[0].adaptive;
|
||||
assert(cache0->version != 0);
|
||||
DEOPT_IF(tp->tp_version_tag != cache0->version, LOAD_ATTR);
|
||||
DEOPT_IF(tp->tp_version_tag != cache0->version, LOAD_ATTR_INSTANCE_VALUE);
|
||||
assert(tp->tp_dictoffset < 0);
|
||||
assert(tp->tp_flags & Py_TPFLAGS_MANAGED_DICT);
|
||||
PyDictValues *values = *_PyObject_ValuesPointer(owner);
|
||||
DEOPT_IF(values == NULL, LOAD_ATTR);
|
||||
DEOPT_IF(values == NULL, LOAD_ATTR_INSTANCE_VALUE);
|
||||
res = values->values[cache0->index];
|
||||
DEOPT_IF(res == NULL, LOAD_ATTR);
|
||||
DEOPT_IF(res == NULL, LOAD_ATTR_INSTANCE_VALUE);
|
||||
STAT_INC(LOAD_ATTR, hit);
|
||||
Py_INCREF(res);
|
||||
SET_TOP(res);
|
||||
@ -5515,6 +5543,52 @@ MISS_WITH_CACHE(BINARY_SUBSCR)
|
||||
MISS_WITH_CACHE(UNPACK_SEQUENCE)
|
||||
MISS_WITH_OPARG_COUNTER(STORE_SUBSCR)
|
||||
|
||||
LOAD_ATTR_INSTANCE_VALUE_miss:
|
||||
{
|
||||
// Special-cased so that if LOAD_ATTR_INSTANCE_VALUE
|
||||
// gets replaced, then any preceeding
|
||||
// LOAD_FAST__LOAD_ATTR_INSTANCE_VALUE gets replaced as well
|
||||
STAT_INC(LOAD_ATTR_INSTANCE_VALUE, miss);
|
||||
STAT_INC(LOAD_ATTR, miss);
|
||||
_PyAdaptiveEntry *cache = &GET_CACHE()->adaptive;
|
||||
cache->counter--;
|
||||
if (cache->counter == 0) {
|
||||
next_instr[-1] = _Py_MAKECODEUNIT(LOAD_ATTR_ADAPTIVE, _Py_OPARG(next_instr[-1]));
|
||||
if (_Py_OPCODE(next_instr[-2]) == LOAD_FAST__LOAD_ATTR_INSTANCE_VALUE) {
|
||||
next_instr[-2] = _Py_MAKECODEUNIT(LOAD_FAST, _Py_OPARG(next_instr[-2]));
|
||||
if (_Py_OPCODE(next_instr[-3]) == LOAD_FAST) {
|
||||
next_instr[-3] = _Py_MAKECODEUNIT(LOAD_FAST__LOAD_FAST, _Py_OPARG(next_instr[-3]));
|
||||
}
|
||||
}
|
||||
STAT_INC(LOAD_ATTR, deopt);
|
||||
cache_backoff(cache);
|
||||
}
|
||||
oparg = cache->original_oparg;
|
||||
JUMP_TO_INSTRUCTION(LOAD_ATTR);
|
||||
}
|
||||
|
||||
LOAD_FAST__LOAD_ATTR_INSTANCE_VALUE_miss:
|
||||
{
|
||||
// This is special-cased because we have a superinstruction
|
||||
// that includes a specialized instruction.
|
||||
// If the specialized portion misses, carry out
|
||||
// the first instruction, then perform a miss
|
||||
// for the second instruction as usual.
|
||||
|
||||
// Do LOAD_FAST
|
||||
{
|
||||
PyObject *value = GETLOCAL(oparg);
|
||||
assert(value != NULL); // Already checked if unbound
|
||||
Py_INCREF(value);
|
||||
PUSH(value);
|
||||
NEXTOPARG();
|
||||
next_instr++;
|
||||
}
|
||||
|
||||
// Now we are in the correct state for LOAD_ATTR
|
||||
goto LOAD_ATTR_INSTANCE_VALUE_miss;
|
||||
}
|
||||
|
||||
binary_subscr_dict_error:
|
||||
{
|
||||
PyObject *sub = POP();
|
||||
|
2
Python/opcode_targets.h
generated
2
Python/opcode_targets.h
generated
@ -173,7 +173,7 @@ static void *opcode_targets[256] = {
|
||||
&&TARGET_CALL,
|
||||
&&TARGET_KW_NAMES,
|
||||
&&TARGET_STORE_FAST__STORE_FAST,
|
||||
&&_unknown_opcode,
|
||||
&&TARGET_LOAD_FAST__LOAD_ATTR_INSTANCE_VALUE,
|
||||
&&_unknown_opcode,
|
||||
&&_unknown_opcode,
|
||||
&&_unknown_opcode,
|
||||
|
@ -889,6 +889,16 @@ _Py_Specialize_LoadAttr(PyObject *owner, _Py_CODEUNIT *instr, PyObject *name, Sp
|
||||
return -1;
|
||||
}
|
||||
if (err) {
|
||||
if (_Py_OPCODE(instr[0]) == LOAD_ATTR_INSTANCE_VALUE) {
|
||||
// Note: instr[-1] exists because there's something on the stack,
|
||||
// and instr[-2] exists because there's at least a RESUME as well.
|
||||
if (_Py_OPCODE(instr[-1]) == LOAD_FAST) {
|
||||
instr[-1] = _Py_MAKECODEUNIT(LOAD_FAST__LOAD_ATTR_INSTANCE_VALUE, _Py_OPARG(instr[-1]));
|
||||
if (_Py_OPCODE(instr[-2]) == LOAD_FAST__LOAD_FAST) {
|
||||
instr[-2] = _Py_MAKECODEUNIT(LOAD_FAST, _Py_OPARG(instr[-2]));
|
||||
}
|
||||
}
|
||||
}
|
||||
goto success;
|
||||
}
|
||||
fail:
|
||||
|
Loading…
Reference in New Issue
Block a user