]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
specialization and deopt fixes
authorKen Jin <28750310+Fidget-Spinner@users.noreply.github.com>
Fri, 24 Oct 2025 10:27:20 +0000 (11:27 +0100)
committerKen Jin <28750310+Fidget-Spinner@users.noreply.github.com>
Fri, 24 Oct 2025 10:27:20 +0000 (11:27 +0100)
Include/internal/pycore_interp_structs.h
Python/bytecodes.c
Python/ceval_macros.h
Python/generated_cases.c.h
Python/optimizer.c
Tools/cases_generator/generators_common.py

index c2cddfe47d3f7322c6753403a44557b084db321e..bc0ae6ea97d654dff7fc7e3ba524dbd2cdaaa628 100644 (file)
@@ -759,14 +759,15 @@ typedef _Py_CODEUNIT *(*_PyJitEntryFuncPtr)(struct _PyExecutorObject *exec, _PyI
 
 typedef struct _PyJitTracerState {
     bool dependencies_still_valid;
-    bool do_not_specialize;
     bool dynamic_jump_taken;
+    bool prev_instr_is_super;
     int code_max_size;
     int code_curr_size;
     int initial_stack_depth;
     int initial_chain_depth;
     int prev_instr_oparg;
     int prev_instr_stacklevel;
+    int specialize_counter;
     _PyUOpInstruction *code_buffer;
     _Py_CODEUNIT *insert_exec_instr;
     _Py_CODEUNIT *close_loop_instr;
index be98f34ce819e4322093aa181cd8a911aa653819..e872dabda874169361efbea9a9d394ac82db97ed 100644 (file)
@@ -5229,10 +5229,21 @@ dummy_func(
                 ERROR_IF(err < 0);
                 DISPATCH_GOTO_NON_TRACING();
             }
-            tstate->interp->jit_state.do_not_specialize = false;
+            // Super instructions. Instruction deopted, There's a mismatch in what the stack expects
+            // in the optimizer. So we have to reflect in the trace correctly.
+            if ((tstate->interp->jit_state.prev_instr->op.code == CALL_LIST_APPEND &&
+                opcode == POP_TOP) ||
+                (tstate->interp->jit_state.prev_instr->op.code == BINARY_OP_INPLACE_ADD_UNICODE &&
+                opcode == STORE_FAST)) {
+                tstate->interp->jit_state.prev_instr_is_super = true;
+            }
+            else {
+                tstate->interp->jit_state.prev_instr = next_instr;
+            }
+            tstate->interp->jit_state.specialize_counter = 0;
             PyCodeObject *prev_code = (PyCodeObject *)Py_NewRef(_PyFrame_GetCode(frame));
             Py_SETREF(tstate->interp->jit_state.prev_instr_code, prev_code);
-            tstate->interp->jit_state.prev_instr = next_instr;
+
             tstate->interp->jit_state.prev_instr_frame = frame;
             tstate->interp->jit_state.prev_instr_oparg = oparg;
             tstate->interp->jit_state.prev_instr_stacklevel = STACK_LEVEL();
index b741707377ae223de404de0a62d4c2b612e1edd3..abef480b902a5cd9b5616da697a9a118e61b7e93 100644 (file)
 
 #if (_Py_TAIL_CALL_INTERP || USE_COMPUTED_GOTOS) && _Py_TIER2
 #  define IS_JIT_TRACING() (DISPATCH_TABLE_VAR == TRACING_DISPATCH_TABLE)
-// Required to not get stuck in infinite pecialization loops due to specialization failure.
-#  define IS_JIT_TRACING_MAKING_PROGRESS() (IS_JIT_TRACING() && !tstate->interp->jit_state.do_not_specialize)
+// Required to not get stuck in infinite specialization loops due to specialization failure.
+#  define IS_JIT_TRACING_MAKING_PROGRESS() (IS_JIT_TRACING() && tstate->interp->jit_state.specialize_counter <= 2)
 #  define ENTER_TRACING() \
     DISPATCH_TABLE_VAR = TRACING_DISPATCH_TABLE;
 #  define LEAVE_TRACING() \
@@ -195,7 +195,7 @@ do { \
 #if _Py_TIER2
 #define DISPATCH_SAME_OPARG() \
     { \
-        tstate->interp->jit_state.do_not_specialize = true; \
+        tstate->interp->jit_state.specialize_counter++; \
         opcode = next_instr->op.code; \
         PRE_DISPATCH_GOTO(); \
         DISPATCH_GOTO_NON_TRACING(); \
index 0665f985ff08cc28605086103ef111808008feee..7b759811b3928d2ae4dde47ff45559c7ea98f782 100644 (file)
                 if (!PyFloat_CheckExact(value_o)) {
                     UPDATE_MISS_STATS(BINARY_OP);
                     assert(_PyOpcode_Deopt[opcode] == (BINARY_OP));
+                    #if _Py_TIER2
+                    tstate->interp->jit_state.specialize_counter++;
+                    #endif
                     JUMP_TO_PREDICTED(BINARY_OP);
                 }
             }
                 if (!PyFloat_CheckExact(left_o)) {
                     UPDATE_MISS_STATS(BINARY_OP);
                     assert(_PyOpcode_Deopt[opcode] == (BINARY_OP));
+                    #if _Py_TIER2
+                    tstate->interp->jit_state.specialize_counter++;
+                    #endif
                     JUMP_TO_PREDICTED(BINARY_OP);
                 }
             }
                 if (!_PyLong_CheckExactAndCompact(value_o)) {
                     UPDATE_MISS_STATS(BINARY_OP);
                     assert(_PyOpcode_Deopt[opcode] == (BINARY_OP));
+                    #if _Py_TIER2
+                    tstate->interp->jit_state.specialize_counter++;
+                    #endif
                     JUMP_TO_PREDICTED(BINARY_OP);
                 }
             }
                 if (!_PyLong_CheckExactAndCompact(left_o)) {
                     UPDATE_MISS_STATS(BINARY_OP);
                     assert(_PyOpcode_Deopt[opcode] == (BINARY_OP));
+                    #if _Py_TIER2
+                    tstate->interp->jit_state.specialize_counter++;
+                    #endif
                     JUMP_TO_PREDICTED(BINARY_OP);
                 }
             }
                 if (PyStackRef_IsNull(res)) {
                     UPDATE_MISS_STATS(BINARY_OP);
                     assert(_PyOpcode_Deopt[opcode] == (BINARY_OP));
+                    #if _Py_TIER2
+                    tstate->interp->jit_state.specialize_counter++;
+                    #endif
                     JUMP_TO_PREDICTED(BINARY_OP);
                 }
                 PyStackRef_CLOSE_SPECIALIZED(right, _PyLong_ExactDealloc);
                 if (!PyUnicode_CheckExact(value_o)) {
                     UPDATE_MISS_STATS(BINARY_OP);
                     assert(_PyOpcode_Deopt[opcode] == (BINARY_OP));
+                    #if _Py_TIER2
+                    tstate->interp->jit_state.specialize_counter++;
+                    #endif
                     JUMP_TO_PREDICTED(BINARY_OP);
                 }
             }
                 if (!PyUnicode_CheckExact(o)) {
                     UPDATE_MISS_STATS(BINARY_OP);
                     assert(_PyOpcode_Deopt[opcode] == (BINARY_OP));
+                    #if _Py_TIER2
+                    tstate->interp->jit_state.specialize_counter++;
+                    #endif
                     JUMP_TO_PREDICTED(BINARY_OP);
                 }
             }
                 if (!res) {
                     UPDATE_MISS_STATS(BINARY_OP);
                     assert(_PyOpcode_Deopt[opcode] == (BINARY_OP));
+                    #if _Py_TIER2
+                    tstate->interp->jit_state.specialize_counter++;
+                    #endif
                     JUMP_TO_PREDICTED(BINARY_OP);
                 }
             }
                 if (!PyUnicode_CheckExact(value_o)) {
                     UPDATE_MISS_STATS(BINARY_OP);
                     assert(_PyOpcode_Deopt[opcode] == (BINARY_OP));
+                    #if _Py_TIER2
+                    tstate->interp->jit_state.specialize_counter++;
+                    #endif
                     JUMP_TO_PREDICTED(BINARY_OP);
                 }
             }
                 if (!PyUnicode_CheckExact(o)) {
                     UPDATE_MISS_STATS(BINARY_OP);
                     assert(_PyOpcode_Deopt[opcode] == (BINARY_OP));
+                    #if _Py_TIER2
+                    tstate->interp->jit_state.specialize_counter++;
+                    #endif
                     JUMP_TO_PREDICTED(BINARY_OP);
                 }
             }
                 if (PyStackRef_AsPyObjectBorrow(*target_local) != left_o) {
                     UPDATE_MISS_STATS(BINARY_OP);
                     assert(_PyOpcode_Deopt[opcode] == (BINARY_OP));
+                    #if _Py_TIER2
+                    tstate->interp->jit_state.specialize_counter++;
+                    #endif
                     JUMP_TO_PREDICTED(BINARY_OP);
                 }
                 STAT_INC(BINARY_OP, hit);
                 if (!PyFloat_CheckExact(value_o)) {
                     UPDATE_MISS_STATS(BINARY_OP);
                     assert(_PyOpcode_Deopt[opcode] == (BINARY_OP));
+                    #if _Py_TIER2
+                    tstate->interp->jit_state.specialize_counter++;
+                    #endif
                     JUMP_TO_PREDICTED(BINARY_OP);
                 }
             }
                 if (!PyFloat_CheckExact(left_o)) {
                     UPDATE_MISS_STATS(BINARY_OP);
                     assert(_PyOpcode_Deopt[opcode] == (BINARY_OP));
+                    #if _Py_TIER2
+                    tstate->interp->jit_state.specialize_counter++;
+                    #endif
                     JUMP_TO_PREDICTED(BINARY_OP);
                 }
             }
                 if (!_PyLong_CheckExactAndCompact(value_o)) {
                     UPDATE_MISS_STATS(BINARY_OP);
                     assert(_PyOpcode_Deopt[opcode] == (BINARY_OP));
+                    #if _Py_TIER2
+                    tstate->interp->jit_state.specialize_counter++;
+                    #endif
                     JUMP_TO_PREDICTED(BINARY_OP);
                 }
             }
                 if (!_PyLong_CheckExactAndCompact(left_o)) {
                     UPDATE_MISS_STATS(BINARY_OP);
                     assert(_PyOpcode_Deopt[opcode] == (BINARY_OP));
+                    #if _Py_TIER2
+                    tstate->interp->jit_state.specialize_counter++;
+                    #endif
                     JUMP_TO_PREDICTED(BINARY_OP);
                 }
             }
                 if (PyStackRef_IsNull(res)) {
                     UPDATE_MISS_STATS(BINARY_OP);
                     assert(_PyOpcode_Deopt[opcode] == (BINARY_OP));
+                    #if _Py_TIER2
+                    tstate->interp->jit_state.specialize_counter++;
+                    #endif
                     JUMP_TO_PREDICTED(BINARY_OP);
                 }
                 PyStackRef_CLOSE_SPECIALIZED(right, _PyLong_ExactDealloc);
                 if (!PyDict_CheckExact(o)) {
                     UPDATE_MISS_STATS(BINARY_OP);
                     assert(_PyOpcode_Deopt[opcode] == (BINARY_OP));
+                    #if _Py_TIER2
+                    tstate->interp->jit_state.specialize_counter++;
+                    #endif
                     JUMP_TO_PREDICTED(BINARY_OP);
                 }
             }
                 if (tstate->interp->eval_frame) {
                     UPDATE_MISS_STATS(BINARY_OP);
                     assert(_PyOpcode_Deopt[opcode] == (BINARY_OP));
+                    #if _Py_TIER2
+                    tstate->interp->jit_state.specialize_counter++;
+                    #endif
                     JUMP_TO_PREDICTED(BINARY_OP);
                 }
             }
                 if (!PyType_HasFeature(tp, Py_TPFLAGS_HEAPTYPE)) {
                     UPDATE_MISS_STATS(BINARY_OP);
                     assert(_PyOpcode_Deopt[opcode] == (BINARY_OP));
+                    #if _Py_TIER2
+                    tstate->interp->jit_state.specialize_counter++;
+                    #endif
                     JUMP_TO_PREDICTED(BINARY_OP);
                 }
                 PyHeapTypeObject *ht = (PyHeapTypeObject *)tp;
                 if (getitem_o == NULL) {
                     UPDATE_MISS_STATS(BINARY_OP);
                     assert(_PyOpcode_Deopt[opcode] == (BINARY_OP));
+                    #if _Py_TIER2
+                    tstate->interp->jit_state.specialize_counter++;
+                    #endif
                     JUMP_TO_PREDICTED(BINARY_OP);
                 }
                 assert(PyFunction_Check(getitem_o));
                 if (((PyFunctionObject *)getitem_o)->func_version != cached_version) {
                     UPDATE_MISS_STATS(BINARY_OP);
                     assert(_PyOpcode_Deopt[opcode] == (BINARY_OP));
+                    #if _Py_TIER2
+                    tstate->interp->jit_state.specialize_counter++;
+                    #endif
                     JUMP_TO_PREDICTED(BINARY_OP);
                 }
                 PyCodeObject *code = (PyCodeObject *)PyFunction_GET_CODE(getitem_o);
                 if (!_PyThreadState_HasStackSpace(tstate, code->co_framesize)) {
                     UPDATE_MISS_STATS(BINARY_OP);
                     assert(_PyOpcode_Deopt[opcode] == (BINARY_OP));
+                    #if _Py_TIER2
+                    tstate->interp->jit_state.specialize_counter++;
+                    #endif
                     JUMP_TO_PREDICTED(BINARY_OP);
                 }
                 getitem = PyStackRef_FromPyObjectNew(getitem_o);
                 if (!_PyLong_CheckExactAndCompact(value_o)) {
                     UPDATE_MISS_STATS(BINARY_OP);
                     assert(_PyOpcode_Deopt[opcode] == (BINARY_OP));
+                    #if _Py_TIER2
+                    tstate->interp->jit_state.specialize_counter++;
+                    #endif
                     JUMP_TO_PREDICTED(BINARY_OP);
                 }
             }
                 if (!PyList_CheckExact(o)) {
                     UPDATE_MISS_STATS(BINARY_OP);
                     assert(_PyOpcode_Deopt[opcode] == (BINARY_OP));
+                    #if _Py_TIER2
+                    tstate->interp->jit_state.specialize_counter++;
+                    #endif
                     JUMP_TO_PREDICTED(BINARY_OP);
                 }
             }
                 if (!_PyLong_IsNonNegativeCompact((PyLongObject *)sub)) {
                     UPDATE_MISS_STATS(BINARY_OP);
                     assert(_PyOpcode_Deopt[opcode] == (BINARY_OP));
+                    #if _Py_TIER2
+                    tstate->interp->jit_state.specialize_counter++;
+                    #endif
                     JUMP_TO_PREDICTED(BINARY_OP);
                 }
                 Py_ssize_t index = ((PyLongObject*)sub)->long_value.ob_digit[0];
                 if (res_o == NULL) {
                     UPDATE_MISS_STATS(BINARY_OP);
                     assert(_PyOpcode_Deopt[opcode] == (BINARY_OP));
+                    #if _Py_TIER2
+                    tstate->interp->jit_state.specialize_counter++;
+                    #endif
                     JUMP_TO_PREDICTED(BINARY_OP);
                 }
                 STAT_INC(BINARY_OP, hit);
                 if (index >= PyList_GET_SIZE(list)) {
                     UPDATE_MISS_STATS(BINARY_OP);
                     assert(_PyOpcode_Deopt[opcode] == (BINARY_OP));
+                    #if _Py_TIER2
+                    tstate->interp->jit_state.specialize_counter++;
+                    #endif
                     JUMP_TO_PREDICTED(BINARY_OP);
                 }
                 STAT_INC(BINARY_OP, hit);
                 if (!PySlice_Check(o)) {
                     UPDATE_MISS_STATS(BINARY_OP);
                     assert(_PyOpcode_Deopt[opcode] == (BINARY_OP));
+                    #if _Py_TIER2
+                    tstate->interp->jit_state.specialize_counter++;
+                    #endif
                     JUMP_TO_PREDICTED(BINARY_OP);
                 }
             }
                 if (!PyList_CheckExact(o)) {
                     UPDATE_MISS_STATS(BINARY_OP);
                     assert(_PyOpcode_Deopt[opcode] == (BINARY_OP));
+                    #if _Py_TIER2
+                    tstate->interp->jit_state.specialize_counter++;
+                    #endif
                     JUMP_TO_PREDICTED(BINARY_OP);
                 }
             }
                 if (!_PyLong_CheckExactAndCompact(value_o)) {
                     UPDATE_MISS_STATS(BINARY_OP);
                     assert(_PyOpcode_Deopt[opcode] == (BINARY_OP));
+                    #if _Py_TIER2
+                    tstate->interp->jit_state.specialize_counter++;
+                    #endif
                     JUMP_TO_PREDICTED(BINARY_OP);
                 }
             }
                 if (!PyUnicode_CheckExact(o)) {
                     UPDATE_MISS_STATS(BINARY_OP);
                     assert(_PyOpcode_Deopt[opcode] == (BINARY_OP));
+                    #if _Py_TIER2
+                    tstate->interp->jit_state.specialize_counter++;
+                    #endif
                     JUMP_TO_PREDICTED(BINARY_OP);
                 }
             }
                 if (!_PyLong_IsNonNegativeCompact((PyLongObject *)sub)) {
                     UPDATE_MISS_STATS(BINARY_OP);
                     assert(_PyOpcode_Deopt[opcode] == (BINARY_OP));
+                    #if _Py_TIER2
+                    tstate->interp->jit_state.specialize_counter++;
+                    #endif
                     JUMP_TO_PREDICTED(BINARY_OP);
                 }
                 Py_ssize_t index = ((PyLongObject*)sub)->long_value.ob_digit[0];
                 if (PyUnicode_GET_LENGTH(str) <= index) {
                     UPDATE_MISS_STATS(BINARY_OP);
                     assert(_PyOpcode_Deopt[opcode] == (BINARY_OP));
+                    #if _Py_TIER2
+                    tstate->interp->jit_state.specialize_counter++;
+                    #endif
                     JUMP_TO_PREDICTED(BINARY_OP);
                 }
                 Py_UCS4 c = PyUnicode_READ_CHAR(str, index);
                 if (Py_ARRAY_LENGTH(_Py_SINGLETON(strings).ascii) <= c) {
                     UPDATE_MISS_STATS(BINARY_OP);
                     assert(_PyOpcode_Deopt[opcode] == (BINARY_OP));
+                    #if _Py_TIER2
+                    tstate->interp->jit_state.specialize_counter++;
+                    #endif
                     JUMP_TO_PREDICTED(BINARY_OP);
                 }
                 STAT_INC(BINARY_OP, hit);
                 if (!_PyLong_CheckExactAndCompact(value_o)) {
                     UPDATE_MISS_STATS(BINARY_OP);
                     assert(_PyOpcode_Deopt[opcode] == (BINARY_OP));
+                    #if _Py_TIER2
+                    tstate->interp->jit_state.specialize_counter++;
+                    #endif
                     JUMP_TO_PREDICTED(BINARY_OP);
                 }
             }
                 if (!PyTuple_CheckExact(o)) {
                     UPDATE_MISS_STATS(BINARY_OP);
                     assert(_PyOpcode_Deopt[opcode] == (BINARY_OP));
+                    #if _Py_TIER2
+                    tstate->interp->jit_state.specialize_counter++;
+                    #endif
                     JUMP_TO_PREDICTED(BINARY_OP);
                 }
             }
                 if (!_PyLong_IsNonNegativeCompact((PyLongObject *)sub)) {
                     UPDATE_MISS_STATS(BINARY_OP);
                     assert(_PyOpcode_Deopt[opcode] == (BINARY_OP));
+                    #if _Py_TIER2
+                    tstate->interp->jit_state.specialize_counter++;
+                    #endif
                     JUMP_TO_PREDICTED(BINARY_OP);
                 }
                 Py_ssize_t index = ((PyLongObject*)sub)->long_value.ob_digit[0];
                 if (index >= PyTuple_GET_SIZE(tuple)) {
                     UPDATE_MISS_STATS(BINARY_OP);
                     assert(_PyOpcode_Deopt[opcode] == (BINARY_OP));
+                    #if _Py_TIER2
+                    tstate->interp->jit_state.specialize_counter++;
+                    #endif
                     JUMP_TO_PREDICTED(BINARY_OP);
                 }
                 STAT_INC(BINARY_OP, hit);
                 if (!PyFloat_CheckExact(value_o)) {
                     UPDATE_MISS_STATS(BINARY_OP);
                     assert(_PyOpcode_Deopt[opcode] == (BINARY_OP));
+                    #if _Py_TIER2
+                    tstate->interp->jit_state.specialize_counter++;
+                    #endif
                     JUMP_TO_PREDICTED(BINARY_OP);
                 }
             }
                 if (!PyFloat_CheckExact(left_o)) {
                     UPDATE_MISS_STATS(BINARY_OP);
                     assert(_PyOpcode_Deopt[opcode] == (BINARY_OP));
+                    #if _Py_TIER2
+                    tstate->interp->jit_state.specialize_counter++;
+                    #endif
                     JUMP_TO_PREDICTED(BINARY_OP);
                 }
             }
                 if (!_PyLong_CheckExactAndCompact(value_o)) {
                     UPDATE_MISS_STATS(BINARY_OP);
                     assert(_PyOpcode_Deopt[opcode] == (BINARY_OP));
+                    #if _Py_TIER2
+                    tstate->interp->jit_state.specialize_counter++;
+                    #endif
                     JUMP_TO_PREDICTED(BINARY_OP);
                 }
             }
                 if (!_PyLong_CheckExactAndCompact(left_o)) {
                     UPDATE_MISS_STATS(BINARY_OP);
                     assert(_PyOpcode_Deopt[opcode] == (BINARY_OP));
+                    #if _Py_TIER2
+                    tstate->interp->jit_state.specialize_counter++;
+                    #endif
                     JUMP_TO_PREDICTED(BINARY_OP);
                 }
             }
                 if (PyStackRef_IsNull(res)) {
                     UPDATE_MISS_STATS(BINARY_OP);
                     assert(_PyOpcode_Deopt[opcode] == (BINARY_OP));
+                    #if _Py_TIER2
+                    tstate->interp->jit_state.specialize_counter++;
+                    #endif
                     JUMP_TO_PREDICTED(BINARY_OP);
                 }
                 PyStackRef_CLOSE_SPECIALIZED(right, _PyLong_ExactDealloc);
                 if (tstate->interp->eval_frame) {
                     UPDATE_MISS_STATS(CALL);
                     assert(_PyOpcode_Deopt[opcode] == (CALL));
+                    #if _Py_TIER2
+                    tstate->interp->jit_state.specialize_counter++;
+                    #endif
                     JUMP_TO_PREDICTED(CALL);
                 }
             }
                 if (!PyStackRef_IsNull(self_or_null)) {
                     UPDATE_MISS_STATS(CALL);
                     assert(_PyOpcode_Deopt[opcode] == (CALL));
+                    #if _Py_TIER2
+                    tstate->interp->jit_state.specialize_counter++;
+                    #endif
                     JUMP_TO_PREDICTED(CALL);
                 }
                 if (!PyType_Check(callable_o)) {
                     UPDATE_MISS_STATS(CALL);
                     assert(_PyOpcode_Deopt[opcode] == (CALL));
+                    #if _Py_TIER2
+                    tstate->interp->jit_state.specialize_counter++;
+                    #endif
                     JUMP_TO_PREDICTED(CALL);
                 }
                 PyTypeObject *tp = (PyTypeObject *)callable_o;
                 if (FT_ATOMIC_LOAD_UINT32_RELAXED(tp->tp_version_tag) != type_version) {
                     UPDATE_MISS_STATS(CALL);
                     assert(_PyOpcode_Deopt[opcode] == (CALL));
+                    #if _Py_TIER2
+                    tstate->interp->jit_state.specialize_counter++;
+                    #endif
                     JUMP_TO_PREDICTED(CALL);
                 }
                 assert(tp->tp_new == PyBaseObject_Type.tp_new);
                 if (!_PyThreadState_HasStackSpace(tstate, code->co_framesize + _Py_InitCleanup.co_framesize)) {
                     UPDATE_MISS_STATS(CALL);
                     assert(_PyOpcode_Deopt[opcode] == (CALL));
+                    #if _Py_TIER2
+                    tstate->interp->jit_state.specialize_counter++;
+                    #endif
                     JUMP_TO_PREDICTED(CALL);
                 }
                 STAT_INC(CALL, hit);
                 if (tstate->interp->eval_frame) {
                     UPDATE_MISS_STATS(CALL);
                     assert(_PyOpcode_Deopt[opcode] == (CALL));
+                    #if _Py_TIER2
+                    tstate->interp->jit_state.specialize_counter++;
+                    #endif
                     JUMP_TO_PREDICTED(CALL);
                 }
             }
                 if (!PyStackRef_IsNull(null)) {
                     UPDATE_MISS_STATS(CALL);
                     assert(_PyOpcode_Deopt[opcode] == (CALL));
+                    #if _Py_TIER2
+                    tstate->interp->jit_state.specialize_counter++;
+                    #endif
                     JUMP_TO_PREDICTED(CALL);
                 }
                 if (Py_TYPE(PyStackRef_AsPyObjectBorrow(callable)) != &PyMethod_Type) {
                     UPDATE_MISS_STATS(CALL);
                     assert(_PyOpcode_Deopt[opcode] == (CALL));
+                    #if _Py_TIER2
+                    tstate->interp->jit_state.specialize_counter++;
+                    #endif
                     JUMP_TO_PREDICTED(CALL);
                 }
             }
                 if (!PyFunction_Check(callable_o)) {
                     UPDATE_MISS_STATS(CALL);
                     assert(_PyOpcode_Deopt[opcode] == (CALL));
+                    #if _Py_TIER2
+                    tstate->interp->jit_state.specialize_counter++;
+                    #endif
                     JUMP_TO_PREDICTED(CALL);
                 }
                 PyFunctionObject *func = (PyFunctionObject *)callable_o;
                 if (func->func_version != func_version) {
                     UPDATE_MISS_STATS(CALL);
                     assert(_PyOpcode_Deopt[opcode] == (CALL));
+                    #if _Py_TIER2
+                    tstate->interp->jit_state.specialize_counter++;
+                    #endif
                     JUMP_TO_PREDICTED(CALL);
                 }
             }
                 if (code->co_argcount != oparg + (!PyStackRef_IsNull(self_or_null))) {
                     UPDATE_MISS_STATS(CALL);
                     assert(_PyOpcode_Deopt[opcode] == (CALL));
+                    #if _Py_TIER2
+                    tstate->interp->jit_state.specialize_counter++;
+                    #endif
                     JUMP_TO_PREDICTED(CALL);
                 }
             }
                 if (!_PyThreadState_HasStackSpace(tstate, code->co_framesize)) {
                     UPDATE_MISS_STATS(CALL);
                     assert(_PyOpcode_Deopt[opcode] == (CALL));
+                    #if _Py_TIER2
+                    tstate->interp->jit_state.specialize_counter++;
+                    #endif
                     JUMP_TO_PREDICTED(CALL);
                 }
             }
                 if (tstate->py_recursion_remaining <= 1) {
                     UPDATE_MISS_STATS(CALL);
                     assert(_PyOpcode_Deopt[opcode] == (CALL));
+                    #if _Py_TIER2
+                    tstate->interp->jit_state.specialize_counter++;
+                    #endif
                     JUMP_TO_PREDICTED(CALL);
                 }
             }
                 if (tstate->interp->eval_frame) {
                     UPDATE_MISS_STATS(CALL);
                     assert(_PyOpcode_Deopt[opcode] == (CALL));
+                    #if _Py_TIER2
+                    tstate->interp->jit_state.specialize_counter++;
+                    #endif
                     JUMP_TO_PREDICTED(CALL);
                 }
             }
                 if (Py_TYPE(callable_o) != &PyMethod_Type) {
                     UPDATE_MISS_STATS(CALL);
                     assert(_PyOpcode_Deopt[opcode] == (CALL));
+                    #if _Py_TIER2
+                    tstate->interp->jit_state.specialize_counter++;
+                    #endif
                     JUMP_TO_PREDICTED(CALL);
                 }
                 PyObject *func = ((PyMethodObject *)callable_o)->im_func;
                 if (!PyFunction_Check(func)) {
                     UPDATE_MISS_STATS(CALL);
                     assert(_PyOpcode_Deopt[opcode] == (CALL));
+                    #if _Py_TIER2
+                    tstate->interp->jit_state.specialize_counter++;
+                    #endif
                     JUMP_TO_PREDICTED(CALL);
                 }
                 if (((PyFunctionObject *)func)->func_version != func_version) {
                     UPDATE_MISS_STATS(CALL);
                     assert(_PyOpcode_Deopt[opcode] == (CALL));
+                    #if _Py_TIER2
+                    tstate->interp->jit_state.specialize_counter++;
+                    #endif
                     JUMP_TO_PREDICTED(CALL);
                 }
                 if (!PyStackRef_IsNull(null)) {
                     UPDATE_MISS_STATS(CALL);
                     assert(_PyOpcode_Deopt[opcode] == (CALL));
+                    #if _Py_TIER2
+                    tstate->interp->jit_state.specialize_counter++;
+                    #endif
                     JUMP_TO_PREDICTED(CALL);
                 }
             }
                 if (tstate->py_recursion_remaining <= 1) {
                     UPDATE_MISS_STATS(CALL);
                     assert(_PyOpcode_Deopt[opcode] == (CALL));
+                    #if _Py_TIER2
+                    tstate->interp->jit_state.specialize_counter++;
+                    #endif
                     JUMP_TO_PREDICTED(CALL);
                 }
             }
                 if (!PyType_Check(callable_o)) {
                     UPDATE_MISS_STATS(CALL);
                     assert(_PyOpcode_Deopt[opcode] == (CALL));
+                    #if _Py_TIER2
+                    tstate->interp->jit_state.specialize_counter++;
+                    #endif
                     JUMP_TO_PREDICTED(CALL);
                 }
                 PyTypeObject *tp = (PyTypeObject *)callable_o;
                 if (tp->tp_vectorcall == NULL) {
                     UPDATE_MISS_STATS(CALL);
                     assert(_PyOpcode_Deopt[opcode] == (CALL));
+                    #if _Py_TIER2
+                    tstate->interp->jit_state.specialize_counter++;
+                    #endif
                     JUMP_TO_PREDICTED(CALL);
                 }
                 STAT_INC(CALL, hit);
                 if (!PyCFunction_CheckExact(callable_o)) {
                     UPDATE_MISS_STATS(CALL);
                     assert(_PyOpcode_Deopt[opcode] == (CALL));
+                    #if _Py_TIER2
+                    tstate->interp->jit_state.specialize_counter++;
+                    #endif
                     JUMP_TO_PREDICTED(CALL);
                 }
                 if (PyCFunction_GET_FLAGS(callable_o) != METH_FASTCALL) {
                     UPDATE_MISS_STATS(CALL);
                     assert(_PyOpcode_Deopt[opcode] == (CALL));
+                    #if _Py_TIER2
+                    tstate->interp->jit_state.specialize_counter++;
+                    #endif
                     JUMP_TO_PREDICTED(CALL);
                 }
                 STAT_INC(CALL, hit);
                 if (!PyCFunction_CheckExact(callable_o)) {
                     UPDATE_MISS_STATS(CALL);
                     assert(_PyOpcode_Deopt[opcode] == (CALL));
+                    #if _Py_TIER2
+                    tstate->interp->jit_state.specialize_counter++;
+                    #endif
                     JUMP_TO_PREDICTED(CALL);
                 }
                 if (PyCFunction_GET_FLAGS(callable_o) != (METH_FASTCALL | METH_KEYWORDS)) {
                     UPDATE_MISS_STATS(CALL);
                     assert(_PyOpcode_Deopt[opcode] == (CALL));
+                    #if _Py_TIER2
+                    tstate->interp->jit_state.specialize_counter++;
+                    #endif
                     JUMP_TO_PREDICTED(CALL);
                 }
                 STAT_INC(CALL, hit);
                 if (total_args != 1) {
                     UPDATE_MISS_STATS(CALL);
                     assert(_PyOpcode_Deopt[opcode] == (CALL));
+                    #if _Py_TIER2
+                    tstate->interp->jit_state.specialize_counter++;
+                    #endif
                     JUMP_TO_PREDICTED(CALL);
                 }
                 if (!PyCFunction_CheckExact(callable_o)) {
                     UPDATE_MISS_STATS(CALL);
                     assert(_PyOpcode_Deopt[opcode] == (CALL));
+                    #if _Py_TIER2
+                    tstate->interp->jit_state.specialize_counter++;
+                    #endif
                     JUMP_TO_PREDICTED(CALL);
                 }
                 if (PyCFunction_GET_FLAGS(callable_o) != METH_O) {
                     UPDATE_MISS_STATS(CALL);
                     assert(_PyOpcode_Deopt[opcode] == (CALL));
+                    #if _Py_TIER2
+                    tstate->interp->jit_state.specialize_counter++;
+                    #endif
                     JUMP_TO_PREDICTED(CALL);
                 }
                 if (_Py_ReachedRecursionLimit(tstate)) {
                     UPDATE_MISS_STATS(CALL);
                     assert(_PyOpcode_Deopt[opcode] == (CALL));
+                    #if _Py_TIER2
+                    tstate->interp->jit_state.specialize_counter++;
+                    #endif
                     JUMP_TO_PREDICTED(CALL);
                 }
                 STAT_INC(CALL, hit);
                 if (!PyStackRef_IsNull(null)) {
                     UPDATE_MISS_STATS(CALL);
                     assert(_PyOpcode_Deopt[opcode] == (CALL));
+                    #if _Py_TIER2
+                    tstate->interp->jit_state.specialize_counter++;
+                    #endif
                     JUMP_TO_PREDICTED(CALL);
                 }
             }
                 if (callable_o != interp->callable_cache.isinstance) {
                     UPDATE_MISS_STATS(CALL);
                     assert(_PyOpcode_Deopt[opcode] == (CALL));
+                    #if _Py_TIER2
+                    tstate->interp->jit_state.specialize_counter++;
+                    #endif
                     JUMP_TO_PREDICTED(CALL);
                 }
             }
                 if (tstate->interp->eval_frame) {
                     UPDATE_MISS_STATS(CALL_KW);
                     assert(_PyOpcode_Deopt[opcode] == (CALL_KW));
+                    #if _Py_TIER2
+                    tstate->interp->jit_state.specialize_counter++;
+                    #endif
                     JUMP_TO_PREDICTED(CALL_KW);
                 }
             }
                 if (Py_TYPE(callable_o) != &PyMethod_Type) {
                     UPDATE_MISS_STATS(CALL_KW);
                     assert(_PyOpcode_Deopt[opcode] == (CALL_KW));
+                    #if _Py_TIER2
+                    tstate->interp->jit_state.specialize_counter++;
+                    #endif
                     JUMP_TO_PREDICTED(CALL_KW);
                 }
                 PyObject *func = ((PyMethodObject *)callable_o)->im_func;
                 if (!PyFunction_Check(func)) {
                     UPDATE_MISS_STATS(CALL_KW);
                     assert(_PyOpcode_Deopt[opcode] == (CALL_KW));
+                    #if _Py_TIER2
+                    tstate->interp->jit_state.specialize_counter++;
+                    #endif
                     JUMP_TO_PREDICTED(CALL_KW);
                 }
                 if (((PyFunctionObject *)func)->func_version != func_version) {
                     UPDATE_MISS_STATS(CALL_KW);
                     assert(_PyOpcode_Deopt[opcode] == (CALL_KW));
+                    #if _Py_TIER2
+                    tstate->interp->jit_state.specialize_counter++;
+                    #endif
                     JUMP_TO_PREDICTED(CALL_KW);
                 }
                 if (!PyStackRef_IsNull(null)) {
                     UPDATE_MISS_STATS(CALL_KW);
                     assert(_PyOpcode_Deopt[opcode] == (CALL_KW));
+                    #if _Py_TIER2
+                    tstate->interp->jit_state.specialize_counter++;
+                    #endif
                     JUMP_TO_PREDICTED(CALL_KW);
                 }
             }
                 if (PyFunction_Check(callable_o)) {
                     UPDATE_MISS_STATS(CALL_KW);
                     assert(_PyOpcode_Deopt[opcode] == (CALL_KW));
+                    #if _Py_TIER2
+                    tstate->interp->jit_state.specialize_counter++;
+                    #endif
                     JUMP_TO_PREDICTED(CALL_KW);
                 }
                 if (Py_TYPE(callable_o) == &PyMethod_Type) {
                     UPDATE_MISS_STATS(CALL_KW);
                     assert(_PyOpcode_Deopt[opcode] == (CALL_KW));
+                    #if _Py_TIER2
+                    tstate->interp->jit_state.specialize_counter++;
+                    #endif
                     JUMP_TO_PREDICTED(CALL_KW);
                 }
             }
                 if (tstate->interp->eval_frame) {
                     UPDATE_MISS_STATS(CALL_KW);
                     assert(_PyOpcode_Deopt[opcode] == (CALL_KW));
+                    #if _Py_TIER2
+                    tstate->interp->jit_state.specialize_counter++;
+                    #endif
                     JUMP_TO_PREDICTED(CALL_KW);
                 }
             }
                 if (!PyFunction_Check(callable_o)) {
                     UPDATE_MISS_STATS(CALL_KW);
                     assert(_PyOpcode_Deopt[opcode] == (CALL_KW));
+                    #if _Py_TIER2
+                    tstate->interp->jit_state.specialize_counter++;
+                    #endif
                     JUMP_TO_PREDICTED(CALL_KW);
                 }
                 PyFunctionObject *func = (PyFunctionObject *)callable_o;
                 if (func->func_version != func_version) {
                     UPDATE_MISS_STATS(CALL_KW);
                     assert(_PyOpcode_Deopt[opcode] == (CALL_KW));
+                    #if _Py_TIER2
+                    tstate->interp->jit_state.specialize_counter++;
+                    #endif
                     JUMP_TO_PREDICTED(CALL_KW);
                 }
             }
                 if (tstate->py_recursion_remaining <= 1) {
                     UPDATE_MISS_STATS(CALL_KW);
                     assert(_PyOpcode_Deopt[opcode] == (CALL_KW));
+                    #if _Py_TIER2
+                    tstate->interp->jit_state.specialize_counter++;
+                    #endif
                     JUMP_TO_PREDICTED(CALL_KW);
                 }
             }
                 if (!PyStackRef_IsNull(null)) {
                     UPDATE_MISS_STATS(CALL);
                     assert(_PyOpcode_Deopt[opcode] == (CALL));
+                    #if _Py_TIER2
+                    tstate->interp->jit_state.specialize_counter++;
+                    #endif
                     JUMP_TO_PREDICTED(CALL);
                 }
             }
                 if (callable_o != interp->callable_cache.len) {
                     UPDATE_MISS_STATS(CALL);
                     assert(_PyOpcode_Deopt[opcode] == (CALL));
+                    #if _Py_TIER2
+                    tstate->interp->jit_state.specialize_counter++;
+                    #endif
                     JUMP_TO_PREDICTED(CALL);
                 }
             }
                 if (callable_o != interp->callable_cache.list_append) {
                     UPDATE_MISS_STATS(CALL);
                     assert(_PyOpcode_Deopt[opcode] == (CALL));
+                    #if _Py_TIER2
+                    tstate->interp->jit_state.specialize_counter++;
+                    #endif
                     JUMP_TO_PREDICTED(CALL);
                 }
             }
                 if (o == NULL) {
                     UPDATE_MISS_STATS(CALL);
                     assert(_PyOpcode_Deopt[opcode] == (CALL));
+                    #if _Py_TIER2
+                    tstate->interp->jit_state.specialize_counter++;
+                    #endif
                     JUMP_TO_PREDICTED(CALL);
                 }
             }
                 if (!PyList_CheckExact(o)) {
                     UPDATE_MISS_STATS(CALL);
                     assert(_PyOpcode_Deopt[opcode] == (CALL));
+                    #if _Py_TIER2
+                    tstate->interp->jit_state.specialize_counter++;
+                    #endif
                     JUMP_TO_PREDICTED(CALL);
                 }
             }
                 if (!PyList_CheckExact(self_o)) {
                     UPDATE_MISS_STATS(CALL);
                     assert(_PyOpcode_Deopt[opcode] == (CALL));
+                    #if _Py_TIER2
+                    tstate->interp->jit_state.specialize_counter++;
+                    #endif
                     JUMP_TO_PREDICTED(CALL);
                 }
                 if (!LOCK_OBJECT(self_o)) {
                     UPDATE_MISS_STATS(CALL);
                     assert(_PyOpcode_Deopt[opcode] == (CALL));
+                    #if _Py_TIER2
+                    tstate->interp->jit_state.specialize_counter++;
+                    #endif
                     JUMP_TO_PREDICTED(CALL);
                 }
                 STAT_INC(CALL, hit);
                 if (total_args == 0) {
                     UPDATE_MISS_STATS(CALL);
                     assert(_PyOpcode_Deopt[opcode] == (CALL));
+                    #if _Py_TIER2
+                    tstate->interp->jit_state.specialize_counter++;
+                    #endif
                     JUMP_TO_PREDICTED(CALL);
                 }
                 PyMethodDescrObject *method = (PyMethodDescrObject *)callable_o;
                 if (!Py_IS_TYPE(method, &PyMethodDescr_Type)) {
                     UPDATE_MISS_STATS(CALL);
                     assert(_PyOpcode_Deopt[opcode] == (CALL));
+                    #if _Py_TIER2
+                    tstate->interp->jit_state.specialize_counter++;
+                    #endif
                     JUMP_TO_PREDICTED(CALL);
                 }
                 PyMethodDef *meth = method->d_method;
                 if (meth->ml_flags != METH_FASTCALL) {
                     UPDATE_MISS_STATS(CALL);
                     assert(_PyOpcode_Deopt[opcode] == (CALL));
+                    #if _Py_TIER2
+                    tstate->interp->jit_state.specialize_counter++;
+                    #endif
                     JUMP_TO_PREDICTED(CALL);
                 }
                 PyObject *self = PyStackRef_AsPyObjectBorrow(arguments[0]);
                 if (!Py_IS_TYPE(self, method->d_common.d_type)) {
                     UPDATE_MISS_STATS(CALL);
                     assert(_PyOpcode_Deopt[opcode] == (CALL));
+                    #if _Py_TIER2
+                    tstate->interp->jit_state.specialize_counter++;
+                    #endif
                     JUMP_TO_PREDICTED(CALL);
                 }
                 STAT_INC(CALL, hit);
                 if (total_args == 0) {
                     UPDATE_MISS_STATS(CALL);
                     assert(_PyOpcode_Deopt[opcode] == (CALL));
+                    #if _Py_TIER2
+                    tstate->interp->jit_state.specialize_counter++;
+                    #endif
                     JUMP_TO_PREDICTED(CALL);
                 }
                 PyMethodDescrObject *method = (PyMethodDescrObject *)callable_o;
                 if (!Py_IS_TYPE(method, &PyMethodDescr_Type)) {
                     UPDATE_MISS_STATS(CALL);
                     assert(_PyOpcode_Deopt[opcode] == (CALL));
+                    #if _Py_TIER2
+                    tstate->interp->jit_state.specialize_counter++;
+                    #endif
                     JUMP_TO_PREDICTED(CALL);
                 }
                 PyMethodDef *meth = method->d_method;
                 if (meth->ml_flags != (METH_FASTCALL|METH_KEYWORDS)) {
                     UPDATE_MISS_STATS(CALL);
                     assert(_PyOpcode_Deopt[opcode] == (CALL));
+                    #if _Py_TIER2
+                    tstate->interp->jit_state.specialize_counter++;
+                    #endif
                     JUMP_TO_PREDICTED(CALL);
                 }
                 PyTypeObject *d_type = method->d_common.d_type;
                 if (!Py_IS_TYPE(self, d_type)) {
                     UPDATE_MISS_STATS(CALL);
                     assert(_PyOpcode_Deopt[opcode] == (CALL));
+                    #if _Py_TIER2
+                    tstate->interp->jit_state.specialize_counter++;
+                    #endif
                     JUMP_TO_PREDICTED(CALL);
                 }
                 STAT_INC(CALL, hit);
                 if (total_args != 1) {
                     UPDATE_MISS_STATS(CALL);
                     assert(_PyOpcode_Deopt[opcode] == (CALL));
+                    #if _Py_TIER2
+                    tstate->interp->jit_state.specialize_counter++;
+                    #endif
                     JUMP_TO_PREDICTED(CALL);
                 }
                 PyMethodDescrObject *method = (PyMethodDescrObject *)callable_o;
                 if (!Py_IS_TYPE(method, &PyMethodDescr_Type)) {
                     UPDATE_MISS_STATS(CALL);
                     assert(_PyOpcode_Deopt[opcode] == (CALL));
+                    #if _Py_TIER2
+                    tstate->interp->jit_state.specialize_counter++;
+                    #endif
                     JUMP_TO_PREDICTED(CALL);
                 }
                 PyMethodDef *meth = method->d_method;
                 if (!Py_IS_TYPE(self, method->d_common.d_type)) {
                     UPDATE_MISS_STATS(CALL);
                     assert(_PyOpcode_Deopt[opcode] == (CALL));
+                    #if _Py_TIER2
+                    tstate->interp->jit_state.specialize_counter++;
+                    #endif
                     JUMP_TO_PREDICTED(CALL);
                 }
                 if (meth->ml_flags != METH_NOARGS) {
                     UPDATE_MISS_STATS(CALL);
                     assert(_PyOpcode_Deopt[opcode] == (CALL));
+                    #if _Py_TIER2
+                    tstate->interp->jit_state.specialize_counter++;
+                    #endif
                     JUMP_TO_PREDICTED(CALL);
                 }
                 if (_Py_ReachedRecursionLimit(tstate)) {
                     UPDATE_MISS_STATS(CALL);
                     assert(_PyOpcode_Deopt[opcode] == (CALL));
+                    #if _Py_TIER2
+                    tstate->interp->jit_state.specialize_counter++;
+                    #endif
                     JUMP_TO_PREDICTED(CALL);
                 }
                 STAT_INC(CALL, hit);
                 if (total_args != 2) {
                     UPDATE_MISS_STATS(CALL);
                     assert(_PyOpcode_Deopt[opcode] == (CALL));
+                    #if _Py_TIER2
+                    tstate->interp->jit_state.specialize_counter++;
+                    #endif
                     JUMP_TO_PREDICTED(CALL);
                 }
                 if (!Py_IS_TYPE(method, &PyMethodDescr_Type)) {
                     UPDATE_MISS_STATS(CALL);
                     assert(_PyOpcode_Deopt[opcode] == (CALL));
+                    #if _Py_TIER2
+                    tstate->interp->jit_state.specialize_counter++;
+                    #endif
                     JUMP_TO_PREDICTED(CALL);
                 }
                 PyMethodDef *meth = method->d_method;
                 if (meth->ml_flags != METH_O) {
                     UPDATE_MISS_STATS(CALL);
                     assert(_PyOpcode_Deopt[opcode] == (CALL));
+                    #if _Py_TIER2
+                    tstate->interp->jit_state.specialize_counter++;
+                    #endif
                     JUMP_TO_PREDICTED(CALL);
                 }
                 if (_Py_ReachedRecursionLimit(tstate)) {
                     UPDATE_MISS_STATS(CALL);
                     assert(_PyOpcode_Deopt[opcode] == (CALL));
+                    #if _Py_TIER2
+                    tstate->interp->jit_state.specialize_counter++;
+                    #endif
                     JUMP_TO_PREDICTED(CALL);
                 }
                 _PyStackRef arg_stackref = arguments[1];
                                 method->d_common.d_type)) {
                     UPDATE_MISS_STATS(CALL);
                     assert(_PyOpcode_Deopt[opcode] == (CALL));
+                    #if _Py_TIER2
+                    tstate->interp->jit_state.specialize_counter++;
+                    #endif
                     JUMP_TO_PREDICTED(CALL);
                 }
                 STAT_INC(CALL, hit);
                 if (PyFunction_Check(callable_o)) {
                     UPDATE_MISS_STATS(CALL);
                     assert(_PyOpcode_Deopt[opcode] == (CALL));
+                    #if _Py_TIER2
+                    tstate->interp->jit_state.specialize_counter++;
+                    #endif
                     JUMP_TO_PREDICTED(CALL);
                 }
                 if (Py_TYPE(callable_o) == &PyMethod_Type) {
                     UPDATE_MISS_STATS(CALL);
                     assert(_PyOpcode_Deopt[opcode] == (CALL));
+                    #if _Py_TIER2
+                    tstate->interp->jit_state.specialize_counter++;
+                    #endif
                     JUMP_TO_PREDICTED(CALL);
                 }
             }
                 if (tstate->interp->eval_frame) {
                     UPDATE_MISS_STATS(CALL);
                     assert(_PyOpcode_Deopt[opcode] == (CALL));
+                    #if _Py_TIER2
+                    tstate->interp->jit_state.specialize_counter++;
+                    #endif
                     JUMP_TO_PREDICTED(CALL);
                 }
             }
                 if (!PyFunction_Check(callable_o)) {
                     UPDATE_MISS_STATS(CALL);
                     assert(_PyOpcode_Deopt[opcode] == (CALL));
+                    #if _Py_TIER2
+                    tstate->interp->jit_state.specialize_counter++;
+                    #endif
                     JUMP_TO_PREDICTED(CALL);
                 }
                 PyFunctionObject *func = (PyFunctionObject *)callable_o;
                 if (func->func_version != func_version) {
                     UPDATE_MISS_STATS(CALL);
                     assert(_PyOpcode_Deopt[opcode] == (CALL));
+                    #if _Py_TIER2
+                    tstate->interp->jit_state.specialize_counter++;
+                    #endif
                     JUMP_TO_PREDICTED(CALL);
                 }
             }
                 if (code->co_argcount != oparg + (!PyStackRef_IsNull(self_or_null))) {
                     UPDATE_MISS_STATS(CALL);
                     assert(_PyOpcode_Deopt[opcode] == (CALL));
+                    #if _Py_TIER2
+                    tstate->interp->jit_state.specialize_counter++;
+                    #endif
                     JUMP_TO_PREDICTED(CALL);
                 }
             }
                 if (!_PyThreadState_HasStackSpace(tstate, code->co_framesize)) {
                     UPDATE_MISS_STATS(CALL);
                     assert(_PyOpcode_Deopt[opcode] == (CALL));
+                    #if _Py_TIER2
+                    tstate->interp->jit_state.specialize_counter++;
+                    #endif
                     JUMP_TO_PREDICTED(CALL);
                 }
             }
                 if (tstate->py_recursion_remaining <= 1) {
                     UPDATE_MISS_STATS(CALL);
                     assert(_PyOpcode_Deopt[opcode] == (CALL));
+                    #if _Py_TIER2
+                    tstate->interp->jit_state.specialize_counter++;
+                    #endif
                     JUMP_TO_PREDICTED(CALL);
                 }
             }
                 if (tstate->interp->eval_frame) {
                     UPDATE_MISS_STATS(CALL);
                     assert(_PyOpcode_Deopt[opcode] == (CALL));
+                    #if _Py_TIER2
+                    tstate->interp->jit_state.specialize_counter++;
+                    #endif
                     JUMP_TO_PREDICTED(CALL);
                 }
             }
                 if (!PyFunction_Check(callable_o)) {
                     UPDATE_MISS_STATS(CALL);
                     assert(_PyOpcode_Deopt[opcode] == (CALL));
+                    #if _Py_TIER2
+                    tstate->interp->jit_state.specialize_counter++;
+                    #endif
                     JUMP_TO_PREDICTED(CALL);
                 }
                 PyFunctionObject *func = (PyFunctionObject *)callable_o;
                 if (func->func_version != func_version) {
                     UPDATE_MISS_STATS(CALL);
                     assert(_PyOpcode_Deopt[opcode] == (CALL));
+                    #if _Py_TIER2
+                    tstate->interp->jit_state.specialize_counter++;
+                    #endif
                     JUMP_TO_PREDICTED(CALL);
                 }
             }
                 if (tstate->py_recursion_remaining <= 1) {
                     UPDATE_MISS_STATS(CALL);
                     assert(_PyOpcode_Deopt[opcode] == (CALL));
+                    #if _Py_TIER2
+                    tstate->interp->jit_state.specialize_counter++;
+                    #endif
                     JUMP_TO_PREDICTED(CALL);
                 }
             }
                 if (!PyStackRef_IsNull(null)) {
                     UPDATE_MISS_STATS(CALL);
                     assert(_PyOpcode_Deopt[opcode] == (CALL));
+                    #if _Py_TIER2
+                    tstate->interp->jit_state.specialize_counter++;
+                    #endif
                     JUMP_TO_PREDICTED(CALL);
                 }
             }
                 if (callable_o != (PyObject *)&PyUnicode_Type) {
                     UPDATE_MISS_STATS(CALL);
                     assert(_PyOpcode_Deopt[opcode] == (CALL));
+                    #if _Py_TIER2
+                    tstate->interp->jit_state.specialize_counter++;
+                    #endif
                     JUMP_TO_PREDICTED(CALL);
                 }
             }
                 if (!PyStackRef_IsNull(null)) {
                     UPDATE_MISS_STATS(CALL);
                     assert(_PyOpcode_Deopt[opcode] == (CALL));
+                    #if _Py_TIER2
+                    tstate->interp->jit_state.specialize_counter++;
+                    #endif
                     JUMP_TO_PREDICTED(CALL);
                 }
             }
                 if (callable_o != (PyObject *)&PyTuple_Type) {
                     UPDATE_MISS_STATS(CALL);
                     assert(_PyOpcode_Deopt[opcode] == (CALL));
+                    #if _Py_TIER2
+                    tstate->interp->jit_state.specialize_counter++;
+                    #endif
                     JUMP_TO_PREDICTED(CALL);
                 }
             }
                 if (!PyStackRef_IsNull(null)) {
                     UPDATE_MISS_STATS(CALL);
                     assert(_PyOpcode_Deopt[opcode] == (CALL));
+                    #if _Py_TIER2
+                    tstate->interp->jit_state.specialize_counter++;
+                    #endif
                     JUMP_TO_PREDICTED(CALL);
                 }
             }
                 if (callable_o != (PyObject *)&PyType_Type) {
                     UPDATE_MISS_STATS(CALL);
                     assert(_PyOpcode_Deopt[opcode] == (CALL));
+                    #if _Py_TIER2
+                    tstate->interp->jit_state.specialize_counter++;
+                    #endif
                     JUMP_TO_PREDICTED(CALL);
                 }
             }
                 if (!PyFloat_CheckExact(value_o)) {
                     UPDATE_MISS_STATS(COMPARE_OP);
                     assert(_PyOpcode_Deopt[opcode] == (COMPARE_OP));
+                    #if _Py_TIER2
+                    tstate->interp->jit_state.specialize_counter++;
+                    #endif
                     JUMP_TO_PREDICTED(COMPARE_OP);
                 }
             }
                 if (!PyFloat_CheckExact(left_o)) {
                     UPDATE_MISS_STATS(COMPARE_OP);
                     assert(_PyOpcode_Deopt[opcode] == (COMPARE_OP));
+                    #if _Py_TIER2
+                    tstate->interp->jit_state.specialize_counter++;
+                    #endif
                     JUMP_TO_PREDICTED(COMPARE_OP);
                 }
             }
                 if (!_PyLong_CheckExactAndCompact(value_o)) {
                     UPDATE_MISS_STATS(COMPARE_OP);
                     assert(_PyOpcode_Deopt[opcode] == (COMPARE_OP));
+                    #if _Py_TIER2
+                    tstate->interp->jit_state.specialize_counter++;
+                    #endif
                     JUMP_TO_PREDICTED(COMPARE_OP);
                 }
             }
                 if (!_PyLong_CheckExactAndCompact(left_o)) {
                     UPDATE_MISS_STATS(COMPARE_OP);
                     assert(_PyOpcode_Deopt[opcode] == (COMPARE_OP));
+                    #if _Py_TIER2
+                    tstate->interp->jit_state.specialize_counter++;
+                    #endif
                     JUMP_TO_PREDICTED(COMPARE_OP);
                 }
             }
                 if (!PyUnicode_CheckExact(value_o)) {
                     UPDATE_MISS_STATS(COMPARE_OP);
                     assert(_PyOpcode_Deopt[opcode] == (COMPARE_OP));
+                    #if _Py_TIER2
+                    tstate->interp->jit_state.specialize_counter++;
+                    #endif
                     JUMP_TO_PREDICTED(COMPARE_OP);
                 }
             }
                 if (!PyUnicode_CheckExact(o)) {
                     UPDATE_MISS_STATS(COMPARE_OP);
                     assert(_PyOpcode_Deopt[opcode] == (COMPARE_OP));
+                    #if _Py_TIER2
+                    tstate->interp->jit_state.specialize_counter++;
+                    #endif
                     JUMP_TO_PREDICTED(COMPARE_OP);
                 }
             }
                 if (!PyDict_CheckExact(o)) {
                     UPDATE_MISS_STATS(CONTAINS_OP);
                     assert(_PyOpcode_Deopt[opcode] == (CONTAINS_OP));
+                    #if _Py_TIER2
+                    tstate->interp->jit_state.specialize_counter++;
+                    #endif
                     JUMP_TO_PREDICTED(CONTAINS_OP);
                 }
             }
                 if (!PyAnySet_CheckExact(o)) {
                     UPDATE_MISS_STATS(CONTAINS_OP);
                     assert(_PyOpcode_Deopt[opcode] == (CONTAINS_OP));
+                    #if _Py_TIER2
+                    tstate->interp->jit_state.specialize_counter++;
+                    #endif
                     JUMP_TO_PREDICTED(CONTAINS_OP);
                 }
             }
                 if (tstate->interp->eval_frame) {
                     UPDATE_MISS_STATS(FOR_ITER);
                     assert(_PyOpcode_Deopt[opcode] == (FOR_ITER));
+                    #if _Py_TIER2
+                    tstate->interp->jit_state.specialize_counter++;
+                    #endif
                     JUMP_TO_PREDICTED(FOR_ITER);
                 }
             }
                 if (Py_TYPE(gen) != &PyGen_Type) {
                     UPDATE_MISS_STATS(FOR_ITER);
                     assert(_PyOpcode_Deopt[opcode] == (FOR_ITER));
+                    #if _Py_TIER2
+                    tstate->interp->jit_state.specialize_counter++;
+                    #endif
                     JUMP_TO_PREDICTED(FOR_ITER);
                 }
                 #ifdef Py_GIL_DISABLED
                 if (!_PyObject_IsUniquelyReferenced((PyObject *)gen)) {
                     UPDATE_MISS_STATS(FOR_ITER);
                     assert(_PyOpcode_Deopt[opcode] == (FOR_ITER));
+                    #if _Py_TIER2
+                    tstate->interp->jit_state.specialize_counter++;
+                    #endif
                     JUMP_TO_PREDICTED(FOR_ITER);
                 }
                 #endif
                 if (gen->gi_frame_state >= FRAME_EXECUTING) {
                     UPDATE_MISS_STATS(FOR_ITER);
                     assert(_PyOpcode_Deopt[opcode] == (FOR_ITER));
+                    #if _Py_TIER2
+                    tstate->interp->jit_state.specialize_counter++;
+                    #endif
                     JUMP_TO_PREDICTED(FOR_ITER);
                 }
                 STAT_INC(FOR_ITER, hit);
                 if (Py_TYPE(iter_o) != &PyList_Type) {
                     UPDATE_MISS_STATS(FOR_ITER);
                     assert(_PyOpcode_Deopt[opcode] == (FOR_ITER));
+                    #if _Py_TIER2
+                    tstate->interp->jit_state.specialize_counter++;
+                    #endif
                     JUMP_TO_PREDICTED(FOR_ITER);
                 }
                 assert(PyStackRef_IsTaggedInt(null_or_index));
                 if (!_Py_IsOwnedByCurrentThread(iter_o) && !_PyObject_GC_IS_SHARED(iter_o)) {
                     UPDATE_MISS_STATS(FOR_ITER);
                     assert(_PyOpcode_Deopt[opcode] == (FOR_ITER));
+                    #if _Py_TIER2
+                    tstate->interp->jit_state.specialize_counter++;
+                    #endif
                     JUMP_TO_PREDICTED(FOR_ITER);
                 }
                 #endif
                 if (result < 0) {
                     UPDATE_MISS_STATS(FOR_ITER);
                     assert(_PyOpcode_Deopt[opcode] == (FOR_ITER));
+                    #if _Py_TIER2
+                    tstate->interp->jit_state.specialize_counter++;
+                    #endif
                     JUMP_TO_PREDICTED(FOR_ITER);
                 }
                 if (result == 0) {
                 if (Py_TYPE(r) != &PyRangeIter_Type) {
                     UPDATE_MISS_STATS(FOR_ITER);
                     assert(_PyOpcode_Deopt[opcode] == (FOR_ITER));
+                    #if _Py_TIER2
+                    tstate->interp->jit_state.specialize_counter++;
+                    #endif
                     JUMP_TO_PREDICTED(FOR_ITER);
                 }
                 #ifdef Py_GIL_DISABLED
                 if (!_PyObject_IsUniquelyReferenced((PyObject *)r)) {
                     UPDATE_MISS_STATS(FOR_ITER);
                     assert(_PyOpcode_Deopt[opcode] == (FOR_ITER));
+                    #if _Py_TIER2
+                    tstate->interp->jit_state.specialize_counter++;
+                    #endif
                     JUMP_TO_PREDICTED(FOR_ITER);
                 }
                 #endif
                 if (Py_TYPE(iter_o) != &PyTuple_Type) {
                     UPDATE_MISS_STATS(FOR_ITER);
                     assert(_PyOpcode_Deopt[opcode] == (FOR_ITER));
+                    #if _Py_TIER2
+                    tstate->interp->jit_state.specialize_counter++;
+                    #endif
                     JUMP_TO_PREDICTED(FOR_ITER);
                 }
                 assert(PyStackRef_IsTaggedInt(null_or_index));
                 if (!PyType_Check(owner_o)) {
                     UPDATE_MISS_STATS(LOAD_ATTR);
                     assert(_PyOpcode_Deopt[opcode] == (LOAD_ATTR));
+                    #if _Py_TIER2
+                    tstate->interp->jit_state.specialize_counter++;
+                    #endif
                     JUMP_TO_PREDICTED(LOAD_ATTR);
                 }
                 assert(type_version != 0);
                 if (FT_ATOMIC_LOAD_UINT_RELAXED(((PyTypeObject *)owner_o)->tp_version_tag) != type_version) {
                     UPDATE_MISS_STATS(LOAD_ATTR);
                     assert(_PyOpcode_Deopt[opcode] == (LOAD_ATTR));
+                    #if _Py_TIER2
+                    tstate->interp->jit_state.specialize_counter++;
+                    #endif
                     JUMP_TO_PREDICTED(LOAD_ATTR);
                 }
             }
                 if (!PyType_Check(owner_o)) {
                     UPDATE_MISS_STATS(LOAD_ATTR);
                     assert(_PyOpcode_Deopt[opcode] == (LOAD_ATTR));
+                    #if _Py_TIER2
+                    tstate->interp->jit_state.specialize_counter++;
+                    #endif
                     JUMP_TO_PREDICTED(LOAD_ATTR);
                 }
                 assert(type_version != 0);
                 if (FT_ATOMIC_LOAD_UINT_RELAXED(((PyTypeObject *)owner_o)->tp_version_tag) != type_version) {
                     UPDATE_MISS_STATS(LOAD_ATTR);
                     assert(_PyOpcode_Deopt[opcode] == (LOAD_ATTR));
+                    #if _Py_TIER2
+                    tstate->interp->jit_state.specialize_counter++;
+                    #endif
                     JUMP_TO_PREDICTED(LOAD_ATTR);
                 }
             }
                 if (FT_ATOMIC_LOAD_UINT_RELAXED(tp->tp_version_tag) != type_version) {
                     UPDATE_MISS_STATS(LOAD_ATTR);
                     assert(_PyOpcode_Deopt[opcode] == (LOAD_ATTR));
+                    #if _Py_TIER2
+                    tstate->interp->jit_state.specialize_counter++;
+                    #endif
                     JUMP_TO_PREDICTED(LOAD_ATTR);
                 }
             }
             if (tstate->interp->eval_frame) {
                 UPDATE_MISS_STATS(LOAD_ATTR);
                 assert(_PyOpcode_Deopt[opcode] == (LOAD_ATTR));
+                #if _Py_TIER2
+                tstate->interp->jit_state.specialize_counter++;
+                #endif
                 JUMP_TO_PREDICTED(LOAD_ATTR);
             }
             PyTypeObject *cls = Py_TYPE(owner_o);
             if (FT_ATOMIC_LOAD_UINT_RELAXED(cls->tp_version_tag) != type_version) {
                 UPDATE_MISS_STATS(LOAD_ATTR);
                 assert(_PyOpcode_Deopt[opcode] == (LOAD_ATTR));
+                #if _Py_TIER2
+                tstate->interp->jit_state.specialize_counter++;
+                #endif
                 JUMP_TO_PREDICTED(LOAD_ATTR);
             }
             assert(Py_IS_TYPE(getattribute, &PyFunction_Type));
             if (f->func_version != func_version) {
                 UPDATE_MISS_STATS(LOAD_ATTR);
                 assert(_PyOpcode_Deopt[opcode] == (LOAD_ATTR));
+                #if _Py_TIER2
+                tstate->interp->jit_state.specialize_counter++;
+                #endif
                 JUMP_TO_PREDICTED(LOAD_ATTR);
             }
             PyCodeObject *code = (PyCodeObject *)f->func_code;
             if (!_PyThreadState_HasStackSpace(tstate, code->co_framesize)) {
                 UPDATE_MISS_STATS(LOAD_ATTR);
                 assert(_PyOpcode_Deopt[opcode] == (LOAD_ATTR));
+                #if _Py_TIER2
+                tstate->interp->jit_state.specialize_counter++;
+                #endif
                 JUMP_TO_PREDICTED(LOAD_ATTR);
             }
             STAT_INC(LOAD_ATTR, hit);
                 if (FT_ATOMIC_LOAD_UINT_RELAXED(tp->tp_version_tag) != type_version) {
                     UPDATE_MISS_STATS(LOAD_ATTR);
                     assert(_PyOpcode_Deopt[opcode] == (LOAD_ATTR));
+                    #if _Py_TIER2
+                    tstate->interp->jit_state.specialize_counter++;
+                    #endif
                     JUMP_TO_PREDICTED(LOAD_ATTR);
                 }
             }
                 if (!FT_ATOMIC_LOAD_UINT8(_PyObject_InlineValues(owner_o)->valid)) {
                     UPDATE_MISS_STATS(LOAD_ATTR);
                     assert(_PyOpcode_Deopt[opcode] == (LOAD_ATTR));
+                    #if _Py_TIER2
+                    tstate->interp->jit_state.specialize_counter++;
+                    #endif
                     JUMP_TO_PREDICTED(LOAD_ATTR);
                 }
             }
                 if (attr_o == NULL) {
                     UPDATE_MISS_STATS(LOAD_ATTR);
                     assert(_PyOpcode_Deopt[opcode] == (LOAD_ATTR));
+                    #if _Py_TIER2
+                    tstate->interp->jit_state.specialize_counter++;
+                    #endif
                     JUMP_TO_PREDICTED(LOAD_ATTR);
                 }
                 #ifdef Py_GIL_DISABLED
                     if (true) {
                         UPDATE_MISS_STATS(LOAD_ATTR);
                         assert(_PyOpcode_Deopt[opcode] == (LOAD_ATTR));
+                        #if _Py_TIER2
+                        tstate->interp->jit_state.specialize_counter++;
+                        #endif
                         JUMP_TO_PREDICTED(LOAD_ATTR);
                     }
                 }
                 if (FT_ATOMIC_LOAD_UINT_RELAXED(tp->tp_version_tag) != type_version) {
                     UPDATE_MISS_STATS(LOAD_ATTR);
                     assert(_PyOpcode_Deopt[opcode] == (LOAD_ATTR));
+                    #if _Py_TIER2
+                    tstate->interp->jit_state.specialize_counter++;
+                    #endif
                     JUMP_TO_PREDICTED(LOAD_ATTR);
                 }
             }
                 if (dict != NULL) {
                     UPDATE_MISS_STATS(LOAD_ATTR);
                     assert(_PyOpcode_Deopt[opcode] == (LOAD_ATTR));
+                    #if _Py_TIER2
+                    tstate->interp->jit_state.specialize_counter++;
+                    #endif
                     JUMP_TO_PREDICTED(LOAD_ATTR);
                 }
             }
                 if (FT_ATOMIC_LOAD_UINT_RELAXED(tp->tp_version_tag) != type_version) {
                     UPDATE_MISS_STATS(LOAD_ATTR);
                     assert(_PyOpcode_Deopt[opcode] == (LOAD_ATTR));
+                    #if _Py_TIER2
+                    tstate->interp->jit_state.specialize_counter++;
+                    #endif
                     JUMP_TO_PREDICTED(LOAD_ATTR);
                 }
             }
                 if (FT_ATOMIC_LOAD_UINT_RELAXED(tp->tp_version_tag) != type_version) {
                     UPDATE_MISS_STATS(LOAD_ATTR);
                     assert(_PyOpcode_Deopt[opcode] == (LOAD_ATTR));
+                    #if _Py_TIER2
+                    tstate->interp->jit_state.specialize_counter++;
+                    #endif
                     JUMP_TO_PREDICTED(LOAD_ATTR);
                 }
             }
                 if (!FT_ATOMIC_LOAD_UINT8(ivs->valid)) {
                     UPDATE_MISS_STATS(LOAD_ATTR);
                     assert(_PyOpcode_Deopt[opcode] == (LOAD_ATTR));
+                    #if _Py_TIER2
+                    tstate->interp->jit_state.specialize_counter++;
+                    #endif
                     JUMP_TO_PREDICTED(LOAD_ATTR);
                 }
             }
                 if (FT_ATOMIC_LOAD_UINT32_RELAXED(keys->dk_version) != keys_version) {
                     UPDATE_MISS_STATS(LOAD_ATTR);
                     assert(_PyOpcode_Deopt[opcode] == (LOAD_ATTR));
+                    #if _Py_TIER2
+                    tstate->interp->jit_state.specialize_counter++;
+                    #endif
                     JUMP_TO_PREDICTED(LOAD_ATTR);
                 }
             }
                 if (Py_TYPE(owner_o)->tp_getattro != PyModule_Type.tp_getattro) {
                     UPDATE_MISS_STATS(LOAD_ATTR);
                     assert(_PyOpcode_Deopt[opcode] == (LOAD_ATTR));
+                    #if _Py_TIER2
+                    tstate->interp->jit_state.specialize_counter++;
+                    #endif
                     JUMP_TO_PREDICTED(LOAD_ATTR);
                 }
                 PyDictObject *dict = (PyDictObject *)((PyModuleObject *)owner_o)->md_dict;
                 if (FT_ATOMIC_LOAD_UINT32_RELAXED(keys->dk_version) != dict_version) {
                     UPDATE_MISS_STATS(LOAD_ATTR);
                     assert(_PyOpcode_Deopt[opcode] == (LOAD_ATTR));
+                    #if _Py_TIER2
+                    tstate->interp->jit_state.specialize_counter++;
+                    #endif
                     JUMP_TO_PREDICTED(LOAD_ATTR);
                 }
                 assert(keys->dk_kind == DICT_KEYS_UNICODE);
                 if (attr_o == NULL) {
                     UPDATE_MISS_STATS(LOAD_ATTR);
                     assert(_PyOpcode_Deopt[opcode] == (LOAD_ATTR));
+                    #if _Py_TIER2
+                    tstate->interp->jit_state.specialize_counter++;
+                    #endif
                     JUMP_TO_PREDICTED(LOAD_ATTR);
                 }
                 #ifdef Py_GIL_DISABLED
                     if (true) {
                         UPDATE_MISS_STATS(LOAD_ATTR);
                         assert(_PyOpcode_Deopt[opcode] == (LOAD_ATTR));
+                        #if _Py_TIER2
+                        tstate->interp->jit_state.specialize_counter++;
+                        #endif
                         JUMP_TO_PREDICTED(LOAD_ATTR);
                     }
                 }
                 if (FT_ATOMIC_LOAD_UINT_RELAXED(tp->tp_version_tag) != type_version) {
                     UPDATE_MISS_STATS(LOAD_ATTR);
                     assert(_PyOpcode_Deopt[opcode] == (LOAD_ATTR));
+                    #if _Py_TIER2
+                    tstate->interp->jit_state.specialize_counter++;
+                    #endif
                     JUMP_TO_PREDICTED(LOAD_ATTR);
                 }
             }
                 if (FT_ATOMIC_LOAD_UINT_RELAXED(tp->tp_version_tag) != type_version) {
                     UPDATE_MISS_STATS(LOAD_ATTR);
                     assert(_PyOpcode_Deopt[opcode] == (LOAD_ATTR));
+                    #if _Py_TIER2
+                    tstate->interp->jit_state.specialize_counter++;
+                    #endif
                     JUMP_TO_PREDICTED(LOAD_ATTR);
                 }
             }
                 if (!FT_ATOMIC_LOAD_UINT8(ivs->valid)) {
                     UPDATE_MISS_STATS(LOAD_ATTR);
                     assert(_PyOpcode_Deopt[opcode] == (LOAD_ATTR));
+                    #if _Py_TIER2
+                    tstate->interp->jit_state.specialize_counter++;
+                    #endif
                     JUMP_TO_PREDICTED(LOAD_ATTR);
                 }
             }
                 if (FT_ATOMIC_LOAD_UINT32_RELAXED(keys->dk_version) != keys_version) {
                     UPDATE_MISS_STATS(LOAD_ATTR);
                     assert(_PyOpcode_Deopt[opcode] == (LOAD_ATTR));
+                    #if _Py_TIER2
+                    tstate->interp->jit_state.specialize_counter++;
+                    #endif
                     JUMP_TO_PREDICTED(LOAD_ATTR);
                 }
             }
                 if (tstate->interp->eval_frame) {
                     UPDATE_MISS_STATS(LOAD_ATTR);
                     assert(_PyOpcode_Deopt[opcode] == (LOAD_ATTR));
+                    #if _Py_TIER2
+                    tstate->interp->jit_state.specialize_counter++;
+                    #endif
                     JUMP_TO_PREDICTED(LOAD_ATTR);
                 }
             }
                 if (FT_ATOMIC_LOAD_UINT_RELAXED(tp->tp_version_tag) != type_version) {
                     UPDATE_MISS_STATS(LOAD_ATTR);
                     assert(_PyOpcode_Deopt[opcode] == (LOAD_ATTR));
+                    #if _Py_TIER2
+                    tstate->interp->jit_state.specialize_counter++;
+                    #endif
                     JUMP_TO_PREDICTED(LOAD_ATTR);
                 }
             }
                 if ((code->co_flags & (CO_VARKEYWORDS | CO_VARARGS | CO_OPTIMIZED)) != CO_OPTIMIZED) {
                     UPDATE_MISS_STATS(LOAD_ATTR);
                     assert(_PyOpcode_Deopt[opcode] == (LOAD_ATTR));
+                    #if _Py_TIER2
+                    tstate->interp->jit_state.specialize_counter++;
+                    #endif
                     JUMP_TO_PREDICTED(LOAD_ATTR);
                 }
                 if (code->co_kwonlyargcount) {
                     UPDATE_MISS_STATS(LOAD_ATTR);
                     assert(_PyOpcode_Deopt[opcode] == (LOAD_ATTR));
+                    #if _Py_TIER2
+                    tstate->interp->jit_state.specialize_counter++;
+                    #endif
                     JUMP_TO_PREDICTED(LOAD_ATTR);
                 }
                 if (code->co_argcount != 1) {
                     UPDATE_MISS_STATS(LOAD_ATTR);
                     assert(_PyOpcode_Deopt[opcode] == (LOAD_ATTR));
+                    #if _Py_TIER2
+                    tstate->interp->jit_state.specialize_counter++;
+                    #endif
                     JUMP_TO_PREDICTED(LOAD_ATTR);
                 }
                 if (!_PyThreadState_HasStackSpace(tstate, code->co_framesize)) {
                     UPDATE_MISS_STATS(LOAD_ATTR);
                     assert(_PyOpcode_Deopt[opcode] == (LOAD_ATTR));
+                    #if _Py_TIER2
+                    tstate->interp->jit_state.specialize_counter++;
+                    #endif
                     JUMP_TO_PREDICTED(LOAD_ATTR);
                 }
                 STAT_INC(LOAD_ATTR, hit);
                 if (FT_ATOMIC_LOAD_UINT_RELAXED(tp->tp_version_tag) != type_version) {
                     UPDATE_MISS_STATS(LOAD_ATTR);
                     assert(_PyOpcode_Deopt[opcode] == (LOAD_ATTR));
+                    #if _Py_TIER2
+                    tstate->interp->jit_state.specialize_counter++;
+                    #endif
                     JUMP_TO_PREDICTED(LOAD_ATTR);
                 }
             }
                 if (attr_o == NULL) {
                     UPDATE_MISS_STATS(LOAD_ATTR);
                     assert(_PyOpcode_Deopt[opcode] == (LOAD_ATTR));
+                    #if _Py_TIER2
+                    tstate->interp->jit_state.specialize_counter++;
+                    #endif
                     JUMP_TO_PREDICTED(LOAD_ATTR);
                 }
                 #ifdef Py_GIL_DISABLED
                 if (!increfed) {
                     UPDATE_MISS_STATS(LOAD_ATTR);
                     assert(_PyOpcode_Deopt[opcode] == (LOAD_ATTR));
+                    #if _Py_TIER2
+                    tstate->interp->jit_state.specialize_counter++;
+                    #endif
                     JUMP_TO_PREDICTED(LOAD_ATTR);
                 }
                 #else
                 if (FT_ATOMIC_LOAD_UINT_RELAXED(tp->tp_version_tag) != type_version) {
                     UPDATE_MISS_STATS(LOAD_ATTR);
                     assert(_PyOpcode_Deopt[opcode] == (LOAD_ATTR));
+                    #if _Py_TIER2
+                    tstate->interp->jit_state.specialize_counter++;
+                    #endif
                     JUMP_TO_PREDICTED(LOAD_ATTR);
                 }
             }
                 if (dict == NULL) {
                     UPDATE_MISS_STATS(LOAD_ATTR);
                     assert(_PyOpcode_Deopt[opcode] == (LOAD_ATTR));
+                    #if _Py_TIER2
+                    tstate->interp->jit_state.specialize_counter++;
+                    #endif
                     JUMP_TO_PREDICTED(LOAD_ATTR);
                 }
                 PyDictKeysObject *dk = FT_ATOMIC_LOAD_PTR(dict->ma_keys);
                 if (!_Py_IsOwnedByCurrentThread((PyObject *)dict) && !_PyObject_GC_IS_SHARED(dict)) {
                     UPDATE_MISS_STATS(LOAD_ATTR);
                     assert(_PyOpcode_Deopt[opcode] == (LOAD_ATTR));
+                    #if _Py_TIER2
+                    tstate->interp->jit_state.specialize_counter++;
+                    #endif
                     JUMP_TO_PREDICTED(LOAD_ATTR);
                 }
                 #endif
                     if (true) {
                         UPDATE_MISS_STATS(LOAD_ATTR);
                         assert(_PyOpcode_Deopt[opcode] == (LOAD_ATTR));
+                        #if _Py_TIER2
+                        tstate->interp->jit_state.specialize_counter++;
+                        #endif
                         JUMP_TO_PREDICTED(LOAD_ATTR);
                     }
                 }
                     if (true) {
                         UPDATE_MISS_STATS(LOAD_ATTR);
                         assert(_PyOpcode_Deopt[opcode] == (LOAD_ATTR));
+                        #if _Py_TIER2
+                        tstate->interp->jit_state.specialize_counter++;
+                        #endif
                         JUMP_TO_PREDICTED(LOAD_ATTR);
                     }
                 }
                     if (true) {
                         UPDATE_MISS_STATS(LOAD_ATTR);
                         assert(_PyOpcode_Deopt[opcode] == (LOAD_ATTR));
+                        #if _Py_TIER2
+                        tstate->interp->jit_state.specialize_counter++;
+                        #endif
                         JUMP_TO_PREDICTED(LOAD_ATTR);
                     }
                 }
                     if (true) {
                         UPDATE_MISS_STATS(LOAD_ATTR);
                         assert(_PyOpcode_Deopt[opcode] == (LOAD_ATTR));
+                        #if _Py_TIER2
+                        tstate->interp->jit_state.specialize_counter++;
+                        #endif
                         JUMP_TO_PREDICTED(LOAD_ATTR);
                     }
                 }
                     if (true) {
                         UPDATE_MISS_STATS(LOAD_ATTR);
                         assert(_PyOpcode_Deopt[opcode] == (LOAD_ATTR));
+                        #if _Py_TIER2
+                        tstate->interp->jit_state.specialize_counter++;
+                        #endif
                         JUMP_TO_PREDICTED(LOAD_ATTR);
                     }
                 }
                 if (!PyDict_CheckExact(dict)) {
                     UPDATE_MISS_STATS(LOAD_GLOBAL);
                     assert(_PyOpcode_Deopt[opcode] == (LOAD_GLOBAL));
+                    #if _Py_TIER2
+                    tstate->interp->jit_state.specialize_counter++;
+                    #endif
                     JUMP_TO_PREDICTED(LOAD_GLOBAL);
                 }
                 PyDictKeysObject *keys = FT_ATOMIC_LOAD_PTR_ACQUIRE(dict->ma_keys);
                 if (FT_ATOMIC_LOAD_UINT32_RELAXED(keys->dk_version) != version) {
                     UPDATE_MISS_STATS(LOAD_GLOBAL);
                     assert(_PyOpcode_Deopt[opcode] == (LOAD_GLOBAL));
+                    #if _Py_TIER2
+                    tstate->interp->jit_state.specialize_counter++;
+                    #endif
                     JUMP_TO_PREDICTED(LOAD_GLOBAL);
                 }
                 assert(DK_IS_UNICODE(keys));
                 if (!PyDict_CheckExact(dict)) {
                     UPDATE_MISS_STATS(LOAD_GLOBAL);
                     assert(_PyOpcode_Deopt[opcode] == (LOAD_GLOBAL));
+                    #if _Py_TIER2
+                    tstate->interp->jit_state.specialize_counter++;
+                    #endif
                     JUMP_TO_PREDICTED(LOAD_GLOBAL);
                 }
                 PyDictKeysObject *keys = FT_ATOMIC_LOAD_PTR_ACQUIRE(dict->ma_keys);
                 if (FT_ATOMIC_LOAD_UINT32_RELAXED(keys->dk_version) != version) {
                     UPDATE_MISS_STATS(LOAD_GLOBAL);
                     assert(_PyOpcode_Deopt[opcode] == (LOAD_GLOBAL));
+                    #if _Py_TIER2
+                    tstate->interp->jit_state.specialize_counter++;
+                    #endif
                     JUMP_TO_PREDICTED(LOAD_GLOBAL);
                 }
                 assert(DK_IS_UNICODE(keys));
                 if (res_o == NULL) {
                     UPDATE_MISS_STATS(LOAD_GLOBAL);
                     assert(_PyOpcode_Deopt[opcode] == (LOAD_GLOBAL));
+                    #if _Py_TIER2
+                    tstate->interp->jit_state.specialize_counter++;
+                    #endif
                     JUMP_TO_PREDICTED(LOAD_GLOBAL);
                 }
                 #if Py_GIL_DISABLED
                 if (!increfed) {
                     UPDATE_MISS_STATS(LOAD_GLOBAL);
                     assert(_PyOpcode_Deopt[opcode] == (LOAD_GLOBAL));
+                    #if _Py_TIER2
+                    tstate->interp->jit_state.specialize_counter++;
+                    #endif
                     JUMP_TO_PREDICTED(LOAD_GLOBAL);
                 }
                 #else
                 if (!PyDict_CheckExact(dict)) {
                     UPDATE_MISS_STATS(LOAD_GLOBAL);
                     assert(_PyOpcode_Deopt[opcode] == (LOAD_GLOBAL));
+                    #if _Py_TIER2
+                    tstate->interp->jit_state.specialize_counter++;
+                    #endif
                     JUMP_TO_PREDICTED(LOAD_GLOBAL);
                 }
                 PyDictKeysObject *keys = FT_ATOMIC_LOAD_PTR_ACQUIRE(dict->ma_keys);
                 if (FT_ATOMIC_LOAD_UINT32_RELAXED(keys->dk_version) != version) {
                     UPDATE_MISS_STATS(LOAD_GLOBAL);
                     assert(_PyOpcode_Deopt[opcode] == (LOAD_GLOBAL));
+                    #if _Py_TIER2
+                    tstate->interp->jit_state.specialize_counter++;
+                    #endif
                     JUMP_TO_PREDICTED(LOAD_GLOBAL);
                 }
                 assert(DK_IS_UNICODE(keys));
                 if (res_o == NULL) {
                     UPDATE_MISS_STATS(LOAD_GLOBAL);
                     assert(_PyOpcode_Deopt[opcode] == (LOAD_GLOBAL));
+                    #if _Py_TIER2
+                    tstate->interp->jit_state.specialize_counter++;
+                    #endif
                     JUMP_TO_PREDICTED(LOAD_GLOBAL);
                 }
                 #if Py_GIL_DISABLED
                 if (!increfed) {
                     UPDATE_MISS_STATS(LOAD_GLOBAL);
                     assert(_PyOpcode_Deopt[opcode] == (LOAD_GLOBAL));
+                    #if _Py_TIER2
+                    tstate->interp->jit_state.specialize_counter++;
+                    #endif
                     JUMP_TO_PREDICTED(LOAD_GLOBAL);
                 }
                 #else
             if (global_super != (PyObject *)&PySuper_Type) {
                 UPDATE_MISS_STATS(LOAD_SUPER_ATTR);
                 assert(_PyOpcode_Deopt[opcode] == (LOAD_SUPER_ATTR));
+                #if _Py_TIER2
+                tstate->interp->jit_state.specialize_counter++;
+                #endif
                 JUMP_TO_PREDICTED(LOAD_SUPER_ATTR);
             }
             if (!PyType_Check(class)) {
                 UPDATE_MISS_STATS(LOAD_SUPER_ATTR);
                 assert(_PyOpcode_Deopt[opcode] == (LOAD_SUPER_ATTR));
+                #if _Py_TIER2
+                tstate->interp->jit_state.specialize_counter++;
+                #endif
                 JUMP_TO_PREDICTED(LOAD_SUPER_ATTR);
             }
             STAT_INC(LOAD_SUPER_ATTR, hit);
             if (global_super != (PyObject *)&PySuper_Type) {
                 UPDATE_MISS_STATS(LOAD_SUPER_ATTR);
                 assert(_PyOpcode_Deopt[opcode] == (LOAD_SUPER_ATTR));
+                #if _Py_TIER2
+                tstate->interp->jit_state.specialize_counter++;
+                #endif
                 JUMP_TO_PREDICTED(LOAD_SUPER_ATTR);
             }
             if (!PyType_Check(class)) {
                 UPDATE_MISS_STATS(LOAD_SUPER_ATTR);
                 assert(_PyOpcode_Deopt[opcode] == (LOAD_SUPER_ATTR));
+                #if _Py_TIER2
+                tstate->interp->jit_state.specialize_counter++;
+                #endif
                 JUMP_TO_PREDICTED(LOAD_SUPER_ATTR);
             }
             STAT_INC(LOAD_SUPER_ATTR, hit);
                 }
                 DISPATCH_GOTO_NON_TRACING();
             }
