Bug 1867190 - Add prefs for PHC probablities r=glandium
[gecko.git] / js / public / Value.h
blobbe6869dac9c46542c809bc4aaf5a4f7d5053c3dd
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2 * vim: set ts=8 sts=2 et sw=2 tw=80:
3 * This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 /* JS::Value implementation. */
9 #ifndef js_Value_h
10 #define js_Value_h
12 #include "mozilla/Attributes.h"
13 #include "mozilla/Casting.h"
14 #include "mozilla/FloatingPoint.h"
15 #include "mozilla/Likely.h"
16 #include "mozilla/Maybe.h"
18 #include <limits> /* for std::numeric_limits */
19 #include <type_traits>
21 #include "jstypes.h"
23 #include "js/HeapAPI.h"
24 #include "js/RootingAPI.h"
25 #include "js/TypeDecls.h"
27 namespace JS {
28 class JS_PUBLIC_API Value;
31 // [SMDOC] JS::Value Boxing Formats
33 // JS::Value is a 64-bit value, on all architectures. It is conceptually a
34 // discriminated union of all the types of values that can be represented in SM:
35 // - Object Pointers
36 // - 64 bit IEEE 754 floats
37 // - 32-bit integer values
38 // - and quite a few more (see JSValueType)
40 // The ECMAScript standard specifies that ECMAScript numbers are IEEE 64-bit
41 // floating-point values. A JS::Value can represent any JavaScript number
42 // value directly, without referring to additional storage, or represent an
43 // object, string, or other ECMAScript value, and remember which type it is.
45 // This may seem surprising: how can a 64-bit type hold all the 64-bit IEEE
46 // values, and still distinguish them from objects, strings, and so on,
47 // which have 64-bit addresses ?
49 // This is possible for two reasons:
51 // - First, ECMAScript implementations aren't required to distinguish all
52 // the values the IEEE 64-bit format can represent.
54 // The IEEE 754 format for floating point numbers specifies that every
55 // floating-point value whose 11-bit exponent field is all ones, and whose
56 // 52-bit fraction field is non-zero, has the value NaN. EMCAScript requires
57 // only one NaN value. This means we can use one IEEE NaN to represent
58 // ECMAScript's NaN, and use all the other 2^52-2 NaN bitstrings to
59 // represent the other ECMAScript values.
61 // - Second, on the 64 bit architectures we suppport, only the
62 // lower 48 bits of an address are currently significant. The upper sixteen
63 // bits are required to be the sign-extension of bit 48. Furthermore, user
64 // code always runs in "positive addresses": those in which bit 48 is zero. So
65 // we only actually need 47 bits to store all possible object or string
66 // addresses, even on 64-bit platforms.
68 // Our memory initialization system ensures that all pointers we will store in
69 // objects use only 47 bits. See js::gc::MapAlignedPagesRandom.
71 // The introduction of 5-level page tables, supporting 57-bit virtual
72 // addresses, is a potential complication. For now, large addresses are
73 // opt-in, and we simply don't use them.
75 // With a 52-bit fraction field, and 47 bits needed for the 'payload', we
76 // have up to five bits left to store a 'tag' value, to indicate which
77 // branch of our discriminated union is live. (In practice, one of those
78 // bits is used up to simplify NaN representation; see micro-optimization 5
79 // below.)
81 // Thus, we define JS::Value representations in terms of the IEEE 64-bit
82 // floating-point format:
84 // - Any bitstring that IEEE calls a number or an infinity represents that
85 // ECMAScript number.
87 // - Any bitstring that IEEE calls a NaN represents either an ECMAScript NaN
88 // or a non-number ECMAScript value, as determined by a tag field stored
89 // towards the most significant end of the fraction field (exactly where
90 // depends on the address size). If the tag field indicates that this
91 // JS::Value is an object, the fraction field's least significant end
92 // holds the address of a JSObject; if a string, the address of a
93 // JSString; and so on.
95 // To enforce this invariant, anywhere that may provide a numerical value
96 // which may have a non-canonical NaN value (NaN, but not the one we've chosen
97 // for ECMAScript) we must convert that to the canonical NaN. See
98 // JS::CanonicalizeNaN.
100 // We have two boxing modes defined: NUNBOX32 and PUNBOX64.The first is
101 // "NaN unboxed boxing" (or Nunboxing), as non-Number payload are stored
102 // unaltered in the lower bits. The second is "Packed NaN boxing" (or
103 // punboxing), which is 'logically like nunboxing, but with all the unused bits
104 // sucked out' [1], as we rely on unused bits of the payload to pack the
105 // payload in the lower bits using Nunboxing.
107 // - In NUNBOX32 the tag is stored in the least-significant bits of the high
108 // word of the NaN. Since it's used on 32-bit systems, this has the nice
109 // property that boxed values are simply stored in the low-word of the 8-byte
110 // NaN.
112 // - In PUNBOX64, since we need to store more pointer bits (47, see above), the
113 // tag is stored in the 5 most significant bits of the fraction adjacent to
114 // the exponent.
116 // Tag values are carefully ordered to support a set of micro-optimizations. In
117 // particular:
119 // 1. Object is the highest tag, to simplify isPrimitive checks. (See
120 // ValueUpperExclPrimitiveTag)
121 // 2. Numbers (Double and Int32) are the lowest tags, to simplify isNumber
122 // checks. (See ValueUpperInclNumberTag)
123 // 3. Non-GC tags are ordered before GC-tags, to simplify isGCThing checks. (See
124 // ValueLowerInclGCThingTag)
125 // 4. The tags for Object and Null differ by a single flipped bit, to simplify
126 // toObjectOrNull. (See ValueObjectOrNullBit)
127 // 5. In PUNBOX64, the most significant bit of every non-Double tag is always
128 // set. This is to simplify isDouble checks. Note that the highest bitstring
129 // that corresponds to a non-NaN double is -Infinity:
130 // 0xfff0_0000_0000_0000
131 // But the canonical hardware NaN (produced by, for example, 0/0) is:
132 // 0x?ff8_0000_0000_0000
133 // on all platforms with JIT support*. (The most significant bit is the sign
134 // bit; it is 1 on x86, but 0 on ARM.) The most significant bit of the
135 // fraction field is set, which corresponds to the most significant of the 5
136 // tag bits. Because we only use tags that have the high bit set, any Value
137 // represented by a bitstring less than or equal to 0xfff8_..._0000 is a
138 // Double. (If we wanted to use all five bits, we could define 0x10 as
139 // JSVAL_TYPE_NAN, and mask off the most significant bit of the tag for
140 // IsDouble checks. This is not yet necessary, because we still have room
141 // left to allocate new tags.)
143 // * But see JS_NONCANONICAL_HARDWARE_NAN below.
145 // [1]:
146 // https://wingolog.org/archives/2011/05/18/value-representation-in-javascript-implementations#969f63bbe4eb912778c9da85feb0f5763e7a7862
148 /* JS::Value can store a full int32_t. */
149 #define JSVAL_INT_BITS 32
150 #define JSVAL_INT_MIN ((int32_t)0x80000000)
151 #define JSVAL_INT_MAX ((int32_t)0x7fffffff)
153 #if defined(JS_NUNBOX32)
154 # define JSVAL_TAG_SHIFT 32
155 #elif defined(JS_PUNBOX64)
156 # define JSVAL_TAG_SHIFT 47
157 #endif
159 // Use enums so that printing a JS::Value in the debugger shows nice
160 // symbolic type tags.
162 enum JSValueType : uint8_t {
163 JSVAL_TYPE_DOUBLE = 0x00,
164 JSVAL_TYPE_INT32 = 0x01,
165 JSVAL_TYPE_BOOLEAN = 0x02,
166 JSVAL_TYPE_UNDEFINED = 0x03,
167 JSVAL_TYPE_NULL = 0x04,
168 JSVAL_TYPE_MAGIC = 0x05,
169 JSVAL_TYPE_STRING = 0x06,
170 JSVAL_TYPE_SYMBOL = 0x07,
171 JSVAL_TYPE_PRIVATE_GCTHING = 0x08,
172 JSVAL_TYPE_BIGINT = 0x09,
173 #ifdef ENABLE_RECORD_TUPLE
174 JSVAL_TYPE_EXTENDED_PRIMITIVE = 0x0b,
175 #endif
176 JSVAL_TYPE_OBJECT = 0x0c,
178 // This type never appears in a Value; it's only an out-of-band value.
179 JSVAL_TYPE_UNKNOWN = 0x20
182 namespace JS {
183 enum class ValueType : uint8_t {
184 Double = JSVAL_TYPE_DOUBLE,
185 Int32 = JSVAL_TYPE_INT32,
186 Boolean = JSVAL_TYPE_BOOLEAN,
187 Undefined = JSVAL_TYPE_UNDEFINED,
188 Null = JSVAL_TYPE_NULL,
189 Magic = JSVAL_TYPE_MAGIC,
190 String = JSVAL_TYPE_STRING,
191 Symbol = JSVAL_TYPE_SYMBOL,
192 PrivateGCThing = JSVAL_TYPE_PRIVATE_GCTHING,
193 BigInt = JSVAL_TYPE_BIGINT,
194 #ifdef ENABLE_RECORD_TUPLE
195 ExtendedPrimitive = JSVAL_TYPE_EXTENDED_PRIMITIVE,
196 #endif
197 Object = JSVAL_TYPE_OBJECT,
199 } // namespace JS
201 static_assert(sizeof(JSValueType) == 1,
202 "compiler typed enum support is apparently buggy");
204 #if defined(JS_NUNBOX32)
206 enum JSValueTag : uint32_t {
207 JSVAL_TAG_CLEAR = 0xFFFFFF80,
208 JSVAL_TAG_INT32 = JSVAL_TAG_CLEAR | JSVAL_TYPE_INT32,
209 JSVAL_TAG_UNDEFINED = JSVAL_TAG_CLEAR | JSVAL_TYPE_UNDEFINED,
210 JSVAL_TAG_NULL = JSVAL_TAG_CLEAR | JSVAL_TYPE_NULL,
211 JSVAL_TAG_BOOLEAN = JSVAL_TAG_CLEAR | JSVAL_TYPE_BOOLEAN,
212 JSVAL_TAG_MAGIC = JSVAL_TAG_CLEAR | JSVAL_TYPE_MAGIC,
213 JSVAL_TAG_STRING = JSVAL_TAG_CLEAR | JSVAL_TYPE_STRING,
214 JSVAL_TAG_SYMBOL = JSVAL_TAG_CLEAR | JSVAL_TYPE_SYMBOL,
215 JSVAL_TAG_PRIVATE_GCTHING = JSVAL_TAG_CLEAR | JSVAL_TYPE_PRIVATE_GCTHING,
216 JSVAL_TAG_BIGINT = JSVAL_TAG_CLEAR | JSVAL_TYPE_BIGINT,
217 # ifdef ENABLE_RECORD_TUPLE
218 JSVAL_TAG_EXTENDED_PRIMITIVE =
219 JSVAL_TAG_CLEAR | JSVAL_TYPE_EXTENDED_PRIMITIVE,
220 # endif
221 JSVAL_TAG_OBJECT = JSVAL_TAG_CLEAR | JSVAL_TYPE_OBJECT
224 static_assert(sizeof(JSValueTag) == sizeof(uint32_t),
225 "compiler typed enum support is apparently buggy");
227 #elif defined(JS_PUNBOX64)
229 enum JSValueTag : uint32_t {
230 JSVAL_TAG_MAX_DOUBLE = 0x1FFF0,
231 JSVAL_TAG_INT32 = JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_INT32,
232 JSVAL_TAG_UNDEFINED = JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_UNDEFINED,
233 JSVAL_TAG_NULL = JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_NULL,
234 JSVAL_TAG_BOOLEAN = JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_BOOLEAN,
235 JSVAL_TAG_MAGIC = JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_MAGIC,
236 JSVAL_TAG_STRING = JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_STRING,
237 JSVAL_TAG_SYMBOL = JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_SYMBOL,
238 JSVAL_TAG_PRIVATE_GCTHING = JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_PRIVATE_GCTHING,
239 JSVAL_TAG_BIGINT = JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_BIGINT,
240 # ifdef ENABLE_RECORD_TUPLE
241 JSVAL_TAG_EXTENDED_PRIMITIVE =
242 JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_EXTENDED_PRIMITIVE,
243 # endif
244 JSVAL_TAG_OBJECT = JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_OBJECT
247 static_assert(sizeof(JSValueTag) == sizeof(uint32_t),
248 "compiler typed enum support is apparently buggy");
250 enum JSValueShiftedTag : uint64_t {
251 // See Bug 584653 for why we include 0xFFFFFFFF.
252 JSVAL_SHIFTED_TAG_MAX_DOUBLE =
253 ((uint64_t(JSVAL_TAG_MAX_DOUBLE) << JSVAL_TAG_SHIFT) | 0xFFFFFFFF),
254 JSVAL_SHIFTED_TAG_INT32 = (uint64_t(JSVAL_TAG_INT32) << JSVAL_TAG_SHIFT),
255 JSVAL_SHIFTED_TAG_UNDEFINED =
256 (uint64_t(JSVAL_TAG_UNDEFINED) << JSVAL_TAG_SHIFT),
257 JSVAL_SHIFTED_TAG_NULL = (uint64_t(JSVAL_TAG_NULL) << JSVAL_TAG_SHIFT),
258 JSVAL_SHIFTED_TAG_BOOLEAN = (uint64_t(JSVAL_TAG_BOOLEAN) << JSVAL_TAG_SHIFT),
259 JSVAL_SHIFTED_TAG_MAGIC = (uint64_t(JSVAL_TAG_MAGIC) << JSVAL_TAG_SHIFT),
260 JSVAL_SHIFTED_TAG_STRING = (uint64_t(JSVAL_TAG_STRING) << JSVAL_TAG_SHIFT),
261 JSVAL_SHIFTED_TAG_SYMBOL = (uint64_t(JSVAL_TAG_SYMBOL) << JSVAL_TAG_SHIFT),
262 JSVAL_SHIFTED_TAG_PRIVATE_GCTHING =
263 (uint64_t(JSVAL_TAG_PRIVATE_GCTHING) << JSVAL_TAG_SHIFT),
264 JSVAL_SHIFTED_TAG_BIGINT = (uint64_t(JSVAL_TAG_BIGINT) << JSVAL_TAG_SHIFT),
265 # ifdef ENABLE_RECORD_TUPLE
266 JSVAL_SHIFTED_TAG_EXTENDED_PRIMITIVE =
267 (uint64_t(JSVAL_TYPE_EXTENDED_PRIMITIVE) << JSVAL_TAG_SHIFT),
268 # endif
269 JSVAL_SHIFTED_TAG_OBJECT = (uint64_t(JSVAL_TAG_OBJECT) << JSVAL_TAG_SHIFT)
272 static_assert(sizeof(JSValueShiftedTag) == sizeof(uint64_t),
273 "compiler typed enum support is apparently buggy");
275 #endif
277 namespace JS {
278 namespace detail {
280 #if defined(JS_NUNBOX32)
282 constexpr JSValueTag ValueTypeToTag(JSValueType type) {
283 return static_cast<JSValueTag>(JSVAL_TAG_CLEAR |
284 std::underlying_type_t<JSValueType>(type));
287 constexpr bool ValueIsDouble(uint64_t bits) {
288 return uint32_t(bits >> JSVAL_TAG_SHIFT) <= uint32_t(JSVAL_TAG_CLEAR);
291 constexpr JSValueTag ValueUpperExclPrimitiveTag = JSVAL_TAG_OBJECT;
292 constexpr JSValueTag ValueUpperInclNumberTag = JSVAL_TAG_INT32;
293 constexpr JSValueTag ValueLowerInclGCThingTag = JSVAL_TAG_STRING;
295 #elif defined(JS_PUNBOX64)
297 constexpr JSValueTag ValueTypeToTag(JSValueType type) {
298 return static_cast<JSValueTag>(JSVAL_TAG_MAX_DOUBLE |
299 std::underlying_type_t<JSValueType>(type));
302 constexpr bool ValueIsDouble(uint64_t bits) {
303 return bits <= JSVAL_SHIFTED_TAG_MAX_DOUBLE;
306 constexpr uint64_t ValueTagMask = 0xFFFF'8000'0000'0000;
308 // This should only be used in toGCThing. See the 'Spectre mitigations' comment.
309 constexpr uint64_t ValueGCThingPayloadMask = 0x0000'7FFF'FFFF'FFFF;
311 // Mask used to combine an unbox operation with getting the chunk base.
312 constexpr uint64_t ValueGCThingPayloadChunkMask =
313 ValueGCThingPayloadMask & ~js::gc::ChunkMask;
315 constexpr uint64_t ValueTypeToShiftedTag(JSValueType type) {
316 return static_cast<uint64_t>(ValueTypeToTag(type)) << JSVAL_TAG_SHIFT;
318 # define JSVAL_TYPE_TO_SHIFTED_TAG(type) \
319 (JS::detail::ValueTypeToShiftedTag(type))
321 constexpr JSValueTag ValueUpperExclPrimitiveTag = JSVAL_TAG_OBJECT;
322 constexpr JSValueTag ValueUpperInclNumberTag = JSVAL_TAG_INT32;
323 constexpr JSValueTag ValueLowerInclGCThingTag = JSVAL_TAG_STRING;
325 constexpr uint64_t ValueUpperExclShiftedPrimitiveTag = JSVAL_SHIFTED_TAG_OBJECT;
326 constexpr uint64_t ValueUpperExclShiftedNumberTag = JSVAL_SHIFTED_TAG_BOOLEAN;
327 constexpr uint64_t ValueLowerInclShiftedGCThingTag = JSVAL_SHIFTED_TAG_STRING;
329 // JSVAL_TYPE_OBJECT and JSVAL_TYPE_NULL differ by one bit. We can use this to
330 // implement toObjectOrNull more efficiently.
331 constexpr uint64_t ValueObjectOrNullBit = 0x8ULL << JSVAL_TAG_SHIFT;
332 static_assert(
333 (JSVAL_SHIFTED_TAG_NULL ^ JSVAL_SHIFTED_TAG_OBJECT) == ValueObjectOrNullBit,
334 "ValueObjectOrNullBit must be consistent with object and null tags");
336 constexpr uint64_t IsValidUserModePointer(uint64_t bits) {
337 // All 64-bit platforms that we support actually have a 48-bit address space
338 // for user-mode pointers, with the top 16 bits all set to zero.
339 return (bits & 0xFFFF'0000'0000'0000) == 0;
342 #endif /* JS_PUNBOX64 */
344 } // namespace detail
345 } // namespace JS
347 #define JSVAL_TYPE_TO_TAG(type) (JS::detail::ValueTypeToTag(type))
349 enum JSWhyMagic {
350 /** a hole in a native object's elements */
351 JS_ELEMENTS_HOLE,
353 /** there is not a pending iterator value */
354 JS_NO_ITER_VALUE,
356 /** exception value thrown when closing a generator */
357 JS_GENERATOR_CLOSING,
359 /** used in debug builds to catch tracing errors */
360 JS_ARG_POISON,
362 /** an empty subnode in the AST serializer */
363 JS_SERIALIZE_NO_NODE,
365 /** magic value passed to natives to indicate construction */
366 JS_IS_CONSTRUCTING,
368 /** see class js::HashableValue */
369 JS_HASH_KEY_EMPTY,
371 /** error while running Ion code */
372 JS_ION_ERROR,
374 /** missing recover instruction result */
375 JS_ION_BAILOUT,
377 /** optimized out slot */
378 JS_OPTIMIZED_OUT,
380 /** uninitialized lexical bindings that produce ReferenceError on touch. */
381 JS_UNINITIALIZED_LEXICAL,
383 /** arguments object can't be created because environment is dead. */
384 JS_MISSING_ARGUMENTS,
386 /** for local use */
387 JS_GENERIC_MAGIC,
390 * When an error object is created without the error cause argument, we set
391 * the error's cause slot to this magic value.
393 JS_ERROR_WITHOUT_CAUSE,
395 JS_WHY_MAGIC_COUNT
398 namespace js {
399 static inline JS::Value PoisonedObjectValue(uintptr_t poison);
400 #ifdef ENABLE_RECORD_TUPLE
401 // Re-defined in vm/RecordTupleBoxShared.h. We cannot include that
402 // file because it circularly includes this one.
403 bool IsExtendedPrimitive(const JSObject& obj);
404 namespace gc {
405 bool MaybeForwardedIsExtendedPrimitive(const JSObject& obj);
406 } // namespace gc
407 #endif
408 } // namespace js
410 namespace JS {
412 namespace detail {
414 // IEEE-754 bit pattern for double-precision positive infinity.
415 constexpr int InfinitySignBit = 0;
416 constexpr uint64_t InfinityBits =
417 mozilla::InfinityBits<double, detail::InfinitySignBit>::value;
419 // This is a quiet NaN on IEEE-754[2008] compatible platforms, including X86,
420 // ARM, SPARC, RISC-V and modern MIPS.
422 // Note: The default sign bit for a hardware synthesized NaN differs between X86
423 // and ARM. Both values are considered compatible values on both
424 // platforms.
425 constexpr int CanonicalizedNaNSignBit = 0;
426 constexpr uint64_t CanonicalizedNaNSignificand = 0x8000000000000;
428 #if defined(__sparc__)
429 // Some architectures (not to name names) generate NaNs with bit patterns that
430 // are incompatible with JS::Value's bit pattern restrictions. Instead we must
431 // canonicalize all hardware values before storing in JS::Value.
432 # define JS_NONCANONICAL_HARDWARE_NAN
433 #endif
435 #if defined(__mips__) && !defined(__mips_nan_2008)
436 // These builds may run on hardware that has differing polarity of the signaling
437 // NaN bit. While the kernel may handle the trap for us, it is a performance
438 // issue so instead we compute the NaN to use on startup. The runtime value must
439 // still meet `ValueIsDouble` requirements which are checked on startup.
441 // In particular, we expect one of the following values on MIPS:
442 // - 0x7FF7FFFFFFFFFFFF Legacy
443 // - 0x7FF8000000000000 IEEE-754[2008]
444 # define JS_RUNTIME_CANONICAL_NAN
445 #endif
447 #if defined(JS_RUNTIME_CANONICAL_NAN)
448 extern uint64_t CanonicalizedNaNBits;
449 #else
450 constexpr uint64_t CanonicalizedNaNBits =
451 mozilla::SpecificNaNBits<double, detail::CanonicalizedNaNSignBit,
452 detail::CanonicalizedNaNSignificand>::value;
453 #endif
454 } // namespace detail
456 // Return a quiet NaN that is compatible with JS::Value restrictions.
457 static MOZ_ALWAYS_INLINE double GenericNaN() {
458 #if !defined(JS_RUNTIME_CANONICAL_NAN)
459 static_assert(detail::ValueIsDouble(detail::CanonicalizedNaNBits),
460 "Canonical NaN must be compatible with JS::Value");
461 #endif
463 return mozilla::BitwiseCast<double>(detail::CanonicalizedNaNBits);
466 // Return the infinity the engine uses
467 static MOZ_ALWAYS_INLINE double Infinity() {
468 return mozilla::BitwiseCast<double>(detail::InfinityBits);
471 // Convert an arbitrary double to one compatible with JS::Value representation
472 // by replacing any NaN value with a canonical one.
473 static MOZ_ALWAYS_INLINE double CanonicalizeNaN(double d) {
474 if (MOZ_UNLIKELY(std::isnan(d))) {
475 return GenericNaN();
477 return d;
481 * [SMDOC] JS::Value type
483 * JS::Value is the interface for a single JavaScript Engine value. A few
484 * general notes on JS::Value:
486 * - JS::Value has setX() and isX() members for X in
488 * { Int32, Double, String, Symbol, BigInt, Boolean, Undefined, Null,
489 * Object, Magic }
491 * JS::Value also contains toX() for each of the non-singleton types.
493 * - Magic is a singleton type whose payload contains either a JSWhyMagic
494 * "reason" for the magic value or a uint32_t value. By providing JSWhyMagic
495 * values when creating and checking for magic values, it is possible to
496 * assert, at runtime, that only magic values with the expected reason flow
497 * through a particular value. For example, if cx->exception has a magic
498 * value, the reason must be JS_GENERATOR_CLOSING.
500 * - The JS::Value operations are preferred. The JSVAL_* operations remain for
501 * compatibility; they may be removed at some point. These operations mostly
502 * provide similar functionality. But there are a few key differences. One
503 * is that JS::Value gives null a separate type.
504 * Also, to help prevent mistakenly boxing a nullable JSObject* as an object,
505 * Value::setObject takes a JSObject&. (Conversely, Value::toObject returns a
506 * JSObject&.) A convenience member Value::setObjectOrNull is provided.
508 * - Note that JS::Value is 8 bytes on 32 and 64-bit architectures. Thus, on
509 * 32-bit user code should avoid copying jsval/JS::Value as much as possible,
510 * preferring to pass by const Value&.
512 * Spectre mitigations
513 * ===================
514 * To mitigate Spectre attacks, we do the following:
516 * - On 64-bit platforms, when unboxing a Value, we XOR the bits with the
517 * expected type tag (instead of masking the payload bits). This guarantees
518 * that toString, toObject, toSymbol will return an invalid pointer (because
519 * some high bits will be set) when called on a Value with a different type
520 * tag.
522 * - On 32-bit platforms,when unboxing an object/string/symbol Value, we use a
523 * conditional move (not speculated) to zero the payload register if the type
524 * doesn't match.
526 class alignas(8) Value {
527 private:
528 uint64_t asBits_;
530 public:
531 constexpr Value() : asBits_(bitsFromTagAndPayload(JSVAL_TAG_UNDEFINED, 0)) {}
533 private:
534 explicit constexpr Value(uint64_t asBits) : asBits_(asBits) {}
536 static uint64_t bitsFromDouble(double d) {
537 #if defined(JS_NONCANONICAL_HARDWARE_NAN)
538 d = CanonicalizeNaN(d);
539 #endif
540 return mozilla::BitwiseCast<uint64_t>(d);
543 static_assert(sizeof(JSValueType) == 1,
544 "type bits must fit in a single byte");
545 static_assert(sizeof(JSValueTag) == 4,
546 "32-bit Value's tag_ must have size 4 to complement the "
547 "payload union's size 4");
548 static_assert(sizeof(JSWhyMagic) <= 4,
549 "32-bit Value's JSWhyMagic payload field must not inflate "
550 "the payload beyond 4 bytes");
552 public:
553 #if defined(JS_NUNBOX32)
554 using PayloadType = uint32_t;
555 #elif defined(JS_PUNBOX64)
556 using PayloadType = uint64_t;
557 #endif
559 static constexpr uint64_t bitsFromTagAndPayload(JSValueTag tag,
560 PayloadType payload) {
561 return (uint64_t(tag) << JSVAL_TAG_SHIFT) | payload;
564 static constexpr Value fromTagAndPayload(JSValueTag tag,
565 PayloadType payload) {
566 return fromRawBits(bitsFromTagAndPayload(tag, payload));
569 static constexpr Value fromRawBits(uint64_t asBits) { return Value(asBits); }
571 static constexpr Value fromInt32(int32_t i) {
572 return fromTagAndPayload(JSVAL_TAG_INT32, uint32_t(i));
575 static Value fromDouble(double d) { return fromRawBits(bitsFromDouble(d)); }
578 * Returns false if creating a NumberValue containing the given type would
579 * be lossy, true otherwise.
581 template <typename T>
582 static bool isNumberRepresentable(const T t) {
583 return T(double(t)) == t;
586 /*** Mutators ***/
588 void setNull() {
589 asBits_ = bitsFromTagAndPayload(JSVAL_TAG_NULL, 0);
590 MOZ_ASSERT(isNull());
593 void setUndefined() {
594 asBits_ = bitsFromTagAndPayload(JSVAL_TAG_UNDEFINED, 0);
595 MOZ_ASSERT(isUndefined());
598 void setInt32(int32_t i) {
599 asBits_ = bitsFromTagAndPayload(JSVAL_TAG_INT32, uint32_t(i));
600 MOZ_ASSERT(toInt32() == i);
603 void setDouble(double d) {
604 asBits_ = bitsFromDouble(d);
605 MOZ_ASSERT(isDouble());
608 void setString(JSString* str) {
609 MOZ_ASSERT(js::gc::IsCellPointerValid(str));
610 asBits_ = bitsFromTagAndPayload(JSVAL_TAG_STRING, PayloadType(str));
611 MOZ_ASSERT(toString() == str);
614 void setSymbol(JS::Symbol* sym) {
615 MOZ_ASSERT(js::gc::IsCellPointerValid(sym));
616 asBits_ = bitsFromTagAndPayload(JSVAL_TAG_SYMBOL, PayloadType(sym));
617 MOZ_ASSERT(toSymbol() == sym);
620 void setBigInt(JS::BigInt* bi) {
621 MOZ_ASSERT(js::gc::IsCellPointerValid(bi));
622 asBits_ = bitsFromTagAndPayload(JSVAL_TAG_BIGINT, PayloadType(bi));
623 MOZ_ASSERT(toBigInt() == bi);
626 void setObject(JSObject& obj) {
627 MOZ_ASSERT(js::gc::IsCellPointerValid(&obj));
628 #ifdef ENABLE_RECORD_TUPLE
629 MOZ_ASSERT(!js::gc::MaybeForwardedIsExtendedPrimitive(obj));
630 #endif
631 setObjectNoCheck(&obj);
632 MOZ_ASSERT(&toObject() == &obj);
635 #ifdef ENABLE_RECORD_TUPLE
636 void setExtendedPrimitive(JSObject& obj) {
637 MOZ_ASSERT(js::gc::IsCellPointerValid(&obj));
638 MOZ_ASSERT(js::gc::MaybeForwardedIsExtendedPrimitive(obj));
639 asBits_ =
640 bitsFromTagAndPayload(JSVAL_TAG_EXTENDED_PRIMITIVE, PayloadType(&obj));
641 MOZ_ASSERT(&toExtendedPrimitive() == &obj);
643 #endif
645 private:
646 void setObjectNoCheck(JSObject* obj) {
647 asBits_ = bitsFromTagAndPayload(JSVAL_TAG_OBJECT, PayloadType(obj));
650 friend inline Value js::PoisonedObjectValue(uintptr_t poison);
652 public:
653 void setBoolean(bool b) {
654 asBits_ = bitsFromTagAndPayload(JSVAL_TAG_BOOLEAN, uint32_t(b));
655 MOZ_ASSERT(toBoolean() == b);
658 void setMagic(JSWhyMagic why) {
659 asBits_ = bitsFromTagAndPayload(JSVAL_TAG_MAGIC, uint32_t(why));
660 MOZ_ASSERT(whyMagic() == why);
663 void setMagicUint32(uint32_t payload) {
664 MOZ_ASSERT(payload >= JS_WHY_MAGIC_COUNT,
665 "This should only be used for non-standard magic values");
666 asBits_ = bitsFromTagAndPayload(JSVAL_TAG_MAGIC, payload);
667 MOZ_ASSERT(magicUint32() == payload);
670 void setNumber(float f) {
671 int32_t i;
672 if (mozilla::NumberIsInt32(f, &i)) {
673 setInt32(i);
674 return;
677 setDouble(double(f));
680 void setNumber(double d) {
681 int32_t i;
682 if (mozilla::NumberIsInt32(d, &i)) {
683 setInt32(i);
684 return;
687 setDouble(d);
690 template <typename T>
691 void setNumber(const T t) {
692 static_assert(std::is_integral<T>::value, "must be integral type");
693 MOZ_ASSERT(isNumberRepresentable(t), "value creation would be lossy");
695 if constexpr (std::numeric_limits<T>::is_signed) {
696 if constexpr (sizeof(t) <= sizeof(int32_t)) {
697 setInt32(int32_t(t));
698 } else {
699 if (JSVAL_INT_MIN <= t && t <= JSVAL_INT_MAX) {
700 setInt32(int32_t(t));
701 } else {
702 setDouble(double(t));
705 } else {
706 if constexpr (sizeof(t) <= sizeof(uint16_t)) {
707 setInt32(int32_t(t));
708 } else {
709 if (t <= JSVAL_INT_MAX) {
710 setInt32(int32_t(t));
711 } else {
712 setDouble(double(t));
718 void setObjectOrNull(JSObject* arg) {
719 if (arg) {
720 setObject(*arg);
721 } else {
722 setNull();
726 void swap(Value& rhs) {
727 uint64_t tmp = rhs.asBits_;
728 rhs.asBits_ = asBits_;
729 asBits_ = tmp;
732 private:
733 JSValueTag toTag() const { return JSValueTag(asBits_ >> JSVAL_TAG_SHIFT); }
735 template <typename T, JSValueTag Tag>
736 T* unboxGCPointer() const {
737 MOZ_ASSERT((asBits_ & js::gc::CellAlignMask) == 0,
738 "GC pointer is not aligned. Is this memory corruption?");
739 #if defined(JS_NUNBOX32)
740 uintptr_t payload = uint32_t(asBits_);
741 return reinterpret_cast<T*>(payload);
742 #elif defined(JS_PUNBOX64)
743 // Note: the 'Spectre mitigations' comment at the top of this class
744 // explains why we use XOR here.
745 constexpr uint64_t shiftedTag = uint64_t(Tag) << JSVAL_TAG_SHIFT;
746 return reinterpret_cast<T*>(uintptr_t(asBits_ ^ shiftedTag));
747 #endif
750 public:
751 /*** JIT-only interfaces to interact with and create raw Values ***/
752 #if defined(JS_NUNBOX32)
753 PayloadType toNunboxPayload() const { return uint32_t(asBits_); }
755 JSValueTag toNunboxTag() const { return toTag(); }
756 #elif defined(JS_PUNBOX64)
757 const void* bitsAsPunboxPointer() const {
758 return reinterpret_cast<void*>(asBits_);
760 #endif
762 /*** Value type queries ***/
765 * N.B. GCC, in some but not all cases, chooses to emit signed comparison
766 * of JSValueTag even though its underlying type has been forced to be
767 * uint32_t. Thus, all comparisons should explicitly cast operands to
768 * uint32_t.
771 bool isUndefined() const {
772 #if defined(JS_NUNBOX32)
773 return toTag() == JSVAL_TAG_UNDEFINED;
774 #elif defined(JS_PUNBOX64)
775 return asBits_ == JSVAL_SHIFTED_TAG_UNDEFINED;
776 #endif
779 bool isNull() const {
780 #if defined(JS_NUNBOX32)
781 return toTag() == JSVAL_TAG_NULL;
782 #elif defined(JS_PUNBOX64)
783 return asBits_ == JSVAL_SHIFTED_TAG_NULL;
784 #endif
787 bool isNullOrUndefined() const { return isNull() || isUndefined(); }
789 bool isInt32() const { return toTag() == JSVAL_TAG_INT32; }
791 bool isInt32(int32_t i32) const {
792 return asBits_ == bitsFromTagAndPayload(JSVAL_TAG_INT32, uint32_t(i32));
795 bool isDouble() const { return detail::ValueIsDouble(asBits_); }
797 bool isNumber() const {
798 #if defined(JS_NUNBOX32)
799 MOZ_ASSERT(toTag() != JSVAL_TAG_CLEAR);
800 return uint32_t(toTag()) <= uint32_t(detail::ValueUpperInclNumberTag);
801 #elif defined(JS_PUNBOX64)
802 return asBits_ < detail::ValueUpperExclShiftedNumberTag;
803 #endif
806 bool isString() const { return toTag() == JSVAL_TAG_STRING; }
808 bool isSymbol() const { return toTag() == JSVAL_TAG_SYMBOL; }
810 bool isBigInt() const { return toTag() == JSVAL_TAG_BIGINT; }
812 bool isObject() const {
813 #if defined(JS_NUNBOX32)
814 return toTag() == JSVAL_TAG_OBJECT;
815 #elif defined(JS_PUNBOX64)
816 MOZ_ASSERT((asBits_ >> JSVAL_TAG_SHIFT) <= JSVAL_TAG_OBJECT);
817 return asBits_ >= JSVAL_SHIFTED_TAG_OBJECT;
818 #endif
821 #ifdef ENABLE_RECORD_TUPLE
822 bool isExtendedPrimitive() const {
823 return toTag() == JSVAL_TAG_EXTENDED_PRIMITIVE;
825 #endif
827 bool hasObjectPayload() const {
828 return isObject() || IF_RECORD_TUPLE(isExtendedPrimitive(), false);
831 bool isPrimitive() const {
832 #if defined(JS_NUNBOX32)
833 return uint32_t(toTag()) < uint32_t(detail::ValueUpperExclPrimitiveTag);
834 #elif defined(JS_PUNBOX64)
835 return asBits_ < detail::ValueUpperExclShiftedPrimitiveTag;
836 #endif
839 bool isObjectOrNull() const { return isObject() || isNull(); }
841 bool isNumeric() const { return isNumber() || isBigInt(); }
843 bool isGCThing() const {
844 #if defined(JS_NUNBOX32)
845 /* gcc sometimes generates signed < without explicit casts. */
846 return uint32_t(toTag()) >= uint32_t(detail::ValueLowerInclGCThingTag);
847 #elif defined(JS_PUNBOX64)
848 return asBits_ >= detail::ValueLowerInclShiftedGCThingTag;
849 #endif
852 bool isBoolean() const { return toTag() == JSVAL_TAG_BOOLEAN; }
854 bool isTrue() const {
855 return asBits_ == bitsFromTagAndPayload(JSVAL_TAG_BOOLEAN, uint32_t(true));
858 bool isFalse() const {
859 return asBits_ == bitsFromTagAndPayload(JSVAL_TAG_BOOLEAN, uint32_t(false));
862 bool isMagic() const { return toTag() == JSVAL_TAG_MAGIC; }
864 bool isMagic(JSWhyMagic why) const {
865 if (!isMagic()) {
866 return false;
868 MOZ_RELEASE_ASSERT(whyMagic() == why);
869 return true;
872 // Like isMagic, but without the release assertion.
873 bool isMagicNoReleaseCheck(JSWhyMagic why) const {
874 if (!isMagic()) {
875 return false;
877 MOZ_ASSERT(whyMagic() == why);
878 return true;
881 JS::TraceKind traceKind() const {
882 MOZ_ASSERT(isGCThing());
883 static_assert((JSVAL_TAG_STRING & 0x03) == size_t(JS::TraceKind::String),
884 "Value type tags must correspond with JS::TraceKinds.");
885 static_assert((JSVAL_TAG_SYMBOL & 0x03) == size_t(JS::TraceKind::Symbol),
886 "Value type tags must correspond with JS::TraceKinds.");
887 static_assert((JSVAL_TAG_OBJECT & 0x03) == size_t(JS::TraceKind::Object),
888 "Value type tags must correspond with JS::TraceKinds.");
889 static_assert((JSVAL_TAG_BIGINT & 0x03) == size_t(JS::TraceKind::BigInt),
890 "Value type tags must correspond with JS::TraceKinds.");
891 if (MOZ_UNLIKELY(isPrivateGCThing())) {
892 return JS::GCThingTraceKind(toGCThing());
894 #ifdef ENABLE_RECORD_TUPLE
895 if (isExtendedPrimitive()) {
896 return JS::TraceKind::Object;
898 #endif
899 return JS::TraceKind(toTag() & 0x03);
902 JSWhyMagic whyMagic() const {
903 MOZ_ASSERT(magicUint32() < JS_WHY_MAGIC_COUNT);
904 return static_cast<JSWhyMagic>(magicUint32());
907 uint32_t magicUint32() const {
908 MOZ_ASSERT(isMagic());
909 return uint32_t(asBits_);
912 /*** Comparison ***/
914 bool operator==(const Value& rhs) const { return asBits_ == rhs.asBits_; }
916 bool operator!=(const Value& rhs) const { return asBits_ != rhs.asBits_; }
918 friend inline bool SameType(const Value& lhs, const Value& rhs);
920 /*** Extract the value's typed payload ***/
922 int32_t toInt32() const {
923 MOZ_ASSERT(isInt32());
924 return int32_t(asBits_);
927 double toDouble() const {
928 MOZ_ASSERT(isDouble());
929 return mozilla::BitwiseCast<double>(asBits_);
932 double toNumber() const {
933 MOZ_ASSERT(isNumber());
934 return isDouble() ? toDouble() : double(toInt32());
937 JSString* toString() const {
938 MOZ_ASSERT(isString());
939 return unboxGCPointer<JSString, JSVAL_TAG_STRING>();
942 JS::Symbol* toSymbol() const {
943 MOZ_ASSERT(isSymbol());
944 return unboxGCPointer<JS::Symbol, JSVAL_TAG_SYMBOL>();
947 JS::BigInt* toBigInt() const {
948 MOZ_ASSERT(isBigInt());
949 return unboxGCPointer<JS::BigInt, JSVAL_TAG_BIGINT>();
952 JSObject& toObject() const {
953 MOZ_ASSERT(isObject());
954 #if defined(JS_PUNBOX64)
955 MOZ_ASSERT((asBits_ & detail::ValueGCThingPayloadMask) != 0);
956 #endif
957 return *unboxGCPointer<JSObject, JSVAL_TAG_OBJECT>();
960 JSObject* toObjectOrNull() const {
961 MOZ_ASSERT(isObjectOrNull());
962 #if defined(JS_NUNBOX32)
963 return reinterpret_cast<JSObject*>(uintptr_t(asBits_));
964 #elif defined(JS_PUNBOX64)
965 // Note: the 'Spectre mitigations' comment at the top of this class
966 // explains why we use XOR here and in other to* methods.
967 uint64_t ptrBits =
968 (asBits_ ^ JSVAL_SHIFTED_TAG_OBJECT) & ~detail::ValueObjectOrNullBit;
969 MOZ_ASSERT((ptrBits & 0x7) == 0);
970 return reinterpret_cast<JSObject*>(ptrBits);
971 #endif
974 #ifdef ENABLE_RECORD_TUPLE
975 JSObject& toExtendedPrimitive() const {
976 MOZ_ASSERT(isExtendedPrimitive());
977 # if defined(JS_PUNBOX64)
978 MOZ_ASSERT((asBits_ & detail::ValueGCThingPayloadMask) != 0);
979 # endif
980 return *unboxGCPointer<JSObject, JSVAL_TAG_EXTENDED_PRIMITIVE>();
982 #endif
984 JSObject& getObjectPayload() const {
985 #ifdef ENABLE_RECORD_TUPLE
986 return isExtendedPrimitive() ? toExtendedPrimitive() : toObject();
987 #else
988 return toObject();
989 #endif
992 js::gc::Cell* toGCThing() const {
993 MOZ_ASSERT(isGCThing());
994 #if defined(JS_NUNBOX32)
995 return reinterpret_cast<js::gc::Cell*>(uintptr_t(asBits_));
996 #elif defined(JS_PUNBOX64)
997 uint64_t ptrBits = asBits_ & detail::ValueGCThingPayloadMask;
998 MOZ_ASSERT((ptrBits & 0x7) == 0);
999 return reinterpret_cast<js::gc::Cell*>(ptrBits);
1000 #endif
1003 GCCellPtr toGCCellPtr() const { return GCCellPtr(toGCThing(), traceKind()); }
1005 bool toBoolean() const {
1006 MOZ_ASSERT(isBoolean());
1007 #if defined(JS_NUNBOX32)
1008 return bool(toNunboxPayload());
1009 #elif defined(JS_PUNBOX64)
1010 return bool(asBits_ & 0x1);
1011 #endif
1014 constexpr uint64_t asRawBits() const { return asBits_; }
1016 JSValueType extractNonDoubleType() const {
1017 uint32_t type = toTag() & 0xF;
1018 MOZ_ASSERT(type > JSVAL_TYPE_DOUBLE);
1019 return JSValueType(type);
1022 JS::ValueType type() const {
1023 if (isDouble()) {
1024 return JS::ValueType::Double;
1027 JSValueType type = extractNonDoubleType();
1028 MOZ_ASSERT(type <= JSVAL_TYPE_OBJECT);
1029 return JS::ValueType(type);
1033 * Private API
1035 * Private setters/getters allow the caller to read/write arbitrary
1036 * word-size pointers or uint32s. After storing to a value with
1037 * setPrivateX, it is the caller's responsibility to only read using
1038 * toPrivateX. Private values are given a type which ensures they
1039 * aren't marked by the GC.
1042 void setPrivate(void* ptr) {
1043 #if defined(JS_PUNBOX64)
1044 MOZ_ASSERT(detail::IsValidUserModePointer(uintptr_t(ptr)));
1045 #endif
1046 asBits_ = uintptr_t(ptr);
1047 MOZ_ASSERT(isDouble());
1050 void* toPrivate() const {
1051 MOZ_ASSERT(isDouble());
1052 #if defined(JS_PUNBOX64)
1053 MOZ_ASSERT(detail::IsValidUserModePointer(asBits_));
1054 #endif
1055 return reinterpret_cast<void*>(uintptr_t(asBits_));
1058 void setPrivateUint32(uint32_t ui) {
1059 MOZ_ASSERT(uint32_t(int32_t(ui)) == ui);
1060 setInt32(int32_t(ui));
1063 uint32_t toPrivateUint32() const { return uint32_t(toInt32()); }
1066 * Private GC Thing API
1068 * Non-JSObject, JSString, and JS::Symbol cells may be put into the 64-bit
1069 * payload as private GC things. Such Values are considered isGCThing(), and
1070 * as such, automatically marked. Their traceKind() is gotten via their
1071 * cells.
1074 void setPrivateGCThing(js::gc::Cell* cell) {
1075 MOZ_ASSERT(JS::GCThingTraceKind(cell) != JS::TraceKind::String,
1076 "Private GC thing Values must not be strings. Make a "
1077 "StringValue instead.");
1078 MOZ_ASSERT(JS::GCThingTraceKind(cell) != JS::TraceKind::Symbol,
1079 "Private GC thing Values must not be symbols. Make a "
1080 "SymbolValue instead.");
1081 MOZ_ASSERT(JS::GCThingTraceKind(cell) != JS::TraceKind::BigInt,
1082 "Private GC thing Values must not be BigInts. Make a "
1083 "BigIntValue instead.");
1084 MOZ_ASSERT(JS::GCThingTraceKind(cell) != JS::TraceKind::Object,
1085 "Private GC thing Values must not be objects. Make an "
1086 "ObjectValue instead.");
1088 MOZ_ASSERT(js::gc::IsCellPointerValid(cell));
1089 #if defined(JS_PUNBOX64)
1090 // VisualStudio cannot contain parenthesized C++ style cast and shift
1091 // inside decltype in template parameter:
1092 // AssertionConditionType<decltype((uintptr_t(x) >> 1))>
1093 // It throws syntax error.
1094 MOZ_ASSERT((((uintptr_t)cell) >> JSVAL_TAG_SHIFT) == 0);
1095 #endif
1096 asBits_ =
1097 bitsFromTagAndPayload(JSVAL_TAG_PRIVATE_GCTHING, PayloadType(cell));
1100 bool isPrivateGCThing() const { return toTag() == JSVAL_TAG_PRIVATE_GCTHING; }
1101 } JS_HAZ_GC_POINTER MOZ_NON_PARAM;
1103 static_assert(sizeof(Value) == 8,
1104 "Value size must leave three tag bits, be a binary power, and "
1105 "is ubiquitously depended upon everywhere");
1107 static MOZ_ALWAYS_INLINE void ExposeValueToActiveJS(const Value& v) {
1108 #ifdef DEBUG
1109 Value tmp = v;
1110 MOZ_ASSERT(!js::gc::EdgeNeedsSweepUnbarrieredSlow(&tmp));
1111 #endif
1112 if (v.isGCThing()) {
1113 js::gc::ExposeGCThingToActiveJS(v.toGCCellPtr());
1117 /************************************************************************/
1119 static inline MOZ_MAY_CALL_AFTER_MUST_RETURN Value NullValue() {
1120 Value v;
1121 v.setNull();
1122 return v;
1125 static constexpr Value UndefinedValue() { return Value(); }
1127 static constexpr Value Int32Value(int32_t i32) { return Value::fromInt32(i32); }
1129 static inline Value DoubleValue(double dbl) {
1130 Value v;
1131 v.setDouble(dbl);
1132 return v;
1135 static inline Value CanonicalizedDoubleValue(double d) {
1136 return Value::fromDouble(CanonicalizeNaN(d));
1139 static inline Value NaNValue() {
1140 return Value::fromRawBits(detail::CanonicalizedNaNBits);
1143 static inline Value InfinityValue() {
1144 return Value::fromRawBits(detail::InfinityBits);
1147 static inline Value Float32Value(float f) {
1148 Value v;
1149 v.setDouble(f);
1150 return v;
1153 static inline Value StringValue(JSString* str) {
1154 Value v;
1155 v.setString(str);
1156 return v;
1159 static inline Value SymbolValue(JS::Symbol* sym) {
1160 Value v;
1161 v.setSymbol(sym);
1162 return v;
1165 static inline Value BigIntValue(JS::BigInt* bi) {
1166 Value v;
1167 v.setBigInt(bi);
1168 return v;
1171 static inline Value BooleanValue(bool boo) {
1172 Value v;
1173 v.setBoolean(boo);
1174 return v;
1177 static inline Value TrueValue() {
1178 Value v;
1179 v.setBoolean(true);
1180 return v;
1183 static inline Value FalseValue() {
1184 Value v;
1185 v.setBoolean(false);
1186 return v;
1189 static inline Value ObjectValue(JSObject& obj) {
1190 Value v;
1191 v.setObject(obj);
1192 return v;
1195 #ifdef ENABLE_RECORD_TUPLE
1196 static inline Value ExtendedPrimitiveValue(JSObject& obj) {
1197 Value v;
1198 v.setExtendedPrimitive(obj);
1199 return v;
1201 #endif
1203 static inline Value MagicValue(JSWhyMagic why) {
1204 Value v;
1205 v.setMagic(why);
1206 return v;
1209 static inline Value MagicValueUint32(uint32_t payload) {
1210 Value v;
1211 v.setMagicUint32(payload);
1212 return v;
1215 static constexpr Value NumberValue(uint32_t i) {
1216 return i <= JSVAL_INT_MAX ? Int32Value(int32_t(i))
1217 : Value::fromDouble(double(i));
1220 template <typename T>
1221 static inline Value NumberValue(const T t) {
1222 Value v;
1223 v.setNumber(t);
1224 return v;
1227 static inline Value ObjectOrNullValue(JSObject* obj) {
1228 Value v;
1229 v.setObjectOrNull(obj);
1230 return v;
1233 static inline Value PrivateValue(void* ptr) {
1234 Value v;
1235 v.setPrivate(ptr);
1236 return v;
1239 static inline Value PrivateValue(uintptr_t ptr) {
1240 return PrivateValue(reinterpret_cast<void*>(ptr));
1243 static inline Value PrivateUint32Value(uint32_t ui) {
1244 Value v;
1245 v.setPrivateUint32(ui);
1246 return v;
1249 static inline Value PrivateGCThingValue(js::gc::Cell* cell) {
1250 Value v;
1251 v.setPrivateGCThing(cell);
1252 return v;
1255 inline bool SameType(const Value& lhs, const Value& rhs) {
1256 #if defined(JS_NUNBOX32)
1257 JSValueTag ltag = lhs.toTag(), rtag = rhs.toTag();
1258 return ltag == rtag || (ltag < JSVAL_TAG_CLEAR && rtag < JSVAL_TAG_CLEAR);
1259 #elif defined(JS_PUNBOX64)
1260 return (lhs.isDouble() && rhs.isDouble()) ||
1261 (((lhs.asBits_ ^ rhs.asBits_) & 0xFFFF800000000000ULL) == 0);
1262 #endif
1265 } // namespace JS
1267 /************************************************************************/
1269 namespace JS {
1270 JS_PUBLIC_API void HeapValuePostWriteBarrier(Value* valuep, const Value& prev,
1271 const Value& next);
1272 JS_PUBLIC_API void HeapValueWriteBarriers(Value* valuep, const Value& prev,
1273 const Value& next);
1275 template <>
1276 struct GCPolicy<JS::Value> {
1277 static void trace(JSTracer* trc, Value* v, const char* name) {
1278 // This should only be called as part of root marking since that's the only
1279 // time we should trace unbarriered GC thing pointers. This will assert if
1280 // called at other times.
1281 TraceRoot(trc, v, name);
1283 static bool isTenured(const Value& thing) {
1284 return !thing.isGCThing() || !IsInsideNursery(thing.toGCThing());
1286 static bool isValid(const Value& value) {
1287 return !value.isGCThing() || js::gc::IsCellPointerValid(value.toGCThing());
1291 } // namespace JS
1293 namespace js {
1295 template <>
1296 struct BarrierMethods<JS::Value> {
1297 static gc::Cell* asGCThingOrNull(const JS::Value& v) {
1298 return v.isGCThing() ? v.toGCThing() : nullptr;
1300 static void postWriteBarrier(JS::Value* v, const JS::Value& prev,
1301 const JS::Value& next) {
1302 JS::HeapValuePostWriteBarrier(v, prev, next);
1304 static void exposeToJS(const JS::Value& v) { JS::ExposeValueToActiveJS(v); }
1305 static void readBarrier(const JS::Value& v) {
1306 if (v.isGCThing()) {
1307 js::gc::IncrementalReadBarrier(v.toGCCellPtr());
1312 template <class Wrapper>
1313 class MutableValueOperations;
1316 * A class designed for CRTP use in implementing the non-mutating parts of the
1317 * Value interface in Value-like classes. Wrapper must be a class inheriting
1318 * ValueOperations<Wrapper> with a visible get() method returning a const
1319 * reference to the Value abstracted by Wrapper.
1321 template <class Wrapper>
1322 class WrappedPtrOperations<JS::Value, Wrapper> {
1323 const JS::Value& value() const {
1324 return static_cast<const Wrapper*>(this)->get();
1327 public:
1328 bool isUndefined() const { return value().isUndefined(); }
1329 bool isNull() const { return value().isNull(); }
1330 bool isBoolean() const { return value().isBoolean(); }
1331 bool isTrue() const { return value().isTrue(); }
1332 bool isFalse() const { return value().isFalse(); }
1333 bool isNumber() const { return value().isNumber(); }
1334 bool isInt32() const { return value().isInt32(); }
1335 bool isInt32(int32_t i32) const { return value().isInt32(i32); }
1336 bool isDouble() const { return value().isDouble(); }
1337 bool isString() const { return value().isString(); }
1338 bool isSymbol() const { return value().isSymbol(); }
1339 bool isBigInt() const { return value().isBigInt(); }
1340 bool isObject() const { return value().isObject(); }
1341 #ifdef ENABLE_RECORD_TUPLE
1342 bool isExtendedPrimitive() const { return value().isExtendedPrimitive(); }
1343 #endif
1344 bool hasObjectPayload() const { return value().hasObjectPayload(); }
1345 bool isMagic() const { return value().isMagic(); }
1346 bool isMagic(JSWhyMagic why) const { return value().isMagic(why); }
1347 bool isGCThing() const { return value().isGCThing(); }
1348 bool isPrivateGCThing() const { return value().isPrivateGCThing(); }
1349 bool isPrimitive() const { return value().isPrimitive(); }
1351 bool isNullOrUndefined() const { return value().isNullOrUndefined(); }
1352 bool isObjectOrNull() const { return value().isObjectOrNull(); }
1353 bool isNumeric() const { return value().isNumeric(); }
1355 bool toBoolean() const { return value().toBoolean(); }
1356 double toNumber() const { return value().toNumber(); }
1357 int32_t toInt32() const { return value().toInt32(); }
1358 double toDouble() const { return value().toDouble(); }
1359 JSString* toString() const { return value().toString(); }
1360 JS::Symbol* toSymbol() const { return value().toSymbol(); }
1361 JS::BigInt* toBigInt() const { return value().toBigInt(); }
1362 JSObject& toObject() const { return value().toObject(); }
1363 JSObject* toObjectOrNull() const { return value().toObjectOrNull(); }
1364 #ifdef ENABLE_RECORD_TUPLE
1365 JSObject& toExtendedPrimitive() const {
1366 return value().toExtendedPrimitive();
1368 #endif
1369 JSObject& getObjectPayload() const { return value().getObjectPayload(); }
1370 JS::GCCellPtr toGCCellPtr() const { return value().toGCCellPtr(); }
1371 gc::Cell* toGCThing() const { return value().toGCThing(); }
1372 JS::TraceKind traceKind() const { return value().traceKind(); }
1373 void* toPrivate() const { return value().toPrivate(); }
1374 uint32_t toPrivateUint32() const { return value().toPrivateUint32(); }
1376 uint64_t asRawBits() const { return value().asRawBits(); }
1377 JSValueType extractNonDoubleType() const {
1378 return value().extractNonDoubleType();
1380 JS::ValueType type() const { return value().type(); }
1382 JSWhyMagic whyMagic() const { return value().whyMagic(); }
1383 uint32_t magicUint32() const { return value().magicUint32(); }
1387 * A class designed for CRTP use in implementing all the mutating parts of the
1388 * Value interface in Value-like classes. Wrapper must be a class inheriting
1389 * MutableWrappedPtrOperations<Wrapper> with visible get() methods returning
1390 * const and non-const references to the Value abstracted by Wrapper.
1392 template <class Wrapper>
1393 class MutableWrappedPtrOperations<JS::Value, Wrapper>
1394 : public WrappedPtrOperations<JS::Value, Wrapper> {
1395 protected:
1396 void set(const JS::Value& v) {
1397 // Call Wrapper::set to trigger any barriers.
1398 static_cast<Wrapper*>(this)->set(v);
1401 public:
1402 void setNull() { set(JS::NullValue()); }
1403 void setUndefined() { set(JS::UndefinedValue()); }
1404 void setInt32(int32_t i) { set(JS::Int32Value(i)); }
1405 void setDouble(double d) { set(JS::DoubleValue(d)); }
1406 void setNaN() { set(JS::NaNValue()); }
1407 void setInfinity() { set(JS::InfinityValue()); }
1408 void setBoolean(bool b) { set(JS::BooleanValue(b)); }
1409 void setMagic(JSWhyMagic why) { set(JS::MagicValue(why)); }
1410 template <typename T>
1411 void setNumber(T t) {
1412 set(JS::NumberValue(t));
1414 void setString(JSString* str) { set(JS::StringValue(str)); }
1415 void setSymbol(JS::Symbol* sym) { set(JS::SymbolValue(sym)); }
1416 void setBigInt(JS::BigInt* bi) { set(JS::BigIntValue(bi)); }
1417 void setObject(JSObject& obj) { set(JS::ObjectValue(obj)); }
1418 void setObjectOrNull(JSObject* arg) { set(JS::ObjectOrNullValue(arg)); }
1419 #ifdef ENABLE_RECORD_TUPLE
1420 void setExtendedPrimitive(JSObject& obj) {
1421 return set(JS::ExtendedPrimitiveValue(obj));
1423 #endif
1424 void setPrivate(void* ptr) { set(JS::PrivateValue(ptr)); }
1425 void setPrivateUint32(uint32_t ui) { set(JS::PrivateUint32Value(ui)); }
1426 void setPrivateGCThing(js::gc::Cell* cell) {
1427 set(JS::PrivateGCThingValue(cell));
1432 * Augment the generic Heap<T> interface when T = Value with
1433 * type-querying, value-extracting, and mutating operations.
1435 template <typename Wrapper>
1436 class HeapOperations<JS::Value, Wrapper>
1437 : public MutableWrappedPtrOperations<JS::Value, Wrapper> {};
1439 MOZ_HAVE_NORETURN MOZ_COLD MOZ_NEVER_INLINE void ReportBadValueTypeAndCrash(
1440 const JS::Value& val);
1442 // If the Value is a GC pointer type, call |f| with the pointer cast to that
1443 // type and return the result wrapped in a Maybe, otherwise return None().
1444 template <typename F>
1445 auto MapGCThingTyped(const JS::Value& val, F&& f) {
1446 switch (val.type()) {
1447 case JS::ValueType::String: {
1448 JSString* str = val.toString();
1449 MOZ_ASSERT(gc::IsCellPointerValid(str));
1450 return mozilla::Some(f(str));
1452 #ifdef ENABLE_RECORD_TUPLE
1453 case JS::ValueType::ExtendedPrimitive:
1454 #endif
1455 case JS::ValueType::Object: {
1456 JSObject* obj = &val.getObjectPayload();
1457 MOZ_ASSERT(gc::IsCellPointerValid(obj));
1458 return mozilla::Some(f(obj));
1460 case JS::ValueType::Symbol: {
1461 JS::Symbol* sym = val.toSymbol();
1462 MOZ_ASSERT(gc::IsCellPointerValid(sym));
1463 return mozilla::Some(f(sym));
1465 case JS::ValueType::BigInt: {
1466 JS::BigInt* bi = val.toBigInt();
1467 MOZ_ASSERT(gc::IsCellPointerValid(bi));
1468 return mozilla::Some(f(bi));
1470 case JS::ValueType::PrivateGCThing: {
1471 MOZ_ASSERT(gc::IsCellPointerValid(val.toGCThing()));
1472 return mozilla::Some(MapGCThingTyped(val.toGCCellPtr(), std::move(f)));
1474 case JS::ValueType::Double:
1475 case JS::ValueType::Int32:
1476 case JS::ValueType::Boolean:
1477 case JS::ValueType::Undefined:
1478 case JS::ValueType::Null:
1479 case JS::ValueType::Magic: {
1480 MOZ_ASSERT(!val.isGCThing());
1481 using ReturnType = decltype(f(static_cast<JSObject*>(nullptr)));
1482 return mozilla::Maybe<ReturnType>();
1486 ReportBadValueTypeAndCrash(val);
1489 // If the Value is a GC pointer type, call |f| with the pointer cast to that
1490 // type. Return whether this happened.
1491 template <typename F>
1492 bool ApplyGCThingTyped(const JS::Value& val, F&& f) {
1493 return MapGCThingTyped(val,
1494 [&f](auto t) {
1495 f(t);
1496 return true;
1498 .isSome();
1501 static inline JS::Value PoisonedObjectValue(uintptr_t poison) {
1502 JS::Value v;
1503 v.setObjectNoCheck(reinterpret_cast<JSObject*>(poison));
1504 return v;
1507 } // namespace js
1509 #ifdef DEBUG
1510 namespace JS {
1512 MOZ_ALWAYS_INLINE void AssertValueIsNotGray(const Value& value) {
1513 if (value.isGCThing()) {
1514 AssertCellIsNotGray(value.toGCThing());
1518 MOZ_ALWAYS_INLINE void AssertValueIsNotGray(const Heap<Value>& value) {
1519 AssertValueIsNotGray(value.unbarrieredGet());
1522 } // namespace JS
1523 #endif
1525 /************************************************************************/
1527 namespace JS {
1529 extern JS_PUBLIC_DATA const HandleValue NullHandleValue;
1530 extern JS_PUBLIC_DATA const HandleValue UndefinedHandleValue;
1531 extern JS_PUBLIC_DATA const HandleValue TrueHandleValue;
1532 extern JS_PUBLIC_DATA const HandleValue FalseHandleValue;
1533 extern JS_PUBLIC_DATA const Handle<mozilla::Maybe<Value>> NothingHandleValue;
1535 } // namespace JS
1537 #endif /* js_Value_h */