summaryrefslogtreecommitdiffstats
path: root/Python
diff options
context:
space:
mode:
authorKen Jin <kenjin@python.org>2024-03-07 16:21:21 (GMT)
committerGitHub <noreply@github.com>2024-03-07 16:21:21 (GMT)
commit41457c7fdb04819d04a528b8dfa72c1aa5745cc9 (patch)
tree45a20bbed062946dae7b20c9fb616245b2751485 /Python
parent4298d69d4b2f7d0e9d93ad325238930bd6235dbf (diff)
downloadcpython-41457c7fdb04819d04a528b8dfa72c1aa5745cc9.zip
cpython-41457c7fdb04819d04a528b8dfa72c1aa5745cc9.tar.gz
cpython-41457c7fdb04819d04a528b8dfa72c1aa5745cc9.tar.bz2
gh-116381: Remove bad specializations, add fail stats (GH-116464)
* Remove bad specializations, add fail stats
Diffstat (limited to 'Python')
-rw-r--r--Python/bytecodes.c32
-rw-r--r--Python/executor_cases.c.h59
-rw-r--r--Python/generated_cases.c.h71
-rw-r--r--Python/opcode_targets.h6
-rw-r--r--Python/optimizer_cases.c.h27
-rw-r--r--Python/specialize.c40
6 files changed, 41 insertions, 194 deletions
diff --git a/Python/bytecodes.c b/Python/bytecodes.c
index 3276a4a..0397d96 100644
--- a/Python/bytecodes.c
+++ b/Python/bytecodes.c
@@ -2238,11 +2238,8 @@ dummy_func(
}
family(CONTAINS_OP, INLINE_CACHE_ENTRIES_CONTAINS_OP) = {
- CONTAINS_OP_LIST,
CONTAINS_OP_SET,
- CONTAINS_OP_TUPLE,
CONTAINS_OP_DICT,
- CONTAINS_OP_STR,
};
op(_CONTAINS_OP, (left, right -- b)) {
@@ -2266,46 +2263,25 @@ dummy_func(
macro(CONTAINS_OP) = _SPECIALIZE_CONTAINS_OP + _CONTAINS_OP;
- inst(CONTAINS_OP_LIST, (unused/1, left, right -- b)) {
- DEOPT_IF(!PyList_CheckExact(right));
- int res = _PyList_Contains(right, left);
- DECREF_INPUTS();
- ERROR_IF(res < 0, error);
- b = (res ^ oparg) ? Py_True : Py_False;
- }
-
inst(CONTAINS_OP_SET, (unused/1, left, right -- b)) {
- DEOPT_IF(!PySet_CheckExact(right));
+ DEOPT_IF(!(PySet_CheckExact(right) || PyFrozenSet_CheckExact(right)));
+ STAT_INC(CONTAINS_OP, hit);
+ // Note: both set and frozenset use the same seq_contains method!
int res = _PySet_Contains((PySetObject *)right, left);
DECREF_INPUTS();
ERROR_IF(res < 0, error);
b = (res ^ oparg) ? Py_True : Py_False;
}
- inst(CONTAINS_OP_TUPLE, (unused/1, left, right -- b)) {
- DEOPT_IF(!PyTuple_CheckExact(right));
- int res = _PyTuple_Contains((PyTupleObject *)right, left);
- DECREF_INPUTS();
- ERROR_IF(res < 0, error);
- b = (res ^ oparg) ? Py_True : Py_False;
- }
-
inst(CONTAINS_OP_DICT, (unused/1, left, right -- b)) {
DEOPT_IF(!PyDict_CheckExact(right));
+ STAT_INC(CONTAINS_OP, hit);
int res = PyDict_Contains(right, left);
DECREF_INPUTS();
ERROR_IF(res < 0, error);
b = (res ^ oparg) ? Py_True : Py_False;
}
- inst(CONTAINS_OP_STR, (unused/1, left, right -- b)) {
- DEOPT_IF(!PyUnicode_CheckExact(right));
- int res = PyUnicode_Contains(right, left);
- DECREF_INPUTS();
- ERROR_IF(res < 0, error);
- b = (res ^ oparg) ? Py_True : Py_False;
- }
-
inst(CHECK_EG_MATCH, (exc_value, match_type -- rest, match)) {
if (_PyEval_CheckExceptStarTypeValid(tstate, match_type) < 0) {
DECREF_INPUTS();
diff --git a/Python/executor_cases.c.h b/Python/executor_cases.c.h
index 2e7b970..26ac159 100644
--- a/Python/executor_cases.c.h
+++ b/Python/executor_cases.c.h
@@ -2189,24 +2189,6 @@
break;
}
- case _CONTAINS_OP_LIST: {
- PyObject *right;
- PyObject *left;
- PyObject *b;
- oparg = CURRENT_OPARG();
- right = stack_pointer[-1];
- left = stack_pointer[-2];
- if (!PyList_CheckExact(right)) goto deoptimize;
- int res = _PyList_Contains(right, left);
- Py_DECREF(left);
- Py_DECREF(right);
- if (res < 0) goto pop_2_error_tier_two;
- b = (res ^ oparg) ? Py_True : Py_False;
- stack_pointer[-2] = b;
- stack_pointer += -1;
- break;
- }
-
case _CONTAINS_OP_SET: {
PyObject *right;
PyObject *left;
@@ -2214,7 +2196,9 @@
oparg = CURRENT_OPARG();
right = stack_pointer[-1];
left = stack_pointer[-2];
- if (!PySet_CheckExact(right)) goto deoptimize;
+ if (!(PySet_CheckExact(right) || PyFrozenSet_CheckExact(right))) goto deoptimize;
+ STAT_INC(CONTAINS_OP, hit);
+ // Note: both set and frozenset use the same seq_contains method!
int res = _PySet_Contains((PySetObject *)right, left);
Py_DECREF(left);
Py_DECREF(right);
@@ -2225,24 +2209,6 @@
break;
}
- case _CONTAINS_OP_TUPLE: {
- PyObject *right;
- PyObject *left;
- PyObject *b;
- oparg = CURRENT_OPARG();
- right = stack_pointer[-1];
- left = stack_pointer[-2];
- if (!PyTuple_CheckExact(right)) goto deoptimize;
- int res = _PyTuple_Contains((PyTupleObject *)right, left);
- Py_DECREF(left);
- Py_DECREF(right);
- if (res < 0) goto pop_2_error_tier_two;
- b = (res ^ oparg) ? Py_True : Py_False;
- stack_pointer[-2] = b;
- stack_pointer += -1;
- break;
- }
-
case _CONTAINS_OP_DICT: {
PyObject *right;
PyObject *left;
@@ -2251,6 +2217,7 @@
right = stack_pointer[-1];
left = stack_pointer[-2];
if (!PyDict_CheckExact(right)) goto deoptimize;
+ STAT_INC(CONTAINS_OP, hit);
int res = PyDict_Contains(right, left);
Py_DECREF(left);
Py_DECREF(right);
@@ -2261,24 +2228,6 @@
break;
}
- case _CONTAINS_OP_STR: {
- PyObject *right;
- PyObject *left;
- PyObject *b;
- oparg = CURRENT_OPARG();
- right = stack_pointer[-1];
- left = stack_pointer[-2];
- if (!PyUnicode_CheckExact(right)) goto deoptimize;
- int res = PyUnicode_Contains(right, left);
- Py_DECREF(left);
- Py_DECREF(right);
- if (res < 0) goto pop_2_error_tier_two;
- b = (res ^ oparg) ? Py_True : Py_False;
- stack_pointer[-2] = b;
- stack_pointer += -1;
- break;
- }
-
case _CHECK_EG_MATCH: {
PyObject *match_type;
PyObject *exc_value;
diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h
index 54c4861..f5d125c 100644
--- a/Python/generated_cases.c.h
+++ b/Python/generated_cases.c.h
@@ -2176,6 +2176,7 @@
right = stack_pointer[-1];
left = stack_pointer[-2];
DEOPT_IF(!PyDict_CheckExact(right), CONTAINS_OP);
+ STAT_INC(CONTAINS_OP, hit);
int res = PyDict_Contains(right, left);
Py_DECREF(left);
Py_DECREF(right);
@@ -2186,28 +2187,6 @@
DISPATCH();
}
- TARGET(CONTAINS_OP_LIST) {
- frame->instr_ptr = next_instr;
- next_instr += 2;
- INSTRUCTION_STATS(CONTAINS_OP_LIST);
- static_assert(INLINE_CACHE_ENTRIES_CONTAINS_OP == 1, "incorrect cache size");
- PyObject *right;
- PyObject *left;
- PyObject *b;
- /* Skip 1 cache entry */
- right = stack_pointer[-1];
- left = stack_pointer[-2];
- DEOPT_IF(!PyList_CheckExact(right), CONTAINS_OP);
- int res = _PyList_Contains(right, left);
- Py_DECREF(left);
- Py_DECREF(right);
- if (res < 0) goto pop_2_error;
- b = (res ^ oparg) ? Py_True : Py_False;
- stack_pointer[-2] = b;
- stack_pointer += -1;
- DISPATCH();
- }
-
TARGET(CONTAINS_OP_SET) {
frame->instr_ptr = next_instr;
next_instr += 2;
@@ -2219,7 +2198,9 @@
/* Skip 1 cache entry */
right = stack_pointer[-1];
left = stack_pointer[-2];
- DEOPT_IF(!PySet_CheckExact(right), CONTAINS_OP);
+ DEOPT_IF(!(PySet_CheckExact(right) || PyFrozenSet_CheckExact(right)), CONTAINS_OP);
+ STAT_INC(CONTAINS_OP, hit);
+ // Note: both set and frozenset use the same seq_contains method!
int res = _PySet_Contains((PySetObject *)right, left);
Py_DECREF(left);
Py_DECREF(right);
@@ -2230,50 +2211,6 @@
DISPATCH();
}
- TARGET(CONTAINS_OP_STR) {
- frame->instr_ptr = next_instr;
- next_instr += 2;
- INSTRUCTION_STATS(CONTAINS_OP_STR);
- static_assert(INLINE_CACHE_ENTRIES_CONTAINS_OP == 1, "incorrect cache size");
- PyObject *right;
- PyObject *left;
- PyObject *b;
- /* Skip 1 cache entry */
- right = stack_pointer[-1];
- left = stack_pointer[-2];
- DEOPT_IF(!PyUnicode_CheckExact(right), CONTAINS_OP);
- int res = PyUnicode_Contains(right, left);
- Py_DECREF(left);
- Py_DECREF(right);
- if (res < 0) goto pop_2_error;
- b = (res ^ oparg) ? Py_True : Py_False;
- stack_pointer[-2] = b;
- stack_pointer += -1;
- DISPATCH();
- }
-
- TARGET(CONTAINS_OP_TUPLE) {
- frame->instr_ptr = next_instr;
- next_instr += 2;
- INSTRUCTION_STATS(CONTAINS_OP_TUPLE);
- static_assert(INLINE_CACHE_ENTRIES_CONTAINS_OP == 1, "incorrect cache size");
- PyObject *right;
- PyObject *left;
- PyObject *b;
- /* Skip 1 cache entry */
- right = stack_pointer[-1];
- left = stack_pointer[-2];
- DEOPT_IF(!PyTuple_CheckExact(right), CONTAINS_OP);
- int res = _PyTuple_Contains((PyTupleObject *)right, left);
- Py_DECREF(left);
- Py_DECREF(right);
- if (res < 0) goto pop_2_error;
- b = (res ^ oparg) ? Py_True : Py_False;
- stack_pointer[-2] = b;
- stack_pointer += -1;
- DISPATCH();
- }
-
TARGET(CONVERT_VALUE) {
frame->instr_ptr = next_instr;
next_instr += 1;
diff --git a/Python/opcode_targets.h b/Python/opcode_targets.h
index 6b3846d..4061ba3 100644
--- a/Python/opcode_targets.h
+++ b/Python/opcode_targets.h
@@ -183,10 +183,7 @@ static void *opcode_targets[256] = {
&&TARGET_COMPARE_OP_INT,
&&TARGET_COMPARE_OP_STR,
&&TARGET_CONTAINS_OP_DICT,
- &&TARGET_CONTAINS_OP_LIST,
&&TARGET_CONTAINS_OP_SET,
- &&TARGET_CONTAINS_OP_STR,
- &&TARGET_CONTAINS_OP_TUPLE,
&&TARGET_FOR_ITER_GEN,
&&TARGET_FOR_ITER_LIST,
&&TARGET_FOR_ITER_RANGE,
@@ -235,6 +232,9 @@ static void *opcode_targets[256] = {
&&_unknown_opcode,
&&_unknown_opcode,
&&_unknown_opcode,
+ &&_unknown_opcode,
+ &&_unknown_opcode,
+ &&_unknown_opcode,
&&TARGET_INSTRUMENTED_RESUME,
&&TARGET_INSTRUMENTED_END_FOR,
&&TARGET_INSTRUMENTED_END_SEND,
diff --git a/Python/optimizer_cases.c.h b/Python/optimizer_cases.c.h
index e438497..c88b251 100644
--- a/Python/optimizer_cases.c.h
+++ b/Python/optimizer_cases.c.h
@@ -1218,15 +1218,6 @@
break;
}
- case _CONTAINS_OP_LIST: {
- _Py_UopsSymbol *b;
- b = sym_new_unknown(ctx);
- if (b == NULL) goto out_of_space;
- stack_pointer[-2] = b;
- stack_pointer += -1;
- break;
- }
-
case _CONTAINS_OP_SET: {
_Py_UopsSymbol *b;
b = sym_new_unknown(ctx);
@@ -1236,15 +1227,6 @@
break;
}
- case _CONTAINS_OP_TUPLE: {
- _Py_UopsSymbol *b;
- b = sym_new_unknown(ctx);
- if (b == NULL) goto out_of_space;
- stack_pointer[-2] = b;
- stack_pointer += -1;
- break;
- }
-
case _CONTAINS_OP_DICT: {
_Py_UopsSymbol *b;
b = sym_new_unknown(ctx);
@@ -1254,15 +1236,6 @@
break;
}
- case _CONTAINS_OP_STR: {
- _Py_UopsSymbol *b;
- b = sym_new_unknown(ctx);
- if (b == NULL) goto out_of_space;
- stack_pointer[-2] = b;
- stack_pointer += -1;
- break;
- }
-
case _CHECK_EG_MATCH: {
_Py_UopsSymbol *rest;
_Py_UopsSymbol *match;
diff --git a/Python/specialize.c b/Python/specialize.c
index 5d339b8..b1f9eb7 100644
--- a/Python/specialize.c
+++ b/Python/specialize.c
@@ -600,6 +600,12 @@ _PyCode_Quicken(PyCodeObject *code)
#define SPEC_FAIL_TO_BOOL_SET 17
#define SPEC_FAIL_TO_BOOL_TUPLE 18
+// CONTAINS_OP
+#define SPEC_FAIL_CONTAINS_OP_STR 9
+#define SPEC_FAIL_CONTAINS_OP_TUPLE 10
+#define SPEC_FAIL_CONTAINS_OP_LIST 11
+#define SPEC_FAIL_CONTAINS_OP_USER_CLASS 12
+
static int function_kind(PyCodeObject *code);
static bool function_check_args(PyObject *o, int expected_argcount, int opcode);
static uint32_t function_get_version(PyObject *o, int opcode);
@@ -2562,34 +2568,40 @@ success:
cache->counter = adaptive_counter_cooldown();
}
-void
-_Py_Specialize_ContainsOp(PyObject *value, _Py_CODEUNIT *instr)
-{
- assert(ENABLE_SPECIALIZATION);
- assert(_PyOpcode_Caches[CONTAINS_OP] == INLINE_CACHE_ENTRIES_COMPARE_OP);
- _PyContainsOpCache *cache = (_PyContainsOpCache *)(instr + 1);
+#ifdef Py_STATS
+static int containsop_fail_kind(PyObject *value) {
if (PyUnicode_CheckExact(value)) {
- instr->op.code = CONTAINS_OP_STR;
- goto success;
+ return SPEC_FAIL_CONTAINS_OP_STR;
}
if (PyList_CheckExact(value)) {
- instr->op.code = CONTAINS_OP_LIST;
- goto success;
+ return SPEC_FAIL_CONTAINS_OP_LIST;
}
if (PyTuple_CheckExact(value)) {
- instr->op.code = CONTAINS_OP_TUPLE;
- goto success;
+ return SPEC_FAIL_CONTAINS_OP_TUPLE;
+ }
+ if (PyType_Check(value)) {
+ return SPEC_FAIL_CONTAINS_OP_USER_CLASS;
}
+ return SPEC_FAIL_OTHER;
+}
+#endif // Py_STATS
+
+void
+_Py_Specialize_ContainsOp(PyObject *value, _Py_CODEUNIT *instr)
+{
+ assert(ENABLE_SPECIALIZATION);
+ assert(_PyOpcode_Caches[CONTAINS_OP] == INLINE_CACHE_ENTRIES_COMPARE_OP);
+ _PyContainsOpCache *cache = (_PyContainsOpCache *)(instr + 1);
if (PyDict_CheckExact(value)) {
instr->op.code = CONTAINS_OP_DICT;
goto success;
}
- if (PySet_CheckExact(value)) {
+ if (PySet_CheckExact(value) || PyFrozenSet_CheckExact(value)) {
instr->op.code = CONTAINS_OP_SET;
goto success;
}
-
+ SPECIALIZATION_FAIL(CONTAINS_OP, containsop_fail_kind(value));
STAT_INC(CONTAINS_OP, failure);
instr->op.code = CONTAINS_OP;
cache->counter = adaptive_counter_backoff(cache->counter);