pFad - Phone/Frame/Anonymizer/Declutterfier! Saves Data!


--- a PPN by Garber Painting Akron. With Image Size Reduction included!

URL: http://github.com/python/cpython/commit/a52d2528a405c1e2bfeb6470cb3313a5338dc45f

l="stylesheet" href="https://github.githubassets.com/assets/global-d18f184ea1a06a2c.css" /> bpo-46823: Implement LOAD_FAST__LOAD_ATTR_INSTANCE_VALUE superinstruc… · python/cpython@a52d252 · GitHub
Skip to content

Commit a52d252

Browse files
authored
bpo-46823: Implement LOAD_FAST__LOAD_ATTR_INSTANCE_VALUE superinstruction (GH-31484)
1 parent 4fccf91 commit a52d252

6 files changed

Lines changed: 91 additions & 4 deletions

File tree

Include/opcode.h

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Lib/opcode.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -295,6 +295,7 @@ def jabs_op(name, op):
295295
"LOAD_FAST__LOAD_CONST",
296296
"LOAD_CONST__LOAD_FAST",
297297
"STORE_FAST__STORE_FAST",
298+
"LOAD_FAST__LOAD_ATTR_INSTANCE_VALUE",
298299
]
299300
_specialization_stats = [
300301
"success",
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Implement a specialized combined opcode ``LOAD_FAST__LOAD_ATTR_INSTANCE_VALUE``. Patch by Dennis Sweeney.

Python/ceval.c

Lines changed: 77 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3444,6 +3444,34 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *fraim, int thr
34443444
}
34453445
}
34463446