-            tstate->interp->jit_state.do_not_specialize = false;
+            if ((tstate->interp->jit_state.prev_instr->op.code == CALL_LIST_APPEND &&
+                 opcode == POP_TOP) ||
+                (tstate->interp->jit_state.prev_instr->op.code == BINARY_OP_INPLACE_ADD_UNICODE &&
+                 opcode == STORE_FAST)) {
+                tstate->interp->jit_state.prev_instr_is_super = true;
+            }
+            else {
+                tstate->interp->jit_state.prev_instr = next_instr;
+            }
+            tstate->interp->jit_state.specialize_counter = 0;
             PyCodeObject *prev_code = (PyCodeObject *)Py_NewRef(_PyFrame_GetCode(frame));
             _PyFrame_SetStackPointer(frame, stack_pointer);
             Py_SETREF(tstate->interp->jit_state.prev_instr_code, prev_code);
             stack_pointer = _PyFrame_GetStackPointer(frame);
-            tstate->interp->jit_state.prev_instr = next_instr;
             tstate->interp->jit_state.prev_instr_frame = frame;
             tstate->interp->jit_state.prev_instr_oparg = oparg;
             tstate->interp->jit_state.prev_instr_stacklevel = STACK_LEVEL();
             if (_Py_emscripten_signal_clock == 0) {
                 UPDATE_MISS_STATS(RESUME);
                 assert(_PyOpcode_Deopt[opcode] == (RESUME));
+                #if _Py_TIER2
+                tstate->interp->jit_state.specialize_counter++;
+                #endif
                 JUMP_TO_PREDICTED(RESUME);
             }
             _Py_emscripten_signal_clock -= Py_EMSCRIPTEN_SIGNAL_HANDLING;
             if (eval_breaker != version) {
                 UPDATE_MISS_STATS(RESUME);
                 assert(_PyOpcode_Deopt[opcode] == (RESUME));
+                #if _Py_TIER2
+                tstate->interp->jit_state.specialize_counter++;
+                #endif
                 JUMP_TO_PREDICTED(RESUME);
             }
             #ifdef Py_GIL_DISABLED
                 ((_PyThreadStateImpl *)tstate)->tlbc_index) {
                 UPDATE_MISS_STATS(RESUME);
                 assert(_PyOpcode_Deopt[opcode] == (RESUME));
+                #if _Py_TIER2
+                tstate->interp->jit_state.specialize_counter++;
+                #endif
                 JUMP_TO_PREDICTED(RESUME);
             }
             #endif
                 if (tstate->interp->eval_frame) {
                     UPDATE_MISS_STATS(SEND);
                     assert(_PyOpcode_Deopt[opcode] == (SEND));
+                    #if _Py_TIER2
+                    tstate->interp->jit_state.specialize_counter++;
+                    #endif
                     JUMP_TO_PREDICTED(SEND);
                 }
             }
                 if (Py_TYPE(gen) != &PyGen_Type && Py_TYPE(gen) != &PyCoro_Type) {
                     UPDATE_MISS_STATS(SEND);
                     assert(_PyOpcode_Deopt[opcode] == (SEND));
+                    #if _Py_TIER2
+                    tstate->interp->jit_state.specialize_counter++;
+                    #endif
                     JUMP_TO_PREDICTED(SEND);
                 }
                 if (gen->gi_frame_state >= FRAME_EXECUTING) {
                     UPDATE_MISS_STATS(SEND);
                     assert(_PyOpcode_Deopt[opcode] == (SEND));
+                    #if _Py_TIER2
+                    tstate->interp->jit_state.specialize_counter++;
+                    #endif
                     JUMP_TO_PREDICTED(SEND);
                 }
                 STAT_INC(SEND, hit);
                 if (!LOCK_OBJECT(owner_o)) {
                     UPDATE_MISS_STATS(STORE_ATTR);
                     assert(_PyOpcode_Deopt[opcode] == (STORE_ATTR));
+                    #if _Py_TIER2
+                    tstate->interp->jit_state.specialize_counter++;
+                    #endif
                     JUMP_TO_PREDICTED(STORE_ATTR);
                 }
                 PyTypeObject *tp = Py_TYPE(owner_o);
                     if (true) {
                         UPDATE_MISS_STATS(STORE_ATTR);
                         assert(_PyOpcode_Deopt[opcode] == (STORE_ATTR));
+                        #if _Py_TIER2
+                        tstate->interp->jit_state.specialize_counter++;
+                        #endif
                         JUMP_TO_PREDICTED(STORE_ATTR);
                     }
                 }
                     if (true) {
                         UPDATE_MISS_STATS(STORE_ATTR);
                         assert(_PyOpcode_Deopt[opcode] == (STORE_ATTR));
+                        #if _Py_TIER2
+                        tstate->interp->jit_state.specialize_counter++;
+                        #endif
                         JUMP_TO_PREDICTED(STORE_ATTR);
                     }
                 }
                 if (FT_ATOMIC_LOAD_UINT_RELAXED(tp->tp_version_tag) != type_version) {
                     UPDATE_MISS_STATS(STORE_ATTR);
                     assert(_PyOpcode_Deopt[opcode] == (STORE_ATTR));
+                    #if _Py_TIER2
+                    tstate->interp->jit_state.specialize_counter++;
+                    #endif
                     JUMP_TO_PREDICTED(STORE_ATTR);
                 }
             }
                 if (!LOCK_OBJECT(owner_o)) {
                     UPDATE_MISS_STATS(STORE_ATTR);
                     assert(_PyOpcode_Deopt[opcode] == (STORE_ATTR));
+                    #if _Py_TIER2
+                    tstate->interp->jit_state.specialize_counter++;
+                    #endif
                     JUMP_TO_PREDICTED(STORE_ATTR);
                 }
                 char *addr = (char *)owner_o + index;
                 if (FT_ATOMIC_LOAD_UINT_RELAXED(tp->tp_version_tag) != type_version) {
                     UPDATE_MISS_STATS(STORE_ATTR);
                     assert(_PyOpcode_Deopt[opcode] == (STORE_ATTR));
+                    #if _Py_TIER2
+                    tstate->interp->jit_state.specialize_counter++;
+                    #endif
                     JUMP_TO_PREDICTED(STORE_ATTR);
                 }
             }
                 if (dict == NULL) {
                     UPDATE_MISS_STATS(STORE_ATTR);
                     assert(_PyOpcode_Deopt[opcode] == (STORE_ATTR));
+                    #if _Py_TIER2
+                    tstate->interp->jit_state.specialize_counter++;
+                    #endif
                     JUMP_TO_PREDICTED(STORE_ATTR);
                 }
                 if (!LOCK_OBJECT(dict)) {
                     UPDATE_MISS_STATS(STORE_ATTR);
                     assert(_PyOpcode_Deopt[opcode] == (STORE_ATTR));
+                    #if _Py_TIER2
+                    tstate->interp->jit_state.specialize_counter++;
+                    #endif
                     JUMP_TO_PREDICTED(STORE_ATTR);
                 }
                 assert(PyDict_CheckExact((PyObject *)dict));
                     if (true) {
                         UPDATE_MISS_STATS(STORE_ATTR);
                         assert(_PyOpcode_Deopt[opcode] == (STORE_ATTR));
+                        #if _Py_TIER2
+                        tstate->interp->jit_state.specialize_counter++;
+                        #endif
                         JUMP_TO_PREDICTED(STORE_ATTR);
                     }
                 }
                     if (true) {
                         UPDATE_MISS_STATS(STORE_ATTR);
                         assert(_PyOpcode_Deopt[opcode] == (STORE_ATTR));
+                        #if _Py_TIER2
+                        tstate->interp->jit_state.specialize_counter++;
+                        #endif
                         JUMP_TO_PREDICTED(STORE_ATTR);
                     }
                 }
                     if (true) {
                         UPDATE_MISS_STATS(STORE_ATTR);
                         assert(_PyOpcode_Deopt[opcode] == (STORE_ATTR));
+                        #if _Py_TIER2
+                        tstate->interp->jit_state.specialize_counter++;
+                        #endif
                         JUMP_TO_PREDICTED(STORE_ATTR);
                     }
                 }
                 if (!PyDict_CheckExact(o)) {
                     UPDATE_MISS_STATS(STORE_SUBSCR);
                     assert(_PyOpcode_Deopt[opcode] == (STORE_SUBSCR));
+                    #if _Py_TIER2
+                    tstate->interp->jit_state.specialize_counter++;
+                    #endif
                     JUMP_TO_PREDICTED(STORE_SUBSCR);
                 }
             }
                 if (!_PyLong_CheckExactAndCompact(value_o)) {
                     UPDATE_MISS_STATS(STORE_SUBSCR);
                     assert(_PyOpcode_Deopt[opcode] == (STORE_SUBSCR));
+                    #if _Py_TIER2
+                    tstate->interp->jit_state.specialize_counter++;
+                    #endif
                     JUMP_TO_PREDICTED(STORE_SUBSCR);
                 }
             }
                 if (!PyList_CheckExact(o)) {
                     UPDATE_MISS_STATS(STORE_SUBSCR);
                     assert(_PyOpcode_Deopt[opcode] == (STORE_SUBSCR));
+                    #if _Py_TIER2
+                    tstate->interp->jit_state.specialize_counter++;
+                    #endif
                     JUMP_TO_PREDICTED(STORE_SUBSCR);
                 }
             }
                 if (!_PyLong_IsNonNegativeCompact((PyLongObject *)sub)) {
                     UPDATE_MISS_STATS(STORE_SUBSCR);
                     assert(_PyOpcode_Deopt[opcode] == (STORE_SUBSCR));
+                    #if _Py_TIER2
+                    tstate->interp->jit_state.specialize_counter++;
+                    #endif
                     JUMP_TO_PREDICTED(STORE_SUBSCR);
                 }
                 Py_ssize_t index = ((PyLongObject*)sub)->long_value.ob_digit[0];
                 if (!LOCK_OBJECT(list)) {
                     UPDATE_MISS_STATS(STORE_SUBSCR);
                     assert(_PyOpcode_Deopt[opcode] == (STORE_SUBSCR));
+                    #if _Py_TIER2
+                    tstate->interp->jit_state.specialize_counter++;
+                    #endif
                     JUMP_TO_PREDICTED(STORE_SUBSCR);
                 }
                 if (index >= PyList_GET_SIZE(list)) {
                     if (true) {
                         UPDATE_MISS_STATS(STORE_SUBSCR);
                         assert(_PyOpcode_Deopt[opcode] == (STORE_SUBSCR));
+                        #if _Py_TIER2
+                        tstate->interp->jit_state.specialize_counter++;
+                        #endif
                         JUMP_TO_PREDICTED(STORE_SUBSCR);
                     }
                 }
                 if (FT_ATOMIC_LOAD_UINT_RELAXED(tp->tp_version_tag) != type_version) {
                     UPDATE_MISS_STATS(TO_BOOL);
                     assert(_PyOpcode_Deopt[opcode] == (TO_BOOL));
+                    #if _Py_TIER2
+                    tstate->interp->jit_state.specialize_counter++;
+                    #endif
                     JUMP_TO_PREDICTED(TO_BOOL);
                 }
             }
             if (!PyStackRef_BoolCheck(value)) {
                 UPDATE_MISS_STATS(TO_BOOL);
                 assert(_PyOpcode_Deopt[opcode] == (TO_BOOL));
+                #if _Py_TIER2
+                tstate->interp->jit_state.specialize_counter++;
+                #endif
                 JUMP_TO_PREDICTED(TO_BOOL);
             }
             STAT_INC(TO_BOOL, hit);
             if (!PyLong_CheckExact(value_o)) {
                 UPDATE_MISS_STATS(TO_BOOL);
                 assert(_PyOpcode_Deopt[opcode] == (TO_BOOL));
+                #if _Py_TIER2
+                tstate->interp->jit_state.specialize_counter++;
+                #endif
                 JUMP_TO_PREDICTED(TO_BOOL);
             }
             STAT_INC(TO_BOOL, hit);
                 if (!PyList_CheckExact(o)) {
                     UPDATE_MISS_STATS(TO_BOOL);
                     assert(_PyOpcode_Deopt[opcode] == (TO_BOOL));
+                    #if _Py_TIER2
+                    tstate->interp->jit_state.specialize_counter++;
+                    #endif
                     JUMP_TO_PREDICTED(TO_BOOL);
                 }
             }
             if (!PyStackRef_IsNone(value)) {
                 UPDATE_MISS_STATS(TO_BOOL);
                 assert(_PyOpcode_Deopt[opcode] == (TO_BOOL));
+                #if _Py_TIER2
+                tstate->interp->jit_state.specialize_counter++;
+                #endif
                 JUMP_TO_PREDICTED(TO_BOOL);
             }
             STAT_INC(TO_BOOL, hit);
                 if (!PyUnicode_CheckExact(value_o)) {
                     UPDATE_MISS_STATS(TO_BOOL);
                     assert(_PyOpcode_Deopt[opcode] == (TO_BOOL));
+                    #if _Py_TIER2
+                    tstate->interp->jit_state.specialize_counter++;
+                    #endif
                     JUMP_TO_PREDICTED(TO_BOOL);
                 }
             }
                 if (!PyList_CheckExact(o)) {
                     UPDATE_MISS_STATS(UNPACK_SEQUENCE);
                     assert(_PyOpcode_Deopt[opcode] == (UNPACK_SEQUENCE));
+                    #if _Py_TIER2
+                    tstate->interp->jit_state.specialize_counter++;
+                    #endif
                     JUMP_TO_PREDICTED(UNPACK_SEQUENCE);
                 }
             }
                 if (!LOCK_OBJECT(seq_o)) {
                     UPDATE_MISS_STATS(UNPACK_SEQUENCE);
                     assert(_PyOpcode_Deopt[opcode] == (UNPACK_SEQUENCE));
+                    #if _Py_TIER2
+                    tstate->interp->jit_state.specialize_counter++;
+                    #endif
                     JUMP_TO_PREDICTED(UNPACK_SEQUENCE);
                 }
                 if (PyList_GET_SIZE(seq_o) != oparg) {
                     if (true) {
                         UPDATE_MISS_STATS(UNPACK_SEQUENCE);
                         assert(_PyOpcode_Deopt[opcode] == (UNPACK_SEQUENCE));
+                        #if _Py_TIER2
+                        tstate->interp->jit_state.specialize_counter++;
+                        #endif
                         JUMP_TO_PREDICTED(UNPACK_SEQUENCE);
                     }
                 }
                 if (!PyTuple_CheckExact(o)) {
                     UPDATE_MISS_STATS(UNPACK_SEQUENCE);
                     assert(_PyOpcode_Deopt[opcode] == (UNPACK_SEQUENCE));
+                    #if _Py_TIER2
+                    tstate->interp->jit_state.specialize_counter++;
+                    #endif
                     JUMP_TO_PREDICTED(UNPACK_SEQUENCE);
                 }
             }
                 if (PyTuple_GET_SIZE(seq_o) != oparg) {
                     UPDATE_MISS_STATS(UNPACK_SEQUENCE);
                     assert(_PyOpcode_Deopt[opcode] == (UNPACK_SEQUENCE));
+                    #if _Py_TIER2
+                    tstate->interp->jit_state.specialize_counter++;
+                    #endif
                     JUMP_TO_PREDICTED(UNPACK_SEQUENCE);
                 }
                 STAT_INC(UNPACK_SEQUENCE, hit);
                 if (!PyTuple_CheckExact(o)) {
                     UPDATE_MISS_STATS(UNPACK_SEQUENCE);
                     assert(_PyOpcode_Deopt[opcode] == (UNPACK_SEQUENCE));
+                    #if _Py_TIER2
+                    tstate->interp->jit_state.specialize_counter++;
+                    #endif
                     JUMP_TO_PREDICTED(UNPACK_SEQUENCE);
                 }
             }
                 if (PyTuple_GET_SIZE(seq_o) != 2) {
                     UPDATE_MISS_STATS(UNPACK_SEQUENCE);
                     assert(_PyOpcode_Deopt[opcode] == (UNPACK_SEQUENCE));
+                    #if _Py_TIER2
+                    tstate->interp->jit_state.specialize_counter++;
+                    #endif
                     JUMP_TO_PREDICTED(UNPACK_SEQUENCE);
                 }
                 STAT_INC(UNPACK_SEQUENCE, hit);
