tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

Value.h (48668B)


      1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
      2 * vim: set ts=8 sts=2 et sw=2 tw=80:
      3 * This Source Code Form is subject to the terms of the Mozilla Public
      4 * License, v. 2.0. If a copy of the MPL was not distributed with this
      5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      6 
      7 /* JS::Value implementation. */
      8 
      9 #ifndef js_Value_h
     10 #define js_Value_h
     11 
     12 #include "mozilla/Attributes.h"
     13 #include "mozilla/Casting.h"
     14 #include "mozilla/FloatingPoint.h"
     15 #include "mozilla/Likely.h"
     16 #include "mozilla/Maybe.h"
     17 
     18 #include <limits> /* for std::numeric_limits */
     19 #include <type_traits>
     20 
     21 #include "jstypes.h"
     22 
     23 #include "js/HeapAPI.h"
     24 #include "js/RootingAPI.h"
     25 #include "js/TypeDecls.h"
     26 
     27 namespace JS {
     28 class JS_PUBLIC_API Value;
     29 }
     30 
     31 // [SMDOC] JS::Value Boxing Formats
     32 //
     33 // JS::Value is a 64-bit value, on all architectures. It is conceptually a
     34 // discriminated union of all the types of values that can be represented in SM:
     35 // - Object Pointers
     36 // - 64 bit IEEE 754 floats
     37 // - 32-bit integer values
     38 // - and quite a few more (see JSValueType)
     39 //
     40 // The ECMAScript standard specifies that ECMAScript numbers are IEEE 64-bit
     41 // floating-point values. A JS::Value can represent any JavaScript number
     42 // value directly, without referring to additional storage, or represent an
     43 // object, string, or other ECMAScript value, and remember which type it is.
     44 //
     45 // This may seem surprising: how can a 64-bit type hold all the 64-bit IEEE
     46 // values, and still distinguish them from objects, strings, and so on,
     47 // which have 64-bit addresses ?
     48 //
     49 // This is possible for two reasons:
     50 //
     51 // - First, ECMAScript implementations aren't required to distinguish all
     52 //   the values the IEEE 64-bit format can represent.
     53 //
     54 //   The IEEE 754 format for floating point numbers specifies that every
     55 //   floating-point value whose 11-bit exponent field is all ones, and whose
     56 //   52-bit fraction field is non-zero, has the value NaN. EMCAScript requires
     57 //   only one NaN value. This means we can use one IEEE NaN to represent
     58 //   ECMAScript's NaN, and use all the other 2^52-2 NaN bitstrings to
     59 //   represent the other ECMAScript values.
     60 //
     61 // - Second, on the 64 bit architectures we suppport, only the
     62 //   lower 48 bits of an address are currently significant. The upper sixteen
     63 //   bits are required to be the sign-extension of bit 48. Furthermore, user
     64 //   code always runs in "positive addresses": those in which bit 48 is zero. So
     65 //   we only actually need 47 bits to store all possible object or string
     66 //   addresses, even on 64-bit platforms.
     67 //
     68 //   Our memory initialization system ensures that all pointers we will store in
     69 //   objects use only 47 bits. See js::gc::MapAlignedPagesRandom.
     70 //
     71 //   The introduction of 5-level page tables, supporting 57-bit virtual
     72 //   addresses, is a potential complication. For now, large addresses are
     73 //   opt-in, and we simply don't use them.
     74 //
     75 // With a 52-bit fraction field, and 47 bits needed for the 'payload', we
     76 // have up to five bits left to store a 'tag' value, to indicate which
     77 // branch of our discriminated union is live. (In practice, one of those
     78 // bits is used up to simplify NaN representation; see micro-optimization 5
     79 // below.)
     80 //
     81 // Thus, we define JS::Value representations in terms of the IEEE 64-bit
     82 // floating-point format:
     83 //
     84 // - Any bitstring that IEEE calls a number or an infinity represents that
     85 //   ECMAScript number.
     86 //
     87 // - Any bitstring that IEEE calls a NaN represents either an ECMAScript NaN
     88 //   or a non-number ECMAScript value, as determined by a tag field stored
     89 //   towards the most significant end of the fraction field (exactly where
     90 //   depends on the address size). If the tag field indicates that this
     91 //   JS::Value is an object, the fraction field's least significant end
     92 //   holds the address of a JSObject; if a string, the address of a
     93 //   JSString; and so on.
     94 //
     95 //   To enforce this invariant, anywhere that may provide a numerical value
     96 //   which may have a non-canonical NaN value (NaN, but not the one we've chosen
     97 //   for ECMAScript) we must convert that to the canonical NaN. See
     98 //   JS::CanonicalizeNaN.
     99 //
    100 // We have two boxing modes defined: NUNBOX32 and PUNBOX64.The first is
    101 // "NaN unboxed boxing" (or Nunboxing), as non-Number payload are stored
    102 // unaltered in the lower bits. The second is "Packed NaN boxing" (or
    103 // punboxing), which is 'logically like nunboxing, but with all the unused bits
    104 // sucked out' [1],  as we rely on unused bits of the payload to pack the
    105 // payload in the lower bits using Nunboxing.
    106 //
    107 // - In NUNBOX32 the tag is stored in the least-significant bits of the high
    108 //   word of the NaN. Since it's used on 32-bit systems, this has the nice
    109 //   property that boxed values are simply stored in the low-word of the 8-byte
    110 //   NaN.
    111 //
    112 // - In PUNBOX64, since we need to store more pointer bits (47, see above), the
    113 //   tag is stored in the 5 most significant bits of the fraction adjacent to
    114 //   the exponent.
    115 //
    116 // Tag values are carefully ordered to support a set of micro-optimizations. In
    117 // particular:
    118 //
    119 // 1. Object is the highest tag, to simplify isPrimitive checks. (See
    120 //    ValueUpperExclPrimitiveTag)
    121 // 2. Numbers (Double and Int32) are the lowest tags, to simplify isNumber
    122 //    checks. (See ValueUpperInclNumberTag)
    123 // 3. Non-GC tags are ordered before GC-tags, to simplify isGCThing checks. (See
    124 //    ValueLowerInclGCThingTag)
    125 // 4. The tags for Object and Null differ by a single flipped bit, to simplify
    126 //    toObjectOrNull. (See ValueObjectOrNullBit)
    127 // 5. In PUNBOX64, the most significant bit of every non-Double tag is always
    128 //    set. This is to simplify isDouble checks. Note that the highest bitstring
    129 //    that corresponds to a non-NaN double is -Infinity:
    130 //      0xfff0_0000_0000_0000
    131 //    But the canonical hardware NaN (produced by, for example, 0/0) is:
    132 //      0x?ff8_0000_0000_0000
    133 //    on all platforms with JIT support*. (The most significant bit is the sign
    134 //    bit; it is 1 on x86, but 0 on ARM.) The most significant bit of the
    135 //    fraction field is set, which corresponds to the most significant of the 5
    136 //    tag bits. Because we only use tags that have the high bit set, any Value
    137 //    represented by a bitstring less than or equal to 0xfff8_..._0000 is a
    138 //    Double. (If we wanted to use all five bits, we could define 0x10 as
    139 //    JSVAL_TYPE_NAN, and mask off the most significant bit of the tag for
    140 //    IsDouble checks. This is not yet necessary, because we still have room
    141 //    left to allocate new tags.)
    142 //
    143 //    * But see JS_NONCANONICAL_HARDWARE_NAN below.
    144 //
    145 // [1]:
    146 // https://wingolog.org/archives/2011/05/18/value-representation-in-javascript-implementations#969f63bbe4eb912778c9da85feb0f5763e7a7862
    147 
    148 /* JS::Value can store a full int32_t. */
    149 #define JSVAL_INT_BITS 32
    150 #define JSVAL_INT_MIN ((int32_t)0x80000000)
    151 #define JSVAL_INT_MAX ((int32_t)0x7fffffff)
    152 
    153 #if defined(JS_NUNBOX32)
    154 #  define JSVAL_TAG_SHIFT 32
    155 #elif defined(JS_PUNBOX64)
    156 #  define JSVAL_TAG_SHIFT 47
    157 #endif
    158 
    159 // Use enums so that printing a JS::Value in the debugger shows nice
    160 // symbolic type tags.
    161 
    162 enum JSValueType : uint8_t {
    163  JSVAL_TYPE_DOUBLE = 0x00,
    164  JSVAL_TYPE_INT32 = 0x01,
    165  JSVAL_TYPE_BOOLEAN = 0x02,
    166  JSVAL_TYPE_UNDEFINED = 0x03,
    167  JSVAL_TYPE_NULL = 0x04,
    168  JSVAL_TYPE_MAGIC = 0x05,
    169  JSVAL_TYPE_STRING = 0x06,
    170  JSVAL_TYPE_SYMBOL = 0x07,
    171  JSVAL_TYPE_PRIVATE_GCTHING = 0x08,
    172  JSVAL_TYPE_BIGINT = 0x09,
    173  JSVAL_TYPE_OBJECT = 0x0c,
    174 
    175  // This type never appears in a Value; it's only an out-of-band value.
    176  JSVAL_TYPE_UNKNOWN = 0x20
    177 };
    178 
    179 namespace JS {
    180 enum class ValueType : uint8_t {
    181  Double = JSVAL_TYPE_DOUBLE,
    182  Int32 = JSVAL_TYPE_INT32,
    183  Boolean = JSVAL_TYPE_BOOLEAN,
    184  Undefined = JSVAL_TYPE_UNDEFINED,
    185  Null = JSVAL_TYPE_NULL,
    186  Magic = JSVAL_TYPE_MAGIC,
    187  String = JSVAL_TYPE_STRING,
    188  Symbol = JSVAL_TYPE_SYMBOL,
    189  PrivateGCThing = JSVAL_TYPE_PRIVATE_GCTHING,
    190  BigInt = JSVAL_TYPE_BIGINT,
    191  Object = JSVAL_TYPE_OBJECT,
    192 };
    193 }  // namespace JS
    194 
    195 static_assert(sizeof(JSValueType) == 1,
    196              "compiler typed enum support is apparently buggy");
    197 
    198 #if defined(JS_NUNBOX32)
    199 
    200 enum JSValueTag : uint32_t {
    201  JSVAL_TAG_CLEAR = 0xFFFFFF80,
    202  JSVAL_TAG_INT32 = JSVAL_TAG_CLEAR | JSVAL_TYPE_INT32,
    203  JSVAL_TAG_UNDEFINED = JSVAL_TAG_CLEAR | JSVAL_TYPE_UNDEFINED,
    204  JSVAL_TAG_NULL = JSVAL_TAG_CLEAR | JSVAL_TYPE_NULL,
    205  JSVAL_TAG_BOOLEAN = JSVAL_TAG_CLEAR | JSVAL_TYPE_BOOLEAN,
    206  JSVAL_TAG_MAGIC = JSVAL_TAG_CLEAR | JSVAL_TYPE_MAGIC,
    207  JSVAL_TAG_STRING = JSVAL_TAG_CLEAR | JSVAL_TYPE_STRING,
    208  JSVAL_TAG_SYMBOL = JSVAL_TAG_CLEAR | JSVAL_TYPE_SYMBOL,
    209  JSVAL_TAG_PRIVATE_GCTHING = JSVAL_TAG_CLEAR | JSVAL_TYPE_PRIVATE_GCTHING,
    210  JSVAL_TAG_BIGINT = JSVAL_TAG_CLEAR | JSVAL_TYPE_BIGINT,
    211  JSVAL_TAG_OBJECT = JSVAL_TAG_CLEAR | JSVAL_TYPE_OBJECT
    212 };
    213 
    214 static_assert(sizeof(JSValueTag) == sizeof(uint32_t),
    215              "compiler typed enum support is apparently buggy");
    216 
    217 #elif defined(JS_PUNBOX64)
    218 
    219 enum JSValueTag : uint32_t {
    220  JSVAL_TAG_MAX_DOUBLE = 0x1FFF0,
    221  JSVAL_TAG_INT32 = JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_INT32,
    222  JSVAL_TAG_UNDEFINED = JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_UNDEFINED,
    223  JSVAL_TAG_NULL = JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_NULL,
    224  JSVAL_TAG_BOOLEAN = JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_BOOLEAN,
    225  JSVAL_TAG_MAGIC = JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_MAGIC,
    226  JSVAL_TAG_STRING = JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_STRING,
    227  JSVAL_TAG_SYMBOL = JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_SYMBOL,
    228  JSVAL_TAG_PRIVATE_GCTHING = JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_PRIVATE_GCTHING,
    229  JSVAL_TAG_BIGINT = JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_BIGINT,
    230  JSVAL_TAG_OBJECT = JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_OBJECT
    231 };
    232 
    233 static_assert(sizeof(JSValueTag) == sizeof(uint32_t),
    234              "compiler typed enum support is apparently buggy");
    235 
    236 enum JSValueShiftedTag : uint64_t {
    237  // See Bug 584653 for why we include 0xFFFFFFFF.
    238  JSVAL_SHIFTED_TAG_MAX_DOUBLE =
    239      ((uint64_t(JSVAL_TAG_MAX_DOUBLE) << JSVAL_TAG_SHIFT) | 0xFFFFFFFF),
    240  JSVAL_SHIFTED_TAG_INT32 = (uint64_t(JSVAL_TAG_INT32) << JSVAL_TAG_SHIFT),
    241  JSVAL_SHIFTED_TAG_UNDEFINED =
    242      (uint64_t(JSVAL_TAG_UNDEFINED) << JSVAL_TAG_SHIFT),
    243  JSVAL_SHIFTED_TAG_NULL = (uint64_t(JSVAL_TAG_NULL) << JSVAL_TAG_SHIFT),
    244  JSVAL_SHIFTED_TAG_BOOLEAN = (uint64_t(JSVAL_TAG_BOOLEAN) << JSVAL_TAG_SHIFT),
    245  JSVAL_SHIFTED_TAG_MAGIC = (uint64_t(JSVAL_TAG_MAGIC) << JSVAL_TAG_SHIFT),
    246  JSVAL_SHIFTED_TAG_STRING = (uint64_t(JSVAL_TAG_STRING) << JSVAL_TAG_SHIFT),
    247  JSVAL_SHIFTED_TAG_SYMBOL = (uint64_t(JSVAL_TAG_SYMBOL) << JSVAL_TAG_SHIFT),
    248  JSVAL_SHIFTED_TAG_PRIVATE_GCTHING =
    249      (uint64_t(JSVAL_TAG_PRIVATE_GCTHING) << JSVAL_TAG_SHIFT),
    250  JSVAL_SHIFTED_TAG_BIGINT = (uint64_t(JSVAL_TAG_BIGINT) << JSVAL_TAG_SHIFT),
    251  JSVAL_SHIFTED_TAG_OBJECT = (uint64_t(JSVAL_TAG_OBJECT) << JSVAL_TAG_SHIFT)
    252 };
    253 
    254 static_assert(sizeof(JSValueShiftedTag) == sizeof(uint64_t),
    255              "compiler typed enum support is apparently buggy");
    256 
    257 #endif
    258 
    259 namespace JS {
    260 namespace detail {
    261 
    262 #if defined(JS_NUNBOX32)
    263 
    264 constexpr JSValueTag ValueTypeToTag(JSValueType type) {
    265  return static_cast<JSValueTag>(JSVAL_TAG_CLEAR |
    266                                 std::underlying_type_t<JSValueType>(type));
    267 }
    268 
    269 constexpr bool ValueIsDouble(uint64_t bits) {
    270  return uint32_t(bits >> JSVAL_TAG_SHIFT) <= uint32_t(JSVAL_TAG_CLEAR);
    271 }
    272 
    273 constexpr JSValueTag ValueUpperExclPrimitiveTag = JSVAL_TAG_OBJECT;
    274 constexpr JSValueTag ValueUpperInclNumberTag = JSVAL_TAG_INT32;
    275 constexpr JSValueTag ValueLowerInclGCThingTag = JSVAL_TAG_STRING;
    276 
    277 #elif defined(JS_PUNBOX64)
    278 
    279 constexpr JSValueTag ValueTypeToTag(JSValueType type) {
    280  return static_cast<JSValueTag>(JSVAL_TAG_MAX_DOUBLE |
    281                                 std::underlying_type_t<JSValueType>(type));
    282 }
    283 
    284 constexpr bool ValueIsDouble(uint64_t bits) {
    285  return bits <= JSVAL_SHIFTED_TAG_MAX_DOUBLE;
    286 }
    287 
    288 constexpr uint64_t ValueTagMask = 0xFFFF'8000'0000'0000;
    289 
    290 // This should only be used in toGCThing. See the 'Spectre mitigations' comment.
    291 constexpr uint64_t ValueGCThingPayloadMask = 0x0000'7FFF'FFFF'FFFF;
    292 
    293 // Mask used to combine an unbox operation with getting the chunk base.
    294 constexpr uint64_t ValueGCThingPayloadChunkMask =
    295    ValueGCThingPayloadMask & ~js::gc::ChunkMask;
    296 
    297 constexpr uint64_t ValueTypeToShiftedTag(JSValueType type) {
    298  return static_cast<uint64_t>(ValueTypeToTag(type)) << JSVAL_TAG_SHIFT;
    299 }
    300 #  define JSVAL_TYPE_TO_SHIFTED_TAG(type) \
    301    (JS::detail::ValueTypeToShiftedTag(type))
    302 
    303 constexpr JSValueTag ValueUpperExclPrimitiveTag = JSVAL_TAG_OBJECT;
    304 constexpr JSValueTag ValueUpperInclNumberTag = JSVAL_TAG_INT32;
    305 constexpr JSValueTag ValueLowerInclGCThingTag = JSVAL_TAG_STRING;
    306 
    307 constexpr uint64_t ValueUpperExclShiftedPrimitiveTag = JSVAL_SHIFTED_TAG_OBJECT;
    308 constexpr uint64_t ValueUpperExclShiftedNumberTag = JSVAL_SHIFTED_TAG_BOOLEAN;
    309 constexpr uint64_t ValueLowerInclShiftedGCThingTag = JSVAL_SHIFTED_TAG_STRING;
    310 
    311 // JSVAL_TYPE_OBJECT and JSVAL_TYPE_NULL differ by one bit. We can use this to
    312 // implement toObjectOrNull more efficiently.
    313 constexpr uint64_t ValueObjectOrNullBit = 0x8ULL << JSVAL_TAG_SHIFT;
    314 static_assert(
    315    (JSVAL_SHIFTED_TAG_NULL ^ JSVAL_SHIFTED_TAG_OBJECT) == ValueObjectOrNullBit,
    316    "ValueObjectOrNullBit must be consistent with object and null tags");
    317 
    318 constexpr uint64_t IsValidUserModePointer(uint64_t bits) {
    319  // All 64-bit platforms that we support actually have a 48-bit address space
    320  // for user-mode pointers, with the top 16 bits all set to zero.
    321  return (bits & 0xFFFF'0000'0000'0000) == 0;
    322 }
    323 
    324 #endif /* JS_PUNBOX64 */
    325 
    326 }  // namespace detail
    327 }  // namespace JS
    328 
    329 #define JSVAL_TYPE_TO_TAG(type) (JS::detail::ValueTypeToTag(type))
    330 
    331 enum JSWhyMagic {
    332  /** a hole in a native object's elements */
    333  JS_ELEMENTS_HOLE,
    334 
    335  /** there is not a pending iterator value */
    336  JS_NO_ITER_VALUE,
    337 
    338  /** exception value thrown when closing a generator */
    339  JS_GENERATOR_CLOSING,
    340 
    341  /** used in debug builds to catch tracing errors */
    342  JS_ARG_POISON,
    343 
    344  /** an empty subnode in the AST serializer */
    345  JS_SERIALIZE_NO_NODE,
    346 
    347  /** magic value passed to natives to indicate construction */
    348  JS_IS_CONSTRUCTING,
    349 
    350  /** see class js::HashableValue */
    351  JS_HASH_KEY_EMPTY,
    352 
    353  /** error while running Ion code */
    354  JS_ION_ERROR,
    355 
    356  /** missing recover instruction result */
    357  JS_ION_BAILOUT,
    358 
    359  /** optimized out slot */
    360  JS_OPTIMIZED_OUT,
    361 
    362  /** uninitialized lexical bindings that produce ReferenceError on touch. */
    363  JS_UNINITIALIZED_LEXICAL,
    364 
    365  /** arguments object can't be created because environment is dead. */
    366  JS_MISSING_ARGUMENTS,
    367 
    368  /** exception value thrown when interrupting irregexp */
    369  JS_INTERRUPT_REGEXP,
    370 
    371  /** for local use */
    372  JS_GENERIC_MAGIC,
    373 
    374  /**
    375   * When an error object is created without the error cause argument, we set
    376   * the error's cause slot to this magic value.
    377   */
    378  JS_ERROR_WITHOUT_CAUSE,
    379 
    380  JS_WHY_MAGIC_COUNT
    381 };
    382 
    383 namespace js {
    384 class JS_PUBLIC_API GenericPrinter;
    385 class JSONPrinter;
    386 
    387 static inline JS::Value PoisonedObjectValue(uintptr_t poison);
    388 
    389 }  // namespace js
    390 
    391 namespace JS {
    392 
    393 namespace detail {
    394 
    395 // IEEE-754 bit pattern for double-precision positive infinity.
    396 constexpr int InfinitySignBit = 0;
    397 constexpr uint64_t InfinityBits =
    398    mozilla::InfinityBits<double, detail::InfinitySignBit>::value;
    399 
    400 // This is a quiet NaN on IEEE-754[2008] compatible platforms, including X86,
    401 // ARM, SPARC, RISC-V and modern MIPS.
    402 //
    403 // Note: The default sign bit for a hardware synthesized NaN differs between X86
    404 //       and ARM. Both values are considered compatible values on both
    405 //       platforms.
    406 constexpr int CanonicalizedNaNSignBit = 0;
    407 constexpr uint64_t CanonicalizedNaNSignificand = 0x8000000000000;
    408 
    409 #if defined(__sparc__)
    410 // Some architectures (not to name names) generate NaNs with bit patterns that
    411 // are incompatible with JS::Value's bit pattern restrictions. Instead we must
    412 // canonicalize all hardware values before storing in JS::Value.
    413 #  define JS_NONCANONICAL_HARDWARE_NAN
    414 #endif
    415 
    416 #if defined(__mips__) && !defined(__mips_nan_2008)
    417 // These builds may run on hardware that has differing polarity of the signaling
    418 // NaN bit. While the kernel may handle the trap for us, it is a performance
    419 // issue so instead we compute the NaN to use on startup. The runtime value must
    420 // still meet `ValueIsDouble` requirements which are checked on startup.
    421 
    422 // In particular, we expect one of the following values on MIPS:
    423 //  - 0x7FF7FFFFFFFFFFFF    Legacy
    424 //  - 0x7FF8000000000000    IEEE-754[2008]
    425 #  define JS_RUNTIME_CANONICAL_NAN
    426 #endif
    427 
    428 #if defined(JS_RUNTIME_CANONICAL_NAN)
    429 extern uint64_t CanonicalizedNaNBits;
    430 #else
    431 constexpr uint64_t CanonicalizedNaNBits =
    432    mozilla::SpecificNaNBits<double, detail::CanonicalizedNaNSignBit,
    433                             detail::CanonicalizedNaNSignificand>::value;
    434 #endif
    435 }  // namespace detail
    436 
    437 // Return a quiet NaN that is compatible with JS::Value restrictions.
    438 static MOZ_ALWAYS_INLINE double GenericNaN() {
    439 #if !defined(JS_RUNTIME_CANONICAL_NAN)
    440  static_assert(detail::ValueIsDouble(detail::CanonicalizedNaNBits),
    441                "Canonical NaN must be compatible with JS::Value");
    442 #endif
    443 
    444  return mozilla::BitwiseCast<double>(detail::CanonicalizedNaNBits);
    445 }
    446 
    447 // Return the infinity the engine uses
    448 static MOZ_ALWAYS_INLINE double Infinity() {
    449  return mozilla::BitwiseCast<double>(detail::InfinityBits);
    450 }
    451 
    452 // Convert an arbitrary double to one compatible with JS::Value representation
    453 // by replacing any NaN value with a canonical one.
    454 static MOZ_ALWAYS_INLINE double CanonicalizeNaN(double d) {
    455  if (MOZ_UNLIKELY(std::isnan(d))) {
    456    return GenericNaN();
    457  }
    458  return d;
    459 }
    460 
    461 /**
    462 * [SMDOC] JS::Value type
    463 *
    464 * JS::Value is the interface for a single JavaScript Engine value.  A few
    465 * general notes on JS::Value:
    466 *
    467 * - JS::Value has setX() and isX() members for X in
    468 *
    469 *     { Int32, Double, String, Symbol, BigInt, Boolean, Undefined, Null,
    470 *       Object, Magic }
    471 *
    472 *   JS::Value also contains toX() for each of the non-singleton types.
    473 *
    474 * - Magic is a singleton type whose payload contains either a JSWhyMagic
    475 *   "reason" for the magic value or a uint32_t value. By providing JSWhyMagic
    476 *   values when creating and checking for magic values, it is possible to
    477 *   assert, at runtime, that only magic values with the expected reason flow
    478 *   through a particular value. For example, if cx->exception has a magic
    479 *   value, the reason must be JS_GENERATOR_CLOSING.
    480 *
    481 * - To help prevent mistakenly boxing a nullable JSObject* as an object,
    482 *   Value::setObject takes a JSObject&. (Conversely, Value::toObject returns a
    483 *   JSObject&.)  A convenience member Value::setObjectOrNull is provided.
    484 *
    485 * - Note that JS::Value is 8 bytes on 32 and 64-bit architectures. Because most
    486 *   of our users are now on 64-bit platforms, code should prefer passing
    487 *   JS::Value by value instead of |const Value&|.
    488 *
    489 * Spectre mitigations
    490 * ===================
    491 * To mitigate Spectre attacks, we do the following:
    492 *
    493 * - On 64-bit platforms, when unboxing a Value, we XOR the bits with the
    494 *   expected type tag (instead of masking the payload bits). This guarantees
    495 *   that toString, toObject, toSymbol will return an invalid pointer (because
    496 *   some high bits will be set) when called on a Value with a different type
    497 *   tag.
    498 *
    499 * - On 32-bit platforms,when unboxing an object/string/symbol Value, we use a
    500 *   conditional move (not speculated) to zero the payload register if the type
    501 *   doesn't match.
    502 */
    503 class Value {
    504 private:
    505  uint64_t asBits_;
    506 
    507 public:
    508  constexpr Value() : asBits_(bitsFromTagAndPayload(JSVAL_TAG_UNDEFINED, 0)) {}
    509 
    510 private:
    511  explicit constexpr Value(uint64_t asBits) : asBits_(asBits) {}
    512 
    513  static uint64_t bitsFromDouble(double d) {
    514 #if defined(JS_NONCANONICAL_HARDWARE_NAN)
    515    d = CanonicalizeNaN(d);
    516 #endif
    517    return mozilla::BitwiseCast<uint64_t>(d);
    518  }
    519 
    520  static_assert(sizeof(JSValueType) == 1,
    521                "type bits must fit in a single byte");
    522  static_assert(sizeof(JSValueTag) == 4,
    523                "32-bit Value's tag_ must have size 4 to complement the "
    524                "payload union's size 4");
    525  static_assert(sizeof(JSWhyMagic) <= 4,
    526                "32-bit Value's JSWhyMagic payload field must not inflate "
    527                "the payload beyond 4 bytes");
    528 
    529 public:
    530 #if defined(JS_NUNBOX32)
    531  using PayloadType = uint32_t;
    532 #elif defined(JS_PUNBOX64)
    533  using PayloadType = uint64_t;
    534 #endif
    535 
    536  static constexpr uint64_t bitsFromTagAndPayload(JSValueTag tag,
    537                                                  PayloadType payload) {
    538    return (uint64_t(tag) << JSVAL_TAG_SHIFT) | payload;
    539  }
    540 
    541  static constexpr Value fromTagAndPayload(JSValueTag tag,
    542                                           PayloadType payload) {
    543    return fromRawBits(bitsFromTagAndPayload(tag, payload));
    544  }
    545 
    546  static constexpr Value fromRawBits(uint64_t asBits) { return Value(asBits); }
    547 
    548  static constexpr Value fromInt32(int32_t i) {
    549    return fromTagAndPayload(JSVAL_TAG_INT32, uint32_t(i));
    550  }
    551 
    552  static Value fromDouble(double d) { return fromRawBits(bitsFromDouble(d)); }
    553 
    554  /**
    555   * Returns false if creating a NumberValue containing the given type would
    556   * be lossy, true otherwise.
    557   */
    558  template <typename T>
    559  static bool isNumberRepresentable(const T t) {
    560    return T(double(t)) == t;
    561  }
    562 
    563  /*** Mutators ***/
    564 
    565  void setNull() {
    566    asBits_ = bitsFromTagAndPayload(JSVAL_TAG_NULL, 0);
    567    MOZ_ASSERT(isNull());
    568  }
    569 
    570  void setUndefined() {
    571    asBits_ = bitsFromTagAndPayload(JSVAL_TAG_UNDEFINED, 0);
    572    MOZ_ASSERT(isUndefined());
    573  }
    574 
    575  void setInt32(int32_t i) {
    576    asBits_ = bitsFromTagAndPayload(JSVAL_TAG_INT32, uint32_t(i));
    577    MOZ_ASSERT(toInt32() == i);
    578  }
    579 
    580  void setDouble(double d) {
    581    asBits_ = bitsFromDouble(d);
    582    MOZ_ASSERT(isDouble());
    583  }
    584 
    585  void setString(JSString* str) {
    586    MOZ_ASSERT(js::gc::IsCellPointerValid(str));
    587    asBits_ = bitsFromTagAndPayload(JSVAL_TAG_STRING, PayloadType(str));
    588    MOZ_ASSERT(toString() == str);
    589  }
    590 
    591  void setSymbol(JS::Symbol* sym) {
    592    MOZ_ASSERT(js::gc::IsCellPointerValid(sym));
    593    asBits_ = bitsFromTagAndPayload(JSVAL_TAG_SYMBOL, PayloadType(sym));
    594    MOZ_ASSERT(toSymbol() == sym);
    595  }
    596 
    597  void setBigInt(JS::BigInt* bi) {
    598    MOZ_ASSERT(js::gc::IsCellPointerValid(bi));
    599    asBits_ = bitsFromTagAndPayload(JSVAL_TAG_BIGINT, PayloadType(bi));
    600    MOZ_ASSERT(toBigInt() == bi);
    601  }
    602 
    603  void setObject(JSObject& obj) {
    604    MOZ_ASSERT(js::gc::IsCellPointerValid(&obj));
    605    setObjectNoCheck(&obj);
    606    MOZ_ASSERT(&toObject() == &obj);
    607  }
    608 
    609  void changeGCThingPayload(js::gc::Cell* cell) {
    610    MOZ_ASSERT(js::gc::IsCellPointerValid(cell));
    611 #ifdef DEBUG
    612    assertTraceKindMatches(cell);
    613 #endif
    614    asBits_ = bitsFromTagAndPayload(toTag(), PayloadType(cell));
    615    MOZ_ASSERT(toGCThing() == cell);
    616  }
    617 
    618 private:
    619 #ifdef DEBUG
    620  void assertTraceKindMatches(js::gc::Cell* cell) const;
    621 #endif
    622 
    623  void setObjectNoCheck(JSObject* obj) {
    624    asBits_ = bitsFromTagAndPayload(JSVAL_TAG_OBJECT, PayloadType(obj));
    625  }
    626 
    627  friend inline Value js::PoisonedObjectValue(uintptr_t poison);
    628 
    629 public:
    630  void setBoolean(bool b) {
    631    asBits_ = bitsFromTagAndPayload(JSVAL_TAG_BOOLEAN, uint32_t(b));
    632    MOZ_ASSERT(toBoolean() == b);
    633  }
    634 
    635  void setMagic(JSWhyMagic why) {
    636    asBits_ = bitsFromTagAndPayload(JSVAL_TAG_MAGIC, uint32_t(why));
    637    MOZ_ASSERT(whyMagic() == why);
    638  }
    639 
    640  void setMagicUint32(uint32_t payload) {
    641    MOZ_ASSERT(payload >= JS_WHY_MAGIC_COUNT,
    642               "This should only be used for non-standard magic values");
    643    asBits_ = bitsFromTagAndPayload(JSVAL_TAG_MAGIC, payload);
    644    MOZ_ASSERT(magicUint32() == payload);
    645  }
    646 
    647  void setNumber(float f) {
    648    int32_t i;
    649    if (mozilla::NumberIsInt32(f, &i)) {
    650      setInt32(i);
    651      return;
    652    }
    653 
    654    setDouble(double(f));
    655  }
    656 
    657  void setNumber(double d) {
    658    int32_t i;
    659    if (mozilla::NumberIsInt32(d, &i)) {
    660      setInt32(i);
    661      return;
    662    }
    663 
    664    setDouble(d);
    665  }
    666 
    667  template <typename T>
    668  void setNumber(const T t) {
    669    static_assert(std::is_integral<T>::value, "must be integral type");
    670    MOZ_ASSERT(isNumberRepresentable(t), "value creation would be lossy");
    671 
    672    if constexpr (std::numeric_limits<T>::is_signed) {
    673      if constexpr (sizeof(t) <= sizeof(int32_t)) {
    674        setInt32(int32_t(t));
    675      } else {
    676        if (JSVAL_INT_MIN <= t && t <= JSVAL_INT_MAX) {
    677          setInt32(int32_t(t));
    678        } else {
    679          setDouble(double(t));
    680        }
    681      }
    682    } else {
    683      if constexpr (sizeof(t) <= sizeof(uint16_t)) {
    684        setInt32(int32_t(t));
    685      } else {
    686        if (t <= JSVAL_INT_MAX) {
    687          setInt32(int32_t(t));
    688        } else {
    689          setDouble(double(t));
    690        }
    691      }
    692    }
    693  }
    694 
    695  void setObjectOrNull(JSObject* arg) {
    696    if (arg) {
    697      setObject(*arg);
    698    } else {
    699      setNull();
    700    }
    701  }
    702 
    703  void swap(Value& rhs) {
    704    uint64_t tmp = rhs.asBits_;
    705    rhs.asBits_ = asBits_;
    706    asBits_ = tmp;
    707  }
    708 
    709 private:
    710  JSValueTag toTag() const { return JSValueTag(asBits_ >> JSVAL_TAG_SHIFT); }
    711 
    712  template <typename T, JSValueTag Tag>
    713  T* unboxGCPointer() const {
    714    MOZ_ASSERT((asBits_ & js::gc::CellAlignMask) == 0,
    715               "GC pointer is not aligned. Is this memory corruption?");
    716 #if defined(JS_NUNBOX32)
    717    uintptr_t payload = uint32_t(asBits_);
    718    return reinterpret_cast<T*>(payload);
    719 #elif defined(JS_PUNBOX64)
    720    // Note: the 'Spectre mitigations' comment at the top of this class
    721    // explains why we use XOR here.
    722    constexpr uint64_t shiftedTag = uint64_t(Tag) << JSVAL_TAG_SHIFT;
    723    return reinterpret_cast<T*>(uintptr_t(asBits_ ^ shiftedTag));
    724 #endif
    725  }
    726 
    727 public:
    728  /*** JIT-only interfaces to interact with and create raw Values ***/
    729 #if defined(JS_NUNBOX32)
    730  PayloadType toNunboxPayload() const { return uint32_t(asBits_); }
    731 
    732  JSValueTag toNunboxTag() const { return toTag(); }
    733 #elif defined(JS_PUNBOX64)
    734  const void* bitsAsPunboxPointer() const {
    735    return reinterpret_cast<void*>(asBits_);
    736  }
    737 #endif
    738 
    739  /*** Value type queries ***/
    740 
    741  /*
    742   * N.B. GCC, in some but not all cases, chooses to emit signed comparison
    743   * of JSValueTag even though its underlying type has been forced to be
    744   * uint32_t.  Thus, all comparisons should explicitly cast operands to
    745   * uint32_t.
    746   */
    747 
    748  bool isUndefined() const {
    749 #if defined(JS_NUNBOX32)
    750    return toTag() == JSVAL_TAG_UNDEFINED;
    751 #elif defined(JS_PUNBOX64)
    752    return asBits_ == JSVAL_SHIFTED_TAG_UNDEFINED;
    753 #endif
    754  }
    755 
    756  bool isNull() const {
    757 #if defined(JS_NUNBOX32)
    758    return toTag() == JSVAL_TAG_NULL;
    759 #elif defined(JS_PUNBOX64)
    760    return asBits_ == JSVAL_SHIFTED_TAG_NULL;
    761 #endif
    762  }
    763 
    764  bool isNullOrUndefined() const { return isNull() || isUndefined(); }
    765 
    766  bool isInt32() const { return toTag() == JSVAL_TAG_INT32; }
    767 
    768  bool isInt32(int32_t i32) const {
    769    return asBits_ == bitsFromTagAndPayload(JSVAL_TAG_INT32, uint32_t(i32));
    770  }
    771 
    772  bool isDouble() const { return detail::ValueIsDouble(asBits_); }
    773 
    774  bool isNaN() const { return isDouble() && std::isnan(toDouble()); }
    775 
    776  bool isNumber() const {
    777 #if defined(JS_NUNBOX32)
    778    MOZ_ASSERT(toTag() != JSVAL_TAG_CLEAR);
    779    return uint32_t(toTag()) <= uint32_t(detail::ValueUpperInclNumberTag);
    780 #elif defined(JS_PUNBOX64)
    781    return asBits_ < detail::ValueUpperExclShiftedNumberTag;
    782 #endif
    783  }
    784 
    785  bool isString() const { return toTag() == JSVAL_TAG_STRING; }
    786 
    787  bool isSymbol() const { return toTag() == JSVAL_TAG_SYMBOL; }
    788 
    789  bool isBigInt() const { return toTag() == JSVAL_TAG_BIGINT; }
    790 
    791  bool isObject() const {
    792 #if defined(JS_NUNBOX32)
    793    return toTag() == JSVAL_TAG_OBJECT;
    794 #elif defined(JS_PUNBOX64)
    795    MOZ_ASSERT((asBits_ >> JSVAL_TAG_SHIFT) <= JSVAL_TAG_OBJECT);
    796    return asBits_ >= JSVAL_SHIFTED_TAG_OBJECT;
    797 #endif
    798  }
    799 
    800  bool isPrimitive() const {
    801 #if defined(JS_NUNBOX32)
    802    return uint32_t(toTag()) < uint32_t(detail::ValueUpperExclPrimitiveTag);
    803 #elif defined(JS_PUNBOX64)
    804    return asBits_ < detail::ValueUpperExclShiftedPrimitiveTag;
    805 #endif
    806  }
    807 
    808  bool isObjectOrNull() const { return isObject() || isNull(); }
    809 
    810  bool isNumeric() const { return isNumber() || isBigInt(); }
    811 
    812  bool isGCThing() const {
    813 #if defined(JS_NUNBOX32)
    814    /* gcc sometimes generates signed < without explicit casts. */
    815    return uint32_t(toTag()) >= uint32_t(detail::ValueLowerInclGCThingTag);
    816 #elif defined(JS_PUNBOX64)
    817    return asBits_ >= detail::ValueLowerInclShiftedGCThingTag;
    818 #endif
    819  }
    820 
    821  bool isBoolean() const { return toTag() == JSVAL_TAG_BOOLEAN; }
    822 
    823  bool isTrue() const {
    824    return asBits_ == bitsFromTagAndPayload(JSVAL_TAG_BOOLEAN, uint32_t(true));
    825  }
    826 
    827  bool isFalse() const {
    828    return asBits_ == bitsFromTagAndPayload(JSVAL_TAG_BOOLEAN, uint32_t(false));
    829  }
    830 
    831  bool isMagic() const { return toTag() == JSVAL_TAG_MAGIC; }
    832 
    833  bool isMagic(JSWhyMagic why) const {
    834    if (!isMagic()) {
    835      return false;
    836    }
    837    MOZ_RELEASE_ASSERT(whyMagic() == why);
    838    return true;
    839  }
    840 
    841  // Like isMagic, but without the release assertion.
    842  bool isMagicNoReleaseCheck(JSWhyMagic why) const {
    843    if (!isMagic()) {
    844      return false;
    845    }
    846    MOZ_ASSERT(whyMagic() == why);
    847    return true;
    848  }
    849 
    850  JS::TraceKind traceKind() const {
    851    MOZ_ASSERT(isGCThing());
    852    static_assert((JSVAL_TAG_STRING & 0x03) == size_t(JS::TraceKind::String),
    853                  "Value type tags must correspond with JS::TraceKinds.");
    854    static_assert((JSVAL_TAG_OBJECT & 0x03) == size_t(JS::TraceKind::Object),
    855                  "Value type tags must correspond with JS::TraceKinds.");
    856    static_assert((JSVAL_TAG_BIGINT & 0x03) == size_t(JS::TraceKind::BigInt),
    857                  "Value type tags must correspond with JS::TraceKinds.");
    858    static_assert(JSVAL_TAG_SYMBOL + 1 == JSVAL_TAG_PRIVATE_GCTHING,
    859                  "Symbol and PrivateGCThing tags should be adjacent to allow "
    860                  "checking for them with a single branch");
    861    JSValueTag tag = toTag();
    862    if (MOZ_UNLIKELY(tag == JSVAL_TAG_SYMBOL ||
    863                     tag == JSVAL_TAG_PRIVATE_GCTHING)) {
    864      return JS::GCThingTraceKind(toGCThing());
    865    }
    866    return JS::TraceKind(tag & 0x03);
    867  }
    868 
    869  JSWhyMagic whyMagic() const {
    870    MOZ_ASSERT(magicUint32() < JS_WHY_MAGIC_COUNT);
    871    return static_cast<JSWhyMagic>(magicUint32());
    872  }
    873 
    874  uint32_t magicUint32() const {
    875    MOZ_ASSERT(isMagic());
    876    return uint32_t(asBits_);
    877  }
    878 
    879  /*** Comparison ***/
    880 
    881  bool operator==(const Value& rhs) const { return asBits_ == rhs.asBits_; }
    882 
    883  bool operator!=(const Value& rhs) const { return asBits_ != rhs.asBits_; }
    884 
    885  friend inline bool SameType(const Value& lhs, const Value& rhs);
    886 
    887  /*** Extract the value's typed payload ***/
    888 
    889  int32_t toInt32() const {
    890    MOZ_ASSERT(isInt32());
    891    return int32_t(asBits_);
    892  }
    893 
    894  double toDouble() const {
    895    MOZ_ASSERT(isDouble());
    896    return mozilla::BitwiseCast<double>(asBits_);
    897  }
    898 
    899  double toNumber() const {
    900    MOZ_ASSERT(isNumber());
    901    return isDouble() ? toDouble() : double(toInt32());
    902  }
    903 
    904  JSString* toString() const {
    905    MOZ_ASSERT(isString());
    906    return unboxGCPointer<JSString, JSVAL_TAG_STRING>();
    907  }
    908 
    909  JS::Symbol* toSymbol() const {
    910    MOZ_ASSERT(isSymbol());
    911    return unboxGCPointer<JS::Symbol, JSVAL_TAG_SYMBOL>();
    912  }
    913 
    914  JS::BigInt* toBigInt() const {
    915    MOZ_ASSERT(isBigInt());
    916    return unboxGCPointer<JS::BigInt, JSVAL_TAG_BIGINT>();
    917  }
    918 
    919  JSObject& toObject() const {
    920    MOZ_ASSERT(isObject());
    921 #if defined(JS_PUNBOX64)
    922    MOZ_ASSERT((asBits_ & detail::ValueGCThingPayloadMask) != 0);
    923 #endif
    924    return *unboxGCPointer<JSObject, JSVAL_TAG_OBJECT>();
    925  }
    926 
    927  JSObject* toObjectOrNull() const {
    928    MOZ_ASSERT(isObjectOrNull());
    929 #if defined(JS_NUNBOX32)
    930    return reinterpret_cast<JSObject*>(uintptr_t(asBits_));
    931 #elif defined(JS_PUNBOX64)
    932    // Note: the 'Spectre mitigations' comment at the top of this class
    933    // explains why we use XOR here and in other to* methods.
    934    uint64_t ptrBits =
    935        (asBits_ ^ JSVAL_SHIFTED_TAG_OBJECT) & ~detail::ValueObjectOrNullBit;
    936    MOZ_ASSERT((ptrBits & 0x7) == 0);
    937    return reinterpret_cast<JSObject*>(ptrBits);
    938 #endif
    939  }
    940 
    941  js::gc::Cell* toGCThing() const {
    942    MOZ_ASSERT(isGCThing());
    943 #if defined(JS_NUNBOX32)
    944    return reinterpret_cast<js::gc::Cell*>(uintptr_t(asBits_));
    945 #elif defined(JS_PUNBOX64)
    946    uint64_t ptrBits = asBits_ & detail::ValueGCThingPayloadMask;
    947    MOZ_ASSERT((ptrBits & 0x7) == 0);
    948    return reinterpret_cast<js::gc::Cell*>(ptrBits);
    949 #endif
    950  }
    951 
    952  GCCellPtr toGCCellPtr() const { return GCCellPtr(toGCThing(), traceKind()); }
    953 
    954  bool toBoolean() const {
    955    MOZ_ASSERT(isBoolean());
    956 #if defined(JS_NUNBOX32)
    957    return bool(toNunboxPayload());
    958 #elif defined(JS_PUNBOX64)
    959    return bool(asBits_ & 0x1);
    960 #endif
    961  }
    962 
    963  constexpr uint64_t asRawBits() const { return asBits_; }
    964 
    965  JSValueType extractNonDoubleType() const {
    966    uint32_t type = toTag() & 0xF;
    967    MOZ_ASSERT(type > JSVAL_TYPE_DOUBLE);
    968    return JSValueType(type);
    969  }
    970 
    971  JS::ValueType type() const {
    972    if (isDouble()) {
    973      return JS::ValueType::Double;
    974    }
    975 
    976    JSValueType type = extractNonDoubleType();
    977    MOZ_ASSERT(type <= JSVAL_TYPE_OBJECT);
    978    return JS::ValueType(type);
    979  }
    980 
    981  /*
    982   * Private API
    983   *
    984   * Private setters/getters allow the caller to read/write arbitrary
    985   * word-size pointers or uint32s.  After storing to a value with
    986   * setPrivateX, it is the caller's responsibility to only read using
    987   * toPrivateX. Private values are given a type which ensures they
    988   * aren't marked by the GC.
    989   */
    990 
    991  void setPrivate(void* ptr) {
    992 #if defined(JS_PUNBOX64)
    993    MOZ_ASSERT(detail::IsValidUserModePointer(uintptr_t(ptr)));
    994 #endif
    995    asBits_ = uintptr_t(ptr);
    996    MOZ_ASSERT(isDouble());
    997  }
    998 
    999  void* toPrivate() const {
   1000    MOZ_ASSERT(isDouble());
   1001 #if defined(JS_PUNBOX64)
   1002    MOZ_ASSERT(detail::IsValidUserModePointer(asBits_));
   1003 #endif
   1004    return reinterpret_cast<void*>(uintptr_t(asBits_));
   1005  }
   1006 
   1007  void* toPrivateUnchecked() const {
   1008    return reinterpret_cast<void*>(uintptr_t(asBits_));
   1009  }
   1010 
   1011  void setPrivateUint32(uint32_t ui) {
   1012    MOZ_ASSERT(uint32_t(int32_t(ui)) == ui);
   1013    setInt32(int32_t(ui));
   1014  }
   1015 
   1016  uint32_t toPrivateUint32() const { return uint32_t(toInt32()); }
   1017 
   1018  /*
   1019   * Private GC Thing API
   1020   *
   1021   * Non-JSObject, JSString, and JS::Symbol cells may be put into the 64-bit
   1022   * payload as private GC things. Such Values are considered isGCThing(), and
   1023   * as such, automatically marked. Their traceKind() is gotten via their
   1024   * cells.
   1025   */
   1026 
   1027  void setPrivateGCThing(js::gc::Cell* cell) {
   1028    MOZ_ASSERT(JS::GCThingTraceKind(cell) != JS::TraceKind::String,
   1029               "Private GC thing Values must not be strings. Make a "
   1030               "StringValue instead.");
   1031    MOZ_ASSERT(JS::GCThingTraceKind(cell) != JS::TraceKind::Symbol,
   1032               "Private GC thing Values must not be symbols. Make a "
   1033               "SymbolValue instead.");
   1034    MOZ_ASSERT(JS::GCThingTraceKind(cell) != JS::TraceKind::BigInt,
   1035               "Private GC thing Values must not be BigInts. Make a "
   1036               "BigIntValue instead.");
   1037    MOZ_ASSERT(JS::GCThingTraceKind(cell) != JS::TraceKind::Object,
   1038               "Private GC thing Values must not be objects. Make an "
   1039               "ObjectValue instead.");
   1040 
   1041    MOZ_ASSERT(js::gc::IsCellPointerValid(cell));
   1042 #if defined(JS_PUNBOX64)
   1043    // VisualStudio cannot contain parenthesized C++ style cast and shift
   1044    // inside decltype in template parameter:
   1045    //   AssertionConditionType<decltype((uintptr_t(x) >> 1))>
   1046    // It throws syntax error.
   1047    MOZ_ASSERT((((uintptr_t)cell) >> JSVAL_TAG_SHIFT) == 0);
   1048 #endif
   1049    asBits_ =
   1050        bitsFromTagAndPayload(JSVAL_TAG_PRIVATE_GCTHING, PayloadType(cell));
   1051  }
   1052 
   1053  bool isPrivateGCThing() const { return toTag() == JSVAL_TAG_PRIVATE_GCTHING; }
   1054 
   1055 #if defined(DEBUG) || defined(JS_JITSPEW)
   1056  void dump() const;
   1057  void dump(js::GenericPrinter& out) const;
   1058  void dump(js::JSONPrinter& json) const;
   1059 
   1060  void dumpFields(js::JSONPrinter& json) const;
   1061  void dumpStringContent(js::GenericPrinter& out) const;
   1062 #endif
   1063 } JS_HAZ_GC_POINTER;
   1064 
   1065 static_assert(sizeof(Value) == 8,
   1066              "Value size must leave three tag bits, be a binary power, and "
   1067              "is ubiquitously depended upon everywhere");
   1068 
   1069 static MOZ_ALWAYS_INLINE void ExposeValueToActiveJS(const Value& v) {
   1070 #ifdef DEBUG
   1071  Value tmp = v;
   1072  MOZ_ASSERT(!js::gc::EdgeNeedsSweepUnbarrieredSlow(&tmp));
   1073 #endif
   1074  if (v.isGCThing()) {
   1075    js::gc::ExposeGCThingToActiveJS(v.toGCCellPtr());
   1076  }
   1077 }
   1078 
   1079 /************************************************************************/
   1080 
   1081 static inline MOZ_MAY_CALL_AFTER_MUST_RETURN Value NullValue() {
   1082  Value v;
   1083  v.setNull();
   1084  return v;
   1085 }
   1086 
   1087 static constexpr Value UndefinedValue() { return Value(); }
   1088 
   1089 static constexpr Value Int32Value(int32_t i32) { return Value::fromInt32(i32); }
   1090 
   1091 static inline Value DoubleValue(double dbl) {
   1092  Value v;
   1093  v.setDouble(dbl);
   1094  return v;
   1095 }
   1096 
   1097 static inline Value CanonicalizedDoubleValue(double d) {
   1098  return Value::fromDouble(CanonicalizeNaN(d));
   1099 }
   1100 
   1101 static inline Value NaNValue() {
   1102  return Value::fromRawBits(detail::CanonicalizedNaNBits);
   1103 }
   1104 
   1105 static inline Value InfinityValue() {
   1106  return Value::fromRawBits(detail::InfinityBits);
   1107 }
   1108 
   1109 static inline Value Float32Value(float f) {
   1110  Value v;
   1111  v.setDouble(f);
   1112  return v;
   1113 }
   1114 
   1115 static inline Value StringValue(JSString* str) {
   1116  Value v;
   1117  v.setString(str);
   1118  return v;
   1119 }
   1120 
   1121 static inline Value SymbolValue(JS::Symbol* sym) {
   1122  Value v;
   1123  v.setSymbol(sym);
   1124  return v;
   1125 }
   1126 
   1127 static inline Value BigIntValue(JS::BigInt* bi) {
   1128  Value v;
   1129  v.setBigInt(bi);
   1130  return v;
   1131 }
   1132 
   1133 static inline Value BooleanValue(bool boo) {
   1134  Value v;
   1135  v.setBoolean(boo);
   1136  return v;
   1137 }
   1138 
   1139 static inline Value TrueValue() {
   1140  Value v;
   1141  v.setBoolean(true);
   1142  return v;
   1143 }
   1144 
   1145 static inline Value FalseValue() {
   1146  Value v;
   1147  v.setBoolean(false);
   1148  return v;
   1149 }
   1150 
   1151 static inline Value ObjectValue(JSObject& obj) {
   1152  Value v;
   1153  v.setObject(obj);
   1154  return v;
   1155 }
   1156 
   1157 static inline Value MagicValue(JSWhyMagic why) {
   1158  Value v;
   1159  v.setMagic(why);
   1160  return v;
   1161 }
   1162 
   1163 static inline Value MagicValueUint32(uint32_t payload) {
   1164  Value v;
   1165  v.setMagicUint32(payload);
   1166  return v;
   1167 }
   1168 
   1169 static constexpr Value NumberValue(uint32_t i) {
   1170  return i <= JSVAL_INT_MAX ? Int32Value(int32_t(i))
   1171                            : Value::fromDouble(double(i));
   1172 }
   1173 
   1174 template <typename T>
   1175 static inline Value NumberValue(const T t) {
   1176  Value v;
   1177  v.setNumber(t);
   1178  return v;
   1179 }
   1180 
   1181 static inline Value ObjectOrNullValue(JSObject* obj) {
   1182  Value v;
   1183  v.setObjectOrNull(obj);
   1184  return v;
   1185 }
   1186 
   1187 static inline Value PrivateValue(void* ptr) {
   1188  Value v;
   1189  v.setPrivate(ptr);
   1190  return v;
   1191 }
   1192 
   1193 static inline Value PrivateValue(uintptr_t ptr) {
   1194  return PrivateValue(reinterpret_cast<void*>(ptr));
   1195 }
   1196 
   1197 static inline Value PrivateUint32Value(uint32_t ui) {
   1198  Value v;
   1199  v.setPrivateUint32(ui);
   1200  return v;
   1201 }
   1202 
   1203 static inline Value PrivateGCThingValue(js::gc::Cell* cell) {
   1204  Value v;
   1205  v.setPrivateGCThing(cell);
   1206  return v;
   1207 }
   1208 
   1209 inline bool SameType(const Value& lhs, const Value& rhs) {
   1210 #if defined(JS_NUNBOX32)
   1211  JSValueTag ltag = lhs.toTag(), rtag = rhs.toTag();
   1212  return ltag == rtag || (ltag < JSVAL_TAG_CLEAR && rtag < JSVAL_TAG_CLEAR);
   1213 #elif defined(JS_PUNBOX64)
   1214  return (lhs.isDouble() && rhs.isDouble()) ||
   1215         (((lhs.asBits_ ^ rhs.asBits_) & 0xFFFF800000000000ULL) == 0);
   1216 #endif
   1217 }
   1218 
   1219 }  // namespace JS
   1220 
   1221 /************************************************************************/
   1222 
   1223 namespace JS {
   1224 JS_PUBLIC_API void HeapValuePostWriteBarrier(Value* valuep, const Value& prev,
   1225                                             const Value& next);
   1226 JS_PUBLIC_API void HeapValueWriteBarriers(Value* valuep, const Value& prev,
   1227                                          const Value& next);
   1228 
   1229 template <>
   1230 struct GCPolicy<JS::Value> : public GCPolicyBase<JS::Value> {
   1231  static void trace(JSTracer* trc, Value* v, const char* name) {
   1232    // This should only be called as part of root marking since that's the only
   1233    // time we should trace unbarriered GC thing pointers. This will assert if
   1234    // called at other times.
   1235    TraceRoot(trc, v, name);
   1236  }
   1237  static bool isTenured(const Value& thing) {
   1238    return !thing.isGCThing() || !IsInsideNursery(thing.toGCThing());
   1239  }
   1240  static bool isValid(const Value& value) {
   1241    return !value.isGCThing() || js::gc::IsCellPointerValid(value.toGCThing());
   1242  }
   1243 };
   1244 
   1245 }  // namespace JS
   1246 
   1247 namespace js {
   1248 
   1249 template <>
   1250 struct BarrierMethods<JS::Value> {
   1251  static gc::Cell* asGCThingOrNull(const JS::Value& v) {
   1252    return v.isGCThing() ? v.toGCThing() : nullptr;
   1253  }
   1254  static void writeBarriers(JS::Value* v, const JS::Value& prev,
   1255                            const JS::Value& next) {
   1256    JS::HeapValueWriteBarriers(v, prev, next);
   1257  }
   1258  static void postWriteBarrier(JS::Value* v, const JS::Value& prev,
   1259                               const JS::Value& next) {
   1260    JS::HeapValuePostWriteBarrier(v, prev, next);
   1261  }
   1262  static void exposeToJS(const JS::Value& v) { JS::ExposeValueToActiveJS(v); }
   1263  static void readBarrier(const JS::Value& v) {
   1264    if (v.isGCThing()) {
   1265      js::gc::IncrementalReadBarrier(v.toGCCellPtr());
   1266    }
   1267  }
   1268 };
   1269 
   1270 template <class Wrapper>
   1271 class MutableValueOperations;
   1272 
   1273 /**
   1274 * A class designed for CRTP use in implementing the non-mutating parts of the
   1275 * Value interface in Value-like classes.  Wrapper must be a class inheriting
   1276 * ValueOperations<Wrapper> with a visible get() method returning a const
   1277 * reference to the Value abstracted by Wrapper.
   1278 */
   1279 template <class Wrapper>
   1280 class WrappedPtrOperations<JS::Value, Wrapper> {
   1281  const JS::Value& value() const {
   1282    return static_cast<const Wrapper*>(this)->get();
   1283  }
   1284 
   1285 public:
   1286  bool isUndefined() const { return value().isUndefined(); }
   1287  bool isNull() const { return value().isNull(); }
   1288  bool isBoolean() const { return value().isBoolean(); }
   1289  bool isTrue() const { return value().isTrue(); }
   1290  bool isFalse() const { return value().isFalse(); }
   1291  bool isNumber() const { return value().isNumber(); }
   1292  bool isInt32() const { return value().isInt32(); }
   1293  bool isInt32(int32_t i32) const { return value().isInt32(i32); }
   1294  bool isDouble() const { return value().isDouble(); }
   1295  bool isString() const { return value().isString(); }
   1296  bool isSymbol() const { return value().isSymbol(); }
   1297  bool isBigInt() const { return value().isBigInt(); }
   1298  bool isObject() const { return value().isObject(); }
   1299  bool isMagic() const { return value().isMagic(); }
   1300  bool isMagic(JSWhyMagic why) const { return value().isMagic(why); }
   1301  bool isGCThing() const { return value().isGCThing(); }
   1302  bool isPrivateGCThing() const { return value().isPrivateGCThing(); }
   1303  bool isPrimitive() const { return value().isPrimitive(); }
   1304 
   1305  bool isNullOrUndefined() const { return value().isNullOrUndefined(); }
   1306  bool isObjectOrNull() const { return value().isObjectOrNull(); }
   1307  bool isNumeric() const { return value().isNumeric(); }
   1308 
   1309  bool toBoolean() const { return value().toBoolean(); }
   1310  double toNumber() const { return value().toNumber(); }
   1311  int32_t toInt32() const { return value().toInt32(); }
   1312  double toDouble() const { return value().toDouble(); }
   1313  JSString* toString() const { return value().toString(); }
   1314  JS::Symbol* toSymbol() const { return value().toSymbol(); }
   1315  JS::BigInt* toBigInt() const { return value().toBigInt(); }
   1316  JSObject& toObject() const { return value().toObject(); }
   1317  JSObject* toObjectOrNull() const { return value().toObjectOrNull(); }
   1318  JS::GCCellPtr toGCCellPtr() const { return value().toGCCellPtr(); }
   1319  gc::Cell* toGCThing() const { return value().toGCThing(); }
   1320  JS::TraceKind traceKind() const { return value().traceKind(); }
   1321  void* toPrivate() const { return value().toPrivate(); }
   1322  uint32_t toPrivateUint32() const { return value().toPrivateUint32(); }
   1323 
   1324  uint64_t asRawBits() const { return value().asRawBits(); }
   1325  JSValueType extractNonDoubleType() const {
   1326    return value().extractNonDoubleType();
   1327  }
   1328  JS::ValueType type() const { return value().type(); }
   1329 
   1330  JSWhyMagic whyMagic() const { return value().whyMagic(); }
   1331  uint32_t magicUint32() const { return value().magicUint32(); }
   1332 };
   1333 
   1334 /**
   1335 * A class designed for CRTP use in implementing all the mutating parts of the
   1336 * Value interface in Value-like classes.  Wrapper must be a class inheriting
   1337 * MutableWrappedPtrOperations<Wrapper> with visible get() methods returning
   1338 * const and non-const references to the Value abstracted by Wrapper.
   1339 */
   1340 template <class Wrapper>
   1341 class MutableWrappedPtrOperations<JS::Value, Wrapper>
   1342    : public WrappedPtrOperations<JS::Value, Wrapper> {
   1343 protected:
   1344  void set(const JS::Value& v) {
   1345    // Call Wrapper::set to trigger any barriers.
   1346    static_cast<Wrapper*>(this)->set(v);
   1347  }
   1348 
   1349 public:
   1350  void setNull() { set(JS::NullValue()); }
   1351  void setUndefined() { set(JS::UndefinedValue()); }
   1352  void setInt32(int32_t i) { set(JS::Int32Value(i)); }
   1353  void setDouble(double d) { set(JS::DoubleValue(d)); }
   1354  void setNaN() { set(JS::NaNValue()); }
   1355  void setInfinity() { set(JS::InfinityValue()); }
   1356  void setBoolean(bool b) { set(JS::BooleanValue(b)); }
   1357  void setMagic(JSWhyMagic why) { set(JS::MagicValue(why)); }
   1358  template <typename T>
   1359  void setNumber(T t) {
   1360    set(JS::NumberValue(t));
   1361  }
   1362  void setString(JSString* str) { set(JS::StringValue(str)); }
   1363  void setSymbol(JS::Symbol* sym) { set(JS::SymbolValue(sym)); }
   1364  void setBigInt(JS::BigInt* bi) { set(JS::BigIntValue(bi)); }
   1365  void setObject(JSObject& obj) { set(JS::ObjectValue(obj)); }
   1366  void setObjectOrNull(JSObject* arg) { set(JS::ObjectOrNullValue(arg)); }
   1367  void setPrivate(void* ptr) { set(JS::PrivateValue(ptr)); }
   1368  void setPrivateUint32(uint32_t ui) { set(JS::PrivateUint32Value(ui)); }
   1369  void setPrivateGCThing(js::gc::Cell* cell) {
   1370    set(JS::PrivateGCThingValue(cell));
   1371  }
   1372 };
   1373 
   1374 /*
   1375 * Augment the generic Heap<T> interface when T = Value with
   1376 * type-querying, value-extracting, and mutating operations.
   1377 */
   1378 template <typename Wrapper>
   1379 class HeapOperations<JS::Value, Wrapper>
   1380    : public MutableWrappedPtrOperations<JS::Value, Wrapper> {};
   1381 
   1382 [[noreturn]] MOZ_COLD MOZ_NEVER_INLINE void ReportBadValueTypeAndCrash(
   1383    const JS::Value& val);
   1384 
   1385 // If the Value is a GC pointer type, call |f| with the pointer cast to that
   1386 // type and return the result wrapped in a Maybe, otherwise return None().
   1387 template <typename F>
   1388 auto MapGCThingTyped(const JS::Value& val, F&& f) {
   1389  switch (val.type()) {
   1390    case JS::ValueType::String: {
   1391      JSString* str = val.toString();
   1392      MOZ_ASSERT(gc::IsCellPointerValid(str));
   1393      return mozilla::Some(f(str));
   1394    }
   1395    case JS::ValueType::Object: {
   1396      JSObject* obj = &val.toObject();
   1397      MOZ_ASSERT(gc::IsCellPointerValid(obj));
   1398      return mozilla::Some(f(obj));
   1399    }
   1400    case JS::ValueType::Symbol: {
   1401      JS::Symbol* sym = val.toSymbol();
   1402      MOZ_ASSERT(gc::IsCellPointerValid(sym));
   1403      return mozilla::Some(f(sym));
   1404    }
   1405    case JS::ValueType::BigInt: {
   1406      JS::BigInt* bi = val.toBigInt();
   1407      MOZ_ASSERT(gc::IsCellPointerValid(bi));
   1408      return mozilla::Some(f(bi));
   1409    }
   1410    case JS::ValueType::PrivateGCThing: {
   1411      MOZ_ASSERT(gc::IsCellPointerValid(val.toGCThing()));
   1412      return mozilla::Some(MapGCThingTyped(val.toGCCellPtr(), std::move(f)));
   1413    }
   1414    case JS::ValueType::Double:
   1415    case JS::ValueType::Int32:
   1416    case JS::ValueType::Boolean:
   1417    case JS::ValueType::Undefined:
   1418    case JS::ValueType::Null:
   1419    case JS::ValueType::Magic: {
   1420      MOZ_ASSERT(!val.isGCThing());
   1421      using ReturnType = decltype(f(static_cast<JSObject*>(nullptr)));
   1422      return mozilla::Maybe<ReturnType>();
   1423    }
   1424  }
   1425 
   1426  ReportBadValueTypeAndCrash(val);
   1427 }
   1428 
   1429 // If the Value is a GC pointer type, call |f| with the pointer cast to that
   1430 // type. Return whether this happened.
   1431 template <typename F>
   1432 bool ApplyGCThingTyped(const JS::Value& val, F&& f) {
   1433  return MapGCThingTyped(val,
   1434                         [&f](auto t) {
   1435                           f(t);
   1436                           return true;
   1437                         })
   1438      .isSome();
   1439 }
   1440 
   1441 static inline JS::Value PoisonedObjectValue(uintptr_t poison) {
   1442  JS::Value v;
   1443  v.setObjectNoCheck(reinterpret_cast<JSObject*>(poison));
   1444  return v;
   1445 }
   1446 
   1447 }  // namespace js
   1448 
   1449 #ifdef DEBUG
   1450 namespace JS {
   1451 
   1452 MOZ_ALWAYS_INLINE void AssertValueIsNotGray(const Value& value) {
   1453  if (value.isGCThing()) {
   1454    AssertCellIsNotGray(value.toGCThing());
   1455  }
   1456 }
   1457 
   1458 MOZ_ALWAYS_INLINE void AssertValueIsNotGray(const Heap<Value>& value) {
   1459  AssertValueIsNotGray(value.unbarrieredGet());
   1460 }
   1461 
   1462 }  // namespace JS
   1463 #endif
   1464 
   1465 /************************************************************************/
   1466 
   1467 namespace JS {
   1468 
   1469 extern JS_PUBLIC_DATA const HandleValue NullHandleValue;
   1470 extern JS_PUBLIC_DATA const HandleValue UndefinedHandleValue;
   1471 extern JS_PUBLIC_DATA const HandleValue TrueHandleValue;
   1472 extern JS_PUBLIC_DATA const HandleValue FalseHandleValue;
   1473 extern JS_PUBLIC_DATA const Handle<mozilla::Maybe<Value>> NothingHandleValue;
   1474 
   1475 }  // namespace JS
   1476 
   1477 #endif /* js_Value_h */