[SM91] Update to Spidermonkey 91.1.3 APIs
[0ad.git] / libraries / source / spidermonkey / include-win32-release / js / Value.h
blob3f3bd3cf82576093cc84a2b570e8c53286beef30
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. */
9 #ifndef js_Value_h
10 #define js_Value_h
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 */
20 #include "jstypes.h"
22 #include "js/HeapAPI.h"
23 #include "js/RootingAPI.h"
24 #include "js/TypeDecls.h"
26 namespace JS {
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
39 #endif
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
61 namespace JS {
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");
139 #endif
141 namespace JS {
142 namespace detail {
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;
190 static_assert(
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
203 } // namespace JS
205 #define JSVAL_TYPE_TO_TAG(type) (JS::detail::ValueTypeToTag(type))
207 enum JSWhyMagic {
208 /** a hole in a native object's elements */
209 JS_ELEMENTS_HOLE,
211 /** there is not a pending iterator value */
212 JS_NO_ITER_VALUE,
214 /** exception value thrown when closing a generator */
215 JS_GENERATOR_CLOSING,
217 /** used in debug builds to catch tracing errors */
218 JS_ARG_POISON,
220 /** an empty subnode in the AST serializer */
221 JS_SERIALIZE_NO_NODE,
223 /** magic value passed to natives to indicate construction */
224 JS_IS_CONSTRUCTING,
226 /** see class js::HashableValue */
227 JS_HASH_KEY_EMPTY,
229 /** error while running Ion code */
230 JS_ION_ERROR,
232 /** missing recover instruction result */
233 JS_ION_BAILOUT,
235 /** optimized out slot */
236 JS_OPTIMIZED_OUT,
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,
247 /** for local use */
248 JS_GENERIC_MAGIC,
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,
274 JS_WHY_MAGIC_COUNT
277 namespace js {
278 static inline JS::Value PoisonedObjectValue(uintptr_t poison);
279 } // namespace js
281 namespace JS {
283 namespace detail {
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
295 // platforms.
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
304 #endif
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
316 #endif
318 #if defined(JS_RUNTIME_CANONICAL_NAN)
319 extern uint64_t CanonicalizedNaNBits;
320 #else
321 constexpr uint64_t CanonicalizedNaNBits =
322 mozilla::SpecificNaNBits<double, detail::CanonicalizedNaNSignBit,
323 detail::CanonicalizedNaNSignificand>::value;
324 #endif
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");
332 #endif
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))) {
341 return GenericNaN();
343 return 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,
355 * Object, Magic }
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
386 * tag.
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
390 * doesn't match.
392 class alignas(8) Value {
393 private:
394 uint64_t asBits_;
396 public:
397 constexpr Value() : asBits_(bitsFromTagAndPayload(JSVAL_TAG_UNDEFINED, 0)) {}
399 private:
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);
405 #endif
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");
418 public:
419 #if defined(JS_NUNBOX32)
420 using PayloadType = uint32_t;
421 #elif defined(JS_PUNBOX64)
422 using PayloadType = uint64_t;
423 #endif
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;
452 /*** Mutators ***/
454 void setNull() {
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);
498 private:
499 void setObjectNoCheck(JSObject* obj) {
500 asBits_ = bitsFromTagAndPayload(JSVAL_TAG_OBJECT, PayloadType(obj));
503 friend inline Value js::PoisonedObjectValue(uintptr_t poison);
505 public:
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) {
524 int32_t i;
525 if (mozilla::NumberIsInt32(f, &i)) {
526 setInt32(i);
527 return;
530 setDouble(double(f));
533 void setNumber(double d) {
534 int32_t i;
535 if (mozilla::NumberIsInt32(d, &i)) {
536 setInt32(i);
537 return;
540 setDouble(d);
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));
551 } else {
552 if (JSVAL_INT_MIN <= t && t <= JSVAL_INT_MAX) {
553 setInt32(int32_t(t));
554 } else {
555 setDouble(double(t));
558 } else {
559 if constexpr (sizeof(t) <= sizeof(uint16_t)) {
560 setInt32(int32_t(t));
561 } else {
562 if (t <= JSVAL_INT_MAX) {
563 setInt32(int32_t(t));
564 } else {
565 setDouble(double(t));
571 void setObjectOrNull(JSObject* arg) {
572 if (arg) {
573 setObject(*arg);
574 } else {
575 setNull();
579 void swap(Value& rhs) {
580 uint64_t tmp = rhs.asBits_;
581 rhs.asBits_ = asBits_;
582 asBits_ = tmp;
585 private:
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));
600 #endif
603 public:
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_);
613 #endif
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
621 * uint32_t.
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;
629 #endif
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;
637 #endif
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;
656 #endif
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;
671 #endif
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;
679 #endif
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;
692 #endif
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 {
708 if (!isMagic()) {
709 return false;
711 MOZ_RELEASE_ASSERT(whyMagic() == why);
712 return true;
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_);
741 /*** Comparison ***/
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);
785 #endif
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.
796 uint64_t ptrBits =
797 (asBits_ ^ JSVAL_SHIFTED_TAG_OBJECT) & ~detail::ValueObjectOrNullBit;
798 MOZ_ASSERT((ptrBits & 0x7) == 0);
799 return reinterpret_cast<JSObject*>(ptrBits);
800 #endif
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);
811 #endif
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);
822 #endif
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 {
839 if (isDouble()) {
840 return JS::ValueType::Double;
843 JSValueType type = extractNonDoubleType();
844 MOZ_ASSERT(type <= JSVAL_TYPE_OBJECT);
845 return JS::ValueType(type);
849 * Private API
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)));
861 #endif
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_));
870 #endif
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
887 * cells.
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);
911 #endif
912 asBits_ =
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) {
924 #ifdef DEBUG
925 Value tmp = v;
926 MOZ_ASSERT(!js::gc::EdgeNeedsSweepUnbarrieredSlow(&tmp));
927 #endif
928 if (v.isGCThing()) {
929 js::gc::ExposeGCThingToActiveJS(v.toGCCellPtr());
933 /************************************************************************/
935 static inline MOZ_MAY_CALL_AFTER_MUST_RETURN Value NullValue() {
936 Value v;
937 v.setNull();
938 return v;
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) {
946 Value v;
947 v.setDouble(dbl);
948 return v;
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) {
964 Value v;
965 v.setDouble(f);
966 return v;
969 static inline Value StringValue(JSString* str) {
970 Value v;
971 v.setString(str);
972 return v;
975 static inline Value SymbolValue(JS::Symbol* sym) {
976 Value v;
977 v.setSymbol(sym);
978 return v;
981 static inline Value BigIntValue(JS::BigInt* bi) {
982 Value v;
983 v.setBigInt(bi);
984 return v;
987 static inline Value BooleanValue(bool boo) {
988 Value v;
989 v.setBoolean(boo);
990 return v;
993 static inline Value TrueValue() {
994 Value v;
995 v.setBoolean(true);
996 return v;
999 static inline Value FalseValue() {
1000 Value v;
1001 v.setBoolean(false);
1002 return v;
1005 static inline Value ObjectValue(JSObject& obj) {
1006 Value v;
1007 v.setObject(obj);
1008 return v;
1011 static inline Value MagicValue(JSWhyMagic why) {
1012 Value v;
1013 v.setMagic(why);
1014 return v;
1017 static inline Value MagicValueUint32(uint32_t payload) {
1018 Value v;
1019 v.setMagicUint32(payload);
1020 return v;
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) {
1030 Value v;
1031 v.setNumber(t);
1032 return v;
1035 static inline Value ObjectOrNullValue(JSObject* obj) {
1036 Value v;
1037 v.setObjectOrNull(obj);
1038 return v;
1041 static inline Value PrivateValue(void* ptr) {
1042 Value v;
1043 v.setPrivate(ptr);
1044 return v;
1047 static inline Value PrivateValue(uintptr_t ptr) {
1048 return PrivateValue(reinterpret_cast<void*>(ptr));
1051 static inline Value PrivateUint32Value(uint32_t ui) {
1052 Value v;
1053 v.setPrivateUint32(ui);
1054 return v;
1057 static inline Value PrivateGCThingValue(js::gc::Cell* cell) {
1058 Value v;
1059 v.setPrivateGCThing(cell);
1060 return v;
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);
1070 #endif
1073 } // namespace JS
1075 /************************************************************************/
1077 namespace JS {
1078 JS_PUBLIC_API void HeapValuePostWriteBarrier(Value* valuep, const Value& prev,
1079 const Value& next);
1080 JS_PUBLIC_API void HeapValueWriteBarriers(Value* valuep, const Value& prev,
1081 const Value& next);
1083 template <>
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
1087 // marking.
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());
1098 } // namespace JS
1100 namespace js {
1102 template <>
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();
1129 public:
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> {
1187 protected:
1188 void set(const JS::Value& v) {
1189 // Call Wrapper::set to trigger any barriers.
1190 static_cast<Wrapper*>(this)->set(v);
1193 public:
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,
1278 [&f](auto t) {
1279 f(t);
1280 return true;
1282 .isSome();
1285 static inline JS::Value PoisonedObjectValue(uintptr_t poison) {
1286 JS::Value v;
1287 v.setObjectNoCheck(reinterpret_cast<JSObject*>(poison));
1288 return v;
1291 } // namespace js
1293 #ifdef DEBUG
1294 namespace JS {
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());
1306 } // namespace JS
1307 #endif
1309 /************************************************************************/
1311 namespace JS {
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;
1319 } // namespace JS
1321 #endif /* js_Value_h */