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/. */
7 /* JS::Value implementation. */
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"
18 #include <limits> /* for std::numeric_limits */
22 #include "js/HeapAPI.h"
23 #include "js/RootingAPI.h"
24 #include "js/TypeDecls.h"
27 class JS_PUBLIC_API Value
;
30 /* JS::Value can store a full int32_t. */
31 #define JSVAL_INT_BITS 32
32 #define JSVAL_INT_MIN ((int32_t)0x80000000)
33 #define JSVAL_INT_MAX ((int32_t)0x7fffffff)
35 #if defined(JS_NUNBOX32)
36 # define JSVAL_TAG_SHIFT 32
37 #elif defined(JS_PUNBOX64)
38 # define JSVAL_TAG_SHIFT 47
41 // Use enums so that printing a JS::Value in the debugger shows nice
42 // symbolic type tags.
44 enum JSValueType
: uint8_t {
45 JSVAL_TYPE_DOUBLE
= 0x00,
46 JSVAL_TYPE_INT32
= 0x01,
47 JSVAL_TYPE_BOOLEAN
= 0x02,
48 JSVAL_TYPE_UNDEFINED
= 0x03,
49 JSVAL_TYPE_NULL
= 0x04,
50 JSVAL_TYPE_MAGIC
= 0x05,
51 JSVAL_TYPE_STRING
= 0x06,
52 JSVAL_TYPE_SYMBOL
= 0x07,
53 JSVAL_TYPE_PRIVATE_GCTHING
= 0x08,
54 JSVAL_TYPE_BIGINT
= 0x09,
55 JSVAL_TYPE_OBJECT
= 0x0c,
57 // This type never appears in a Value; it's only an out-of-band value.
58 JSVAL_TYPE_UNKNOWN
= 0x20
62 enum class ValueType
: uint8_t {
63 Double
= JSVAL_TYPE_DOUBLE
,
64 Int32
= JSVAL_TYPE_INT32
,
65 Boolean
= JSVAL_TYPE_BOOLEAN
,
66 Undefined
= JSVAL_TYPE_UNDEFINED
,
67 Null
= JSVAL_TYPE_NULL
,
68 Magic
= JSVAL_TYPE_MAGIC
,
69 String
= JSVAL_TYPE_STRING
,
70 Symbol
= JSVAL_TYPE_SYMBOL
,
71 PrivateGCThing
= JSVAL_TYPE_PRIVATE_GCTHING
,
72 BigInt
= JSVAL_TYPE_BIGINT
,
73 Object
= JSVAL_TYPE_OBJECT
,
77 static_assert(sizeof(JSValueType
) == 1,
78 "compiler typed enum support is apparently buggy");
80 #if defined(JS_NUNBOX32)
82 enum JSValueTag
: uint32_t {
83 JSVAL_TAG_CLEAR
= 0xFFFFFF80,
84 JSVAL_TAG_INT32
= JSVAL_TAG_CLEAR
| JSVAL_TYPE_INT32
,
85 JSVAL_TAG_UNDEFINED
= JSVAL_TAG_CLEAR
| JSVAL_TYPE_UNDEFINED
,
86 JSVAL_TAG_NULL
= JSVAL_TAG_CLEAR
| JSVAL_TYPE_NULL
,
87 JSVAL_TAG_BOOLEAN
= JSVAL_TAG_CLEAR
| JSVAL_TYPE_BOOLEAN
,
88 JSVAL_TAG_MAGIC
= JSVAL_TAG_CLEAR
| JSVAL_TYPE_MAGIC
,
89 JSVAL_TAG_STRING
= JSVAL_TAG_CLEAR
| JSVAL_TYPE_STRING
,
90 JSVAL_TAG_SYMBOL
= JSVAL_TAG_CLEAR
| JSVAL_TYPE_SYMBOL
,
91 JSVAL_TAG_PRIVATE_GCTHING
= JSVAL_TAG_CLEAR
| JSVAL_TYPE_PRIVATE_GCTHING
,
92 JSVAL_TAG_BIGINT
= JSVAL_TAG_CLEAR
| JSVAL_TYPE_BIGINT
,
93 JSVAL_TAG_OBJECT
= JSVAL_TAG_CLEAR
| JSVAL_TYPE_OBJECT
96 static_assert(sizeof(JSValueTag
) == sizeof(uint32_t),
97 "compiler typed enum support is apparently buggy");
99 #elif defined(JS_PUNBOX64)
101 enum JSValueTag
: uint32_t {
102 JSVAL_TAG_MAX_DOUBLE
= 0x1FFF0,
103 JSVAL_TAG_INT32
= JSVAL_TAG_MAX_DOUBLE
| JSVAL_TYPE_INT32
,
104 JSVAL_TAG_UNDEFINED
= JSVAL_TAG_MAX_DOUBLE
| JSVAL_TYPE_UNDEFINED
,
105 JSVAL_TAG_NULL
= JSVAL_TAG_MAX_DOUBLE
| JSVAL_TYPE_NULL
,
106 JSVAL_TAG_BOOLEAN
= JSVAL_TAG_MAX_DOUBLE
| JSVAL_TYPE_BOOLEAN
,
107 JSVAL_TAG_MAGIC
= JSVAL_TAG_MAX_DOUBLE
| JSVAL_TYPE_MAGIC
,
108 JSVAL_TAG_STRING
= JSVAL_TAG_MAX_DOUBLE
| JSVAL_TYPE_STRING
,
109 JSVAL_TAG_SYMBOL
= JSVAL_TAG_MAX_DOUBLE
| JSVAL_TYPE_SYMBOL
,
110 JSVAL_TAG_PRIVATE_GCTHING
= JSVAL_TAG_MAX_DOUBLE
| JSVAL_TYPE_PRIVATE_GCTHING
,
111 JSVAL_TAG_BIGINT
= JSVAL_TAG_MAX_DOUBLE
| JSVAL_TYPE_BIGINT
,
112 JSVAL_TAG_OBJECT
= JSVAL_TAG_MAX_DOUBLE
| JSVAL_TYPE_OBJECT
115 static_assert(sizeof(JSValueTag
) == sizeof(uint32_t),
116 "compiler typed enum support is apparently buggy");
118 enum JSValueShiftedTag
: uint64_t {
119 // See Bug 584653 for why we include 0xFFFFFFFF.
120 JSVAL_SHIFTED_TAG_MAX_DOUBLE
=
121 ((uint64_t(JSVAL_TAG_MAX_DOUBLE
) << JSVAL_TAG_SHIFT
) | 0xFFFFFFFF),
122 JSVAL_SHIFTED_TAG_INT32
= (uint64_t(JSVAL_TAG_INT32
) << JSVAL_TAG_SHIFT
),
123 JSVAL_SHIFTED_TAG_UNDEFINED
=
124 (uint64_t(JSVAL_TAG_UNDEFINED
) << JSVAL_TAG_SHIFT
),
125 JSVAL_SHIFTED_TAG_NULL
= (uint64_t(JSVAL_TAG_NULL
) << JSVAL_TAG_SHIFT
),
126 JSVAL_SHIFTED_TAG_BOOLEAN
= (uint64_t(JSVAL_TAG_BOOLEAN
) << JSVAL_TAG_SHIFT
),
127 JSVAL_SHIFTED_TAG_MAGIC
= (uint64_t(JSVAL_TAG_MAGIC
) << JSVAL_TAG_SHIFT
),
128 JSVAL_SHIFTED_TAG_STRING
= (uint64_t(JSVAL_TAG_STRING
) << JSVAL_TAG_SHIFT
),
129 JSVAL_SHIFTED_TAG_SYMBOL
= (uint64_t(JSVAL_TAG_SYMBOL
) << JSVAL_TAG_SHIFT
),
130 JSVAL_SHIFTED_TAG_PRIVATE_GCTHING
=
131 (uint64_t(JSVAL_TAG_PRIVATE_GCTHING
) << JSVAL_TAG_SHIFT
),
132 JSVAL_SHIFTED_TAG_BIGINT
= (uint64_t(JSVAL_TAG_BIGINT
) << JSVAL_TAG_SHIFT
),
133 JSVAL_SHIFTED_TAG_OBJECT
= (uint64_t(JSVAL_TAG_OBJECT
) << JSVAL_TAG_SHIFT
)
136 static_assert(sizeof(JSValueShiftedTag
) == sizeof(uint64_t),
137 "compiler typed enum support is apparently buggy");
144 #if defined(JS_NUNBOX32)
146 constexpr JSValueTag
ValueTypeToTag(JSValueType type
) {
147 return static_cast<JSValueTag
>(JSVAL_TAG_CLEAR
| type
);
150 constexpr bool ValueIsDouble(uint64_t bits
) {
151 return uint32_t(bits
>> JSVAL_TAG_SHIFT
) <= uint32_t(JSVAL_TAG_CLEAR
);
154 constexpr JSValueTag ValueUpperExclPrimitiveTag
= JSVAL_TAG_OBJECT
;
155 constexpr JSValueTag ValueUpperInclNumberTag
= JSVAL_TAG_INT32
;
156 constexpr JSValueTag ValueLowerInclGCThingTag
= JSVAL_TAG_STRING
;
158 #elif defined(JS_PUNBOX64)
160 constexpr JSValueTag
ValueTypeToTag(JSValueType type
) {
161 return static_cast<JSValueTag
>(JSVAL_TAG_MAX_DOUBLE
| type
);
164 constexpr bool ValueIsDouble(uint64_t bits
) {
165 return bits
<= JSVAL_SHIFTED_TAG_MAX_DOUBLE
;
168 constexpr uint64_t ValueTagMask
= 0xFFFF'8000'0000'0000;
170 // This should only be used in toGCThing. See the 'Spectre mitigations' comment.
171 constexpr uint64_t ValueGCThingPayloadMask
= 0x0000'7FFF'FFFF'FFFF;
173 constexpr uint64_t ValueTypeToShiftedTag(JSValueType type
) {
174 return static_cast<uint64_t>(ValueTypeToTag(type
)) << JSVAL_TAG_SHIFT
;
176 # define JSVAL_TYPE_TO_SHIFTED_TAG(type) \
177 (JS::detail::ValueTypeToShiftedTag(type))
179 constexpr JSValueTag ValueUpperExclPrimitiveTag
= JSVAL_TAG_OBJECT
;
180 constexpr JSValueTag ValueUpperInclNumberTag
= JSVAL_TAG_INT32
;
181 constexpr JSValueTag ValueLowerInclGCThingTag
= JSVAL_TAG_STRING
;
183 constexpr uint64_t ValueUpperExclShiftedPrimitiveTag
= JSVAL_SHIFTED_TAG_OBJECT
;
184 constexpr uint64_t ValueUpperExclShiftedNumberTag
= JSVAL_SHIFTED_TAG_BOOLEAN
;
185 constexpr uint64_t ValueLowerInclShiftedGCThingTag
= JSVAL_SHIFTED_TAG_STRING
;
187 // JSVAL_TYPE_OBJECT and JSVAL_TYPE_NULL differ by one bit. We can use this to
188 // implement toObjectOrNull more efficiently.
189 constexpr uint64_t ValueObjectOrNullBit
= 0x8ULL
<< JSVAL_TAG_SHIFT
;
191 (JSVAL_SHIFTED_TAG_NULL
^ JSVAL_SHIFTED_TAG_OBJECT
) == ValueObjectOrNullBit
,
192 "ValueObjectOrNullBit must be consistent with object and null tags");
194 constexpr uint64_t IsValidUserModePointer(uint64_t bits
) {
195 // All 64-bit platforms that we support actually have a 48-bit address space
196 // for user-mode pointers, with the top 16 bits all set to zero.
197 return (bits
& 0xFFFF'0000'0000'0000) == 0;
200 #endif /* JS_PUNBOX64 */
202 } // namespace detail
205 #define JSVAL_TYPE_TO_TAG(type) (JS::detail::ValueTypeToTag(type))
208 /** a hole in a native object's elements */
211 /** there is not a pending iterator value */
214 /** exception value thrown when closing a generator */
215 JS_GENERATOR_CLOSING
,
217 /** used in debug builds to catch tracing errors */
220 /** an empty subnode in the AST serializer */
221 JS_SERIALIZE_NO_NODE
,
223 /** magic value passed to natives to indicate construction */
226 /** see class js::HashableValue */
229 /** error while running Ion code */
232 /** missing recover instruction result */
235 /** optimized out slot */
238 /** uninitialized lexical bindings that produce ReferenceError on touch. */
239 JS_UNINITIALIZED_LEXICAL
,
241 /** arguments object can't be created because environment is dead. */
242 JS_MISSING_ARGUMENTS
,
248 * Write records queued up in WritableStreamDefaultController.[[queue]] in the
249 * spec are either "close" (a String) or Record { [[chunk]]: chunk }, where
250 * chunk is an arbitrary user-provided (and therefore non-magic) value.
251 * Represent "close" the String as this magic value; represent Record records
252 * as the |chunk| value within each of them.
254 JS_WRITABLESTREAM_CLOSE_RECORD
,
257 * The ReadableStream pipe-to operation concludes with a "finalize" operation
258 * that accepts an optional |error| argument. In certain cases that optional
259 * |error| must be stored in a handler function, for use after a promise has
260 * settled. We represent the argument not being provided, in those cases,
261 * using this magic value.
263 JS_READABLESTREAM_PIPETO_FINALIZE_WITHOUT_ERROR
,
266 * When an error object is created without the error cause argument, we set
267 * the error's cause slot to this magic value.
269 JS_ERROR_WITHOUT_CAUSE
,
275 static inline JS::Value
PoisonedObjectValue(uintptr_t poison
);
282 // IEEE-754 bit pattern for double-precision positive infinity.
283 constexpr int InfinitySignBit
= 0;
284 constexpr uint64_t InfinityBits
=
285 mozilla::InfinityBits
<double, detail::InfinitySignBit
>::value
;
287 // This is a quiet NaN on IEEE-754[2008] compatible platforms, including X86,
288 // ARM, SPARC and modern MIPS.
290 // Note: The default sign bit for a hardware sythesized NaN differs between X86
291 // and ARM. Both values are considered compatible values on both
293 constexpr int CanonicalizedNaNSignBit
= 0;
294 constexpr uint64_t CanonicalizedNaNSignificand
= 0x8000000000000;
296 #if defined(__sparc__)
297 // Some architectures (not to name names) generate NaNs with bit patterns that
298 // are incompatible with JS::Value's bit pattern restrictions. Instead we must
299 // canonicalize all hardware values before storing in JS::Value.
300 # define JS_NONCANONICAL_HARDWARE_NAN
303 #if defined(__mips__) && !defined(__mips_nan_2008)
304 // These builds may run on hardware that has differing polarity of the signaling
305 // NaN bit. While the kernel may handle the trap for us, it is a performance
306 // issue so instead we compute the NaN to use on startup. The runtime value must
307 // still meet `ValueIsDouble` requirements which are checked on startup.
309 // In particular, we expect one of the following values on MIPS:
310 // - 0x7FF7FFFFFFFFFFFF Legacy
311 // - 0x7FF8000000000000 IEEE-754[2008]
312 # define JS_RUNTIME_CANONICAL_NAN
315 #if defined(JS_RUNTIME_CANONICAL_NAN)
316 extern uint64_t CanonicalizedNaNBits
;
318 constexpr uint64_t CanonicalizedNaNBits
=
319 mozilla::SpecificNaNBits
<double, detail::CanonicalizedNaNSignBit
,
320 detail::CanonicalizedNaNSignificand
>::value
;
322 } // namespace detail
324 // Return a quiet NaN that is compatible with JS::Value restrictions.
325 static MOZ_ALWAYS_INLINE
double GenericNaN() {
326 #if !defined(JS_RUNTIME_CANONICAL_NAN)
327 static_assert(detail::ValueIsDouble(detail::CanonicalizedNaNBits
),
328 "Canonical NaN must be compatible with JS::Value");
331 return mozilla::BitwiseCast
<double>(detail::CanonicalizedNaNBits
);
334 // Convert an arbitrary double to one compatible with JS::Value representation
335 // by replacing any NaN value with a canonical one.
336 static MOZ_ALWAYS_INLINE
double CanonicalizeNaN(double d
) {
337 if (MOZ_UNLIKELY(mozilla::IsNaN(d
))) {
344 * [SMDOC] JS::Value type
346 * JS::Value is the interface for a single JavaScript Engine value. A few
347 * general notes on JS::Value:
349 * - JS::Value has setX() and isX() members for X in
351 * { Int32, Double, String, Symbol, BigInt, Boolean, Undefined, Null,
354 * JS::Value also contains toX() for each of the non-singleton types.
356 * - Magic is a singleton type whose payload contains either a JSWhyMagic
357 * "reason" for the magic value or a uint32_t value. By providing JSWhyMagic
358 * values when creating and checking for magic values, it is possible to
359 * assert, at runtime, that only magic values with the expected reason flow
360 * through a particular value. For example, if cx->exception has a magic
361 * value, the reason must be JS_GENERATOR_CLOSING.
363 * - The JS::Value operations are preferred. The JSVAL_* operations remain for
364 * compatibility; they may be removed at some point. These operations mostly
365 * provide similar functionality. But there are a few key differences. One
366 * is that JS::Value gives null a separate type.
367 * Also, to help prevent mistakenly boxing a nullable JSObject* as an object,
368 * Value::setObject takes a JSObject&. (Conversely, Value::toObject returns a
369 * JSObject&.) A convenience member Value::setObjectOrNull is provided.
371 * - Note that JS::Value is 8 bytes on 32 and 64-bit architectures. Thus, on
372 * 32-bit user code should avoid copying jsval/JS::Value as much as possible,
373 * preferring to pass by const Value&.
375 * Spectre mitigations
376 * ===================
377 * To mitigate Spectre attacks, we do the following:
379 * - On 64-bit platforms, when unboxing a Value, we XOR the bits with the
380 * expected type tag (instead of masking the payload bits). This guarantees
381 * that toString, toObject, toSymbol will return an invalid pointer (because
382 * some high bits will be set) when called on a Value with a different type
385 * - On 32-bit platforms,when unboxing an object/string/symbol Value, we use a
386 * conditional move (not speculated) to zero the payload register if the type
389 class alignas(8) Value
{
394 constexpr Value() : asBits_(bitsFromTagAndPayload(JSVAL_TAG_UNDEFINED
, 0)) {}
397 explicit constexpr Value(uint64_t asBits
) : asBits_(asBits
) {}
399 static uint64_t bitsFromDouble(double d
) {
400 #if defined(JS_NONCANONICAL_HARDWARE_NAN)
401 d
= CanonicalizeNaN(d
);
403 return mozilla::BitwiseCast
<uint64_t>(d
);
406 static_assert(sizeof(JSValueType
) == 1,
407 "type bits must fit in a single byte");
408 static_assert(sizeof(JSValueTag
) == 4,
409 "32-bit Value's tag_ must have size 4 to complement the "
410 "payload union's size 4");
411 static_assert(sizeof(JSWhyMagic
) <= 4,
412 "32-bit Value's JSWhyMagic payload field must not inflate "
413 "the payload beyond 4 bytes");
416 #if defined(JS_NUNBOX32)
417 using PayloadType
= uint32_t;
418 #elif defined(JS_PUNBOX64)
419 using PayloadType
= uint64_t;
422 static constexpr uint64_t bitsFromTagAndPayload(JSValueTag tag
,
423 PayloadType payload
) {
424 return (uint64_t(tag
) << JSVAL_TAG_SHIFT
) | payload
;
427 static constexpr Value
fromTagAndPayload(JSValueTag tag
,
428 PayloadType payload
) {
429 return fromRawBits(bitsFromTagAndPayload(tag
, payload
));
432 static constexpr Value
fromRawBits(uint64_t asBits
) { return Value(asBits
); }
434 static constexpr Value
fromInt32(int32_t i
) {
435 return fromTagAndPayload(JSVAL_TAG_INT32
, uint32_t(i
));
438 static Value
fromDouble(double d
) { return fromRawBits(bitsFromDouble(d
)); }
441 * Returns false if creating a NumberValue containing the given type would
442 * be lossy, true otherwise.
444 template <typename T
>
445 static bool isNumberRepresentable(const T t
) {
446 return T(double(t
)) == t
;
452 asBits_
= bitsFromTagAndPayload(JSVAL_TAG_NULL
, 0);
453 MOZ_ASSERT(isNull());
456 void setUndefined() {
457 asBits_
= bitsFromTagAndPayload(JSVAL_TAG_UNDEFINED
, 0);
458 MOZ_ASSERT(isUndefined());
461 void setInt32(int32_t i
) {
462 asBits_
= bitsFromTagAndPayload(JSVAL_TAG_INT32
, uint32_t(i
));
463 MOZ_ASSERT(toInt32() == i
);
466 void setDouble(double d
) {
467 asBits_
= bitsFromDouble(d
);
468 MOZ_ASSERT(isDouble());
471 void setString(JSString
* str
) {
472 MOZ_ASSERT(js::gc::IsCellPointerValid(str
));
473 asBits_
= bitsFromTagAndPayload(JSVAL_TAG_STRING
, PayloadType(str
));
474 MOZ_ASSERT(toString() == str
);
477 void setSymbol(JS::Symbol
* sym
) {
478 MOZ_ASSERT(js::gc::IsCellPointerValid(sym
));
479 asBits_
= bitsFromTagAndPayload(JSVAL_TAG_SYMBOL
, PayloadType(sym
));
480 MOZ_ASSERT(toSymbol() == sym
);
483 void setBigInt(JS::BigInt
* bi
) {
484 MOZ_ASSERT(js::gc::IsCellPointerValid(bi
));
485 asBits_
= bitsFromTagAndPayload(JSVAL_TAG_BIGINT
, PayloadType(bi
));
486 MOZ_ASSERT(toBigInt() == bi
);
489 void setObject(JSObject
& obj
) {
490 MOZ_ASSERT(js::gc::IsCellPointerValid(&obj
));
491 setObjectNoCheck(&obj
);
492 MOZ_ASSERT(&toObject() == &obj
);
496 void setObjectNoCheck(JSObject
* obj
) {
497 asBits_
= bitsFromTagAndPayload(JSVAL_TAG_OBJECT
, PayloadType(obj
));
500 friend inline Value
js::PoisonedObjectValue(uintptr_t poison
);
503 void setBoolean(bool b
) {
504 asBits_
= bitsFromTagAndPayload(JSVAL_TAG_BOOLEAN
, uint32_t(b
));
505 MOZ_ASSERT(toBoolean() == b
);
508 void setMagic(JSWhyMagic why
) {
509 asBits_
= bitsFromTagAndPayload(JSVAL_TAG_MAGIC
, uint32_t(why
));
510 MOZ_ASSERT(whyMagic() == why
);
513 void setMagicUint32(uint32_t payload
) {
514 MOZ_ASSERT(payload
>= JS_WHY_MAGIC_COUNT
,
515 "This should only be used for non-standard magic values");
516 asBits_
= bitsFromTagAndPayload(JSVAL_TAG_MAGIC
, payload
);
517 MOZ_ASSERT(magicUint32() == payload
);
520 void setNumber(float f
) {
522 if (mozilla::NumberIsInt32(f
, &i
)) {
527 setDouble(double(f
));
530 void setNumber(double d
) {
532 if (mozilla::NumberIsInt32(d
, &i
)) {
540 template <typename T
>
541 void setNumber(const T t
) {
542 static_assert(std::is_integral
<T
>::value
, "must be integral type");
543 MOZ_ASSERT(isNumberRepresentable(t
), "value creation would be lossy");
545 if constexpr (std::numeric_limits
<T
>::is_signed
) {
546 if constexpr (sizeof(t
) <= sizeof(int32_t)) {
547 setInt32(int32_t(t
));
549 if (JSVAL_INT_MIN
<= t
&& t
<= JSVAL_INT_MAX
) {
550 setInt32(int32_t(t
));
552 setDouble(double(t
));
556 if constexpr (sizeof(t
) <= sizeof(uint16_t)) {
557 setInt32(int32_t(t
));
559 if (t
<= JSVAL_INT_MAX
) {
560 setInt32(int32_t(t
));
562 setDouble(double(t
));
568 void setObjectOrNull(JSObject
* arg
) {
576 void swap(Value
& rhs
) {
577 uint64_t tmp
= rhs
.asBits_
;
578 rhs
.asBits_
= asBits_
;
583 JSValueTag
toTag() const { return JSValueTag(asBits_
>> JSVAL_TAG_SHIFT
); }
585 template <typename T
, JSValueTag Tag
>
586 T
* unboxGCPointer() const {
587 MOZ_ASSERT((asBits_
& js::gc::CellAlignMask
) == 0,
588 "GC pointer is not aligned. Is this memory corruption?");
589 #if defined(JS_NUNBOX32)
590 uintptr_t payload
= uint32_t(asBits_
);
591 return reinterpret_cast<T
*>(payload
);
592 #elif defined(JS_PUNBOX64)
593 // Note: the 'Spectre mitigations' comment at the top of this class
594 // explains why we use XOR here.
595 constexpr uint64_t shiftedTag
= uint64_t(Tag
) << JSVAL_TAG_SHIFT
;
596 return reinterpret_cast<T
*>(uintptr_t(asBits_
^ shiftedTag
));
601 /*** JIT-only interfaces to interact with and create raw Values ***/
602 #if defined(JS_NUNBOX32)
603 PayloadType
toNunboxPayload() const { return uint32_t(asBits_
); }
605 JSValueTag
toNunboxTag() const { return toTag(); }
606 #elif defined(JS_PUNBOX64)
607 const void* bitsAsPunboxPointer() const {
608 return reinterpret_cast<void*>(asBits_
);
612 /*** Value type queries ***/
615 * N.B. GCC, in some but not all cases, chooses to emit signed comparison
616 * of JSValueTag even though its underlying type has been forced to be
617 * uint32_t. Thus, all comparisons should explicitly cast operands to
621 bool isUndefined() const {
622 #if defined(JS_NUNBOX32)
623 return toTag() == JSVAL_TAG_UNDEFINED
;
624 #elif defined(JS_PUNBOX64)
625 return asBits_
== JSVAL_SHIFTED_TAG_UNDEFINED
;
629 bool isNull() const {
630 #if defined(JS_NUNBOX32)
631 return toTag() == JSVAL_TAG_NULL
;
632 #elif defined(JS_PUNBOX64)
633 return asBits_
== JSVAL_SHIFTED_TAG_NULL
;
637 bool isNullOrUndefined() const { return isNull() || isUndefined(); }
639 bool isInt32() const { return toTag() == JSVAL_TAG_INT32
; }
641 bool isInt32(int32_t i32
) const {
642 return asBits_
== bitsFromTagAndPayload(JSVAL_TAG_INT32
, uint32_t(i32
));
645 bool isDouble() const { return detail::ValueIsDouble(asBits_
); }
647 bool isNumber() const {
648 #if defined(JS_NUNBOX32)
649 MOZ_ASSERT(toTag() != JSVAL_TAG_CLEAR
);
650 return uint32_t(toTag()) <= uint32_t(detail::ValueUpperInclNumberTag
);
651 #elif defined(JS_PUNBOX64)
652 return asBits_
< detail::ValueUpperExclShiftedNumberTag
;
656 bool isString() const { return toTag() == JSVAL_TAG_STRING
; }
658 bool isSymbol() const { return toTag() == JSVAL_TAG_SYMBOL
; }
660 bool isBigInt() const { return toTag() == JSVAL_TAG_BIGINT
; }
662 bool isObject() const {
663 #if defined(JS_NUNBOX32)
664 return toTag() == JSVAL_TAG_OBJECT
;
665 #elif defined(JS_PUNBOX64)
666 MOZ_ASSERT((asBits_
>> JSVAL_TAG_SHIFT
) <= JSVAL_TAG_OBJECT
);
667 return asBits_
>= JSVAL_SHIFTED_TAG_OBJECT
;
671 bool isPrimitive() const {
672 #if defined(JS_NUNBOX32)
673 return uint32_t(toTag()) < uint32_t(detail::ValueUpperExclPrimitiveTag
);
674 #elif defined(JS_PUNBOX64)
675 return asBits_
< detail::ValueUpperExclShiftedPrimitiveTag
;
679 bool isObjectOrNull() const { return isObject() || isNull(); }
681 bool isNumeric() const { return isNumber() || isBigInt(); }
683 bool isGCThing() const {
684 #if defined(JS_NUNBOX32)
685 /* gcc sometimes generates signed < without explicit casts. */
686 return uint32_t(toTag()) >= uint32_t(detail::ValueLowerInclGCThingTag
);
687 #elif defined(JS_PUNBOX64)
688 return asBits_
>= detail::ValueLowerInclShiftedGCThingTag
;
692 bool isBoolean() const { return toTag() == JSVAL_TAG_BOOLEAN
; }
694 bool isTrue() const {
695 return asBits_
== bitsFromTagAndPayload(JSVAL_TAG_BOOLEAN
, uint32_t(true));
698 bool isFalse() const {
699 return asBits_
== bitsFromTagAndPayload(JSVAL_TAG_BOOLEAN
, uint32_t(false));
702 bool isMagic() const { return toTag() == JSVAL_TAG_MAGIC
; }
704 bool isMagic(JSWhyMagic why
) const {
708 MOZ_RELEASE_ASSERT(whyMagic() == why
);
712 JS::TraceKind
traceKind() const {
713 MOZ_ASSERT(isGCThing());
714 static_assert((JSVAL_TAG_STRING
& 0x03) == size_t(JS::TraceKind::String
),
715 "Value type tags must correspond with JS::TraceKinds.");
716 static_assert((JSVAL_TAG_SYMBOL
& 0x03) == size_t(JS::TraceKind::Symbol
),
717 "Value type tags must correspond with JS::TraceKinds.");
718 static_assert((JSVAL_TAG_OBJECT
& 0x03) == size_t(JS::TraceKind::Object
),
719 "Value type tags must correspond with JS::TraceKinds.");
720 static_assert((JSVAL_TAG_BIGINT
& 0x03) == size_t(JS::TraceKind::BigInt
),
721 "Value type tags must correspond with JS::TraceKinds.");
722 if (MOZ_UNLIKELY(isPrivateGCThing())) {
723 return JS::GCThingTraceKind(toGCThing());
725 return JS::TraceKind(toTag() & 0x03);
728 JSWhyMagic
whyMagic() const {
729 MOZ_ASSERT(magicUint32() < JS_WHY_MAGIC_COUNT
);
730 return static_cast<JSWhyMagic
>(magicUint32());
733 uint32_t magicUint32() const {
734 MOZ_ASSERT(isMagic());
735 return uint32_t(asBits_
);
740 bool operator==(const Value
& rhs
) const { return asBits_
== rhs
.asBits_
; }
742 bool operator!=(const Value
& rhs
) const { return asBits_
!= rhs
.asBits_
; }
744 friend inline bool SameType(const Value
& lhs
, const Value
& rhs
);
746 /*** Extract the value's typed payload ***/
748 int32_t toInt32() const {
749 MOZ_ASSERT(isInt32());
750 return int32_t(asBits_
);
753 double toDouble() const {
754 MOZ_ASSERT(isDouble());
755 return mozilla::BitwiseCast
<double>(asBits_
);
758 double toNumber() const {
759 MOZ_ASSERT(isNumber());
760 return isDouble() ? toDouble() : double(toInt32());
763 JSString
* toString() const {
764 MOZ_ASSERT(isString());
765 return unboxGCPointer
<JSString
, JSVAL_TAG_STRING
>();
768 JS::Symbol
* toSymbol() const {
769 MOZ_ASSERT(isSymbol());
770 return unboxGCPointer
<JS::Symbol
, JSVAL_TAG_SYMBOL
>();
773 JS::BigInt
* toBigInt() const {
774 MOZ_ASSERT(isBigInt());
775 return unboxGCPointer
<JS::BigInt
, JSVAL_TAG_BIGINT
>();
778 JSObject
& toObject() const {
779 MOZ_ASSERT(isObject());
780 #if defined(JS_PUNBOX64)
781 MOZ_ASSERT((asBits_
& detail::ValueGCThingPayloadMask
) != 0);
783 return *unboxGCPointer
<JSObject
, JSVAL_TAG_OBJECT
>();
786 JSObject
* toObjectOrNull() const {
787 MOZ_ASSERT(isObjectOrNull());
788 #if defined(JS_NUNBOX32)
789 return reinterpret_cast<JSObject
*>(uintptr_t(asBits_
));
790 #elif defined(JS_PUNBOX64)
791 // Note: the 'Spectre mitigations' comment at the top of this class
792 // explains why we use XOR here and in other to* methods.
794 (asBits_
^ JSVAL_SHIFTED_TAG_OBJECT
) & ~detail::ValueObjectOrNullBit
;
795 MOZ_ASSERT((ptrBits
& 0x7) == 0);
796 return reinterpret_cast<JSObject
*>(ptrBits
);
800 js::gc::Cell
* toGCThing() const {
801 MOZ_ASSERT(isGCThing());
802 #if defined(JS_NUNBOX32)
803 return reinterpret_cast<js::gc::Cell
*>(uintptr_t(asBits_
));
804 #elif defined(JS_PUNBOX64)
805 uint64_t ptrBits
= asBits_
& detail::ValueGCThingPayloadMask
;
806 MOZ_ASSERT((ptrBits
& 0x7) == 0);
807 return reinterpret_cast<js::gc::Cell
*>(ptrBits
);
811 GCCellPtr
toGCCellPtr() const { return GCCellPtr(toGCThing(), traceKind()); }
813 bool toBoolean() const {
814 MOZ_ASSERT(isBoolean());
815 #if defined(JS_NUNBOX32)
816 return bool(toNunboxPayload());
817 #elif defined(JS_PUNBOX64)
818 return bool(asBits_
& 0x1);
822 uint32_t payloadAsRawUint32() const {
823 MOZ_ASSERT(!isDouble());
824 return uint32_t(asBits_
);
827 constexpr uint64_t asRawBits() const { return asBits_
; }
829 JSValueType
extractNonDoubleType() const {
830 uint32_t type
= toTag() & 0xF;
831 MOZ_ASSERT(type
> JSVAL_TYPE_DOUBLE
);
832 return JSValueType(type
);
835 JS::ValueType
type() const {
837 return JS::ValueType::Double
;
840 JSValueType type
= extractNonDoubleType();
841 MOZ_ASSERT(type
<= JSVAL_TYPE_OBJECT
);
842 return JS::ValueType(type
);
848 * Private setters/getters allow the caller to read/write arbitrary
849 * word-size pointers or uint32s. After storing to a value with
850 * setPrivateX, it is the caller's responsibility to only read using
851 * toPrivateX. Private values are given a type which ensures they
852 * aren't marked by the GC.
855 void setPrivate(void* ptr
) {
856 #if defined(JS_PUNBOX64)
857 MOZ_ASSERT(detail::IsValidUserModePointer(uintptr_t(ptr
)));
859 asBits_
= uintptr_t(ptr
);
860 MOZ_ASSERT(isDouble());
863 void* toPrivate() const {
864 MOZ_ASSERT(isDouble());
865 #if defined(JS_PUNBOX64)
866 MOZ_ASSERT(detail::IsValidUserModePointer(asBits_
));
868 return reinterpret_cast<void*>(uintptr_t(asBits_
));
871 void setPrivateUint32(uint32_t ui
) {
872 MOZ_ASSERT(uint32_t(int32_t(ui
)) == ui
);
873 setInt32(int32_t(ui
));
876 uint32_t toPrivateUint32() const { return uint32_t(toInt32()); }
879 * Private GC Thing API
881 * Non-JSObject, JSString, and JS::Symbol cells may be put into the 64-bit
882 * payload as private GC things. Such Values are considered isGCThing(), and
883 * as such, automatically marked. Their traceKind() is gotten via their
887 void setPrivateGCThing(js::gc::Cell
* cell
) {
888 MOZ_ASSERT(JS::GCThingTraceKind(cell
) != JS::TraceKind::String
,
889 "Private GC thing Values must not be strings. Make a "
890 "StringValue instead.");
891 MOZ_ASSERT(JS::GCThingTraceKind(cell
) != JS::TraceKind::Symbol
,
892 "Private GC thing Values must not be symbols. Make a "
893 "SymbolValue instead.");
894 MOZ_ASSERT(JS::GCThingTraceKind(cell
) != JS::TraceKind::BigInt
,
895 "Private GC thing Values must not be BigInts. Make a "
896 "BigIntValue instead.");
897 MOZ_ASSERT(JS::GCThingTraceKind(cell
) != JS::TraceKind::Object
,
898 "Private GC thing Values must not be objects. Make an "
899 "ObjectValue instead.");
901 MOZ_ASSERT(js::gc::IsCellPointerValid(cell
));
902 #if defined(JS_PUNBOX64)
903 // VisualStudio cannot contain parenthesized C++ style cast and shift
904 // inside decltype in template parameter:
905 // AssertionConditionType<decltype((uintptr_t(x) >> 1))>
906 // It throws syntax error.
907 MOZ_ASSERT((((uintptr_t)cell
) >> JSVAL_TAG_SHIFT
) == 0);
910 bitsFromTagAndPayload(JSVAL_TAG_PRIVATE_GCTHING
, PayloadType(cell
));
913 bool isPrivateGCThing() const { return toTag() == JSVAL_TAG_PRIVATE_GCTHING
; }
914 } JS_HAZ_GC_POINTER MOZ_NON_PARAM
;
916 static_assert(sizeof(Value
) == 8,
917 "Value size must leave three tag bits, be a binary power, and "
918 "is ubiquitously depended upon everywhere");
920 static MOZ_ALWAYS_INLINE
void ExposeValueToActiveJS(const Value
& v
) {
923 MOZ_ASSERT(!js::gc::EdgeNeedsSweepUnbarrieredSlow(&tmp
));
926 js::gc::ExposeGCThingToActiveJS(v
.toGCCellPtr());
930 /************************************************************************/
932 static inline MOZ_MAY_CALL_AFTER_MUST_RETURN Value
NullValue() {
938 static constexpr Value
UndefinedValue() { return Value(); }
940 static constexpr Value
Int32Value(int32_t i32
) { return Value::fromInt32(i32
); }
942 static inline Value
DoubleValue(double dbl
) {
948 static inline Value
CanonicalizedDoubleValue(double d
) {
949 return Value::fromDouble(CanonicalizeNaN(d
));
952 static inline Value
NaNValue() {
953 return Value::fromRawBits(detail::CanonicalizedNaNBits
);
956 static inline Value
InfinityValue() {
957 return Value::fromRawBits(detail::InfinityBits
);
960 static inline Value
Float32Value(float f
) {
966 static inline Value
StringValue(JSString
* str
) {
972 static inline Value
SymbolValue(JS::Symbol
* sym
) {
978 static inline Value
BigIntValue(JS::BigInt
* bi
) {
984 static inline Value
BooleanValue(bool boo
) {
990 static inline Value
TrueValue() {
996 static inline Value
FalseValue() {
1002 static inline Value
ObjectValue(JSObject
& obj
) {
1008 static inline Value
MagicValue(JSWhyMagic why
) {
1014 static inline Value
MagicValueUint32(uint32_t payload
) {
1016 v
.setMagicUint32(payload
);
1020 static constexpr Value
NumberValue(uint32_t i
) {
1021 return i
<= JSVAL_INT_MAX
? Int32Value(int32_t(i
))
1022 : Value::fromDouble(double(i
));
1025 template <typename T
>
1026 static inline Value
NumberValue(const T t
) {
1032 static inline Value
ObjectOrNullValue(JSObject
* obj
) {
1034 v
.setObjectOrNull(obj
);
1038 static inline Value
PrivateValue(void* ptr
) {
1044 static inline Value
PrivateValue(uintptr_t ptr
) {
1045 return PrivateValue(reinterpret_cast<void*>(ptr
));
1048 static inline Value
PrivateUint32Value(uint32_t ui
) {
1050 v
.setPrivateUint32(ui
);
1054 static inline Value
PrivateGCThingValue(js::gc::Cell
* cell
) {
1056 v
.setPrivateGCThing(cell
);
1060 inline bool SameType(const Value
& lhs
, const Value
& rhs
) {
1061 #if defined(JS_NUNBOX32)
1062 JSValueTag ltag
= lhs
.toTag(), rtag
= rhs
.toTag();
1063 return ltag
== rtag
|| (ltag
< JSVAL_TAG_CLEAR
&& rtag
< JSVAL_TAG_CLEAR
);
1064 #elif defined(JS_PUNBOX64)
1065 return (lhs
.isDouble() && rhs
.isDouble()) ||
1066 (((lhs
.asBits_
^ rhs
.asBits_
) & 0xFFFF800000000000ULL
) == 0);
1072 /************************************************************************/
1075 JS_PUBLIC_API
void HeapValuePostWriteBarrier(Value
* valuep
, const Value
& prev
,
1077 JS_PUBLIC_API
void HeapValueWriteBarriers(Value
* valuep
, const Value
& prev
,
1081 struct GCPolicy
<JS::Value
> {
1082 static void trace(JSTracer
* trc
, Value
* v
, const char* name
) {
1083 // It's not safe to trace unbarriered pointers except as part of root
1085 UnsafeTraceRoot(trc
, v
, name
);
1087 static bool isTenured(const Value
& thing
) {
1088 return !thing
.isGCThing() || !IsInsideNursery(thing
.toGCThing());
1090 static bool isValid(const Value
& value
) {
1091 return !value
.isGCThing() || js::gc::IsCellPointerValid(value
.toGCThing());
1100 struct BarrierMethods
<JS::Value
> {
1101 static gc::Cell
* asGCThingOrNull(const JS::Value
& v
) {
1102 return v
.isGCThing() ? v
.toGCThing() : nullptr;
1104 static void postWriteBarrier(JS::Value
* v
, const JS::Value
& prev
,
1105 const JS::Value
& next
) {
1106 JS::HeapValuePostWriteBarrier(v
, prev
, next
);
1108 static void exposeToJS(const JS::Value
& v
) { JS::ExposeValueToActiveJS(v
); }
1111 template <class Wrapper
>
1112 class MutableValueOperations
;
1115 * A class designed for CRTP use in implementing the non-mutating parts of the
1116 * Value interface in Value-like classes. Wrapper must be a class inheriting
1117 * ValueOperations<Wrapper> with a visible get() method returning a const
1118 * reference to the Value abstracted by Wrapper.
1120 template <class Wrapper
>
1121 class WrappedPtrOperations
<JS::Value
, Wrapper
> {
1122 const JS::Value
& value() const {
1123 return static_cast<const Wrapper
*>(this)->get();
1127 bool isUndefined() const { return value().isUndefined(); }
1128 bool isNull() const { return value().isNull(); }
1129 bool isBoolean() const { return value().isBoolean(); }
1130 bool isTrue() const { return value().isTrue(); }
1131 bool isFalse() const { return value().isFalse(); }
1132 bool isNumber() const { return value().isNumber(); }
1133 bool isInt32() const { return value().isInt32(); }
1134 bool isInt32(int32_t i32
) const { return value().isInt32(i32
); }
1135 bool isDouble() const { return value().isDouble(); }
1136 bool isString() const { return value().isString(); }
1137 bool isSymbol() const { return value().isSymbol(); }
1138 bool isBigInt() const { return value().isBigInt(); }
1139 bool isObject() const { return value().isObject(); }
1140 bool isMagic() const { return value().isMagic(); }
1141 bool isMagic(JSWhyMagic why
) const { return value().isMagic(why
); }
1142 bool isGCThing() const { return value().isGCThing(); }
1143 bool isPrivateGCThing() const { return value().isPrivateGCThing(); }
1144 bool isPrimitive() const { return value().isPrimitive(); }
1146 bool isNullOrUndefined() const { return value().isNullOrUndefined(); }
1147 bool isObjectOrNull() const { return value().isObjectOrNull(); }
1148 bool isNumeric() const { return value().isNumeric(); }
1150 bool toBoolean() const { return value().toBoolean(); }
1151 double toNumber() const { return value().toNumber(); }
1152 int32_t toInt32() const { return value().toInt32(); }
1153 double toDouble() const { return value().toDouble(); }
1154 JSString
* toString() const { return value().toString(); }
1155 JS::Symbol
* toSymbol() const { return value().toSymbol(); }
1156 JS::BigInt
* toBigInt() const { return value().toBigInt(); }
1157 JSObject
& toObject() const { return value().toObject(); }
1158 JSObject
* toObjectOrNull() const { return value().toObjectOrNull(); }
1159 JS::GCCellPtr
toGCCellPtr() const { return value().toGCCellPtr(); }
1160 gc::Cell
* toGCThing() const { return value().toGCThing(); }
1161 JS::TraceKind
traceKind() const { return value().traceKind(); }
1162 void* toPrivate() const { return value().toPrivate(); }
1163 uint32_t toPrivateUint32() const { return value().toPrivateUint32(); }
1165 uint64_t asRawBits() const { return value().asRawBits(); }
1166 JSValueType
extractNonDoubleType() const {
1167 return value().extractNonDoubleType();
1169 JS::ValueType
type() const { return value().type(); }
1171 JSWhyMagic
whyMagic() const { return value().whyMagic(); }
1172 uint32_t magicUint32() const { return value().magicUint32(); }
1176 * A class designed for CRTP use in implementing all the mutating parts of the
1177 * Value interface in Value-like classes. Wrapper must be a class inheriting
1178 * MutableWrappedPtrOperations<Wrapper> with visible get() methods returning
1179 * const and non-const references to the Value abstracted by Wrapper.
1181 template <class Wrapper
>
1182 class MutableWrappedPtrOperations
<JS::Value
, Wrapper
>
1183 : public WrappedPtrOperations
<JS::Value
, Wrapper
> {
1185 void set(const JS::Value
& v
) {
1186 // Call Wrapper::set to trigger any barriers.
1187 static_cast<Wrapper
*>(this)->set(v
);
1191 void setNull() { set(JS::NullValue()); }
1192 void setUndefined() { set(JS::UndefinedValue()); }
1193 void setInt32(int32_t i
) { set(JS::Int32Value(i
)); }
1194 void setDouble(double d
) { set(JS::DoubleValue(d
)); }
1195 void setNaN() { set(JS::NaNValue()); }
1196 void setInfinity() { set(JS::InfinityValue()); }
1197 void setBoolean(bool b
) { set(JS::BooleanValue(b
)); }
1198 void setMagic(JSWhyMagic why
) { set(JS::MagicValue(why
)); }
1199 template <typename T
>
1200 void setNumber(T t
) {
1201 set(JS::NumberValue(t
));
1203 void setString(JSString
* str
) { set(JS::StringValue(str
)); }
1204 void setSymbol(JS::Symbol
* sym
) { set(JS::SymbolValue(sym
)); }
1205 void setBigInt(JS::BigInt
* bi
) { set(JS::BigIntValue(bi
)); }
1206 void setObject(JSObject
& obj
) { set(JS::ObjectValue(obj
)); }
1207 void setObjectOrNull(JSObject
* arg
) { set(JS::ObjectOrNullValue(arg
)); }
1208 void setPrivate(void* ptr
) { set(JS::PrivateValue(ptr
)); }
1209 void setPrivateUint32(uint32_t ui
) { set(JS::PrivateUint32Value(ui
)); }
1210 void setPrivateGCThing(js::gc::Cell
* cell
) {
1211 set(JS::PrivateGCThingValue(cell
));
1216 * Augment the generic Heap<T> interface when T = Value with
1217 * type-querying, value-extracting, and mutating operations.
1219 template <typename Wrapper
>
1220 class HeapOperations
<JS::Value
, Wrapper
>
1221 : public MutableWrappedPtrOperations
<JS::Value
, Wrapper
> {};
1223 MOZ_HAVE_NORETURN MOZ_COLD MOZ_NEVER_INLINE
void ReportBadValueTypeAndCrash(
1224 const JS::Value
& val
);
1226 // If the Value is a GC pointer type, call |f| with the pointer cast to that
1227 // type and return the result wrapped in a Maybe, otherwise return None().
1228 template <typename F
>
1229 auto MapGCThingTyped(const JS::Value
& val
, F
&& f
) {
1230 switch (val
.type()) {
1231 case JS::ValueType::String
: {
1232 JSString
* str
= val
.toString();
1233 MOZ_ASSERT(gc::IsCellPointerValid(str
));
1234 return mozilla::Some(f(str
));
1236 case JS::ValueType::Object
: {
1237 JSObject
* obj
= &val
.toObject();
1238 MOZ_ASSERT(gc::IsCellPointerValid(obj
));
1239 return mozilla::Some(f(obj
));
1241 case JS::ValueType::Symbol
: {
1242 JS::Symbol
* sym
= val
.toSymbol();
1243 MOZ_ASSERT(gc::IsCellPointerValid(sym
));
1244 return mozilla::Some(f(sym
));
1246 case JS::ValueType::BigInt
: {
1247 JS::BigInt
* bi
= val
.toBigInt();
1248 MOZ_ASSERT(gc::IsCellPointerValid(bi
));
1249 return mozilla::Some(f(bi
));
1251 case JS::ValueType::PrivateGCThing
: {
1252 MOZ_ASSERT(gc::IsCellPointerValid(val
.toGCThing()));
1253 return mozilla::Some(MapGCThingTyped(val
.toGCCellPtr(), std::move(f
)));
1255 case JS::ValueType::Double
:
1256 case JS::ValueType::Int32
:
1257 case JS::ValueType::Boolean
:
1258 case JS::ValueType::Undefined
:
1259 case JS::ValueType::Null
:
1260 case JS::ValueType::Magic
: {
1261 MOZ_ASSERT(!val
.isGCThing());
1262 using ReturnType
= decltype(f(static_cast<JSObject
*>(nullptr)));
1263 return mozilla::Maybe
<ReturnType
>();
1267 ReportBadValueTypeAndCrash(val
);
1270 // If the Value is a GC pointer type, call |f| with the pointer cast to that
1271 // type. Return whether this happened.
1272 template <typename F
>
1273 bool ApplyGCThingTyped(const JS::Value
& val
, F
&& f
) {
1274 return MapGCThingTyped(val
,
1282 static inline JS::Value
PoisonedObjectValue(uintptr_t poison
) {
1284 v
.setObjectNoCheck(reinterpret_cast<JSObject
*>(poison
));
1293 MOZ_ALWAYS_INLINE
void AssertValueIsNotGray(const Value
& value
) {
1294 if (value
.isGCThing()) {
1295 AssertCellIsNotGray(value
.toGCThing());
1299 MOZ_ALWAYS_INLINE
void AssertValueIsNotGray(const Heap
<Value
>& value
) {
1300 AssertValueIsNotGray(value
.unbarrieredGet());
1306 /************************************************************************/
1310 extern JS_PUBLIC_DATA
const HandleValue NullHandleValue
;
1311 extern JS_PUBLIC_DATA
const HandleValue UndefinedHandleValue
;
1312 extern JS_PUBLIC_DATA
const HandleValue TrueHandleValue
;
1313 extern JS_PUBLIC_DATA
const HandleValue FalseHandleValue
;
1314 extern JS_PUBLIC_DATA
const Handle
<mozilla::Maybe
<Value
>> NothingHandleValue
;
1318 #endif /* js_Value_h */