diff options
Diffstat (limited to 'Python')
-rw-r--r-- | Python/bytecodes.c | 64 | ||||
-rw-r--r-- | Python/executor_cases.c.h | 90 | ||||
-rw-r--r-- | Python/generated_cases.c.h | 134 | ||||
-rw-r--r-- | Python/opcode_targets.h | 10 | ||||
-rw-r--r-- | Python/optimizer_cases.c.h | 45 | ||||
-rw-r--r-- | Python/specialize.c | 38 |
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 |