summaryrefslogtreecommitdiffstats
path: root/Python
diff options
context:
space:
mode:
Diffstat (limited to 'Python')
-rw-r--r--Python/bytecodes.c64
-rw-r--r--Python/executor_cases.c.h90
-rw-r--r--Python/generated_cases.c.h134
-rw-r--r--Python/opcode_targets.h10
-rw-r--r--Python/optimizer_cases.c.h45
-rw-r--r--Python/specialize.c38
6 files changed, 373 insertions, 8 deletions
diff --git a/Python/bytecodes.c b/Python/bytecodes.c
index ad4ea4e..bf0583d 100644
--- a/Python/bytecodes.c
+++ b/Python/bytecodes.c
@@ -2237,13 +2237,75 @@ dummy_func(
b = res ? Py_True : Py_False;
}
- inst(CONTAINS_OP, (left, right -- b)) {
+ 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)) {
int res = PySequence_Contains(right, left);
DECREF_INPUTS();
ERROR_IF(res < 0, error);
b = (res ^ oparg) ? Py_True : Py_False;
}
+ specializing op(_SPECIALIZE_CONTAINS_OP, (counter/1, left, right -- left, right)) {
+ #if ENABLE_SPECIALIZATION
+ if (ADAPTIVE_COUNTER_IS_ZERO(counter)) {
+ next_instr = this_instr;
+ _Py_Specialize_ContainsOp(right, next_instr);
+ DISPATCH_SAME_OPARG();
+ }
+ STAT_INC(CONTAINS_OP, deferred);
+ DECREMENT_ADAPTIVE_COUNTER(this_instr[1].cache);
+ #endif /* ENABLE_SPECIALIZATION */
+ }
+
+ 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));
+ 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));
+ 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 a057466..4420c40 100644
--- a/Python/executor_cases.c.h
+++ b/Python/executor_cases.c.h
@@ -2189,6 +2189,96 @@
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;
+ PyObject *b;
+ oparg = CURRENT_OPARG();
+ right = stack_pointer[-1];
+ left = stack_pointer[-2];
+ if (!PySet_CheckExact(right)) goto deoptimize;
+ int res = _PySet_Contains((PySetObject *)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_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;
+ PyObject *b;
+ oparg = CURRENT_OPARG();
+ right = stack_pointer[-1];
+ left = stack_pointer[-2];
+ if (!PyDict_CheckExact(right)) goto deoptimize;
+ int res = PyDict_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_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 4947c91..6e8ca82 100644
--- a/Python/generated_cases.c.h
+++ b/Python/generated_cases.c.h
@@ -2127,14 +2127,144 @@
TARGET(CONTAINS_OP) {
frame->instr_ptr = next_instr;
- next_instr += 1;
+ next_instr += 2;
INSTRUCTION_STATS(CONTAINS_OP);
+ PREDICTED(CONTAINS_OP);
+ _Py_CODEUNIT *this_instr = next_instr - 2;
+ (void)this_instr;
+ PyObject *right;
+ PyObject *left;
+ PyObject *b;
+ // _SPECIALIZE_CONTAINS_OP
+ right = stack_pointer[-1];
+ left = stack_pointer[-2];
+ {
+ uint16_t counter = read_u16(&this_instr[1].cache);
+ (void)counter;
+ #if ENABLE_SPECIALIZATION
+ if (ADAPTIVE_COUNTER_IS_ZERO(counter)) {
+ next_instr = this_instr;
+ _Py_Specialize_ContainsOp(right, next_instr);
+ DISPATCH_SAME_OPARG();
+ }
+ STAT_INC(CONTAINS_OP, deferred);
+ DECREMENT_ADAPTIVE_COUNTER(this_instr[1].cache);
+ #endif /* ENABLE_SPECIALIZATION */
+ }
+ // _CONTAINS_OP
+ {
+ int res = PySequence_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_DICT) {
+ frame->instr_ptr = next_instr;
+ next_instr += 2;
+ INSTRUCTION_STATS(CONTAINS_OP_DICT);
+ 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(!PyDict_CheckExact(right), CONTAINS_OP);
+ int res = PyDict_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_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;
+ INSTRUCTION_STATS(CONTAINS_OP_SET);
+ 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(!PySet_CheckExact(right), CONTAINS_OP);
+ int res = _PySet_Contains((PySetObject *)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_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];
- int res = PySequence_Contains(right, left);
+ 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;
diff --git a/Python/opcode_targets.h b/Python/opcode_targets.h
index e664e63..6b3846d 100644
--- a/Python/opcode_targets.h
+++ b/Python/opcode_targets.h
@@ -182,6 +182,11 @@ static void *opcode_targets[256] = {
&&TARGET_COMPARE_OP_FLOAT,
&&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,
@@ -230,11 +235,6 @@ static void *opcode_targets[256] = {
&&_unknown_opcode,
&&_unknown_opcode,
&&_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 a114b03..a19010c 100644
--- a/Python/optimizer_cases.c.h
+++ b/Python/optimizer_cases.c.h
@@ -1206,6 +1206,51 @@
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);
+ if (b == NULL) goto out_of_space;
+ stack_pointer[-2] = b;
+ stack_pointer += -1;
+ 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);
+ if (b == NULL) goto out_of_space;
+ stack_pointer[-2] = b;
+ stack_pointer += -1;
+ 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 f83d8a9..5d339b8 100644
--- a/Python/specialize.c
+++ b/Python/specialize.c
@@ -103,6 +103,7 @@ _Py_GetSpecializationStats(void) {
return NULL;
}
int err = 0;
+ err += add_stat_dict(stats, CONTAINS_OP, "contains_op");
err += add_stat_dict(stats, LOAD_SUPER_ATTR, "load_super_attr");
err += add_stat_dict(stats, LOAD_ATTR, "load_attr");
err += add_stat_dict(stats, LOAD_GLOBAL, "load_global");
@@ -2561,6 +2562,43 @@ 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);
+ if (PyUnicode_CheckExact(value)) {
+ instr->op.code = CONTAINS_OP_STR;
+ goto success;
+ }
+ if (PyList_CheckExact(value)) {
+ instr->op.code = CONTAINS_OP_LIST;
+ goto success;
+ }
+ if (PyTuple_CheckExact(value)) {
+ instr->op.code = CONTAINS_OP_TUPLE;
+ goto success;
+ }
+ if (PyDict_CheckExact(value)) {
+ instr->op.code = CONTAINS_OP_DICT;
+ goto success;
+ }
+ if (PySet_CheckExact(value)) {
+ instr->op.code = CONTAINS_OP_SET;
+ goto success;
+ }
+
+
+ STAT_INC(CONTAINS_OP, failure);
+ instr->op.code = CONTAINS_OP;
+ cache->counter = adaptive_counter_backoff(cache->counter);
+ return;
+success:
+ STAT_INC(CONTAINS_OP, success);
+ cache->counter = adaptive_counter_cooldown();
+}
+
/* Code init cleanup.
* CALL_ALLOC_AND_ENTER_INIT will set up
* the frame to execute the EXIT_INIT_CHECK