8000 bpo-46564: Optimize ``super().meth()`` calls via adaptive superinstructions by Fidget-Spinner · Pull Request #30992 · python/cpython · GitHub
[go: up one dir, main page]

Skip to content

bpo-46564: Optimize super().meth() calls via adaptive superinstructions #30992

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

Closed
wants to merge 11 commits into from
Closed
Prev Previous commit
Next Next commit
fix formatting, correct specialization
  • Loading branch information
Fidget-Spinner committed Jan 28, 2022
commit 1f9bb6cfb98be80c2841431557ad139413b2a0ac
4 changes: 0 additions & 4 deletions Python/ceval.c
Original file line number Diff line number Diff line change
Expand Up @@ -5088,7 +5088,6 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr
PyObject *super_callable = TOP();

DEOPT_IF(_PyType_CAST(super_callable) != &PySuper_Type, CALL);

/* super() - zero argument form */
if (_PySuper_GetTypeArgs(frame, frame->f_code, &su_type, &su_obj) < 0) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can't we do this at specialization time? The number of locals, the index of "self", and whether it is a cell are all known then. Likewise the nature of __class__ is also known.

PyErr_Clear();
Expand All @@ -5097,7 +5096,6 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr
assert(su_obj != NULL);
DEOPT_IF(lm_adaptive->version != Py_TYPE(su_obj)->tp_version_tag, CALL);
DEOPT_IF(cache0->version != su_type->tp_version_tag, CALL);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When can this fail?
Isn't the next item in the MRO determined solely by type(self) and __class__, both of which are known at this point?

Copy link
Member Author
@Fidget-Spinner Fidget-Spinner Jan 29, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

8000

I wanted assurance that __class__ didn't change.. Then again, I'm not sure if it can?


STAT_INC(CALL, hit);

/* LOAD_METHOD_CACHED */
Expand Down Expand Up @@ -5133,11 +5131,9 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr
PyObject *meth;

DEOPT_IF(_PyType_CAST(super_callable) != &PySuper_Type, CALL);

assert(su_obj != NULL);
DEOPT_IF(lm_adaptive->version != Py_TYPE(su_obj)->tp_version_tag, CALL);
DEOPT_IF(cache0->version != su_type->tp_version_tag, CALL);

STAT_INC(CALL, hit);

(void)(POP());
Expand Down
89 changes: 46 additions & 43 deletions Python/specialize.c
10000
Original file line number Diff line number Diff line change
Expand Up @@ -1375,6 +1375,52 @@ specialize_class_call(
return 0;
}
}
/* Adaptive super instruction of CALL and LOAD_METHOD_ADAPTIVE. */
if (tp == &PySuper_Type &&
_Py_OPCODE(instr[1]) == LOAD_METHOD_ADAPTIVE &&
_Py_OPCODE(instr[-1]) == PRECALL_FUNCTION &&
(nargs == 0 || nargs == 2)) {
/* Use load_method cache entries too. */
_PyAdaptiveEntry *lm_adaptive = &cache[-cache_requirements[CALL]].adaptive;
_PyObjectCache *cache1 = &cache[-1].obj;
PyObject *su_obj;
PyTypeObject *su_type;
PyObject *meth;
int meth_found;
PyObject *name = PyTuple_GET_ITEM(names, lm_adaptive->original_oparg);

/* Note (KJ): the following operations must not affect tp_version_tag. */
/* super() zero arg form. */
if (nargs == 0) {
if (_PySuper_GetTypeArgs(frame, frame->f_code, &su_type, &su_obj) < 0) {
PyErr_Clear();
SPECIALIZATION_FAIL(CALL, SPEC_FAIL_NOT_DESCRIPTOR);
return -1;
}
}
/* super(su_type, su_obj) two arg form. */
else if (nargs == 2) {
su_type = _PyType_CAST(stack_pointer[-2]);
su_obj = stack_pointer[-1];
}
meth = _PySuper_Lookup(su_type, su_obj, name, &meth_found);
if (meth == NULL) {
assert(PyErr_Occurred());
PyErr_Clear();
SPECIALIZATION_FAIL(CALL, SPEC_FAIL_OTHER);
return -1;
}
if (!meth_found) {
SPECIALIZATION_FAIL(CALL, SPEC_FAIL_NOT_DESCRIPTOR);
return -1;
}
cache->adaptive.version = su_type->tp_version_tag;
cache1->obj = meth;
lm_adaptive->version = Py_TYPE(su_obj)->tp_version_tag;
*instr = _Py_MAKECODEUNIT(nargs == 0 ? CALL_NO_KW_SUPER_0__LOAD_METHOD_CACHED
: CALL_NO_KW_SUPER_2__LOAD_METHOD_CACHED, _Py_OPARG(*instr));
return 0;
}
if (tp->tp_vectorcall != NULL) {
*instr = _Py_MAKECODEUNIT(CALL_BUILTIN_CLASS, _Py_OPARG(*instr));
return 0;
Expand All @@ -1384,49 +1430,6 @@ specialize_class_call(
return -1;
}

_Py_CODEUNIT next_instr = instr[1];
/* Adaptive super instruction of CALL and LOAD_METHOD_ADAPTIVE. */
if (tp == &PySuper_Type &&
_Py_OPCODE(next_instr) == LOAD_METHOD_ADAPTIVE &&
(nargs == 0 || nargs == 2)) {
/* Use load_method cache entries too. */
_PyAdaptiveEntry *lm_adaptive = &cache[-cache_requirements[CALL]].adaptive;
_PyObjectCache *cache1 = &cache[-1].obj;
PyObject *su_obj;
PyTypeObject *su_type;
PyObject *meth;
int meth_found;
PyObject *name = PyTuple_GET_ITEM(names, lm_adaptive->original_oparg);

/* Note (KJ): the following operations must not affect tp_version_tag. */
/* super() zero arg form. */
if (nargs == 0) {
if (_PySuper_GetTypeArgs(frame, frame->f_code, &su_type, &su_obj) < 0) {
PyErr_Clear();
goto fail;
}
}
/* super(su_type, su_obj) two arg form. */
else if (nargs == 2) {
su_type = _PyType_CAST(stack_pointer[-2]);
su_obj = stack_pointer[-1];
}
meth = _PySuper_Lookup(su_type, su_obj, name, &meth_found);
if (meth == NULL) {
assert(PyErr_Occurred());
PyErr_Clear();
goto fail;
}
if (!meth_found) {
goto fail;
}
cache->adaptive.version = su_type->tp_version_tag;
cache1->obj = meth;
lm_adaptive->version = Py_TYPE(su_obj)->tp_version_tag;
*instr = _Py_MAKECODEUNIT(nargs == 0 ? CALL_NO_KW_SUPER_0__LOAD_METHOD_CACHED
: CALL_NO_KW_SUPER_2__LOAD_METHOD_CACHED, _Py_OPARG(*instr));
return 0;
}
fail:
SPECIALIZATION_FAIL(CALL, SPEC_FAIL_CLASS_MUTABLE);
return -1;
Expand Down
0