diff options
author | Brandt Bucher <brandtbucher@microsoft.com> | 2023-06-29 20:49:54 (GMT) |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-06-29 20:49:54 (GMT) |
commit | 7b2d94d87513967b357c658c6e7e1b8c8d02487d (patch) | |
tree | bdd79e2c20b235f3d4c1272c8c8e2f1880bfb129 /Python/bytecodes.c | |
parent | 6e9f83d9aee34192de5d0ef7285be23514911ccd (diff) | |
download | cpython-7b2d94d87513967b357c658c6e7e1b8c8d02487d.zip cpython-7b2d94d87513967b357c658c6e7e1b8c8d02487d.tar.gz cpython-7b2d94d87513967b357c658c6e7e1b8c8d02487d.tar.bz2 |
GH-106008: Make implicit boolean conversions explicit (GH-106003)
Diffstat (limited to 'Python/bytecodes.c')
-rw-r--r-- | Python/bytecodes.c | 144 |
1 files changed, 100 insertions, 44 deletions
diff --git a/Python/bytecodes.c b/Python/bytecodes.c index 1d9664b..cd23e66 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -279,15 +279,90 @@ dummy_func( } inst(UNARY_NOT, (value -- res)) { + assert(PyBool_Check(value)); + res = Py_IsFalse(value) ? Py_True : Py_False; + } + + family(to_bool, INLINE_CACHE_ENTRIES_TO_BOOL) = { + TO_BOOL, + TO_BOOL_ALWAYS_TRUE, + TO_BOOL_BOOL, + TO_BOOL_INT, + TO_BOOL_LIST, + TO_BOOL_NONE, + TO_BOOL_STR, + }; + + inst(TO_BOOL, (unused/1, unused/2, value -- res)) { + #if ENABLE_SPECIALIZATION + _PyToBoolCache *cache = (_PyToBoolCache *)next_instr; + if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { + next_instr--; + _Py_Specialize_ToBool(value, next_instr); + DISPATCH_SAME_OPARG(); + } + STAT_INC(TO_BOOL, deferred); + DECREMENT_ADAPTIVE_COUNTER(cache->counter); + #endif /* ENABLE_SPECIALIZATION */ int err = PyObject_IsTrue(value); DECREF_INPUTS(); ERROR_IF(err < 0, error); - if (err == 0) { - res = Py_True; + res = err ? Py_True : Py_False; + } + + inst(TO_BOOL_BOOL, (unused/1, unused/2, value -- value)) { + DEOPT_IF(!PyBool_Check(value), TO_BOOL); + STAT_INC(TO_BOOL, hit); + } + + inst(TO_BOOL_INT, (unused/1, unused/2, value -- res)) { + DEOPT_IF(!PyLong_CheckExact(value), TO_BOOL); + STAT_INC(TO_BOOL, hit); + if (_PyLong_IsZero((PyLongObject *)value)) { + assert(_Py_IsImmortal(value)); + res = Py_False; } else { + DECREF_INPUTS(); + res = Py_True; + } + } + + inst(TO_BOOL_LIST, (unused/1, unused/2, value -- res)) { + DEOPT_IF(!PyList_CheckExact(value), TO_BOOL); + STAT_INC(TO_BOOL, hit); + res = Py_SIZE(value) ? Py_True : Py_False; + DECREF_INPUTS(); + } + + inst(TO_BOOL_NONE, (unused/1, unused/2, value -- res)) { + // This one is a bit weird, because we expect *some* failures: + DEOPT_IF(!Py_IsNone(value), TO_BOOL); + STAT_INC(TO_BOOL, hit); + res = Py_False; + } + + inst(TO_BOOL_STR, (unused/1, unused/2, value -- res)) { + DEOPT_IF(!PyUnicode_CheckExact(value), TO_BOOL); + STAT_INC(TO_BOOL, hit); + if (value == &_Py_STR(empty)) { + assert(_Py_IsImmortal(value)); res = Py_False; } + else { + assert(Py_SIZE(value)); + DECREF_INPUTS(); + res = Py_True; + } + } + + inst(TO_BOOL_ALWAYS_TRUE, (unused/1, version/2, value -- res)) { + // This one is a bit weird, because we expect *some* failures: + assert(version); + DEOPT_IF(Py_TYPE(value)->tp_version_tag != version, TO_BOOL); + STAT_INC(TO_BOOL, hit); + DECREF_INPUTS(); + res = Py_True; } inst(UNARY_INVERT, (value -- res)) { @@ -2024,10 +2099,16 @@ dummy_func( STAT_INC(COMPARE_OP, deferred); DECREMENT_ADAPTIVE_COUNTER(cache->counter); #endif /* ENABLE_SPECIALIZATION */ - assert((oparg >> 4) <= Py_GE); - res = PyObject_RichCompare(left, right, oparg>>4); + assert((oparg >> 5) <= Py_GE); + res = PyObject_RichCompare(left, right, oparg >> 5); DECREF_INPUTS(); ERROR_IF(res == NULL, error); + if (oparg & 16) { + int res_bool = PyObject_IsTrue(res); + Py_DECREF(res); + ERROR_IF(res_bool < 0, error); + res = res_bool ? Py_True : Py_False; + } } inst(COMPARE_OP_FLOAT, (unused/1, left, right -- res)) { @@ -2041,6 +2122,7 @@ dummy_func( _Py_DECREF_SPECIALIZED(left, _PyFloat_ExactDealloc); _Py_DECREF_SPECIALIZED(right, _PyFloat_ExactDealloc); res = (sign_ish & oparg) ? Py_True : Py_False; + // It's always a bool, so we don't care about oparg & 16. } // Similar to COMPARE_OP_FLOAT @@ -2059,6 +2141,7 @@ dummy_func( _Py_DECREF_SPECIALIZED(left, (destructor)PyObject_Free); _Py_DECREF_SPECIALIZED(right, (destructor)PyObject_Free); res = (sign_ish & oparg) ? Py_True : Py_False; + // It's always a bool, so we don't care about oparg & 16. } // Similar to COMPARE_OP_FLOAT, but for ==, != only @@ -2067,13 +2150,14 @@ dummy_func( DEOPT_IF(!PyUnicode_CheckExact(right), COMPARE_OP); STAT_INC(COMPARE_OP, hit); int eq = _PyUnicode_Equal(left, right); - assert((oparg >>4) == Py_EQ || (oparg >>4) == Py_NE); + assert((oparg >> 5) == Py_EQ || (oparg >> 5) == Py_NE); _Py_DECREF_SPECIALIZED(left, _PyUnicode_ExactDealloc); _Py_DECREF_SPECIALIZED(right, _PyUnicode_ExactDealloc); assert(eq == 0 || eq == 1); assert((oparg & 0xf) == COMPARISON_NOT_EQUALS || (oparg & 0xf) == COMPARISON_EQUALS); assert(COMPARISON_NOT_EQUALS + 1 == COMPARISON_EQUALS); res = ((COMPARISON_NOT_EQUALS + eq) & oparg) ? Py_True : Py_False; + // It's always a bool, so we don't care about oparg & 16. } inst(IS_OP, (left, right -- b)) { @@ -2183,35 +2267,13 @@ dummy_func( } inst(POP_JUMP_IF_FALSE, (cond -- )) { - if (Py_IsFalse(cond)) { - JUMPBY(oparg); - } - else if (!Py_IsTrue(cond)) { - int err = PyObject_IsTrue(cond); - DECREF_INPUTS(); - if (err == 0) { - JUMPBY(oparg); - } - else { - ERROR_IF(err < 0, error); - } - } + assert(PyBool_Check(cond)); + JUMPBY(oparg * Py_IsFalse(cond)); } inst(POP_JUMP_IF_TRUE, (cond -- )) { - if (Py_IsTrue(cond)) { - JUMPBY(oparg); - } - else if (!Py_IsFalse(cond)) { - int err = PyObject_IsTrue(cond); - DECREF_INPUTS(); - if (err > 0) { - JUMPBY(oparg); - } - else { - ERROR_IF(err < 0, error); - } - } + assert(PyBool_Check(cond)); + JUMPBY(oparg * Py_IsTrue(cond)); } inst(POP_JUMP_IF_NOT_NONE, (value -- )) { @@ -3515,23 +3577,17 @@ dummy_func( inst(INSTRUMENTED_POP_JUMP_IF_TRUE, ( -- )) { PyObject *cond = POP(); - int err = PyObject_IsTrue(cond); - Py_DECREF(cond); - ERROR_IF(err < 0, error); - _Py_CODEUNIT *here = next_instr-1; - assert(err == 0 || err == 1); - int offset = err*oparg; + assert(PyBool_Check(cond)); + _Py_CODEUNIT *here = next_instr - 1; + int offset = Py_IsTrue(cond) * oparg; INSTRUMENTED_JUMP(here, next_instr + offset, PY_MONITORING_EVENT_BRANCH); } inst(INSTRUMENTED_POP_JUMP_IF_FALSE, ( -- )) { PyObject *cond = POP(); - int err = PyObject_IsTrue(cond); - Py_DECREF(cond); - ERROR_IF(err < 0, error); - _Py_CODEUNIT *here = next_instr-1; - assert(err == 0 || err == 1); - int offset = (1-err)*oparg; + assert(PyBool_Check(cond)); + _Py_CODEUNIT *here = next_instr - 1; + int offset = Py_IsFalse(cond) * oparg; INSTRUMENTED_JUMP(here, next_instr + offset, PY_MONITORING_EVENT_BRANCH); } @@ -3558,7 +3614,7 @@ dummy_func( } else { Py_DECREF(value); - offset = oparg; + offset = oparg; } INSTRUMENTED_JUMP(here, next_instr + offset, PY_MONITORING_EVENT_BRANCH); } |