summaryrefslogtreecommitdiffstats
path: root/Python/executor_cases.c.h
diff options
context:
space:
mode:
authorMark Shannon <mark@hotpy.org>2024-02-20 09:39:55 (GMT)
committerGitHub <noreply@github.com>2024-02-20 09:39:55 (GMT)
commit7b21403ccd16c480812a1e857c0ee2deca592be0 (patch)
treeae54fc68fe298bea063502adff747e3ac1dd734d /Python/executor_cases.c.h
parentacda1757bc682922292215906459c2735ee99c04 (diff)
downloadcpython-7b21403ccd16c480812a1e857c0ee2deca592be0.zip
cpython-7b21403ccd16c480812a1e857c0ee2deca592be0.tar.gz
cpython-7b21403ccd16c480812a1e857c0ee2deca592be0.tar.bz2
GH-112354: Initial implementation of warm up on exits and trace-stitching (GH-114142)
Diffstat (limited to 'Python/executor_cases.c.h')
-rw-r--r--Python/executor_cases.c.h96
1 files changed, 75 insertions, 21 deletions
diff --git a/Python/executor_cases.c.h b/Python/executor_cases.c.h
index 11e2a1f..a18284d 100644
--- a/Python/executor_cases.c.h
+++ b/Python/executor_cases.c.h
@@ -141,7 +141,7 @@
case _TO_BOOL_BOOL: {
PyObject *value;
value = stack_pointer[-1];
- if (!PyBool_Check(value)) goto deoptimize;
+ if (!PyBool_Check(value)) goto side_exit;
STAT_INC(TO_BOOL, hit);
break;
}
@@ -150,7 +150,7 @@
PyObject *value;
PyObject *res;
value = stack_pointer[-1];
- if (!PyLong_CheckExact(value)) goto deoptimize;
+ if (!PyLong_CheckExact(value)) goto side_exit;
STAT_INC(TO_BOOL, hit);
if (_PyLong_IsZero((PyLongObject *)value)) {
assert(_Py_IsImmortal(value));
@@ -168,7 +168,7 @@
PyObject *value;
PyObject *res;
value = stack_pointer[-1];
- if (!PyList_CheckExact(value)) goto deoptimize;
+ if (!PyList_CheckExact(value)) goto side_exit;
STAT_INC(TO_BOOL, hit);
res = Py_SIZE(value) ? Py_True : Py_False;
Py_DECREF(value);
@@ -181,7 +181,7 @@
PyObject *res;
value = stack_pointer[-1];
// This one is a bit weird, because we expect *some* failures:
- if (!Py_IsNone(value)) goto deoptimize;
+ if (!Py_IsNone(value)) goto side_exit;
STAT_INC(TO_BOOL, hit);
res = Py_False;
stack_pointer[-1] = res;
@@ -192,7 +192,7 @@
PyObject *value;
PyObject *res;
value = stack_pointer[-1];
- if (!PyUnicode_CheckExact(value)) goto deoptimize;
+ if (!PyUnicode_CheckExact(value)) goto side_exit;
STAT_INC(TO_BOOL, hit);
if (value == &_Py_STR(empty)) {
assert(_Py_IsImmortal(value));
@@ -214,7 +214,7 @@
uint32_t version = (uint32_t)CURRENT_OPERAND();
// This one is a bit weird, because we expect *some* failures:
assert(version);
- if (Py_TYPE(value)->tp_version_tag != version) goto deoptimize;
+ if (Py_TYPE(value)->tp_version_tag != version) goto side_exit;
STAT_INC(TO_BOOL, hit);
Py_DECREF(value);
res = Py_True;
@@ -238,8 +238,8 @@
PyObject *left;
right = stack_pointer[-1];
left = stack_pointer[-2];
- if (!PyLong_CheckExact(left)) goto deoptimize;
- if (!PyLong_CheckExact(right)) goto deoptimize;
+ if (!PyLong_CheckExact(left)) goto side_exit;
+ if (!PyLong_CheckExact(right)) goto side_exit;
break;
}
@@ -296,8 +296,8 @@
PyObject *left;
right = stack_pointer[-1];
left = stack_pointer[-2];
- if (!PyFloat_CheckExact(left)) goto deoptimize;
- if (!PyFloat_CheckExact(right)) goto deoptimize;
+ if (!PyFloat_CheckExact(left)) goto side_exit;
+ if (!PyFloat_CheckExact(right)) goto side_exit;
break;
}
@@ -354,8 +354,8 @@
PyObject *left;
right = stack_pointer[-1];
left = stack_pointer[-2];
- if (!PyUnicode_CheckExact(left)) goto deoptimize;
- if (!PyUnicode_CheckExact(right)) goto deoptimize;
+ if (!PyUnicode_CheckExact(left)) goto side_exit;
+ if (!PyUnicode_CheckExact(right)) goto side_exit;
break;
}
@@ -1623,7 +1623,7 @@
uint32_t type_version = (uint32_t)CURRENT_OPERAND();
PyTypeObject *tp = Py_TYPE(owner);
assert(type_version != 0);
- if (tp->tp_version_tag != type_version) goto deoptimize;
+ if (tp->tp_version_tag != type_version) goto side_exit;
break;
}
@@ -2013,8 +2013,6 @@
break;
}
- /* _JUMP_BACKWARD is not a viable micro-op for tier 2 */
-
/* _POP_JUMP_IF_FALSE is not a viable micro-op for tier 2 */
/* _POP_JUMP_IF_TRUE is not a viable micro-op for tier 2 */
@@ -3318,7 +3316,7 @@
PyObject *flag;
flag = stack_pointer[-1];
stack_pointer += -1;
- if (!Py_IsTrue(flag)) goto deoptimize;
+ if (!Py_IsTrue(flag)) goto side_exit;
assert(Py_IsTrue(flag));
break;
}
@@ -3327,7 +3325,7 @@
PyObject *flag;
flag = stack_pointer[-1];
stack_pointer += -1;
- if (!Py_IsFalse(flag)) goto deoptimize;
+ if (!Py_IsFalse(flag)) goto side_exit;
assert(Py_IsFalse(flag));
break;
}
@@ -3338,7 +3336,7 @@
stack_pointer += -1;
if (!Py_IsNone(val)) {
Py_DECREF(val);
- if (1) goto deoptimize;
+ if (1) goto side_exit;
}
break;
}
@@ -3347,13 +3345,15 @@
PyObject *val;
val = stack_pointer[-1];
stack_pointer += -1;
- if (Py_IsNone(val)) goto deoptimize;
+ if (Py_IsNone(val)) goto side_exit;
Py_DECREF(val);
break;
}
case _JUMP_TO_TOP: {
- next_uop = current_executor->trace;
+ #ifndef _Py_JIT
+ next_uop = &current_executor->trace[1];
+ #endif
CHECK_EVAL_BREAKER();
break;
}
@@ -3378,7 +3378,7 @@
case _EXIT_TRACE: {
TIER_TWO_ONLY
- if (1) goto deoptimize;
+ if (1) goto side_exit;
break;
}
@@ -3457,6 +3457,60 @@
break;
}
+ case _COLD_EXIT: {
+ oparg = CURRENT_OPARG();
+ TIER_TWO_ONLY
+ _PyExecutorObject *previous = (_PyExecutorObject *)tstate->previous_executor;
+ _PyExitData *exit = &previous->exits[oparg];
+ exit->temperature++;
+ PyCodeObject *code = _PyFrame_GetCode(frame);
+ _Py_CODEUNIT *target = _PyCode_CODE(code) + exit->target;
+ if (exit->temperature < (int32_t)tstate->interp->optimizer_side_threshold) {
+ GOTO_TIER_ONE(target);
+ }
+ _PyExecutorObject *executor;
+ if (target->op.code == ENTER_EXECUTOR) {
+ executor = code->co_executors->executors[target->op.arg];
+ Py_INCREF(executor);
+ } else {
+ int optimized = _PyOptimizer_Optimize(frame, target, stack_pointer, &executor);
+ if (optimized <= 0) {
+ int32_t new_temp = -1 * tstate->interp->optimizer_side_threshold;
+ exit->temperature = (new_temp < INT16_MIN) ? INT16_MIN : new_temp;
+ if (optimized < 0) {
+ Py_DECREF(previous);
+ tstate->previous_executor = Py_None;
+ if (1) goto error_tier_two;
+ }
+ GOTO_TIER_ONE(target);
+ }
+ }
+ /* We need two references. One to store in exit->executor and
+ * one to keep the executor alive when executing. */
+ Py_INCREF(executor);
+ exit->executor = executor;
+ GOTO_TIER_TWO(executor);
+ break;
+ }
+
+ case _START_EXECUTOR: {
+ PyObject *executor = (PyObject *)CURRENT_OPERAND();
+ TIER_TWO_ONLY
+ Py_DECREF(tstate->previous_executor);
+ tstate->previous_executor = NULL;
+ #ifndef _Py_JIT
+ current_executor = (_PyExecutorObject*)executor;
+ #endif
+ break;
+ }
+
+ case _FATAL_ERROR: {
+ TIER_TWO_ONLY
+ assert(0);
+ Py_FatalError("Fatal error uop executed.");
+ break;
+ }
+
case _CHECK_VALIDITY_AND_SET_IP: {
PyObject *instr_ptr = (PyObject *)CURRENT_OPERAND();
TIER_TWO_ONLY