diff options
author | Mark Shannon <mark@hotpy.org> | 2024-10-07 14:56:39 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-10-07 14:56:39 +0100 |
commit | da071fa3e8e01e0cacf13d632aae0835a2203eb2 (patch) | |
tree | ebd70c16c871dee470785be5aed0bccbb1e3cbaf /Python/bytecodes.c | |
parent | cda3b5a576412a8671bbe4c68bb792ec14f1a4b1 (diff) | |
download | cpython-da071fa3e8e01e0cacf13d632aae0835a2203eb2.tar.gz cpython-da071fa3e8e01e0cacf13d632aae0835a2203eb2.zip |
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.
Diffstat (limited to 'Python/bytecodes.c')
-rw-r--r-- | Python/bytecodes.c | 650 |
1 files changed, 369 insertions, 281 deletions
diff --git a/Python/bytecodes.c b/Python/bytecodes.c index f251b79e00e..a0edf17d747 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -149,7 +149,7 @@ dummy_func( op(_CHECK_PERIODIC, (--)) { _Py_CHECK_EMSCRIPTEN_SIGNALS_PERIODICALLY(); - QSBR_QUIESCENT_STATE(tstate); \ + QSBR_QUIESCENT_STATE(tstate); if (_Py_atomic_load_uintptr_relaxed(&tstate->eval_breaker) & _PY_EVAL_EVENTS_MASK) { int err = _Py_HandlePending(tstate); ERROR_IF(err != 0, error); @@ -207,10 +207,8 @@ dummy_func( } op(_MONITOR_RESUME, (--)) { - _PyFrame_SetStackPointer(frame, stack_pointer); int err = _Py_call_instrumentation( tstate, oparg > 0, frame, this_instr); - stack_pointer = _PyFrame_GetStackPointer(frame); ERROR_IF(err, error); if (frame->instr_ptr != this_instr) { /* Instrumentation has jumped */ @@ -263,6 +261,7 @@ dummy_func( replicate(8) inst(STORE_FAST, (value --)) { SETLOCAL(oparg, value); + DEAD(value); } pseudo(STORE_FAST_MAYBE_NULL, (unused --)) = { @@ -273,6 +272,7 @@ dummy_func( uint32_t oparg1 = oparg >> 4; uint32_t oparg2 = oparg & 15; SETLOCAL(oparg1, value1); + DEAD(value1); value2 = PyStackRef_DUP(GETLOCAL(oparg2)); } @@ -280,7 +280,9 @@ dummy_func( uint32_t oparg1 = oparg >> 4; uint32_t oparg2 = oparg & 15; SETLOCAL(oparg1, value1); + DEAD(value1); SETLOCAL(oparg2, value2); + DEAD(value2); } pure inst(POP_TOP, (value --)) { @@ -305,12 +307,14 @@ dummy_func( DECREF_INPUTS(); } - pure inst(END_SEND, (receiver, value -- value)) { + pure inst(END_SEND, (receiver, value -- val)) { (void)receiver; + val = value; + DEAD(value); PyStackRef_CLOSE(receiver); } - tier1 inst(INSTRUMENTED_END_SEND, (receiver, value -- value)) { + tier1 inst(INSTRUMENTED_END_SEND, (receiver, value -- val)) { PyObject *receiver_o = PyStackRef_AsPyObjectBorrow(receiver); if (PyGen_Check(receiver_o) || PyCoro_CheckExact(receiver_o)) { int err = monitor_stop_iteration(tstate, frame, this_instr, PyStackRef_AsPyObjectBorrow(value)); @@ -318,6 +322,8 @@ dummy_func( ERROR_NO_POP(); } } + val = value; + DEAD(value); PyStackRef_CLOSE(receiver); } @@ -332,6 +338,7 @@ dummy_func( assert(PyStackRef_BoolCheck(value)); res = PyStackRef_Is(value, PyStackRef_False) ? PyStackRef_True : PyStackRef_False; + DEAD(value); } family(TO_BOOL, INLINE_CACHE_ENTRIES_TO_BOOL) = { @@ -375,6 +382,7 @@ dummy_func( STAT_INC(TO_BOOL, hit); if (_PyLong_IsZero((PyLongObject *)value_o)) { assert(_Py_IsImmortalLoose(value_o)); + DEAD(value); res = PyStackRef_False; } else { @@ -394,6 +402,7 @@ dummy_func( inst(TO_BOOL_NONE, (unused/1, unused/2, value -- res)) { // This one is a bit weird, because we expect *some* failures: EXIT_IF(!PyStackRef_Is(value, PyStackRef_None)); + DEAD(value); STAT_INC(TO_BOOL, hit); res = PyStackRef_False; } @@ -404,6 +413,7 @@ dummy_func( STAT_INC(TO_BOOL, hit); if (value_o == &_Py_STR(empty)) { assert(_Py_IsImmortalLoose(value_o)); + DEAD(value); res = PyStackRef_False; } else { @@ -466,6 +476,7 @@ dummy_func( PyObject *res_o = _PyLong_Multiply((PyLongObject *)left_o, (PyLongObject *)right_o); _Py_DECREF_SPECIALIZED(right_o, (destructor)PyObject_Free); _Py_DECREF_SPECIALIZED(left_o, (destructor)PyObject_Free); + INPUTS_DEAD(); ERROR_IF(res_o == NULL, error); res = PyStackRef_FromPyObjectSteal(res_o); } @@ -478,6 +489,7 @@ dummy_func( PyObject *res_o = _PyLong_Add((PyLongObject *)left_o, (PyLongObject *)right_o); _Py_DECREF_SPECIALIZED(right_o, (destructor)PyObject_Free); _Py_DECREF_SPECIALIZED(left_o, (destructor)PyObject_Free); + INPUTS_DEAD(); ERROR_IF(res_o == NULL, error); res = PyStackRef_FromPyObjectSteal(res_o); } @@ -489,7 +501,8 @@ dummy_func( STAT_INC(BINARY_OP, hit); PyObject *res_o = _PyLong_Subtract((PyLongObject *)left_o, (PyLongObject *)right_o); _Py_DECREF_SPECIALIZED(right_o, (destructor)PyObject_Free); - _Py_DECREF_SPECIALIZED(left_o, (destructor)PyObject_Free);; + _Py_DECREF_SPECIALIZED(left_o, (destructor)PyObject_Free); + INPUTS_DEAD(); ERROR_IF(res_o == NULL, error); res = PyStackRef_FromPyObjectSteal(res_o); } @@ -528,6 +541,7 @@ dummy_func( ((PyFloatObject *)right_o)->ob_fval; PyObject *res_o; DECREF_INPUTS_AND_REUSE_FLOAT(left_o, right_o, dres, res_o); + INPUTS_DEAD(); res = PyStackRef_FromPyObjectSteal(res_o); } @@ -541,6 +555,7 @@ dummy_func( ((PyFloatObject *)right_o)->ob_fval; PyObject *res_o; DECREF_INPUTS_AND_REUSE_FLOAT(left_o, right_o, dres, res_o); + INPUTS_DEAD(); res = PyStackRef_FromPyObjectSteal(res_o); } @@ -554,6 +569,7 @@ dummy_func( ((PyFloatObject *)right_o)->ob_fval; PyObject *res_o; DECREF_INPUTS_AND_REUSE_FLOAT(left_o, right_o, dres, res_o); + INPUTS_DEAD(); res = PyStackRef_FromPyObjectSteal(res_o); } @@ -580,6 +596,7 @@ dummy_func( PyObject *res_o = PyUnicode_Concat(left_o, right_o); _Py_DECREF_SPECIALIZED(left_o, _PyUnicode_ExactDealloc); _Py_DECREF_SPECIALIZED(right_o, _PyUnicode_ExactDealloc); + INPUTS_DEAD(); ERROR_IF(res_o == NULL, error); res = PyStackRef_FromPyObjectSteal(res_o); } @@ -620,10 +637,12 @@ dummy_func( */ assert(Py_REFCNT(left_o) >= 2); _Py_DECREF_NO_DEALLOC(left_o); + DEAD(left); PyObject *temp = PyStackRef_AsPyObjectBorrow(*target_local); PyUnicode_Append(&temp, right_o); *target_local = PyStackRef_FromPyObjectSteal(temp); _Py_DECREF_SPECIALIZED(right_o, _PyUnicode_ExactDealloc); + DEAD(right); ERROR_IF(PyStackRef_IsNull(*target_local), error); #if TIER_ONE // The STORE_FAST is already done. This is done here in tier one, @@ -645,6 +664,7 @@ dummy_func( }; specializing op(_SPECIALIZE_BINARY_SUBSCR, (counter/1, container, sub -- container, sub)) { + assert(frame->stackpointer == NULL); #if ENABLE_SPECIALIZATION if (ADAPTIVE_COUNTER_TRIGGERS(counter)) { next_instr = this_instr; @@ -736,6 +756,7 @@ dummy_func( assert(res_o != NULL); Py_INCREF(res_o); _Py_DECREF_SPECIALIZED(sub, (destructor)PyObject_Free); + DEAD(sub_st); PyStackRef_CLOSE(list_st); res = PyStackRef_FromPyObjectSteal(res_o); } @@ -755,6 +776,7 @@ dummy_func( STAT_INC(BINARY_SUBSCR, hit); PyObject *res_o = (PyObject*)&_Py_SINGLETON(strings).ascii[c]; _Py_DECREF_SPECIALIZED(sub, (destructor)PyObject_Free); + DEAD(sub_st); PyStackRef_CLOSE(str_st); res = PyStackRef_FromPyObjectSteal(res_o); } @@ -775,6 +797,7 @@ dummy_func( assert(res_o != NULL); Py_INCREF(res_o); _Py_DECREF_SPECIALIZED(sub, (destructor)PyObject_Free); + DEAD(sub_st); PyStackRef_CLOSE(tuple_st); res = PyStackRef_FromPyObjectSteal(res_o); } @@ -815,9 +838,9 @@ dummy_func( PyHeapTypeObject *ht = (PyHeapTypeObject *)tp; PyObject *getitem = ht->_spec_cache.getitem; new_frame = _PyFrame_PushUnchecked(tstate, PyStackRef_FromPyObjectNew(getitem), 2, frame); - SYNC_SP(); new_frame->localsplus[0] = container; new_frame->localsplus[1] = sub; + INPUTS_DEAD(); frame->return_offset = (uint16_t)(1 + INLINE_CACHE_ENTRIES_BINARY_SUBSCR); } @@ -829,8 +852,9 @@ dummy_func( _PUSH_FRAME; inst(LIST_APPEND, (list, unused[oparg-1], v -- list, unused[oparg-1])) { - ERROR_IF(_PyList_AppendTakeRef((PyListObject *)PyStackRef_AsPyObjectBorrow(list), - PyStackRef_AsPyObjectSteal(v)) < 0, error); + int err = _PyList_AppendTakeRef((PyListObject *)PyStackRef_AsPyObjectBorrow(list), + PyStackRef_AsPyObjectSteal(v)); + ERROR_IF(err < 0, error); } inst(SET_ADD, (set, unused[oparg-1], v -- set, unused[oparg-1])) { @@ -885,6 +909,7 @@ dummy_func( assert(old_value != NULL); Py_DECREF(old_value); _Py_DECREF_SPECIALIZED(sub, (destructor)PyObject_Free); + DEAD(sub_st); PyStackRef_CLOSE(list_st); } @@ -928,25 +953,14 @@ dummy_func( } tier1 inst(RAISE_VARARGS, (args[oparg] -- )) { - PyObject *cause = NULL, *exc = NULL; - switch (oparg) { - case 2: - cause = PyStackRef_AsPyObjectSteal(args[1]); - _Py_FALLTHROUGH; - case 1: - exc = PyStackRef_AsPyObjectSteal(args[0]); - _Py_FALLTHROUGH; - case 0: - if (do_raise(tstate, exc, cause)) { - assert(oparg == 0); - monitor_reraise(tstate, frame, this_instr); - goto exception_unwind; - } - break; - default: - _PyErr_SetString(tstate, PyExc_SystemError, - "bad RAISE_VARARGS oparg"); - break; + assert(oparg < 3); + PyObject *cause = oparg == 2 ? PyStackRef_AsPyObjectSteal(args[1]) : NULL; + PyObject *exc = oparg > 0 ? PyStackRef_AsPyObjectSteal(args[0]) : NULL; + int err = do_raise(tstate, exc, cause); + if (err) { + assert(oparg == 0); + monitor_reraise(tstate, frame, this_instr); + goto exception_unwind; } ERROR_IF(true, error); } @@ -969,17 +983,18 @@ dummy_func( #if TIER_ONE assert(frame != &entry_frame); #endif - SYNC_SP(); - _PyFrame_SetStackPointer(frame, stack_pointer); + _PyStackRef temp = retval; + DEAD(retval); + SAVE_STACK(); assert(EMPTY()); _Py_LeaveRecursiveCallPy(tstate); // GH-99729: We need to unlink the frame *before* clearing it: _PyInterpreterFrame *dying = frame; frame = tstate->current_frame = dying->previous; _PyEval_FrameClearAndPop(tstate, dying); - LOAD_SP(); + RELOAD_STACK(); LOAD_IP(frame->return_offset); - res = retval; + res = temp; LLTRACE_RESUME_FRAME(); } @@ -987,7 +1002,7 @@ dummy_func( int err = _Py_call_instrumentation_arg( tstate, PY_MONITORING_EVENT_PY_RETURN, frame, this_instr, PyStackRef_AsPyObjectBorrow(val)); - if (err) ERROR_NO_POP(); + ERROR_IF(err, error); } macro(INSTRUMENTED_RETURN_VALUE) = @@ -1111,7 +1126,8 @@ dummy_func( JUMPBY(oparg); } else { - ERROR_NO_POP(); + DECREF_INPUTS(); + ERROR_IF(true, error); } } PyStackRef_CLOSE(v); @@ -1127,6 +1143,7 @@ dummy_func( STAT_INC(SEND, hit); gen_frame = &gen->gi_iframe; _PyFrame_StackPush(gen_frame, v); + DEAD(v); gen->gi_frame_state = FRAME_EXECUTING; gen->gi_exc_state.previous_item = tstate->exc_info; tstate->exc_info = &gen->gi_exc_state; @@ -1153,8 +1170,9 @@ dummy_func( assert(FRAME_SUSPENDED_YIELD_FROM == FRAME_SUSPENDED + 1); assert(oparg == 0 || oparg == 1); gen->gi_frame_state = FRAME_SUSPENDED + oparg; - SYNC_SP(); - _PyFrame_SetStackPointer(frame, stack_pointer); + _PyStackRef temp = retval; + DEAD(retval); + SAVE_STACK(); tstate->exc_info = gen->gi_exc_state.previous_item; gen->gi_exc_state.previous_item = NULL; _Py_LeaveRecursiveCallPy(tstate); @@ -1171,19 +1189,19 @@ dummy_func( _PyOpcode_Deopt[frame->instr_ptr->op.code] == INTERPRETER_EXIT || _PyOpcode_Deopt[frame->instr_ptr->op.code] == ENTER_EXECUTOR); #endif + RELOAD_STACK(); LOAD_IP(1 + INLINE_CACHE_ENTRIES_SEND); - LOAD_SP(); - value = retval; + value = temp; LLTRACE_RESUME_FRAME(); } tier1 op(_YIELD_VALUE_EVENT, (val -- val)) { - SAVE_SP(); int err = _Py_call_instrumentation_arg( tstate, PY_MONITORING_EVENT_PY_YIELD, frame, this_instr, PyStackRef_AsPyObjectBorrow(val)); - LOAD_SP(); - if (err) ERROR_NO_POP(); + if (err) { + ERROR_NO_POP(); + } if (frame->instr_ptr != this_instr) { next_instr = frame->instr_ptr; DISPATCH(); @@ -1202,7 +1220,7 @@ dummy_func( } tier1 inst(RERAISE, (values[oparg], exc_st -- values[oparg])) { - PyObject *exc = PyStackRef_AsPyObjectBorrow(exc_st); + PyObject *exc = PyStackRef_AsPyObjectSteal(exc_st); assert(oparg >= 0 && oparg <= 2); if (oparg) { @@ -1213,11 +1231,11 @@ dummy_func( } else { _PyErr_SetString(tstate, PyExc_SystemError, "lasti is not an int"); + Py_DECREF(exc); ERROR_NO_POP(); } } assert(exc && PyExceptionInstance_Check(exc)); - Py_INCREF(exc); _PyErr_SetRaisedException(tstate, exc); monitor_reraise(tstate, frame, this_instr); goto exception_unwind; @@ -1227,7 +1245,8 @@ dummy_func( PyObject *exc = PyStackRef_AsPyObjectBorrow(exc_st); assert(exc && PyExceptionInstance_Check(exc)); - if (PyErr_GivenExceptionMatches(exc, PyExc_StopAsyncIteration)) { + int matches = PyErr_GivenExceptionMatches(exc, PyExc_StopAsyncIteration); + if (matches) { DECREF_INPUTS(); } else { @@ -1245,9 +1264,9 @@ dummy_func( int matches = PyErr_GivenExceptionMatches(exc_value, PyExc_StopIteration); if (matches) { + none = PyStackRef_None; value = PyStackRef_FromPyObjectNew(((PyStopIterationObject *)exc_value)->value); DECREF_INPUTS(); - none = PyStackRef_None; } else { _PyErr_SetRaisedException(tstate, Py_NewRef(exc_value)); @@ -1258,21 +1277,22 @@ dummy_func( inst(LOAD_COMMON_CONSTANT, ( -- value)) { // Keep in sync with _common_constants in opcode.py - switch(oparg) { - case CONSTANT_ASSERTIONERROR: - value = PyStackRef_FromPyObjectImmortal(PyExc_AssertionError); - break; - case CONSTANT_NOTIMPLEMENTEDERROR: - value = PyStackRef_FromPyObjectImmortal(PyExc_NotImplementedError); - break; - default: - Py_FatalError("bad LOAD_COMMON_CONSTANT oparg"); + // If we ever have more than two constants, use a lookup table + PyObject *val; + if (oparg == CONSTANT_ASSERTIONERROR) { + val = PyExc_AssertionError; + } + else { + assert(oparg == CONSTANT_NOTIMPLEMENTEDERROR); + val = PyExc_NotImplementedError; } + value = PyStackRef_FromPyObjectImmortal(val); } inst(LOAD_BUILD_CLASS, ( -- bc)) { PyObject *bc_o; - ERROR_IF(PyMapping_GetOptionalItem(BUILTINS(), &_Py_ID(__build_class__), &bc_o) < 0, error); + int err = PyMapping_GetOptionalItem(BUILTINS(), &_Py_ID(__build_class__), &bc_o); + ERROR_IF(err < 0, error); if (bc_o == NULL) { _PyErr_SetString(tstate, PyExc_NameError, "__build_class__ not found"); @@ -1291,10 +1311,12 @@ dummy_func( DECREF_INPUTS(); ERROR_IF(true, error); } - if (PyDict_CheckExact(ns)) + if (PyDict_CheckExact(ns)) { err = PyDict_SetItem(ns, name, PyStackRef_AsPyObjectBorrow(v)); - else + } + else { err = PyObject_SetItem(ns, name, PyStackRef_AsPyObjectBorrow(v)); + } DECREF_INPUTS(); ERROR_IF(err, error); } @@ -1460,9 +1482,8 @@ dummy_func( PyObject *name = GETITEM(FRAME_CO_NAMES, oparg); PyObject *v_o; int err = PyMapping_GetOptionalItem(PyStackRef_AsPyObjectBorrow(mod_or_class_dict), name, &v_o); - if (err < 0) { - ERROR_NO_POP(); - } + DECREF_INPUTS(); + ERROR_IF(err < 0, error); if (v_o == NULL) { if (PyDict_CheckExact(GLOBALS()) && PyDict_CheckExact(BUILTINS())) @@ -1483,10 +1504,12 @@ dummy_func( else { /* Slow-path if globals or builtins is not a dict */ /* namespace 1: globals */ - ERROR_IF(PyMapping_GetOptionalItem(GLOBALS(), name, &v_o) < 0, error); + int err = PyMapping_GetOptionalItem(GLOBALS(), name, &v_o); + ERROR_IF(err < 0, error); if (v_o == NULL) { /* namespace 2: builtins */ - ERROR_IF(PyMapping_GetOptionalItem(BUILTINS(), name, &v_o) < 0, error); + int err = PyMapping_GetOptionalItem(BUILTINS(), name, &v_o); + ERROR_IF(err < 0, error); if (v_o == NULL) { _PyEval_FormatExcCheckArg( tstate, PyExc_NameError, @@ -1496,7 +1519,6 @@ dummy_func( } } } - DECREF_INPUTS(); v = PyStackRef_FromPyObjectSteal(v_o); } @@ -1691,12 +1713,14 @@ dummy_func( inst(BUILD_TUPLE, (values[oparg] -- tup)) { PyObject *tup_o = _PyTuple_FromStackRefSteal(values, oparg); + INPUTS_DEAD(); ERROR_IF(tup_o == NULL, error); tup = PyStackRef_FromPyObjectSteal(tup_o); } inst(BUILD_LIST, (values[oparg] -- list)) { PyObject *list_o = _PyList_FromStackRefSteal(values, oparg); + INPUTS_DEAD(); ERROR_IF(list_o == NULL, error); list = PyStackRef_FromPyObjectSteal(list_o); } @@ -1743,6 +1767,7 @@ dummy_func( } PyStackRef_CLOSE(values[i]); } + DEAD(values); if (err != 0) { Py_DECREF(set_o); ERROR_IF(true, error); @@ -1767,7 +1792,6 @@ dummy_func( } inst(SETUP_ANNOTATIONS, (--)) { - int err; PyObject *ann_dict; if (LOCALS() == NULL) { _PyErr_Format(tstate, PyExc_SystemError, @@ -1775,7 +1799,8 @@ dummy_func( ERROR_IF(true, error); } /* check if __annotations__ in locals()... */ - ERROR_IF(PyMapping_GetOptionalItem(LOCALS(), &_Py_ID(__annotations__), &ann_dict) < 0, error); + int err = PyMapping_GetOptionalItem(LOCALS(), &_Py_ID(__annotations__), &ann_dict); + ERROR_IF(err < 0, error); if (ann_dict == NULL) { ann_dict = PyDict_New(); ERROR_IF(ann_dict == NULL, error); @@ -1869,7 +1894,10 @@ dummy_func( int err = _Py_call_instrumentation_2args( tstate, PY_MONITORING_EVENT_CALL, frame, this_instr, global_super, arg); - ERROR_IF(err, error); + if (err) { + DECREF_INPUTS(); + ERROR_IF(true, error); + } } // we make no attempt to optimize here; specializations should // handle any case whose performance we care about @@ -1940,6 +1968,7 @@ dummy_func( } if (method_found) { self_or_null = self_st; // transfer ownership + DEAD(self_st); } else { PyStackRef_CLOSE(self_st); self_or_null = PyStackRef_NULL; @@ -1991,6 +2020,7 @@ dummy_func( */ assert(attr_o != NULL); // No errors on this branch self_or_null = owner; // Transfer ownership + DEAD(owner); } else { /* meth is not an unbound method (but a regular attr, or @@ -2009,6 +2039,8 @@ dummy_func( attr_o = PyObject_GetAttr(PyStackRef_AsPyObjectBorrow(owner), name); DECREF_INPUTS(); ERROR_IF(attr_o == NULL, error); + /* We need to define self_or_null on all paths */ + self_or_null = PyStackRef_NULL; } attr = PyStackRef_FromPyObjectSteal(attr_o); } @@ -2172,6 +2204,7 @@ dummy_func( STAT_INC(LOAD_ATTR, hit); new_frame = _PyFrame_PushUnchecked(tstate, PyStackRef_FromPyObjectNew(fget), 1, frame); new_frame->localsplus[0] = owner; + DEAD(owner); } macro(LOAD_ATTR_PROPERTY) = @@ -2206,6 +2239,7 @@ dummy_func( // Manipulate stack directly because we exit with DISPATCH_INLINED(). STACK_SHRINK(1); new_frame->localsplus[0] = owner; + DEAD(owner); new_frame->localsplus[1] = PyStackRef_FromPyObjectNew(name); frame->return_offset = (uint16_t)(next_instr - this_instr); DISPATCH_INLINED(new_frame); @@ -2351,7 +2385,9 @@ dummy_func( // 1 if NaN, 2 if <, 4 if >, 8 if ==; this matches low four bits of the oparg int sign_ish = COMPARISON_BIT(dleft, dright); _Py_DECREF_SPECIALIZED(left_o, _PyFloat_ExactDealloc); + DEAD(left); _Py_DECREF_SPECIALIZED(right_o, _PyFloat_ExactDealloc); + DEAD(right); res = (sign_ish & oparg) ? PyStackRef_True : PyStackRef_False; // It's always a bool, so we don't care about oparg & 16. } @@ -2371,7 +2407,9 @@ dummy_func( // 2 if <, 4 if >, 8 if ==; this matches the low 4 bits of the oparg int sign_ish = COMPARISON_BIT(ileft, iright); _Py_DECREF_SPECIALIZED(left_o, (destructor)PyObject_Free); + DEAD(left); _Py_DECREF_SPECIALIZED(right_o, (destructor)PyObject_Free); + DEAD(right); res = (sign_ish & oparg) ? PyStackRef_True : PyStackRef_False; // It's always a bool, so we don't care about oparg & 16. } @@ -2385,7 +2423,9 @@ dummy_func( int eq = _PyUnicode_Equal(left_o, right_o); assert((oparg >> 5) == Py_EQ || (oparg >> 5) == Py_NE); _Py_DECREF_SPECIALIZED(left_o, _PyUnicode_ExactDealloc); + DEAD(left); _Py_DECREF_SPECIALIZED(right_o, _PyUnicode_ExactDealloc); + DEAD(right); assert(eq == 0 || eq == 1); assert((oparg & 0xf) == COMPARISON_NOT_EQUALS || (oparg & 0xf) == COMPARISON_EQUALS); assert(COMPARISON_NOT_EQUALS + 1 == COMPARISON_EQUALS); @@ -2607,6 +2647,7 @@ dummy_func( replaced op(_POP_JUMP_IF_FALSE, (cond -- )) { assert(PyStackRef_BoolCheck(cond)); int flag = PyStackRef_Is(cond, PyStackRef_False); + DEAD(cond); #if ENABLE_SPECIALIZATION this_instr[1].cache = (this_instr[1].cache << 1) | flag; #endif @@ -2616,6 +2657,7 @@ dummy_func( replaced op(_POP_JUMP_IF_TRUE, (cond -- )) { assert(PyStackRef_BoolCheck(cond)); int flag = PyStackRef_Is(cond, PyStackRef_True); + DEAD(cond); #if ENABLE_SPECIALIZATION this_instr[1].cache = (this_instr[1].cache << 1) | flag; #endif @@ -2625,6 +2667,7 @@ dummy_func( op(_IS_NONE, (value -- b)) { if (PyStackRef_Is(value, PyStackRef_None)) { b = PyStackRef_True; + DEAD(value); } else { b = PyStackRef_False; @@ -2716,13 +2759,16 @@ dummy_func( ERROR_NO_POP(); } iter = iterable; + DEAD(iterable); } else if (PyGen_CheckExact(iterable_o)) { iter = iterable; + DEAD(iterable); } else { /* `iterable` is not a generator. */ iter = PyStackRef_FromPyObjectSteal(PyObject_GetIter(iterable_o)); + DEAD(iterable); if (PyStackRef_IsNull(iter)) { ERROR_NO_POP(); } @@ -2760,7 +2806,6 @@ dummy_func( PyObject *iter_o = PyStackRef_AsPyObjectBorrow(iter); PyObject *next_o = (*Py_TYPE(iter_o)->tp_iternext)(iter_o); if (next_o == NULL) { - next = PyStackRef_NULL; if (_PyErr_Occurred(tstate)) { int matches = _PyErr_ExceptionMatches(tstate, PyExc_StopIteration); if (!matches) { @@ -3076,7 +3121,7 @@ dummy_func( NOP, }; - inst(PUSH_EXC_INFO, (new_exc -- prev_exc, new_exc)) { + inst(PUSH_EXC_INFO, (exc -- prev_exc, new_exc)) { _PyErr_StackItem *exc_info = tstate->exc_info; if (exc_info->exc_value != NULL) { @@ -3085,8 +3130,10 @@ dummy_func( else { prev_exc = PyStackRef_None; } - assert(PyStackRef_ExceptionInstanceCheck(new_exc)); - exc_info->exc_value = PyStackRef_AsPyObjectNew(new_exc); + assert(PyStackRef_ExceptionInstanceCheck(exc)); + exc_info->exc_value = PyStackRef_AsPyObjectNew(exc); + new_exc = exc; + DEAD(exc); } op(_GUARD_DORV_VALUES_INST_ATTR_FROM_DICT, (owner -- owner)) { @@ -3109,6 +3156,7 @@ dummy_func( assert(_PyType_HasFeature(Py_TYPE(descr), Py_TPFLAGS_METHOD_DESCRIPTOR)); attr = PyStackRef_FromPyObjectNew(descr); self = owner; + DEAD(owner); } macro(LOAD_ATTR_METHOD_WITH_VALUES) = @@ -3126,6 +3174,7 @@ dummy_func( assert(_PyType_HasFeature(Py_TYPE(descr), Py_TPFLAGS_METHOD_DESCRIPTOR)); attr = PyStackRef_FromPyObjectNew(descr); self = owner; + DEAD(owner); } macro(LOAD_ATTR_METHOD_NO_DICT) = @@ -3178,6 +3227,7 @@ dummy_func( assert(_PyType_HasFeature(Py_TYPE(descr), Py_TPFLAGS_METHOD_DESCRIPTOR)); attr = PyStackRef_FromPyObjectNew(descr); self = owner; + DEAD(owner); } macro(LOAD_ATTR_METHOD_LAZY_DICT) = @@ -3212,11 +3262,11 @@ dummy_func( CALL_NON_PY_GENERAL, }; - specializing op(_SPECIALIZE_CALL, (counter/1, callable, self_or_null[1], args[oparg] -- callable, self_or_null[1], args[oparg])) { + specializing op(_SPECIALIZE_CALL, (counter/1, callable[1], self_or_null[1], args[oparg] -- callable[1], self_or_null[1], args[oparg])) { #if ENABLE_SPECIALIZATION if (ADAPTIVE_COUNTER_TRIGGERS(counter)) { next_instr = this_instr; - _Py_Specialize_Call(callable, next_instr, oparg + !PyStackRef_IsNull(self_or_null[0])); + _Py_Specialize_Call(callable[0], next_instr, oparg + !PyStackRef_IsNull(self_or_null[0])); DISPATCH_SAME_OPARG(); } OPCODE_DEFERRED_INC(CALL); @@ -3224,23 +3274,21 @@ dummy_func( #endif /* ENABLE_SPECIALIZATION */ } - op(_MAYBE_EXPAND_METHOD, (callable, self_or_null[1], args[oparg] -- func, maybe_self[1], args[oparg])) { - if (PyStackRef_TYPE(callable) == &PyMethod_Type && PyStackRef_IsNull(self_or_null[0])) { - PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable); + op(_MAYBE_EXPAND_METHOD, (callable[1], self_or_null[1], args[oparg] -- func[1], maybe_self[1], args[oparg])) { + if (PyStackRef_TYPE(callable[0]) == &PyMethod_Type && PyStackRef_IsNull(self_or_null[0])) { + PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable[0]); PyObject *self = ((PyMethodObject *)callable_o)->im_self; maybe_self[0] = PyStackRef_FromPyObjectNew(self); PyObject *method = ((PyMethodObject *)callable_o)->im_func; - func = PyStackRef_FromPyObjectNew(method); - PyStackRef_CLOSE(callable); - } - else { - func = callable; + _PyStackRef temp = callable[0]; + func[0] = PyStackRef_FromPyObjectNew(method); + PyStackRef_CLOSE(temp); } } // When calling Python, inline the call using DISPATCH_INLINED(). - op(_DO_CALL, (callable, self_or_null[1], args[oparg] -- res)) { - PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable); + op(_DO_CALL, (callable[1], self_or_null[1], args[oparg] -- res)) { + PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable[0]); // oparg counts all of the args, but *not* self: int total_args = oparg; @@ -3256,11 +3304,11 @@ dummy_func( int code_flags = ((PyCodeObject*)PyFunction_GET_CODE(callable_o))->co_flags; PyObject *locals = code_flags & CO_OPTIMIZED ? NULL : Py_NewRef(PyFunction_GET_GLOBALS(callable_o)); _PyInterpreterFrame *new_frame = _PyEvalFramePushAndInit( - tstate, callable, locals, + tstate, callable[0], locals, args, total_args, NULL, frame ); // Manipulate stack directly since we leave using DISPATCH_INLINED(). - STACK_SHRINK(oparg + 2); + SYNC_SP(); // The frame has stolen all the arguments from the stack, // so there is no need to clean them up. if (new_frame == NULL) { @@ -3272,10 +3320,11 @@ dummy_func( /* Callable is not a normal Python function */ STACKREFS_TO_PYOBJECTS(args, total_args, args_o); if (CONVERSION_FAILED(args_o)) { - PyStackRef_CLOSE(callable); + PyStackRef_CLOSE(callable[0]); for (int i = 0; i < total_args; i++) { PyStackRef_CLOSE(args[i]); } + DEAD(self_or_null); ERROR_IF(true, error); } PyObject *res_o = PyObject_Vectorcall( @@ -3301,17 +3350,18 @@ dummy_func( } } assert((res_o != NULL) ^ (_PyErr_Occurred(tstate) != NULL)); - PyStackRef_CLOSE(callable); + PyStackRef_CLOSE(callable[0]); for (int i = 0; i < total_args; i++) { PyStackRef_CLOSE(args[i]); } + DEAD(self_or_null); ERROR_IF(res_o == NULL, error); res = PyStackRef_FromPyObjectSteal(res_o); } - op(_MONITOR_CALL, (func, maybe_self[1], args[oparg] -- func, maybe_self[1], args[oparg])) { + op(_MONITOR_CALL, (func[1], maybe_self[1], args[oparg] -- func[1], maybe_self[1], args[oparg])) { int is_meth = !PyStackRef_IsNull(maybe_self[0]); - PyObject *function = PyStackRef_AsPyObjectBorrow(func); + PyObject *function = PyStackRef_AsPyObjectBorrow(func[0]); PyObject *arg0; if (is_meth) { arg0 = PyStackRef_AsPyObjectBorrow(maybe_self[0]); @@ -3322,6 +3372,7 @@ dummy_func( else { arg0 = &_PyInstrumentation_MISSING; } + SYNC_SP(); int err = _Py_call_instrumentation_2args( tstate, PY_MONITORING_EVENT_CALL, frame, this_instr, function, arg0 @@ -3332,8 +3383,8 @@ dummy_func( macro(CALL) = _SPECIALIZE_CALL + unused/2 + _MAYBE_EXPAND_METHOD + _DO_CALL + _CHECK_PERIODIC; macro(INSTRUMENTED_CALL) = unused/3 + _MAYBE_EXPAND_METHOD + _MONITOR_CALL + _DO_CALL + _CHECK_PERIODIC; - op(_PY_FRAME_GENERAL, (callable, self_or_null[1], args[oparg] -- new_frame: _PyInterpreterFrame*)) { - PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable); + op(_PY_FRAME_GENERAL, (callable[1], self_or_null[1], args[oparg] -- new_frame: _PyInterpreterFrame*)) { + PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable[0]); // oparg counts all of the args, but *not* self: int total_args = oparg; @@ -3344,20 +3395,21 @@ dummy_func( assert(Py_TYPE(callable_o) == &PyFunction_Type); int code_flags = ((PyCodeObject*)PyFunction_GET_CODE(callable_o))->co_flags; PyObject *locals = code_flags & CO_OPTIMIZED ? NULL : Py_NewRef(PyFunction_GET_GLOBALS(callable_o)); - new_frame = _PyEvalFramePushAndInit( - tstate, callable, locals, + _PyInterpreterFrame *temp = _PyEvalFramePushAndInit( + tstate, callable[0], locals, args, total_args, NULL, frame ); - // The frame has stolen all the arguments from the stack, - // so there is no need to clean them up. + // The frame has stolen all the arguments from the stack. + INPUTS_DEAD(); SYNC_SP(); - if (new_frame == NULL) { + if (temp == NULL) { ERROR_NO_POP(); } + new_frame = temp; } - op(_CHECK_FUNCTION_VERSION, (func_version/2, callable, self_or_null[1], unused[oparg] -- callable, self_or_null[1], unused[oparg])) { - PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable); + op(_CHECK_FUNCTION_VERSION, (func_version/2, callable[1], self_or_null[1], unused[oparg] -- callable[1], self_or_null[1], unused[oparg])) { + PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable[0]); EXIT_IF(!PyFunction_Check(callable_o)); PyFunctionObject *func = (PyFunctionObject *)callable_o; EXIT_IF(func->func_version != func_version); @@ -3371,8 +3423,8 @@ dummy_func( _SAVE_RETURN_OFFSET + _PUSH_FRAME; - op(_CHECK_METHOD_VERSION, (func_version/2, callable, null[1], unused[oparg] -- callable, null[1], unused[oparg])) { - PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable); + op(_CHECK_METHOD_VERSION, (func_version/2, callable[1], null[1], unused[oparg] -- callable[1], null[1], unused[oparg])) { + PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable[0]); EXIT_IF(Py_TYPE(callable_o) != &PyMethod_Type); PyObject *func = ((PyMethodObject *)callable_o)->im_func; @@ -3381,15 +3433,16 @@ dummy_func( EXIT_IF(!PyStackRef_IsNull(null[0])); } - op(_EXPAND_METHOD, (callable, null[1], unused[oparg] -- method, self[1], unused[oparg])) { - PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable); - + op(_EXPAND_METHOD, (callable[1], null[1], unused[oparg] -- method[1], self[1], unused[oparg])) { + PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable[0]); assert(PyStackRef_IsNull(null[0])); + DEAD(null); assert(Py_TYPE(callable_o) == &PyMethod_Type); self[0] = PyStackRef_FromPyObjectNew(((PyMethodObject *)callable_o)->im_self); - method = PyStackRef_FromPyObjectNew(((PyMethodObject *)callable_o)->im_func); - assert(PyStackRef_FunctionCheck(method)); - PyStackRef_CLOSE(callable); + _PyStackRef temp = callable[0]; + method[0] = PyStackRef_FromPyObjectNew(((PyMethodObject *)callable_o)->im_func); + assert(PyStackRef_FunctionCheck(method[0])); + PyStackRef_CLOSE(temp); } macro(CALL_BOUND_METHOD_GENERAL) = @@ -3402,17 +3455,17 @@ dummy_func( _SAVE_RETURN_OFFSET + _PUSH_FRAME; - op(_CHECK_IS_NOT_PY_CALLABLE, (callable, unused[1], unused[oparg] -- callable, unused[1], unused[oparg])) { - PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable); + op(_CHECK_IS_NOT_PY_CALLABLE, (callable[1], unused[1], unused[oparg] -- callable[1], unused[1], unused[oparg])) { + PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable[0]); EXIT_IF(PyFunction_Check(callable_o)); EXIT_IF(Py_TYPE(callable_o) == &PyMethod_Type); } - op(_CALL_NON_PY_GENERAL, (callable, self_or_null[1], args[oparg] -- res)) { + op(_CALL_NON_PY_GENERAL, (callable[1], self_or_null[1], args[oparg] -- res)) { #if TIER_ONE assert(opcode != INSTRUMENTED_CALL); #endif - PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable); + PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable[0]); int total_args = oparg; if (!PyStackRef_IsNull(self_or_null[0])) { @@ -3431,10 +3484,11 @@ dummy_func( NULL); STACKREFS_TO_PYOBJECTS_CLEANUP(args_o); assert((res_o != NULL) ^ (_PyErr_Occurred(tstate) != NULL)); - PyStackRef_CLOSE(callable); + PyStackRef_CLOSE(callable[0]); for (int i = 0; i < total_args; i++) { PyStackRef_CLOSE(args[i]); } + DEAD(self_or_null); ERROR_IF(res_o == NULL, error); res = PyStackRef_FromPyObjectSteal(res_o); } @@ -3446,59 +3500,64 @@ dummy_func( _CALL_NON_PY_GENERAL + _CHECK_PERIODIC; - op(_CHECK_CALL_BOUND_METHOD_EXACT_ARGS, (callable, null[1], unused[oparg] -- callable, null[1], unused[oparg])) { + op(_CHECK_CALL_BOUND_METHOD_EXACT_ARGS, (callable[1], null[1], unused[oparg] -- callable[1], null[1], unused[oparg])) { EXIT_IF(!PyStackRef_IsNull(null[0])); - EXIT_IF(Py_TYPE(PyStackRef_AsPyObjectBorrow(callable)) != &PyMethod_Type); + EXIT_IF(Py_TYPE(PyStackRef_AsPyObjectBorrow(callable[0])) != &PyMethod_Type); } - op(_INIT_CALL_BOUND_METHOD_EXACT_ARGS, (callable, null[1], unused[oparg] -- func, self[1], unused[oparg])) { - PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable); + op(_INIT_CALL_BOUND_METHOD_EXACT_ARGS, (callable[1], null[1], unused[oparg] -- func[1], self[1], unused[oparg])) { + DEAD(null); + PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable[0]); STAT_INC(CALL, hit); self[0] = PyStackRef_FromPyObjectNew(((PyMethodObject *)callable_o)->im_self); - func = PyStackRef_FromPyObjectNew(((PyMethodObject *)callable_o)->im_func); - PyStackRef_CLOSE(callable); + _PyStackRef temp = callable[0]; + func[0] = PyStackRef_FromPyObjectNew(((PyMethodObject *)callable_o)->im_func); + PyStackRef_CLOSE(temp); } op(_CHECK_PEP_523, (--)) { DEOPT_IF(tstate->interp->eval_frame); } - op(_CHECK_FUNCTION_EXACT_ARGS, (callable, self_or_null[1], unused[oparg] -- callable, self_or_null[1], unused[oparg])) { - PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable); + op(_CHECK_FUNCTION_EXACT_ARGS, (callable[1], self_or_null[1], unused[oparg] -- callable[1], self_or_null[1], unused[oparg])) { + PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable[0]); assert(PyFunction_Check(callable_o)); PyFunctionObject *func = (PyFunctionObject *)callable_o; PyCodeObject *code = (PyCodeObject *)func->func_code; EXIT_IF(code->co_argcount != oparg + (!PyStackRef_IsNull(self_or_null[0]))); } - op(_CHECK_STACK_SPACE, (callable, self_or_null[1], unused[oparg] -- callable, self_or_null[1], unused[oparg])) { - PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable); + op(_CHECK_STACK_SPACE, (callable[1], self_or_null[1], unused[oparg] -- callable[1], self_or_null[1], unused[oparg])) { + PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable[0]); PyFunctionObject *func = (PyFunctionObject *)callable_o; PyCodeObject *code = (PyCodeObject *)func->func_code; DEOPT_IF(!_PyThreadState_HasStackSpace(tstate, code->co_framesize)); DEOPT_IF(tstate->py_recursion_remaining <= 1); } - replicate(5) pure op(_INIT_CALL_PY_EXACT_ARGS, (callable, self_or_null[1], args[oparg] -- new_frame: _PyInterpreterFrame*)) { + replicate(5) pure op(_INIT_CALL_PY_EXACT_ARGS, (callable[1], self_or_null[1], args[oparg] -- new_frame: _PyInterpreterFrame*)) { int has_self = !PyStackRef_IsNull(self_or_null[0]); STAT_INC(CALL, hit); - new_frame = _PyFrame_PushUnchecked(tstate, callable, oparg + has_self, frame); + new_frame = _PyFrame_PushUnchecked(tstate, callable[0], oparg + has_self, frame); _PyStackRef *first_non_self_local = new_frame->localsplus + has_self; new_frame->localsplus[0] = self_or_null[0]; for (int i = 0; i < oparg; i++) { first_non_self_local[i] = args[i]; } + INPUTS_DEAD(); } op(_PUSH_FRAME, (new_frame: _PyInterpreterFrame* -- )) { // Write it out explicitly because it's subtly different. // Eventually this should be the only occurrence of this code. assert(tstate->interp->eval_frame == NULL); + _PyInterpreterFrame *temp = new_frame; + DEAD(new_frame); SYNC_SP(); _PyFrame_SetStackPointer(frame, stack_pointer); assert(new_frame->previous == frame || new_frame->previous->previous == frame); CALL_STAT_INC(inlined_py_calls); - frame = tstate->current_frame = new_frame; + frame = tstate->current_frame = temp; tstate->py_recursion_remaining--; LOAD_SP(); LOAD_IP(0); @@ -3534,7 +3593,9 @@ dummy_func( assert(oparg == 1); DEOPT_IF(!PyStackRef_IsNull(null)); + DEAD(null); DEOPT_IF(callable_o != (PyObject *)&PyType_Type); + DEAD(callable); STAT_INC(CALL, hit); res = PyStackRef_FromPyObjectSteal(Py_NewRef(Py_TYPE(arg_o))); PyStackRef_CLOSE(arg); @@ -3549,6 +3610,8 @@ dummy_func( DEOPT_IF(callable_o != (PyObject *)&PyUnicode_Type); STAT_INC(CALL, hit); res = PyStackRef_FromPyObjectSteal(PyObject_Str(arg_o)); + DEAD(null); + DEAD(callable); PyStackRef_CLOSE(arg); ERROR_IF(PyStackRef_IsNull(res), error); } @@ -3568,6 +3631,8 @@ dummy_func( DEOPT_IF(callable_o != (PyObject *)&PyTuple_Type); STAT_INC(CALL, hit); res = PyStackRef_FromPyObjectSteal(PySequence_Tuple(arg_o)); + DEAD(null); + DEAD(callable); PyStackRef_CLOSE(arg); ERROR_IF(PyStackRef_IsNull(res), error); } @@ -3578,9 +3643,9 @@ dummy_func( _CALL_TUPLE_1 + _CHECK_PERIODIC; - op(_CHECK_AND_ALLOCATE_OBJECT, (type_version/2, callable, null, args[oparg] -- self, init, args[oparg])) { - PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable); - DEOPT_IF(!PyStackRef_IsNull(null)); + op(_CHECK_AND_ALLOCATE_OBJECT, (type_version/2, callable[1], null[1], args[oparg] -- init[1], self[1], args[oparg])) { + PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable[0]); + DEOPT_IF(!PyStackRef_IsNull(null[0])); DEOPT_IF(!PyType_Check(callable_o)); PyTypeObject *tp = (PyTypeObject *)callable_o; DEOPT_IF(tp->tp_version_tag != type_version); @@ -3590,23 +3655,26 @@ dummy_func( PyCodeObject *code = (PyCodeObject *)init_func->func_code; DEOPT_IF(!_PyThreadState_HasStackSpace(tstate, code->co_framesize + _Py_InitCleanup.co_framesize)); STAT_INC(CALL, hit); - self = PyStackRef_FromPyObjectSteal(_PyType_NewManagedObject(tp)); - if (PyStackRef_IsNull(self)) { + PyObject *self_o = _PyType_NewManagedObject(tp); + if (self_o == NULL) { ERROR_NO_POP(); } - PyStackRef_CLOSE(callable); - init = PyStackRef_FromPyObjectNew(init_func); + self[0] = PyStackRef_FromPyObjectSteal(self_o); + _PyStackRef temp = callable[0]; + init[0] = PyStackRef_FromPyObjectNew(init_func); + PyStackRef_CLOSE(temp); } - op(_CREATE_INIT_FRAME, (self, init, args[oparg] -- init_frame: _PyInterpreterFrame *)) { + op(_CREATE_INIT_FRAME, (init[1], self[1], args[oparg] -- init_frame: _PyInterpreterFrame *)) { _PyInterpreterFrame *shim = _PyFrame_PushTrampolineUnchecked( tstate, (PyCodeObject *)&_Py_InitCleanup, 1, frame); assert(_PyCode_CODE(_PyFrame_GetCode(shim))[0].op.code == EXIT_INIT_CHECK); /* Push self onto stack of shim */ - shim->localsplus[0] = PyStackRef_DUP(self); - args[-1] = self; + shim->localsplus[0] = PyStackRef_DUP(self[0]); + DEAD(init); + DEAD(self); init_frame = _PyEvalFramePushAndInit( - tstate, init, NULL, args-1, oparg+1, NULL, shim); + tstate, init[0], NULL, args-1, oparg+1, NULL, shim); SYNC_SP(); if (init_frame == NULL) { _PyEval_FrameClearAndPop(tstate, shim); @@ -3634,16 +3702,18 @@ dummy_func( Py_TYPE(PyStackRef_AsPyObjectBorrow(should_be_none))->tp_name); ERROR_NO_POP(); } + DEAD(should_be_none); } - op(_CALL_BUILTIN_CLASS, (callable, self_or_null[1], args[oparg] -- res)) { - PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable); + op(_CALL_BUILTIN_CLASS, (callable[1], self_or_null[1], args[oparg] -- res)) { + PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable[0]); int total_args = oparg; if (!PyStackRef_IsNull(self_or_null[0])) { args--; total_args++; } + DEAD(self_or_null); DEOPT_IF(!PyType_Check(callable_o)); PyTypeObject *tp = (PyTypeObject *)callable_o; DEOPT_IF(tp->tp_vectorcall == NULL); @@ -3659,7 +3729,7 @@ dummy_func( for (int i = 0; i < total_args; i++) { PyStackRef_CLOSE(args[i]); } - PyStackRef_CLOSE(callable); + PyStackRef_CLOSE(callable[0]); ERROR_IF(res_o == NULL, error); res = PyStackRef_FromPyObjectSteal(res_o); } @@ -3670,9 +3740,9 @@ dummy_func( _CALL_BUILTIN_CLASS + _CHECK_PERIODIC; - op(_CALL_BUILTIN_O, (callable, self_or_null[1], args[oparg] -- res)) { + op(_CALL_BUILTIN_O, (callable[1], self_or_null[1], args[oparg] -- res)) { /* Builtin METH_O functions */ - PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable); + PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable[0]); int total_args = oparg; if (!PyStackRef_IsNull(self_or_null[0])) { @@ -3693,7 +3763,9 @@ dummy_func( assert((res_o != NULL) ^ (_PyErr_Occurred(tstate) != NULL)); PyStackRef_CLOSE(arg); - PyStackRef_CLOSE(callable); + DEAD(args); + DEAD(self_or_null); + PyStackRef_CLOSE(callable[0]); ERROR_IF(res_o == NULL, error); res = PyStackRef_FromPyObjectSteal(res_o); } @@ -3704,15 +3776,16 @@ dummy_func( _CALL_BUILTIN_O + _CHECK_PERIODIC; - op(_CALL_BUILTIN_FAST, (callable, self_or_null[1], args[oparg] -- res)) { + op(_CALL_BUILTIN_FAST, (callable[1], self_or_null[1], args[oparg] -- res)) { /* Builtin METH_FASTCALL functions, without keywords */ - PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable); + PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable[0]); int total_args = oparg; if (!PyStackRef_IsNull(self_or_null[0])) { args--; total_args++; } + DEAD(self_or_null); DEOPT_IF(!PyCFunction_CheckExact(callable_o)); DEOPT_IF(PyCFunction_GET_FLAGS(callable_o) != METH_FASTCALL); STAT_INC(CALL, hit); @@ -3734,7 +3807,7 @@ dummy_func( for (int i = 0; i < total_args; i++) { PyStackRef_CLOSE(args[i]); } - PyStackRef_CLOSE(callable); + PyStackRef_CLOSE(callable[0]); ERROR_IF(res_o == NULL, error); res = PyStackRef_FromPyObjectSteal(res_o); } @@ -3745,9 +3818,9 @@ dummy_func( _CALL_BUILTIN_FAST + _CHECK_PERIODIC; - op(_CALL_BUILTIN_FAST_WITH_KEYWORDS, (callable, self_or_null[1], args[oparg] -- res)) { + op(_CALL_BUILTIN_FAST_WITH_KEYWORDS, (callable[1], self_or_null[1], args[oparg] -- res)) { /* Builtin METH_FASTCALL | METH_KEYWORDS functions */ - PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable); + PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable[0]); int total_args = oparg; if (!PyStackRef_IsNull(self_or_null[0])) { @@ -3776,7 +3849,8 @@ dummy_func( for (int i = 0; i < total_args; i++) { PyStackRef_CLOSE(args[i]); } - PyStackRef_CLOSE(callable); + DEAD(self_or_null); + PyStackRef_CLOSE(callable[0]); ERROR_IF(res_o == NULL, error); res = PyStackRef_FromPyObjectSteal(res_o); } @@ -3787,9 +3861,9 @@ dummy_func( _CALL_BUILTIN_FAST_WITH_KEYWORDS + _CHECK_PERIODIC; - inst(CALL_LEN, (unused/1, unused/2, callable, self_or_null[1], args[oparg] -- res)) { + inst(CALL_LEN, (unused/1, unused/2, callable[1], self_or_null[1], args[oparg] -- res)) { /* len(o) */ - PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable); + PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable[0]); int total_args = oparg; if (!PyStackRef_IsNull(self_or_null[0])) { @@ -3811,14 +3885,14 @@ dummy_func( if (res_o == NULL) { GOTO_ERROR(error); } - PyStackRef_CLOSE(callable); + PyStackRef_CLOSE(callable[0]); PyStackRef_CLOSE(arg_stackref); res = PyStackRef_FromPyObjectSteal(res_o); } - inst(CALL_ISINSTANCE, (unused/1, unused/2, callable, self_or_null[1], args[oparg] -- res)) { + inst(CALL_ISINSTANCE, (unused/1, unused/2, callable[1], self_or_null[1], args[oparg] -- res)) { /* isinstance(o, o2) */ - PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable); + PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable[0]); int total_args = oparg; if (!PyStackRef_IsNull(self_or_null[0])) { @@ -3839,7 +3913,7 @@ dummy_func( assert((!PyStackRef_IsNull(res)) ^ (_PyErr_Occurred(tstate) != NULL)); PyStackRef_CLOSE(inst_stackref); PyStackRef_CLOSE(cls_stackref); - PyStackRef_CLOSE(callable); + PyStackRef_CLOSE(callable[0]); } // This is secretly a super-instruction @@ -3865,8 +3939,8 @@ dummy_func( #endif } - op(_CALL_METHOD_DESCRIPTOR_O, (callable, self_or_null[1], args[oparg] -- res)) { - PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable); + op(_CALL_METHOD_DESCRIPTOR_O, (callable[1], self_or_null[1], args[oparg] -- res)) { + PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable[0]); int total_args = oparg; if (!PyStackRef_IsNull(self_or_null[0])) { @@ -3895,7 +3969,9 @@ dummy_func( assert((res_o != NULL) ^ (_PyErr_Occurred(tstate) != NULL)); PyStackRef_CLOSE(self_stackref); PyStackRef_CLOSE(arg_stackref); - PyStackRef_CLOSE(callable); + DEAD(args); + DEAD(self_or_null); + PyStackRef_CLOSE(callable[0]); ERROR_IF(res_o == NULL, error); res = PyStackRef_FromPyObjectSteal(res_o); } @@ -3906,8 +3982,8 @@ dummy_func( _CALL_METHOD_DESCRIPTOR_O + _CHECK_PERIODIC; - op(_CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS, (callable, self_or_null[1], args[oparg] -- res)) { - PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable); + op(_CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS, (callable[1], self_or_null[1], args[oparg] -- res)) { + PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable[0]); int total_args = oparg; if (!PyStackRef_IsNull(self_or_null[0])) { @@ -3923,14 +3999,14 @@ dummy_func( EXIT_IF(!Py_IS_TYPE(self, d_type)); STAT_INC(CALL, hit); int nargs = total_args - 1; - PyCFunctionFastWithKeywords cfunc = - (PyCFunctionFastWithKeywords)(void(*)(void))meth->ml_meth; STACKREFS_TO_PYOBJECTS(args, total_args, args_o); if (CONVERSION_FAILED(args_o)) { DECREF_INPUTS(); ERROR_IF(true, error); } + PyCFunctionFastWithKeywords cfunc = + (PyCFunctionFastWithKeywords)(void(*)(void))meth->ml_meth; PyObject *res_o = cfunc(self, (args_o + 1), nargs, NULL); STACKREFS_TO_PYOBJECTS_CLEANUP(args_o); assert((res_o != NULL) ^ (_PyErr_Occurred(tstate) != NULL)); @@ -3939,7 +4015,8 @@ dummy_func( for (int i = 0; i < total_args; i++) { PyStackRef_CLOSE(args[i]); } - PyStackRef_CLOSE(callable); + DEAD(self_or_null); + PyStackRef_CLOSE(callable[0]); ERROR_IF(res_o == NULL, error); res = PyStackRef_FromPyObjectSteal(res_o); } @@ -3950,9 +4027,9 @@ dummy_func( _CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS + _CHECK_PERIODIC; - op(_CALL_METHOD_DESCRIPTOR_NOARGS, (callable, self_or_null[1], args[oparg] -- res)) { + op(_CALL_METHOD_DESCRIPTOR_NOARGS, (callable[1], self_or_null[1], args[oparg] -- res)) { assert(oparg == 0 || oparg == 1); - PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable); + PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable[0]); int total_args = oparg; if (!PyStackRef_IsNull(self_or_null[0])) { @@ -3976,7 +4053,9 @@ dummy_func( _Py_LeaveRecursiveCallTstate(tstate); assert((res_o != NULL) ^ (_PyErr_Occurred(tstate) != NULL)); PyStackRef_CLOSE(self_stackref); - PyStackRef_CLOSE(callable); + DEAD(args); + DEAD(self_or_null); + PyStackRef_CLOSE(callable[0]); ERROR_IF(res_o == NULL, error); res = PyStackRef_FromPyObjectSteal(res_o); } @@ -3987,8 +4066,8 @@ dummy_func( _CALL_METHOD_DESCRIPTOR_NOARGS + _CHECK_PERIODIC; - op(_CALL_METHOD_DESCRIPTOR_FAST, (callable, self_or_null[1], args[oparg] -- res)) { - PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable); + op(_CALL_METHOD_DESCRIPTOR_FAST, (callable[1], self_or_null[1], args[oparg] -- res)) { + PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable[0]); int total_args = oparg; if (!PyStackRef_IsNull(self_or_null[0])) { @@ -4003,8 +4082,6 @@ dummy_func( PyObject *self = PyStackRef_AsPyObjectBorrow(args[0]); EXIT_IF(!Py_IS_TYPE(self, method->d_common.d_type)); STAT_INC(CALL, hit); - PyCFunctionFast cfunc = - (PyCFunctionFast)(void(*)(void))meth->ml_meth; int nargs = total_args - 1; STACKREFS_TO_PYOBJECTS(args, total_args, args_o); @@ -4012,6 +4089,8 @@ dummy_func( DECREF_INPUTS(); ERROR_IF(true, error); } + PyCFunctionFast cfunc = + (PyCFunctionFast)(void(*)(void))meth->ml_meth; PyObject *res_o = cfunc(self, (args_o + 1), nargs); STACKREFS_TO_PYOBJECTS_CLEANUP(args_o); assert((res_o != NULL) ^ (_PyErr_Occurred(tstate) != NULL)); @@ -4020,7 +4099,8 @@ dummy_func( for (int i = 0; i < total_args; i++) { PyStackRef_CLOSE(args[i]); } - PyStackRef_CLOSE(callable); + DEAD(self_or_null); + PyStackRef_CLOSE(callable[0]); ERROR_IF(res_o == NULL, error); res = PyStackRef_FromPyObjectSteal(res_o); } @@ -4052,8 +4132,22 @@ dummy_func( GO_TO_INSTRUCTION(CALL_KW); } - op(_DO_CALL_KW, (callable, self_or_null[1], args[oparg], kwnames -- res)) { - PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable); + op(_MAYBE_EXPAND_METHOD_KW, (callable[1], self_or_null[1], args[oparg], kwnames_in -- func[1], maybe_self[1], args[oparg], kwnames_out)) { + if (PyStackRef_TYPE(callable[0]) == &PyMethod_Type && PyStackRef_IsNull(self_or_null[0])) { + PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable[0]); + PyObject *self = ((PyMethodObject *)callable_o)->im_self; + maybe_self[0] = PyStackRef_FromPyObjectNew(self); + PyObject *method = ((PyMethodObject *)callable_o)->im_func; + _PyStackRef temp = callable[0]; + func[0] = PyStackRef_FromPyObjectNew(method); + PyStackRef_CLOSE(temp); + } + kwnames_out = kwnames_in; + DEAD(kwnames_in); + } + + op(_DO_CALL_KW, (callable[1], self_or_null[1], args[oparg], kwnames -- res)) { + PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable[0]); PyObject *kwnames_o = PyStackRef_AsPyObjectBorrow(kwnames); // oparg counts all of the args, but *not* self: @@ -4062,17 +4156,6 @@ dummy_func( args--; total_args++; } - else if (Py_TYPE(callable_o) == &PyMethod_Type) { - args--; - total_args++; - PyObject *self = ((PyMethodObject *)callable_o)->im_self; - args[0] = PyStackRef_FromPyObjectNew(self); - PyObject *method = ((PyMethodObject *)callable_o)->im_func; - args[-1] = PyStackRef_FromPyObjectNew(method); - PyStackRef_CLOSE(callable); - callable_o = method; - callable = args[-1]; - } int positional_args = total_args - (int)PyTuple_GET_SIZE(kwnames_o); // Check if the call can be inlined or not if (Py_TYPE(callable_o) == &PyFunction_Type && @@ -4082,12 +4165,12 @@ dummy_func( int code_flags = ((PyCodeObject*)PyFunction_GET_CODE(callable_o))->co_flags; PyObject *locals = code_flags & CO_OPTIMIZED ? NULL : Py_NewRef(PyFunction_GET_GLOBALS(callable_o)); _PyInterpreterFrame *new_frame = _PyEvalFramePushAndInit( - tstate, callable, locals, + tstate, callable[0], locals, args, positional_args, kwnames_o, frame ); PyStackRef_CLOSE(kwnames); - // Manipulate stack directly since we leave using DISPATCH_INLINED(). - STACK_SHRINK(oparg + 3); + // Sync stack explicitly since we leave using DISPATCH_INLINED(). + SYNC_SP(); // The frame has stolen all the arguments from the stack, // so there is no need to clean them up. if (new_frame == NULL) { @@ -4127,16 +4210,17 @@ dummy_func( } PyStackRef_CLOSE(kwnames); assert((res_o != NULL) ^ (_PyErr_Occurred(tstate) != NULL)); - PyStackRef_CLOSE(callable); + PyStackRef_CLOSE(callable[0]); for (int i = 0; i < total_args; i++) { PyStackRef_CLOSE(args[i]); } + DEAD(self_or_null); ERROR_IF(res_o == NULL, error); res = PyStackRef_FromPyObjectSteal(res_o); } - op(_PY_FRAME_KW, (callable, self_or_null[1], args[oparg], kwnames -- new_frame: _PyInterpreterFrame*)) { - PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable); + op(_PY_FRAME_KW, (callable[1], self_or_null[1], args[oparg], kwnames -- new_frame: _PyInterpreterFrame*)) { + PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable[0]); // oparg counts all of the args, but *not* self: int total_args = oparg; @@ -4150,7 +4234,7 @@ dummy_func( int code_flags = ((PyCodeObject*)PyFunction_GET_CODE(callable_o))->co_flags; PyObject *locals = code_flags & CO_OPTIMIZED ? NULL : Py_NewRef(PyFunction_GET_GLOBALS(callable_o)); new_frame = _PyEvalFramePushAndInit( - tstate, callable, locals, + tstate, callable[0], locals, args, positional_args, kwnames_o, frame ); PyStackRef_CLOSE(kwnames); @@ -4162,8 +4246,8 @@ dummy_func( } } - op(_CHECK_FUNCTION_VERSION_KW, (func_version/2, callable, self_or_null[1], unused[oparg], kwnames -- callable, self_or_null[1], unused[oparg], kwnames)) { - PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable); + op(_CHECK_FUNCTION_VERSION_KW, (func_version/2, callable[1], self_or_null[1], unused[oparg], kwnames -- callable[1], self_or_null[1], unused[oparg], kwnames)) { + PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable[0]); EXIT_IF(!PyFunction_Check(callable_o)); PyFunctionObject *func = (PyFunctionObject *)callable_o; EXIT_IF(func->func_version != func_version); @@ -4177,8 +4261,8 @@ dummy_func( _SAVE_RETURN_OFFSET + _PUSH_FRAME; - op(_CHECK_METHOD_VERSION_KW, (func_version/2, callable, null[1], unused[oparg], kwnames -- callable, null[1], unused[oparg], kwnames)) { - PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable); + op(_CHECK_METHOD_VERSION_KW, (func_version/2, callable[1], null[1], unused[oparg], kwnames -- callable[1], null[1], unused[oparg], kwnames)) { + PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable[0]); EXIT_IF(Py_TYPE(callable_o) != &PyMethod_Type); PyObject *func = ((PyMethodObject *)callable_o)->im_func; @@ -4187,15 +4271,16 @@ dummy_func( EXIT_IF(!PyStackRef_IsNull(null[0])); } - op(_EXPAND_METHOD_KW, (callable, null[1], unused[oparg], kwnames -- method, self[1], unused[oparg], kwnames)) { - PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable); + op(_EXPAND_METHOD_KW, (callable[1], null[1], unused[oparg], unused -- method[1], self[1], unused[oparg], unused)) { + _PyStackRef callable_s = callable[0]; + PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable_s); assert(PyStackRef_IsNull(null[0])); assert(Py_TYPE(callable_o) == &PyMethod_Type); self[0] = PyStackRef_FromPyObjectNew(((PyMethodObject *)callable_o)->im_self); - method = PyStackRef_FromPyObjectNew(((PyMethodObject *)callable_o)->im_func); - assert(PyStackRef_FunctionCheck(method)); - PyStackRef_CLOSE(callable); + method[0] = PyStackRef_FromPyObjectNew(((PyMethodObject *)callable_o)->im_func); + assert(PyStackRef_FunctionCheck(method[0])); + PyStackRef_CLOSE(callable_s); } macro(CALL_KW_BOUND_METHOD) = @@ -4208,11 +4293,11 @@ dummy_func( _SAVE_RETURN_OFFSET + _PUSH_FRAME; - specializing op(_SPECIALIZE_CALL_KW, (counter/1, callable, self_or_null[1], args[oparg], kwnames -- callable, self_or_null[1], args[oparg], kwnames)) { + specializing op(_SPECIALIZE_CALL_KW, (counter/1, callable[1], self_or_null[1], args[oparg], kwnames -- callable[1], self_or_null[1], args[oparg], kwnames)) { #if ENABLE_SPECIALIZATION if (ADAPTIVE_COUNTER_TRIGGERS(counter)) { next_instr = this_instr; - _Py_Specialize_CallKw(callable, next_instr, oparg + !PyStackRef_IsNull(self_or_null[0])); + _Py_Specialize_CallKw(callable[0], next_instr, oparg + !PyStackRef_IsNull(self_or_null[0])); DISPATCH_SAME_OPARG(); } OPCODE_DEFERRED_INC(CALL_KW); @@ -4223,20 +4308,21 @@ dummy_func( macro(CALL_KW) = _SPECIALIZE_CALL_KW + unused/2 + + _MAYBE_EXPAND_METHOD_KW + _DO_CALL_KW; - op(_CHECK_IS_NOT_PY_CALLABLE_KW, (callable, unused[1], unused[oparg], kwnames -- callable, unused[1], unused[oparg], kwnames)) { - PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable); + op(_CHECK_IS_NOT_PY_CALLABLE_KW, (callable[1], unused[1], unused[oparg], kwnames -- callable[1], unused[1], unused[oparg], kwnames)) { + PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable[0]); EXIT_IF(PyFunction_Check(callable_o)); EXIT_IF(Py_TYPE(callable_o) == &PyMethod_Type); } - op(_CALL_KW_NON_PY, (callable, self_or_null[1], args[oparg], kwnames -- res)) { + op(_CALL_KW_NON_PY, (callable[1], self_or_null[1], args[oparg], kwnames -- res)) { #if TIER_ONE assert(opcode != INSTRUMENTED_CALL); #endif - PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable); + PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable[0]); int total_args = oparg; if (!PyStackRef_IsNull(self_or_null[0])) { @@ -4258,10 +4344,11 @@ dummy_func( PyStackRef_CLOSE(kwnames); STACKREFS_TO_PYOBJECTS_CLEANUP(args_o); assert((res_o != NULL) ^ (_PyErr_Occurred(tstate) != NULL)); - PyStackRef_CLOSE(callable); for (int i = 0; i < total_args; i++) { PyStackRef_CLOSE(args[i]); } + DEAD(self_or_null); + PyStackRef_CLOSE(callable[0]); ERROR_IF(res_o == NULL, error); res = PyStackRef_FromPyObjectSteal(res_o); } @@ -4277,7 +4364,29 @@ dummy_func( GO_TO_INSTRUCTION(CALL_FUNCTION_EX); } - inst(_DO_CALL_FUNCTION_EX, (func_st, unused, callargs_st, kwargs_st if (oparg & 1) -- result)) { + op(_MAKE_CALLARGS_A_TUPLE, (func, unused, callargs, kwargs_in if (oparg & 1) -- func, unused, tuple, kwargs_out if (oparg & 1))) { + PyObject *callargs_o = PyStackRef_AsPyObjectBorrow(callargs); + if (PyTuple_CheckExact(callargs_o)) { + tuple = callargs; + DEAD(callargs); + } + else { + int err = _Py_Check_ArgsIterable(tstate, PyStackRef_AsPyObjectBorrow(func), callargs_o); + if (err < 0) { + ERROR_NO_POP(); + } + PyObject *tuple_o = PySequence_Tuple(callargs_o); + if (tuple_o == NULL) { + ERROR_NO_POP(); + } + PyStackRef_CLOSE(callargs); + tuple = PyStackRef_FromPyObjectSteal(tuple_o); + } + kwargs_out = kwargs_in; + DEAD(kwargs_in); + } + + op(_DO_CALL_FUNCTION_EX, (func_st, unused, callargs_st, kwargs_st if (oparg & 1) -- result)) { PyObject *func = PyStackRef_AsPyObjectBorrow(func_st); PyObject *callargs = PyStackRef_AsPyObjectBorrow(callargs_st); PyObject *kwargs = PyStackRef_AsPyObjectBorrow(kwargs_st); @@ -4285,32 +4394,23 @@ dummy_func( // DICT_MERGE is called before this opcode if there are kwargs. // It converts all dict subtypes in kwargs into regular dicts. assert(kwargs == NULL || PyDict_CheckExact(kwargs)); - if (!PyTuple_CheckExact(callargs)) { - int err = check_args_iterable(tstate, func, callargs); - if (err < 0) { - ERROR_NO_POP(); - } - PyObject *tuple = PySequence_Tuple(callargs); - if (tuple == NULL) { - ERROR_NO_POP(); - } - PyStackRef_CLOSE(callargs_st); - callargs_st = PyStackRef_FromPyObjectSteal(tuple); - callargs = tuple; - } assert(PyTuple_CheckExact(callargs)); EVAL_CALL_STAT_INC_IF_FUNCTION(EVAL_CALL_FUNCTION_EX, func); + PyObject *result_o; + assert(!_PyErr_Occurred(tstate)); if (opcode == INSTRUMENTED_CALL_FUNCTION_EX) { PyObject *arg = PyTuple_GET_SIZE(callargs) > 0 ? PyTuple_GET_ITEM(callargs, 0) : &_PyInstrumentation_MISSING; int err = _Py_call_instrumentation_2args( tstate, PY_MONITORING_EVENT_CALL, frame, this_instr, func, arg); - if (err) ERROR_NO_POP(); - result = PyStackRef_FromPyObjectSteal(PyObject_Call(func, callargs, kwargs)); + if (err) { + ERROR_NO_POP(); + } + result_o = PyObject_Call(func, callargs, kwargs); if (!PyFunction_Check(func) && !PyMethod_Check(func)) { - if (PyStackRef_IsNull(result)) { + if (result_o == NULL) { _Py_call_instrumentation_exc2( tstate, PY_MONITORING_EVENT_C_RAISE, frame, this_instr, func, arg); @@ -4320,7 +4420,7 @@ dummy_func( tstate, PY_MONITORING_EVENT_C_RETURN, frame, this_instr, func, arg); if (err < 0) { - PyStackRef_CLEAR(result); + Py_CLEAR(result_o); } } } @@ -4337,8 +4437,9 @@ dummy_func( _PyInterpreterFrame *new_frame = _PyEvalFramePushAndInit_Ex( tstate, func_st, locals, nargs, callargs, kwargs, frame); - // Need to manually shrink the stack since we exit with DISPATCH_INLINED. - STACK_SHRINK(oparg + 3); + // Need to sync the stack since we exit with DISPATCH_INLINED. + INPUTS_DEAD(); + SYNC_SP(); if (new_frame == NULL) { ERROR_NO_POP(); } @@ -4346,14 +4447,18 @@ dummy_func( frame->return_offset = 1; DISPATCH_INLINED(new_frame); } - result = PyStackRef_FromPyObjectSteal(PyObject_Call(func, callargs, kwargs)); + result_o = PyObject_Call(func, callargs, kwargs); } - DECREF_INPUTS(); - assert(PyStackRef_AsPyObjectBorrow(PEEK(2 + (oparg & 1))) == NULL); - ERROR_IF(PyStackRef_IsNull(result), error); + PyStackRef_XCLOSE(kwargs_st); + DEAD(kwargs_st); + PyStackRef_CLOSE(callargs_st); + PyStackRef_CLOSE(func_st); + ERROR_IF(result_o == NULL, error); + result = PyStackRef_FromPyObjectSteal(result_o); } macro(CALL_FUNCTION_EX) = + _MAKE_CALLARGS_A_TUPLE + _DO_CALL_FUNCTION_EX + _CHECK_PERIODIC; @@ -4365,59 +4470,33 @@ dummy_func( PyFunction_New(codeobj, GLOBALS()); PyStackRef_CLOSE(codeobj_st); - if (func_obj == NULL) { - ERROR_NO_POP(); - } + ERROR_IF(func_obj == NULL, error); _PyFunction_SetVersion( func_obj, ((PyCodeObject *)codeobj)->co_version); func = PyStackRef_FromPyObjectSteal((PyObject *)func_obj); } - inst(SET_FUNCTION_ATTRIBUTE, (attr_st, func_st -- func_st)) { - PyObject *func = PyStackRef_AsPyObjectBorrow(func_st); - PyObject *attr = PyStackRef_AsPyObjectBorrow(attr_st); - + inst(SET_FUNCTION_ATTRIBUTE, (attr_st, func_in -- func_out)) { + PyObject *func = PyStackRef_AsPyObjectBorrow(func_in); + PyObject *attr = PyStackRef_AsPyObjectSteal(attr_st); + func_out = func_in; + DEAD(func_in); assert(PyFunction_Check(func)); - PyFunctionObject *func_obj = (PyFunctionObject *)func; - switch(oparg) { - case MAKE_FUNCTION_CLOSURE: - assert(func_obj->func_closure == NULL); - func_obj->func_closure = attr; - break; - case MAKE_FUNCTION_ANNOTATIONS: - assert(func_obj->func_annotations == NULL); - func_obj->func_annotations = attr; - break; - case MAKE_FUNCTION_KWDEFAULTS: - assert(PyDict_CheckExact(attr)); - assert(func_obj->func_kwdefaults == NULL); - func_obj->func_kwdefaults = attr; - break; - case MAKE_FUNCTION_DEFAULTS: - assert(PyTuple_CheckExact(attr)); - assert(func_obj->func_defaults == NULL); - func_obj->func_defaults = attr; - break; - case MAKE_FUNCTION_ANNOTATE: - assert(PyCallable_Check(attr)); - assert(func_obj->func_annotate == NULL); - func_obj->func_annotate = attr; - break; - default: - Py_UNREACHABLE(); - } + size_t offset = _Py_FunctionAttributeOffsets[oparg]; + assert(offset != 0); + PyObject **ptr = (PyObject **)(((char *)func) + offset); + assert(*ptr == NULL); + *ptr = attr; } inst(RETURN_GENERATOR, (-- res)) { assert(PyStackRef_FunctionCheck(frame->f_funcobj)); PyFunctionObject *func = (PyFunctionObject *)PyStackRef_AsPyObjectBorrow(frame->f_funcobj); PyGenObject *gen = (PyGenObject *)_Py_MakeCoro(func); - if (gen == NULL) { - ERROR_NO_POP(); - } + ERROR_IF(gen == NULL, error); assert(EMPTY()); - _PyFrame_SetStackPointer(frame, stack_pointer); + SAVE_STACK(); _PyInterpreterFrame *gen_frame = &gen->gi_iframe; frame->instr_ptr++; _PyFrame_Copy(frame, gen_frame); @@ -4425,12 +4504,12 @@ dummy_func( gen->gi_frame_state = FRAME_CREATED; gen_frame->owner = FRAME_OWNED_BY_GENERATOR; _Py_LeaveRecursiveCallPy(tstate); - res = PyStackRef_FromPyObjectSteal((PyObject *)gen); _PyInterpreterFrame *prev = frame->previous; _PyThreadState_PopFrame(tstate, frame); frame = tstate->current_frame = prev; LOAD_IP(frame->return_offset); - LOAD_SP(); + RELOAD_STACK(); + res = PyStackRef_FromPyObjectSteal((PyObject *)gen); LLTRACE_RESUME_FRAME(); } @@ -4466,6 +4545,7 @@ dummy_func( } else { res = value; + DEAD(value); } } @@ -4509,8 +4589,12 @@ dummy_func( macro(BINARY_OP) = _SPECIALIZE_BINARY_OP + _BINARY_OP; - pure inst(SWAP, (bottom, unused[oparg-2], top -- - top, unused[oparg-2], bottom)) { + pure inst(SWAP, (bottom_in, unused[oparg-2], top_in -- + top_out, unused[oparg-2], bottom_out)) { + bottom_out = bottom_in; + DEAD(bottom_in); + top_out = top_in; + DEAD(top_in); assert(oparg >= 2); } @@ -4521,10 +4605,8 @@ dummy_func( original_opcode = code->_co_monitoring->lines[(int)(this_instr - _PyCode_CODE(code))].original_opcode; next_instr = this_instr; } else { - _PyFrame_SetStackPointer(frame, stack_pointer); original_opcode = _Py_call_instrumentation_line( tstate, frame, this_instr, prev_instr); - stack_pointer = _PyFrame_GetStackPointer(frame); if (original_opcode < 0) { next_instr = this_instr+1; goto error; @@ -4647,29 +4729,34 @@ dummy_func( ///////// Tier-2 only opcodes ///////// op (_GUARD_IS_TRUE_POP, (flag -- )) { + int is_true = PyStackRef_Is(flag, PyStackRef_True); + DEAD(flag); SYNC_SP(); - EXIT_IF(!PyStackRef_Is(flag, PyStackRef_True)); - assert(PyStackRef_Is(flag, PyStackRef_True)); + EXIT_IF(!is_true); } op (_GUARD_IS_FALSE_POP, (flag -- )) { + int is_false = PyStackRef_Is(flag, PyStackRef_False); + DEAD(flag); SYNC_SP(); - EXIT_IF(!PyStackRef_Is(flag, PyStackRef_False)); - assert(PyStackRef_Is(flag, PyStackRef_False)); + EXIT_IF(!is_false); } op (_GUARD_IS_NONE_POP, (val -- )) { - SYNC_SP(); - if (!PyStackRef_Is(val, PyStackRef_None)) { + int is_none = PyStackRef_Is(val, PyStackRef_None); + if (!is_none) { PyStackRef_CLOSE(val); + SYNC_SP(); EXIT_IF(1); } + DEAD(val); } op (_GUARD_IS_NOT_NONE_POP, (val -- )) { - SYNC_SP(); - EXIT_IF(PyStackRef_Is(val, PyStackRef_None)); + int is_none = PyStackRef_Is(val, PyStackRef_None); PyStackRef_CLOSE(val); + SYNC_SP(); + EXIT_IF(is_none); } op(_JUMP_TO_TOP, (--)) { @@ -4782,6 +4869,7 @@ dummy_func( op(_INTERNAL_INCREMENT_OPT_COUNTER, (opt --)) { _PyCounterOptimizerObject *exe = (_PyCounterOptimizerObject *)PyStackRef_AsPyObjectBorrow(opt); exe->count++; + DEAD(opt); } tier2 op(_DYNAMIC_EXIT, (exit_p/4 --)) { |