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