Skip to content

gh-93429: Merge LOAD_METHOD back into LOAD_ATTR #93430

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 17 commits into from
Jun 14, 2022
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Merge specialization code more (stats are still broken)
  • Loading branch information
Fidget-Spinner committed Jun 7, 2022
commit 65e6abaef2b10d5208c695ce829b0af794691966
6 changes: 3 additions & 3 deletions Include/internal/pycore_opcode.h

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

10 changes: 5 additions & 5 deletions Include/opcode.h

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Lib/opcode.py
Original file line number Diff line number Diff line change
Expand Up @@ -284,12 +284,12 @@ def jabs_op(name, op):
"LOAD_ATTR": [
"LOAD_ATTR_ADAPTIVE",
# LOAD_ATTR
"LOAD_ATTR_CLASS",
"LOAD_ATTR_INSTANCE_VALUE",
"LOAD_ATTR_MODULE",
"LOAD_ATTR_SLOT",
"LOAD_ATTR_WITH_HINT",
# LOAD_METHOD
"LOAD_ATTR_METHOD_CLASS",
"LOAD_ATTR_METHOD_LAZY_DICT",
"LOAD_ATTR_METHOD_NO_DICT",
"LOAD_ATTR_METHOD_WITH_DICT",
Expand Down
47 changes: 24 additions & 23 deletions Python/ceval.c
Original file line number Diff line number Diff line change
Expand Up @@ -3626,6 +3626,30 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int
NOTRACE_DISPATCH();
}

TARGET(LOAD_ATTR_CLASS) {
/* LOAD_METHOD, for class methods */
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);

STAT_INC(LOAD_ATTR, hit);
PyObject* res = read_obj(cache->descr);
assert(res != NULL);
Py_INCREF(res);
SET_TOP(NULL);
STACK_GROW((oparg & 1));
SET_TOP(res);
Py_DECREF(cls);
JUMPBY(INLINE_CACHE_ENTRIES_LOAD_ATTR);
NOTRACE_DISPATCH();
}

TARGET(STORE_ATTR_ADAPTIVE) {
assert(cframe.use_tracing == 0);
_PyAttrCache *cache = (_PyAttrCache *)next_instr;
Expand Down Expand Up @@ -4621,29 +4645,6 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int
NOTRACE_DISPATCH();
}

TARGET(LOAD_ATTR_METHOD_CLASS) {
/* LOAD_METHOD, for class methods */
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);

STAT_INC(LOAD_ATTR, hit);
PyObject *res = read_obj(cache->descr);
assert(res != NULL);
Py_INCREF(res);
SET_TOP(NULL);
Py_DECREF(cls);
PUSH(res);
JUMPBY(INLINE_CACHE_ENTRIES_LOAD_ATTR);
NOTRACE_DISPATCH();
}

TARGET(CALL_BOUND_METHOD_EXACT_ARGS) {
DEOPT_IF(is_method(stack_pointer, oparg), CALL);
PyObject *function = PEEK(oparg + 1);
Expand Down
2 changes: 1 addition & 1 deletion Python/opcode_targets.h

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

65 changes: 25 additions & 40 deletions Python/specialize.c
Original file line number Diff line number Diff line change
Expand Up @@ -653,8 +653,9 @@ specialize_dict_access(
return 1;
}

static int
specialize_attr_loadmethod(PyObject* owner, _Py_CODEUNIT* instr, PyObject* name);
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);

