Skip to content

Commit

Permalink
LibJS: Add fast paths for bitwise ops on 2x Int32 JS::Value
Browse files Browse the repository at this point in the history
~9% speed-up on Kraken/stanford-crypto-aes.js :^)
  • Loading branch information
awesomekling committed Jul 1, 2023
1 parent 9840439 commit 6e1b905
Show file tree
Hide file tree
Showing 2 changed files with 35 additions and 11 deletions.
24 changes: 24 additions & 0 deletions Userland/Libraries/LibJS/Runtime/Value.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1344,6 +1344,10 @@ ThrowCompletionOr<Value> less_than_equals(VM& vm, Value lhs, Value rhs)
// BitwiseANDExpression : BitwiseANDExpression & EqualityExpression
ThrowCompletionOr<Value> bitwise_and(VM& vm, Value lhs, Value rhs)
{
// OPTIMIZATION: Fast path when both values are Int32.
if (lhs.is_int32() && rhs.is_int32())
return Value(lhs.as_i32() & rhs.as_i32());

// 13.15.3 ApplyStringOrNumericBinaryOperator ( lval, opText, rval ), https://tc39.es/ecma262/#sec-applystringornumericbinaryoperator
// 1-2, 6. N/A.

Expand Down Expand Up @@ -1377,6 +1381,10 @@ ThrowCompletionOr<Value> bitwise_and(VM& vm, Value lhs, Value rhs)
// BitwiseORExpression : BitwiseORExpression | BitwiseXORExpression
ThrowCompletionOr<Value> bitwise_or(VM& vm, Value lhs, Value rhs)
{
// OPTIMIZATION: Fast path when both values are Int32.
if (lhs.is_int32() && rhs.is_int32())
return Value(lhs.as_i32() | rhs.as_i32());

// 13.15.3 ApplyStringOrNumericBinaryOperator ( lval, opText, rval ), https://tc39.es/ecma262/#sec-applystringornumericbinaryoperator
// 1-2, 6. N/A.

Expand Down Expand Up @@ -1414,6 +1422,10 @@ ThrowCompletionOr<Value> bitwise_or(VM& vm, Value lhs, Value rhs)
// BitwiseXORExpression : BitwiseXORExpression ^ BitwiseANDExpression
ThrowCompletionOr<Value> bitwise_xor(VM& vm, Value lhs, Value rhs)
{
// OPTIMIZATION: Fast path when both values are Int32.
if (lhs.is_int32() && rhs.is_int32())
return Value(lhs.as_i32() ^ rhs.as_i32());

// 13.15.3 ApplyStringOrNumericBinaryOperator ( lval, opText, rval ), https://tc39.es/ecma262/#sec-applystringornumericbinaryoperator
// 1-2, 6. N/A.

Expand Down Expand Up @@ -1598,6 +1610,12 @@ ThrowCompletionOr<Value> left_shift(VM& vm, Value lhs, Value rhs)
// ShiftExpression : ShiftExpression >> AdditiveExpression
ThrowCompletionOr<Value> right_shift(VM& vm, Value lhs, Value rhs)
{
// OPTIMIZATION: Fast path when both values are suitable Int32 values.
if (lhs.is_int32() && rhs.is_int32() && rhs.as_i32() > 0) {
auto shift_count = static_cast<u32>(rhs.as_i32()) % 32;
return Value(lhs.as_i32() >> shift_count);
}

// 13.15.3 ApplyStringOrNumericBinaryOperator ( lval, opText, rval ), https://tc39.es/ecma262/#sec-applystringornumericbinaryoperator
// 1-2, 6. N/A.

Expand Down Expand Up @@ -1649,6 +1667,12 @@ ThrowCompletionOr<Value> right_shift(VM& vm, Value lhs, Value rhs)
// ShiftExpression : ShiftExpression >>> AdditiveExpression
ThrowCompletionOr<Value> unsigned_right_shift(VM& vm, Value lhs, Value rhs)
{
// OPTIMIZATION: Fast path when both values are suitable Int32 values.
if (lhs.is_int32() && rhs.is_int32() && lhs.as_i32() >= 0 && rhs.as_i32() > 0) {
auto shift_count = static_cast<u32>(rhs.as_i32()) % 32;
return Value(static_cast<u32>(lhs.as_i32()) >> shift_count);
}

// 13.15.3 ApplyStringOrNumericBinaryOperator ( lval, opText, rval ), https://tc39.es/ecma262/#sec-applystringornumericbinaryoperator
// 1-2, 5-6. N/A.

Expand Down
22 changes: 11 additions & 11 deletions Userland/Libraries/LibJS/Runtime/Value.h
Original file line number Diff line number Diff line change
Expand Up @@ -428,6 +428,17 @@ class Value {
#endif
}

// A double is any Value which does not have the full exponent and top mantissa bit set or has
// exactly only those bits set.
bool is_double() const { return (m_value.encoded & CANON_NAN_BITS) != CANON_NAN_BITS || (m_value.encoded == CANON_NAN_BITS); }
bool is_int32() const { return m_value.tag == INT32_TAG; }

i32 as_i32() const
{
VERIFY(is_int32());
return static_cast<i32>(m_value.encoded & 0xFFFFFFFF);
}

private:
Value(u64 tag, u64 val)
{
Expand Down Expand Up @@ -459,17 +470,6 @@ class Value {
}
}

// A double is any Value which does not have the full exponent and top mantissa bit set or has
// exactly only those bits set.
bool is_double() const { return (m_value.encoded & CANON_NAN_BITS) != CANON_NAN_BITS || (m_value.encoded == CANON_NAN_BITS); }
bool is_int32() const { return m_value.tag == INT32_TAG; }

i32 as_i32() const
{
VERIFY(is_int32());
return static_cast<i32>(m_value.encoded & 0xFFFFFFFF);
}

template<typename PointerType>
PointerType* extract_pointer() const
{
Expand Down

0 comments on commit 6e1b905

Please sign in to comment.