/
githubmirror
/
node
Обзор
Документация
Войти
/
githubmirror
/
node
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
main
deps/v8/src/utils/boxed-float.h
220 строк
7 KB
Michaël Zasso
deps: update V8 to 14.6.202.33
24 апр 2026, 19:01
Не верифицирован
24 апр 2026, 19:01
f1e0b83
Код
Авторство
О чём код?
// Copyright 2017 the V8 project authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #ifndef V8_UTILS_BOXED_FLOAT_H_ #define V8_UTILS_BOXED_FLOAT_H_ #include <cmath> #include "absl/strings/str_format.h" #include "src/base/hashing.h" #include "src/base/macros.h" #include "src/base/numbers/double.h" #include "src/common/globals.h" #include "src/utils/ostreams.h" namespace v8 { namespace internal { // TODO(ahaas): Make these classes with the one in double.h // Safety wrapper for a 32-bit floating-point value to make sure we don't lose // the exact bit pattern during deoptimization when passing this value. class Float32 { public: constexpr Float32() = default; // This constructor does not guarantee that bit pattern of the input value // is preserved if the input is a NaN. explicit Float32(float value) : bit_pattern_(base::bit_cast<uint32_t>(value)) { // Check that the provided value is not a NaN, because the bit pattern of a // NaN may be changed by a base::bit_cast, e.g. for signalling NaNs on // ia32. DCHECK(!std::isnan(value)); } constexpr uint32_t get_bits() const { return bit_pattern_; } float get_scalar() const { return base::bit_cast<float>(bit_pattern_); } bool is_nan() const { // Even though {get_scalar()} might set the quiet NaN bit, it's ok here, // because this does not change the is_nan property. bool nan = std::isnan(get_scalar()); DCHECK_EQ(nan, exponent() == 0xff && mantissa() != 0); return nan; } bool is_quiet_nan() const { return is_nan() && (bit_pattern_ & kQuietNanBit); } bool is_inf() const { bool inf = std::isinf(get_scalar()); DCHECK_EQ(inf, exponent() == 0xff && mantissa() == 0); return inf; } constexpr bool is_negative() const { return bit_pattern_ & kSignBit; } V8_WARN_UNUSED_RESULT Float32 to_quiet_nan() const { DCHECK(is_nan()); Float32 quiet_nan{bit_pattern_ | kQuietNanBit}; DCHECK(quiet_nan.is_quiet_nan()); return quiet_nan; } V8_WARN_UNUSED_RESULT Float32 to_negative() const { return Float32::FromBits(bit_pattern_ | kSignBit); } constexpr bool operator==(const Float32&) const = default; constexpr Float32 operator-() const { return Float32::FromBits(bit_pattern_ ^ kSignBit); } static constexpr Float32 FromBits(uint32_t bits) { return Float32(bits); } // This static constructor allows passing NaNs, but as the signalling bit // might get lost when passing the float parameter we explicitly put this in // the method name, and still DCHECK for it (which might not trigger if a // signalling NaN is implicitly silenced when passed here). static Float32 FromNonSignallingFloat(float value) { Float32 result = Float32::FromBits(base::bit_cast<uint32_t>(value)); DCHECK(!result.is_nan() || result.is_quiet_nan()); return result; } static constexpr Float32 quiet_nan() { return FromBits((0xffu << kExponentShift) | kQuietNanBit); } static constexpr Float32 infinity() { return FromBits(0xffu << kExponentShift); } // absl stringify support, enabling e.g. FuzzTest outputting Float32 values // instead of printing "unprintable value". template <typename Sink> friend void AbslStringify(Sink& sink, Float32 f) { absl::Format(&sink, "%f (0x%08x)", f.get_scalar(), f.get_bits()); } private: explicit constexpr Float32(uint32_t bit_pattern) : bit_pattern_(bit_pattern) {} static constexpr int kExponentShift = 23; static constexpr uint32_t kQuietNanBit = 1 << 22; static constexpr uint32_t kSignBit = 1 << 31; uint32_t exponent() const { return (bit_pattern_ >> kExponentShift) & 0xff; } uint32_t mantissa() const { return bit_pattern_ & ((1 << kExponentShift) - 1); } uint32_t bit_pattern_ = 0; }; ASSERT_TRIVIALLY_COPYABLE(Float32); inline std::ostream& operator<<(std::ostream& os, const Float32& float32) { return os << float32.get_scalar() << " (" << AsHex(float32.get_bits(), 8, true) << ")"; } // Safety wrapper for a 64-bit floating-point value to make sure we don't lose // the exact bit pattern during deoptimization when passing this value. // TODO(ahaas): Unify this class with Double in double.h class Float64 { public: Float64() = default; // This constructor does not guarantee that bit pattern of the input value // is preserved if the input is a NaN. explicit Float64(double value) : bit_pattern_(base::bit_cast<uint64_t>(value)) { // Check that the provided value is not a NaN, because the bit pattern of a // NaN may be changed by a base::bit_cast, e.g. for signalling NaNs on // ia32. DCHECK(!std::isnan(value)); } explicit Float64(base::Double value) : bit_pattern_(value.AsUint64()) {} static constexpr Float64 quiet_nan() { return Float64::FromBits( base::double_to_uint64(std::numeric_limits<double>::quiet_NaN())); } static constexpr Float64 hole_nan() { return Float64::FromBits(kHoleNanInt64); } #ifdef V8_ENABLE_UNDEFINED_DOUBLE static constexpr Float64 undefined_nan() { return Float64::FromBits(kUndefinedNanInt64); } #endif uint64_t get_bits() const { return bit_pattern_; } double get_scalar() const { return base::bit_cast<double>(bit_pattern_); } bool is_hole_nan() const { return bit_pattern_ == kHoleNanInt64; } #ifdef V8_ENABLE_UNDEFINED_DOUBLE bool is_undefined_nan() const { return bit_pattern_ == kUndefinedNanInt64; } #endif // V8_ENABLE_UNDEFINED_DOUBLE bool is_undefined_or_hole_nan() const { return #ifdef V8_ENABLE_UNDEFINED_DOUBLE is_undefined_nan() || #endif is_hole_nan(); } bool is_nan() const { // Even though {get_scalar()} might set the quiet NaN bit, it's ok here, // because this does not change the is_nan property. bool nan = std::isnan(get_scalar()); DCHECK_EQ(nan, exponent() == 0x7ff && mantissa() != 0); return nan; } bool is_quiet_nan() const { return is_nan() && (bit_pattern_ & (uint64_t{1} << 51)); } V8_WARN_UNUSED_RESULT Float64 to_quiet_nan() const { DCHECK(is_nan()); Float64 quiet_nan{bit_pattern_ | (uint64_t{1} << 51)}; DCHECK(quiet_nan.is_quiet_nan()); return quiet_nan; } static constexpr Float64 FromBits(uint64_t bits) { return Float64(bits); } constexpr bool operator==(const Float64&) const = default; size_t hash_value() const { return base::hash_value(bit_pattern_); } private: explicit constexpr Float64(uint64_t bit_pattern) : bit_pattern_(bit_pattern) {} uint64_t exponent() const { return (bit_pattern_ >> 52) & ((1 << 11) - 1); } uint64_t mantissa() const { return bit_pattern_ & ((uint64_t{1} << 52) - 1); } uint64_t bit_pattern_ = 0; }; ASSERT_TRIVIALLY_COPYABLE(Float64); inline std::ostream& operator<<(std::ostream& os, const Float64& float64) { return os << float64.get_scalar() << " (" << AsHex(float64.get_bits(), 16, true) << ")"; } } // namespace internal } // namespace v8 #endif // V8_UTILS_BOXED_FLOAT_H_