GH-131498: Cases generator: manage stacks automatically (GH-132074)

This commit is contained in:
Mark Shannon 2025-04-04 17:59:36 +01:00 committed by GitHub
parent 305be5fb1a
commit 7099c75550
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
15 changed files with 216 additions and 251 deletions

View file

@ -234,7 +234,7 @@ int _PyOpcode_num_popped(int opcode, int oparg) {
case INSTRUMENTED_END_SEND: case INSTRUMENTED_END_SEND:
return 2; return 2;
case INSTRUMENTED_FOR_ITER: case INSTRUMENTED_FOR_ITER:
return 0; return 1;
case INSTRUMENTED_INSTRUCTION: case INSTRUMENTED_INSTRUCTION:
return 0; return 0;
case INSTRUMENTED_JUMP_BACKWARD: case INSTRUMENTED_JUMP_BACKWARD:
@ -250,13 +250,13 @@ int _PyOpcode_num_popped(int opcode, int oparg) {
case INSTRUMENTED_POP_ITER: case INSTRUMENTED_POP_ITER:
return 1; return 1;
case INSTRUMENTED_POP_JUMP_IF_FALSE: case INSTRUMENTED_POP_JUMP_IF_FALSE:
return 0; return 1;
case INSTRUMENTED_POP_JUMP_IF_NONE: case INSTRUMENTED_POP_JUMP_IF_NONE:
return 0; return 1;
case INSTRUMENTED_POP_JUMP_IF_NOT_NONE: case INSTRUMENTED_POP_JUMP_IF_NOT_NONE:
return 0; return 1;
case INSTRUMENTED_POP_JUMP_IF_TRUE: case INSTRUMENTED_POP_JUMP_IF_TRUE:
return 0; return 1;
case INSTRUMENTED_RESUME: case INSTRUMENTED_RESUME:
return 0; return 0;
case INSTRUMENTED_RETURN_VALUE: case INSTRUMENTED_RETURN_VALUE:
@ -713,7 +713,7 @@ int _PyOpcode_num_pushed(int opcode, int oparg) {
case INSTRUMENTED_END_SEND: case INSTRUMENTED_END_SEND:
return 1; return 1;
case INSTRUMENTED_FOR_ITER: case INSTRUMENTED_FOR_ITER:
return 0; return 2;
case INSTRUMENTED_INSTRUCTION: case INSTRUMENTED_INSTRUCTION:
return 0; return 0;
case INSTRUMENTED_JUMP_BACKWARD: case INSTRUMENTED_JUMP_BACKWARD:

View file

@ -4,11 +4,6 @@
extern "C" { extern "C" {
#endif #endif
// Define this to get precise tracking of closed stackrefs.
// This will use unbounded memory, as it can only grow.
// Use this to track double closes in short-lived programs
// #define Py_STACKREF_CLOSE_DEBUG 1
#ifndef Py_BUILD_CORE #ifndef Py_BUILD_CORE
# error "this header requires Py_BUILD_CORE define" # error "this header requires Py_BUILD_CORE define"
#endif #endif

View file

@ -57,6 +57,12 @@ typedef struct {
// Define this to get precise tracking of stackrefs. // Define this to get precise tracking of stackrefs.
// #define Py_STACKREF_DEBUG 1 // #define Py_STACKREF_DEBUG 1
// Define this to get precise tracking of closed stackrefs.
// This will use unbounded memory, as it can only grow.
// Use this to track double closes in short-lived programs
// #define Py_STACKREF_CLOSE_DEBUG 1
typedef union _PyStackRef { typedef union _PyStackRef {
#if !defined(Py_GIL_DISABLED) && defined(Py_STACKREF_DEBUG) #if !defined(Py_GIL_DISABLED) && defined(Py_STACKREF_DEBUG)
uint64_t index; uint64_t index;

View file

@ -204,7 +204,7 @@ dummy_func(
ptrdiff_t off = this_instr - _PyFrame_GetBytecode(frame); ptrdiff_t off = this_instr - _PyFrame_GetBytecode(frame);
frame->tlbc_index = ((_PyThreadStateImpl *)tstate)->tlbc_index; frame->tlbc_index = ((_PyThreadStateImpl *)tstate)->tlbc_index;
frame->instr_ptr = bytecode + off; frame->instr_ptr = bytecode + off;
// Make sure this_instr gets reset correctley for any uops that // Make sure this_instr gets reset correctly for any uops that
// follow // follow
next_instr = frame->instr_ptr; next_instr = frame->instr_ptr;
DISPATCH(); DISPATCH();
@ -1111,7 +1111,7 @@ dummy_func(
tstate->current_frame = frame->previous; tstate->current_frame = frame->previous;
assert(!_PyErr_Occurred(tstate)); assert(!_PyErr_Occurred(tstate));
PyObject *result = PyStackRef_AsPyObjectSteal(retval); PyObject *result = PyStackRef_AsPyObjectSteal(retval);
SYNC_SP(); /* Not strictly necessary, but prevents warnings */ LLTRACE_RESUME_FRAME();
return result; return result;
} }
@ -1123,7 +1123,7 @@ dummy_func(
_PyStackRef temp = PyStackRef_MakeHeapSafe(retval); _PyStackRef temp = PyStackRef_MakeHeapSafe(retval);
DEAD(retval); DEAD(retval);
SAVE_STACK(); SAVE_STACK();
assert(EMPTY()); assert(STACK_LEVEL() == 0);
_Py_LeaveRecursiveCallPy(tstate); _Py_LeaveRecursiveCallPy(tstate);
// GH-99729: We need to unlink the frame *before* clearing it: // GH-99729: We need to unlink the frame *before* clearing it:
_PyInterpreterFrame *dying = frame; _PyInterpreterFrame *dying = frame;
@ -1223,8 +1223,9 @@ dummy_func(
{ {
PyGenObject *gen = (PyGenObject *)receiver_o; PyGenObject *gen = (PyGenObject *)receiver_o;
_PyInterpreterFrame *gen_frame = &gen->gi_iframe; _PyInterpreterFrame *gen_frame = &gen->gi_iframe;
STACK_SHRINK(1);
_PyFrame_StackPush(gen_frame, PyStackRef_MakeHeapSafe(v)); _PyFrame_StackPush(gen_frame, PyStackRef_MakeHeapSafe(v));
DEAD(v);
SYNC_SP();
gen->gi_frame_state = FRAME_EXECUTING; gen->gi_frame_state = FRAME_EXECUTING;
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;
@ -2436,10 +2437,10 @@ dummy_func(
PyObject *name = GETITEM(FRAME_CO_NAMES, oparg >> 1); PyObject *name = GETITEM(FRAME_CO_NAMES, oparg >> 1);
_PyInterpreterFrame *new_frame = _PyFrame_PushUnchecked( _PyInterpreterFrame *new_frame = _PyFrame_PushUnchecked(
tstate, PyStackRef_FromPyObjectNew(f), 2, frame); tstate, PyStackRef_FromPyObjectNew(f), 2, frame);
// Manipulate stack directly because we exit with DISPATCH_INLINED().
STACK_SHRINK(1);
new_frame->localsplus[0] = owner; new_frame->localsplus[0] = owner;
DEAD(owner); DEAD(owner);
// Manipulate stack directly because we exit with DISPATCH_INLINED().
SYNC_SP();
new_frame->localsplus[1] = PyStackRef_FromPyObjectNew(name); new_frame->localsplus[1] = PyStackRef_FromPyObjectNew(name);
frame->return_offset = INSTRUCTION_SIZE; frame->return_offset = INSTRUCTION_SIZE;
DISPATCH_INLINED(new_frame); DISPATCH_INLINED(new_frame);
@ -3083,12 +3084,11 @@ dummy_func(
macro(FOR_ITER) = _SPECIALIZE_FOR_ITER + _FOR_ITER; macro(FOR_ITER) = _SPECIALIZE_FOR_ITER + _FOR_ITER;
inst(INSTRUMENTED_FOR_ITER, (unused/1 -- )) { inst(INSTRUMENTED_FOR_ITER, (unused/1, iter -- iter, next)) {
_PyStackRef iter_stackref = TOP(); PyObject *iter_o = PyStackRef_AsPyObjectBorrow(iter);
PyObject *iter = PyStackRef_AsPyObjectBorrow(iter_stackref); PyObject *next_o = (*Py_TYPE(iter_o)->tp_iternext)(iter_o);
PyObject *next = (*Py_TYPE(iter)->tp_iternext)(iter); if (next_o != NULL) {
if (next != NULL) { next = PyStackRef_FromPyObjectSteal(next_o);
PUSH(PyStackRef_FromPyObjectSteal(next));
INSTRUMENTED_JUMP(this_instr, next_instr, PY_MONITORING_EVENT_BRANCH_LEFT); INSTRUMENTED_JUMP(this_instr, next_instr, PY_MONITORING_EVENT_BRANCH_LEFT);
} }
else { else {
@ -3105,6 +3105,7 @@ dummy_func(
next_instr[oparg].op.code == INSTRUMENTED_END_FOR); next_instr[oparg].op.code == INSTRUMENTED_END_FOR);
/* Skip END_FOR */ /* Skip END_FOR */
JUMPBY(oparg + 1); JUMPBY(oparg + 1);
DISPATCH();
} }
} }
@ -4022,7 +4023,6 @@ dummy_func(
_PUSH_FRAME; _PUSH_FRAME;
inst(EXIT_INIT_CHECK, (should_be_none -- )) { inst(EXIT_INIT_CHECK, (should_be_none -- )) {
assert(STACK_LEVEL() == 2);
if (!PyStackRef_IsNone(should_be_none)) { if (!PyStackRef_IsNone(should_be_none)) {
PyErr_Format(PyExc_TypeError, PyErr_Format(PyExc_TypeError,
"__init__() should return None, not '%.200s'", "__init__() should return None, not '%.200s'",
@ -4813,7 +4813,7 @@ dummy_func(
PyFunctionObject *func = (PyFunctionObject *)PyStackRef_AsPyObjectBorrow(frame->f_funcobj); PyFunctionObject *func = (PyFunctionObject *)PyStackRef_AsPyObjectBorrow(frame->f_funcobj);
PyGenObject *gen = (PyGenObject *)_Py_MakeCoro(func); PyGenObject *gen = (PyGenObject *)_Py_MakeCoro(func);
ERROR_IF(gen == NULL, error); ERROR_IF(gen == NULL, error);
assert(EMPTY()); assert(STACK_LEVEL() == 0);
SAVE_STACK(); SAVE_STACK();
_PyInterpreterFrame *gen_frame = &gen->gi_iframe; _PyInterpreterFrame *gen_frame = &gen->gi_iframe;
frame->instr_ptr++; frame->instr_ptr++;
@ -4932,6 +4932,7 @@ dummy_func(
} }
next_instr = frame->instr_ptr; next_instr = frame->instr_ptr;
if (next_instr != this_instr) { if (next_instr != this_instr) {
SYNC_SP();
DISPATCH(); DISPATCH();
} }
} }
@ -4976,46 +4977,48 @@ dummy_func(
_CHECK_PERIODIC + _CHECK_PERIODIC +
_MONITOR_JUMP_BACKWARD; _MONITOR_JUMP_BACKWARD;
inst(INSTRUMENTED_POP_JUMP_IF_TRUE, (unused/1 -- )) { inst(INSTRUMENTED_POP_JUMP_IF_TRUE, (unused/1, cond -- )) {
_PyStackRef cond = POP();
assert(PyStackRef_BoolCheck(cond)); assert(PyStackRef_BoolCheck(cond));
int jump = PyStackRef_IsTrue(cond); int jump = PyStackRef_IsTrue(cond);
DEAD(cond);
RECORD_BRANCH_TAKEN(this_instr[1].cache, jump); RECORD_BRANCH_TAKEN(this_instr[1].cache, jump);
if (jump) { if (jump) {
INSTRUMENTED_JUMP(this_instr, next_instr + oparg, PY_MONITORING_EVENT_BRANCH_RIGHT); INSTRUMENTED_JUMP(this_instr, next_instr + oparg, PY_MONITORING_EVENT_BRANCH_RIGHT);
} }
} }
inst(INSTRUMENTED_POP_JUMP_IF_FALSE, (unused/1 -- )) { inst(INSTRUMENTED_POP_JUMP_IF_FALSE, (unused/1, cond -- )) {
_PyStackRef cond = POP();
assert(PyStackRef_BoolCheck(cond)); assert(PyStackRef_BoolCheck(cond));
int jump = PyStackRef_IsFalse(cond); int jump = PyStackRef_IsFalse(cond);
DEAD(cond);
RECORD_BRANCH_TAKEN(this_instr[1].cache, jump); RECORD_BRANCH_TAKEN(this_instr[1].cache, jump);
if (jump) { if (jump) {
INSTRUMENTED_JUMP(this_instr, next_instr + oparg, PY_MONITORING_EVENT_BRANCH_RIGHT); INSTRUMENTED_JUMP(this_instr, next_instr + oparg, PY_MONITORING_EVENT_BRANCH_RIGHT);
} }
} }
inst(INSTRUMENTED_POP_JUMP_IF_NONE, (unused/1 -- )) { inst(INSTRUMENTED_POP_JUMP_IF_NONE, (unused/1, value -- )) {
_PyStackRef value_stackref = POP(); int jump = PyStackRef_IsNone(value);
int jump = PyStackRef_IsNone(value_stackref);
RECORD_BRANCH_TAKEN(this_instr[1].cache, jump); RECORD_BRANCH_TAKEN(this_instr[1].cache, jump);
if (jump) { if (jump) {
DEAD(value);
INSTRUMENTED_JUMP(this_instr, next_instr + oparg, PY_MONITORING_EVENT_BRANCH_RIGHT); INSTRUMENTED_JUMP(this_instr, next_instr + oparg, PY_MONITORING_EVENT_BRANCH_RIGHT);
} }
else { else {
PyStackRef_CLOSE(value_stackref); PyStackRef_CLOSE(value);
} }
} }
inst(INSTRUMENTED_POP_JUMP_IF_NOT_NONE, (unused/1 -- )) { inst(INSTRUMENTED_POP_JUMP_IF_NOT_NONE, (unused/1, value -- )) {
_PyStackRef value_stackref = POP(); int jump = !PyStackRef_IsNone(value);
int jump = !PyStackRef_IsNone(value_stackref);
RECORD_BRANCH_TAKEN(this_instr[1].cache, jump); RECORD_BRANCH_TAKEN(this_instr[1].cache, jump);
if (jump) { if (jump) {
PyStackRef_CLOSE(value_stackref); PyStackRef_CLOSE(value);
INSTRUMENTED_JUMP(this_instr, next_instr + oparg, PY_MONITORING_EVENT_BRANCH_RIGHT); INSTRUMENTED_JUMP(this_instr, next_instr + oparg, PY_MONITORING_EVENT_BRANCH_RIGHT);
} }
else {
DEAD(value);
}
} }
tier1 inst(EXTENDED_ARG, ( -- )) { tier1 inst(EXTENDED_ARG, ( -- )) {
@ -5219,22 +5222,26 @@ dummy_func(
} }
label(pop_4_error) { label(pop_4_error) {
STACK_SHRINK(4); stack_pointer -= 4;
assert(WITHIN_STACK_BOUNDS());
goto error; goto error;
} }
label(pop_3_error) { label(pop_3_error) {
STACK_SHRINK(3); stack_pointer -= 3;
assert(WITHIN_STACK_BOUNDS());
goto error; goto error;
} }
label(pop_2_error) { label(pop_2_error) {
STACK_SHRINK(2); stack_pointer -= 2;
assert(WITHIN_STACK_BOUNDS());
goto error; goto error;
} }
label(pop_1_error) { label(pop_1_error) {
STACK_SHRINK(1); stack_pointer -= 1;
assert(WITHIN_STACK_BOUNDS());
goto error; goto error;
} }

View file

@ -151,18 +151,6 @@ dump_item(_PyStackRef item)
printf("<nil>"); printf("<nil>");
return; return;
} }
if (
obj == Py_None
|| PyBool_Check(obj)
|| PyLong_CheckExact(obj)
|| PyFloat_CheckExact(obj)
|| PyUnicode_CheckExact(obj)
) {
if (PyObject_Print(obj, stdout, 0) == 0) {
return;
}
PyErr_Clear();
}
// Don't call __repr__(), it might recurse into the interpreter. // Don't call __repr__(), it might recurse into the interpreter.
printf("<%s at %p>", Py_TYPE(obj)->tp_name, (void *)obj); printf("<%s at %p>", Py_TYPE(obj)->tp_name, (void *)obj);
} }
@ -182,14 +170,19 @@ dump_stack(_PyInterpreterFrame *frame, _PyStackRef *stack_pointer)
dump_item(*ptr); dump_item(*ptr);
} }
printf("]\n"); printf("]\n");
printf(" stack=["); if (stack_pointer < stack_base) {
for (_PyStackRef *ptr = stack_base; ptr < stack_pointer; ptr++) { printf(" stack=%d\n", (int)(stack_pointer-stack_base));
if (ptr != stack_base) { }
printf(", "); else {
} printf(" stack=[");
dump_item(*ptr); for (_PyStackRef *ptr = stack_base; ptr < stack_pointer; ptr++) {
if (ptr != stack_base) {
printf(", ");
}
dump_item(*ptr);
}
printf("]\n");
} }
printf("]\n");
fflush(stdout); fflush(stdout);
PyErr_SetRaisedException(exc); PyErr_SetRaisedException(exc);
_PyFrame_GetStackPointer(frame); _PyFrame_GetStackPointer(frame);
@ -202,13 +195,13 @@ lltrace_instruction(_PyInterpreterFrame *frame,
int opcode, int opcode,
int oparg) int oparg)
{ {
if (frame->owner >= FRAME_OWNED_BY_INTERPRETER) { int offset = 0;
return; if (frame->owner < FRAME_OWNED_BY_INTERPRETER) {
dump_stack(frame, stack_pointer);
offset = (int)(next_instr - _PyFrame_GetBytecode(frame));
} }
dump_stack(frame, stack_pointer);
const char *opname = _PyOpcode_OpName[opcode]; const char *opname = _PyOpcode_OpName[opcode];
assert(opname != NULL); assert(opname != NULL);
int offset = (int)(next_instr - _PyFrame_GetBytecode(frame));
if (OPCODE_HAS_ARG((int)_PyOpcode_Deopt[opcode])) { if (OPCODE_HAS_ARG((int)_PyOpcode_Deopt[opcode])) {
printf("%d: %s %d\n", offset * 2, opname, oparg); printf("%d: %s %d\n", offset * 2, opname, oparg);
} }
@ -986,8 +979,10 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int
* These are cached values from the frame and code object. */ * These are cached values from the frame and code object. */
_Py_CODEUNIT *next_instr; _Py_CODEUNIT *next_instr;
_PyStackRef *stack_pointer; _PyStackRef *stack_pointer;
entry_frame.localsplus[0] = PyStackRef_NULL;
#if defined(Py_DEBUG) && !defined(Py_STACKREF_DEBUG) #ifdef Py_STACKREF_DEBUG
entry_frame.f_funcobj = PyStackRef_None;
#elif defined(Py_DEBUG)
/* Set these to invalid but identifiable values for debugging. */ /* Set these to invalid but identifiable values for debugging. */
entry_frame.f_funcobj = (_PyStackRef){.bits = 0xaaa0}; entry_frame.f_funcobj = (_PyStackRef){.bits = 0xaaa0};
entry_frame.f_locals = (PyObject*)0xaaa1; entry_frame.f_locals = (PyObject*)0xaaa1;
@ -1044,7 +1039,6 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int
_PyExecutorObject *current_executor = NULL; _PyExecutorObject *current_executor = NULL;
const _PyUOpInstruction *next_uop = NULL; const _PyUOpInstruction *next_uop = NULL;
#endif #endif
#if Py_TAIL_CALL_INTERP #if Py_TAIL_CALL_INTERP
return _TAIL_CALL_start_frame(frame, NULL, tstate, NULL, 0); return _TAIL_CALL_start_frame(frame, NULL, tstate, NULL, 0);
#else #else

View file

@ -194,48 +194,8 @@ GETITEM(PyObject *v, Py_ssize_t i) {
#define JUMPBY(x) (next_instr += (x)) #define JUMPBY(x) (next_instr += (x))
#define SKIP_OVER(x) (next_instr += (x)) #define SKIP_OVER(x) (next_instr += (x))
/* Stack manipulation macros */
/* The stack can grow at most MAXINT deep, as co_nlocals and
co_stacksize are ints. */
#define STACK_LEVEL() ((int)(stack_pointer - _PyFrame_Stackbase(frame))) #define STACK_LEVEL() ((int)(stack_pointer - _PyFrame_Stackbase(frame)))
#define STACK_SIZE() (_PyFrame_GetCode(frame)->co_stacksize) #define STACK_SIZE() (_PyFrame_GetCode(frame)->co_stacksize)
#define EMPTY() (STACK_LEVEL() == 0)
#define TOP() (stack_pointer[-1])
#define SECOND() (stack_pointer[-2])
#define THIRD() (stack_pointer[-3])
#define FOURTH() (stack_pointer[-4])
#define PEEK(n) (stack_pointer[-(n)])
#define POKE(n, v) (stack_pointer[-(n)] = (v))
#define SET_TOP(v) (stack_pointer[-1] = (v))
#define SET_SECOND(v) (stack_pointer[-2] = (v))
#define BASIC_STACKADJ(n) (stack_pointer += n)
#define BASIC_PUSH(v) (*stack_pointer++ = (v))
#define BASIC_POP() (*--stack_pointer)
#ifdef Py_DEBUG
#define PUSH(v) do { \
BASIC_PUSH(v); \
assert(STACK_LEVEL() <= STACK_SIZE()); \
} while (0)
#define POP() (assert(STACK_LEVEL() > 0), BASIC_POP())
#define STACK_GROW(n) do { \
assert(n >= 0); \
BASIC_STACKADJ(n); \
assert(STACK_LEVEL() <= STACK_SIZE()); \
} while (0)
#define STACK_SHRINK(n) do { \
assert(n >= 0); \
assert(STACK_LEVEL() >= n); \
BASIC_STACKADJ(-(n)); \
} while (0)
#else
#define PUSH(v) BASIC_PUSH(v)
#define POP() BASIC_POP()
#define STACK_GROW(n) BASIC_STACKADJ(n)
#define STACK_SHRINK(n) BASIC_STACKADJ(-(n))
#endif
#define WITHIN_STACK_BOUNDS() \ #define WITHIN_STACK_BOUNDS() \
(frame->owner == FRAME_OWNED_BY_INTERPRETER || (STACK_LEVEL() >= 0 && STACK_LEVEL() <= STACK_SIZE())) (frame->owner == FRAME_OWNED_BY_INTERPRETER || (STACK_LEVEL() >= 0 && STACK_LEVEL() <= STACK_SIZE()))

View file

@ -714,7 +714,6 @@
stack_pointer = _PyFrame_GetStackPointer(frame); stack_pointer = _PyFrame_GetStackPointer(frame);
res = PyStackRef_True; res = PyStackRef_True;
stack_pointer += 1; stack_pointer += 1;
assert(WITHIN_STACK_BOUNDS());
} }
stack_pointer[-1] = res; stack_pointer[-1] = res;
break; break;
@ -798,7 +797,6 @@
stack_pointer = _PyFrame_GetStackPointer(frame); stack_pointer = _PyFrame_GetStackPointer(frame);
res = PyStackRef_True; res = PyStackRef_True;
stack_pointer += 1; stack_pointer += 1;
assert(WITHIN_STACK_BOUNDS());
} }
stack_pointer[-1] = res; stack_pointer[-1] = res;
break; break;
@ -1206,7 +1204,6 @@
Py_DECREF(slice); Py_DECREF(slice);
stack_pointer = _PyFrame_GetStackPointer(frame); stack_pointer = _PyFrame_GetStackPointer(frame);
stack_pointer += 2; stack_pointer += 2;
assert(WITHIN_STACK_BOUNDS());
} }
stack_pointer += -3; stack_pointer += -3;
assert(WITHIN_STACK_BOUNDS()); assert(WITHIN_STACK_BOUNDS());
@ -1248,21 +1245,18 @@
Py_DECREF(slice); Py_DECREF(slice);
stack_pointer = _PyFrame_GetStackPointer(frame); stack_pointer = _PyFrame_GetStackPointer(frame);
stack_pointer += 2; stack_pointer += 2;
assert(WITHIN_STACK_BOUNDS());
} }
stack_pointer += -2;
assert(WITHIN_STACK_BOUNDS());
_PyFrame_SetStackPointer(frame, stack_pointer); _PyFrame_SetStackPointer(frame, stack_pointer);
_PyStackRef tmp = container; _PyStackRef tmp = container;
container = PyStackRef_NULL; container = PyStackRef_NULL;
stack_pointer[-1] = container; stack_pointer[-3] = container;
PyStackRef_CLOSE(tmp); PyStackRef_CLOSE(tmp);
tmp = v; tmp = v;
v = PyStackRef_NULL; v = PyStackRef_NULL;
stack_pointer[-2] = v; stack_pointer[-4] = v;
PyStackRef_CLOSE(tmp); PyStackRef_CLOSE(tmp);
stack_pointer = _PyFrame_GetStackPointer(frame); stack_pointer = _PyFrame_GetStackPointer(frame);
stack_pointer += -2; stack_pointer += -4;
assert(WITHIN_STACK_BOUNDS()); assert(WITHIN_STACK_BOUNDS());
if (err) { if (err) {
JUMP_TO_ERROR(); JUMP_TO_ERROR();
@ -1732,7 +1726,7 @@
stack_pointer += -1; stack_pointer += -1;
assert(WITHIN_STACK_BOUNDS()); assert(WITHIN_STACK_BOUNDS());
_PyFrame_SetStackPointer(frame, stack_pointer); _PyFrame_SetStackPointer(frame, stack_pointer);
assert(EMPTY()); assert(STACK_LEVEL() == 0);
_Py_LeaveRecursiveCallPy(tstate); _Py_LeaveRecursiveCallPy(tstate);
_PyInterpreterFrame *dying = frame; _PyInterpreterFrame *dying = frame;
frame = tstate->current_frame = dying->previous; frame = tstate->current_frame = dying->previous;
@ -2073,7 +2067,6 @@
_PyFrame_SetStackPointer(frame, stack_pointer); _PyFrame_SetStackPointer(frame, stack_pointer);
PyStackRef_CLOSE(seq); PyStackRef_CLOSE(seq);
stack_pointer = _PyFrame_GetStackPointer(frame); stack_pointer = _PyFrame_GetStackPointer(frame);
stack_pointer[-1] = val0;
break; break;
} }
@ -3004,7 +2997,6 @@
stack_pointer = _PyFrame_GetStackPointer(frame); stack_pointer = _PyFrame_GetStackPointer(frame);
self_or_null = PyStackRef_NULL; self_or_null = PyStackRef_NULL;
stack_pointer += 1; stack_pointer += 1;
assert(WITHIN_STACK_BOUNDS());
} }
stack_pointer += -1; stack_pointer += -1;
assert(WITHIN_STACK_BOUNDS()); assert(WITHIN_STACK_BOUNDS());
@ -3057,7 +3049,6 @@
} }
self_or_null[0] = PyStackRef_NULL; self_or_null[0] = PyStackRef_NULL;
stack_pointer += 1; stack_pointer += 1;
assert(WITHIN_STACK_BOUNDS());
} }
} }
else { else {
@ -3073,7 +3064,6 @@
JUMP_TO_ERROR(); JUMP_TO_ERROR();
} }
stack_pointer += 1; stack_pointer += 1;
assert(WITHIN_STACK_BOUNDS());
} }
attr = PyStackRef_FromPyObjectSteal(attr_o); attr = PyStackRef_FromPyObjectSteal(attr_o);
stack_pointer[-1] = attr; stack_pointer[-1] = attr;
@ -5289,7 +5279,6 @@
case _EXIT_INIT_CHECK: { case _EXIT_INIT_CHECK: {
_PyStackRef should_be_none; _PyStackRef should_be_none;
should_be_none = stack_pointer[-1]; should_be_none = stack_pointer[-1];
assert(STACK_LEVEL() == 2);
if (!PyStackRef_IsNone(should_be_none)) { if (!PyStackRef_IsNone(should_be_none)) {
_PyFrame_SetStackPointer(frame, stack_pointer); _PyFrame_SetStackPointer(frame, stack_pointer);
PyErr_Format(PyExc_TypeError, PyErr_Format(PyExc_TypeError,
@ -6347,7 +6336,6 @@
stack_pointer = _PyFrame_GetStackPointer(frame); stack_pointer = _PyFrame_GetStackPointer(frame);
tuple = PyStackRef_FromPyObjectSteal(tuple_o); tuple = PyStackRef_FromPyObjectSteal(tuple_o);
stack_pointer += 2; stack_pointer += 2;
assert(WITHIN_STACK_BOUNDS());
} }
stack_pointer[-2] = tuple; stack_pointer[-2] = tuple;
stack_pointer[-1] = kwargs_out; stack_pointer[-1] = kwargs_out;
@ -6414,7 +6402,7 @@
if (gen == NULL) { if (gen == NULL) {
JUMP_TO_ERROR(); JUMP_TO_ERROR();
} }
assert(EMPTY()); assert(STACK_LEVEL() == 0);
_PyFrame_SetStackPointer(frame, stack_pointer); _PyFrame_SetStackPointer(frame, stack_pointer);
_PyInterpreterFrame *gen_frame = &gen->gi_iframe; _PyInterpreterFrame *gen_frame = &gen->gi_iframe;
frame->instr_ptr++; frame->instr_ptr++;
@ -6513,7 +6501,6 @@
else { else {
res = value; res = value;
stack_pointer += -1; stack_pointer += -1;
assert(WITHIN_STACK_BOUNDS());
} }
stack_pointer[0] = res; stack_pointer[0] = res;
stack_pointer += 1; stack_pointer += 1;

View file

@ -1062,7 +1062,6 @@
Py_DECREF(slice); Py_DECREF(slice);
stack_pointer = _PyFrame_GetStackPointer(frame); stack_pointer = _PyFrame_GetStackPointer(frame);
stack_pointer += 2; stack_pointer += 2;
assert(WITHIN_STACK_BOUNDS());
} }
stack_pointer += -3; stack_pointer += -3;
assert(WITHIN_STACK_BOUNDS()); assert(WITHIN_STACK_BOUNDS());
@ -1498,7 +1497,6 @@
JUMP_TO_LABEL(error); JUMP_TO_LABEL(error);
} }
stack_pointer += -1; stack_pointer += -1;
assert(WITHIN_STACK_BOUNDS());
} }
} }
stack_pointer[0] = res; stack_pointer[0] = res;
@ -1983,7 +1981,6 @@
JUMP_TO_LABEL(error); JUMP_TO_LABEL(error);
} }
stack_pointer += -1; stack_pointer += -1;
assert(WITHIN_STACK_BOUNDS());
} }
} }
stack_pointer[0] = res; stack_pointer[0] = res;
@ -2097,7 +2094,6 @@
JUMP_TO_LABEL(error); JUMP_TO_LABEL(error);
} }
stack_pointer += -1; stack_pointer += -1;
assert(WITHIN_STACK_BOUNDS());
} }
} }
stack_pointer[0] = res; stack_pointer[0] = res;
@ -2212,7 +2208,6 @@
JUMP_TO_LABEL(error); JUMP_TO_LABEL(error);
} }
stack_pointer += -1; stack_pointer += -1;
assert(WITHIN_STACK_BOUNDS());
} }
} }
stack_pointer[0] = res; stack_pointer[0] = res;
@ -2305,7 +2300,6 @@
JUMP_TO_LABEL(error); JUMP_TO_LABEL(error);
} }
stack_pointer += -1; stack_pointer += -1;
assert(WITHIN_STACK_BOUNDS());
} }
} }
stack_pointer[0] = res; stack_pointer[0] = res;
@ -2366,7 +2360,6 @@
stack_pointer = _PyFrame_GetStackPointer(frame); stack_pointer = _PyFrame_GetStackPointer(frame);
tuple = PyStackRef_FromPyObjectSteal(tuple_o); tuple = PyStackRef_FromPyObjectSteal(tuple_o);
stack_pointer += 2; stack_pointer += 2;
assert(WITHIN_STACK_BOUNDS());
} }
} }
// _DO_CALL_FUNCTION_EX // _DO_CALL_FUNCTION_EX
@ -2494,7 +2487,6 @@
JUMP_TO_LABEL(error); JUMP_TO_LABEL(error);
} }
stack_pointer += -1; stack_pointer += -1;
assert(WITHIN_STACK_BOUNDS());
} }
} }
stack_pointer[0] = result; stack_pointer[0] = result;
@ -2736,7 +2728,6 @@
} }
STACKREFS_TO_PYOBJECTS(arguments, total_args, args_o); STACKREFS_TO_PYOBJECTS(arguments, total_args, args_o);
if (CONVERSION_FAILED(args_o)) { if (CONVERSION_FAILED(args_o)) {
stack_pointer[-1] = kwnames;
_PyFrame_SetStackPointer(frame, stack_pointer); _PyFrame_SetStackPointer(frame, stack_pointer);
_PyStackRef tmp = kwnames; _PyStackRef tmp = kwnames;
kwnames = PyStackRef_NULL; kwnames = PyStackRef_NULL;
@ -3070,7 +3061,6 @@
JUMP_TO_LABEL(error); JUMP_TO_LABEL(error);
} }
stack_pointer += -1; stack_pointer += -1;
assert(WITHIN_STACK_BOUNDS());
} }
} }
stack_pointer[0] = res; stack_pointer[0] = res;
@ -3422,7 +3412,6 @@
JUMP_TO_LABEL(error); JUMP_TO_LABEL(error);
} }
stack_pointer += -1; stack_pointer += -1;
assert(WITHIN_STACK_BOUNDS());
} }
} }
stack_pointer[0] = res; stack_pointer[0] = res;
@ -3544,7 +3533,6 @@
JUMP_TO_LABEL(error); JUMP_TO_LABEL(error);
} }
stack_pointer += -1; stack_pointer += -1;
assert(WITHIN_STACK_BOUNDS());
} }
} }
stack_pointer[0] = res; stack_pointer[0] = res;
@ -3646,7 +3634,6 @@
JUMP_TO_LABEL(error); JUMP_TO_LABEL(error);
} }
stack_pointer += -1; stack_pointer += -1;
assert(WITHIN_STACK_BOUNDS());
} }
} }
stack_pointer[0] = res; stack_pointer[0] = res;
@ -3759,7 +3746,6 @@
JUMP_TO_LABEL(error); JUMP_TO_LABEL(error);
} }
stack_pointer += -1; stack_pointer += -1;
assert(WITHIN_STACK_BOUNDS());
} }
} }
stack_pointer[0] = res; stack_pointer[0] = res;
@ -3879,7 +3865,6 @@
JUMP_TO_LABEL(error); JUMP_TO_LABEL(error);
} }
stack_pointer += -1; stack_pointer += -1;
assert(WITHIN_STACK_BOUNDS());
} }
} }
stack_pointer[0] = res; stack_pointer[0] = res;
@ -4154,7 +4139,6 @@
JUMP_TO_LABEL(error); JUMP_TO_LABEL(error);
} }
stack_pointer += -1; stack_pointer += -1;
assert(WITHIN_STACK_BOUNDS());
} }
} }
stack_pointer[0] = res; stack_pointer[0] = res;
@ -4227,7 +4211,6 @@
JUMP_TO_LABEL(error); JUMP_TO_LABEL(error);
} }
stack_pointer += -1; stack_pointer += -1;
assert(WITHIN_STACK_BOUNDS());
} }
} }
stack_pointer[0] = res; stack_pointer[0] = res;
@ -5310,7 +5293,6 @@
INSTRUCTION_STATS(EXIT_INIT_CHECK); INSTRUCTION_STATS(EXIT_INIT_CHECK);
_PyStackRef should_be_none; _PyStackRef should_be_none;
should_be_none = stack_pointer[-1]; should_be_none = stack_pointer[-1];
assert(STACK_LEVEL() == 2);
if (!PyStackRef_IsNone(should_be_none)) { if (!PyStackRef_IsNone(should_be_none)) {
_PyFrame_SetStackPointer(frame, stack_pointer); _PyFrame_SetStackPointer(frame, stack_pointer);
PyErr_Format(PyExc_TypeError, PyErr_Format(PyExc_TypeError,
@ -5369,7 +5351,6 @@
else { else {
res = value; res = value;
stack_pointer += -1; stack_pointer += -1;
assert(WITHIN_STACK_BOUNDS());
} }
stack_pointer[0] = res; stack_pointer[0] = res;
stack_pointer += 1; stack_pointer += 1;
@ -6130,8 +6111,9 @@
} }
// _DO_CALL // _DO_CALL
{ {
self_or_null = maybe_self; args = &stack_pointer[-oparg];
callable = func; self_or_null = &stack_pointer[-1 - oparg];
callable = &stack_pointer[-2 - oparg];
PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable[0]); PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable[0]);
int total_args = oparg; int total_args = oparg;
_PyStackRef *arguments = args; _PyStackRef *arguments = args;
@ -6246,7 +6228,6 @@
JUMP_TO_LABEL(error); JUMP_TO_LABEL(error);
} }
stack_pointer += -1; stack_pointer += -1;
assert(WITHIN_STACK_BOUNDS());
} }
} }
stack_pointer[0] = res; stack_pointer[0] = res;
@ -6307,7 +6288,6 @@
stack_pointer = _PyFrame_GetStackPointer(frame); stack_pointer = _PyFrame_GetStackPointer(frame);
tuple = PyStackRef_FromPyObjectSteal(tuple_o); tuple = PyStackRef_FromPyObjectSteal(tuple_o);
stack_pointer += 2; stack_pointer += 2;
assert(WITHIN_STACK_BOUNDS());
} }
} }
// _DO_CALL_FUNCTION_EX // _DO_CALL_FUNCTION_EX
@ -6435,7 +6415,6 @@
JUMP_TO_LABEL(error); JUMP_TO_LABEL(error);
} }
stack_pointer += -1; stack_pointer += -1;
assert(WITHIN_STACK_BOUNDS());
} }
} }
stack_pointer[0] = result; stack_pointer[0] = result;
@ -6753,14 +6732,16 @@
frame->instr_ptr = next_instr; frame->instr_ptr = next_instr;
next_instr += 2; next_instr += 2;
INSTRUCTION_STATS(INSTRUMENTED_FOR_ITER); INSTRUCTION_STATS(INSTRUMENTED_FOR_ITER);
_PyStackRef iter;
_PyStackRef next;
/* Skip 1 cache entry */ /* Skip 1 cache entry */
_PyStackRef iter_stackref = TOP(); iter = stack_pointer[-1];
PyObject *iter = PyStackRef_AsPyObjectBorrow(iter_stackref); PyObject *iter_o = PyStackRef_AsPyObjectBorrow(iter);
_PyFrame_SetStackPointer(frame, stack_pointer); _PyFrame_SetStackPointer(frame, stack_pointer);
PyObject *next = (*Py_TYPE(iter)->tp_iternext)(iter); PyObject *next_o = (*Py_TYPE(iter_o)->tp_iternext)(iter_o);
stack_pointer = _PyFrame_GetStackPointer(frame); stack_pointer = _PyFrame_GetStackPointer(frame);
if (next != NULL) { if (next_o != NULL) {
PUSH(PyStackRef_FromPyObjectSteal(next)); next = PyStackRef_FromPyObjectSteal(next_o);
INSTRUMENTED_JUMP(this_instr, next_instr, PY_MONITORING_EVENT_BRANCH_LEFT); INSTRUMENTED_JUMP(this_instr, next_instr, PY_MONITORING_EVENT_BRANCH_LEFT);
} }
else { else {
@ -6779,7 +6760,11 @@
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);
JUMPBY(oparg + 1); JUMPBY(oparg + 1);
DISPATCH();
} }
stack_pointer[0] = next;
stack_pointer += 1;
assert(WITHIN_STACK_BOUNDS());
DISPATCH(); DISPATCH();
} }
@ -7063,14 +7048,17 @@
frame->instr_ptr = next_instr; frame->instr_ptr = next_instr;
next_instr += 2; next_instr += 2;
INSTRUCTION_STATS(INSTRUMENTED_POP_JUMP_IF_FALSE); INSTRUCTION_STATS(INSTRUMENTED_POP_JUMP_IF_FALSE);
_PyStackRef cond;
/* Skip 1 cache entry */ /* Skip 1 cache entry */
_PyStackRef cond = POP(); cond = stack_pointer[-1];
assert(PyStackRef_BoolCheck(cond)); assert(PyStackRef_BoolCheck(cond));
int jump = PyStackRef_IsFalse(cond); int jump = PyStackRef_IsFalse(cond);
RECORD_BRANCH_TAKEN(this_instr[1].cache, jump); RECORD_BRANCH_TAKEN(this_instr[1].cache, jump);
if (jump) { if (jump) {
INSTRUMENTED_JUMP(this_instr, next_instr + oparg, PY_MONITORING_EVENT_BRANCH_RIGHT); INSTRUMENTED_JUMP(this_instr, next_instr + oparg, PY_MONITORING_EVENT_BRANCH_RIGHT);
} }
stack_pointer += -1;
assert(WITHIN_STACK_BOUNDS());
DISPATCH(); DISPATCH();
} }
@ -7084,18 +7072,24 @@
frame->instr_ptr = next_instr; frame->instr_ptr = next_instr;
next_instr += 2; next_instr += 2;
INSTRUCTION_STATS(INSTRUMENTED_POP_JUMP_IF_NONE); INSTRUCTION_STATS(INSTRUMENTED_POP_JUMP_IF_NONE);
_PyStackRef value;
/* Skip 1 cache entry */ /* Skip 1 cache entry */
_PyStackRef value_stackref = POP(); value = stack_pointer[-1];
int jump = PyStackRef_IsNone(value_stackref); int jump = PyStackRef_IsNone(value);
RECORD_BRANCH_TAKEN(this_instr[1].cache, jump); RECORD_BRANCH_TAKEN(this_instr[1].cache, jump);
if (jump) { if (jump) {
INSTRUMENTED_JUMP(this_instr, next_instr + oparg, PY_MONITORING_EVENT_BRANCH_RIGHT); INSTRUMENTED_JUMP(this_instr, next_instr + oparg, PY_MONITORING_EVENT_BRANCH_RIGHT);
} }
else { else {
stack_pointer += -1;
assert(WITHIN_STACK_BOUNDS());
_PyFrame_SetStackPointer(frame, stack_pointer); _PyFrame_SetStackPointer(frame, stack_pointer);
PyStackRef_CLOSE(value_stackref); PyStackRef_CLOSE(value);
stack_pointer = _PyFrame_GetStackPointer(frame); stack_pointer = _PyFrame_GetStackPointer(frame);
stack_pointer += 1;
} }
stack_pointer += -1;
assert(WITHIN_STACK_BOUNDS());
DISPATCH(); DISPATCH();
} }
@ -7109,16 +7103,22 @@
frame->instr_ptr = next_instr; frame->instr_ptr = next_instr;
next_instr += 2; next_instr += 2;
INSTRUCTION_STATS(INSTRUMENTED_POP_JUMP_IF_NOT_NONE); INSTRUCTION_STATS(INSTRUMENTED_POP_JUMP_IF_NOT_NONE);
_PyStackRef value;
/* Skip 1 cache entry */ /* Skip 1 cache entry */
_PyStackRef value_stackref = POP(); value = stack_pointer[-1];
int jump = !PyStackRef_IsNone(value_stackref); int jump = !PyStackRef_IsNone(value);
RECORD_BRANCH_TAKEN(this_instr[1].cache, jump); RECORD_BRANCH_TAKEN(this_instr[1].cache, jump);
if (jump) { if (jump) {
stack_pointer += -1;
assert(WITHIN_STACK_BOUNDS());
_PyFrame_SetStackPointer(frame, stack_pointer); _PyFrame_SetStackPointer(frame, stack_pointer);
PyStackRef_CLOSE(value_stackref); PyStackRef_CLOSE(value);
stack_pointer = _PyFrame_GetStackPointer(frame); stack_pointer = _PyFrame_GetStackPointer(frame);
INSTRUMENTED_JUMP(this_instr, next_instr + oparg, PY_MONITORING_EVENT_BRANCH_RIGHT); INSTRUMENTED_JUMP(this_instr, next_instr + oparg, PY_MONITORING_EVENT_BRANCH_RIGHT);
} }
else {
stack_pointer += -1;
}
DISPATCH(); DISPATCH();
} }
@ -7132,14 +7132,17 @@
frame->instr_ptr = next_instr; frame->instr_ptr = next_instr;
next_instr += 2; next_instr += 2;
INSTRUCTION_STATS(INSTRUMENTED_POP_JUMP_IF_TRUE); INSTRUCTION_STATS(INSTRUMENTED_POP_JUMP_IF_TRUE);
_PyStackRef cond;
/* Skip 1 cache entry */ /* Skip 1 cache entry */
_PyStackRef cond = POP(); cond = stack_pointer[-1];
assert(PyStackRef_BoolCheck(cond)); assert(PyStackRef_BoolCheck(cond));
int jump = PyStackRef_IsTrue(cond); int jump = PyStackRef_IsTrue(cond);
RECORD_BRANCH_TAKEN(this_instr[1].cache, jump); RECORD_BRANCH_TAKEN(this_instr[1].cache, jump);
if (jump) { if (jump) {
INSTRUMENTED_JUMP(this_instr, next_instr + oparg, PY_MONITORING_EVENT_BRANCH_RIGHT); INSTRUMENTED_JUMP(this_instr, next_instr + oparg, PY_MONITORING_EVENT_BRANCH_RIGHT);
} }
stack_pointer += -1;
assert(WITHIN_STACK_BOUNDS());
DISPATCH(); DISPATCH();
} }
@ -7254,7 +7257,7 @@
stack_pointer += -1; stack_pointer += -1;
assert(WITHIN_STACK_BOUNDS()); assert(WITHIN_STACK_BOUNDS());
_PyFrame_SetStackPointer(frame, stack_pointer); _PyFrame_SetStackPointer(frame, stack_pointer);
assert(EMPTY()); assert(STACK_LEVEL() == 0);
_Py_LeaveRecursiveCallPy(tstate); _Py_LeaveRecursiveCallPy(tstate);
_PyInterpreterFrame *dying = frame; _PyInterpreterFrame *dying = frame;
frame = tstate->current_frame = dying->previous; frame = tstate->current_frame = dying->previous;
@ -7353,9 +7356,11 @@
tstate->current_frame = frame->previous; tstate->current_frame = frame->previous;
assert(!_PyErr_Occurred(tstate)); assert(!_PyErr_Occurred(tstate));
PyObject *result = PyStackRef_AsPyObjectSteal(retval); PyObject *result = PyStackRef_AsPyObjectSteal(retval);
LLTRACE_RESUME_FRAME();
return result;
stack_pointer += -1; stack_pointer += -1;
assert(WITHIN_STACK_BOUNDS()); assert(WITHIN_STACK_BOUNDS());
return result; DISPATCH();
} }
TARGET(IS_OP) { TARGET(IS_OP) {
@ -7684,7 +7689,6 @@
} }
self_or_null[0] = PyStackRef_NULL; self_or_null[0] = PyStackRef_NULL;
stack_pointer += 1; stack_pointer += 1;
assert(WITHIN_STACK_BOUNDS());
} }
} }
else { else {
@ -7700,7 +7704,6 @@
JUMP_TO_LABEL(error); JUMP_TO_LABEL(error);
} }
stack_pointer += 1; stack_pointer += 1;
assert(WITHIN_STACK_BOUNDS());
} }
attr = PyStackRef_FromPyObjectSteal(attr_o); attr = PyStackRef_FromPyObjectSteal(attr_o);
} }
@ -7886,8 +7889,9 @@
PyObject *name = GETITEM(FRAME_CO_NAMES, oparg >> 1); PyObject *name = GETITEM(FRAME_CO_NAMES, oparg >> 1);
_PyInterpreterFrame *new_frame = _PyFrame_PushUnchecked( _PyInterpreterFrame *new_frame = _PyFrame_PushUnchecked(
tstate, PyStackRef_FromPyObjectNew(f), 2, frame); tstate, PyStackRef_FromPyObjectNew(f), 2, frame);
STACK_SHRINK(1);
new_frame->localsplus[0] = owner; new_frame->localsplus[0] = owner;
stack_pointer += -1;
assert(WITHIN_STACK_BOUNDS());
new_frame->localsplus[1] = PyStackRef_FromPyObjectNew(name); new_frame->localsplus[1] = PyStackRef_FromPyObjectNew(name);
frame->return_offset = 10 ; frame->return_offset = 10 ;
DISPATCH_INLINED(new_frame); DISPATCH_INLINED(new_frame);
@ -9551,7 +9555,6 @@
stack_pointer = _PyFrame_GetStackPointer(frame); stack_pointer = _PyFrame_GetStackPointer(frame);
self_or_null = PyStackRef_NULL; self_or_null = PyStackRef_NULL;
stack_pointer += 1; stack_pointer += 1;
assert(WITHIN_STACK_BOUNDS());
} }
stack_pointer += -1; stack_pointer += -1;
assert(WITHIN_STACK_BOUNDS()); assert(WITHIN_STACK_BOUNDS());
@ -10243,7 +10246,7 @@
if (gen == NULL) { if (gen == NULL) {
JUMP_TO_LABEL(error); JUMP_TO_LABEL(error);
} }
assert(EMPTY()); assert(STACK_LEVEL() == 0);
_PyFrame_SetStackPointer(frame, stack_pointer); _PyFrame_SetStackPointer(frame, stack_pointer);
_PyInterpreterFrame *gen_frame = &gen->gi_iframe; _PyInterpreterFrame *gen_frame = &gen->gi_iframe;
frame->instr_ptr++; frame->instr_ptr++;
@ -10281,7 +10284,7 @@
stack_pointer += -1; stack_pointer += -1;
assert(WITHIN_STACK_BOUNDS()); assert(WITHIN_STACK_BOUNDS());
_PyFrame_SetStackPointer(frame, stack_pointer); _PyFrame_SetStackPointer(frame, stack_pointer);
assert(EMPTY()); assert(STACK_LEVEL() == 0);
_Py_LeaveRecursiveCallPy(tstate); _Py_LeaveRecursiveCallPy(tstate);
_PyInterpreterFrame *dying = frame; _PyInterpreterFrame *dying = frame;
frame = tstate->current_frame = dying->previous; frame = tstate->current_frame = dying->previous;
@ -10339,8 +10342,9 @@
{ {
PyGenObject *gen = (PyGenObject *)receiver_o; PyGenObject *gen = (PyGenObject *)receiver_o;
_PyInterpreterFrame *gen_frame = &gen->gi_iframe; _PyInterpreterFrame *gen_frame = &gen->gi_iframe;
STACK_SHRINK(1);
_PyFrame_StackPush(gen_frame, PyStackRef_MakeHeapSafe(v)); _PyFrame_StackPush(gen_frame, PyStackRef_MakeHeapSafe(v));
stack_pointer += -1;
assert(WITHIN_STACK_BOUNDS());
gen->gi_frame_state = FRAME_EXECUTING; gen->gi_frame_state = FRAME_EXECUTING;
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;
@ -11095,21 +11099,18 @@
Py_DECREF(slice); Py_DECREF(slice);
stack_pointer = _PyFrame_GetStackPointer(frame); stack_pointer = _PyFrame_GetStackPointer(frame);
stack_pointer += 2; stack_pointer += 2;
assert(WITHIN_STACK_BOUNDS());
} }
stack_pointer += -2;
assert(WITHIN_STACK_BOUNDS());
_PyFrame_SetStackPointer(frame, stack_pointer); _PyFrame_SetStackPointer(frame, stack_pointer);
_PyStackRef tmp = container; _PyStackRef tmp = container;
container = PyStackRef_NULL; container = PyStackRef_NULL;
stack_pointer[-1] = container; stack_pointer[-3] = container;
PyStackRef_CLOSE(tmp); PyStackRef_CLOSE(tmp);
tmp = v; tmp = v;
v = PyStackRef_NULL; v = PyStackRef_NULL;
stack_pointer[-2] = v; stack_pointer[-4] = v;
PyStackRef_CLOSE(tmp); PyStackRef_CLOSE(tmp);
stack_pointer = _PyFrame_GetStackPointer(frame); stack_pointer = _PyFrame_GetStackPointer(frame);
stack_pointer += -2; stack_pointer += -4;
assert(WITHIN_STACK_BOUNDS()); assert(WITHIN_STACK_BOUNDS());
if (err) { if (err) {
JUMP_TO_LABEL(error); JUMP_TO_LABEL(error);
@ -11465,7 +11466,6 @@
stack_pointer = _PyFrame_GetStackPointer(frame); stack_pointer = _PyFrame_GetStackPointer(frame);
res = PyStackRef_True; res = PyStackRef_True;
stack_pointer += 1; stack_pointer += 1;
assert(WITHIN_STACK_BOUNDS());
} }
stack_pointer[-1] = res; stack_pointer[-1] = res;
DISPATCH(); DISPATCH();
@ -11573,7 +11573,6 @@
stack_pointer = _PyFrame_GetStackPointer(frame); stack_pointer = _PyFrame_GetStackPointer(frame);
res = PyStackRef_True; res = PyStackRef_True;
stack_pointer += 1; stack_pointer += 1;
assert(WITHIN_STACK_BOUNDS());
} }
} }
stack_pointer[-1] = res; stack_pointer[-1] = res;
@ -11861,7 +11860,6 @@
_PyFrame_SetStackPointer(frame, stack_pointer); _PyFrame_SetStackPointer(frame, stack_pointer);
PyStackRef_CLOSE(seq); PyStackRef_CLOSE(seq);
stack_pointer = _PyFrame_GetStackPointer(frame); stack_pointer = _PyFrame_GetStackPointer(frame);
stack_pointer[-1] = val0;
DISPATCH(); DISPATCH();
} }
@ -11984,25 +11982,29 @@ JUMP_TO_LABEL(error);
LABEL(pop_4_error) LABEL(pop_4_error)
{ {
STACK_SHRINK(4); stack_pointer -= 4;
assert(WITHIN_STACK_BOUNDS());
JUMP_TO_LABEL(error); JUMP_TO_LABEL(error);
} }
LABEL(pop_3_error) LABEL(pop_3_error)
{ {
STACK_SHRINK(3); stack_pointer -= 3;
assert(WITHIN_STACK_BOUNDS());
JUMP_TO_LABEL(error); JUMP_TO_LABEL(error);
} }
LABEL(pop_2_error) LABEL(pop_2_error)
{ {
STACK_SHRINK(2); stack_pointer -= 2;
assert(WITHIN_STACK_BOUNDS());
JUMP_TO_LABEL(error); JUMP_TO_LABEL(error);
} }
LABEL(pop_1_error) LABEL(pop_1_error)
{ {
STACK_SHRINK(1); stack_pointer -= 1;
assert(WITHIN_STACK_BOUNDS());
JUMP_TO_LABEL(error); JUMP_TO_LABEL(error);
} }

