From 3b12d1b9ccef8a2942dd37a92399ac55730aefd1 Mon Sep 17 00:00:00 2001 From: Fidget-Spinner <28750310+Fidget-Spinner@users.noreply.github.com> Date: Sat, 29 Jan 2022 00:45:38 +0800 Subject: [PATCH 1/9] Near zero-cost super().meth() calls --- Include/internal/pycore_code.h | 8 +- Include/internal/pycore_typeobject.h | 5 ++ Include/opcode.h | 2 + Lib/opcode.py | 3 + .../2022-01-29-00-44-09.bpo-46564.MwLSHf.rst | 5 ++ Objects/typeobject.c | 81 +++++++++++------ Python/ceval.c | 87 ++++++++++++++++++- Python/opcode_targets.h | 4 +- Python/specialize.c | 55 +++++++++++- 9 files changed, 216 insertions(+), 34 deletions(-) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2022-01-29-00-44-09.bpo-46564.MwLSHf.rst diff --git a/Include/internal/pycore_code.h b/Include/internal/pycore_code.h index bbf7a06189ba10..ca7a878d215504 100644 --- a/Include/internal/pycore_code.h +++ b/Include/internal/pycore_code.h @@ -263,6 +263,9 @@ cache_backoff(_PyAdaptiveEntry *entry) { entry->counter = ADAPTIVE_CACHE_BACKOFF; } +/* _interpreter_frame is defined in pycore_frame.h */ +typedef struct _interpreter_frame InterpreterFrame; + /* Specialization functions */ int _Py_Specialize_LoadAttr(PyObject *owner, _Py_CODEUNIT *instr, PyObject *name, SpecializedCacheEntry *cache); @@ -271,7 +274,8 @@ int _Py_Specialize_LoadGlobal(PyObject *globals, PyObject *builtins, _Py_CODEUNI int _Py_Specialize_LoadMethod(PyObject *owner, _Py_CODEUNIT *instr, PyObject *name, SpecializedCacheEntry *cache); int _Py_Specialize_BinarySubscr(PyObject *sub, PyObject *container, _Py_CODEUNIT *instr, SpecializedCacheEntry *cache); int _Py_Specialize_StoreSubscr(PyObject *container, PyObject *sub, _Py_CODEUNIT *instr); -int _Py_Specialize_CallNoKw(PyObject *callable, _Py_CODEUNIT *instr, int nargs, SpecializedCacheEntry *cache, PyObject *builtins); +int _Py_Specialize_CallNoKw(PyObject *callable, _Py_CODEUNIT *instr, int nargs, SpecializedCacheEntry *cache, PyObject *builtins, PyObject **stack_pointer, + InterpreterFrame *frame, PyObject *names); void _Py_Specialize_BinaryOp(PyObject *lhs, PyObject *rhs, _Py_CODEUNIT *instr, SpecializedCacheEntry *cache); void _Py_Specialize_CompareOp(PyObject *lhs, PyObject *rhs, _Py_CODEUNIT *instr, SpecializedCacheEntry *cache); @@ -279,6 +283,8 @@ void _Py_Specialize_CompareOp(PyObject *lhs, PyObject *rhs, _Py_CODEUNIT *instr, /* Deallocator function for static codeobjects used in deepfreeze.py */ void _PyStaticCode_Dealloc(PyCodeObject *co); +#define Py_STATS + #ifdef Py_STATS #define SPECIALIZATION_FAILURE_KINDS 30 diff --git a/Include/internal/pycore_typeobject.h b/Include/internal/pycore_typeobject.h index c480a3a57b436c..9b10398345768e 100644 --- a/Include/internal/pycore_typeobject.h +++ b/Include/internal/pycore_typeobject.h @@ -43,6 +43,11 @@ extern PyStatus _PyTypes_InitSlotDefs(void); extern void _PyStaticType_Dealloc(PyTypeObject *type); +/* _interpreter_frame is defined in pycore_frame.h */ +typedef struct _interpreter_frame InterpreterFrame; + +PyObject *_PySuper_Lookup(PyTypeObject *, PyObject *, PyObject *, int *); +int _PySuper_GetTypeArgs(InterpreterFrame *, PyCodeObject *, PyTypeObject **, PyObject **); #ifdef __cplusplus } diff --git a/Include/opcode.h b/Include/opcode.h index 02cdf42fe2443f..ea32d7e38b333f 100644 --- a/Include/opcode.h +++ b/Include/opcode.h @@ -167,6 +167,8 @@ extern "C" { #define LOAD_FAST__LOAD_CONST 80 #define LOAD_CONST__LOAD_FAST 81 #define STORE_FAST__STORE_FAST 131 +#define CALL_NO_KW_SUPER_0__LOAD_METHOD_CACHED 140 +#define CALL_NO_KW_SUPER_2__LOAD_METHOD_CACHED 141 #define DO_TRACING 255 #ifdef NEED_OPCODE_JUMP_TABLES static uint32_t _PyOpcode_RelativeJump[8] = { diff --git a/Lib/opcode.py b/Lib/opcode.py index 37da05d76d734a..d0fc8b94565575 100644 --- a/Lib/opcode.py +++ b/Lib/opcode.py @@ -280,6 +280,9 @@ def jabs_op(name, op): "LOAD_FAST__LOAD_CONST", "LOAD_CONST__LOAD_FAST", "STORE_FAST__STORE_FAST", + # Specialized super instructions. + "CALL_NO_KW_SUPER_0__LOAD_METHOD_CACHED", + "CALL_NO_KW_SUPER_2__LOAD_METHOD_CACHED", ] _specialization_stats = [ "success", diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-01-29-00-44-09.bpo-46564.MwLSHf.rst b/Misc/NEWS.d/next/Core and Builtins/2022-01-29-00-44-09.bpo-46564.MwLSHf.rst new file mode 100644 index 00000000000000..3f2722c42cbfa6 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2022-01-29-00-44-09.bpo-46564.MwLSHf.rst @@ -0,0 +1,5 @@ +Method calls on :class:`super` are sped up. The 2-argument form, +``super(type, obj).meth()`` is now nearly as fast as an equivalent +``self.meth()`` call. The 0-argument form, while still slower, is still +faster than in previous versions of CPython. Patch by Ken Jin, with +additional contributions by Vladimir Matveev. diff --git a/Objects/typeobject.c b/Objects/typeobject.c index 621ad9745d8448..cbc1b06adc3bca 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -8846,16 +8846,18 @@ super_repr(PyObject *self) ", NULL>", su->type ? su->type->tp_name : "NULL"); } +/* Forward */ +static PyTypeObject *supercheck(PyTypeObject *type, PyObject *obj); static PyObject * -super_getattro(PyObject *self, PyObject *name) +do_super_lookup(superobject *su, PyTypeObject *su_type, PyObject *su_obj, + PyTypeObject *su_obj_type, PyObject *name, int *meth_found) { - superobject *su = (superobject *)self; PyTypeObject *starttype; PyObject *mro; Py_ssize_t i, n; - starttype = su->obj_type; + starttype = su_obj_type; if (starttype == NULL) goto skip; @@ -8875,7 +8877,7 @@ super_getattro(PyObject *self, PyObject *name) /* No need to check the last one: it's gonna be skipped anyway. */ for (i = 0; i+1 < n; i++) { - if ((PyObject *)(su->type) == PyTuple_GET_ITEM(mro, i)) + if ((PyObject *)(su_type) == PyTuple_GET_ITEM(mro, i)) break; } i++; /* skip su->type (if any) */ @@ -8893,17 +8895,25 @@ super_getattro(PyObject *self, PyObject *name) PyObject *res = PyDict_GetItemWithError(dict, name); if (res != NULL) { Py_INCREF(res); - - descrgetfunc f = Py_TYPE(res)->tp_descr_get; - if (f != NULL) { - PyObject *res2; - res2 = f(res, - /* Only pass 'obj' param if this is instance-mode super - (See SF ID #743627) */ - (su->obj == (PyObject *)starttype) ? NULL : su->obj, - (PyObject *)starttype); - Py_DECREF(res); - res = res2; + if (meth_found && + _PyType_HasFeature(Py_TYPE(res), Py_TPFLAGS_METHOD_DESCRIPTOR)) { + *meth_found = 1; + } + else { + if (meth_found) { + *meth_found = 0; + } + descrgetfunc f = Py_TYPE(res)->tp_descr_get; + if (f != NULL) { + PyObject *res2; + res2 = f(res, + /* Only pass 'obj' param if this is instance-mode super + (See SF ID #743627) */ + (su_obj == (PyObject *)starttype) ? NULL : su_obj, + (PyObject *)starttype); + Py_DECREF(res); + res = res2; + } } Py_DECREF(mro); @@ -8919,7 +8929,27 @@ super_getattro(PyObject *self, PyObject *name) Py_DECREF(mro); skip: - return PyObject_GenericGetAttr(self, name); + assert(su != NULL); + return PyObject_GenericGetAttr((PyObject *)su, name); +} + +static PyObject * +super_getattro(PyObject *self, PyObject *name) +{ + superobject *su = (superobject *)self; + return do_super_lookup(su, su->type, su->obj, su->obj_type, name, NULL); +} + +PyObject * +_PySuper_Lookup(PyTypeObject *su_type, PyObject *su_obj, PyObject *name, int *meth_found) +{ + PyTypeObject *starttype = supercheck(su_type, su_obj); + if (starttype == NULL) { + return NULL; + } + PyObject *res = do_super_lookup(NULL, su_type, su_obj, starttype, name, meth_found); + Py_DECREF(starttype); + return res; } static PyTypeObject * @@ -9011,8 +9041,8 @@ super_descr_get(PyObject *self, PyObject *obj, PyObject *type) } } -static int -super_init_without_args(PyFrameObject *f, PyCodeObject *co, +int +_PySuper_GetTypeArgs(InterpreterFrame *f, PyCodeObject *co, PyTypeObject **type_p, PyObject **obj_p) { if (co->co_argcount == 0) { @@ -9021,13 +9051,13 @@ super_init_without_args(PyFrameObject *f, PyCodeObject *co, return -1; } - assert(f->f_frame->f_code->co_nlocalsplus > 0); - PyObject *firstarg = _PyFrame_GetLocalsArray(f->f_frame)[0]; + assert(f->f_code->co_nlocalsplus > 0); + PyObject *firstarg = _PyFrame_GetLocalsArray(f)[0]; // The first argument might be a cell. if (firstarg != NULL && (_PyLocals_GetKind(co->co_localspluskinds, 0) & CO_FAST_CELL)) { // "firstarg" is a cell here unless (very unlikely) super() // was called from the C-API before the first MAKE_CELL op. - if (f->f_frame->f_lasti >= 0) { + if (f->f_lasti >= 0) { assert(_Py_OPCODE(*co->co_firstinstr) == MAKE_CELL || _Py_OPCODE(*co->co_firstinstr) == COPY_FREE_VARS); assert(PyCell_Check(firstarg)); firstarg = PyCell_GET(firstarg); @@ -9047,7 +9077,7 @@ super_init_without_args(PyFrameObject *f, PyCodeObject *co, PyObject *name = PyTuple_GET_ITEM(co->co_localsplusnames, i); assert(PyUnicode_Check(name)); if (_PyUnicode_EqualToASCIIId(name, &PyId___class__)) { - PyObject *cell = _PyFrame_GetLocalsArray(f->f_frame)[i]; + PyObject *cell = _PyFrame_GetLocalsArray(f)[i]; if (cell == NULL || !PyCell_Check(cell)) { PyErr_SetString(PyExc_RuntimeError, "super(): bad __class__ cell"); @@ -9096,17 +9126,14 @@ super_init(PyObject *self, PyObject *args, PyObject *kwds) /* Call super(), without args -- fill in from __class__ and first local variable on the stack. */ PyThreadState *tstate = _PyThreadState_GET(); - PyFrameObject *frame = PyThreadState_GetFrame(tstate); + InterpreterFrame *frame = tstate->cframe->current_frame; if (frame == NULL) { PyErr_SetString(PyExc_RuntimeError, "super(): no current frame"); return -1; } - PyCodeObject *code = PyFrame_GetCode(frame); - int res = super_init_without_args(frame, code, &type, &obj); - Py_DECREF(frame); - Py_DECREF(code); + int res = _PySuper_GetTypeArgs(frame, frame->f_code, &type, &obj); if (res < 0) { return -1; diff --git a/Python/ceval.c b/Python/ceval.c index 106e4080840f44..3fddde7e2f66d1 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -4613,7 +4613,8 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr next_instr--; int nargs = oparg+extra_args; if (_Py_Specialize_CallNoKw( - PEEK(nargs + 1), next_instr, nargs, cache, BUILTINS()) < 0) { + PEEK(nargs + 1), next_instr, nargs, cache, BUILTINS(), + stack_pointer, frame, names) < 0) { goto error; } DISPATCH(); @@ -4930,6 +4931,90 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr DISPATCH(); } + TARGET(CALL_NO_KW_SUPER_0__LOAD_METHOD_CACHED) { + /* super().meth */ + assert(_Py_OPCODE(next_instr[0]) == LOAD_METHOD_ADAPTIVE); + assert(_Py_OPCODE(next_instr[-2]) != PRECALL_METHOD); + SpecializedCacheEntry *caches = GET_CACHE(); + _PyAdaptiveEntry *cache0 = &caches[0].adaptive; + _PyObjectCache *cache1 = &caches[-1].obj; + _PyAdaptiveEntry *lm_adaptive = &caches[-2].adaptive; + int nargs = cache0->original_oparg; + assert(nargs == 0); + + /* CALL_NO_KW_SUPER */ + PyObject *su_obj; + PyTypeObject *su_type; + PyObject *meth; + PyObject *super_callable = TOP(); + + DEOPT_IF(_PyType_CAST(super_callable) != &PySuper_Type, CALL_NO_KW); + + /* super() - zero argument form */ + if (_PySuper_GetTypeArgs(frame, frame->f_code, &su_type, &su_obj) < 0) { + PyErr_Clear(); + DEOPT_IF(1, CALL_NO_KW); + } + assert(su_obj != NULL); + DEOPT_IF(lm_adaptive->version != Py_TYPE(su_obj)->tp_version_tag, CALL_NO_KW); + DEOPT_IF(cache0->version != su_type->tp_version_tag, CALL_NO_KW); + + STAT_INC(CALL_NO_KW, hit); + + /* LOAD_METHOD_CACHED */ + meth = cache1->obj; + assert(meth != NULL && _PyType_HasFeature(Py_TYPE(meth), Py_TPFLAGS_METHOD_DESCRIPTOR)); + Py_INCREF(meth); + SET_TOP(meth); + Py_INCREF(su_obj); + PUSH(su_obj); + + Py_DECREF(super_callable); + next_instr++; + DISPATCH(); + } + + TARGET(CALL_NO_KW_SUPER_2__LOAD_METHOD_CACHED) { + /* super(type, obj).meth */ + assert(_Py_OPCODE(next_instr[0]) == LOAD_METHOD_ADAPTIVE); + assert(_Py_OPCODE(next_instr[-2]) != PRECALL_METHOD); + SpecializedCacheEntry *caches = GET_CACHE(); + _PyAdaptiveEntry *cache0 = &caches[0].adaptive; + _PyObjectCache *cache1 = &caches[-1].obj; + _PyAdaptiveEntry *lm_adaptive = &caches[-2].adaptive; + int nargs = cache0->original_oparg; + int lm_oparg = cache0->index; + assert(nargs == 2); + + /* CALL_NO_KW_SUPER */ + /* super(type, obj) - two argument form */ + PyObject *su_obj = TOP(); + PyTypeObject *su_type = _PyType_CAST(SECOND()); + PyObject *super_callable = THIRD(); + PyObject *meth; + + DEOPT_IF(_PyType_CAST(super_callable) != &PySuper_Type, CALL_NO_KW); + + assert(su_obj != NULL); + DEOPT_IF(lm_adaptive->version != Py_TYPE(su_obj)->tp_version_tag, CALL_NO_KW); + DEOPT_IF(cache0->version != su_type->tp_version_tag, CALL_NO_KW); + + STAT_INC(CALL_NO_KW, hit); + + (void)(POP()); + /* LOAD_METHOD_CACHED */ + meth = cache1->obj; + assert(meth != NULL && _PyType_HasFeature(Py_TYPE(meth), Py_TPFLAGS_METHOD_DESCRIPTOR)); + Py_INCREF(meth); + SET_SECOND(meth); + SET_TOP(su_obj); + + Py_DECREF(super_callable); + Py_DECREF(su_type); + next_instr++; + DISPATCH(); + } + TARGET(CALL_FUNCTION_EX) { PREDICTED(CALL_FUNCTION_EX); PyObject *func, *callargs, *kwargs = NULL, *result; diff --git a/Python/opcode_targets.h b/Python/opcode_targets.h index c6e6d826aee609..acfc6537f7eed1 100644 --- a/Python/opcode_targets.h +++ b/Python/opcode_targets.h @@ -139,8 +139,8 @@ static void *opcode_targets[256] = { &&TARGET_LOAD_DEREF, &&TARGET_STORE_DEREF, &&TARGET_DELETE_DEREF, - &&_unknown_opcode, - &&_unknown_opcode, + &&TARGET_CALL_NO_KW_SUPER_0__LOAD_METHOD_CACHED, + &&TARGET_CALL_NO_KW_SUPER_2__LOAD_METHOD_CACHED, &&TARGET_CALL_FUNCTION_EX, &&_unknown_opcode, &&TARGET_EXTENDED_ARG, diff --git a/Python/specialize.c b/Python/specialize.c index 44c006245ebfc9..8e32a3b11275a5 100644 --- a/Python/specialize.c +++ b/Python/specialize.c @@ -4,6 +4,7 @@ #include "pycore_long.h" #include "pycore_moduleobject.h" #include "pycore_object.h" +#include "pycore_frame.h" #include "opcode.h" #include "structmember.h" // struct PyMemberDef, T_OFFSET_EX @@ -1337,7 +1338,8 @@ _Py_Specialize_StoreSubscr(PyObject *container, PyObject *sub, _Py_CODEUNIT *ins static int specialize_class_call( PyObject *callable, _Py_CODEUNIT *instr, - int nargs, SpecializedCacheEntry *cache) + int nargs, SpecializedCacheEntry *cache, PyObject **stack_pointer, + InterpreterFrame *frame, PyObject *names) { PyTypeObject *tp = _PyType_CAST(callable); if (_Py_OPCODE(instr[-1]) == PRECALL_METHOD) { @@ -1359,6 +1361,51 @@ specialize_class_call( return 0; } } + + _Py_CODEUNIT next_instr = instr[1]; + /* Adaptive super instruction of CALL_NO_KW andLOAD_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_NO_KW]].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_NO_KW, SPEC_FAIL_CLASS); return -1; } @@ -1560,7 +1607,8 @@ int _Py_Specialize_CallNoKw( PyObject *callable, _Py_CODEUNIT *instr, int nargs, SpecializedCacheEntry *cache, - PyObject *builtins) + PyObject *builtins, PyObject **stack_pointer, InterpreterFrame *frame, + PyObject *names) { int fail; if (PyCFunction_CheckExact(callable)) { @@ -1570,7 +1618,8 @@ _Py_Specialize_CallNoKw( fail = specialize_py_call((PyFunctionObject *)callable, instr, nargs, cache); } else if (PyType_Check(callable)) { - fail = specialize_class_call(callable, instr, nargs, cache); + fail = specialize_class_call(callable, instr, nargs, cache, stack_pointer, + frame, names); } else if (Py_IS_TYPE(callable, &PyMethodDescr_Type)) { fail = specialize_method_descriptor( From 5b7a98d77f27cbad654195c027bc597b64fdfb05 Mon Sep 17 00:00:00 2001 From: Fidget-Spinner <28750310+Fidget-Spinner@users.noreply.github.com> Date: Sat, 29 Jan 2022 00:47:02 +0800 Subject: [PATCH 2/9] remove py_stats --- Include/internal/pycore_code.h | 1 - 1 file changed, 1 deletion(-) diff --git a/Include/internal/pycore_code.h b/Include/internal/pycore_code.h index ca7a878d215504..682c6b4d868e2e 100644 --- a/Include/internal/pycore_code.h +++ b/Include/internal/pycore_code.h @@ -283,7 +283,6 @@ void _Py_Specialize_CompareOp(PyObject *lhs, PyObject *rhs, _Py_CODEUNIT *instr, /* Deallocator function for static codeobjects used in deepfreeze.py */ void _PyStaticCode_Dealloc(PyCodeObject *co); -#define Py_STATS #ifdef Py_STATS From efb0ae37c4863b0c3bb19f8980424656d0343970 Mon Sep 17 00:00:00 2001 From: Fidget-Spinner <28750310+Fidget-Spinner@users.noreply.github.com> Date: Sat, 29 Jan 2022 01:06:55 +0800 Subject: [PATCH 3/9] Add vladima to co-authors Co-Authored-By: Vladimir Matveev --- Include/internal/pycore_code.h | 1 - 1 file changed, 1 deletion(-) diff --git a/Include/internal/pycore_code.h b/Include/internal/pycore_code.h index 682c6b4d868e2e..59e423a3d6b0ed 100644 --- a/Include/internal/pycore_code.h +++ b/Include/internal/pycore_code.h @@ -283,7 +283,6 @@ void _Py_Specialize_CompareOp(PyObject *lhs, PyObject *rhs, _Py_CODEUNIT *instr, /* Deallocator function for static codeobjects used in deepfreeze.py */ void _PyStaticCode_Dealloc(PyCodeObject *co); - #ifdef Py_STATS #define SPECIALIZATION_FAILURE_KINDS 30 From 9d64819e62a7aa6d5b7882bfb5e5b44c349b9058 Mon Sep 17 00:00:00 2001 From: Fidget-Spinner <28750310+Fidget-Spinner@users.noreply.github.com> Date: Sat, 29 Jan 2022 01:38:12 +0800 Subject: [PATCH 4/9] fix merge errors --- Include/internal/pycore_code.h | 2 +- Include/opcode.h | 77 ++++++++++++++++++---------------- Programs/test_frozenmain.h | 59 +++++++++++++------------- Python/ceval.c | 20 ++++----- Python/opcode_targets.h | 6 +-- Python/specialize.c | 4 +- 6 files changed, 85 insertions(+), 83 deletions(-) diff --git a/Include/internal/pycore_code.h b/Include/internal/pycore_code.h index b77bab7f7546b5..f81829733d94c5 100644 --- a/Include/internal/pycore_code.h +++ b/Include/internal/pycore_code.h @@ -275,7 +275,7 @@ int _Py_Specialize_LoadMethod(PyObject *owner, _Py_CODEUNIT *instr, PyObject *na int _Py_Specialize_BinarySubscr(PyObject *sub, PyObject *container, _Py_CODEUNIT *instr, SpecializedCacheEntry *cache); int _Py_Specialize_StoreSubscr(PyObject *container, PyObject *sub, _Py_CODEUNIT *instr); int _Py_Specialize_CallNoKw(PyObject *callable, _Py_CODEUNIT *instr, int nargs, - SpecializedCacheEntry *cache, PyObject *kwnames, PyObject *builtins, + PyObject *kwnames, SpecializedCacheEntry *cache, PyObject *builtins, PyObject **stack_pointer, InterpreterFrame *frame, PyObject *names); void _Py_Specialize_BinaryOp(PyObject *lhs, PyObject *rhs, _Py_CODEUNIT *instr, SpecializedCacheEntry *cache); diff --git a/Include/opcode.h b/Include/opcode.h index c29d23c780a7ab..646c4baae010ae 100644 --- a/Include/opcode.h +++ b/Include/opcode.h @@ -134,42 +134,47 @@ extern "C" { #define STORE_SUBSCR_ADAPTIVE 26 #define STORE_SUBSCR_LIST_INT 27 #define STORE_SUBSCR_DICT 28 -#define CALL_NO_KW_ADAPTIVE 29 -#define CALL_NO_KW_BUILTIN_O 34 -#define CALL_NO_KW_BUILTIN_FAST 36 -#define CALL_NO_KW_LEN 37 -#define CALL_NO_KW_ISINSTANCE 38 -#define CALL_NO_KW_PY_SIMPLE 39 -#define CALL_NO_KW_LIST_APPEND 40 -#define CALL_NO_KW_METHOD_DESCRIPTOR_O 41 -#define CALL_NO_KW_TYPE_1 42 -#define CALL_NO_KW_BUILTIN_CLASS_1 43 -#define CALL_NO_KW_METHOD_DESCRIPTOR_FAST 44 -#define JUMP_ABSOLUTE_QUICK 45 -#define LOAD_ATTR_ADAPTIVE 46 -#define LOAD_ATTR_INSTANCE_VALUE 47 -#define LOAD_ATTR_WITH_HINT 48 -#define LOAD_ATTR_SLOT 55 -#define LOAD_ATTR_MODULE 56 -#define LOAD_GLOBAL_ADAPTIVE 57 -#define LOAD_GLOBAL_MODULE 58 -#define LOAD_GLOBAL_BUILTIN 59 -#define LOAD_METHOD_ADAPTIVE 62 -#define LOAD_METHOD_CACHED 63 -#define LOAD_METHOD_CLASS 64 -#define LOAD_METHOD_MODULE 65 -#define LOAD_METHOD_NO_DICT 66 -#define STORE_ATTR_ADAPTIVE 67 -#define STORE_ATTR_INSTANCE_VALUE 72 -#define STORE_ATTR_SLOT 76 -#define STORE_ATTR_WITH_HINT 77 -#define LOAD_FAST__LOAD_FAST 78 -#define STORE_FAST__LOAD_FAST 79 -#define LOAD_FAST__LOAD_CONST 80 -#define LOAD_CONST__LOAD_FAST 81 -#define STORE_FAST__STORE_FAST 131 -#define CALL_NO_KW_SUPER_0__LOAD_METHOD_CACHED 140 -#define CALL_NO_KW_SUPER_2__LOAD_METHOD_CACHED 141 +#define CALL_ADAPTIVE 29 +#define CALL_BUILTIN_CLASS 34 +#define CALL_NO_KW_BUILTIN_O 36 +#define CALL_NO_KW_BUILTIN_FAST 37 +#define CALL_BUILTIN_FAST_WITH_KEYWORDS 38 +#define CALL_NO_KW_LEN 39 +#define CALL_NO_KW_ISINSTANCE 40 +#define CALL_PY_EXACT_ARGS 41 +#define CALL_PY_WITH_DEFAULTS 42 +#define CALL_NO_KW_LIST_APPEND 43 +#define CALL_NO_KW_METHOD_DESCRIPTOR_O 44 +#define CALL_NO_KW_METHOD_DESCRIPTOR_NOARGS 45 +#define CALL_NO_KW_STR_1 46 +#define CALL_NO_KW_TUPLE_1 47 +#define CALL_NO_KW_TYPE_1 48 +#define CALL_NO_KW_METHOD_DESCRIPTOR_FAST 55 +#define JUMP_ABSOLUTE_QUICK 56 +#define LOAD_ATTR_ADAPTIVE 57 +#define LOAD_ATTR_INSTANCE_VALUE 58 +#define LOAD_ATTR_WITH_HINT 59 +#define LOAD_ATTR_SLOT 62 +#define LOAD_ATTR_MODULE 63 +#define LOAD_GLOBAL_ADAPTIVE 64 +#define LOAD_GLOBAL_MODULE 65 +#define LOAD_GLOBAL_BUILTIN 66 +#define LOAD_METHOD_ADAPTIVE 67 +#define LOAD_METHOD_CACHED 72 +#define LOAD_METHOD_CLASS 76 +#define LOAD_METHOD_MODULE 77 +#define LOAD_METHOD_NO_DICT 78 +#define STORE_ATTR_ADAPTIVE 79 +#define STORE_ATTR_INSTANCE_VALUE 80 +#define STORE_ATTR_SLOT 81 +#define STORE_ATTR_WITH_HINT 131 +#define LOAD_FAST__LOAD_FAST 140 +#define STORE_FAST__LOAD_FAST 141 +#define LOAD_FAST__LOAD_CONST 143 +#define LOAD_CONST__LOAD_FAST 150 +#define STORE_FAST__STORE_FAST 153 +#define CALL_NO_KW_SUPER_0__LOAD_METHOD_CACHED 154 +#define CALL_NO_KW_SUPER_2__LOAD_METHOD_CACHED 158 #define DO_TRACING 255 #ifdef NEED_OPCODE_JUMP_TABLES static uint32_t _PyOpcode_RelativeJump[8] = { diff --git a/Programs/test_frozenmain.h b/Programs/test_frozenmain.h index 00f36ff9bd70fa..4052fc6c92632f 100644 --- a/Programs/test_frozenmain.h +++ b/Programs/test_frozenmain.h @@ -1,36 +1,35 @@ // Auto-generated by Programs/freeze_test_frozenmain.py unsigned char M_test_frozenmain[] = { 227,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0, - 0,0,0,0,0,115,96,0,0,0,151,0,100,0,100,1, + 0,0,0,0,0,115,88,0,0,0,151,0,100,0,100,1, 108,0,90,0,100,0,100,1,108,1,90,1,101,2,100,2, - 167,1,171,0,1,0,101,2,100,3,101,0,106,3,167,2, - 171,0,1,0,101,1,106,4,167,0,171,0,100,4,25,0, - 90,5,100,5,68,0,93,15,90,6,101,2,100,6,101,6, - 155,0,100,7,101,5,101,6,25,0,155,0,157,4,167,1, - 171,0,1,0,113,30,100,1,83,0,41,8,233,0,0,0, - 0,78,122,18,70,114,111,122,101,110,32,72,101,108,108,111, - 32,87,111,114,108,100,122,8,115,121,115,46,97,114,103,118, - 218,6,99,111,110,102,105,103,41,5,90,12,112,114,111,103, - 114,97,109,95,110,97,109,101,218,10,101,120,101,99,117,116, - 97,98,108,101,90,15,117,115,101,95,101,110,118,105,114,111, - 110,109,101,110,116,90,17,99,111,110,102,105,103,117,114,101, - 95,99,95,115,116,100,105,111,90,14,98,117,102,102,101,114, - 101,100,95,115,116,100,105,111,122,7,99,111,110,102,105,103, - 32,122,2,58,32,41,7,218,3,115,121,115,90,17,95,116, - 101,115,116,105,110,116,101,114,110,97,108,99,97,112,105,218, - 5,112,114,105,110,116,218,4,97,114,103,118,90,11,103,101, - 116,95,99,111,110,102,105,103,115,114,2,0,0,0,218,3, - 107,101,121,169,0,243,0,0,0,0,250,18,116,101,115,116, - 95,102,114,111,122,101,110,109,97,105,110,46,112,121,218,8, - 60,109,111,100,117,108,101,62,114,11,0,0,0,1,0,0, - 0,115,18,0,0,0,2,128,8,3,8,1,10,2,14,1, - 14,1,8,1,28,7,4,249,115,20,0,0,0,2,128,8, - 3,8,1,10,2,14,1,14,1,2,7,4,1,2,249,32, - 7,115,96,0,0,0,0,0,1,11,1,11,1,11,1,11, - 1,25,1,25,1,25,1,25,1,6,7,27,1,28,1,28, - 1,28,1,6,7,17,19,22,19,27,1,28,1,28,1,28, - 10,27,10,39,10,41,10,41,42,50,10,51,1,7,12,2, - 1,42,1,42,5,8,5,10,11,41,21,24,11,41,11,41, - 28,34,35,38,28,39,11,41,11,41,5,42,5,42,5,42, + 169,1,1,0,101,2,100,3,101,0,106,3,169,2,1,0, + 101,1,106,4,169,0,100,4,25,0,90,5,100,5,68,0, + 93,14,90,6,101,2,100,6,101,6,155,0,100,7,101,5, + 101,6,25,0,155,0,157,4,169,1,1,0,113,27,100,1, + 83,0,41,8,233,0,0,0,0,78,122,18,70,114,111,122, + 101,110,32,72,101,108,108,111,32,87,111,114,108,100,122,8, + 115,121,115,46,97,114,103,118,218,6,99,111,110,102,105,103, + 41,5,90,12,112,114,111,103,114,97,109,95,110,97,109,101, + 218,10,101,120,101,99,117,116,97,98,108,101,90,15,117,115, + 101,95,101,110,118,105,114,111,110,109,101,110,116,90,17,99, + 111,110,102,105,103,117,114,101,95,99,95,115,116,100,105,111, + 90,14,98,117,102,102,101,114,101,100,95,115,116,100,105,111, + 122,7,99,111,110,102,105,103,32,122,2,58,32,41,7,218, + 3,115,121,115,90,17,95,116,101,115,116,105,110,116,101,114, + 110,97,108,99,97,112,105,218,5,112,114,105,110,116,218,4, + 97,114,103,118,90,11,103,101,116,95,99,111,110,102,105,103, + 115,114,2,0,0,0,218,3,107,101,121,169,0,243,0,0, + 0,0,250,18,116,101,115,116,95,102,114,111,122,101,110,109, + 97,105,110,46,112,121,218,8,60,109,111,100,117,108,101,62, + 114,11,0,0,0,1,0,0,0,115,18,0,0,0,2,128, + 8,3,8,1,8,2,12,1,12,1,8,1,26,7,4,249, + 115,20,0,0,0,2,128,8,3,8,1,8,2,12,1,12, + 1,2,7,4,1,2,249,30,7,115,88,0,0,0,0,0, + 1,11,1,11,1,11,1,11,1,25,1,25,1,25,1,25, + 1,6,7,27,1,28,1,28,1,6,7,17,19,22,19,27, + 1,28,1,28,10,27,10,39,10,41,42,50,10,51,1,7, + 12,2,1,42,1,42,5,8,5,10,11,41,21,24,11,41, + 11,41,28,34,35,38,28,39,11,41,11,41,5,42,5,42, 5,42,1,42,1,42,114,9,0,0,0, }; diff --git a/Python/ceval.c b/Python/ceval.c index 4110cdbdc76076..bc519e7de80b7c 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -4634,7 +4634,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr int err = _Py_Specialize_CallNoKw( call_shape.callable, next_instr, nargs, call_shape.kwnames, cache, BUILTINS(), - tack_pointer, frame, names); + stack_pointer, frame, names); if (err < 0) { goto error; } @@ -5087,18 +5087,18 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr PyObject *meth; PyObject *super_callable = TOP(); - DEOPT_IF(_PyType_CAST(super_callable) != &PySuper_Type, CALL_NO_KW); + 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) { PyErr_Clear(); - DEOPT_IF(1, CALL_NO_KW); + DEOPT_IF(1, CALL); } assert(su_obj != NULL); - DEOPT_IF(lm_adaptive->version != Py_TYPE(su_obj)->tp_version_tag, CALL_NO_KW); - DEOPT_IF(cache0->version != su_type->tp_version_tag, CALL_NO_KW); + 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_NO_KW, hit); + STAT_INC(CALL, hit); /* LOAD_METHOD_CACHED */ meth = cache1->obj; @@ -5132,13 +5132,13 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr PyObject *super_callable = THIRD(); PyObject *meth; - DEOPT_IF(_PyType_CAST(super_callable) != &PySuper_Type, CALL_NO_KW); + 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_NO_KW); - DEOPT_IF(cache0->version != su_type->tp_version_tag, CALL_NO_KW); + 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_NO_KW, hit); + STAT_INC(CALL, hit); (void)(POP()); /* LOAD_METHOD_CACHED */ diff --git a/Python/opcode_targets.h b/Python/opcode_targets.h index c0076ef0dfa53e..a8a7649280e64c 100644 --- a/Python/opcode_targets.h +++ b/Python/opcode_targets.h @@ -139,8 +139,6 @@ static void *opcode_targets[256] = { &&TARGET_LOAD_DEREF, &&TARGET_STORE_DEREF, &&TARGET_DELETE_DEREF, - &&TARGET_CALL_NO_KW_SUPER_0__LOAD_METHOD_CACHED, - &&TARGET_CALL_NO_KW_SUPER_2__LOAD_METHOD_CACHED, &&TARGET_LOAD_FAST__LOAD_FAST, &&TARGET_STORE_FAST__LOAD_FAST, &&TARGET_CALL_FUNCTION_EX, @@ -155,11 +153,11 @@ static void *opcode_targets[256] = { &&TARGET_RESUME, &&TARGET_MATCH_CLASS, &&TARGET_STORE_FAST__STORE_FAST, - &&_unknown_opcode, + &&TARGET_CALL_NO_KW_SUPER_0__LOAD_METHOD_CACHED, &&TARGET_FORMAT_VALUE, &&TARGET_BUILD_CONST_KEY_MAP, &&TARGET_BUILD_STRING, - &&_unknown_opcode, + &&TARGET_CALL_NO_KW_SUPER_2__LOAD_METHOD_CACHED, &&_unknown_opcode, &&TARGET_LOAD_METHOD, &&_unknown_opcode, diff --git a/Python/specialize.c b/Python/specialize.c index ebc6493b10f438..d67608338e4ce9 100644 --- a/Python/specialize.c +++ b/Python/specialize.c @@ -1385,12 +1385,12 @@ specialize_class_call( } _Py_CODEUNIT next_instr = instr[1]; - /* Adaptive super instruction of CALL_NO_KW andLOAD_METHOD_ADAPTIVE. */ + /* 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_NO_KW]].adaptive; + _PyAdaptiveEntry *lm_adaptive = &cache[-cache_requirements[CALL]].adaptive; _PyObjectCache *cache1 = &cache[-1].obj; PyObject *su_obj; PyTypeObject *su_type; From ac19aa1c1955f9c639904a871c9a24e3f769b351 Mon Sep 17 00:00:00 2001 From: Fidget-Spinner <28750310+Fidget-Spinner@users.noreply.github.com> Date: Sat, 29 Jan 2022 01:46:57 +0800 Subject: [PATCH 5/9] Update test_frozenmain.h --- Programs/test_frozenmain.h | 59 +++++++++++++++++++------------------- 1 file changed, 30 insertions(+), 29 deletions(-) diff --git a/Programs/test_frozenmain.h b/Programs/test_frozenmain.h index 4052fc6c92632f..00f36ff9bd70fa 100644 --- a/Programs/test_frozenmain.h +++ b/Programs/test_frozenmain.h @@ -1,35 +1,36 @@ // Auto-generated by Programs/freeze_test_frozenmain.py unsigned char M_test_frozenmain[] = { 227,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0, - 0,0,0,0,0,115,88,0,0,0,151,0,100,0,100,1, + 0,0,0,0,0,115,96,0,0,0,151,0,100,0,100,1, 108,0,90,0,100,0,100,1,108,1,90,1,101,2,100,2, - 169,1,1,0,101,2,100,3,101,0,106,3,169,2,1,0, - 101,1,106,4,169,0,100,4,25,0,90,5,100,5,68,0, - 93,14,90,6,101,2,100,6,101,6,155,0,100,7,101,5, - 101,6,25,0,155,0,157,4,169,1,1,0,113,27,100,1, - 83,0,41,8,233,0,0,0,0,78,122,18,70,114,111,122, - 101,110,32,72,101,108,108,111,32,87,111,114,108,100,122,8, - 115,121,115,46,97,114,103,118,218,6,99,111,110,102,105,103, - 41,5,90,12,112,114,111,103,114,97,109,95,110,97,109,101, - 218,10,101,120,101,99,117,116,97,98,108,101,90,15,117,115, - 101,95,101,110,118,105,114,111,110,109,101,110,116,90,17,99, - 111,110,102,105,103,117,114,101,95,99,95,115,116,100,105,111, - 90,14,98,117,102,102,101,114,101,100,95,115,116,100,105,111, - 122,7,99,111,110,102,105,103,32,122,2,58,32,41,7,218, - 3,115,121,115,90,17,95,116,101,115,116,105,110,116,101,114, - 110,97,108,99,97,112,105,218,5,112,114,105,110,116,218,4, - 97,114,103,118,90,11,103,101,116,95,99,111,110,102,105,103, - 115,114,2,0,0,0,218,3,107,101,121,169,0,243,0,0, - 0,0,250,18,116,101,115,116,95,102,114,111,122,101,110,109, - 97,105,110,46,112,121,218,8,60,109,111,100,117,108,101,62, - 114,11,0,0,0,1,0,0,0,115,18,0,0,0,2,128, - 8,3,8,1,8,2,12,1,12,1,8,1,26,7,4,249, - 115,20,0,0,0,2,128,8,3,8,1,8,2,12,1,12, - 1,2,7,4,1,2,249,30,7,115,88,0,0,0,0,0, - 1,11,1,11,1,11,1,11,1,25,1,25,1,25,1,25, - 1,6,7,27,1,28,1,28,1,6,7,17,19,22,19,27, - 1,28,1,28,10,27,10,39,10,41,42,50,10,51,1,7, - 12,2,1,42,1,42,5,8,5,10,11,41,21,24,11,41, - 11,41,28,34,35,38,28,39,11,41,11,41,5,42,5,42, + 167,1,171,0,1,0,101,2,100,3,101,0,106,3,167,2, + 171,0,1,0,101,1,106,4,167,0,171,0,100,4,25,0, + 90,5,100,5,68,0,93,15,90,6,101,2,100,6,101,6, + 155,0,100,7,101,5,101,6,25,0,155,0,157,4,167,1, + 171,0,1,0,113,30,100,1,83,0,41,8,233,0,0,0, + 0,78,122,18,70,114,111,122,101,110,32,72,101,108,108,111, + 32,87,111,114,108,100,122,8,115,121,115,46,97,114,103,118, + 218,6,99,111,110,102,105,103,41,5,90,12,112,114,111,103, + 114,97,109,95,110,97,109,101,218,10,101,120,101,99,117,116, + 97,98,108,101,90,15,117,115,101,95,101,110,118,105,114,111, + 110,109,101,110,116,90,17,99,111,110,102,105,103,117,114,101, + 95,99,95,115,116,100,105,111,90,14,98,117,102,102,101,114, + 101,100,95,115,116,100,105,111,122,7,99,111,110,102,105,103, + 32,122,2,58,32,41,7,218,3,115,121,115,90,17,95,116, + 101,115,116,105,110,116,101,114,110,97,108,99,97,112,105,218, + 5,112,114,105,110,116,218,4,97,114,103,118,90,11,103,101, + 116,95,99,111,110,102,105,103,115,114,2,0,0,0,218,3, + 107,101,121,169,0,243,0,0,0,0,250,18,116,101,115,116, + 95,102,114,111,122,101,110,109,97,105,110,46,112,121,218,8, + 60,109,111,100,117,108,101,62,114,11,0,0,0,1,0,0, + 0,115,18,0,0,0,2,128,8,3,8,1,10,2,14,1, + 14,1,8,1,28,7,4,249,115,20,0,0,0,2,128,8, + 3,8,1,10,2,14,1,14,1,2,7,4,1,2,249,32, + 7,115,96,0,0,0,0,0,1,11,1,11,1,11,1,11, + 1,25,1,25,1,25,1,25,1,6,7,27,1,28,1,28, + 1,28,1,6,7,17,19,22,19,27,1,28,1,28,1,28, + 10,27,10,39,10,41,10,41,42,50,10,51,1,7,12,2, + 1,42,1,42,5,8,5,10,11,41,21,24,11,41,11,41, + 28,34,35,38,28,39,11,41,11,41,5,42,5,42,5,42, 5,42,1,42,1,42,114,9,0,0,0, }; From 1f9bb6cfb98be80c2841431557ad139413b2a0ac Mon Sep 17 00:00:00 2001 From: Fidget-Spinner <28750310+Fidget-Spinner@users.noreply.github.com> Date: Sat, 29 Jan 2022 02:07:43 +0800 Subject: [PATCH 6/9] fix formatting, correct specialization --- Python/ceval.c | 4 -- Python/specialize.c | 89 +++++++++++++++++++++++---------------------- 2 files changed, 46 insertions(+), 47 deletions(-) diff --git a/Python/ceval.c b/Python/ceval.c index bc519e7de80b7c..2067f06fa4e4d7 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -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) { PyErr_Clear(); @@ -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); - STAT_INC(CALL, hit); /* LOAD_METHOD_CACHED */ @@ -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()); diff --git a/Python/specialize.c b/Python/specialize.c index d67608338e4ce9..c655ddce2a9170 100644 --- a/Python/specialize.c +++ b/Python/specialize.c @@ -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; @@ -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; From f4cd3f9aa3f73b34c2bc3a85431d42b993938e70 Mon Sep 17 00:00:00 2001 From: Fidget-Spinner <28750310+Fidget-Spinner@users.noreply.github.com> Date: Sat, 29 Jan 2022 02:22:52 +0800 Subject: [PATCH 7/9] work with new call convention --- Python/ceval.c | 6 +++--- Python/specialize.c | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Python/ceval.c b/Python/ceval.c index 2067f06fa4e4d7..31843b005ac8a4 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -5078,7 +5078,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr _PyAdaptiveEntry *cache0 = &caches[0].adaptive; _PyObjectCache *cache1 = &caches[-1].obj; _PyAdaptiveEntry *lm_adaptive = &caches[-2].adaptive; - int nargs = cache0->original_oparg; + int nargs = call_shape.total_args; assert(nargs == 0); /* CALL_NO_KW_SUPER */ @@ -5119,9 +5119,9 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr _PyAdaptiveEntry *cache0 = &caches[0].adaptive; _PyObjectCache *cache1 = &caches[-1].obj; _PyAdaptiveEntry *lm_adaptive = &caches[-2].adaptive; - int nargs = cache0->original_oparg; - int lm_oparg = cache0->index; + int nargs = call_shape.total_args; assert(nargs == 2); + assert(call_shape.kwnames == NULL); /* CALL_NO_KW_SUPER */ /* super(type, obj) - two argument form */ diff --git a/Python/specialize.c b/Python/specialize.c index c655ddce2a9170..4fe6a5a990f62e 100644 --- a/Python/specialize.c +++ b/Python/specialize.c @@ -1377,6 +1377,7 @@ specialize_class_call( } /* Adaptive super instruction of CALL and LOAD_METHOD_ADAPTIVE. */ if (tp == &PySuper_Type && + kwnames == NULL && _Py_OPCODE(instr[1]) == LOAD_METHOD_ADAPTIVE && _Py_OPCODE(instr[-1]) == PRECALL_FUNCTION && (nargs == 0 || nargs == 2)) { @@ -1430,7 +1431,6 @@ specialize_class_call( return -1; } -fail: SPECIALIZATION_FAIL(CALL, SPEC_FAIL_CLASS_MUTABLE); return -1; } From 19880a919812b51167981fef4e08d6ec64730028 Mon Sep 17 00:00:00 2001 From: Fidget-Spinner <28750310+Fidget-Spinner@users.noreply.github.com> Date: Sat, 29 Jan 2022 21:27:04 +0800 Subject: [PATCH 8/9] partially address review: fix tests, add asserts, add cache modification guards --- Objects/typeobject.c | 6 +++++- Python/ceval.c | 12 ++++++++---- Python/specialize.c | 11 ++++++++++- 3 files changed, 23 insertions(+), 6 deletions(-) diff --git a/Objects/typeobject.c b/Objects/typeobject.c index cbc1b06adc3bca..8bcc90c4474ff7 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -8929,7 +8929,11 @@ do_super_lookup(superobject *su, PyTypeObject *su_type, PyObject *su_obj, Py_DECREF(mro); skip: - assert(su != NULL); + /* only happens when using manual _PySuper_Lookup, never happens in super_getattro */ + if (su == NULL) { + PyErr_BadInternalCall(); + return NULL; + } return PyObject_GenericGetAttr((PyObject *)su, name); } diff --git a/Python/ceval.c b/Python/ceval.c index 31843b005ac8a4..049f9cda1dc54a 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -1361,6 +1361,7 @@ eval_frame_handle_pending(PyThreadState *tstate) /* The integer overflow is checked by an assertion below. */ #define INSTR_OFFSET() ((int)(next_instr - first_instr)) +#define NEXT_INSTR_OFFSET() ((int)(next_instr+1 - first_instr)) #define NEXTOPARG() do { \ _Py_CODEUNIT word = *next_instr; \ opcode = _Py_OPCODE(word); \ @@ -1486,6 +1487,9 @@ eval_frame_handle_pending(PyThreadState *tstate) #define GET_CACHE() \ _GetSpecializedCacheEntryForInstruction(first_instr, INSTR_OFFSET(), oparg) +# define GET_NEXT_INSTR_CACHE() \ + _GetSpecializedCacheEntryForInstruction(first_instr, NEXT_INSTR_OFFSET(), \ + _Py_OPARG(*next_instr)) #define DEOPT_IF(cond, instname) if (cond) { goto instname ## _miss; } @@ -5078,8 +5082,8 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr _PyAdaptiveEntry *cache0 = &caches[0].adaptive; _PyObjectCache *cache1 = &caches[-1].obj; _PyAdaptiveEntry *lm_adaptive = &caches[-2].adaptive; - int nargs = call_shape.total_args; - assert(nargs == 0); + assert(lm_adaptive == &GET_NEXT_INSTR_CACHE()[0].adaptive); + assert(call_shape.total_args == 0); /* CALL_NO_KW_SUPER */ PyObject *su_obj; @@ -5119,8 +5123,8 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr _PyAdaptiveEntry *cache0 = &caches[0].adaptive; _PyObjectCache *cache1 = &caches[-1].obj; _PyAdaptiveEntry *lm_adaptive = &caches[-2].adaptive; - int nargs = call_shape.total_args; - assert(nargs == 2); + assert(lm_adaptive == &GET_NEXT_INSTR_CACHE()[0].adaptive); + assert(call_shape.total_args == 2); assert(call_shape.kwnames == NULL); /* CALL_NO_KW_SUPER */ diff --git a/Python/specialize.c b/Python/specialize.c index 4fe6a5a990f62e..104921de4cdd80 100644 --- a/Python/specialize.c +++ b/Python/specialize.c @@ -962,6 +962,12 @@ _Py_Specialize_LoadMethod(PyObject *owner, _Py_CODEUNIT *instr, PyObject *name, _PyObjectCache *cache2 = &cache[-2].obj; PyTypeObject *owner_cls = Py_TYPE(owner); + _Py_CODEUNIT prev_instr = _Py_OPCODE(instr[-1]); + if (prev_instr == CALL_NO_KW_SUPER_0__LOAD_METHOD_CACHED || + prev_instr == CALL_NO_KW_SUPER_2__LOAD_METHOD_CACHED) { + /* Our own cache entries are already being used by superinstructions. */ + goto fail; + } if (PyModule_CheckExact(owner)) { int err = specialize_module_load_attr(owner, instr, name, cache0, cache1, LOAD_METHOD, LOAD_METHOD_MODULE); @@ -1378,6 +1384,10 @@ specialize_class_call( /* Adaptive super instruction of CALL and LOAD_METHOD_ADAPTIVE. */ if (tp == &PySuper_Type && kwnames == NULL && + /* Important: this also protects us from accidentally overriding a + the next specialized instruction's cache. We can only use the + subsequent LOAD_METHOD cache if it hasn't specialized yet. + */ _Py_OPCODE(instr[1]) == LOAD_METHOD_ADAPTIVE && _Py_OPCODE(instr[-1]) == PRECALL_FUNCTION && (nargs == 0 || nargs == 2)) { @@ -1430,7 +1440,6 @@ specialize_class_call( SPEC_FAIL_CALL_STR : SPEC_FAIL_CLASS_NO_VECTORCALL); return -1; } - SPECIALIZATION_FAIL(CALL, SPEC_FAIL_CLASS_MUTABLE); return -1; } From 696a0e8c3591ba276c6cc102573010aa228939ed Mon Sep 17 00:00:00 2001 From: Fidget-Spinner <28750310+Fidget-Spinner@users.noreply.github.com> Date: Sat, 29 Jan 2022 21:50:46 +0800 Subject: [PATCH 9/9] fix refleak --- Python/specialize.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Python/specialize.c b/Python/specialize.c index 104921de4cdd80..1986a19df6a0d5 100644 --- a/Python/specialize.c +++ b/Python/specialize.c @@ -1421,12 +1421,13 @@ specialize_class_call( SPECIALIZATION_FAIL(CALL, SPEC_FAIL_OTHER); return -1; } + Py_DECREF(meth); if (!meth_found) { SPECIALIZATION_FAIL(CALL, SPEC_FAIL_NOT_DESCRIPTOR); return -1; } cache->adaptive.version = su_type->tp_version_tag; - cache1->obj = meth; + cache1->obj = meth; /* borrowed */ 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)); 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