mirror of
https://github.com/python/cpython.git
synced 2026-05-06 04:37:33 -04:00
gh-149049: Fix jit binary op stack underflow (GH-149076)
This commit is contained in:
@@ -3919,6 +3919,38 @@ class TestUopsOptimization(unittest.TestCase):
|
||||
expected = TIER2_THRESHOLD * (5.0 / Fraction(4))
|
||||
self.assertAlmostEqual(res, float(expected))
|
||||
|
||||
def test_float_truediv_partial_float_no_stack_underflow(self):
|
||||
# gh-149049: a speculative _GUARD_*_FLOAT for a partially-float
|
||||
# truediv/remainder must not drop the original _BINARY_OP.
|
||||
def truediv(args):
|
||||
n, = args
|
||||
nan = float("nan")
|
||||
def victim(a=0, b=nan, c=2):
|
||||
return (a + b) / c
|
||||
for _ in range(n):
|
||||
victim()
|
||||
|
||||
def remainder(args):
|
||||
n, = args
|
||||
nan = float("nan")
|
||||
def victim(a=0, b=nan, c=2):
|
||||
return (a + b) % c
|
||||
for _ in range(n):
|
||||
victim()
|
||||
|
||||
for testfunc in (truediv, remainder):
|
||||
with self.subTest(op=testfunc.__name__):
|
||||
# Iterations must be high enough that the buggy trace
|
||||
# is not only built but executed (where it underflows).
|
||||
_, ex = self._run_with_optimizer(
|
||||
testfunc, (TIER2_THRESHOLD * 10,))
|
||||
self.assertIsNotNone(ex)
|
||||
uops = get_opnames(ex)
|
||||
self.assertTrue(
|
||||
"_GUARD_TOS_FLOAT" in uops or "_GUARD_NOS_FLOAT" in uops,
|
||||
uops,
|
||||
)
|
||||
|
||||
def test_int_add_inplace_unique_lhs(self):
|
||||
# a * b produces a unique compact int; adding c reuses it in place
|
||||
def testfunc(args):
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
Fix stack underflow for ``BINARY_OP`` in tier 2.
|
||||
@@ -293,6 +293,7 @@ dummy_func(void) {
|
||||
|| oparg == NB_INPLACE_TRUE_DIVIDE);
|
||||
bool is_remainder = (oparg == NB_REMAINDER
|
||||
|| oparg == NB_INPLACE_REMAINDER);
|
||||
int emit_op = _BINARY_OP;
|
||||
// Promote probable-float operands to known floats via speculative
|
||||
// guards. _RECORD_TOS_TYPE / _RECORD_NOS_TYPE in the BINARY_OP macro
|
||||
// record the observed operand type during tracing, which
|
||||
@@ -318,17 +319,17 @@ dummy_func(void) {
|
||||
}
|
||||
if (is_truediv && lhs_float && rhs_float) {
|
||||
if (PyJitRef_IsUnique(lhs)) {
|
||||
ADD_OP(_BINARY_OP_TRUEDIV_FLOAT_INPLACE, 0, 0);
|
||||
emit_op = _BINARY_OP_TRUEDIV_FLOAT_INPLACE;
|
||||
l = sym_new_null(ctx);
|
||||
r = rhs;
|
||||
}
|
||||
else if (PyJitRef_IsUnique(rhs)) {
|
||||
ADD_OP(_BINARY_OP_TRUEDIV_FLOAT_INPLACE_RIGHT, 0, 0);
|
||||
emit_op = _BINARY_OP_TRUEDIV_FLOAT_INPLACE_RIGHT;
|
||||
l = lhs;
|
||||
r = sym_new_null(ctx);
|
||||
}
|
||||
else {
|
||||
ADD_OP(_BINARY_OP_TRUEDIV_FLOAT, 0, 0);
|
||||
emit_op = _BINARY_OP_TRUEDIV_FLOAT;
|
||||
l = lhs;
|
||||
r = rhs;
|
||||
}
|
||||
@@ -382,6 +383,7 @@ dummy_func(void) {
|
||||
else {
|
||||
res = PyJitRef_MakeUnique(sym_new_type(ctx, &PyFloat_Type));
|
||||
}
|
||||
ADD_OP(emit_op, oparg, 0);
|
||||
}
|
||||
|
||||
op(_BINARY_OP_ADD_INT, (left, right -- res, l, r)) {
|
||||
|
||||
Generated
+5
-3
@@ -5242,6 +5242,7 @@
|
||||
|| oparg == NB_INPLACE_TRUE_DIVIDE);
|
||||
bool is_remainder = (oparg == NB_REMAINDER
|
||||
|| oparg == NB_INPLACE_REMAINDER);
|
||||
int emit_op = _BINARY_OP;
|
||||
if (is_truediv || is_remainder) {
|
||||
if (!sym_has_type(rhs)
|
||||
&& sym_get_probable_type(rhs) == &PyFloat_Type) {
|
||||
@@ -5258,17 +5259,17 @@
|
||||
}
|
||||
if (is_truediv && lhs_float && rhs_float) {
|
||||
if (PyJitRef_IsUnique(lhs)) {
|
||||
ADD_OP(_BINARY_OP_TRUEDIV_FLOAT_INPLACE, 0, 0);
|
||||
emit_op = _BINARY_OP_TRUEDIV_FLOAT_INPLACE;
|
||||
l = sym_new_null(ctx);
|
||||
r = rhs;
|
||||
}
|
||||
else if (PyJitRef_IsUnique(rhs)) {
|
||||
ADD_OP(_BINARY_OP_TRUEDIV_FLOAT_INPLACE_RIGHT, 0, 0);
|
||||
emit_op = _BINARY_OP_TRUEDIV_FLOAT_INPLACE_RIGHT;
|
||||
l = lhs;
|
||||
r = sym_new_null(ctx);
|
||||
}
|
||||
else {
|
||||
ADD_OP(_BINARY_OP_TRUEDIV_FLOAT, 0, 0);
|
||||
emit_op = _BINARY_OP_TRUEDIV_FLOAT;
|
||||
l = lhs;
|
||||
r = rhs;
|
||||
}
|
||||
@@ -5304,6 +5305,7 @@
|
||||
else {
|
||||
res = PyJitRef_MakeUnique(sym_new_type(ctx, &PyFloat_Type));
|
||||
}
|
||||
ADD_OP(emit_op, oparg, 0);
|
||||
CHECK_STACK_BOUNDS(1);
|
||||
stack_pointer[-2] = res;
|
||||
stack_pointer[-1] = l;
|
||||
|
||||
Reference in New Issue
Block a user