diff --git a/Include/internal/pycore_frame.h b/Include/internal/pycore_frame.h index f2d1c5f26ddcff..0f9e7333cf1e1c 100644 --- a/Include/internal/pycore_frame.h +++ b/Include/internal/pycore_frame.h @@ -65,7 +65,6 @@ typedef struct _PyInterpreterFrame { _Py_CODEUNIT *instr_ptr; /* Instruction currently executing (or about to begin) */ int stacktop; /* Offset of TOS from localsplus */ uint16_t return_offset; /* Only relevant during a function call */ - uint16_t tier2_extra_size; /* How many extra entries is at the end of localsplus for tier 2 inlining */ char owner; /* Locals and stack */ PyObject *localsplus[1]; @@ -132,7 +131,6 @@ _PyFrame_Initialize( frame->instr_ptr = _PyCode_CODE(code); frame->return_offset = 0; frame->owner = FRAME_OWNED_BY_THREAD; - frame->tier2_extra_size = 0; for (int i = null_locals_from; i < code->co_nlocalsplus; i++) { frame->localsplus[i] = NULL; @@ -260,35 +258,6 @@ _PyThreadState_PushFrame(PyThreadState *tstate, size_t size); void _PyThreadState_PopFrame(PyThreadState *tstate, _PyInterpreterFrame *frame); - -/* Converts frame for tier 2. - * Adds stack space at the end of the current frame for Tier 2 execution. - * The frame that is being expanded MUST be the current executing frame, and - * it must be at the top of the datastack. - * */ -static inline int -_PyFrame_ConvertToTier2(PyThreadState *tstate, _PyInterpreterFrame *frame, - int localsplus_grow) -{ - assert(localsplus_grow > 0); - // Already grown previously - if (frame->tier2_extra_size >= localsplus_grow) { - return 0; - } - if (frame->owner != FRAME_OWNED_BY_THREAD) { - return 1; - } - if (!_PyThreadState_HasStackSpace(tstate, localsplus_grow)) { - return 1; - } - assert(_PyThreadState_HasStackSpace(tstate, localsplus_grow)); - assert(tstate->current_frame == frame); - tstate->datastack_top += localsplus_grow; - assert(tstate->datastack_top < tstate->datastack_limit); - frame->tier2_extra_size += localsplus_grow; - return 0; -} - /* Pushes a frame without checking for space. * Must be guarded by _PyThreadState_HasStackSpace() * Consumes reference to func. */ diff --git a/Include/internal/pycore_uop_metadata.h b/Include/internal/pycore_uop_metadata.h index bec9a052036b21..cb8b427c7239f8 100644 --- a/Include/internal/pycore_uop_metadata.h +++ b/Include/internal/pycore_uop_metadata.h @@ -245,7 +245,7 @@ const uint16_t _PyUop_Flags[MAX_UOP_ID+1] = { [_CHECK_VALIDITY_AND_SET_IP] = HAS_DEOPT_FLAG, [_PRE_INLINE] = HAS_ARG_FLAG | HAS_EVAL_BREAK_FLAG, [_POST_INLINE] = HAS_ARG_FLAG | HAS_EVAL_BREAK_FLAG | HAS_ESCAPES_FLAG, - [_GROW_TIER2_FRAME] = HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_ESCAPES_FLAG, + [_GROW_TIER2_FRAME] = HAS_ARG_FLAG | HAS_DEOPT_FLAG, }; const uint8_t _PyUop_Replication[MAX_UOP_ID+1] = { diff --git a/Lib/test/test_sys.py b/Lib/test/test_sys.py index 39fdb1a36dce8c..38dcabd84d8170 100644 --- a/Lib/test/test_sys.py +++ b/Lib/test/test_sys.py @@ -1550,7 +1550,7 @@ class C(object): pass def func(): return sys._getframe() x = func() - check(x, size('3Pi3c7P4ic??2P')) + check(x, size('3Pi3c7P2ic??2P')) # function def func(): pass check(func, size('15Pi')) @@ -1567,7 +1567,7 @@ def bar(cls): check(bar, size('PP')) # generator def get_gen(): yield 1 - check(get_gen(), size('PP4P4c7P4ic??2P')) + check(get_gen(), size('PP4P4c7P2ic??2P')) # iterator check(iter('abc'), size('lP')) # callable-iterator diff --git a/Python/bytecodes.c b/Python/bytecodes.c index 883a66205ba067..d2f104ac5a5666 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -4175,7 +4175,10 @@ dummy_func( } op(_GROW_TIER2_FRAME, (--)) { - DEOPT_IF(_PyFrame_ConvertToTier2(tstate, frame, oparg)); + DEOPT_IF(frame->owner != FRAME_OWNED_BY_THREAD); + DEOPT_IF(stack_pointer + oparg > tstate->datastack_limit); + assert(stack_pointer <= tstate->datastack_top); + tstate->datastack_top = stack_pointer + oparg; } diff --git a/Python/ceval.c b/Python/ceval.c index 3be9668dc65050..f9eb7c2889d9d2 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -1675,11 +1675,10 @@ static void clear_thread_frame(PyThreadState *tstate, _PyInterpreterFrame * frame) { assert(frame->owner == FRAME_OWNED_BY_THREAD); - // Make sure that this is, indeed, the top frame. We can't check this in - // _PyThreadState_PopFrame, since f_code is already cleared at that point: - // This doesn't apply to tier 2 frames. - assert(frame->tier2_extra_size == 0 ? (PyObject **)frame + _PyFrame_GetCode(frame)->co_framesize == - tstate->datastack_top : 1); + // // Make sure that this is, indeed, the top frame. We can't check this in + // // _PyThreadState_PopFrame, since f_code is already cleared at that point: + // assert((PyObject **)frame + _PyFrame_GetCode(frame)->co_framesize == + // tstate->datastack_top); tstate->c_recursion_remaining--; assert(frame->frame_obj == NULL || frame->frame_obj->f_frame == frame); _PyFrame_ClearExceptCode(frame); @@ -1793,7 +1792,6 @@ _PyEvalFramePushAndInit_Ex(PyThreadState *tstate, PyFunctionObject *func, return NULL; } - PyObject * _PyEval_Vector(PyThreadState *tstate, PyFunctionObject *func, PyObject *locals, diff --git a/Python/executor_cases.c.h b/Python/executor_cases.c.h index e8568fc764d1b1..0121479ac6e4b7 100644 --- a/Python/executor_cases.c.h +++ b/Python/executor_cases.c.h @@ -3928,7 +3928,10 @@ case _GROW_TIER2_FRAME: { oparg = CURRENT_OPARG(); - if (_PyFrame_ConvertToTier2(tstate, frame, oparg)) goto deoptimize; + if (frame->owner != FRAME_OWNED_BY_THREAD) goto deoptimize; + if (stack_pointer + oparg > tstate->datastack_limit) goto deoptimize; + assert(stack_pointer <= tstate->datastack_top); + tstate->datastack_top = stack_pointer + oparg; break; }