gh-109094: replace frame->prev_instr by frame->instr_ptr (#109095)

This commit is contained in:
Irit Katriel 2023-10-26 14:43:10 +01:00 committed by GitHub
parent 573eff3e2e
commit 67a91f78e4
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
23 changed files with 249 additions and 164 deletions

View file

@ -58,26 +58,16 @@ typedef struct _PyInterpreterFrame {
PyObject *f_builtins; /* Borrowed reference. Only valid if not on C stack */ PyObject *f_builtins; /* Borrowed reference. Only valid if not on C stack */
PyObject *f_locals; /* Strong reference, may be NULL. Only valid if not on C stack */ PyObject *f_locals; /* Strong reference, may be NULL. Only valid if not on C stack */
PyFrameObject *frame_obj; /* Strong reference, may be NULL. Only valid if not on C stack */ PyFrameObject *frame_obj; /* Strong reference, may be NULL. Only valid if not on C stack */
// NOTE: This is not necessarily the last instruction started in the given _Py_CODEUNIT *instr_ptr; /* Instruction currently executing (or about to begin) */
// frame. Rather, it is the code unit *prior to* the *next* instruction. For
// example, it may be an inline CACHE entry, an instruction we just jumped
// over, or (in the case of a newly-created frame) a totally invalid value:
_Py_CODEUNIT *prev_instr;
int stacktop; /* Offset of TOS from localsplus */ int stacktop; /* Offset of TOS from localsplus */
/* The return_offset determines where a `RETURN` should go in the caller, uint16_t return_offset; /* Only relevant during a function call */
* relative to `prev_instr`.
* It is only meaningful to the callee,
* so it needs to be set in any CALL (to a Python function)
* or SEND (to a coroutine or generator).
* If there is no callee, then it is meaningless. */
uint16_t return_offset;
char owner; char owner;
/* Locals and stack */ /* Locals and stack */
PyObject *localsplus[1]; PyObject *localsplus[1];
} _PyInterpreterFrame; } _PyInterpreterFrame;
#define _PyInterpreterFrame_LASTI(IF) \ #define _PyInterpreterFrame_LASTI(IF) \
((int)((IF)->prev_instr - _PyCode_CODE(_PyFrame_GetCode(IF)))) ((int)((IF)->instr_ptr - _PyCode_CODE(_PyFrame_GetCode(IF))))
static inline PyCodeObject *_PyFrame_GetCode(_PyInterpreterFrame *f) { static inline PyCodeObject *_PyFrame_GetCode(_PyInterpreterFrame *f) {
assert(PyCode_Check(f->f_executable)); assert(PyCode_Check(f->f_executable));
@ -134,7 +124,7 @@ _PyFrame_Initialize(
frame->f_locals = locals; frame->f_locals = locals;
frame->stacktop = code->co_nlocalsplus; frame->stacktop = code->co_nlocalsplus;
frame->frame_obj = NULL; frame->frame_obj = NULL;
frame->prev_instr = _PyCode_CODE(code) - 1; frame->instr_ptr = _PyCode_CODE(code);
frame->return_offset = 0; frame->return_offset = 0;
frame->owner = FRAME_OWNED_BY_THREAD; frame->owner = FRAME_OWNED_BY_THREAD;
@ -185,7 +175,7 @@ _PyFrame_IsIncomplete(_PyInterpreterFrame *frame)
return true; return true;
} }
return frame->owner != FRAME_OWNED_BY_GENERATOR && return frame->owner != FRAME_OWNED_BY_GENERATOR &&
frame->prev_instr < _PyCode_CODE(_PyFrame_GetCode(frame)) + _PyFrame_GetCode(frame)->_co_firsttraceable; frame->instr_ptr < _PyCode_CODE(_PyFrame_GetCode(frame)) + _PyFrame_GetCode(frame)->_co_firsttraceable;
} }
static inline _PyInterpreterFrame * static inline _PyInterpreterFrame *
@ -297,7 +287,7 @@ _PyFrame_PushTrampolineUnchecked(PyThreadState *tstate, PyCodeObject *code, int
frame->f_locals = NULL; frame->f_locals = NULL;
frame->stacktop = code->co_nlocalsplus + stackdepth; frame->stacktop = code->co_nlocalsplus + stackdepth;
frame->frame_obj = NULL; frame->frame_obj = NULL;
frame->prev_instr = _PyCode_CODE(code); frame->instr_ptr = _PyCode_CODE(code);
frame->owner = FRAME_OWNED_BY_THREAD; frame->owner = FRAME_OWNED_BY_THREAD;
frame->return_offset = 0; frame->return_offset = 0;
return frame; return frame;

View file

@ -87,7 +87,7 @@
#define _POP_JUMP_IF_FALSE 359 #define _POP_JUMP_IF_FALSE 359
#define _POP_JUMP_IF_TRUE 360 #define _POP_JUMP_IF_TRUE 360
#define _JUMP_TO_TOP 361 #define _JUMP_TO_TOP 361
#define _SAVE_CURRENT_IP 362 #define _SAVE_RETURN_OFFSET 362
#define _INSERT 363 #define _INSERT 363
extern int _PyOpcode_num_popped(int opcode, int oparg, bool jump); extern int _PyOpcode_num_popped(int opcode, int oparg, bool jump);
@ -654,7 +654,7 @@ int _PyOpcode_num_popped(int opcode, int oparg, bool jump) {
return 0; return 0;
case _SET_IP: case _SET_IP:
return 0; return 0;
case _SAVE_CURRENT_IP: case _SAVE_RETURN_OFFSET:
return 0; return 0;
case _EXIT_TRACE: case _EXIT_TRACE:
return 0; return 0;
@ -1230,7 +1230,7 @@ int _PyOpcode_num_pushed(int opcode, int oparg, bool jump) {
return 0; return 0;
case _SET_IP: case _SET_IP:
return 0; return 0;
case _SAVE_CURRENT_IP: case _SAVE_RETURN_OFFSET:
return 0; return 0;
case _EXIT_TRACE: case _EXIT_TRACE:
return 0; return 0;
@ -1296,7 +1296,7 @@ struct opcode_macro_expansion {
#define OPARG_CACHE_4 4 #define OPARG_CACHE_4 4
#define OPARG_TOP 5 #define OPARG_TOP 5
#define OPARG_BOTTOM 6 #define OPARG_BOTTOM 6
#define OPARG_SET_IP 7 #define OPARG_SAVE_RETURN_OFFSET 7
#define OPCODE_METADATA_FMT(OP) (_PyOpcode_opcode_metadata[(OP)].instr_format) #define OPCODE_METADATA_FMT(OP) (_PyOpcode_opcode_metadata[(OP)].instr_format)
#define SAME_OPCODE_METADATA(OP1, OP2) \ #define SAME_OPCODE_METADATA(OP1, OP2) \
@ -1589,7 +1589,7 @@ const struct opcode_metadata _PyOpcode_opcode_metadata[OPCODE_METADATA_SIZE] = {
[_POP_JUMP_IF_TRUE] = { true, INSTR_FMT_IB, HAS_ARG_FLAG }, [_POP_JUMP_IF_TRUE] = { true, INSTR_FMT_IB, HAS_ARG_FLAG },
[_JUMP_TO_TOP] = { true, INSTR_FMT_IX, HAS_EVAL_BREAK_FLAG }, [_JUMP_TO_TOP] = { true, INSTR_FMT_IX, HAS_EVAL_BREAK_FLAG },
[_SET_IP] = { true, INSTR_FMT_IB, HAS_ARG_FLAG }, [_SET_IP] = { true, INSTR_FMT_IB, HAS_ARG_FLAG },
[_SAVE_CURRENT_IP] = { true, INSTR_FMT_IX, 0 }, [_SAVE_RETURN_OFFSET] = { true, INSTR_FMT_IB, HAS_ARG_FLAG },
[_EXIT_TRACE] = { true, INSTR_FMT_IX, 0 }, [_EXIT_TRACE] = { true, INSTR_FMT_IX, 0 },
[_INSERT] = { true, INSTR_FMT_IB, HAS_ARG_FLAG }, [_INSERT] = { true, INSTR_FMT_IB, HAS_ARG_FLAG },
}; };
@ -1719,8 +1719,8 @@ const struct opcode_macro_expansion _PyOpcode_macro_expansion[OPCODE_MACRO_EXPAN
[LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES] = { .nuops = 4, .uops = { { _GUARD_TYPE_VERSION, 2, 1 }, { _GUARD_DORV_VALUES_INST_ATTR_FROM_DICT, 0, 0 }, { _GUARD_KEYS_VERSION, 2, 3 }, { _LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES, 4, 5 } } }, [LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES] = { .nuops = 4, .uops = { { _GUARD_TYPE_VERSION, 2, 1 }, { _GUARD_DORV_VALUES_INST_ATTR_FROM_DICT, 0, 0 }, { _GUARD_KEYS_VERSION, 2, 3 }, { _LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES, 4, 5 } } },
[LOAD_ATTR_NONDESCRIPTOR_NO_DICT] = { .nuops = 2, .uops = { { _GUARD_TYPE_VERSION, 2, 1 }, { _LOAD_ATTR_NONDESCRIPTOR_NO_DICT, 4, 5 } } }, [LOAD_ATTR_NONDESCRIPTOR_NO_DICT] = { .nuops = 2, .uops = { { _GUARD_TYPE_VERSION, 2, 1 }, { _LOAD_ATTR_NONDESCRIPTOR_NO_DICT, 4, 5 } } },
[LOAD_ATTR_METHOD_LAZY_DICT] = { .nuops = 3, .uops = { { _GUARD_TYPE_VERSION, 2, 1 }, { _CHECK_ATTR_METHOD_LAZY_DICT, 0, 0 }, { _LOAD_ATTR_METHOD_LAZY_DICT, 4, 5 } } }, [LOAD_ATTR_METHOD_LAZY_DICT] = { .nuops = 3, .uops = { { _GUARD_TYPE_VERSION, 2, 1 }, { _CHECK_ATTR_METHOD_LAZY_DICT, 0, 0 }, { _LOAD_ATTR_METHOD_LAZY_DICT, 4, 5 } } },
[CALL_BOUND_METHOD_EXACT_ARGS] = { .nuops = 8, .uops = { { _CHECK_PEP_523, 0, 0 }, { _CHECK_CALL_BOUND_METHOD_EXACT_ARGS, 0, 0 }, { _INIT_CALL_BOUND_METHOD_EXACT_ARGS, 0, 0 }, { _CHECK_FUNCTION_EXACT_ARGS, 2, 1 }, { _CHECK_STACK_SPACE, 0, 0 }, { _INIT_CALL_PY_EXACT_ARGS, 0, 0 }, { _SAVE_CURRENT_IP, 7, 2 }, { _PUSH_FRAME, 0, 0 } } }, [CALL_BOUND_METHOD_EXACT_ARGS] = { .nuops = 8, .uops = { { _CHECK_PEP_523, 0, 0 }, { _CHECK_CALL_BOUND_METHOD_EXACT_ARGS, 0, 0 }, { _INIT_CALL_BOUND_METHOD_EXACT_ARGS, 0, 0 }, { _CHECK_FUNCTION_EXACT_ARGS, 2, 1 }, { _CHECK_STACK_SPACE, 0, 0 }, { _INIT_CALL_PY_EXACT_ARGS, 0, 0 }, { _SAVE_RETURN_OFFSET, 7, 3 }, { _PUSH_FRAME, 0, 0 } } },
[CALL_PY_EXACT_ARGS] = { .nuops = 6, .uops = { { _CHECK_PEP_523, 0, 0 }, { _CHECK_FUNCTION_EXACT_ARGS, 2, 1 }, { _CHECK_STACK_SPACE, 0, 0 }, { _INIT_CALL_PY_EXACT_ARGS, 0, 0 }, { _SAVE_CURRENT_IP, 7, 2 }, { _PUSH_FRAME, 0, 0 } } }, [CALL_PY_EXACT_ARGS] = { .nuops = 6, .uops = { { _CHECK_PEP_523, 0, 0 }, { _CHECK_FUNCTION_EXACT_ARGS, 2, 1 }, { _CHECK_STACK_SPACE, 0, 0 }, { _INIT_CALL_PY_EXACT_ARGS, 0, 0 }, { _SAVE_RETURN_OFFSET, 7, 3 }, { _PUSH_FRAME, 0, 0 } } },
[CALL_TYPE_1] = { .nuops = 1, .uops = { { CALL_TYPE_1, 0, 0 } } }, [CALL_TYPE_1] = { .nuops = 1, .uops = { { CALL_TYPE_1, 0, 0 } } },
[CALL_STR_1] = { .nuops = 1, .uops = { { CALL_STR_1, 0, 0 } } }, [CALL_STR_1] = { .nuops = 1, .uops = { { CALL_STR_1, 0, 0 } } },
[CALL_TUPLE_1] = { .nuops = 1, .uops = { { CALL_TUPLE_1, 0, 0 } } }, [CALL_TUPLE_1] = { .nuops = 1, .uops = { { CALL_TUPLE_1, 0, 0 } } },
@ -1812,7 +1812,7 @@ const char * const _PyOpcode_uop_name[OPCODE_UOP_NAME_SIZE] = {
[_POP_JUMP_IF_FALSE] = "_POP_JUMP_IF_FALSE", [_POP_JUMP_IF_FALSE] = "_POP_JUMP_IF_FALSE",
[_POP_JUMP_IF_TRUE] = "_POP_JUMP_IF_TRUE", [_POP_JUMP_IF_TRUE] = "_POP_JUMP_IF_TRUE",
[_JUMP_TO_TOP] = "_JUMP_TO_TOP", [_JUMP_TO_TOP] = "_JUMP_TO_TOP",
[_SAVE_CURRENT_IP] = "_SAVE_CURRENT_IP", [_SAVE_RETURN_OFFSET] = "_SAVE_RETURN_OFFSET",
[_INSERT] = "_INSERT", [_INSERT] = "_INSERT",
}; };
#endif // NEED_OPCODE_METADATA #endif // NEED_OPCODE_METADATA

View file

@ -87,7 +87,7 @@ typedef struct _Py_DebugOffsets {
struct _interpreter_frame { struct _interpreter_frame {
off_t previous; off_t previous;
off_t executable; off_t executable;
off_t prev_instr; off_t instr_ptr;
off_t localsplus; off_t localsplus;
off_t owner; off_t owner;
} interpreter_frame; } interpreter_frame;

View file

@ -58,7 +58,7 @@ extern PyTypeObject _PyExc_MemoryError;
.interpreter_frame = { \ .interpreter_frame = { \
.previous = offsetof(_PyInterpreterFrame, previous), \ .previous = offsetof(_PyInterpreterFrame, previous), \
.executable = offsetof(_PyInterpreterFrame, f_executable), \ .executable = offsetof(_PyInterpreterFrame, f_executable), \
.prev_instr = offsetof(_PyInterpreterFrame, prev_instr), \ .instr_ptr = offsetof(_PyInterpreterFrame, instr_ptr), \
.localsplus = offsetof(_PyInterpreterFrame, localsplus), \ .localsplus = offsetof(_PyInterpreterFrame, localsplus), \
.owner = offsetof(_PyInterpreterFrame, owner), \ .owner = offsetof(_PyInterpreterFrame, owner), \
}, \ }, \

View file

@ -0,0 +1,3 @@
Replace ``prev_instr`` on the interpreter frame by ``instr_ptr`` which
points to the beginning of the instruction that is currently executing (or
will execute once the frame resumes).

View file

@ -130,3 +130,28 @@ ### Shim frames
`RETURN_GENERATOR` do not need to check whether the current frame is the entry frame. `RETURN_GENERATOR` do not need to check whether the current frame is the entry frame.
The shim frame points to a special code object containing the `INTERPRETER_EXIT` The shim frame points to a special code object containing the `INTERPRETER_EXIT`
instruction which cleans up the shim frame and returns. instruction which cleans up the shim frame and returns.
### The Instruction Pointer
`_PyInterpreterFrame` has two fields which are used to maintain the instruction
pointer: `instr_ptr` and `return_offset`.
When a frame is executing, `instr_ptr` points to the instruction currently being
executed. In a suspended frame, it points to the instruction that would execute
if the frame were to resume. After `frame.f_lineno` is set, `instr_ptr` points to
the next instruction to be executed. During a call to a python function,
`instr_ptr` points to the call instruction, because this is what we would expect
to see in an exception traceback.
The `return_offset` field determines where a `RETURN` should go in the caller,
relative to `instr_ptr`. It is only meaningful to the callee, so it needs to
be set in any instruction that implements a call (to a Python function),
including CALL, SEND and BINARY_SUBSCR_GETITEM, among others. If there is no
callee, then return_offset is meaningless. It is necessary to have a separate
field for the return offset because (1) if we apply this offset to `instr_ptr`
while executing the `RETURN`, this is too early and would lose us information
about the previous instruction which we could need for introspecting and
debugging. (2) `SEND` needs to pass two offsets to the generator: one for
`RETURN` and one for `YIELD`. It uses the `oparg` for one, and the
`return_offset` for the other.

View file

@ -821,7 +821,7 @@ frame_setlineno(PyFrameObject *f, PyObject* p_new_lineno, void *Py_UNUSED(ignore
} }
/* Finally set the new lasti and return OK. */ /* Finally set the new lasti and return OK. */
f->f_lineno = 0; f->f_lineno = 0;
f->f_frame->prev_instr = _PyCode_CODE(code) + best_addr; f->f_frame->instr_ptr = _PyCode_CODE(code) + best_addr;
return 0; return 0;
} }
@ -1079,7 +1079,7 @@ PyFrame_New(PyThreadState *tstate, PyCodeObject *code,
f->f_frame = (_PyInterpreterFrame *)f->_f_frame_data; f->f_frame = (_PyInterpreterFrame *)f->_f_frame_data;
f->f_frame->owner = FRAME_OWNED_BY_FRAME_OBJECT; f->f_frame->owner = FRAME_OWNED_BY_FRAME_OBJECT;
// This frame needs to be "complete", so pretend that the first RESUME ran: // This frame needs to be "complete", so pretend that the first RESUME ran:
f->f_frame->prev_instr = _PyCode_CODE(code) + code->_co_firsttraceable; f->f_frame->instr_ptr = _PyCode_CODE(code) + code->_co_firsttraceable + 1;
assert(!_PyFrame_IsIncomplete(f->f_frame)); assert(!_PyFrame_IsIncomplete(f->f_frame));
Py_DECREF(func); Py_DECREF(func);
_PyObject_GC_TRACK(f); _PyObject_GC_TRACK(f);
@ -1093,7 +1093,7 @@ _PyFrame_OpAlreadyRan(_PyInterpreterFrame *frame, int opcode, int oparg)
assert(_PyOpcode_Deopt[opcode] == opcode); assert(_PyOpcode_Deopt[opcode] == opcode);
int check_oparg = 0; int check_oparg = 0;
for (_Py_CODEUNIT *instruction = _PyCode_CODE(_PyFrame_GetCode(frame)); for (_Py_CODEUNIT *instruction = _PyCode_CODE(_PyFrame_GetCode(frame));
instruction < frame->prev_instr; instruction++) instruction < frame->instr_ptr; instruction++)
{ {
int check_opcode = _PyOpcode_Deopt[instruction->op.code]; int check_opcode = _PyOpcode_Deopt[instruction->op.code];
check_oparg |= instruction->op.arg; check_oparg |= instruction->op.arg;
@ -1135,7 +1135,7 @@ frame_init_get_vars(_PyInterpreterFrame *frame)
frame->localsplus[offset + i] = Py_NewRef(o); frame->localsplus[offset + i] = Py_NewRef(o);
} }
// COPY_FREE_VARS doesn't have inline CACHEs, either: // COPY_FREE_VARS doesn't have inline CACHEs, either:
frame->prev_instr = _PyCode_CODE(_PyFrame_GetCode(frame)); frame->instr_ptr = _PyCode_CODE(_PyFrame_GetCode(frame));
} }

View file

@ -9,6 +9,7 @@
#include "pycore_genobject.h" // struct _Py_async_gen_state #include "pycore_genobject.h" // struct _Py_async_gen_state
#include "pycore_modsupport.h" // _PyArg_CheckPositional() #include "pycore_modsupport.h" // _PyArg_CheckPositional()
#include "pycore_object.h" // _PyObject_GC_UNTRACK() #include "pycore_object.h" // _PyObject_GC_UNTRACK()
#include "pycore_opcode_metadata.h" // _PyOpcode_Caches
#include "pycore_pyerrors.h" // _PyErr_ClearExcState() #include "pycore_pyerrors.h" // _PyErr_ClearExcState()
#include "pycore_pystate.h" // _PyThreadState_GET() #include "pycore_pystate.h" // _PyThreadState_GET()
@ -362,8 +363,7 @@ _PyGen_yf(PyGenObject *gen)
assert(_PyCode_CODE(_PyGen_GetCode(gen))[0].op.code != SEND); assert(_PyCode_CODE(_PyGen_GetCode(gen))[0].op.code != SEND);
return NULL; return NULL;
} }
_Py_CODEUNIT next = frame->prev_instr[1]; if (!is_resume(frame->instr_ptr) || frame->instr_ptr->op.arg < 2)
if (!is_resume(&next) || next.op.arg < 2)
{ {
/* Not in a yield from */ /* Not in a yield from */
return NULL; return NULL;
@ -398,9 +398,12 @@ gen_close(PyGenObject *gen, PyObject *args)
_PyInterpreterFrame *frame = (_PyInterpreterFrame *)gen->gi_iframe; _PyInterpreterFrame *frame = (_PyInterpreterFrame *)gen->gi_iframe;
/* It is possible for the previous instruction to not be a /* It is possible for the previous instruction to not be a
* YIELD_VALUE if the debugger has changed the lineno. */ * YIELD_VALUE if the debugger has changed the lineno. */
if (err == 0 && is_yield(frame->prev_instr)) { assert(_PyOpcode_Caches[YIELD_VALUE] == 0);
assert(is_resume(frame->prev_instr + 1)); assert(_PyOpcode_Caches[INSTRUMENTED_YIELD_VALUE] == 0);
int exception_handler_depth = frame->prev_instr[0].op.arg; if (err == 0 && is_yield(frame->instr_ptr - 1)) {
_Py_CODEUNIT *yield_instr = frame->instr_ptr - 1;
assert(is_resume(frame->instr_ptr));
int exception_handler_depth = yield_instr->op.arg;
assert(exception_handler_depth > 0); assert(exception_handler_depth > 0);
/* We can safely ignore the outermost try block /* We can safely ignore the outermost try block
* as it automatically generated to handle * as it automatically generated to handle

View file

@ -920,6 +920,10 @@
break; break;
} }
case _SAVE_RETURN_OFFSET: {
break;
}
case _EXIT_TRACE: { case _EXIT_TRACE: {
break; break;
} }

View file

@ -183,9 +183,9 @@ dummy_func(
tstate, oparg > 0, frame, next_instr-1); tstate, oparg > 0, frame, next_instr-1);
stack_pointer = _PyFrame_GetStackPointer(frame); stack_pointer = _PyFrame_GetStackPointer(frame);
ERROR_IF(err, error); ERROR_IF(err, error);
if (frame->prev_instr != next_instr-1) { if (frame->instr_ptr != next_instr-1) {
/* Instrumentation has jumped */ /* Instrumentation has jumped */
next_instr = frame->prev_instr; next_instr = frame->instr_ptr;
DISPATCH(); DISPATCH();
} }
} }
@ -657,7 +657,8 @@ dummy_func(
new_frame->localsplus[0] = container; new_frame->localsplus[0] = container;
new_frame->localsplus[1] = sub; new_frame->localsplus[1] = sub;
SKIP_OVER(INLINE_CACHE_ENTRIES_BINARY_SUBSCR); SKIP_OVER(INLINE_CACHE_ENTRIES_BINARY_SUBSCR);
frame->return_offset = 0; assert(1 + INLINE_CACHE_ENTRIES_BINARY_SUBSCR == next_instr - frame->instr_ptr);
frame->return_offset = 1 + INLINE_CACHE_ENTRIES_BINARY_SUBSCR;
DISPATCH_INLINED(new_frame); DISPATCH_INLINED(new_frame);
} }
@ -790,10 +791,9 @@ dummy_func(
_PyInterpreterFrame *dying = frame; _PyInterpreterFrame *dying = frame;
frame = tstate->current_frame = dying->previous; frame = tstate->current_frame = dying->previous;
_PyEval_FrameClearAndPop(tstate, dying); _PyEval_FrameClearAndPop(tstate, dying);
frame->prev_instr += frame->return_offset;
_PyFrame_StackPush(frame, retval); _PyFrame_StackPush(frame, retval);
LOAD_SP(); LOAD_SP();
LOAD_IP(); LOAD_IP(frame->return_offset);
#if LLTRACE && TIER_ONE #if LLTRACE && TIER_ONE
lltrace = maybe_lltrace_resume_frame(frame, &entry_frame, GLOBALS()); lltrace = maybe_lltrace_resume_frame(frame, &entry_frame, GLOBALS());
if (lltrace < 0) { if (lltrace < 0) {
@ -819,8 +819,8 @@ dummy_func(
_PyInterpreterFrame *dying = frame; _PyInterpreterFrame *dying = frame;
frame = tstate->current_frame = dying->previous; frame = tstate->current_frame = dying->previous;
_PyEval_FrameClearAndPop(tstate, dying); _PyEval_FrameClearAndPop(tstate, dying);
frame->prev_instr += frame->return_offset;
_PyFrame_StackPush(frame, retval); _PyFrame_StackPush(frame, retval);
LOAD_IP(frame->return_offset);
goto resume_frame; goto resume_frame;
} }
@ -843,8 +843,8 @@ dummy_func(
_PyInterpreterFrame *dying = frame; _PyInterpreterFrame *dying = frame;
frame = tstate->current_frame = dying->previous; frame = tstate->current_frame = dying->previous;
_PyEval_FrameClearAndPop(tstate, dying); _PyEval_FrameClearAndPop(tstate, dying);
frame->prev_instr += frame->return_offset;
_PyFrame_StackPush(frame, retval); _PyFrame_StackPush(frame, retval);
LOAD_IP(frame->return_offset);
goto resume_frame; goto resume_frame;
} }
@ -980,7 +980,8 @@ dummy_func(
gen->gi_exc_state.previous_item = tstate->exc_info; gen->gi_exc_state.previous_item = tstate->exc_info;
tstate->exc_info = &gen->gi_exc_state; tstate->exc_info = &gen->gi_exc_state;
SKIP_OVER(INLINE_CACHE_ENTRIES_SEND); SKIP_OVER(INLINE_CACHE_ENTRIES_SEND);
frame->return_offset = oparg; assert(1 + INLINE_CACHE_ENTRIES_SEND == next_instr - frame->instr_ptr);
frame->return_offset = (uint16_t)(1 + INLINE_CACHE_ENTRIES_SEND + oparg);
DISPATCH_INLINED(gen_frame); DISPATCH_INLINED(gen_frame);
} }
if (Py_IsNone(v) && PyIter_Check(receiver)) { if (Py_IsNone(v) && PyIter_Check(receiver)) {
@ -1018,13 +1019,15 @@ dummy_func(
gen->gi_exc_state.previous_item = tstate->exc_info; gen->gi_exc_state.previous_item = tstate->exc_info;
tstate->exc_info = &gen->gi_exc_state; tstate->exc_info = &gen->gi_exc_state;
SKIP_OVER(INLINE_CACHE_ENTRIES_SEND); SKIP_OVER(INLINE_CACHE_ENTRIES_SEND);
frame->return_offset = oparg; assert(1 + INLINE_CACHE_ENTRIES_SEND == next_instr - frame->instr_ptr);
frame->return_offset = (uint16_t)(1 + INLINE_CACHE_ENTRIES_SEND + oparg);
DISPATCH_INLINED(gen_frame); DISPATCH_INLINED(gen_frame);
} }
inst(INSTRUMENTED_YIELD_VALUE, (retval -- unused)) { inst(INSTRUMENTED_YIELD_VALUE, (retval -- unused)) {
assert(frame != &entry_frame); assert(frame != &entry_frame);
assert(oparg >= 0); /* make the generator identify this as HAS_ARG */ assert(oparg >= 0); /* make the generator identify this as HAS_ARG */
frame->instr_ptr = next_instr;
PyGenObject *gen = _PyFrame_GetGenerator(frame); PyGenObject *gen = _PyFrame_GetGenerator(frame);
gen->gi_frame_state = FRAME_SUSPENDED; gen->gi_frame_state = FRAME_SUSPENDED;
_PyFrame_SetStackPointer(frame, stack_pointer - 1); _PyFrame_SetStackPointer(frame, stack_pointer - 1);
@ -1039,6 +1042,9 @@ dummy_func(
frame = tstate->current_frame = frame->previous; frame = tstate->current_frame = frame->previous;
gen_frame->previous = NULL; gen_frame->previous = NULL;
_PyFrame_StackPush(frame, retval); _PyFrame_StackPush(frame, retval);
/* We don't know which of these is relevant here, so keep them equal */
assert(INLINE_CACHE_ENTRIES_SEND == INLINE_CACHE_ENTRIES_FOR_ITER);
LOAD_IP(1 + INLINE_CACHE_ENTRIES_SEND);
goto resume_frame; goto resume_frame;
} }
@ -1048,6 +1054,7 @@ dummy_func(
// or throw() call. // or throw() call.
assert(oparg >= 0); /* make the generator identify this as HAS_ARG */ assert(oparg >= 0); /* make the generator identify this as HAS_ARG */
assert(frame != &entry_frame); assert(frame != &entry_frame);
frame->instr_ptr = next_instr;
PyGenObject *gen = _PyFrame_GetGenerator(frame); PyGenObject *gen = _PyFrame_GetGenerator(frame);
gen->gi_frame_state = FRAME_SUSPENDED; gen->gi_frame_state = FRAME_SUSPENDED;
_PyFrame_SetStackPointer(frame, stack_pointer - 1); _PyFrame_SetStackPointer(frame, stack_pointer - 1);
@ -1058,6 +1065,9 @@ dummy_func(
frame = tstate->current_frame = frame->previous; frame = tstate->current_frame = frame->previous;
gen_frame->previous = NULL; gen_frame->previous = NULL;
_PyFrame_StackPush(frame, retval); _PyFrame_StackPush(frame, retval);
/* We don't know which of these is relevant here, so keep them equal */
assert(INLINE_CACHE_ENTRIES_SEND == INLINE_CACHE_ENTRIES_FOR_ITER);
LOAD_IP(1 + INLINE_CACHE_ENTRIES_SEND);
goto resume_frame; goto resume_frame;
} }
@ -1071,7 +1081,7 @@ dummy_func(
if (oparg) { if (oparg) {
PyObject *lasti = values[0]; PyObject *lasti = values[0];
if (PyLong_Check(lasti)) { if (PyLong_Check(lasti)) {
frame->prev_instr = _PyCode_CODE(_PyFrame_GetCode(frame)) + PyLong_AsLong(lasti); frame->instr_ptr = _PyCode_CODE(_PyFrame_GetCode(frame)) + PyLong_AsLong(lasti);
assert(!_PyErr_Occurred(tstate)); assert(!_PyErr_Occurred(tstate));
} }
else { else {
@ -2009,7 +2019,8 @@ dummy_func(
STACK_SHRINK(1); STACK_SHRINK(1);
new_frame->localsplus[0] = owner; new_frame->localsplus[0] = owner;
SKIP_OVER(INLINE_CACHE_ENTRIES_LOAD_ATTR); SKIP_OVER(INLINE_CACHE_ENTRIES_LOAD_ATTR);
frame->return_offset = 0; assert(1 + INLINE_CACHE_ENTRIES_LOAD_ATTR == next_instr - frame->instr_ptr);
frame->return_offset = 1 + INLINE_CACHE_ENTRIES_LOAD_ATTR;
DISPATCH_INLINED(new_frame); DISPATCH_INLINED(new_frame);
} }
@ -2036,7 +2047,8 @@ dummy_func(
new_frame->localsplus[0] = owner; new_frame->localsplus[0] = owner;
new_frame->localsplus[1] = Py_NewRef(name); new_frame->localsplus[1] = Py_NewRef(name);
SKIP_OVER(INLINE_CACHE_ENTRIES_LOAD_ATTR); SKIP_OVER(INLINE_CACHE_ENTRIES_LOAD_ATTR);
frame->return_offset = 0; assert(1 + INLINE_CACHE_ENTRIES_LOAD_ATTR == next_instr - frame->instr_ptr);
frame->return_offset = 1 + INLINE_CACHE_ENTRIES_LOAD_ATTR;
DISPATCH_INLINED(new_frame); DISPATCH_INLINED(new_frame);
} }
@ -2304,13 +2316,14 @@ dummy_func(
_PyExecutorObject *executor = (_PyExecutorObject *)code->co_executors->executors[oparg&255]; _PyExecutorObject *executor = (_PyExecutorObject *)code->co_executors->executors[oparg&255];
int original_oparg = executor->vm_data.oparg | (oparg & 0xfffff00); int original_oparg = executor->vm_data.oparg | (oparg & 0xfffff00);
JUMPBY(1-original_oparg); JUMPBY(1-original_oparg);
frame->prev_instr = next_instr - 1; frame->instr_ptr = next_instr;
Py_INCREF(executor); Py_INCREF(executor);
frame = executor->execute(executor, frame, stack_pointer); frame = executor->execute(executor, frame, stack_pointer);
if (frame == NULL) { if (frame == NULL) {
frame = tstate->current_frame; frame = tstate->current_frame;
goto resume_with_error; goto resume_with_error;
} }
next_instr = frame->instr_ptr;
goto resume_frame; goto resume_frame;
} }
@ -2476,7 +2489,7 @@ dummy_func(
} }
inst(INSTRUMENTED_FOR_ITER, ( -- )) { inst(INSTRUMENTED_FOR_ITER, ( -- )) {
_Py_CODEUNIT *here = next_instr-1; _Py_CODEUNIT *here = frame->instr_ptr;
_Py_CODEUNIT *target; _Py_CODEUNIT *target;
PyObject *iter = TOP(); PyObject *iter = TOP();
PyObject *next = (*Py_TYPE(iter)->tp_iternext)(iter); PyObject *next = (*Py_TYPE(iter)->tp_iternext)(iter);
@ -2672,7 +2685,8 @@ dummy_func(
SKIP_OVER(INLINE_CACHE_ENTRIES_FOR_ITER); SKIP_OVER(INLINE_CACHE_ENTRIES_FOR_ITER);
assert(next_instr[oparg].op.code == END_FOR || assert(next_instr[oparg].op.code == END_FOR ||
next_instr[oparg].op.code == INSTRUMENTED_END_FOR); next_instr[oparg].op.code == INSTRUMENTED_END_FOR);
frame->return_offset = oparg; assert(1 + INLINE_CACHE_ENTRIES_FOR_ITER == next_instr - frame->instr_ptr);
frame->return_offset = 1 + INLINE_CACHE_ENTRIES_FOR_ITER + oparg;
DISPATCH_INLINED(gen_frame); DISPATCH_INLINED(gen_frame);
} }
@ -2983,7 +2997,8 @@ dummy_func(
goto error; goto error;
} }
SKIP_OVER(INLINE_CACHE_ENTRIES_CALL); SKIP_OVER(INLINE_CACHE_ENTRIES_CALL);
frame->return_offset = 0; assert(1 + INLINE_CACHE_ENTRIES_CALL == next_instr - frame->instr_ptr);
frame->return_offset = 1 + INLINE_CACHE_ENTRIES_CALL;
DISPATCH_INLINED(new_frame); DISPATCH_INLINED(new_frame);
} }
/* Callable is not a normal Python function */ /* Callable is not a normal Python function */
@ -3070,7 +3085,6 @@ dummy_func(
op(_PUSH_FRAME, (new_frame: _PyInterpreterFrame* -- unused)) { op(_PUSH_FRAME, (new_frame: _PyInterpreterFrame* -- unused)) {
// Write it out explicitly because it's subtly different. // Write it out explicitly because it's subtly different.
// Eventually this should be the only occurrence of this code. // Eventually this should be the only occurrence of this code.
frame->return_offset = 0;
assert(tstate->interp->eval_frame == NULL); assert(tstate->interp->eval_frame == NULL);
STORE_SP(); STORE_SP();
new_frame->previous = frame; new_frame->previous = frame;
@ -3078,7 +3092,7 @@ dummy_func(
frame = tstate->current_frame = new_frame; frame = tstate->current_frame = new_frame;
tstate->py_recursion_remaining--; tstate->py_recursion_remaining--;
LOAD_SP(); LOAD_SP();
LOAD_IP(); LOAD_IP(0);
#if LLTRACE && TIER_ONE #if LLTRACE && TIER_ONE
lltrace = maybe_lltrace_resume_frame(frame, &entry_frame, GLOBALS()); lltrace = maybe_lltrace_resume_frame(frame, &entry_frame, GLOBALS());
if (lltrace < 0) { if (lltrace < 0) {
@ -3095,7 +3109,7 @@ dummy_func(
_CHECK_FUNCTION_EXACT_ARGS + _CHECK_FUNCTION_EXACT_ARGS +
_CHECK_STACK_SPACE + _CHECK_STACK_SPACE +
_INIT_CALL_PY_EXACT_ARGS + _INIT_CALL_PY_EXACT_ARGS +
_SAVE_CURRENT_IP + // Sets frame->prev_instr _SAVE_RETURN_OFFSET +
_PUSH_FRAME; _PUSH_FRAME;
macro(CALL_PY_EXACT_ARGS) = macro(CALL_PY_EXACT_ARGS) =
@ -3104,7 +3118,7 @@ dummy_func(
_CHECK_FUNCTION_EXACT_ARGS + _CHECK_FUNCTION_EXACT_ARGS +
_CHECK_STACK_SPACE + _CHECK_STACK_SPACE +
_INIT_CALL_PY_EXACT_ARGS + _INIT_CALL_PY_EXACT_ARGS +
_SAVE_CURRENT_IP + // Sets frame->prev_instr _SAVE_RETURN_OFFSET +
_PUSH_FRAME; _PUSH_FRAME;
inst(CALL_PY_WITH_DEFAULTS, (unused/1, func_version/2, callable, self_or_null, args[oparg] -- unused)) { inst(CALL_PY_WITH_DEFAULTS, (unused/1, func_version/2, callable, self_or_null, args[oparg] -- unused)) {
@ -3138,7 +3152,8 @@ dummy_func(
// Manipulate stack and cache directly since we leave using DISPATCH_INLINED(). // Manipulate stack and cache directly since we leave using DISPATCH_INLINED().
STACK_SHRINK(oparg + 2); STACK_SHRINK(oparg + 2);
SKIP_OVER(INLINE_CACHE_ENTRIES_CALL); SKIP_OVER(INLINE_CACHE_ENTRIES_CALL);
frame->return_offset = 0; assert(1 + INLINE_CACHE_ENTRIES_CALL == next_instr - frame->instr_ptr);
frame->return_offset = 1 + INLINE_CACHE_ENTRIES_CALL;
DISPATCH_INLINED(new_frame); DISPATCH_INLINED(new_frame);
} }
@ -3203,7 +3218,7 @@ dummy_func(
Py_DECREF(tp); Py_DECREF(tp);
_PyInterpreterFrame *shim = _PyFrame_PushTrampolineUnchecked( _PyInterpreterFrame *shim = _PyFrame_PushTrampolineUnchecked(
tstate, (PyCodeObject *)&_Py_InitCleanup, 1); tstate, (PyCodeObject *)&_Py_InitCleanup, 1);
assert(_PyCode_CODE((PyCodeObject *)shim->f_executable)[1].op.code == EXIT_INIT_CHECK); assert(_PyCode_CODE((PyCodeObject *)shim->f_executable)[0].op.code == EXIT_INIT_CHECK);
/* Push self onto stack of shim */ /* Push self onto stack of shim */
Py_INCREF(self); Py_INCREF(self);
shim->localsplus[0] = self; shim->localsplus[0] = self;
@ -3215,8 +3230,8 @@ dummy_func(
init_frame->localsplus[i+1] = args[i]; init_frame->localsplus[i+1] = args[i];
} }
SKIP_OVER(INLINE_CACHE_ENTRIES_CALL); SKIP_OVER(INLINE_CACHE_ENTRIES_CALL);
frame->prev_instr = next_instr - 1; assert(1 + INLINE_CACHE_ENTRIES_CALL == next_instr - frame->instr_ptr);
frame->return_offset = 0; frame->return_offset = 1 + INLINE_CACHE_ENTRIES_CALL;
STACK_SHRINK(oparg+2); STACK_SHRINK(oparg+2);
_PyFrame_SetStackPointer(frame, stack_pointer); _PyFrame_SetStackPointer(frame, stack_pointer);
/* Link frames */ /* Link frames */
@ -3585,7 +3600,8 @@ dummy_func(
if (new_frame == NULL) { if (new_frame == NULL) {
goto error; goto error;
} }
frame->return_offset = 0; assert(next_instr - frame->instr_ptr == 1);
frame->return_offset = 1;
DISPATCH_INLINED(new_frame); DISPATCH_INLINED(new_frame);
} }
/* Callable is not a normal Python function */ /* Callable is not a normal Python function */
@ -3681,7 +3697,8 @@ dummy_func(
if (new_frame == NULL) { if (new_frame == NULL) {
goto error; goto error;
} }
frame->return_offset = 0; assert(next_instr - frame->instr_ptr == 1);
frame->return_offset = 1;
DISPATCH_INLINED(new_frame); DISPATCH_INLINED(new_frame);
} }
result = PyObject_Call(func, callargs, kwargs); result = PyObject_Call(func, callargs, kwargs);
@ -3744,6 +3761,7 @@ dummy_func(
assert(EMPTY()); assert(EMPTY());
_PyFrame_SetStackPointer(frame, stack_pointer); _PyFrame_SetStackPointer(frame, stack_pointer);
_PyInterpreterFrame *gen_frame = (_PyInterpreterFrame *)gen->gi_iframe; _PyInterpreterFrame *gen_frame = (_PyInterpreterFrame *)gen->gi_iframe;
frame->instr_ptr = next_instr;
_PyFrame_Copy(frame, gen_frame); _PyFrame_Copy(frame, gen_frame);
assert(frame->frame_obj == NULL); assert(frame->frame_obj == NULL);
gen->gi_frame_state = FRAME_CREATED; gen->gi_frame_state = FRAME_CREATED;
@ -3754,6 +3772,7 @@ dummy_func(
_PyThreadState_PopFrame(tstate, frame); _PyThreadState_PopFrame(tstate, frame);
frame = tstate->current_frame = prev; frame = tstate->current_frame = prev;
_PyFrame_StackPush(frame, (PyObject *)gen); _PyFrame_StackPush(frame, (PyObject *)gen);
LOAD_IP(frame->return_offset);
goto resume_frame; goto resume_frame;
} }
@ -3836,18 +3855,20 @@ dummy_func(
} }
inst(INSTRUMENTED_JUMP_FORWARD, ( -- )) { inst(INSTRUMENTED_JUMP_FORWARD, ( -- )) {
INSTRUMENTED_JUMP(next_instr-1, next_instr+oparg, PY_MONITORING_EVENT_JUMP); _Py_CODEUNIT *here = frame->instr_ptr;
INSTRUMENTED_JUMP(here, next_instr + oparg, PY_MONITORING_EVENT_JUMP);
} }
inst(INSTRUMENTED_JUMP_BACKWARD, ( -- )) { inst(INSTRUMENTED_JUMP_BACKWARD, ( -- )) {
_Py_CODEUNIT *here = frame->instr_ptr;
CHECK_EVAL_BREAKER(); CHECK_EVAL_BREAKER();
INSTRUMENTED_JUMP(next_instr-1, next_instr+1-oparg, PY_MONITORING_EVENT_JUMP); INSTRUMENTED_JUMP(here, next_instr + 1 - oparg, PY_MONITORING_EVENT_JUMP);
} }
inst(INSTRUMENTED_POP_JUMP_IF_TRUE, (unused/1 -- )) { inst(INSTRUMENTED_POP_JUMP_IF_TRUE, (unused/1 -- )) {
PyObject *cond = POP(); PyObject *cond = POP();
assert(PyBool_Check(cond)); assert(PyBool_Check(cond));
_Py_CODEUNIT *here = next_instr - 1; _Py_CODEUNIT *here = frame->instr_ptr;
int flag = Py_IsTrue(cond); int flag = Py_IsTrue(cond);
int offset = flag * oparg; int offset = flag * oparg;
#if ENABLE_SPECIALIZATION #if ENABLE_SPECIALIZATION
@ -3859,7 +3880,7 @@ dummy_func(
inst(INSTRUMENTED_POP_JUMP_IF_FALSE, (unused/1 -- )) { inst(INSTRUMENTED_POP_JUMP_IF_FALSE, (unused/1 -- )) {
PyObject *cond = POP(); PyObject *cond = POP();
assert(PyBool_Check(cond)); assert(PyBool_Check(cond));
_Py_CODEUNIT *here = next_instr - 1; _Py_CODEUNIT *here = frame->instr_ptr;
int flag = Py_IsFalse(cond); int flag = Py_IsFalse(cond);
int offset = flag * oparg; int offset = flag * oparg;
#if ENABLE_SPECIALIZATION #if ENABLE_SPECIALIZATION
@ -3870,7 +3891,7 @@ dummy_func(
inst(INSTRUMENTED_POP_JUMP_IF_NONE, (unused/1 -- )) { inst(INSTRUMENTED_POP_JUMP_IF_NONE, (unused/1 -- )) {
PyObject *value = POP(); PyObject *value = POP();
_Py_CODEUNIT *here = next_instr - 1; _Py_CODEUNIT *here = frame->instr_ptr;
int flag = Py_IsNone(value); int flag = Py_IsNone(value);
int offset; int offset;
if (flag) { if (flag) {
@ -3888,7 +3909,7 @@ dummy_func(
inst(INSTRUMENTED_POP_JUMP_IF_NOT_NONE, (unused/1 -- )) { inst(INSTRUMENTED_POP_JUMP_IF_NOT_NONE, (unused/1 -- )) {
PyObject *value = POP(); PyObject *value = POP();
_Py_CODEUNIT *here = next_instr-1; _Py_CODEUNIT *here = frame->instr_ptr;
int offset; int offset;
int nflag = Py_IsNone(value); int nflag = Py_IsNone(value);
if (nflag) { if (nflag) {
@ -3943,16 +3964,20 @@ dummy_func(
op(_SET_IP, (--)) { op(_SET_IP, (--)) {
TIER_TWO_ONLY TIER_TWO_ONLY
frame->prev_instr = ip_offset + oparg; frame->instr_ptr = ip_offset + oparg;
} }
op(_SAVE_CURRENT_IP, (--)) { op(_SAVE_RETURN_OFFSET, (--)) {
TIER_ONE_ONLY #if TIER_ONE
frame->prev_instr = next_instr - 1; frame->return_offset = (uint16_t)(next_instr - frame->instr_ptr);
#endif
#if TIER_TWO
frame->return_offset = oparg;
#endif
} }
op(_EXIT_TRACE, (--)) { op(_EXIT_TRACE, (--)) {
frame->prev_instr--; // Back up to just before destination TIER_TWO_ONLY
_PyFrame_SetStackPointer(frame, stack_pointer); _PyFrame_SetStackPointer(frame, stack_pointer);
Py_DECREF(self); Py_DECREF(self);
OPT_HIST(trace_uop_execution_counter, trace_run_length_hist); OPT_HIST(trace_uop_execution_counter, trace_run_length_hist);

View file

@ -640,7 +640,9 @@ static const _Py_CODEUNIT _Py_INTERPRETER_TRAMPOLINE_INSTRUCTIONS[] = {
/* Put a NOP at the start, so that the IP points into /* Put a NOP at the start, so that the IP points into
* the code, rather than before it */ * the code, rather than before it */
{ .op.code = NOP, .op.arg = 0 }, { .op.code = NOP, .op.arg = 0 },
{ .op.code = INTERPRETER_EXIT, .op.arg = 0 }, { .op.code = INTERPRETER_EXIT, .op.arg = 0 }, /* reached on return */
{ .op.code = NOP, .op.arg = 0 },
{ .op.code = INTERPRETER_EXIT, .op.arg = 0 }, /* reached on yield */
{ .op.code = RESUME, .op.arg = 0 } { .op.code = RESUME, .op.arg = 0 }
}; };
@ -698,7 +700,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int
entry_frame.f_builtins = (PyObject*)0xaaa4; entry_frame.f_builtins = (PyObject*)0xaaa4;
#endif #endif
entry_frame.f_executable = Py_None; entry_frame.f_executable = Py_None;
entry_frame.prev_instr = (_Py_CODEUNIT *)_Py_INTERPRETER_TRAMPOLINE_INSTRUCTIONS; entry_frame.instr_ptr = (_Py_CODEUNIT *)_Py_INTERPRETER_TRAMPOLINE_INSTRUCTIONS + 1;
entry_frame.stacktop = 0; entry_frame.stacktop = 0;
entry_frame.owner = FRAME_OWNED_BY_CSTACK; entry_frame.owner = FRAME_OWNED_BY_CSTACK;
entry_frame.return_offset = 0; entry_frame.return_offset = 0;
@ -722,7 +724,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int
/* Because this avoids the RESUME, /* Because this avoids the RESUME,
* we need to update instrumentation */ * we need to update instrumentation */
_Py_Instrument(_PyFrame_GetCode(frame), tstate->interp); _Py_Instrument(_PyFrame_GetCode(frame), tstate->interp);
monitor_throw(tstate, frame, frame->prev_instr); monitor_throw(tstate, frame, frame->instr_ptr);
/* TO DO -- Monitor throw entry. */ /* TO DO -- Monitor throw entry. */
goto resume_with_error; goto resume_with_error;
} }
@ -733,19 +735,15 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int
_Py_CODEUNIT *next_instr; _Py_CODEUNIT *next_instr;
PyObject **stack_pointer; PyObject **stack_pointer;
/* Sets the above local variables from the frame */
#define SET_LOCALS_FROM_FRAME() \
/* Jump back to the last instruction executed... */ \
next_instr = frame->prev_instr + 1; \
stack_pointer = _PyFrame_GetStackPointer(frame);
start_frame: start_frame:
if (_Py_EnterRecursivePy(tstate)) { if (_Py_EnterRecursivePy(tstate)) {
goto exit_unwind; goto exit_unwind;
} }
next_instr = frame->instr_ptr;
resume_frame: resume_frame:
SET_LOCALS_FROM_FRAME(); stack_pointer = _PyFrame_GetStackPointer(frame);
#ifdef LLTRACE #ifdef LLTRACE
lltrace = maybe_lltrace_resume_frame(frame, &entry_frame, GLOBALS()); lltrace = maybe_lltrace_resume_frame(frame, &entry_frame, GLOBALS());
@ -774,7 +772,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int
#include "generated_cases.c.h" #include "generated_cases.c.h"
/* INSTRUMENTED_LINE has to be here, rather than in bytecodes.c, /* INSTRUMENTED_LINE has to be here, rather than in bytecodes.c,
* because it needs to capture frame->prev_instr before it is updated, * because it needs to capture frame->instr_ptr before it is updated,
* as happens in the standard instruction prologue. * as happens in the standard instruction prologue.
*/ */
#if USE_COMPUTED_GOTOS #if USE_COMPUTED_GOTOS
@ -783,8 +781,8 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int
case INSTRUMENTED_LINE: case INSTRUMENTED_LINE:
#endif #endif
{ {
_Py_CODEUNIT *prev = frame->prev_instr; _Py_CODEUNIT *prev = frame->instr_ptr;
_Py_CODEUNIT *here = frame->prev_instr = next_instr; _Py_CODEUNIT *here = frame->instr_ptr = next_instr;
_PyFrame_SetStackPointer(frame, stack_pointer); _PyFrame_SetStackPointer(frame, stack_pointer);
int original_opcode = _Py_call_instrumentation_line( int original_opcode = _Py_call_instrumentation_line(
tstate, frame, here, prev); tstate, frame, here, prev);
@ -793,7 +791,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int
next_instr = here+1; next_instr = here+1;
goto error; goto error;
} }
next_instr = frame->prev_instr; next_instr = frame->instr_ptr;
if (next_instr != here) { if (next_instr != here) {
DISPATCH(); DISPATCH();
} }
@ -908,7 +906,8 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int
Python main loop. */ Python main loop. */
PyObject *exc = _PyErr_GetRaisedException(tstate); PyObject *exc = _PyErr_GetRaisedException(tstate);
PUSH(exc); PUSH(exc);
JUMPTO(handler); next_instr = _PyCode_CODE(_PyFrame_GetCode(frame)) + handler;
if (monitor_handled(tstate, frame, next_instr, exc) < 0) { if (monitor_handled(tstate, frame, next_instr, exc) < 0) {
goto exception_unwind; goto exception_unwind;
} }
@ -939,7 +938,8 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int
} }
resume_with_error: resume_with_error:
SET_LOCALS_FROM_FRAME(); next_instr = frame->instr_ptr;
stack_pointer = _PyFrame_GetStackPointer(frame);
goto error; goto error;
} }

View file

@ -62,13 +62,16 @@
#ifdef Py_STATS #ifdef Py_STATS
#define INSTRUCTION_START(op) \ #define INSTRUCTION_START(op) \
do { \ do { \
frame->prev_instr = next_instr++; \ frame->instr_ptr = next_instr++; \
OPCODE_EXE_INC(op); \ OPCODE_EXE_INC(op); \
if (_Py_stats) _Py_stats->opcode_stats[lastopcode].pair_count[op]++; \ if (_Py_stats) _Py_stats->opcode_stats[lastopcode].pair_count[op]++; \
lastopcode = op; \ lastopcode = op; \
} while (0) } while (0)
#else #else
#define INSTRUCTION_START(op) (frame->prev_instr = next_instr++) #define INSTRUCTION_START(op) \
do { \
frame->instr_ptr = next_instr++; \
} while(0)
#endif #endif
#if USE_COMPUTED_GOTOS #if USE_COMPUTED_GOTOS
@ -107,7 +110,6 @@
do { \ do { \
assert(tstate->interp->eval_frame == NULL); \ assert(tstate->interp->eval_frame == NULL); \
_PyFrame_SetStackPointer(frame, stack_pointer); \ _PyFrame_SetStackPointer(frame, stack_pointer); \
frame->prev_instr = next_instr - 1; \
(NEW_FRAME)->previous = frame; \ (NEW_FRAME)->previous = frame; \
frame = tstate->current_frame = (NEW_FRAME); \ frame = tstate->current_frame = (NEW_FRAME); \
CALL_STAT_INC(inlined_py_calls); \ CALL_STAT_INC(inlined_py_calls); \
@ -146,7 +148,6 @@ GETITEM(PyObject *v, Py_ssize_t i) {
opcode = word.op.code; \ opcode = word.op.code; \
oparg = word.op.arg; \ oparg = word.op.arg; \
} while (0) } while (0)
#define JUMPTO(x) (next_instr = _PyCode_CODE(_PyFrame_GetCode(frame)) + (x))
/* JUMPBY makes the generator identify the instruction as a jump. SKIP_OVER is /* JUMPBY makes the generator identify the instruction as a jump. SKIP_OVER is
* for advancing to the next instruction, taking into account cache entries * for advancing to the next instruction, taking into account cache entries
@ -381,8 +382,9 @@ static inline void _Py_LeaveRecursiveCallPy(PyThreadState *tstate) {
#if TIER_ONE #if TIER_ONE
#define LOAD_IP() \ #define LOAD_IP(OFFSET) do { \
do { next_instr = frame->prev_instr+1; } while (0) next_instr = frame->instr_ptr + (OFFSET); \
} while (0)
#define STORE_SP() \ #define STORE_SP() \
_PyFrame_SetStackPointer(frame, stack_pointer) _PyFrame_SetStackPointer(frame, stack_pointer)
@ -395,7 +397,7 @@ stack_pointer = _PyFrame_GetStackPointer(frame);
#if TIER_TWO #if TIER_TWO
#define LOAD_IP() \ #define LOAD_IP(UNUSED) \
do { ip_offset = (_Py_CODEUNIT *)_PyFrame_GetCode(frame)->co_code_adaptive; } while (0) do { ip_offset = (_Py_CODEUNIT *)_PyFrame_GetCode(frame)->co_code_adaptive; } while (0)
#define STORE_SP() \ #define STORE_SP() \

View file

@ -62,7 +62,7 @@ _PyUopExecute(_PyExecutorObject *executor, _PyInterpreterFrame *frame, PyObject
PyUnicode_AsUTF8(_PyFrame_GetCode(frame)->co_qualname), PyUnicode_AsUTF8(_PyFrame_GetCode(frame)->co_qualname),
PyUnicode_AsUTF8(_PyFrame_GetCode(frame)->co_filename), PyUnicode_AsUTF8(_PyFrame_GetCode(frame)->co_filename),
_PyFrame_GetCode(frame)->co_firstlineno, _PyFrame_GetCode(frame)->co_firstlineno,
2 * (long)(frame->prev_instr + 1 - 2 * (long)(frame->instr_ptr -
(_Py_CODEUNIT *)_PyFrame_GetCode(frame)->co_code_adaptive)); (_Py_CODEUNIT *)_PyFrame_GetCode(frame)->co_code_adaptive));
PyThreadState *tstate = _PyThreadState_GET(); PyThreadState *tstate = _PyThreadState_GET();
@ -131,6 +131,7 @@ _PyUopExecute(_PyExecutorObject *executor, _PyInterpreterFrame *frame, PyObject
// The caller recovers the frame from tstate->current_frame. // The caller recovers the frame from tstate->current_frame.
DPRINTF(2, "Error: [Opcode %d, operand %" PRIu64 "]\n", opcode, operand); DPRINTF(2, "Error: [Opcode %d, operand %" PRIu64 "]\n", opcode, operand);
OPT_HIST(trace_uop_execution_counter, trace_run_length_hist); OPT_HIST(trace_uop_execution_counter, trace_run_length_hist);
frame->return_offset = 0; // Don't leave this random
_PyFrame_SetStackPointer(frame, stack_pointer); _PyFrame_SetStackPointer(frame, stack_pointer);
Py_DECREF(self); Py_DECREF(self);
return NULL; return NULL;
@ -140,7 +141,7 @@ _PyUopExecute(_PyExecutorObject *executor, _PyInterpreterFrame *frame, PyObject
// This presumes nothing was popped from the stack (nor pushed). // This presumes nothing was popped from the stack (nor pushed).
DPRINTF(2, "DEOPT: [Opcode %d, operand %" PRIu64 "]\n", opcode, operand); DPRINTF(2, "DEOPT: [Opcode %d, operand %" PRIu64 "]\n", opcode, operand);
OPT_HIST(trace_uop_execution_counter, trace_run_length_hist); OPT_HIST(trace_uop_execution_counter, trace_run_length_hist);
frame->prev_instr--; // Back up to just before destination frame->return_offset = 0; // Dispatch to frame->instr_ptr
_PyFrame_SetStackPointer(frame, stack_pointer); _PyFrame_SetStackPointer(frame, stack_pointer);
Py_DECREF(self); Py_DECREF(self);
return frame; return frame;

View file

@ -692,10 +692,9 @@
_PyInterpreterFrame *dying = frame; _PyInterpreterFrame *dying = frame;
frame = tstate->current_frame = dying->previous; frame = tstate->current_frame = dying->previous;
_PyEval_FrameClearAndPop(tstate, dying); _PyEval_FrameClearAndPop(tstate, dying);
frame->prev_instr += frame->return_offset;
_PyFrame_StackPush(frame, retval); _PyFrame_StackPush(frame, retval);
LOAD_SP(); LOAD_SP();
LOAD_IP(); LOAD_IP(frame->return_offset);
#if LLTRACE && TIER_ONE #if LLTRACE && TIER_ONE
lltrace = maybe_lltrace_resume_frame(frame, &entry_frame, GLOBALS()); lltrace = maybe_lltrace_resume_frame(frame, &entry_frame, GLOBALS());
if (lltrace < 0) { if (lltrace < 0) {
@ -2587,7 +2586,6 @@
STACK_SHRINK(1); STACK_SHRINK(1);
// Write it out explicitly because it's subtly different. // Write it out explicitly because it's subtly different.
// Eventually this should be the only occurrence of this code. // Eventually this should be the only occurrence of this code.
frame->return_offset = 0;
assert(tstate->interp->eval_frame == NULL); assert(tstate->interp->eval_frame == NULL);
STORE_SP(); STORE_SP();
new_frame->previous = frame; new_frame->previous = frame;
@ -2595,7 +2593,7 @@
frame = tstate->current_frame = new_frame; frame = tstate->current_frame = new_frame;
tstate->py_recursion_remaining--; tstate->py_recursion_remaining--;
LOAD_SP(); LOAD_SP();
LOAD_IP(); LOAD_IP(0);
#if LLTRACE && TIER_ONE #if LLTRACE && TIER_ONE
lltrace = maybe_lltrace_resume_frame(frame, &entry_frame, GLOBALS()); lltrace = maybe_lltrace_resume_frame(frame, &entry_frame, GLOBALS());
if (lltrace < 0) { if (lltrace < 0) {
@ -3271,12 +3269,22 @@
case _SET_IP: { case _SET_IP: {
TIER_TWO_ONLY TIER_TWO_ONLY
frame->prev_instr = ip_offset + oparg; frame->instr_ptr = ip_offset + oparg;
break;
}
case _SAVE_RETURN_OFFSET: {
#if TIER_ONE
frame->return_offset = (uint16_t)(next_instr - frame->instr_ptr);
#endif
#if TIER_TWO
frame->return_offset = oparg;
#endif
break; break;
} }
case _EXIT_TRACE: { case _EXIT_TRACE: {
frame->prev_instr--; // Back up to just before destination TIER_TWO_ONLY
_PyFrame_SetStackPointer(frame, stack_pointer); _PyFrame_SetStackPointer(frame, stack_pointer);
Py_DECREF(self); Py_DECREF(self);
OPT_HIST(trace_uop_execution_counter, trace_run_length_hist); OPT_HIST(trace_uop_execution_counter, trace_run_length_hist);

View file

@ -90,7 +90,7 @@ take_ownership(PyFrameObject *f, _PyInterpreterFrame *frame)
// This may be a newly-created generator or coroutine frame. Since it's // This may be a newly-created generator or coroutine frame. Since it's
// dead anyways, just pretend that the first RESUME ran: // dead anyways, just pretend that the first RESUME ran:
PyCodeObject *code = _PyFrame_GetCode(frame); PyCodeObject *code = _PyFrame_GetCode(frame);
frame->prev_instr = _PyCode_CODE(code) + code->_co_firsttraceable; frame->instr_ptr = _PyCode_CODE(code) + code->_co_firsttraceable + 1;
} }
assert(!_PyFrame_IsIncomplete(frame)); assert(!_PyFrame_IsIncomplete(frame));
assert(f->f_back == NULL); assert(f->f_back == NULL);

View file

@ -61,9 +61,9 @@
tstate, oparg > 0, frame, next_instr-1); tstate, oparg > 0, frame, next_instr-1);
stack_pointer = _PyFrame_GetStackPointer(frame); stack_pointer = _PyFrame_GetStackPointer(frame);
if (err) goto error; if (err) goto error;
if (frame->prev_instr != next_instr-1) { if (frame->instr_ptr != next_instr-1) {
/* Instrumentation has jumped */ /* Instrumentation has jumped */
next_instr = frame->prev_instr; next_instr = frame->instr_ptr;
DISPATCH(); DISPATCH();
} }
} }
@ -804,7 +804,8 @@
new_frame->localsplus[0] = container; new_frame->localsplus[0] = container;
new_frame->localsplus[1] = sub; new_frame->localsplus[1] = sub;
SKIP_OVER(INLINE_CACHE_ENTRIES_BINARY_SUBSCR); SKIP_OVER(INLINE_CACHE_ENTRIES_BINARY_SUBSCR);
frame->return_offset = 0; assert(1 + INLINE_CACHE_ENTRIES_BINARY_SUBSCR == next_instr - frame->instr_ptr);
frame->return_offset = 1 + INLINE_CACHE_ENTRIES_BINARY_SUBSCR;
DISPATCH_INLINED(new_frame); DISPATCH_INLINED(new_frame);
} }
@ -999,10 +1000,9 @@
_PyInterpreterFrame *dying = frame; _PyInterpreterFrame *dying = frame;
frame = tstate->current_frame = dying->previous; frame = tstate->current_frame = dying->previous;
_PyEval_FrameClearAndPop(tstate, dying); _PyEval_FrameClearAndPop(tstate, dying);
frame->prev_instr += frame->return_offset;
_PyFrame_StackPush(frame, retval); _PyFrame_StackPush(frame, retval);
LOAD_SP(); LOAD_SP();
LOAD_IP(); LOAD_IP(frame->return_offset);
#if LLTRACE && TIER_ONE #if LLTRACE && TIER_ONE
lltrace = maybe_lltrace_resume_frame(frame, &entry_frame, GLOBALS()); lltrace = maybe_lltrace_resume_frame(frame, &entry_frame, GLOBALS());
if (lltrace < 0) { if (lltrace < 0) {
@ -1028,8 +1028,8 @@
_PyInterpreterFrame *dying = frame; _PyInterpreterFrame *dying = frame;
frame = tstate->current_frame = dying->previous; frame = tstate->current_frame = dying->previous;
_PyEval_FrameClearAndPop(tstate, dying); _PyEval_FrameClearAndPop(tstate, dying);
frame->prev_instr += frame->return_offset;
_PyFrame_StackPush(frame, retval); _PyFrame_StackPush(frame, retval);
LOAD_IP(frame->return_offset);
goto resume_frame; goto resume_frame;
} }
@ -1054,10 +1054,9 @@
_PyInterpreterFrame *dying = frame; _PyInterpreterFrame *dying = frame;
frame = tstate->current_frame = dying->previous; frame = tstate->current_frame = dying->previous;
_PyEval_FrameClearAndPop(tstate, dying); _PyEval_FrameClearAndPop(tstate, dying);
frame->prev_instr += frame->return_offset;
_PyFrame_StackPush(frame, retval); _PyFrame_StackPush(frame, retval);
LOAD_SP(); LOAD_SP();
LOAD_IP(); LOAD_IP(frame->return_offset);
#if LLTRACE && TIER_ONE #if LLTRACE && TIER_ONE
lltrace = maybe_lltrace_resume_frame(frame, &entry_frame, GLOBALS()); lltrace = maybe_lltrace_resume_frame(frame, &entry_frame, GLOBALS());
if (lltrace < 0) { if (lltrace < 0) {
@ -1083,8 +1082,8 @@
_PyInterpreterFrame *dying = frame; _PyInterpreterFrame *dying = frame;
frame = tstate->current_frame = dying->previous; frame = tstate->current_frame = dying->previous;
_PyEval_FrameClearAndPop(tstate, dying); _PyEval_FrameClearAndPop(tstate, dying);
frame->prev_instr += frame->return_offset;
_PyFrame_StackPush(frame, retval); _PyFrame_StackPush(frame, retval);
LOAD_IP(frame->return_offset);
goto resume_frame; goto resume_frame;
} }
@ -1239,7 +1238,8 @@
gen->gi_exc_state.previous_item = tstate->exc_info; gen->gi_exc_state.previous_item = tstate->exc_info;
tstate->exc_info = &gen->gi_exc_state; tstate->exc_info = &gen->gi_exc_state;
SKIP_OVER(INLINE_CACHE_ENTRIES_SEND); SKIP_OVER(INLINE_CACHE_ENTRIES_SEND);
frame->return_offset = oparg; assert(1 + INLINE_CACHE_ENTRIES_SEND == next_instr - frame->instr_ptr);
frame->return_offset = (uint16_t)(1 + INLINE_CACHE_ENTRIES_SEND + oparg);
DISPATCH_INLINED(gen_frame); DISPATCH_INLINED(gen_frame);
} }
if (Py_IsNone(v) && PyIter_Check(receiver)) { if (Py_IsNone(v) && PyIter_Check(receiver)) {
@ -1284,7 +1284,8 @@
gen->gi_exc_state.previous_item = tstate->exc_info; gen->gi_exc_state.previous_item = tstate->exc_info;
tstate->exc_info = &gen->gi_exc_state; tstate->exc_info = &gen->gi_exc_state;
SKIP_OVER(INLINE_CACHE_ENTRIES_SEND); SKIP_OVER(INLINE_CACHE_ENTRIES_SEND);
frame->return_offset = oparg; assert(1 + INLINE_CACHE_ENTRIES_SEND == next_instr - frame->instr_ptr);
frame->return_offset = (uint16_t)(1 + INLINE_CACHE_ENTRIES_SEND + oparg);
DISPATCH_INLINED(gen_frame); DISPATCH_INLINED(gen_frame);
} }
@ -1293,6 +1294,7 @@
retval = stack_pointer[-1]; retval = stack_pointer[-1];
assert(frame != &entry_frame); assert(frame != &entry_frame);
assert(oparg >= 0); /* make the generator identify this as HAS_ARG */ assert(oparg >= 0); /* make the generator identify this as HAS_ARG */
frame->instr_ptr = next_instr;
PyGenObject *gen = _PyFrame_GetGenerator(frame); PyGenObject *gen = _PyFrame_GetGenerator(frame);
gen->gi_frame_state = FRAME_SUSPENDED; gen->gi_frame_state = FRAME_SUSPENDED;
_PyFrame_SetStackPointer(frame, stack_pointer - 1); _PyFrame_SetStackPointer(frame, stack_pointer - 1);
@ -1307,6 +1309,9 @@
frame = tstate->current_frame = frame->previous; frame = tstate->current_frame = frame->previous;
gen_frame->previous = NULL; gen_frame->previous = NULL;
_PyFrame_StackPush(frame, retval); _PyFrame_StackPush(frame, retval);
/* We don't know which of these is relevant here, so keep them equal */
assert(INLINE_CACHE_ENTRIES_SEND == INLINE_CACHE_ENTRIES_FOR_ITER);
LOAD_IP(1 + INLINE_CACHE_ENTRIES_SEND);
goto resume_frame; goto resume_frame;
} }
@ -1318,6 +1323,7 @@
// or throw() call. // or throw() call.
assert(oparg >= 0); /* make the generator identify this as HAS_ARG */ assert(oparg >= 0); /* make the generator identify this as HAS_ARG */
assert(frame != &entry_frame); assert(frame != &entry_frame);
frame->instr_ptr = next_instr;
PyGenObject *gen = _PyFrame_GetGenerator(frame); PyGenObject *gen = _PyFrame_GetGenerator(frame);
gen->gi_frame_state = FRAME_SUSPENDED; gen->gi_frame_state = FRAME_SUSPENDED;
_PyFrame_SetStackPointer(frame, stack_pointer - 1); _PyFrame_SetStackPointer(frame, stack_pointer - 1);
@ -1328,6 +1334,9 @@
frame = tstate->current_frame = frame->previous; frame = tstate->current_frame = frame->previous;
gen_frame->previous = NULL; gen_frame->previous = NULL;
_PyFrame_StackPush(frame, retval); _PyFrame_StackPush(frame, retval);
/* We don't know which of these is relevant here, so keep them equal */
assert(INLINE_CACHE_ENTRIES_SEND == INLINE_CACHE_ENTRIES_FOR_ITER);
LOAD_IP(1 + INLINE_CACHE_ENTRIES_SEND);
goto resume_frame; goto resume_frame;
} }
@ -1349,7 +1358,7 @@
if (oparg) { if (oparg) {
PyObject *lasti = values[0]; PyObject *lasti = values[0];
if (PyLong_Check(lasti)) { if (PyLong_Check(lasti)) {
frame->prev_instr = _PyCode_CODE(_PyFrame_GetCode(frame)) + PyLong_AsLong(lasti); frame->instr_ptr = _PyCode_CODE(_PyFrame_GetCode(frame)) + PyLong_AsLong(lasti);
assert(!_PyErr_Occurred(tstate)); assert(!_PyErr_Occurred(tstate));
} }
else { else {
@ -2578,7 +2587,8 @@
STACK_SHRINK(1); STACK_SHRINK(1);
new_frame->localsplus[0] = owner; new_frame->localsplus[0] = owner;
SKIP_OVER(INLINE_CACHE_ENTRIES_LOAD_ATTR); SKIP_OVER(INLINE_CACHE_ENTRIES_LOAD_ATTR);
frame->return_offset = 0; assert(1 + INLINE_CACHE_ENTRIES_LOAD_ATTR == next_instr - frame->instr_ptr);
frame->return_offset = 1 + INLINE_CACHE_ENTRIES_LOAD_ATTR;
DISPATCH_INLINED(new_frame); DISPATCH_INLINED(new_frame);
} }
@ -2610,7 +2620,8 @@
new_frame->localsplus[0] = owner; new_frame->localsplus[0] = owner;
new_frame->localsplus[1] = Py_NewRef(name); new_frame->localsplus[1] = Py_NewRef(name);
SKIP_OVER(INLINE_CACHE_ENTRIES_LOAD_ATTR); SKIP_OVER(INLINE_CACHE_ENTRIES_LOAD_ATTR);
frame->return_offset = 0; assert(1 + INLINE_CACHE_ENTRIES_LOAD_ATTR == next_instr - frame->instr_ptr);
frame->return_offset = 1 + INLINE_CACHE_ENTRIES_LOAD_ATTR;
DISPATCH_INLINED(new_frame); DISPATCH_INLINED(new_frame);
} }
@ -2986,13 +2997,14 @@
_PyExecutorObject *executor = (_PyExecutorObject *)code->co_executors->executors[oparg&255]; _PyExecutorObject *executor = (_PyExecutorObject *)code->co_executors->executors[oparg&255];
int original_oparg = executor->vm_data.oparg | (oparg & 0xfffff00); int original_oparg = executor->vm_data.oparg | (oparg & 0xfffff00);
JUMPBY(1-original_oparg); JUMPBY(1-original_oparg);
frame->prev_instr = next_instr - 1; frame->instr_ptr = next_instr;
Py_INCREF(executor); Py_INCREF(executor);
frame = executor->execute(executor, frame, stack_pointer); frame = executor->execute(executor, frame, stack_pointer);
if (frame == NULL) { if (frame == NULL) {
frame = tstate->current_frame; frame = tstate->current_frame;
goto resume_with_error; goto resume_with_error;
} }
next_instr = frame->instr_ptr;
goto resume_frame; goto resume_frame;
} }
@ -3259,7 +3271,7 @@
} }
TARGET(INSTRUMENTED_FOR_ITER) { TARGET(INSTRUMENTED_FOR_ITER) {
_Py_CODEUNIT *here = next_instr-1; _Py_CODEUNIT *here = frame->instr_ptr;
_Py_CODEUNIT *target; _Py_CODEUNIT *target;
PyObject *iter = TOP(); PyObject *iter = TOP();
PyObject *next = (*Py_TYPE(iter)->tp_iternext)(iter); PyObject *next = (*Py_TYPE(iter)->tp_iternext)(iter);
@ -3427,7 +3439,8 @@
SKIP_OVER(INLINE_CACHE_ENTRIES_FOR_ITER); SKIP_OVER(INLINE_CACHE_ENTRIES_FOR_ITER);
assert(next_instr[oparg].op.code == END_FOR || assert(next_instr[oparg].op.code == END_FOR ||
next_instr[oparg].op.code == INSTRUMENTED_END_FOR); next_instr[oparg].op.code == INSTRUMENTED_END_FOR);
frame->return_offset = oparg; assert(1 + INLINE_CACHE_ENTRIES_FOR_ITER == next_instr - frame->instr_ptr);
frame->return_offset = 1 + INLINE_CACHE_ENTRIES_FOR_ITER + oparg;
DISPATCH_INLINED(gen_frame); DISPATCH_INLINED(gen_frame);
} }
@ -3815,7 +3828,8 @@
goto error; goto error;
} }
SKIP_OVER(INLINE_CACHE_ENTRIES_CALL); SKIP_OVER(INLINE_CACHE_ENTRIES_CALL);
frame->return_offset = 0; assert(1 + INLINE_CACHE_ENTRIES_CALL == next_instr - frame->instr_ptr);
frame->return_offset = 1 + INLINE_CACHE_ENTRIES_CALL;
DISPATCH_INLINED(new_frame); DISPATCH_INLINED(new_frame);
} }
/* Callable is not a normal Python function */ /* Callable is not a normal Python function */
@ -3915,11 +3929,15 @@
new_frame->localsplus[i] = args[i]; new_frame->localsplus[i] = args[i];
} }
} }
// _SAVE_CURRENT_IP // _SAVE_RETURN_OFFSET
next_instr += 3; next_instr += 3;
{ {
TIER_ONE_ONLY #if TIER_ONE
frame->prev_instr = next_instr - 1; frame->return_offset = (uint16_t)(next_instr - frame->instr_ptr);
#endif
#if TIER_TWO
frame->return_offset = oparg;
#endif
} }
// _PUSH_FRAME // _PUSH_FRAME
STACK_SHRINK(oparg); STACK_SHRINK(oparg);
@ -3927,7 +3945,6 @@
{ {
// Write it out explicitly because it's subtly different. // Write it out explicitly because it's subtly different.
// Eventually this should be the only occurrence of this code. // Eventually this should be the only occurrence of this code.
frame->return_offset = 0;
assert(tstate->interp->eval_frame == NULL); assert(tstate->interp->eval_frame == NULL);
STORE_SP(); STORE_SP();
new_frame->previous = frame; new_frame->previous = frame;
@ -3935,7 +3952,7 @@
frame = tstate->current_frame = new_frame; frame = tstate->current_frame = new_frame;
tstate->py_recursion_remaining--; tstate->py_recursion_remaining--;
LOAD_SP(); LOAD_SP();
LOAD_IP(); LOAD_IP(0);
#if LLTRACE && TIER_ONE #if LLTRACE && TIER_ONE
lltrace = maybe_lltrace_resume_frame(frame, &entry_frame, GLOBALS()); lltrace = maybe_lltrace_resume_frame(frame, &entry_frame, GLOBALS());
if (lltrace < 0) { if (lltrace < 0) {
@ -3988,11 +4005,15 @@
new_frame->localsplus[i] = args[i]; new_frame->localsplus[i] = args[i];
} }
} }
// _SAVE_CURRENT_IP // _SAVE_RETURN_OFFSET
next_instr += 3; next_instr += 3;
{ {
TIER_ONE_ONLY #if TIER_ONE
frame->prev_instr = next_instr - 1; frame->return_offset = (uint16_t)(next_instr - frame->instr_ptr);
#endif
#if TIER_TWO
frame->return_offset = oparg;
#endif
} }
// _PUSH_FRAME // _PUSH_FRAME
STACK_SHRINK(oparg); STACK_SHRINK(oparg);
@ -4000,7 +4021,6 @@
{ {
// Write it out explicitly because it's subtly different. // Write it out explicitly because it's subtly different.
// Eventually this should be the only occurrence of this code. // Eventually this should be the only occurrence of this code.
frame->return_offset = 0;
assert(tstate->interp->eval_frame == NULL); assert(tstate->interp->eval_frame == NULL);
STORE_SP(); STORE_SP();
new_frame->previous = frame; new_frame->previous = frame;
@ -4008,7 +4028,7 @@
frame = tstate->current_frame = new_frame; frame = tstate->current_frame = new_frame;
tstate->py_recursion_remaining--; tstate->py_recursion_remaining--;
LOAD_SP(); LOAD_SP();
LOAD_IP(); LOAD_IP(0);
#if LLTRACE && TIER_ONE #if LLTRACE && TIER_ONE
lltrace = maybe_lltrace_resume_frame(frame, &entry_frame, GLOBALS()); lltrace = maybe_lltrace_resume_frame(frame, &entry_frame, GLOBALS());
if (lltrace < 0) { if (lltrace < 0) {
@ -4057,7 +4077,8 @@
// Manipulate stack and cache directly since we leave using DISPATCH_INLINED(). // Manipulate stack and cache directly since we leave using DISPATCH_INLINED().
STACK_SHRINK(oparg + 2); STACK_SHRINK(oparg + 2);
SKIP_OVER(INLINE_CACHE_ENTRIES_CALL); SKIP_OVER(INLINE_CACHE_ENTRIES_CALL);
frame->return_offset = 0; assert(1 + INLINE_CACHE_ENTRIES_CALL == next_instr - frame->instr_ptr);
frame->return_offset = 1 + INLINE_CACHE_ENTRIES_CALL;
DISPATCH_INLINED(new_frame); DISPATCH_INLINED(new_frame);
} }
@ -4164,7 +4185,7 @@
Py_DECREF(tp); Py_DECREF(tp);
_PyInterpreterFrame *shim = _PyFrame_PushTrampolineUnchecked( _PyInterpreterFrame *shim = _PyFrame_PushTrampolineUnchecked(
tstate, (PyCodeObject *)&_Py_InitCleanup, 1); tstate, (PyCodeObject *)&_Py_InitCleanup, 1);
assert(_PyCode_CODE((PyCodeObject *)shim->f_executable)[1].op.code == EXIT_INIT_CHECK); assert(_PyCode_CODE((PyCodeObject *)shim->f_executable)[0].op.code == EXIT_INIT_CHECK);
/* Push self onto stack of shim */ /* Push self onto stack of shim */
Py_INCREF(self); Py_INCREF(self);
shim->localsplus[0] = self; shim->localsplus[0] = self;
@ -4176,8 +4197,8 @@
init_frame->localsplus[i+1] = args[i]; init_frame->localsplus[i+1] = args[i];
} }
SKIP_OVER(INLINE_CACHE_ENTRIES_CALL); SKIP_OVER(INLINE_CACHE_ENTRIES_CALL);
frame->prev_instr = next_instr - 1; assert(1 + INLINE_CACHE_ENTRIES_CALL == next_instr - frame->instr_ptr);
frame->return_offset = 0; frame->return_offset = 1 + INLINE_CACHE_ENTRIES_CALL;
STACK_SHRINK(oparg+2); STACK_SHRINK(oparg+2);
_PyFrame_SetStackPointer(frame, stack_pointer); _PyFrame_SetStackPointer(frame, stack_pointer);
/* Link frames */ /* Link frames */
@ -4685,7 +4706,8 @@
if (new_frame == NULL) { if (new_frame == NULL) {
goto error; goto error;
} }
frame->return_offset = 0; assert(next_instr - frame->instr_ptr == 1);
frame->return_offset = 1;
DISPATCH_INLINED(new_frame); DISPATCH_INLINED(new_frame);
} }
/* Callable is not a normal Python function */ /* Callable is not a normal Python function */
@ -4793,7 +4815,8 @@
if (new_frame == NULL) { if (new_frame == NULL) {
goto error; goto error;
} }
frame->return_offset = 0; assert(next_instr - frame->instr_ptr == 1);
frame->return_offset = 1;
DISPATCH_INLINED(new_frame); DISPATCH_INLINED(new_frame);
} }
result = PyObject_Call(func, callargs, kwargs); result = PyObject_Call(func, callargs, kwargs);
@ -4874,6 +4897,7 @@
assert(EMPTY()); assert(EMPTY());
_PyFrame_SetStackPointer(frame, stack_pointer); _PyFrame_SetStackPointer(frame, stack_pointer);
_PyInterpreterFrame *gen_frame = (_PyInterpreterFrame *)gen->gi_iframe; _PyInterpreterFrame *gen_frame = (_PyInterpreterFrame *)gen->gi_iframe;
frame->instr_ptr = next_instr;
_PyFrame_Copy(frame, gen_frame); _PyFrame_Copy(frame, gen_frame);
assert(frame->frame_obj == NULL); assert(frame->frame_obj == NULL);
gen->gi_frame_state = FRAME_CREATED; gen->gi_frame_state = FRAME_CREATED;
@ -4884,6 +4908,7 @@
_PyThreadState_PopFrame(tstate, frame); _PyThreadState_PopFrame(tstate, frame);
frame = tstate->current_frame = prev; frame = tstate->current_frame = prev;
_PyFrame_StackPush(frame, (PyObject *)gen); _PyFrame_StackPush(frame, (PyObject *)gen);
LOAD_IP(frame->return_offset);
goto resume_frame; goto resume_frame;
} }
@ -5021,20 +5046,22 @@
} }
TARGET(INSTRUMENTED_JUMP_FORWARD) { TARGET(INSTRUMENTED_JUMP_FORWARD) {
INSTRUMENTED_JUMP(next_instr-1, next_instr+oparg, PY_MONITORING_EVENT_JUMP); _Py_CODEUNIT *here = frame->instr_ptr;
INSTRUMENTED_JUMP(here, next_instr + oparg, PY_MONITORING_EVENT_JUMP);
DISPATCH(); DISPATCH();
} }
TARGET(INSTRUMENTED_JUMP_BACKWARD) { TARGET(INSTRUMENTED_JUMP_BACKWARD) {
_Py_CODEUNIT *here = frame->instr_ptr;
CHECK_EVAL_BREAKER(); CHECK_EVAL_BREAKER();
INSTRUMENTED_JUMP(next_instr-1, next_instr+1-oparg, PY_MONITORING_EVENT_JUMP); INSTRUMENTED_JUMP(here, next_instr + 1 - oparg, PY_MONITORING_EVENT_JUMP);
DISPATCH(); DISPATCH();
} }
TARGET(INSTRUMENTED_POP_JUMP_IF_TRUE) { TARGET(INSTRUMENTED_POP_JUMP_IF_TRUE) {
PyObject *cond = POP(); PyObject *cond = POP();
assert(PyBool_Check(cond)); assert(PyBool_Check(cond));
_Py_CODEUNIT *here = next_instr - 1; _Py_CODEUNIT *here = frame->instr_ptr;
int flag = Py_IsTrue(cond); int flag = Py_IsTrue(cond);
int offset = flag * oparg; int offset = flag * oparg;
#if ENABLE_SPECIALIZATION #if ENABLE_SPECIALIZATION
@ -5048,7 +5075,7 @@
TARGET(INSTRUMENTED_POP_JUMP_IF_FALSE) { TARGET(INSTRUMENTED_POP_JUMP_IF_FALSE) {
PyObject *cond = POP(); PyObject *cond = POP();
assert(PyBool_Check(cond)); assert(PyBool_Check(cond));
_Py_CODEUNIT *here = next_instr - 1; _Py_CODEUNIT *here = frame->instr_ptr;
int flag = Py_IsFalse(cond); int flag = Py_IsFalse(cond);
int offset = flag * oparg; int offset = flag * oparg;
#if ENABLE_SPECIALIZATION #if ENABLE_SPECIALIZATION
@ -5061,7 +5088,7 @@
TARGET(INSTRUMENTED_POP_JUMP_IF_NONE) { TARGET(INSTRUMENTED_POP_JUMP_IF_NONE) {
PyObject *value = POP(); PyObject *value = POP();
_Py_CODEUNIT *here = next_instr - 1; _Py_CODEUNIT *here = frame->instr_ptr;
int flag = Py_IsNone(value); int flag = Py_IsNone(value);
int offset; int offset;
if (flag) { if (flag) {
@ -5081,7 +5108,7 @@
TARGET(INSTRUMENTED_POP_JUMP_IF_NOT_NONE) { TARGET(INSTRUMENTED_POP_JUMP_IF_NOT_NONE) {
PyObject *value = POP(); PyObject *value = POP();
_Py_CODEUNIT *here = next_instr-1; _Py_CODEUNIT *here = frame->instr_ptr;
int offset; int offset;
int nflag = Py_IsNone(value); int nflag = Py_IsNone(value);
if (nflag) { if (nflag) {

View file

@ -1073,7 +1073,7 @@ _Py_call_instrumentation_jump(
{ {
assert(event == PY_MONITORING_EVENT_JUMP || assert(event == PY_MONITORING_EVENT_JUMP ||
event == PY_MONITORING_EVENT_BRANCH); event == PY_MONITORING_EVENT_BRANCH);
assert(frame->prev_instr == instr); assert(frame->instr_ptr == instr);
PyCodeObject *code = _PyFrame_GetCode(frame); PyCodeObject *code = _PyFrame_GetCode(frame);
int to = (int)(target - _PyCode_CODE(code)); int to = (int)(target - _PyCode_CODE(code));
PyObject *to_obj = PyLong_FromLong(to * (int)sizeof(_Py_CODEUNIT)); PyObject *to_obj = PyLong_FromLong(to * (int)sizeof(_Py_CODEUNIT));
@ -1086,9 +1086,9 @@ _Py_call_instrumentation_jump(
if (err) { if (err) {
return NULL; return NULL;
} }
if (frame->prev_instr != instr) { if (frame->instr_ptr != instr) {
/* The callback has caused a jump (by setting the line number) */ /* The callback has caused a jump (by setting the line number) */
return frame->prev_instr; return frame->instr_ptr;
} }
return target; return target;
} }
@ -1138,7 +1138,6 @@ _Py_Instrumentation_GetLine(PyCodeObject *code, int index)
int int
_Py_call_instrumentation_line(PyThreadState *tstate, _PyInterpreterFrame* frame, _Py_CODEUNIT *instr, _Py_CODEUNIT *prev) _Py_call_instrumentation_line(PyThreadState *tstate, _PyInterpreterFrame* frame, _Py_CODEUNIT *instr, _Py_CODEUNIT *prev)
{ {
assert(frame->prev_instr == instr);
PyCodeObject *code = _PyFrame_GetCode(frame); PyCodeObject *code = _PyFrame_GetCode(frame);
assert(is_version_up_to_date(code, tstate->interp)); assert(is_version_up_to_date(code, tstate->interp));
assert(instrumentation_cross_checks(tstate->interp, code)); assert(instrumentation_cross_checks(tstate->interp, code));
@ -1153,6 +1152,7 @@ _Py_call_instrumentation_line(PyThreadState *tstate, _PyInterpreterFrame* frame,
int8_t line_delta = line_data->line_delta; int8_t line_delta = line_data->line_delta;
int line = compute_line(code, i, line_delta); int line = compute_line(code, i, line_delta);
assert(line >= 0); assert(line >= 0);
assert(prev != NULL);
int prev_index = (int)(prev - _PyCode_CODE(code)); int prev_index = (int)(prev - _PyCode_CODE(code));
int prev_line = _Py_Instrumentation_GetLine(code, prev_index); int prev_line = _Py_Instrumentation_GetLine(code, prev_index);
if (prev_line == line) { if (prev_line == line) {

View file

@ -251,7 +251,7 @@ counter_execute(_PyExecutorObject *self, _PyInterpreterFrame *frame, PyObject **
{ {
((_PyCounterExecutorObject *)self)->optimizer->count++; ((_PyCounterExecutorObject *)self)->optimizer->count++;
_PyFrame_SetStackPointer(frame, stack_pointer); _PyFrame_SetStackPointer(frame, stack_pointer);
frame->prev_instr = ((_PyCounterExecutorObject *)self)->next_instr - 1; frame->instr_ptr = ((_PyCounterExecutorObject *)self)->next_instr;
Py_DECREF(self); Py_DECREF(self);
return frame; return frame;
} }
@ -701,11 +701,9 @@ translate_bytecode_to_trace(
case OPARG_BOTTOM: // Second half of super-instr case OPARG_BOTTOM: // Second half of super-instr
oparg = orig_oparg & 0xF; oparg = orig_oparg & 0xF;
break; break;
case OPARG_SET_IP: // uop=_SET_IP; oparg=next_instr-1 case OPARG_SAVE_RETURN_OFFSET: // op=_SAVE_RETURN_OFFSET; oparg=return_offset
// The number of caches is smuggled in via offset: oparg = offset;
assert(offset == _PyOpcode_Caches[_PyOpcode_Deopt[opcode]]); assert(uop == _SAVE_RETURN_OFFSET);
oparg = INSTR_IP(instr + offset, code);
uop = _SET_IP;
break; break;
default: default:

View file

@ -2524,7 +2524,7 @@ static const PyBytesObject no_location = {
}; };
const struct _PyCode_DEF(8) _Py_InitCleanup = { const struct _PyCode_DEF(8) _Py_InitCleanup = {
_PyVarObject_HEAD_INIT(&PyCode_Type, 4) _PyVarObject_HEAD_INIT(&PyCode_Type, 3)
.co_consts = (PyObject *)&_Py_SINGLETON(tuple_empty), .co_consts = (PyObject *)&_Py_SINGLETON(tuple_empty),
.co_names = (PyObject *)&_Py_SINGLETON(tuple_empty), .co_names = (PyObject *)&_Py_SINGLETON(tuple_empty),
.co_exceptiontable = (PyObject *)&_Py_SINGLETON(bytes_empty), .co_exceptiontable = (PyObject *)&_Py_SINGLETON(bytes_empty),
@ -2539,7 +2539,6 @@ const struct _PyCode_DEF(8) _Py_InitCleanup = {
.co_stacksize = 2, .co_stacksize = 2,
.co_framesize = 2 + FRAME_SPECIALS_SIZE, .co_framesize = 2 + FRAME_SPECIALS_SIZE,
.co_code_adaptive = { .co_code_adaptive = {
NOP, 0,
EXIT_INIT_CHECK, 0, EXIT_INIT_CHECK, 0,
RETURN_VALUE, 0, RETURN_VALUE, 0,
RESUME, 0, RESUME, 0,

View file

@ -372,8 +372,8 @@ def analyze_macro(self, macro: parsing.Macro) -> MacroInstruction:
case Instruction() as instr: case Instruction() as instr:
part, offset = self.analyze_instruction(instr, offset) part, offset = self.analyze_instruction(instr, offset)
parts.append(part) parts.append(part)
if instr.name != "_SET_IP": if instr.name != "_SAVE_RETURN_OFFSET":
# _SET_IP in a macro is a no-op in Tier 1 # _SAVE_RETURN_OFFSET's oparg does not transfer
flags.add(instr.instr_flags) flags.add(instr.instr_flags)
case _: case _:
assert_never(component) assert_never(component)

View file

@ -67,7 +67,7 @@
"OPARG_CACHE_4": 4, "OPARG_CACHE_4": 4,
"OPARG_TOP": 5, "OPARG_TOP": 5,
"OPARG_BOTTOM": 6, "OPARG_BOTTOM": 6,
"OPARG_SET_IP": 7, "OPARG_SAVE_RETURN_OFFSET": 7,
} }
INSTR_FMT_PREFIX = "INSTR_FMT_" INSTR_FMT_PREFIX = "INSTR_FMT_"
@ -658,7 +658,7 @@ def write_macro_expansions(
for part in parts: for part in parts:
if isinstance(part, Component): if isinstance(part, Component):
# All component instructions must be viable uops # All component instructions must be viable uops
if not part.instr.is_viable_uop() and part.instr.name != "_SAVE_CURRENT_IP": if not part.instr.is_viable_uop():
# This note just reminds us about macros that cannot # This note just reminds us about macros that cannot
# be expanded to Tier 2 uops. It is not an error. # be expanded to Tier 2 uops. It is not an error.
# It is sometimes emitted for macros that have a # It is sometimes emitted for macros that have a
@ -671,8 +671,8 @@ def write_macro_expansions(
) )
return return
if not part.active_caches: if not part.active_caches:
if part.instr.name == "_SAVE_CURRENT_IP": if part.instr.name == "_SAVE_RETURN_OFFSET":
size, offset = OPARG_SIZES["OPARG_SET_IP"], cache_offset - 1 size, offset = OPARG_SIZES["OPARG_SAVE_RETURN_OFFSET"], cache_offset
else: else:
size, offset = OPARG_SIZES["OPARG_FULL"], 0 size, offset = OPARG_SIZES["OPARG_FULL"], 0
else: else:

View file

@ -448,7 +448,7 @@ def write_components(
), f"Expected {mgr.instr.name!r} to be the last uop" ), f"Expected {mgr.instr.name!r} to be the last uop"
assert_no_pokes(managers) assert_no_pokes(managers)
if mgr.instr.name == "_SAVE_CURRENT_IP": if mgr.instr.name == "_SAVE_RETURN_OFFSET":
next_instr_is_set = True next_instr_is_set = True
if cache_offset: if cache_offset:
out.emit(f"next_instr += {cache_offset};") out.emit(f"next_instr += {cache_offset};")

View file

@ -1065,9 +1065,9 @@ def _f_nlocalsplus(self):
def _f_lasti(self): def _f_lasti(self):
codeunit_p = gdb.lookup_type("_Py_CODEUNIT").pointer() codeunit_p = gdb.lookup_type("_Py_CODEUNIT").pointer()
prev_instr = self._gdbval["prev_instr"] instr_ptr = self._gdbval["instr_ptr"]
first_instr = self._f_code().field("co_code_adaptive").cast(codeunit_p) first_instr = self._f_code().field("co_code_adaptive").cast(codeunit_p)
return int(prev_instr - first_instr) return int(instr_ptr - first_instr)
def is_shim(self): def is_shim(self):
return self._f_special("owner", int) == FRAME_OWNED_BY_CSTACK return self._f_special("owner", int) == FRAME_OWNED_BY_CSTACK