From e67155638c28863e504b3b709a607f492bb0592e Mon Sep 17 00:00:00 2001 From: Andreas Kling Date: Thu, 7 Oct 2021 19:23:56 +0200 Subject: [PATCH] LibJS: Take advantage of Value::Type::Int32 in a bunch of functions If a JS::Value has type Int32, we know it's a finite, 32-bit integer. Use this information to avoid converting it to a double if possible. --- Userland/Libraries/LibJS/Runtime/Value.cpp | 12 ---- Userland/Libraries/LibJS/Runtime/Value.h | 74 +++++++++++++++++++--- 2 files changed, 65 insertions(+), 21 deletions(-) diff --git a/Userland/Libraries/LibJS/Runtime/Value.cpp b/Userland/Libraries/LibJS/Runtime/Value.cpp index 4415f765d7f..7078eb1369e 100644 --- a/Userland/Libraries/LibJS/Runtime/Value.cpp +++ b/Userland/Libraries/LibJS/Runtime/Value.cpp @@ -580,18 +580,6 @@ u64 Value::to_bigint_uint64(GlobalObject& global_object) const return bigint->big_integer().to_u64(); } -// FIXME: These two conversions are wrong for JS, and seem likely to be footguns -i32 Value::as_i32() const -{ - return static_cast(as_double()); -} - -u32 Value::as_u32() const -{ - VERIFY(as_double() >= 0); - return (u32)min(as_double(), (double)NumericLimits::max()); -} - double Value::to_double(GlobalObject& global_object) const { auto number = to_number(global_object); diff --git a/Userland/Libraries/LibJS/Runtime/Value.h b/Userland/Libraries/LibJS/Runtime/Value.h index feef1475c24..db22c57ebdf 100644 --- a/Userland/Libraries/LibJS/Runtime/Value.h +++ b/Userland/Libraries/LibJS/Runtime/Value.h @@ -67,15 +67,59 @@ public: bool is_constructor() const; ThrowCompletionOr is_regexp(GlobalObject&) const; - bool is_nan() const { return is_number() && __builtin_isnan(as_double()); } - bool is_infinity() const { return is_number() && __builtin_isinf(as_double()); } - bool is_positive_infinity() const { return is_number() && __builtin_isinf_sign(as_double()) > 0; } - bool is_negative_infinity() const { return is_number() && __builtin_isinf_sign(as_double()) < 0; } - bool is_positive_zero() const { return is_number() && bit_cast(as_double()) == 0; } - bool is_negative_zero() const { return is_number() && bit_cast(as_double()) == NEGATIVE_ZERO_BITS; } - bool is_integral_number() const { return is_finite_number() && trunc(as_double()) == as_double(); } + bool is_nan() const + { + if (type() == Type::Int32) + return false; + return is_number() && __builtin_isnan(as_double()); + } + + bool is_infinity() const + { + if (type() == Type::Int32) + return false; + return is_number() && __builtin_isinf(as_double()); + } + + bool is_positive_infinity() const + { + if (type() == Type::Int32) + return false; + return is_number() && __builtin_isinf_sign(as_double()) > 0; + } + + bool is_negative_infinity() const + { + if (type() == Type::Int32) + return false; + return is_number() && __builtin_isinf_sign(as_double()) < 0; + } + + bool is_positive_zero() const + { + if (type() == Type::Int32) + return as_i32() == 0; + return is_number() && bit_cast(as_double()) == 0; + } + + bool is_negative_zero() const + { + if (type() == Type::Int32) + return false; + return is_number() && bit_cast(as_double()) == NEGATIVE_ZERO_BITS; + } + + bool is_integral_number() const + { + if (type() == Type::Int32) + return true; + return is_finite_number() && trunc(as_double()) == as_double(); + } + bool is_finite_number() const { + if (type() == Type::Int32) + return true; if (!is_number()) return false; auto number = as_double(); @@ -242,8 +286,20 @@ public: FunctionObject& as_function(); FunctionObject const& as_function() const; - i32 as_i32() const; - u32 as_u32() const; + // FIXME: These two conversions are wrong for JS, and seem likely to be footguns + i32 as_i32() const + { + if (m_type == Type::Int32) + return m_value.as_i32; + return static_cast(as_double()); + } + u32 as_u32() const + { + if (m_type == Type::Int32 && m_value.as_i32 >= 0) + return m_value.as_i32; + VERIFY(as_double() >= 0); + return (u32)min(as_double(), (double)NumericLimits::max()); + } u64 encoded() const { return m_value.encoded; }