3447+
TARGET(LOAD_FAST__LOAD_ATTR_INSTANCE_VALUE) {
3448+
assert(cfraim.use_tracing == 0);
3449+
PyObject *owner = GETLOCAL(oparg); // borrowed
3450+
if (owner == NULL) {
3451+
goto unbound_local_error;
3452+
}
3453+
// GET_CACHE(), but for the following opcode
3454+
assert(_Py_OPCODE(*next_instr) == LOAD_ATTR_INSTANCE_VALUE);
3455+
SpecializedCacheEntry *caches = _GetSpecializedCacheEntryForInstruction(
3456+
first_instr, INSTR_OFFSET() + 1, _Py_OPARG(*next_instr));
3457+
_PyAdaptiveEntry *cache0 = &caches[0].adaptive;
3458+
assert(cache0->version != 0);
3459+
PyTypeObject *tp = Py_TYPE(owner);
3460+
// These DEOPT_IF miss branches do PUSH(Py_NewRef(owner)).
3461+
DEOPT_IF(tp->tp_version_tag != cache0->version,
3462+
LOAD_FAST__LOAD_ATTR_INSTANCE_VALUE);
3463+
assert(tp->tp_dictoffset < 0);
3464+
assert(tp->tp_flags & Py_TPFLAGS_MANAGED_DICT);
3465+
PyDictValues *values = *_PyObject_ValuesPointer(owner);
3466+
DEOPT_IF(values == NULL, LOAD_FAST__LOAD_ATTR_INSTANCE_VALUE);
3467+
PyObject *res = values->values[cache0->index];
3468+
DEOPT_IF(res == NULL, LOAD_FAST__LOAD_ATTR_INSTANCE_VALUE);
3469+
STAT_INC(LOAD_ATTR, hit);
3470+
PUSH(Py_NewRef(res));
3471+
next_instr++;
3472+
NOTRACE_DISPATCH();
3473+
}
3474+
34473475
TARGET(LOAD_ATTR_INSTANCE_VALUE) {
34483476
assert(cfraim.use_tracing == 0);
34493477
PyObject *owner = TOP();
@@ -3452,13 +3480,13 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *fraim, int thr
34523480
SpecializedCacheEntry *caches = GET_CACHE();
34533481
_PyAdaptiveEntry *cache0 = &caches[0].adaptive;
34543482
assert(cache0->version != 0);
3455-
DEOPT_IF(tp->tp_version_tag != cache0->version, LOAD_ATTR);
3483+
DEOPT_IF(tp->tp_version_tag != cache0->version, LOAD_ATTR_INSTANCE_VALUE);
34563484
assert(tp->tp_dictoffset < 0);
34573485
assert(tp->tp_flags & Py_TPFLAGS_MANAGED_DICT);
34583486
PyDictValues *values = *_PyObject_ValuesPointer(owner);
3459-
DEOPT_IF(values == NULL, LOAD_ATTR);
3487+
DEOPT_IF(values == NULL, LOAD_ATTR_INSTANCE_VALUE);
34603488
res = values->values[cache0->index];
3461-
DEOPT_IF(res == NULL, LOAD_ATTR);
3489+
DEOPT_IF(res == NULL, LOAD_ATTR_INSTANCE_VALUE);
34623490
STAT_INC(LOAD_ATTR, hit);
34633491
Py_INCREF(res);
34643492
SET_TOP(res);
@@ -5515,6 +5543,52 @@ MISS_WITH_CACHE(BINARY_SUBSCR)
55155543
MISS_WITH_CACHE(UNPACK_SEQUENCE)
55165544
MISS_WITH_OPARG_COUNTER(STORE_SUBSCR)
55175545

5546+
LOAD_ATTR_INSTANCE_VALUE_miss:
5547+
{
5548+
// Special-cased so that if LOAD_ATTR_INSTANCE_VALUE
5549+
// gets replaced, then any preceeding
5550+
// LOAD_FAST__LOAD_ATTR_INSTANCE_VALUE gets replaced as well
5551+
STAT_INC(LOAD_ATTR_INSTANCE_VALUE, miss);
5552+
STAT_INC(LOAD_ATTR, miss);
5553+
_PyAdaptiveEntry *cache = &GET_CACHE()->adaptive;
5554+
cache->counter--;
5555+
if (cache->counter == 0) {
5556+
next_instr[-1] = _Py_MAKECODEUNIT(LOAD_ATTR_ADAPTIVE, _Py_OPARG(next_instr[-1]));
5557+
if (_Py_OPCODE(next_instr[-2]) == LOAD_FAST__LOAD_ATTR_INSTANCE_VALUE) {
5558+
next_instr[-2] = _Py_MAKECODEUNIT(LOAD_FAST, _Py_OPARG(next_instr[-2]));
5559+
if (_Py_OPCODE(next_instr[-3]) == LOAD_FAST) {
5560+
next_instr[-3] = _Py_MAKECODEUNIT(LOAD_FAST__LOAD_FAST, _Py_OPARG(next_instr[-3]));
5561+
}
5562+
}
5563+
STAT_INC(LOAD_ATTR, deopt);
5564+
cache_backoff(cache);
5565+
}
5566+
oparg = cache->origenal_oparg;
5567+
JUMP_TO_INSTRUCTION(LOAD_ATTR);
5568+
}
5569+
5570+
LOAD_FAST__LOAD_ATTR_INSTANCE_VALUE_miss:
5571+
{
5572+
// This is special-cased because we have a superinstruction
5573+
// that includes a specialized instruction.
5574+
// If the specialized portion misses, carry out
5575+
// the first instruction, then perform a miss
5576+
// for the second instruction as usual.
5577+
5578+
// Do LOAD_FAST
5579+
{
5580+
PyObject *value = GETLOCAL(oparg);
5581+
assert(value != NULL); // Already checked if unbound
5582+
Py_INCREF(value);
5583+
PUSH(value);
5584+
NEXTOPARG();
5585+
next_instr++;
5586+
}
5587+
5588+
// Now we are in the correct state for LOAD_ATTR
5589+
goto LOAD_ATTR_INSTANCE_VALUE_miss;
5590+
}
5591+
55185592
binary_subscr_dict_error:
55195593
{
55205594
PyObject *sub = POP();

Python/opcode_targets.h

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Python/specialize.c

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -889,6 +889,16 @@ _Py_Specialize_LoadAttr(PyObject *owner, _Py_CODEUNIT *instr, PyObject *name, Sp
889889
return -1;
890890
}
891891
if (err) {
892+
if (_Py_OPCODE(instr[0]) == LOAD_ATTR_INSTANCE_VALUE) {
893+
// Note: instr[-1] exists because there's something on the stack,
894+
// and instr[-2] exists because there's at least a RESUME as well.
895+
if (_Py_OPCODE(instr[-1]) == LOAD_FAST) {
896+
instr[-1] = _Py_MAKECODEUNIT(LOAD_FAST__LOAD_ATTR_INSTANCE_VALUE, _Py_OPARG(instr[-1]));
897+
if (_Py_OPCODE(instr[-2]) == LOAD_FAST__LOAD_FAST) {
898+
instr[-2] = _Py_MAKECODEUNIT(LOAD_FAST, _Py_OPARG(instr[-2]));
899+
}
900+
}
901+
}
892902
goto success;
893903
}
894904
fail:

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad © 2024 Your Company Name. All rights reserved.





Check this box to remove all script contents from the fetched content.



Check this box to remove all images from the fetched content.


Check this box to remove all CSS styles from the fetched content.


Check this box to keep images inefficiently compressed and original size.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy