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