View file

@ -310,7 +310,6 @@
else { else {
res = sym_new_type(ctx, &PyLong_Type); res = sym_new_type(ctx, &PyLong_Type);
stack_pointer += -1; stack_pointer += -1;
assert(WITHIN_STACK_BOUNDS());
} }
stack_pointer[-1] = res; stack_pointer[-1] = res;
break; break;
@ -339,7 +338,6 @@
else { else {
res = sym_new_type(ctx, &PyLong_Type); res = sym_new_type(ctx, &PyLong_Type);
stack_pointer += -1; stack_pointer += -1;
assert(WITHIN_STACK_BOUNDS());
} }
stack_pointer[-1] = res; stack_pointer[-1] = res;
break; break;
@ -368,7 +366,6 @@
else { else {
res = sym_new_type(ctx, &PyLong_Type); res = sym_new_type(ctx, &PyLong_Type);
stack_pointer += -1; stack_pointer += -1;
assert(WITHIN_STACK_BOUNDS());
} }
stack_pointer[-1] = res; stack_pointer[-1] = res;
break; break;
@ -418,7 +415,6 @@
else { else {
res = sym_new_type(ctx, &PyFloat_Type); res = sym_new_type(ctx, &PyFloat_Type);
stack_pointer += -1; stack_pointer += -1;
assert(WITHIN_STACK_BOUNDS());
} }
stack_pointer[-1] = res; stack_pointer[-1] = res;
break; break;
@ -448,7 +444,6 @@
else { else {
res = sym_new_type(ctx, &PyFloat_Type); res = sym_new_type(ctx, &PyFloat_Type);
stack_pointer += -1; stack_pointer += -1;
assert(WITHIN_STACK_BOUNDS());
} }
stack_pointer[-1] = res; stack_pointer[-1] = res;
break; break;
@ -478,7 +473,6 @@
else { else {
res = sym_new_type(ctx, &PyFloat_Type); res = sym_new_type(ctx, &PyFloat_Type);
stack_pointer += -1; stack_pointer += -1;
assert(WITHIN_STACK_BOUNDS());
} }
stack_pointer[-1] = res; stack_pointer[-1] = res;
break; break;
@ -506,7 +500,6 @@
else { else {
res = sym_new_type(ctx, &PyUnicode_Type); res = sym_new_type(ctx, &PyUnicode_Type);
stack_pointer += -1; stack_pointer += -1;
assert(WITHIN_STACK_BOUNDS());
} }
stack_pointer[-1] = res; stack_pointer[-1] = res;
break; break;
@ -1257,7 +1250,6 @@
else { else {
res = sym_new_type(ctx, &PyBool_Type); res = sym_new_type(ctx, &PyBool_Type);
stack_pointer += -1; stack_pointer += -1;
assert(WITHIN_STACK_BOUNDS());
} }
stack_pointer[-1] = res; stack_pointer[-1] = res;
break; break;
@ -2031,7 +2023,6 @@
if (co == NULL) { if (co == NULL) {
ctx->done = true; ctx->done = true;
} }
stack_pointer[-1] = res;
break; break;
} }

