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
,
244 /** standard constructors are not created for off-thread parsing. */
245 JS_OFF_THREAD_CONSTRUCTOR
,
251 * Write records queued up in WritableStreamDefaultController.[[queue]] in the
252 * spec are either "close" (a String) or Record { [[chunk]]: chunk }, where
253 * chunk is an arbitrary user-provided (and therefore non-magic) value.
254 * Represent "close" the String as this magic value; represent Record records
255 * as the |chunk| value within each of them.
257 JS_WRITABLESTREAM_CLOSE_RECORD
,
260 * The ReadableStream pipe-to operation concludes with a "finalize" operation
261 * that accepts an optional |error| argument. In certain cases that optional
262 * |error| must be stored in a handler function, for use after a promise has
263 * settled. We represent the argument not being provided, in those cases,
264 * using this magic value.
266 JS_READABLESTREAM_PIPETO_FINALIZE_WITHOUT_ERROR
,
269 * When an error object is created without the error cause argument, we set
270 * the error's cause slot to this magic value.
272 JS_ERROR_WITHOUT_CAUSE
,
278 static inline JS::Value
PoisonedObjectValue(uintptr_t poison
);
285 // IEEE-754 bit pattern for double-precision positive infinity.
286 constexpr int InfinitySignBit
= 0;
287 constexpr uint64_t InfinityBits
=
288 mozilla::InfinityBits
<double, detail::InfinitySignBit
>::value
;
290 // This is a quiet NaN on IEEE-754[2008] compatible platforms, including X86,
291 // ARM, SPARC and modern MIPS.
293 // Note: The default sign bit for a hardware sythesized NaN differs between X86
294 // and ARM. Both values are considered compatible values on both
296 constexpr int CanonicalizedNaNSignBit
= 0;
297 constexpr uint64_t CanonicalizedNaNSignificand
= 0x8000000000000;
299 #if defined(__sparc__)
300 // Some architectures (not to name names) generate NaNs with bit patterns that
301 // are incompatible with JS::Value's bit pattern restrictions. Instead we must
302 // canonicalize all hardware values before storing in JS::Value.
303 # define JS_NONCANONICAL_HARDWARE_NAN
306 #if defined(__mips__) && !defined(__mips_nan_2008)
307 // These builds may run on hardware that has differing polarity of the signaling
308 // NaN bit. While the kernel may handle the trap for us, it is a performance
309 // issue so instead we compute the NaN to use on startup. The runtime value must
310 // still meet `ValueIsDouble` requirements which are checked on startup.
312 // In particular, we expect one of the following values on MIPS:
313 // - 0x7FF7FFFFFFFFFFFF Legacy
314 // - 0x7FF8000000000000 IEEE-754[2008]
315 # define JS_RUNTIME_CANONICAL_NAN
318 #if defined(JS_RUNTIME_CANONICAL_NAN)
319 extern uint64_t CanonicalizedNaNBits
;
321 constexpr uint64_t CanonicalizedNaNBits
=
322 mozilla::SpecificNaNBits
<double, detail::CanonicalizedNaNSignBit
,
323 detail::CanonicalizedNaNSignificand
>::value
;
325 } // namespace detail
327 // Return a quiet NaN that is compatible with JS::Value restrictions.
328 static MOZ_ALWAYS_INLINE
double GenericNaN() {
329 #if !defined(JS_RUNTIME_CANONICAL_NAN)
330 static_assert(detail::ValueIsDouble(detail::CanonicalizedNaNBits
),
331 "Canonical NaN must be compatible with JS::Value");
334 return mozilla::BitwiseCast
<double>(detail::CanonicalizedNaNBits
);
337 // Convert an arbitrary double to one compatible with JS::Value representation
338 // by replacing any NaN value with a canonical one.
339 static MOZ_ALWAYS_INLINE
double CanonicalizeNaN(double d
) {
340 if (MOZ_UNLIKELY(mozilla::IsNaN(d
))) {
347 * [SMDOC] JS::Value type
349 * JS::Value is the interface for a single JavaScript Engine value. A few
350 * general notes on JS::Value:
352 * - JS::Value has setX() and isX() members for X in
354 * { Int32, Double, String, Symbol, BigInt, Boolean, Undefined, Null,
357 * JS::Value also contains toX() for each of the non-singleton types.
359 * - Magic is a singleton type whose payload contains either a JSWhyMagic
360 * "reason" for the magic value or a uint32_t value. By providing JSWhyMagic
361 * values when creating and checking for magic values, it is possible to
362 * assert, at runtime, that only magic values with the expected reason flow
363 * through a particular value. For example, if cx->exception has a magic
364 * value, the reason must be JS_GENERATOR_CLOSING.
366 * - The JS::Value operations are preferred. The JSVAL_* operations remain for
367 * compatibility; they may be removed at some point. These operations mostly
368 * provide similar functionality. But there are a few key differences. One
369 * is that JS::Value gives null a separate type.
370 * Also, to help prevent mistakenly boxing a nullable JSObject* as an object,
371 * Value::setObject takes a JSObject&. (Conversely, Value::toObject returns a
372 * JSObject&.) A convenience member Value::setObjectOrNull is provided.
374 * - Note that JS::Value is 8 bytes on 32 and 64-bit architectures. Thus, on
375 * 32-bit user code should avoid copying jsval/JS::Value as much as possible,
376 * preferring to pass by const Value&.
378 * Spectre mitigations
379 * ===================
380 * To mitigate Spectre attacks, we do the following:
382 * - On 64-bit platforms, when unboxing a Value, we XOR the bits with the
383 * expected type tag (instead of masking the payload bits). This guarantees
384 * that toString, toObject, toSymbol will return an invalid pointer (because
385 * some high bits will be set) when called on a Value with a different type
388 * - On 32-bit platforms,when unboxing an object/string/symbol Value, we use a
389 * conditional move (not speculated) to zero the payload register if the type
392 class alignas(8) Value
{
397 constexpr Value() : asBits_(bitsFromTagAndPayload(JSVAL_TAG_UNDEFINED
, 0)) {}
400 explicit constexpr Value(uint64_t asBits
) : asBits_(asBits
) {}
402 static uint64_t bitsFromDouble(double d
) {
403 #if defined(JS_NONCANONICAL_HARDWARE_NAN)
404 d
= CanonicalizeNaN(d
);
406 return mozilla::BitwiseCast
<uint64_t>(d
);
409 static_assert(sizeof(JSValueType
) == 1,
410 "type bits must fit in a single byte");
411 static_assert(sizeof(JSValueTag
) == 4,
412 "32-bit Value's tag_ must have size 4 to complement the "
413 "payload union's size 4");
414 static_assert(sizeof(JSWhyMagic
) <= 4,
415 "32-bit Value's JSWhyMagic payload field must not inflate "
416 "the payload beyond 4 bytes");
419 #if defined(JS_NUNBOX32)
420 using PayloadType
= uint32_t;
421 #elif defined(JS_PUNBOX64)
422 using PayloadType
= uint64_t;
425 static constexpr uint64_t bitsFromTagAndPayload(JSValueTag tag
,
426 PayloadType payload
) {
427 return (uint64_t(tag
) << JSVAL_TAG_SHIFT
) | payload
;
430 static constexpr Value
fromTagAndPayload(JSValueTag tag
,
431 PayloadType payload
) {
432 return fromRawBits(bitsFromTagAndPayload(tag
, payload
));
435 static constexpr Value
fromRawBits(uint64_t asBits
) { return Value(asBits
); }
437 static constexpr Value
fromInt32(int32_t i
) {
438 return fromTagAndPayload(JSVAL_TAG_INT32
, uint32_t(i
));
441 static Value
fromDouble(double d
) { return fromRawBits(bitsFromDouble(d
)); }
444 * Returns false if creating a NumberValue containing the given type would
445 * be lossy, true otherwise.
447 template <typename T
>
448 static bool isNumberRepresentable(const T t
) {
449 return T(double(t
)) == t
;
455 asBits_
= bitsFromTagAndPayload(JSVAL_TAG_NULL
, 0);
456 MOZ_ASSERT(isNull());
459 void setUndefined() {
460 asBits_
= bitsFromTagAndPayload(JSVAL_TAG_UNDEFINED
, 0);
461 MOZ_ASSERT(isUndefined());
464 void setInt32(int32_t i
) {
465 asBits_
= bitsFromTagAndPayload(JSVAL_TAG_INT32
, uint32_t(i
));
466 MOZ_ASSERT(toInt32() == i
);
469 void setDouble(double d
) {
470 asBits_
= bitsFromDouble(d
);
471 MOZ_ASSERT(isDouble());
474 void setString(JSString
* str
) {
475 MOZ_ASSERT(js::gc::IsCellPointerValid(str
));
476 asBits_
= bitsFromTagAndPayload(JSVAL_TAG_STRING
, PayloadType(str
));
477 MOZ_ASSERT(toString() == str
);
480 void setSymbol(JS::Symbol
* sym
) {
481 MOZ_ASSERT(js::gc::IsCellPointerValid(sym
));
482 asBits_
= bitsFromTagAndPayload(JSVAL_TAG_SYMBOL
, PayloadType(sym
));
483 MOZ_ASSERT(toSymbol() == sym
);
486 void setBigInt(JS::BigInt
* bi
) {
487 MOZ_ASSERT(js::gc::IsCellPointerValid(bi
));
488 asBits_
= bitsFromTagAndPayload(JSVAL_TAG_BIGINT
, PayloadType(bi
));
489 MOZ_ASSERT(toBigInt() == bi
);
492 void setObject(JSObject
& obj
) {
493 MOZ_ASSERT(js::gc::IsCellPointerValid(&obj
));
494 setObjectNoCheck(&obj
);
495 MOZ_ASSERT(&toObject() == &obj
);
499 void setObjectNoCheck(JSObject
* obj
) {
500 asBits_
= bitsFromTagAndPayload(JSVAL_TAG_OBJECT
, PayloadType(obj
));
503 friend inline Value
js::PoisonedObjectValue(uintptr_t poison
);
506 void setBoolean(bool b
) {
507 asBits_
= bitsFromTagAndPayload(JSVAL_TAG_BOOLEAN
, uint32_t(b
));
508 MOZ_ASSERT(toBoolean() == b
);
511 void setMagic(JSWhyMagic why
) {
512 asBits_
= bitsFromTagAndPayload(JSVAL_TAG_MAGIC
, uint32_t(why
));
513 MOZ_ASSERT(whyMagic() == why
);
516 void setMagicUint32(uint32_t payload
) {
517 MOZ_ASSERT(payload
>= JS_WHY_MAGIC_COUNT
,
518 "This should only be used for non-standard magic values");
519 asBits_
= bitsFromTagAndPayload(JSVAL_TAG_MAGIC
, payload
);
520 MOZ_ASSERT(magicUint32() == payload
);
523 void setNumber(float f
) {
525 if (mozilla::NumberIsInt32(f
, &i
)) {
530 setDouble(double(f
));
533 void setNumber(double d
) {
535 if (mozilla::NumberIsInt32(d
, &i
)) {
543 template <typename T
>
544 void setNumber(const T t
) {
545 static_assert(std::is_integral
<T
>::value
, "must be integral type");
546 MOZ_ASSERT(isNumberRepresentable(t
), "value creation would be lossy");
548 if constexpr (std::numeric_limits
<T
>::is_signed
) {
549 if constexpr (sizeof(t
) <= sizeof(int32_t)) {
550 setInt32(int32_t(t
));
552 if (JSVAL_INT_MIN
<= t
&& t
<= JSVAL_INT_MAX
) {
553 setInt32(int32_t(t
));
555 setDouble(double(t
));
559 if constexpr (sizeof(t
) <= sizeof(uint16_t)) {
560 setInt32(int32_t(t
));
562 if (t
<= JSVAL_INT_MAX
) {
563 setInt32(int32_t(t
));
565 setDouble(double(t
));
571 void setObjectOrNull(JSObject
* arg
) {
579 void swap(Value
& rhs
) {
580 uint64_t tmp
= rhs
.asBits_
;
581 rhs
.asBits_
= asBits_
;
586 JSValueTag
toTag() const { return JSValueTag(asBits_
>> JSVAL_TAG_SHIFT
); }
588 template <typename T
, JSValueTag Tag
>
589 T
* unboxGCPointer() const {
590 MOZ_ASSERT((asBits_
& js::gc::CellAlignMask
) == 0,
591 "GC pointer is not aligned. Is this memory corruption?");
592 #if defined(JS_NUNBOX32)
593 uintptr_t payload
= uint32_t(asBits_
);
594 return reinterpret_cast<T
*>(payload
);
595 #elif defined(JS_PUNBOX64)
596 // Note: the 'Spectre mitigations' comment at the top of this class
597 // explains why we use XOR here.
598 constexpr uint64_t shiftedTag
= uint64_t(Tag
) << JSVAL_TAG_SHIFT
;
599 return reinterpret_cast<T
*>(uintptr_t(asBits_
^ shiftedTag
));
604 /*** JIT-only interfaces to interact with and create raw Values ***/
605 #if defined(JS_NUNBOX32)
606 PayloadType
toNunboxPayload() const { return uint32_t(asBits_
); }
608 JSValueTag
toNunboxTag() const { return toTag(); }
609 #elif defined(JS_PUNBOX64)
610 const void* bitsAsPunboxPointer() const {
611 return reinterpret_cast<void*>(asBits_
);
615 /*** Value type queries ***/
618 * N.B. GCC, in some but not all cases, chooses to emit signed comparison
619 * of JSValueTag even though its underlying type has been forced to be
620 * uint32_t. Thus, all comparisons should explicitly cast operands to
624 bool isUndefined() const {
625 #if defined(JS_NUNBOX32)
626 return toTag() == JSVAL_TAG_UNDEFINED
;
627 #elif defined(JS_PUNBOX64)
628 return asBits_
== JSVAL_SHIFTED_TAG_UNDEFINED
;
632 bool isNull() const {
633 #if defined(JS_NUNBOX32)
634 return toTag() == JSVAL_TAG_NULL
;
635 #elif defined(JS_PUNBOX64)
636 return asBits_
== JSVAL_SHIFTED_TAG_NULL
;
640 bool isNullOrUndefined() const { return isNull() || isUndefined(); }
642 bool isInt32() const { return toTag() == JSVAL_TAG_INT32
; }
644 bool isInt32(int32_t i32
) const {
645 return asBits_
== bitsFromTagAndPayload(JSVAL_TAG_INT32
, uint32_t(i32
));
648 bool isDouble() const { return detail::ValueIsDouble(asBits_
); }
650 bool isNumber() const {
651 #if defined(JS_NUNBOX32)
652 MOZ_ASSERT(toTag() != JSVAL_TAG_CLEAR
);
653 return uint32_t(toTag()) <= uint32_t(detail::ValueUpperInclNumberTag
);
654 #elif defined(JS_PUNBOX64)
655 return asBits_
< detail::ValueUpperExclShiftedNumberTag
;
659 bool isString() const { return toTag() == JSVAL_TAG_STRING
; }
661 bool isSymbol() const { return toTag() == JSVAL_TAG_SYMBOL
; }
663 bool isBigInt() const { return toTag() == JSVAL_TAG_BIGINT
; }
665 bool isObject() const {
666 #if defined(JS_NUNBOX32)
667 return toTag() == JSVAL_TAG_OBJECT
;
668 #elif defined(JS_PUNBOX64)
669 MOZ_ASSERT((asBits_
>> JSVAL_TAG_SHIFT
) <= JSVAL_TAG_OBJECT
);
670 return asBits_
>= JSVAL_SHIFTED_TAG_OBJECT
;
674 bool isPrimitive() const {
675 #if defined(JS_NUNBOX32)
676 return uint32_t(toTag()) < uint32_t(detail::ValueUpperExclPrimitiveTag
);
677 #elif defined(JS_PUNBOX64)
678 return asBits_
< detail::ValueUpperExclShiftedPrimitiveTag
;
682 bool isObjectOrNull() const { return isObject() || isNull(); }
684 bool isNumeric() const { return isNumber() || isBigInt(); }
686 bool isGCThing() const {
687 #if defined(JS_NUNBOX32)
688 /* gcc sometimes generates signed < without explicit casts. */
689 return uint32_t(toTag()) >= uint32_t(detail::ValueLowerInclGCThingTag
);
690 #elif defined(JS_PUNBOX64)
691 return asBits_
>= detail::ValueLowerInclShiftedGCThingTag
;
695 bool isBoolean() const { return toTag() == JSVAL_TAG_BOOLEAN
; }
697 bool isTrue() const {
698 return asBits_
== bitsFromTagAndPayload(JSVAL_TAG_BOOLEAN
, uint32_t(true));
701 bool isFalse() const {
702 return asBits_
== bitsFromTagAndPayload(JSVAL_TAG_BOOLEAN
, uint32_t(false));
705 bool isMagic() const { return toTag() == JSVAL_TAG_MAGIC
; }
707 bool isMagic(JSWhyMagic why
) const {
711 MOZ_RELEASE_ASSERT(whyMagic() == why
);
715 JS::TraceKind
traceKind() const {
716 MOZ_ASSERT(isGCThing());
717 static_assert((JSVAL_TAG_STRING
& 0x03) == size_t(JS::TraceKind::String
),
718 "Value type tags must correspond with JS::TraceKinds.");
719 static_assert((JSVAL_TAG_SYMBOL
& 0x03) == size_t(JS::TraceKind::Symbol
),
720 "Value type tags must correspond with JS::TraceKinds.");
721 static_assert((JSVAL_TAG_OBJECT
& 0x03) == size_t(JS::TraceKind::Object
),
722 "Value type tags must correspond with JS::TraceKinds.");
723 static_assert((JSVAL_TAG_BIGINT
& 0x03) == size_t(JS::TraceKind::BigInt
),
724 "Value type tags must correspond with JS::TraceKinds.");
725 if (MOZ_UNLIKELY(isPrivateGCThing())) {
726 return JS::GCThingTraceKind(toGCThing());
728 return JS::TraceKind(toTag() & 0x03);
731 JSWhyMagic
whyMagic() const {
732 MOZ_ASSERT(magicUint32() < JS_WHY_MAGIC_COUNT
);
733 return static_cast<JSWhyMagic
>(magicUint32());
736 uint32_t magicUint32() const {
737 MOZ_ASSERT(isMagic());
738 return uint32_t(asBits_
);
743 bool operator==(const Value
& rhs
) const { return asBits_
== rhs
.asBits_
; }
745 bool operator!=(const Value
& rhs
) const { return asBits_
!= rhs
.asBits_
; }
747 friend inline bool SameType(const Value
& lhs
, const Value
& rhs
);
749 /*** Extract the value's typed payload ***/
751 int32_t toInt32() const {
752 MOZ_ASSERT(isInt32());
753 return int32_t(asBits_
);
756 double toDouble() const {
757 MOZ_ASSERT(isDouble());
758 return mozilla::BitwiseCast
<double>(asBits_
);
761 double toNumber() const {
762 MOZ_ASSERT(isNumber());
763 return isDouble() ? toDouble() : double(toInt32());
766 JSString
* toString() const {
767 MOZ_ASSERT(isString());
768 return unboxGCPointer
<JSString
, JSVAL_TAG_STRING
>();
771 JS::Symbol
* toSymbol() const {
772 MOZ_ASSERT(isSymbol());
773 return unboxGCPointer
<JS::Symbol
, JSVAL_TAG_SYMBOL
>();
776 JS::BigInt
* toBigInt() const {
777 MOZ_ASSERT(isBigInt());
778 return unboxGCPointer
<JS::BigInt
, JSVAL_TAG_BIGINT
>();
781 JSObject
& toObject() const {
782 MOZ_ASSERT(isObject());
783 #if defined(JS_PUNBOX64)
784 MOZ_ASSERT((asBits_
& detail::ValueGCThingPayloadMask
) != 0);
786 return *unboxGCPointer
<JSObject
, JSVAL_TAG_OBJECT
>();
789 JSObject
* toObjectOrNull() const {
790 MOZ_ASSERT(isObjectOrNull());
791 #if defined(JS_NUNBOX32)
792 return reinterpret_cast<JSObject
*>(uintptr_t(asBits_
));
793 #elif defined(JS_PUNBOX64)
794 // Note: the 'Spectre mitigations' comment at the top of this class
795 // explains why we use XOR here and in other to* methods.
797 (asBits_
^ JSVAL_SHIFTED_TAG_OBJECT
) & ~detail::ValueObjectOrNullBit
;
798 MOZ_ASSERT((ptrBits
& 0x7) == 0);
799 return reinterpret_cast<JSObject
*>(ptrBits
);
803 js::gc::Cell
* toGCThing() const {
804 MOZ_ASSERT(isGCThing());
805 #if defined(JS_NUNBOX32)
806 return reinterpret_cast<js::gc::Cell
*>(uintptr_t(asBits_
));
807 #elif defined(JS_PUNBOX64)
808 uint64_t ptrBits
= asBits_
& detail::ValueGCThingPayloadMask
;
809 MOZ_ASSERT((ptrBits
& 0x7) == 0);
810 return reinterpret_cast<js::gc::Cell
*>(ptrBits
);
814 GCCellPtr
toGCCellPtr() const { return GCCellPtr(toGCThing(), traceKind()); }
816 bool toBoolean() const {
817 MOZ_ASSERT(isBoolean());
818 #if defined(JS_NUNBOX32)
819 return bool(toNunboxPayload());
820 #elif defined(JS_PUNBOX64)
821 return bool(asBits_
& 0x1);
825 uint32_t payloadAsRawUint32() const {
826 MOZ_ASSERT(!isDouble());
827 return uint32_t(asBits_
);
830 constexpr uint64_t asRawBits() const { return asBits_
; }
832 JSValueType
extractNonDoubleType() const {
833 uint32_t type
= toTag() & 0xF;
834 MOZ_ASSERT(type
> JSVAL_TYPE_DOUBLE
);
835 return JSValueType(type
);
838 JS::ValueType
type() const {
840 return JS::ValueType::Double
;
843 JSValueType type
= extractNonDoubleType();
844 MOZ_ASSERT(type
<= JSVAL_TYPE_OBJECT
);
845 return JS::ValueType(type
);
851 * Private setters/getters allow the caller to read/write arbitrary
852 * word-size pointers or uint32s. After storing to a value with
853 * setPrivateX, it is the caller's responsibility to only read using
854 * toPrivateX. Private values are given a type which ensures they
855 * aren't marked by the GC.
858 void setPrivate(void* ptr
) {
859 #if defined(JS_PUNBOX64)
860 MOZ_ASSERT(detail::IsValidUserModePointer(uintptr_t(ptr
)));
862 asBits_
= uintptr_t(ptr
);
863 MOZ_ASSERT(isDouble());
866 void* toPrivate() const {
867 MOZ_ASSERT(isDouble());
868 #if defined(JS_PUNBOX64)
869 MOZ_ASSERT(detail::IsValidUserModePointer(asBits_
));
871 return reinterpret_cast<void*>(uintptr_t(asBits_
));
874 void setPrivateUint32(uint32_t ui
) {
875 MOZ_ASSERT(uint32_t(int32_t(ui
)) == ui
);
876 setInt32(int32_t(ui
));
879 uint32_t toPrivateUint32() const { return uint32_t(toInt32()); }
882 * Private GC Thing API
884 * Non-JSObject, JSString, and JS::Symbol cells may be put into the 64-bit
885 * payload as private GC things. Such Values are considered isGCThing(), and
886 * as such, automatically marked. Their traceKind() is gotten via their
890 void setPrivateGCThing(js::gc::Cell
* cell
) {
891 MOZ_ASSERT(JS::GCThingTraceKind(cell
) != JS::TraceKind::String
,
892 "Private GC thing Values must not be strings. Make a "
893 "StringValue instead.");
894 MOZ_ASSERT(JS::GCThingTraceKind(cell
) != JS::TraceKind::Symbol
,
895 "Private GC thing Values must not be symbols. Make a "
896 "SymbolValue instead.");
897 MOZ_ASSERT(JS::GCThingTraceKind(cell
) != JS::TraceKind::BigInt
,
898 "Private GC thing Values must not be BigInts. Make a "
899 "BigIntValue instead.");
900 MOZ_ASSERT(JS::GCThingTraceKind(cell
) != JS::TraceKind::Object
,
901 "Private GC thing Values must not be objects. Make an "
902 "ObjectValue instead.");
904 MOZ_ASSERT(js::gc::IsCellPointerValid(cell
));
905 #if defined(JS_PUNBOX64)
906 // VisualStudio cannot contain parenthesized C++ style cast and shift
907 // inside decltype in template parameter:
908 // AssertionConditionType<decltype((uintptr_t(x) >> 1))>
909 // It throws syntax error.
910 MOZ_ASSERT((((uintptr_t)cell
) >> JSVAL_TAG_SHIFT
) == 0);
913 bitsFromTagAndPayload(JSVAL_TAG_PRIVATE_GCTHING
, PayloadType(cell
));
916 bool isPrivateGCThing() const { return toTag() == JSVAL_TAG_PRIVATE_GCTHING
; }
917 } JS_HAZ_GC_POINTER MOZ_NON_PARAM
;
919 static_assert(sizeof(Value
) == 8,
920 "Value size must leave three tag bits, be a binary power, and "
921 "is ubiquitously depended upon everywhere");
923 static MOZ_ALWAYS_INLINE
void ExposeValueToActiveJS(const Value
& v
) {
926 MOZ_ASSERT(!js::gc::EdgeNeedsSweepUnbarrieredSlow(&tmp
));
929 js::gc::ExposeGCThingToActiveJS(v
.toGCCellPtr());
933 /************************************************************************/
935 static inline MOZ_MAY_CALL_AFTER_MUST_RETURN Value
NullValue() {
941 static constexpr Value
UndefinedValue() { return Value(); }
943 static constexpr Value
Int32Value(int32_t i32
) { return Value::fromInt32(i32
); }
945 static inline Value
DoubleValue(double dbl
) {
951 static inline Value
CanonicalizedDoubleValue(double d
) {
952 return Value::fromDouble(CanonicalizeNaN(d
));
955 static inline Value
NaNValue() {
956 return Value::fromRawBits(detail::CanonicalizedNaNBits
);
959 static inline Value
InfinityValue() {
960 return Value::fromRawBits(detail::InfinityBits
);
963 static inline Value
Float32Value(float f
) {
969 static inline Value
StringValue(JSString
* str
) {
975 static inline Value
SymbolValue(JS::Symbol
* sym
) {
981 static inline Value
BigIntValue(JS::BigInt
* bi
) {
987 static inline Value
BooleanValue(bool boo
) {
993 static inline Value
TrueValue() {
999 static inline Value
FalseValue() {
1001 v
.setBoolean(false);
1005 static inline Value
ObjectValue(JSObject
& obj
) {
1011 static inline Value
MagicValue(JSWhyMagic why
) {
1017 static inline Value
MagicValueUint32(uint32_t payload
) {
1019 v
.setMagicUint32(payload
);
1023 static constexpr Value
NumberValue(uint32_t i
) {
1024 return i
<= JSVAL_INT_MAX
? Int32Value(int32_t(i
))
1025 : Value::fromDouble(double(i
));
1028 template <typename T
>
1029 static inline Value
NumberValue(const T t
) {
1035 static inline Value
ObjectOrNullValue(JSObject
* obj
) {
1037 v
.setObjectOrNull(obj
);
1041 static inline Value
PrivateValue(void* ptr
) {
1047 static inline Value
PrivateValue(uintptr_t ptr
) {
1048 return PrivateValue(reinterpret_cast<void*>(ptr
));
1051 static inline Value
PrivateUint32Value(uint32_t ui
) {
1053 v
.setPrivateUint32(ui
);
1057 static inline Value
PrivateGCThingValue(js::gc::Cell
* cell
) {
1059 v
.setPrivateGCThing(cell
);
1063 inline bool SameType(const Value
& lhs
, const Value
& rhs
) {
1064 #if defined(JS_NUNBOX32)
1065 JSValueTag ltag
= lhs
.toTag(), rtag
= rhs
.toTag();
1066 return ltag
== rtag
|| (ltag
< JSVAL_TAG_CLEAR
&& rtag
< JSVAL_TAG_CLEAR
);
1067 #elif defined(JS_PUNBOX64)
1068 return (lhs
.isDouble() && rhs
.isDouble()) ||
1069 (((lhs
.asBits_
^ rhs
.asBits_
) & 0xFFFF800000000000ULL
) == 0);
1075 /************************************************************************/
1078 JS_PUBLIC_API
void HeapValuePostWriteBarrier(Value
* valuep
, const Value
& prev
,
1080 JS_PUBLIC_API
void HeapValueWriteBarriers(Value
* valuep
, const Value
& prev
,
1084 struct GCPolicy
<JS::Value
> {
1085 static void trace(JSTracer
* trc
, Value
* v
, const char* name
) {
1086 // It's not safe to trace unbarriered pointers except as part of root
1088 UnsafeTraceRoot(trc
, v
, name
);
1090 static bool isTenured(const Value
& thing
) {
1091 return !thing
.isGCThing() || !IsInsideNursery(thing
.toGCThing());
1093 static bool isValid(const Value
& value
) {
1094 return !value
.isGCThing() || js::gc::IsCellPointerValid(value
.toGCThing());
1103 struct BarrierMethods
<JS::Value
> {
1104 static gc::Cell
* asGCThingOrNull(const JS::Value
& v
) {
1105 return v
.isGCThing() ? v
.toGCThing() : nullptr;
1107 static void postWriteBarrier(JS::Value
* v
, const JS::Value
& prev
,
1108 const JS::Value
& next
) {
1109 JS::HeapValuePostWriteBarrier(v
, prev
, next
);
1111 static void exposeToJS(const JS::Value
& v
) { JS::ExposeValueToActiveJS(v
); }
1114 template <class Wrapper
>
1115 class MutableValueOperations
;
1118 * A class designed for CRTP use in implementing the non-mutating parts of the
1119 * Value interface in Value-like classes. Wrapper must be a class inheriting
1120 * ValueOperations<Wrapper> with a visible get() method returning a const
1121 * reference to the Value abstracted by Wrapper.
1123 template <class Wrapper
>
1124 class WrappedPtrOperations
<JS::Value
, Wrapper
> {
1125 const JS::Value
& value() const {
1126 return static_cast<const Wrapper
*>(this)->get();
1130 bool isUndefined() const { return value().isUndefined(); }
1131 bool isNull() const { return value().isNull(); }
1132 bool isBoolean() const { return value().isBoolean(); }
1133 bool isTrue() const { return value().isTrue(); }
1134 bool isFalse() const { return value().isFalse(); }
1135 bool isNumber() const { return value().isNumber(); }
1136 bool isInt32() const { return value().isInt32(); }
1137 bool isInt32(int32_t i32
) const { return value().isInt32(i32
); }
1138 bool isDouble() const { return value().isDouble(); }
1139 bool isString() const { return value().isString(); }
1140 bool isSymbol() const { return value().isSymbol(); }
1141 bool isBigInt() const { return value().isBigInt(); }
1142 bool isObject() const { return value().isObject(); }
1143 bool isMagic() const { return value().isMagic(); }
1144 bool isMagic(JSWhyMagic why
) const { return value().isMagic(why
); }
1145 bool isGCThing() const { return value().isGCThing(); }
1146 bool isPrivateGCThing() const { return value().isPrivateGCThing(); }
1147 bool isPrimitive() const { return value().isPrimitive(); }
1149 bool isNullOrUndefined() const { return value().isNullOrUndefined(); }
1150 bool isObjectOrNull() const { return value().isObjectOrNull(); }
1151 bool isNumeric() const { return value().isNumeric(); }
1153 bool toBoolean() const { return value().toBoolean(); }
1154 double toNumber() const { return value().toNumber(); }
1155 int32_t toInt32() const { return value().toInt32(); }
1156 double toDouble() const { return value().toDouble(); }
1157 JSString
* toString() const { return value().toString(); }
1158 JS::Symbol
* toSymbol() const { return value().toSymbol(); }
1159 JS::BigInt
* toBigInt() const { return value().toBigInt(); }
1160 JSObject
& toObject() const { return value().toObject(); }
1161 JSObject
* toObjectOrNull() const { return value().toObjectOrNull(); }
1162 JS::GCCellPtr
toGCCellPtr() const { return value().toGCCellPtr(); }
1163 gc::Cell
* toGCThing() const { return value().toGCThing(); }
1164 JS::TraceKind
traceKind() const { return value().traceKind(); }
1165 void* toPrivate() const { return value().toPrivate(); }
1166 uint32_t toPrivateUint32() const { return value().toPrivateUint32(); }
1168 uint64_t asRawBits() const { return value().asRawBits(); }
1169 JSValueType
extractNonDoubleType() const {
1170 return value().extractNonDoubleType();
1172 JS::ValueType
type() const { return value().type(); }
1174 JSWhyMagic
whyMagic() const { return value().whyMagic(); }
1175 uint32_t magicUint32() const { return value().magicUint32(); }
1179 * A class designed for CRTP use in implementing all the mutating parts of the
1180 * Value interface in Value-like classes. Wrapper must be a class inheriting
1181 * MutableWrappedPtrOperations<Wrapper> with visible get() methods returning
1182 * const and non-const references to the Value abstracted by Wrapper.
1184 template <class Wrapper
>
1185 class MutableWrappedPtrOperations
<JS::Value
, Wrapper
>
1186 : public WrappedPtrOperations
<JS::Value
, Wrapper
> {
1188 void set(const JS::Value
& v
) {
1189 // Call Wrapper::set to trigger any barriers.
1190 static_cast<Wrapper
*>(this)->set(v
);
1194 void setNull() { set(JS::NullValue()); }
1195 void setUndefined() { set(JS::UndefinedValue()); }
1196 void setInt32(int32_t i
) { set(JS::Int32Value(i
)); }
1197 void setDouble(double d
) { set(JS::DoubleValue(d
)); }
1198 void setNaN() { set(JS::NaNValue()); }
1199 void setInfinity() { set(JS::InfinityValue()); }
1200 void setBoolean(bool b
) { set(JS::BooleanValue(b
)); }
1201 void setMagic(JSWhyMagic why
) { set(JS::MagicValue(why
)); }
1202 template <typename T
>
1203 void setNumber(T t
) {
1204 set(JS::NumberValue(t
));
1206 void setString(JSString
* str
) { set(JS::StringValue(str
)); }
1207 void setSymbol(JS::Symbol
* sym
) { set(JS::SymbolValue(sym
)); }
1208 void setBigInt(JS::BigInt
* bi
) { set(JS::BigIntValue(bi
)); }
1209 void setObject(JSObject
& obj
) { set(JS::ObjectValue(obj
)); }
1210 void setObjectOrNull(JSObject
* arg
) { set(JS::ObjectOrNullValue(arg
)); }
1211 void setPrivate(void* ptr
) { set(JS::PrivateValue(ptr
)); }
1212 void setPrivateUint32(uint32_t ui
) { set(JS::PrivateUint32Value(ui
)); }
1213 void setPrivateGCThing(js::gc::Cell
* cell
) {
1214 set(JS::PrivateGCThingValue(cell
));
1219 * Augment the generic Heap<T> interface when T = Value with
1220 * type-querying, value-extracting, and mutating operations.
1222 template <typename Wrapper
>
1223 class HeapBase
<JS::Value
, Wrapper
>
1224 : public MutableWrappedPtrOperations
<JS::Value
, Wrapper
> {};
1226 MOZ_HAVE_NORETURN MOZ_COLD MOZ_NEVER_INLINE
void ReportBadValueTypeAndCrash(
1227 const JS::Value
& val
);
1229 // If the Value is a GC pointer type, call |f| with the pointer cast to that
1230 // type and return the result wrapped in a Maybe, otherwise return None().
1231 template <typename F
>
1232 auto MapGCThingTyped(const JS::Value
& val
, F
&& f
) {
1233 switch (val
.type()) {
1234 case JS::ValueType::String
: {
1235 JSString
* str
= val
.toString();
1236 MOZ_ASSERT(gc::IsCellPointerValid(str
));
1237 return mozilla::Some(f(str
));
1239 case JS::ValueType::Object
: {
1240 JSObject
* obj
= &val
.toObject();
1241 MOZ_ASSERT(gc::IsCellPointerValid(obj
));
1242 return mozilla::Some(f(obj
));
1244 case JS::ValueType::Symbol
: {
1245 JS::Symbol
* sym
= val
.toSymbol();
1246 MOZ_ASSERT(gc::IsCellPointerValid(sym
));
1247 return mozilla::Some(f(sym
));
1249 case JS::ValueType::BigInt
: {
1250 JS::BigInt
* bi
= val
.toBigInt();
1251 MOZ_ASSERT(gc::IsCellPointerValid(bi
));
1252 return mozilla::Some(f(bi
));
1254 case JS::ValueType::PrivateGCThing
: {
1255 MOZ_ASSERT(gc::IsCellPointerValid(val
.toGCThing()));
1256 return mozilla::Some(MapGCThingTyped(val
.toGCCellPtr(), std::move(f
)));
1258 case JS::ValueType::Double
:
1259 case JS::ValueType::Int32
:
1260 case JS::ValueType::Boolean
:
1261 case JS::ValueType::Undefined
:
1262 case JS::ValueType::Null
:
1263 case JS::ValueType::Magic
: {
1264 MOZ_ASSERT(!val
.isGCThing());
1265 using ReturnType
= decltype(f(static_cast<JSObject
*>(nullptr)));
1266 return mozilla::Maybe
<ReturnType
>();
1270 ReportBadValueTypeAndCrash(val
);
1273 // If the Value is a GC pointer type, call |f| with the pointer cast to that
1274 // type. Return whether this happened.
1275 template <typename F
>
1276 bool ApplyGCThingTyped(const JS::Value
& val
, F
&& f
) {
1277 return MapGCThingTyped(val
,
1285 static inline JS::Value
PoisonedObjectValue(uintptr_t poison
) {
1287 v
.setObjectNoCheck(reinterpret_cast<JSObject
*>(poison
));
1296 MOZ_ALWAYS_INLINE
void AssertValueIsNotGray(const Value
& value
) {
1297 if (value
.isGCThing()) {
1298 AssertCellIsNotGray(value
.toGCThing());
1302 MOZ_ALWAYS_INLINE
void AssertValueIsNotGray(const Heap
<Value
>& value
) {
1303 AssertValueIsNotGray(value
.unbarrieredGet());
1309 /************************************************************************/
1313 extern JS_PUBLIC_DATA
const HandleValue NullHandleValue
;
1314 extern JS_PUBLIC_DATA
const HandleValue UndefinedHandleValue
;
1315 extern JS_PUBLIC_DATA
const HandleValue TrueHandleValue
;
1316 extern JS_PUBLIC_DATA
const HandleValue FalseHandleValue
;
1317 extern JS_PUBLIC_DATA
const Handle
<mozilla::Maybe
<Value
>> NothingHandleValue
;
1321 #endif /* js_Value_h */