summaryrefslogtreecommitdiffstats
path: root/Python/bytecodes.c
diff options
context:
space:
mode:
authorBrandt Bucher <brandtbucher@microsoft.com>2023-06-29 20:49:54 (GMT)
committerGitHub <noreply@github.com>2023-06-29 20:49:54 (GMT)
commit7b2d94d87513967b357c658c6e7e1b8c8d02487d (patch)
treebdd79e2c20b235f3d4c1272c8c8e2f1880bfb129 /Python/bytecodes.c
parent6e9f83d9aee34192de5d0ef7285be23514911ccd (diff)
downloadcpython-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.c144
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);
}