LibJS+LibCrypto: Fix SignedBitInteger::bitwise_not and use it in LibJS

Bitwise operators are defined on two's complement, but SignedBitInteger
uses sign-magnitude. Correctly convert between the two.

Let LibJS delegate to SignedBitInteger for bitwise_not, like it does
for all other bitwise_ operations on bigints.

No behavior change (LibJS is now the only client of
SignedBitInteger::bitwise_not()).
This commit is contained in:
Nico Weber 2022-01-17 12:22:51 -05:00 committed by Ali Mohammad Pur
parent ec37eadb39
commit 945d962322
Notes: sideshowbarker 2024-07-17 20:40:21 +09:00
4 changed files with 15 additions and 5 deletions

View file

@ -467,6 +467,12 @@ TEST_CASE(test_bigint_bitwise_and_different_lengths)
EXPECT_EQ(num1.bitwise_and(num2), "1180290"_bigint);
}
TEST_CASE(test_signed_bigint_bitwise_not)
{
EXPECT_EQ("3"_sbigint.bitwise_not(), "-4"_sbigint);
EXPECT_EQ("-1"_sbigint.bitwise_not(), "0"_sbigint);
}
TEST_CASE(test_signed_bigint_bitwise_and)
{
auto num1 = "-1234567"_sbigint;

View file

@ -160,7 +160,12 @@ FLATTEN SignedBigInteger SignedBigInteger::bitwise_xor(const UnsignedBigInteger&
FLATTEN SignedBigInteger SignedBigInteger::bitwise_not() const
{
return { unsigned_value().bitwise_not(), !m_sign };
// Bitwise operators assume two's complement, while SignedBigInteger uses sign-magnitude.
// In two's complement, -x := ~x + 1.
// Hence, ~x == -x -1 == -(x + 1).
SignedBigInteger result = plus(SignedBigInteger { 1 });
result.negate();
return result;
}
FLATTEN SignedBigInteger SignedBigInteger::multiplied_by(UnsignedBigInteger const& other) const

View file

@ -881,10 +881,7 @@ ThrowCompletionOr<Value> bitwise_not(GlobalObject& global_object, Value lhs)
auto lhs_numeric = TRY(lhs.to_numeric(global_object));
if (lhs_numeric.is_number())
return Value(~TRY(lhs_numeric.to_i32(global_object)));
auto big_integer_bitwise_not = lhs_numeric.as_bigint().big_integer();
big_integer_bitwise_not = big_integer_bitwise_not.plus(Crypto::SignedBigInteger { 1 });
big_integer_bitwise_not.negate();
return Value(js_bigint(vm, big_integer_bitwise_not));
return Value(js_bigint(vm, lhs_numeric.as_bigint().big_integer().bitwise_not()));
}
// 13.5.4 Unary + Operator, https://tc39.es/ecma262/#sec-unary-plus-operator

View file

@ -40,6 +40,8 @@ describe("correct behavior", () => {
expect(1n | 2n).toBe(3n);
expect(5n ^ 3n).toBe(6n);
expect(~1n).toBe(-2n);
expect(~-1n).toBe(0n);
expect(5n << 2n).toBe(20n);
expect(7n >> 1n).toBe(3n);
});