diff options
| author | Ken Jin <28750310+Fidget-Spinner@users.noreply.github.com> | 2022-08-17 19:37:07 +0800 | 
|---|---|---|
| committer | GitHub <noreply@github.com> | 2022-08-17 12:37:07 +0100 | 
| commit | 7276ca25f5f1440aa4d025350d3de15141854dde (patch) | |
| tree | 253f8e34893018705c9f04810d68e2d798c1bd24 /Python/ceval.c | |
| parent | 36517101dd80cae93da379e95e98a688c52935b7 (diff) | |
| download | cpython-git-7276ca25f5f1440aa4d025350d3de15141854dde.tar.gz | |
GH-93911: Specialize `LOAD_ATTR` for custom `__getattribute__` (GH-93988)
Diffstat (limited to 'Python/ceval.c')
| -rw-r--r-- | Python/ceval.c | 43 | 
1 files changed, 41 insertions, 2 deletions
| diff --git a/Python/ceval.c b/Python/ceval.c index d34d6bfeec..8c17e51e80 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -3698,6 +3698,7 @@ handle_eval_breaker:              DEOPT_IF(cls->tp_version_tag != type_version, LOAD_ATTR);              assert(type_version != 0);              PyObject *fget = read_obj(cache->descr); +            assert(Py_IS_TYPE(fget, &PyFunction_Type));              PyFunctionObject *f = (PyFunctionObject *)fget;              uint32_t func_version = read_u32(cache->keys_version);              assert(func_version != 0); @@ -3709,8 +3710,8 @@ handle_eval_breaker:              Py_INCREF(fget);              _PyInterpreterFrame *new_frame = _PyFrame_PushUnchecked(tstate, f);              SET_TOP(NULL); -            int push_null = !(oparg & 1); -            STACK_SHRINK(push_null); +            int shrink_stack = !(oparg & 1); +            STACK_SHRINK(shrink_stack);              new_frame->localsplus[0] = owner;              for (int i = 1; i < code->co_nlocalsplus; i++) {                  new_frame->localsplus[i] = NULL; @@ -3724,6 +3725,44 @@ handle_eval_breaker:              goto start_frame;          } +        TARGET(LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN) { +            assert(cframe.use_tracing == 0); +            DEOPT_IF(tstate->interp->eval_frame, LOAD_ATTR); +            _PyLoadMethodCache *cache = (_PyLoadMethodCache *)next_instr; +            PyObject *owner = TOP(); +            PyTypeObject *cls = Py_TYPE(owner); +            uint32_t type_version = read_u32(cache->type_version); +            DEOPT_IF(cls->tp_version_tag != type_version, LOAD_ATTR); +            assert(type_version != 0); +            PyObject *getattribute = read_obj(cache->descr); +            assert(Py_IS_TYPE(getattribute, &PyFunction_Type)); +            PyFunctionObject *f = (PyFunctionObject *)getattribute; +            PyCodeObject *code = (PyCodeObject *)f->func_code; +            DEOPT_IF(((PyCodeObject *)f->func_code)->co_argcount != 2, LOAD_ATTR); +            DEOPT_IF(!_PyThreadState_HasStackSpace(tstate, code->co_framesize), CALL); +            STAT_INC(LOAD_ATTR, hit); + +            PyObject *name = GETITEM(names, oparg >> 1); +            Py_INCREF(f); +            _PyInterpreterFrame *new_frame = _PyFrame_PushUnchecked(tstate, f); +            SET_TOP(NULL); +            int shrink_stack = !(oparg & 1); +            STACK_SHRINK(shrink_stack); +            Py_INCREF(name); +            new_frame->localsplus[0] = owner; +            new_frame->localsplus[1] = name; +            for (int i = 2; i < code->co_nlocalsplus; i++) { +                new_frame->localsplus[i] = NULL; +            } +            _PyFrame_SetStackPointer(frame, stack_pointer); +            JUMPBY(INLINE_CACHE_ENTRIES_LOAD_ATTR); +            frame->prev_instr = next_instr - 1; +            new_frame->previous = frame; +            frame = cframe.current_frame = new_frame; +            CALL_STAT_INC(inlined_py_calls); +            goto start_frame; +        } +          TARGET(STORE_ATTR_ADAPTIVE) {              assert(cframe.use_tracing == 0);              _PyAttrCache *cache = (_PyAttrCache *)next_instr; | 