View file

@ -71,6 +71,9 @@ _Py_stackref_close(_PyStackRef ref, const char *filename, int linenumber)
} }
PyObject *obj; PyObject *obj;
if (ref.index <= LAST_PREDEFINED_STACKREF_INDEX) { if (ref.index <= LAST_PREDEFINED_STACKREF_INDEX) {
if (ref.index == 0) {
_Py_FatalErrorFormat(__func__, "Passing NULL to PyStackRef_CLOSE at %s:%d\n", filename, linenumber);
}
// Pre-allocated reference to None, False or True -- Do not clear // Pre-allocated reference to None, False or True -- Do not clear
TableEntry *entry = _Py_hashtable_get(interp->open_stackrefs_table, (void *)ref.index); TableEntry *entry = _Py_hashtable_get(interp->open_stackrefs_table, (void *)ref.index);
obj = entry->obj; obj = entry->obj;

View file

@ -13,9 +13,8 @@ from typing import Callable, TextIO, Iterator, Iterable
from lexer import Token from lexer import Token
from stack import Storage, StackError from stack import Storage, StackError
from parser import Stmt, SimpleStmt, BlockStmt, IfStmt, ForStmt, WhileStmt, MacroIfStmt from parser import Stmt, SimpleStmt, BlockStmt, IfStmt, ForStmt, WhileStmt, MacroIfStmt
from stack import PRINT_STACKS
# Set this to true for voluminous output showing state of stack and locals DEBUG = False
PRINT_STACKS = False
class TokenIterator: class TokenIterator:
@ -161,7 +160,7 @@ class Emitter:
self.emit(") {\n") self.emit(") {\n")
next(tkn_iter) # Semi colon next(tkn_iter) # Semi colon
assert inst is not None assert inst is not None
assert inst.family is not None, inst assert inst.family is not None
family_name = inst.family.name family_name = inst.family.name
self.emit(f"UPDATE_MISS_STATS({family_name});\n") self.emit(f"UPDATE_MISS_STATS({family_name});\n")
self.emit(f"assert(_PyOpcode_Deopt[opcode] == ({family_name}));\n") self.emit(f"assert(_PyOpcode_Deopt[opcode] == ({family_name}));\n")
@ -242,6 +241,7 @@ class Emitter:
next(tkn_iter) next(tkn_iter)
next(tkn_iter) next(tkn_iter)
next(tkn_iter) next(tkn_iter)
self._print_storage("DECREF_INPUTS", storage)
try: try:
storage.close_inputs(self.out) storage.close_inputs(self.out)
except StackError as ex: except StackError as ex:
@ -249,7 +249,6 @@ class Emitter:
except Exception as ex: except Exception as ex:
ex.args = (ex.args[0] + str(tkn),) ex.args = (ex.args[0] + str(tkn),)
raise raise
self._print_storage(storage)
return True return True
def kill_inputs( def kill_inputs(
@ -372,7 +371,7 @@ class Emitter:
next(tkn_iter) next(tkn_iter)
storage.clear_inputs("when syncing stack") storage.clear_inputs("when syncing stack")
storage.flush(self.out) storage.flush(self.out)
self._print_storage(storage) storage.stack.clear(self.out)
return True return True
def stack_pointer( def stack_pointer(
@ -406,7 +405,6 @@ class Emitter:
def emit_save(self, storage: Storage) -> None: def emit_save(self, storage: Storage) -> None:
storage.flush(self.out) storage.flush(self.out)
storage.save(self.out) storage.save(self.out)
self._print_storage(storage)
def save_stack( def save_stack(
self, self,
@ -424,7 +422,6 @@ class Emitter:
def emit_reload(self, storage: Storage) -> None: def emit_reload(self, storage: Storage) -> None:
storage.reload(self.out) storage.reload(self.out)
self._print_storage(storage)
def reload_stack( def reload_stack(
self, self,
@ -453,9 +450,10 @@ class Emitter:
self.out.emit(f" {uop.instruction_size} ") self.out.emit(f" {uop.instruction_size} ")
return True return True
def _print_storage(self, storage: Storage) -> None: def _print_storage(self, reason:str, storage: Storage) -> None:
if PRINT_STACKS: if DEBUG:
self.out.start_line() self.out.start_line()
self.emit(f"/* {reason} */\n")
self.emit(storage.as_comment()) self.emit(storage.as_comment())
self.out.start_line() self.out.start_line()
@ -514,7 +512,6 @@ class Emitter:
var.memory_offset = None var.memory_offset = None
break break
if tkn.text.startswith("DISPATCH"): if tkn.text.startswith("DISPATCH"):
self._print_storage(storage)
reachable = False reachable = False
self.out.emit(tkn) self.out.emit(tkn)
else: else:
@ -536,6 +533,8 @@ class Emitter:
self.out.emit(stmt.condition) self.out.emit(stmt.condition)
branch = stmt.else_ is not None branch = stmt.else_ is not None
reachable = True reachable = True
if branch:
else_storage = storage.copy()
for s in stmt.body: for s in stmt.body:
r, tkn, storage = self._emit_stmt(s, uop, storage, inst) r, tkn, storage = self._emit_stmt(s, uop, storage, inst)
if tkn is not None: if tkn is not None:
@ -543,7 +542,6 @@ class Emitter:
if not r: if not r:
reachable = False reachable = False
if branch: if branch:
else_storage = storage.copy()
assert stmt.else_ is not None assert stmt.else_ is not None
self.out.emit(stmt.else_) self.out.emit(stmt.else_)
assert stmt.else_body is not None assert stmt.else_body is not None
@ -553,7 +551,8 @@ class Emitter:
self.out.emit(tkn) self.out.emit(tkn)
if not r: if not r:
reachable = False reachable = False
storage.merge(else_storage, self.out) else_storage.merge(storage, self.out) # type: ignore[possibly-undefined]
storage = else_storage
self.out.emit(stmt.endif) self.out.emit(stmt.endif)
return reachable, None, storage return reachable, None, storage
@ -596,7 +595,6 @@ class Emitter:
reachable = True reachable = True
return reachable, rbrace, storage return reachable, rbrace, storage
except StackError as ex: except StackError as ex:
self._print_storage(if_storage)
assert rbrace is not None assert rbrace is not None
raise analysis_error(ex.args[0], rbrace) from None raise analysis_error(ex.args[0], rbrace) from None
@ -659,20 +657,18 @@ class Emitter:
storage: Storage, storage: Storage,
inst: Instruction | None, inst: Instruction | None,
emit_braces: bool = True emit_braces: bool = True
) -> Storage: ) -> tuple[bool, Storage]:
self.out.start_line() self.out.start_line()
reachable, tkn, storage = self.emit_BlockStmt(code.body, code, storage, inst, emit_braces) reachable, tkn, storage = self.emit_BlockStmt(code.body, code, storage, inst, emit_braces)
assert tkn is not None assert tkn is not None
try: try:
if reachable: if reachable:
self._print_storage(storage)
storage.push_outputs() storage.push_outputs()
self._print_storage(storage)
if emit_braces: if emit_braces:
self.out.emit(tkn) self.out.emit(tkn)
except StackError as ex: except StackError as ex:
raise analysis_error(ex.args[0], tkn) from None raise analysis_error(ex.args[0], tkn) from None
return storage return reachable, storage
def emit(self, txt: str | Token) -> None: def emit(self, txt: str | Token) -> None:
self.out.emit(txt) self.out.emit(txt)

View file

@ -145,7 +145,7 @@ def write_uop(
# No reference management of inputs needed. # No reference management of inputs needed.
for var in storage.inputs: # type: ignore[possibly-undefined] for var in storage.inputs: # type: ignore[possibly-undefined]
var.in_local = False var.in_local = False
storage = emitter.emit_tokens(override, storage, None, False) _, storage = emitter.emit_tokens(override, storage, None, False)
out.start_line() out.start_line()
storage.flush(out) storage.flush(out)
else: else:

View file

@ -6,6 +6,8 @@ from typing import Iterator
UNUSED = {"unused"} UNUSED = {"unused"}
# Set this to true for voluminous output showing state of stack and locals
PRINT_STACKS = False
def maybe_parenthesize(sym: str) -> str: def maybe_parenthesize(sym: str) -> str:
"""Add parentheses around a string if it contains an operator """Add parentheses around a string if it contains an operator
@ -131,9 +133,6 @@ class PointerOffset:
return None return None
return self.numeric return self.numeric
def __bool__(self) -> bool:
return self.numeric != 0 or bool(self.positive) or bool(self.negative)
def __str__(self) -> str: def __str__(self) -> str:
return self.to_c() return self.to_c()
@ -151,7 +150,7 @@ class Local:
def compact_str(self) -> str: def compact_str(self) -> str:
mtag = "M" if self.memory_offset else "" mtag = "M" if self.memory_offset else ""
dtag = "D" if self.in_local else "" dtag = "L" if self.in_local else ""
atag = "A" if self.is_array() else "" atag = "A" if self.is_array() else ""
return f"'{self.item.name}'{mtag}{dtag}{atag}" return f"'{self.item.name}'{mtag}{dtag}{atag}"
@ -167,6 +166,11 @@ class Local:
def from_memory(defn: StackItem, offset: PointerOffset) -> "Local": def from_memory(defn: StackItem, offset: PointerOffset) -> "Local":
return Local(defn, offset, True) return Local(defn, offset, True)
@staticmethod
def register(name: str) -> "Local":
item = StackItem(name, None, "", False, True)
return Local(item, None, True)
def kill(self) -> None: def kill(self) -> None:
self.in_local = False self.in_local = False
self.memory_offset = None self.memory_offset = None
@ -230,20 +234,16 @@ class Stack:
raise StackError(f"Dropping live value '{var.name}'") raise StackError(f"Dropping live value '{var.name}'")
def pop(self, var: StackItem, out: CWriter) -> Local: def pop(self, var: StackItem, out: CWriter) -> Local:
if self.variables:
top = self.variables[-1]
if var.is_array() != top.is_array() or top.size != var.size:
# Mismatch in variables
self.clear(out)
self.logical_sp = self.logical_sp.pop(var) self.logical_sp = self.logical_sp.pop(var)
indirect = "&" if var.is_array() else "" indirect = "&" if var.is_array() else ""
if self.variables: if self.variables:
popped = self.variables.pop() popped = self.variables.pop()
if var.is_array() ^ popped.is_array(): assert var.is_array() == popped.is_array() and popped.size == var.size
raise StackError(
f"Array mismatch when popping '{popped.name}' from stack to assign to '{var.name}'. "
f"Expected {array_or_scalar(var)} got {array_or_scalar(popped)}"
)
if popped.size != var.size:
raise StackError(
f"Size mismatch when popping '{popped.name}' from stack to assign to '{var.name}'. "
f"Expected {var_size(var)} got {var_size(popped.item)}"
)
if not var.used: if not var.used:
return popped return popped
if popped.name != var.name: if popped.name != var.name:
@ -255,27 +255,33 @@ class Stack:
if popped.memory_offset is None: if popped.memory_offset is None:
popped.memory_offset = self.logical_sp popped.memory_offset = self.logical_sp
assert popped.memory_offset == self.logical_sp, (popped, self.as_comment()) assert popped.memory_offset == self.logical_sp, (popped, self.as_comment())
offset = popped.memory_offset.to_c() offset = popped.memory_offset - self.physical_sp
if var.is_array(): if var.is_array():
defn = f"{var.name} = &stack_pointer[{offset}];\n" defn = f"{var.name} = &stack_pointer[{offset.to_c()}];\n"
else: else:
defn = f"{var.name} = stack_pointer[{offset}];\n" defn = f"{var.name} = stack_pointer[{offset.to_c()}];\n"
popped.in_local = True popped.in_local = True
else: else:
defn = rename defn = rename
out.emit(defn) out.emit(defn)
return popped return popped
self.base_offset = self.logical_sp self.base_offset = self.logical_sp
if var.name in UNUSED or not var.used: if var.name in UNUSED or not var.used:
return Local.unused(var, self.base_offset) return Local.unused(var, self.base_offset)
cast = f"({var.type})" if (not indirect and var.type) else "" cast = f"({var.type})" if (not indirect and var.type) else ""
bits = ".bits" if cast and self.extract_bits else "" bits = ".bits" if cast and self.extract_bits else ""
offset = (self.base_offset - self.physical_sp).to_c() c_offset = (self.base_offset - self.physical_sp).to_c()
assign = f"{var.name} = {cast}{indirect}stack_pointer[{offset}]{bits};\n" assign = f"{var.name} = {cast}{indirect}stack_pointer[{c_offset}]{bits};\n"
out.emit(assign) out.emit(assign)
self._print(out)
return Local.from_memory(var, self.base_offset) return Local.from_memory(var, self.base_offset)
def clear(self, out: CWriter) -> None:
"Flush to memory and clear variables stack"
self.flush(out)
self.variables = []
self.base_offset = self.logical_sp
def push(self, var: Local) -> None: def push(self, var: Local) -> None:
assert(var not in self.variables) assert(var not in self.variables)
self.variables.append(var) self.variables.append(var)
@ -298,10 +304,11 @@ class Stack:
diff = self.logical_sp - self.physical_sp diff = self.logical_sp - self.physical_sp
out.start_line() out.start_line()
out.emit(f"stack_pointer += {diff.to_c()};\n") out.emit(f"stack_pointer += {diff.to_c()};\n")
out.emit("assert(WITHIN_STACK_BOUNDS());\n") out.emit(f"assert(WITHIN_STACK_BOUNDS());\n")
self.physical_sp = self.logical_sp self.physical_sp = self.logical_sp
self._print(out)
def flush(self, out: CWriter) -> None: def save_variables(self, out: CWriter) -> None:
out.start_line() out.start_line()
var_offset = self.base_offset var_offset = self.base_offset
for var in self.variables: for var in self.variables:
@ -310,10 +317,15 @@ class Stack:
not var.memory_offset and not var.memory_offset and
not var.is_array() not var.is_array()
): ):
self._print(out)
var.memory_offset = var_offset var.memory_offset = var_offset
stack_offset = var_offset - self.physical_sp stack_offset = var_offset - self.physical_sp
Stack._do_emit(out, var.item, stack_offset, self.cast_type, self.extract_bits) Stack._do_emit(out, var.item, stack_offset, self.cast_type, self.extract_bits)
self._print(out)
var_offset = var_offset.push(var.item) var_offset = var_offset.push(var.item)
def flush(self, out: CWriter) -> None:
self.save_variables(out)
self._save_physical_sp(out) self._save_physical_sp(out)
out.start_line() out.start_line()
@ -329,9 +341,13 @@ class Stack:
def as_comment(self) -> str: def as_comment(self) -> str:
variables = ", ".join([v.compact_str() for v in self.variables]) variables = ", ".join([v.compact_str() for v in self.variables])
return ( return (
f"/* Variables: {variables}. base: {self.base_offset.to_c()}. sp: {self.physical_sp.to_c()}. logical_sp: {self.logical_sp.to_c()} */" f"/* Variables=[{variables}]; base={self.base_offset.to_c()}; sp={self.physical_sp.to_c()}; logical_sp={self.logical_sp.to_c()} */"
) )
def _print(self, out: CWriter) -> None:
if PRINT_STACKS:
out.emit(self.as_comment() + "\n")
def copy(self) -> "Stack": def copy(self) -> "Stack":
other = Stack(self.extract_bits, self.cast_type) other = Stack(self.extract_bits, self.cast_type)
other.base_offset = self.base_offset other.base_offset = self.base_offset
@ -358,7 +374,6 @@ class Stack:
diff = other.physical_sp - self.physical_sp diff = other.physical_sp - self.physical_sp
out.start_line() out.start_line()
out.emit(f"stack_pointer += {diff.to_c()};\n") out.emit(f"stack_pointer += {diff.to_c()};\n")
out.emit("assert(WITHIN_STACK_BOUNDS());\n")
self.physical_sp = other.physical_sp self.physical_sp = other.physical_sp
def merge(self, other: "Stack", out: CWriter) -> None: def merge(self, other: "Stack", out: CWriter) -> None:
@ -621,10 +636,10 @@ class Storage:
def as_comment(self) -> str: def as_comment(self) -> str:
stack_comment = self.stack.as_comment() stack_comment = self.stack.as_comment()
next_line = "\n " next_line = "\n "
inputs = ", ".join([var.compact_str() for var in self.inputs]) inputs = ", ".join([var.compact_str() for var in self.inputs])
outputs = ", ".join([var.compact_str() for var in self.outputs]) outputs = ", ".join([var.compact_str() for var in self.outputs])
return f"{stack_comment[:-2]}{next_line}inputs: {inputs}{next_line}outputs: {outputs}*/" return f"{stack_comment[:-2]}{next_line}inputs: {inputs} outputs: {outputs}*/"
def close_inputs(self, out: CWriter) -> None: def close_inputs(self, out: CWriter) -> None:
@ -637,7 +652,7 @@ class Storage:
tmp_defined = True tmp_defined = True
out.emit(f"tmp = {name};\n") out.emit(f"tmp = {name};\n")
out.emit(f"{name} = {overwrite};\n") out.emit(f"{name} = {overwrite};\n")
self.stack.flush(out) self.stack.save_variables(out)
out.emit(f"{close}(tmp);\n") out.emit(f"{close}(tmp);\n")
else: else:
out.emit(f"{close}({name});\n") out.emit(f"{close}({name});\n")
@ -678,7 +693,6 @@ class Storage:
if output is not None: if output is not None:
raise StackError("Cannot call DECREF_INPUTS with more than one live output") raise StackError("Cannot call DECREF_INPUTS with more than one live output")
output = var output = var
self.stack.flush(out)
if output is not None: if output is not None:
if output.is_array(): if output.is_array():
assert len(self.inputs) == 1 assert len(self.inputs) == 1
@ -691,6 +705,7 @@ class Storage:
return return
if var_size(lowest.item) != var_size(output.item): if var_size(lowest.item) != var_size(output.item):
raise StackError("Cannot call DECREF_INPUTS with live output not matching first input size") raise StackError("Cannot call DECREF_INPUTS with live output not matching first input size")
self.stack.flush(out)
lowest.in_local = True lowest.in_local = True
close_variable(lowest, output.name) close_variable(lowest, output.name)
assert lowest.memory_offset is not None assert lowest.memory_offset is not None

View file

@ -9,6 +9,8 @@ from analyzer import (
Analysis, Analysis,
Instruction, Instruction,
Uop, Uop,
Label,
CodeSection,
Part, Part,
analyze_files, analyze_files,
Skip, Skip,
@ -22,9 +24,13 @@ from generators_common import (
write_header, write_header,
type_and_null, type_and_null,
Emitter, Emitter,
TokenIterator,
always_true,
emit_to,
) )
from cwriter import CWriter from cwriter import CWriter
from typing import TextIO from typing import TextIO
from lexer import Token
from stack import Local, Stack, StackError, get_stack_effect, Storage from stack import Local, Stack, StackError, get_stack_effect, Storage
DEFAULT_OUTPUT = ROOT / "Python/generated_cases.c.h" DEFAULT_OUTPUT = ROOT / "Python/generated_cases.c.h"
@ -69,23 +75,23 @@ def write_uop(
stack: Stack, stack: Stack,
inst: Instruction, inst: Instruction,
braces: bool, braces: bool,
) -> tuple[int, Stack]: ) -> tuple[bool, int, Stack]:
# out.emit(stack.as_comment() + "\n") # out.emit(stack.as_comment() + "\n")
if isinstance(uop, Skip): if isinstance(uop, Skip):
entries = "entries" if uop.size > 1 else "entry" entries = "entries" if uop.size > 1 else "entry"
emitter.emit(f"/* Skip {uop.size} cache {entries} */\n") emitter.emit(f"/* Skip {uop.size} cache {entries} */\n")
return (offset + uop.size), stack return True, (offset + uop.size), stack
if isinstance(uop, Flush): if isinstance(uop, Flush):
emitter.emit(f"// flush\n") emitter.emit(f"// flush\n")
stack.flush(emitter.out) stack.flush(emitter.out)
return offset, stack return True, offset, stack
locals: dict[str, Local] = {} locals: dict[str, Local] = {}
emitter.out.start_line() emitter.out.start_line()
if braces: if braces:
emitter.out.emit(f"// {uop.name}\n") emitter.out.emit(f"// {uop.name}\n")
emitter.emit("{\n") emitter.emit("{\n")
stack._print(emitter.out)
storage = Storage.for_uop(stack, uop, emitter.out) storage = Storage.for_uop(stack, uop, emitter.out)
emitter._print_storage(storage)
for cache in uop.caches: for cache in uop.caches:
if cache.name != "unused": if cache.name != "unused":
@ -102,12 +108,12 @@ def write_uop(
emitter.emit(f"(void){cache.name};\n") emitter.emit(f"(void){cache.name};\n")
offset += cache.size offset += cache.size
storage = emitter.emit_tokens(uop, storage, inst, False) reachable, storage = emitter.emit_tokens(uop, storage, inst, False)
if braces: if braces:
emitter.out.start_line() emitter.out.start_line()
emitter.emit("}\n") emitter.emit("}\n")
# emitter.emit(stack.as_comment() + "\n") # emitter.emit(stack.as_comment() + "\n")
return offset, storage.stack return reachable, offset, storage.stack
def uses_this(inst: Instruction) -> bool: def uses_this(inst: Instruction) -> bool:
@ -204,6 +210,9 @@ def generate_tier1_labels(
emitter.emit_tokens(label, storage, None) emitter.emit_tokens(label, storage, None)
emitter.emit("\n\n") emitter.emit("\n\n")
def get_popped(inst: Instruction, analysis: Analysis) -> str:
stack = get_stack_effect(inst)
return (-stack.base_offset).to_c()
def generate_tier1_cases( def generate_tier1_cases(
analysis: Analysis, outfile: TextIO, lines: bool analysis: Analysis, outfile: TextIO, lines: bool
@ -214,6 +223,7 @@ def generate_tier1_cases(
for name, inst in sorted(analysis.instructions.items()): for name, inst in sorted(analysis.instructions.items()):
out.emit("\n") out.emit("\n")
out.emit(f"TARGET({name}) {{\n") out.emit(f"TARGET({name}) {{\n")
popped = get_popped(inst, analysis)
# We need to ifdef it because this breaks platforms # We need to ifdef it because this breaks platforms
# without computed gotos/tail calling. # without computed gotos/tail calling.
out.emit(f"#if Py_TAIL_CALL_INTERP\n") out.emit(f"#if Py_TAIL_CALL_INTERP\n")
@ -251,11 +261,10 @@ def generate_tier1_cases(
for part in inst.parts: for part in inst.parts:
# Only emit braces if more than one uop # Only emit braces if more than one uop
insert_braces = len([p for p in inst.parts if isinstance(p, Uop)]) > 1 insert_braces = len([p for p in inst.parts if isinstance(p, Uop)]) > 1
offset, stack = write_uop(part, emitter, offset, stack, inst, insert_braces) reachable, offset, stack = write_uop(part, emitter, offset, stack, inst, insert_braces)
out.start_line() out.start_line()
if reachable: # type: ignore[possibly-undefined]
stack.flush(out) stack.flush(out)
if not inst.parts[-1].properties.always_exits:
out.emit("DISPATCH();\n") out.emit("DISPATCH();\n")
out.start_line() out.start_line()
out.emit("}") out.emit("}")

View file

@ -154,7 +154,7 @@ def write_uop(uop: Uop, emitter: Emitter, stack: Stack) -> Stack:
cast = f"uint{cache.size*16}_t" cast = f"uint{cache.size*16}_t"
emitter.emit(f"{type}{cache.name} = ({cast})CURRENT_OPERAND{idx}();\n") emitter.emit(f"{type}{cache.name} = ({cast})CURRENT_OPERAND{idx}();\n")
idx += 1 idx += 1
storage = emitter.emit_tokens(uop, storage, None, False) _, storage = emitter.emit_tokens(uop, storage, None, False)
storage.flush(emitter.out) storage.flush(emitter.out)
except StackError as ex: except StackError as ex:
raise analysis_error(ex.args[0], uop.body.open) from None raise analysis_error(ex.args[0], uop.body.open) from None