int
_Py_Specialize_LoadAttr(PyObject *owner, _Py_CODEUNIT *instr, PyObject *name)
Expand All @@ -669,25 +670,29 @@ _Py_Specialize_LoadAttr(PyObject *owner, _Py_CODEUNIT *instr, PyObject *name)
}
goto success;
}
int oparg = _Py_OPARG(*instr);
if (oparg & 1) {
int res = specialize_attr_loadmethod(owner, instr, name);
if (res < 0) {
return -1;
}
else if (res) {
goto success;
if (PyType_Check(owner)) {
int err = specialize_class_load_attr(owner, instr, name);
if (err) {
goto fail;
}
/* res == 0 (fail), fall through and let LOAD_ATTR specialize for it */
goto success;
}
PyTypeObject *type = Py_TYPE(owner);
int oparg = _Py_OPARG(*instr);
PyTypeObject* type = Py_TYPE(owner);
if (type->tp_dict == NULL) {
if (PyType_Ready(type) < 0) {
return -1;
}
}
PyObject *descr;
PyObject* descr = NULL;
DescriptorClassification kind = analyze_descriptor(type, name, &descr, 0);
assert(descr != NULL || kind == ABSENT || kind == GETSET_OVERRIDDEN);
if ((oparg & 1) && kind == METHOD) {
if (specialize_attr_loadmethod(owner, instr, name, descr, kind)) {
goto success;
}
/* res == 0 (fail), fall through and let LOAD_ATTR specialize for it */
}
switch(kind) {
case OVERRIDING:
SPECIALIZATION_FAIL(LOAD_ATTR, SPEC_FAIL_ATTR_OVERRIDING_DESCRIPTOR);
Expand Down Expand Up @@ -885,7 +890,7 @@ load_method_fail_kind(DescriptorClassification kind)
#endif

static int
specialize_class_load_method(PyObject *owner, _Py_CODEUNIT *instr,
specialize_class_load_attr(PyObject *owner, _Py_CODEUNIT *instr,
PyObject *name)
{
_PyLoadMethodCache *cache = (_PyLoadMethodCache *)(instr + 1);
Expand All @@ -897,7 +902,7 @@ specialize_class_load_method(PyObject *owner, _Py_CODEUNIT *instr,
case NON_DESCRIPTOR:
write_u32(cache->type_version, ((PyTypeObject *)owner)->tp_version_tag);
write_obj(cache->descr, descr);
_Py_SET_OPCODE(*instr, LOAD_ATTR_METHOD_CLASS);
_Py_SET_OPCODE(*instr, LOAD_ATTR_CLASS);
return 0;
#ifdef Py_STATS
case ABSENT:
Expand Down Expand Up @@ -927,32 +932,13 @@ typedef enum {
// can cause a significant drop in cache hits. A possible test is
// python.exe -m test_typing test_re test_dis test_zlib.
static int
specialize_attr_loadmethod(PyObject *owner, _Py_CODEUNIT *instr, PyObject *name)
specialize_attr_loadmethod(PyObject *owner, _Py_CODEUNIT *instr, PyObject *name,
PyObject *descr, DescriptorClassification kind)
{
_PyLoadMethodCache *cache = (_PyLoadMethodCache *)(instr + 1);
PyTypeObject *owner_cls = Py_TYPE(owner);

if (owner_cls->tp_dict == NULL) {
if (PyType_Ready(owner_cls) < 0) {
return -1;
}
}
if (PyType_Check(owner)) {
int err = specialize_class_load_method(owner, instr, name);
if (err) {
goto fail;
}
goto success;
}

PyObject *descr = NULL;
DescriptorClassification kind = 0;
kind = analyze_descriptor(owner_cls, name, &descr, 0);
assert(descr != NULL || kind == ABSENT || kind == GETSET_OVERRIDDEN);
if (kind != METHOD) {
SPECIALIZATION_FAIL(LOAD_METHOD, load_method_fail_kind(kind));
goto fail;
}
assert(kind == METHOD && descr != NULL);
ObjectDictKind dictkind;
PyDictKeysObject *keys;
if (owner_cls->tp_flags & Py_TPFLAGS_MANAGED_DICT) {
Expand All @@ -968,7 +954,7 @@ specialize_attr_loadmethod(PyObject *owner, _Py_CODEUNIT *instr, PyObject *name)
else {
Py_ssize_t dictoffset = owner_cls->tp_dictoffset;
if (dictoffset < 0 || dictoffset > INT16_MAX) {
SPECIALIZATION_FAIL(LOAD_METHOD, SPEC_FAIL_OUT_OF_RANGE);
SPECIALIZATION_FAIL(LOAD_ATTR, SPEC_FAIL_OUT_OF_RANGE);
goto fail;
}
if (dictoffset == 0) {
Expand Down Expand Up @@ -996,7 +982,7 @@ specialize_attr_loadmethod(PyObject *owner, _Py_CODEUNIT *instr, PyObject *name)
}
uint32_t keys_version = _PyDictKeys_GetVersionForCurrentState(keys);
if (keys_version == 0) {
SPECIALIZATION_FAIL(LOAD_METHOD, SPEC_FAIL_OUT_OF_VERSIONS);
SPECIALIZATION_FAIL(LOAD_ATTR, SPEC_FAIL_OUT_OF_VERSIONS);
goto fail;
}
write_u32(cache->keys_version, keys_version);
Expand Down Expand Up @@ -1037,7 +1023,6 @@ specialize_attr_loadmethod(PyObject *owner, _Py_CODEUNIT *instr, PyObject *name)
write_u32(cache->type_version, owner_cls->tp_version_tag);
write_obj(cache->descr, descr);
// Fall through.
success:
return 1;
fail:
return 0;
Expand Down
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

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