index c11cd22cf9dfbc536da8e39c99a162c2f0dc9764..31c9995c4ed6b42f977b02124cf0ae55fad034de 100644 (file)
@@ -593,14 +593,20 @@ _PyJit_translate_single_bytecode_to_trace(
     // We must point to the first EXTENDED_ARG when deopting.
     int oparg = tstate->interp->jit_state.prev_instr_oparg;
     int opcode = this_instr->op.code;
+    // Failed specialization twice in a row. Deopt!
+    if (tstate->interp->jit_state.specialize_counter >= 3) {
+        opcode = _PyOpcode_Deopt[opcode];
+    }
     int rewind_oparg = oparg;
     while (rewind_oparg > 255) {
         rewind_oparg >>= 8;
         target--;
     }
 
+    int old_stack_level = tstate->interp->jit_state.prev_instr_stacklevel;
+
     bool needs_guard_ip = _PyOpcode_NeedsGuardIp[opcode];
-    DPRINTF(2, "%p %d: %s(%d) %d\n", old_code, target, _PyOpcode_OpName[opcode], oparg, needs_guard_ip);
+    DPRINTF(2, "%p %d: %s(%d) %d %d\n", old_code, target, _PyOpcode_OpName[opcode], oparg, needs_guard_ip, old_stack_level);
 
 #ifdef Py_DEBUG
     if (oparg > 255) {
@@ -608,11 +614,16 @@ _PyJit_translate_single_bytecode_to_trace(
     }
 #endif
 
+    // Skip over super instructions.
+    if (tstate->interp->jit_state.prev_instr_is_super) {
+        tstate->interp->jit_state.prev_instr_is_super = false;
+        return 1;
+    }
+
     if (!tstate->interp->jit_state.dependencies_still_valid) {
         goto done;
     }
 
-    int old_stack_level = tstate->interp->jit_state.prev_instr_oparg;
     // Strange control-flow, unsupported opcode, etc.
     if (tstate->interp->jit_state.dynamic_jump_taken) {
         goto unsupported;
@@ -939,13 +950,14 @@ _PyJit_InitializeTracing(PyThreadState *tstate, _PyInterpreterFrame *frame, _Py_
     tstate->interp->jit_state.initial_chain_depth = chain_depth % MAX_CHAIN_DEPTH;
     tstate->interp->jit_state.prev_instr_frame = frame;
     tstate->interp->jit_state.dependencies_still_valid = true;
-    tstate->interp->jit_state.do_not_specialize = false;
+    tstate->interp->jit_state.specialize_counter = 0;
     tstate->interp->jit_state.prev_instr_code = (PyCodeObject *)Py_NewRef(_PyFrame_GetCode(frame));
     tstate->interp->jit_state.prev_instr = curr_instr;
     tstate->interp->jit_state.prev_instr_frame = frame;
     tstate->interp->jit_state.prev_instr_oparg = oparg;
     tstate->interp->jit_state.prev_instr_stacklevel = curr_stackdepth;
     tstate->interp->jit_state.dynamic_jump_taken = false;
+    tstate->interp->jit_state.prev_instr_is_super = false;
     _Py_BloomFilter_Init(&tstate->interp->jit_state.dependencies);
 }
 
@@ -1740,7 +1752,7 @@ executor_to_gv(_PyExecutorObject *executor, FILE *out)
 #ifdef Py_STATS
         fprintf(out, "        <tr><td port=\"i%d\" border=\"1\" >%s -- %" PRIu64 "</td></tr>\n", i, opname, inst->execution_count);
 #else
-        fprintf(out, "        <tr><td port=\"i%d\" border=\"1\" >%s</td></tr>\n", i, opname);
+        fprintf(out, "        <tr><td port=\"i%d\" border=\"1\" >%s op0=%" PRIu64 "</td></tr>\n", i, opname, inst->operand0);
 #endif
         if (inst->opcode == _EXIT_TRACE || inst->opcode == _JUMP_TO_TOP) {
             break;
index 4a66b7d51180643bfebdb7b0f100c9364bc9829c..804bd9773b164a9a4161907c915113e21ca1a9e1 100644 (file)
@@ -169,6 +169,9 @@ class Emitter:
         family_name = inst.family.name
         self.emit(f"UPDATE_MISS_STATS({family_name});\n")
         self.emit(f"assert(_PyOpcode_Deopt[opcode] == ({family_name}));\n")
+        self.emit(f"#if _Py_TIER2\n")
+        self.emit(f"tstate->interp->jit_state.specialize_counter++;\n")
+        self.emit(f"#endif\n")
         self.emit(f"JUMP_TO_PREDICTED({self.jump_prefix}{family_name});\n")
         self.emit("}\n")
         return not always_true(first_tkn)