mirror of
https://github.com/python/cpython.git
synced 2025-11-01 06:01:29 +00:00
GH-119866: Spill the stack around escaping calls. (GH-124392)
* Spill the evaluation around escaping calls in the generated interpreter and JIT. * The code generator tracks live, cached values so they can be saved to memory when needed. * Spills the stack pointer around escaping calls, so that the exact stack is visible to the cycle GC.
This commit is contained in:
parent
cda3b5a576
commit
da071fa3e8
25 changed files with 3841 additions and 2034 deletions
File diff suppressed because it is too large
Load diff
|
|
@ -274,7 +274,6 @@ static void monitor_throw(PyThreadState *tstate,
|
|||
_PyInterpreterFrame *frame,
|
||||
_Py_CODEUNIT *instr);
|
||||
|
||||
static int check_args_iterable(PyThreadState *, PyObject *func, PyObject *vararg);
|
||||
static int get_exception_handler(PyCodeObject *, int, int*, int*, int*);
|
||||
static _PyInterpreterFrame *
|
||||
_PyEvalFramePushAndInit_Ex(PyThreadState *tstate, _PyStackRef func,
|
||||
|
|
@ -394,6 +393,13 @@ const _Py_SpecialMethod _Py_SpecialMethods[] = {
|
|||
}
|
||||
};
|
||||
|
||||
const size_t _Py_FunctionAttributeOffsets[] = {
|
||||
[MAKE_FUNCTION_CLOSURE] = offsetof(PyFunctionObject, func_closure),
|
||||
[MAKE_FUNCTION_ANNOTATIONS] = offsetof(PyFunctionObject, func_annotations),
|
||||
[MAKE_FUNCTION_KWDEFAULTS] = offsetof(PyFunctionObject, func_kwdefaults),
|
||||
[MAKE_FUNCTION_DEFAULTS] = offsetof(PyFunctionObject, func_defaults),
|
||||
[MAKE_FUNCTION_ANNOTATE] = offsetof(PyFunctionObject, func_annotate),
|
||||
};
|
||||
|
||||
// PEP 634: Structural Pattern Matching
|
||||
|
||||
|
|
@ -1036,6 +1042,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int
|
|||
uopcode = next_uop->opcode;
|
||||
#ifdef Py_DEBUG
|
||||
if (lltrace >= 3) {
|
||||
dump_stack(frame, stack_pointer);
|
||||
if (next_uop->opcode == _START_EXECUTOR) {
|
||||
printf("%4d uop: ", 0);
|
||||
}
|
||||
|
|
@ -1043,8 +1050,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int
|
|||
printf("%4d uop: ", (int)(next_uop - current_executor->trace));
|
||||
}
|
||||
_PyUOpPrint(next_uop);
|
||||
printf(" stack_level=%d\n",
|
||||
(int)(stack_pointer - _PyFrame_Stackbase(frame)));
|
||||
printf("\n");
|
||||
}
|
||||
#endif
|
||||
next_uop++;
|
||||
|
|
@ -2920,11 +2926,11 @@ _PyEval_CheckExceptStarTypeValid(PyThreadState *tstate, PyObject* right)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
check_args_iterable(PyThreadState *tstate, PyObject *func, PyObject *args)
|
||||
int
|
||||
_Py_Check_ArgsIterable(PyThreadState *tstate, PyObject *func, PyObject *args)
|
||||
{
|
||||
if (Py_TYPE(args)->tp_iter == NULL && !PySequence_Check(args)) {
|
||||
/* check_args_iterable() may be called with a live exception:
|
||||
/* _Py_Check_ArgsIterable() may be called with a live exception:
|
||||
* clear it to prevent calling _PyObject_FunctionStr() with an
|
||||
* exception set. */
|
||||
_PyErr_Clear(tstate);
|
||||
|
|
|
|||
|
|
@ -108,6 +108,7 @@ do { \
|
|||
/* Do interpreter dispatch accounting for tracing and instrumentation */
|
||||
#define DISPATCH() \
|
||||
{ \
|
||||
assert(frame->stackpointer == NULL); \
|
||||
NEXTOPARG(); \
|
||||
PRE_DISPATCH_GOTO(); \
|
||||
DISPATCH_GOTO(); \
|
||||
|
|
|
|||
935
Python/executor_cases.c.h
generated
935
Python/executor_cases.c.h
generated
File diff suppressed because it is too large
Load diff
1962
Python/generated_cases.c.h
generated
1962
Python/generated_cases.c.h
generated
File diff suppressed because it is too large
Load diff
2
Python/opcode_targets.h
generated
2
Python/opcode_targets.h
generated
|
|
@ -115,7 +115,7 @@ static void *opcode_targets[256] = {
|
|||
&&TARGET_UNPACK_EX,
|
||||
&&TARGET_UNPACK_SEQUENCE,
|
||||
&&TARGET_YIELD_VALUE,
|
||||
&&TARGET__DO_CALL_FUNCTION_EX,
|
||||
&&_unknown_opcode,
|
||||
&&_unknown_opcode,
|
||||
&&_unknown_opcode,
|
||||
&&_unknown_opcode,
|
||||
|
|
|
|||
|
|
@ -182,7 +182,9 @@ dummy_func(void) {
|
|||
res = sym_new_type(ctx, &PyFloat_Type);
|
||||
}
|
||||
}
|
||||
res = sym_new_unknown(ctx);
|
||||
else {
|
||||
res = sym_new_unknown(ctx);
|
||||
}
|
||||
}
|
||||
|
||||
op(_BINARY_OP_ADD_INT, (left, right -- res)) {
|
||||
|
|
@ -448,8 +450,10 @@ dummy_func(void) {
|
|||
top = bottom;
|
||||
}
|
||||
|
||||
op(_SWAP, (bottom, unused[oparg-2], top --
|
||||
top, unused[oparg-2], bottom)) {
|
||||
op(_SWAP, (bottom_in, unused[oparg-2], top_in --
|
||||
top_out, unused[oparg-2], bottom_out)) {
|
||||
bottom_out = bottom_in;
|
||||
top_out = top_in;
|
||||
}
|
||||
|
||||
op(_LOAD_ATTR_INSTANCE_VALUE, (offset/1, owner -- attr, null if (oparg & 1))) {
|
||||
|
|
@ -479,9 +483,7 @@ dummy_func(void) {
|
|||
op(_LOAD_ATTR, (owner -- attr, self_or_null if (oparg & 1))) {
|
||||
(void)owner;
|
||||
attr = sym_new_not_null(ctx);
|
||||
if (oparg & 1) {
|
||||
self_or_null = sym_new_unknown(ctx);
|
||||
}
|
||||
self_or_null = sym_new_unknown(ctx);
|
||||
}
|
||||
|
||||
op(_LOAD_ATTR_MODULE, (index/1, owner -- attr, null if (oparg & 1))) {
|
||||
|
|
@ -570,7 +572,6 @@ dummy_func(void) {
|
|||
|
||||
op(_INIT_CALL_PY_EXACT_ARGS, (callable, self_or_null, args[oparg] -- new_frame: _Py_UOpsAbstractFrame *)) {
|
||||
int argcount = oparg;
|
||||
|
||||
(void)callable;
|
||||
|
||||
PyCodeObject *co = NULL;
|
||||
|
|
@ -647,11 +648,10 @@ dummy_func(void) {
|
|||
}
|
||||
|
||||
op(_RETURN_VALUE, (retval -- res)) {
|
||||
SYNC_SP();
|
||||
SAVE_STACK();
|
||||
ctx->frame->stack_pointer = stack_pointer;
|
||||
frame_pop(ctx);
|
||||
stack_pointer = ctx->frame->stack_pointer;
|
||||
res = retval;
|
||||
|
||||
/* Stack space handling */
|
||||
assert(corresponding_check_stack == NULL);
|
||||
|
|
@ -666,6 +666,8 @@ dummy_func(void) {
|
|||
// might be impossible, but bailing is still safe
|
||||
ctx->done = true;
|
||||
}
|
||||
RELOAD_STACK();
|
||||
res = retval;
|
||||
}
|
||||
|
||||
op(_RETURN_GENERATOR, ( -- res)) {
|
||||
|
|
|
|||
176
Python/optimizer_cases.c.h
generated
176
Python/optimizer_cases.c.h
generated
|
|
@ -93,9 +93,9 @@
|
|||
}
|
||||
|
||||
case _END_SEND: {
|
||||
_Py_UopsSymbol *value;
|
||||
value = sym_new_not_null(ctx);
|
||||
stack_pointer[-2] = value;
|
||||
_Py_UopsSymbol *val;
|
||||
val = sym_new_not_null(ctx);
|
||||
stack_pointer[-2] = val;
|
||||
stack_pointer += -1;
|
||||
assert(WITHIN_STACK_BOUNDS());
|
||||
break;
|
||||
|
|
@ -630,7 +630,6 @@
|
|||
ctx->frame->stack_pointer = stack_pointer;
|
||||
frame_pop(ctx);
|
||||
stack_pointer = ctx->frame->stack_pointer;
|
||||
res = retval;
|
||||
/* Stack space handling */
|
||||
assert(corresponding_check_stack == NULL);
|
||||
assert(co != NULL);
|
||||
|
|
@ -643,6 +642,7 @@
|
|||
// might be impossible, but bailing is still safe
|
||||
ctx->done = true;
|
||||
}
|
||||
res = retval;
|
||||
stack_pointer[0] = res;
|
||||
stack_pointer += 1;
|
||||
assert(WITHIN_STACK_BOUNDS());
|
||||
|
|
@ -832,9 +832,7 @@
|
|||
_Py_UopsSymbol **res;
|
||||
_Py_UopsSymbol *null = NULL;
|
||||
res = &stack_pointer[0];
|
||||
for (int _i = 1; --_i >= 0;) {
|
||||
res[_i] = sym_new_not_null(ctx);
|
||||
}
|
||||
res[0] = sym_new_not_null(ctx);
|
||||
null = sym_new_null(ctx);
|
||||
if (oparg & 1) stack_pointer[1] = null;
|
||||
stack_pointer += 1 + (oparg & 1);
|
||||
|
|
@ -1021,9 +1019,7 @@
|
|||
owner = stack_pointer[-1];
|
||||
(void)owner;
|
||||
attr = sym_new_not_null(ctx);
|
||||
if (oparg & 1) {
|
||||
self_or_null = sym_new_unknown(ctx);
|
||||
}
|
||||
self_or_null = sym_new_unknown(ctx);
|
||||
stack_pointer[-1] = attr;
|
||||
if (oparg & 1) stack_pointer[0] = self_or_null;
|
||||
stack_pointer += (oparg & 1);
|
||||
|
|
@ -1114,11 +1110,17 @@
|
|||
PyModuleObject *mod = (PyModuleObject *)sym_get_const(owner);
|
||||
assert(PyModule_CheckExact(mod));
|
||||
PyObject *dict = mod->md_dict;
|
||||
stack_pointer[-1] = attr;
|
||||
if (oparg & 1) stack_pointer[0] = null;
|
||||
stack_pointer += (oparg & 1);
|
||||
assert(WITHIN_STACK_BOUNDS());
|
||||
PyObject *res = convert_global_to_const(this_instr, dict);
|
||||
if (res != NULL) {
|
||||
this_instr[-1].opcode = _POP_TOP;
|
||||
attr = sym_new_const(ctx, res);
|
||||
}
|
||||
stack_pointer += -(oparg & 1);
|
||||
assert(WITHIN_STACK_BOUNDS());
|
||||
}
|
||||
if (attr == NULL) {
|
||||
/* No conversion made. We don't know what `attr` is. */
|
||||
|
|
@ -1239,7 +1241,11 @@
|
|||
res = sym_new_type(ctx, &PyBool_Type);
|
||||
}
|
||||
else {
|
||||
stack_pointer += -2;
|
||||
assert(WITHIN_STACK_BOUNDS());
|
||||
res = _Py_uop_sym_new_not_null(ctx);
|
||||
stack_pointer += 2;
|
||||
assert(WITHIN_STACK_BOUNDS());
|
||||
}
|
||||
stack_pointer[-2] = res;
|
||||
stack_pointer += -1;
|
||||
|
|
@ -1659,12 +1665,13 @@
|
|||
/* _MONITOR_CALL is not a viable micro-op for tier 2 */
|
||||
|
||||
case _PY_FRAME_GENERAL: {
|
||||
_Py_UopsSymbol **args;
|
||||
_Py_UopsSymbol *self_or_null;
|
||||
_Py_UopsSymbol *callable;
|
||||
_Py_UOpsAbstractFrame *new_frame;
|
||||
self_or_null = stack_pointer[-1 - oparg];
|
||||
callable = stack_pointer[-2 - oparg];
|
||||
stack_pointer += -2 - oparg;
|
||||
assert(WITHIN_STACK_BOUNDS());
|
||||
(void)(self_or_null);
|
||||
(void)(callable);
|
||||
PyCodeObject *co = NULL;
|
||||
|
|
@ -1675,8 +1682,8 @@
|
|||
break;
|
||||
}
|
||||
new_frame = frame_new(ctx, co, 0, NULL, 0);
|
||||
stack_pointer[-2 - oparg] = (_Py_UopsSymbol *)new_frame;
|
||||
stack_pointer += -1 - oparg;
|
||||
stack_pointer[0] = (_Py_UopsSymbol *)new_frame;
|
||||
stack_pointer += 1;
|
||||
assert(WITHIN_STACK_BOUNDS());
|
||||
break;
|
||||
}
|
||||
|
|
@ -1690,14 +1697,12 @@
|
|||
}
|
||||
|
||||
case _EXPAND_METHOD: {
|
||||
_Py_UopsSymbol *method;
|
||||
_Py_UopsSymbol **method;
|
||||
_Py_UopsSymbol **self;
|
||||
method = &stack_pointer[-2 - oparg];
|
||||
self = &stack_pointer[-1 - oparg];
|
||||
method = sym_new_not_null(ctx);
|
||||
for (int _i = 1; --_i >= 0;) {
|
||||
self[_i] = sym_new_not_null(ctx);
|
||||
}
|
||||
stack_pointer[-2 - oparg] = method;
|
||||
method[0] = sym_new_not_null(ctx);
|
||||
self[0] = sym_new_not_null(ctx);
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
@ -1774,6 +1779,8 @@
|
|||
(void)callable;
|
||||
PyCodeObject *co = NULL;
|
||||
assert((this_instr + 2)->opcode == _PUSH_FRAME);
|
||||
stack_pointer += -2 - oparg;
|
||||
assert(WITHIN_STACK_BOUNDS());
|
||||
co = get_code_with_logging((this_instr + 2));
|
||||
if (co == NULL) {
|
||||
ctx->done = true;
|
||||
|
|
@ -1791,8 +1798,8 @@
|
|||
} else {
|
||||
new_frame = frame_new(ctx, co, 0, NULL, 0);
|
||||
}
|
||||
stack_pointer[-2 - oparg] = (_Py_UopsSymbol *)new_frame;
|
||||
stack_pointer += -1 - oparg;
|
||||
stack_pointer[0] = (_Py_UopsSymbol *)new_frame;
|
||||
stack_pointer += 1;
|
||||
assert(WITHIN_STACK_BOUNDS());
|
||||
break;
|
||||
}
|
||||
|
|
@ -1825,9 +1832,11 @@
|
|||
if (first_valid_check_stack == NULL) {
|
||||
first_valid_check_stack = corresponding_check_stack;
|
||||
}
|
||||
else if (corresponding_check_stack) {
|
||||
// delete all but the first valid _CHECK_STACK_SPACE
|
||||
corresponding_check_stack->opcode = _NOP;
|
||||
else {
|
||||
if (corresponding_check_stack) {
|
||||
// delete all but the first valid _CHECK_STACK_SPACE
|
||||
corresponding_check_stack->opcode = _NOP;
|
||||
}
|
||||
}
|
||||
corresponding_check_stack = NULL;
|
||||
break;
|
||||
|
|
@ -2005,6 +2014,24 @@
|
|||
|
||||
/* _INSTRUMENTED_CALL_KW is not a viable micro-op for tier 2 */
|
||||
|
||||
case _MAYBE_EXPAND_METHOD_KW: {
|
||||
_Py_UopsSymbol **func;
|
||||
_Py_UopsSymbol **maybe_self;
|
||||
_Py_UopsSymbol **args;
|
||||
_Py_UopsSymbol *kwnames_out;
|
||||
func = &stack_pointer[-3 - oparg];
|
||||
maybe_self = &stack_pointer[-2 - oparg];
|
||||
args = &stack_pointer[-1 - oparg];
|
||||
func[0] = sym_new_not_null(ctx);
|
||||
maybe_self[0] = sym_new_not_null(ctx);
|
||||
for (int _i = oparg; --_i >= 0;) {
|
||||
args[_i] = sym_new_not_null(ctx);
|
||||
}
|
||||
kwnames_out = sym_new_not_null(ctx);
|
||||
stack_pointer[-1] = kwnames_out;
|
||||
break;
|
||||
}
|
||||
|
||||
/* _DO_CALL_KW is not a viable micro-op for tier 2 */
|
||||
|
||||
case _PY_FRAME_KW: {
|
||||
|
|
@ -2038,17 +2065,12 @@
|
|||
}
|
||||
|
||||
case _EXPAND_METHOD_KW: {
|
||||
_Py_UopsSymbol *method;
|
||||
_Py_UopsSymbol **method;
|
||||
_Py_UopsSymbol **self;
|
||||
_Py_UopsSymbol *kwnames;
|
||||
method = &stack_pointer[-3 - oparg];
|
||||
self = &stack_pointer[-2 - oparg];
|
||||
method = sym_new_not_null(ctx);
|
||||
for (int _i = 1; --_i >= 0;) {
|
||||
self[_i] = sym_new_not_null(ctx);
|
||||
}
|
||||
kwnames = sym_new_not_null(ctx);
|
||||
stack_pointer[-3 - oparg] = method;
|
||||
stack_pointer[-1] = kwnames;
|
||||
method[0] = sym_new_not_null(ctx);
|
||||
self[0] = sym_new_not_null(ctx);
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
@ -2067,7 +2089,17 @@
|
|||
|
||||
/* _INSTRUMENTED_CALL_FUNCTION_EX is not a viable micro-op for tier 2 */
|
||||
|
||||
/* __DO_CALL_FUNCTION_EX is not a viable micro-op for tier 2 */
|
||||
case _MAKE_CALLARGS_A_TUPLE: {
|
||||
_Py_UopsSymbol *tuple;
|
||||
_Py_UopsSymbol *kwargs_out = NULL;
|
||||
tuple = sym_new_not_null(ctx);
|
||||
kwargs_out = sym_new_not_null(ctx);
|
||||
stack_pointer[-1 - (oparg & 1)] = tuple;
|
||||
if (oparg & 1) stack_pointer[-(oparg & 1)] = kwargs_out;
|
||||
break;
|
||||
}
|
||||
|
||||
/* _DO_CALL_FUNCTION_EX is not a viable micro-op for tier 2 */
|
||||
|
||||
case _MAKE_FUNCTION: {
|
||||
_Py_UopsSymbol *func;
|
||||
|
|
@ -2077,9 +2109,9 @@
|
|||
}
|
||||
|
||||
case _SET_FUNCTION_ATTRIBUTE: {
|
||||
_Py_UopsSymbol *func_st;
|
||||
func_st = sym_new_not_null(ctx);
|
||||
stack_pointer[-2] = func_st;
|
||||
_Py_UopsSymbol *func_out;
|
||||
func_out = sym_new_not_null(ctx);
|
||||
stack_pointer[-2] = func_out;
|
||||
stack_pointer += -1;
|
||||
assert(WITHIN_STACK_BOUNDS());
|
||||
break;
|
||||
|
|
@ -2098,14 +2130,14 @@
|
|||
assert(framesize > 0);
|
||||
assert(framesize <= curr_space);
|
||||
curr_space -= framesize;
|
||||
stack_pointer[0] = res;
|
||||
stack_pointer += 1;
|
||||
assert(WITHIN_STACK_BOUNDS());
|
||||
co = get_code(this_instr);
|
||||
if (co == NULL) {
|
||||
// might be impossible, but bailing is still safe
|
||||
ctx->done = true;
|
||||
}
|
||||
stack_pointer[0] = res;
|
||||
stack_pointer += 1;
|
||||
assert(WITHIN_STACK_BOUNDS());
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
@ -2174,7 +2206,9 @@
|
|||
res = sym_new_type(ctx, &PyFloat_Type);
|
||||
}
|
||||
}
|
||||
res = sym_new_unknown(ctx);
|
||||
else {
|
||||
res = sym_new_unknown(ctx);
|
||||
}
|
||||
stack_pointer[-2] = res;
|
||||
stack_pointer += -1;
|
||||
assert(WITHIN_STACK_BOUNDS());
|
||||
|
|
@ -2182,12 +2216,16 @@
|
|||
}
|
||||
|
||||
case _SWAP: {
|
||||
_Py_UopsSymbol *top;
|
||||
_Py_UopsSymbol *bottom;
|
||||
top = stack_pointer[-1];
|
||||
bottom = stack_pointer[-2 - (oparg-2)];
|
||||
stack_pointer[-2 - (oparg-2)] = top;
|
||||
stack_pointer[-1] = bottom;
|
||||
_Py_UopsSymbol *top_in;
|
||||
_Py_UopsSymbol *bottom_in;
|
||||
_Py_UopsSymbol *top_out;
|
||||
_Py_UopsSymbol *bottom_out;
|
||||
top_in = stack_pointer[-1];
|
||||
bottom_in = stack_pointer[-2 - (oparg-2)];
|
||||
bottom_out = bottom_in;
|
||||
top_out = top_in;
|
||||
stack_pointer[-2 - (oparg-2)] = top_out;
|
||||
stack_pointer[-1] = bottom_out;
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
@ -2213,7 +2251,11 @@
|
|||
if (sym_is_const(flag)) {
|
||||
PyObject *value = sym_get_const(flag);
|
||||
assert(value != NULL);
|
||||
stack_pointer += -1;
|
||||
assert(WITHIN_STACK_BOUNDS());
|
||||
eliminate_pop_guard(this_instr, value != Py_True);
|
||||
stack_pointer += 1;
|
||||
assert(WITHIN_STACK_BOUNDS());
|
||||
}
|
||||
stack_pointer += -1;
|
||||
assert(WITHIN_STACK_BOUNDS());
|
||||
|
|
@ -2226,7 +2268,11 @@
|
|||
if (sym_is_const(flag)) {
|
||||
PyObject *value = sym_get_const(flag);
|
||||
assert(value != NULL);
|
||||
stack_pointer += -1;
|
||||
assert(WITHIN_STACK_BOUNDS());
|
||||
eliminate_pop_guard(this_instr, value != Py_False);
|
||||
stack_pointer += 1;
|
||||
assert(WITHIN_STACK_BOUNDS());
|
||||
}
|
||||
stack_pointer += -1;
|
||||
assert(WITHIN_STACK_BOUNDS());
|
||||
|
|
@ -2239,14 +2285,22 @@
|
|||
if (sym_is_const(flag)) {
|
||||
PyObject *value = sym_get_const(flag);
|
||||
assert(value != NULL);
|
||||
stack_pointer += -1;
|
||||
assert(WITHIN_STACK_BOUNDS());
|
||||
eliminate_pop_guard(this_instr, !Py_IsNone(value));
|
||||
}
|
||||
else if (sym_has_type(flag)) {
|
||||
assert(!sym_matches_type(flag, &_PyNone_Type));
|
||||
eliminate_pop_guard(this_instr, true);
|
||||
else {
|
||||
if (sym_has_type(flag)) {
|
||||
assert(!sym_matches_type(flag, &_PyNone_Type));
|
||||
stack_pointer += -1;
|
||||
assert(WITHIN_STACK_BOUNDS());
|
||||
eliminate_pop_guard(this_instr, true);
|
||||
stack_pointer += 1;
|
||||
assert(WITHIN_STACK_BOUNDS());
|
||||
}
|
||||
stack_pointer += -1;
|
||||
assert(WITHIN_STACK_BOUNDS());
|
||||
}
|
||||
stack_pointer += -1;
|
||||
assert(WITHIN_STACK_BOUNDS());
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
@ -2256,14 +2310,22 @@
|
|||
if (sym_is_const(flag)) {
|
||||
PyObject *value = sym_get_const(flag);
|
||||
assert(value != NULL);
|
||||
stack_pointer += -1;
|
||||
assert(WITHIN_STACK_BOUNDS());
|
||||
eliminate_pop_guard(this_instr, Py_IsNone(value));
|
||||
}
|
||||
else if (sym_has_type(flag)) {
|
||||
assert(!sym_matches_type(flag, &_PyNone_Type));
|
||||
eliminate_pop_guard(this_instr, false);
|
||||
else {
|
||||
if (sym_has_type(flag)) {
|
||||
assert(!sym_matches_type(flag, &_PyNone_Type));
|
||||
stack_pointer += -1;
|
||||
assert(WITHIN_STACK_BOUNDS());
|
||||
eliminate_pop_guard(this_instr, false);
|
||||
stack_pointer += 1;
|
||||
assert(WITHIN_STACK_BOUNDS());
|
||||
}
|
||||
stack_pointer += -1;
|
||||
assert(WITHIN_STACK_BOUNDS());
|
||||
}
|
||||
stack_pointer += -1;
|
||||
assert(WITHIN_STACK_BOUNDS());
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue