Line data Source code
1 : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2 : * vim: set ts=8 sts=4 et sw=4 tw=99:
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 :
17 : #include <limits> /* for std::numeric_limits */
18 :
19 : #include "js-config.h"
20 : #include "jstypes.h"
21 :
22 : #include "js/GCAPI.h"
23 : #include "js/RootingAPI.h"
24 : #include "js/Utility.h"
25 :
26 : namespace JS { class Value; }
27 :
28 : /* JS::Value can store a full int32_t. */
29 : #define JSVAL_INT_BITS 32
30 : #define JSVAL_INT_MIN ((int32_t)0x80000000)
31 : #define JSVAL_INT_MAX ((int32_t)0x7fffffff)
32 :
33 : #if defined(JS_PUNBOX64)
34 : # define JSVAL_TAG_SHIFT 47
35 : #endif
36 :
37 : // Use enums so that printing a JS::Value in the debugger shows nice
38 : // symbolic type tags.
39 :
40 : #if defined(_MSC_VER)
41 : # define JS_ENUM_HEADER(id, type) enum id : type
42 : # define JS_ENUM_FOOTER(id)
43 : #else
44 : # define JS_ENUM_HEADER(id, type) enum id
45 : # define JS_ENUM_FOOTER(id) __attribute__((packed))
46 : #endif
47 :
48 : JS_ENUM_HEADER(JSValueType, uint8_t)
49 : {
50 : JSVAL_TYPE_DOUBLE = 0x00,
51 : JSVAL_TYPE_INT32 = 0x01,
52 : JSVAL_TYPE_UNDEFINED = 0x02,
53 : JSVAL_TYPE_NULL = 0x03,
54 : JSVAL_TYPE_BOOLEAN = 0x04,
55 : JSVAL_TYPE_MAGIC = 0x05,
56 : JSVAL_TYPE_STRING = 0x06,
57 : JSVAL_TYPE_SYMBOL = 0x07,
58 : JSVAL_TYPE_PRIVATE_GCTHING = 0x08,
59 : JSVAL_TYPE_OBJECT = 0x0c,
60 :
61 : /* These never appear in a jsval; they are only provided as an out-of-band value. */
62 : JSVAL_TYPE_UNKNOWN = 0x20,
63 : JSVAL_TYPE_MISSING = 0x21
64 : } JS_ENUM_FOOTER(JSValueType);
65 :
66 : static_assert(sizeof(JSValueType) == 1,
67 : "compiler typed enum support is apparently buggy");
68 :
69 : #if defined(JS_NUNBOX32)
70 :
71 : JS_ENUM_HEADER(JSValueTag, uint32_t)
72 : {
73 : JSVAL_TAG_CLEAR = 0xFFFFFF80,
74 : JSVAL_TAG_INT32 = JSVAL_TAG_CLEAR | JSVAL_TYPE_INT32,
75 : JSVAL_TAG_UNDEFINED = JSVAL_TAG_CLEAR | JSVAL_TYPE_UNDEFINED,
76 : JSVAL_TAG_NULL = JSVAL_TAG_CLEAR | JSVAL_TYPE_NULL,
77 : JSVAL_TAG_BOOLEAN = JSVAL_TAG_CLEAR | JSVAL_TYPE_BOOLEAN,
78 : JSVAL_TAG_MAGIC = JSVAL_TAG_CLEAR | JSVAL_TYPE_MAGIC,
79 : JSVAL_TAG_STRING = JSVAL_TAG_CLEAR | JSVAL_TYPE_STRING,
80 : JSVAL_TAG_SYMBOL = JSVAL_TAG_CLEAR | JSVAL_TYPE_SYMBOL,
81 : JSVAL_TAG_PRIVATE_GCTHING = JSVAL_TAG_CLEAR | JSVAL_TYPE_PRIVATE_GCTHING,
82 : JSVAL_TAG_OBJECT = JSVAL_TAG_CLEAR | JSVAL_TYPE_OBJECT
83 : } JS_ENUM_FOOTER(JSValueTag);
84 :
85 : static_assert(sizeof(JSValueTag) == sizeof(uint32_t),
86 : "compiler typed enum support is apparently buggy");
87 :
88 : #elif defined(JS_PUNBOX64)
89 :
90 : JS_ENUM_HEADER(JSValueTag, uint32_t)
91 : {
92 : JSVAL_TAG_MAX_DOUBLE = 0x1FFF0,
93 : JSVAL_TAG_INT32 = JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_INT32,
94 : JSVAL_TAG_UNDEFINED = JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_UNDEFINED,
95 : JSVAL_TAG_NULL = JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_NULL,
96 : JSVAL_TAG_BOOLEAN = JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_BOOLEAN,
97 : JSVAL_TAG_MAGIC = JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_MAGIC,
98 : JSVAL_TAG_STRING = JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_STRING,
99 : JSVAL_TAG_SYMBOL = JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_SYMBOL,
100 : JSVAL_TAG_PRIVATE_GCTHING = JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_PRIVATE_GCTHING,
101 : JSVAL_TAG_OBJECT = JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_OBJECT
102 : } JS_ENUM_FOOTER(JSValueTag);
103 :
104 : static_assert(sizeof(JSValueTag) == sizeof(uint32_t),
105 : "compiler typed enum support is apparently buggy");
106 :
107 : JS_ENUM_HEADER(JSValueShiftedTag, uint64_t)
108 : {
109 : JSVAL_SHIFTED_TAG_MAX_DOUBLE = ((((uint64_t)JSVAL_TAG_MAX_DOUBLE) << JSVAL_TAG_SHIFT) | 0xFFFFFFFF),
110 : JSVAL_SHIFTED_TAG_INT32 = (((uint64_t)JSVAL_TAG_INT32) << JSVAL_TAG_SHIFT),
111 : JSVAL_SHIFTED_TAG_UNDEFINED = (((uint64_t)JSVAL_TAG_UNDEFINED) << JSVAL_TAG_SHIFT),
112 : JSVAL_SHIFTED_TAG_NULL = (((uint64_t)JSVAL_TAG_NULL) << JSVAL_TAG_SHIFT),
113 : JSVAL_SHIFTED_TAG_BOOLEAN = (((uint64_t)JSVAL_TAG_BOOLEAN) << JSVAL_TAG_SHIFT),
114 : JSVAL_SHIFTED_TAG_MAGIC = (((uint64_t)JSVAL_TAG_MAGIC) << JSVAL_TAG_SHIFT),
115 : JSVAL_SHIFTED_TAG_STRING = (((uint64_t)JSVAL_TAG_STRING) << JSVAL_TAG_SHIFT),
116 : JSVAL_SHIFTED_TAG_SYMBOL = (((uint64_t)JSVAL_TAG_SYMBOL) << JSVAL_TAG_SHIFT),
117 : JSVAL_SHIFTED_TAG_PRIVATE_GCTHING = (((uint64_t)JSVAL_TAG_PRIVATE_GCTHING) << JSVAL_TAG_SHIFT),
118 : JSVAL_SHIFTED_TAG_OBJECT = (((uint64_t)JSVAL_TAG_OBJECT) << JSVAL_TAG_SHIFT)
119 : } JS_ENUM_FOOTER(JSValueShiftedTag);
120 :
121 : static_assert(sizeof(JSValueShiftedTag) == sizeof(uint64_t),
122 : "compiler typed enum support is apparently buggy");
123 :
124 : #endif
125 :
126 : /*
127 : * All our supported compilers implement C++11 |enum Foo : T| syntax, so don't
128 : * expose these macros. (This macro exists *only* because gcc bug 51242
129 : * <https://gcc.gnu.org/bugzilla/show_bug.cgi?id=51242> makes bit-fields of
130 : * typed enums trigger a warning that can't be turned off. Don't expose it
131 : * beyond this file!)
132 : */
133 : #undef JS_ENUM_HEADER
134 : #undef JS_ENUM_FOOTER
135 :
136 : #if defined(JS_NUNBOX32)
137 :
138 : #define JSVAL_TYPE_TO_TAG(type) ((JSValueTag)(JSVAL_TAG_CLEAR | (type)))
139 :
140 : #define JSVAL_UPPER_EXCL_TAG_OF_PRIMITIVE_SET JSVAL_TAG_OBJECT
141 : #define JSVAL_UPPER_INCL_TAG_OF_NUMBER_SET JSVAL_TAG_INT32
142 : #define JSVAL_LOWER_INCL_TAG_OF_GCTHING_SET JSVAL_TAG_STRING
143 :
144 : #elif defined(JS_PUNBOX64)
145 :
146 : #define JSVAL_PAYLOAD_MASK 0x00007FFFFFFFFFFFLL
147 : #define JSVAL_TAG_MASK 0xFFFF800000000000LL
148 : #define JSVAL_TYPE_TO_TAG(type) ((JSValueTag)(JSVAL_TAG_MAX_DOUBLE | (type)))
149 : #define JSVAL_TYPE_TO_SHIFTED_TAG(type) (((uint64_t)JSVAL_TYPE_TO_TAG(type)) << JSVAL_TAG_SHIFT)
150 :
151 : #define JSVAL_UPPER_EXCL_TAG_OF_PRIMITIVE_SET JSVAL_TAG_OBJECT
152 : #define JSVAL_UPPER_INCL_TAG_OF_NUMBER_SET JSVAL_TAG_INT32
153 : #define JSVAL_LOWER_INCL_TAG_OF_GCTHING_SET JSVAL_TAG_STRING
154 :
155 : #define JSVAL_UPPER_EXCL_SHIFTED_TAG_OF_PRIMITIVE_SET JSVAL_SHIFTED_TAG_OBJECT
156 : #define JSVAL_UPPER_EXCL_SHIFTED_TAG_OF_NUMBER_SET JSVAL_SHIFTED_TAG_UNDEFINED
157 : #define JSVAL_LOWER_INCL_SHIFTED_TAG_OF_GCTHING_SET JSVAL_SHIFTED_TAG_STRING
158 :
159 : #endif /* JS_PUNBOX64 */
160 :
161 : typedef enum JSWhyMagic
162 : {
163 : /** a hole in a native object's elements */
164 : JS_ELEMENTS_HOLE,
165 :
166 : /** there is not a pending iterator value */
167 : JS_NO_ITER_VALUE,
168 :
169 : /** exception value thrown when closing a generator */
170 : JS_GENERATOR_CLOSING,
171 :
172 : /** compiler sentinel value */
173 : JS_NO_CONSTANT,
174 :
175 : /** used in debug builds to catch tracing errors */
176 : JS_THIS_POISON,
177 :
178 : /** used in debug builds to catch tracing errors */
179 : JS_ARG_POISON,
180 :
181 : /** an empty subnode in the AST serializer */
182 : JS_SERIALIZE_NO_NODE,
183 :
184 : /** lazy arguments value on the stack */
185 : JS_LAZY_ARGUMENTS,
186 :
187 : /** optimized-away 'arguments' value */
188 : JS_OPTIMIZED_ARGUMENTS,
189 :
190 : /** magic value passed to natives to indicate construction */
191 : JS_IS_CONSTRUCTING,
192 :
193 : /** value of static block object slot */
194 : JS_BLOCK_NEEDS_CLONE,
195 :
196 : /** see class js::HashableValue */
197 : JS_HASH_KEY_EMPTY,
198 :
199 : /** error while running Ion code */
200 : JS_ION_ERROR,
201 :
202 : /** missing recover instruction result */
203 : JS_ION_BAILOUT,
204 :
205 : /** optimized out slot */
206 : JS_OPTIMIZED_OUT,
207 :
208 : /** uninitialized lexical bindings that produce ReferenceError on touch. */
209 : JS_UNINITIALIZED_LEXICAL,
210 :
211 : /** for local use */
212 : JS_GENERIC_MAGIC,
213 :
214 : JS_WHY_MAGIC_COUNT
215 : } JSWhyMagic;
216 :
217 : namespace JS {
218 :
219 : static inline constexpr JS::Value UndefinedValue();
220 : static inline JS::Value PoisonedObjectValue(JSObject* obj);
221 :
222 : namespace detail {
223 :
224 : constexpr int CanonicalizedNaNSignBit = 0;
225 : constexpr uint64_t CanonicalizedNaNSignificand = 0x8000000000000ULL;
226 :
227 : constexpr uint64_t CanonicalizedNaNBits =
228 : mozilla::SpecificNaNBits<double,
229 : detail::CanonicalizedNaNSignBit,
230 : detail::CanonicalizedNaNSignificand>::value;
231 :
232 : } // namespace detail
233 :
234 : /**
235 : * Returns a generic quiet NaN value, with all payload bits set to zero.
236 : *
237 : * Among other properties, this NaN's bit pattern conforms to JS::Value's
238 : * bit pattern restrictions.
239 : */
240 : static MOZ_ALWAYS_INLINE double
241 213 : GenericNaN()
242 : {
243 : return mozilla::SpecificNaN<double>(detail::CanonicalizedNaNSignBit,
244 213 : detail::CanonicalizedNaNSignificand);
245 : }
246 :
247 : /* MSVC with PGO miscompiles this function. */
248 : #if defined(_MSC_VER)
249 : # pragma optimize("g", off)
250 : #endif
251 : static inline double
252 3594 : CanonicalizeNaN(double d)
253 : {
254 3594 : if (MOZ_UNLIKELY(mozilla::IsNaN(d)))
255 0 : return GenericNaN();
256 3594 : return d;
257 : }
258 : #if defined(_MSC_VER)
259 : # pragma optimize("", on)
260 : #endif
261 :
262 : /**
263 : * JS::Value is the interface for a single JavaScript Engine value. A few
264 : * general notes on JS::Value:
265 : *
266 : * - JS::Value has setX() and isX() members for X in
267 : *
268 : * { Int32, Double, String, Symbol, Boolean, Undefined, Null, Object, Magic }
269 : *
270 : * JS::Value also contains toX() for each of the non-singleton types.
271 : *
272 : * - Magic is a singleton type whose payload contains either a JSWhyMagic "reason" for
273 : * the magic value or a uint32_t value. By providing JSWhyMagic values when
274 : * creating and checking for magic values, it is possible to assert, at
275 : * runtime, that only magic values with the expected reason flow through a
276 : * particular value. For example, if cx->exception has a magic value, the
277 : * reason must be JS_GENERATOR_CLOSING.
278 : *
279 : * - The JS::Value operations are preferred. The JSVAL_* operations remain for
280 : * compatibility; they may be removed at some point. These operations mostly
281 : * provide similar functionality. But there are a few key differences. One
282 : * is that JS::Value gives null a separate type.
283 : * Also, to help prevent mistakenly boxing a nullable JSObject* as an object,
284 : * Value::setObject takes a JSObject&. (Conversely, Value::toObject returns a
285 : * JSObject&.) A convenience member Value::setObjectOrNull is provided.
286 : *
287 : * - JSVAL_VOID is the same as the singleton value of the Undefined type.
288 : *
289 : * - Note that JS::Value is 8 bytes on 32 and 64-bit architectures. Thus, on
290 : * 32-bit user code should avoid copying jsval/JS::Value as much as possible,
291 : * preferring to pass by const Value&.
292 : */
293 : class MOZ_NON_PARAM alignas(8) Value
294 : {
295 : public:
296 : #if defined(JS_NUNBOX32)
297 : using PayloadType = uint32_t;
298 : #elif defined(JS_PUNBOX64)
299 : using PayloadType = uint64_t;
300 : #endif
301 :
302 : /*
303 : * N.B. the default constructor leaves Value unitialized. Adding a default
304 : * constructor prevents Value from being stored in a union.
305 : */
306 477037 : Value() = default;
307 : Value(const Value& v) = default;
308 :
309 : /**
310 : * Returns false if creating a NumberValue containing the given type would
311 : * be lossy, true otherwise.
312 : */
313 : template <typename T>
314 64 : static bool isNumberRepresentable(const T t) {
315 64 : return T(double(t)) == t;
316 : }
317 :
318 : /*** Mutators ***/
319 :
320 38699 : void setNull() {
321 38699 : data.asBits = bitsFromTagAndPayload(JSVAL_TAG_NULL, 0);
322 38699 : }
323 :
324 127926 : void setUndefined() {
325 127926 : data.asBits = bitsFromTagAndPayload(JSVAL_TAG_UNDEFINED, 0);
326 127926 : }
327 :
328 66247 : void setInt32(int32_t i) {
329 66247 : data.asBits = bitsFromTagAndPayload(JSVAL_TAG_INT32, uint32_t(i));
330 66247 : }
331 :
332 : int32_t& getInt32Ref() {
333 : MOZ_ASSERT(isInt32());
334 : return data.s.payload.i32;
335 : }
336 :
337 2618 : void setDouble(double d) {
338 : // Don't assign to data.asDouble to fix a miscompilation with
339 : // GCC 5.2.1 and 5.3.1. See bug 1312488.
340 2618 : data = layout(d);
341 2618 : MOZ_ASSERT(isDouble());
342 2618 : }
343 :
344 4 : void setNaN() {
345 4 : setDouble(GenericNaN());
346 4 : }
347 :
348 : double& getDoubleRef() {
349 : MOZ_ASSERT(isDouble());
350 : return data.asDouble;
351 : }
352 :
353 114767 : void setString(JSString* str) {
354 114767 : MOZ_ASSERT(uintptr_t(str) > 0x1000);
355 114767 : data.asBits = bitsFromTagAndPayload(JSVAL_TAG_STRING, PayloadType(str));
356 114767 : }
357 :
358 950 : void setSymbol(JS::Symbol* sym) {
359 950 : MOZ_ASSERT(uintptr_t(sym) > 0x1000);
360 950 : data.asBits = bitsFromTagAndPayload(JSVAL_TAG_SYMBOL, PayloadType(sym));
361 950 : }
362 :
363 673690 : void setObject(JSObject& obj) {
364 673690 : MOZ_ASSERT(uintptr_t(&obj) > 0x1000 || uintptr_t(&obj) == 0x48);
365 : #if defined(JS_PUNBOX64)
366 : // VisualStudio cannot contain parenthesized C++ style cast and shift
367 : // inside decltype in template parameter:
368 : // AssertionConditionType<decltype((uintptr_t(x) >> 1))>
369 : // It throws syntax error.
370 673690 : MOZ_ASSERT((((uintptr_t)&obj) >> JSVAL_TAG_SHIFT) == 0);
371 : #endif
372 673690 : setObjectNoCheck(&obj);
373 673690 : }
374 :
375 : private:
376 673690 : void setObjectNoCheck(JSObject* obj) {
377 673690 : data.asBits = bitsFromTagAndPayload(JSVAL_TAG_OBJECT, PayloadType(obj));
378 673690 : }
379 :
380 : friend inline Value PoisonedObjectValue(JSObject* obj);
381 :
382 : public:
383 54765 : void setBoolean(bool b) {
384 54765 : data.asBits = bitsFromTagAndPayload(JSVAL_TAG_BOOLEAN, uint32_t(b));
385 54765 : }
386 :
387 30474 : void setMagic(JSWhyMagic why) {
388 30474 : data.asBits = bitsFromTagAndPayload(JSVAL_TAG_MAGIC, uint32_t(why));
389 30474 : }
390 :
391 14 : void setMagicUint32(uint32_t payload) {
392 14 : data.asBits = bitsFromTagAndPayload(JSVAL_TAG_MAGIC, payload);
393 14 : }
394 :
395 4046 : bool setNumber(uint32_t ui) {
396 4046 : if (ui > JSVAL_INT_MAX) {
397 5 : setDouble((double)ui);
398 5 : return false;
399 : } else {
400 4041 : setInt32((int32_t)ui);
401 4041 : return true;
402 : }
403 : }
404 :
405 17714 : bool setNumber(double d) {
406 : int32_t i;
407 17714 : if (mozilla::NumberIsInt32(d, &i)) {
408 17412 : setInt32(i);
409 17412 : return true;
410 : }
411 :
412 302 : setDouble(d);
413 302 : return false;
414 : }
415 :
416 69602 : void setObjectOrNull(JSObject* arg) {
417 69602 : if (arg)
418 66299 : setObject(*arg);
419 : else
420 3303 : setNull();
421 69602 : }
422 :
423 14737 : void swap(Value& rhs) {
424 14737 : uint64_t tmp = rhs.data.asBits;
425 14737 : rhs.data.asBits = data.asBits;
426 14737 : data.asBits = tmp;
427 14737 : }
428 :
429 : private:
430 3355302 : JSValueTag toTag() const {
431 : #if defined(JS_NUNBOX32)
432 : return data.s.tag;
433 : #elif defined(JS_PUNBOX64)
434 3355302 : return JSValueTag(data.asBits >> JSVAL_TAG_SHIFT);
435 : #endif
436 : }
437 :
438 : public:
439 : /*** JIT-only interfaces to interact with and create raw Values ***/
440 : #if defined(JS_NUNBOX32)
441 : PayloadType toNunboxPayload() const {
442 : return static_cast<PayloadType>(data.s.payload.i32);
443 : }
444 :
445 : JSValueTag toNunboxTag() const {
446 : return data.s.tag;
447 : }
448 : #elif defined(JS_PUNBOX64)
449 0 : const void* bitsAsPunboxPointer() const {
450 0 : return reinterpret_cast<void*>(data.asBits);
451 : }
452 : #endif
453 :
454 : /*** Value type queries ***/
455 :
456 : /*
457 : * N.B. GCC, in some but not all cases, chooses to emit signed comparison
458 : * of JSValueTag even though its underlying type has been forced to be
459 : * uint32_t. Thus, all comparisons should explicitly cast operands to
460 : * uint32_t.
461 : */
462 :
463 623845 : bool isUndefined() const {
464 : #if defined(JS_NUNBOX32)
465 : return toTag() == JSVAL_TAG_UNDEFINED;
466 : #elif defined(JS_PUNBOX64)
467 623845 : return data.asBits == JSVAL_SHIFTED_TAG_UNDEFINED;
468 : #endif
469 : }
470 :
471 89590 : bool isNull() const {
472 : #if defined(JS_NUNBOX32)
473 : return toTag() == JSVAL_TAG_NULL;
474 : #elif defined(JS_PUNBOX64)
475 89590 : return data.asBits == JSVAL_SHIFTED_TAG_NULL;
476 : #endif
477 : }
478 :
479 23739 : bool isNullOrUndefined() const {
480 23739 : return isNull() || isUndefined();
481 : }
482 :
483 216630 : bool isInt32() const {
484 216630 : return toTag() == JSVAL_TAG_INT32;
485 : }
486 :
487 : bool isInt32(int32_t i32) const {
488 : return data.asBits == bitsFromTagAndPayload(JSVAL_TAG_INT32, uint32_t(i32));
489 : }
490 :
491 403132 : bool isDouble() const {
492 : #if defined(JS_NUNBOX32)
493 : return uint32_t(toTag()) <= uint32_t(JSVAL_TAG_CLEAR);
494 : #elif defined(JS_PUNBOX64)
495 403132 : return (data.asBits | mozilla::DoubleTypeTraits::kSignBit) <= JSVAL_SHIFTED_TAG_MAX_DOUBLE;
496 : #endif
497 : }
498 :
499 69759 : bool isNumber() const {
500 : #if defined(JS_NUNBOX32)
501 : MOZ_ASSERT(toTag() != JSVAL_TAG_CLEAR);
502 : return uint32_t(toTag()) <= uint32_t(JSVAL_UPPER_INCL_TAG_OF_NUMBER_SET);
503 : #elif defined(JS_PUNBOX64)
504 69759 : return data.asBits < JSVAL_UPPER_EXCL_SHIFTED_TAG_OF_NUMBER_SET;
505 : #endif
506 : }
507 :
508 1359137 : bool isString() const {
509 1359137 : return toTag() == JSVAL_TAG_STRING;
510 : }
511 :
512 677875 : bool isSymbol() const {
513 677875 : return toTag() == JSVAL_TAG_SYMBOL;
514 : }
515 :
516 7477819 : bool isObject() const {
517 : #if defined(JS_NUNBOX32)
518 : return toTag() == JSVAL_TAG_OBJECT;
519 : #elif defined(JS_PUNBOX64)
520 7477819 : MOZ_ASSERT((data.asBits >> JSVAL_TAG_SHIFT) <= JSVAL_TAG_OBJECT);
521 7477819 : return data.asBits >= JSVAL_SHIFTED_TAG_OBJECT;
522 : #endif
523 : }
524 :
525 136582 : bool isPrimitive() const {
526 : #if defined(JS_NUNBOX32)
527 : return uint32_t(toTag()) < uint32_t(JSVAL_UPPER_EXCL_TAG_OF_PRIMITIVE_SET);
528 : #elif defined(JS_PUNBOX64)
529 136582 : return data.asBits < JSVAL_UPPER_EXCL_SHIFTED_TAG_OF_PRIMITIVE_SET;
530 : #endif
531 : }
532 :
533 2280319 : bool isObjectOrNull() const {
534 2280319 : return isObject() || isNull();
535 : }
536 :
537 1864926 : bool isGCThing() const {
538 : #if defined(JS_NUNBOX32)
539 : /* gcc sometimes generates signed < without explicit casts. */
540 : return uint32_t(toTag()) >= uint32_t(JSVAL_LOWER_INCL_TAG_OF_GCTHING_SET);
541 : #elif defined(JS_PUNBOX64)
542 1864926 : return data.asBits >= JSVAL_LOWER_INCL_SHIFTED_TAG_OF_GCTHING_SET;
543 : #endif
544 : }
545 :
546 69896 : bool isBoolean() const {
547 69896 : return toTag() == JSVAL_TAG_BOOLEAN;
548 : }
549 :
550 2652 : bool isTrue() const {
551 2652 : return data.asBits == bitsFromTagAndPayload(JSVAL_TAG_BOOLEAN, uint32_t(true));
552 : }
553 :
554 2581 : bool isFalse() const {
555 2581 : return data.asBits == bitsFromTagAndPayload(JSVAL_TAG_BOOLEAN, uint32_t(false));
556 : }
557 :
558 633427 : bool isMagic() const {
559 633427 : return toTag() == JSVAL_TAG_MAGIC;
560 : }
561 :
562 251456 : bool isMagic(JSWhyMagic why) const {
563 251456 : MOZ_ASSERT_IF(isMagic(), data.s.payload.why == why);
564 251456 : return isMagic();
565 : }
566 :
567 6063 : JS::TraceKind traceKind() const {
568 6063 : MOZ_ASSERT(isGCThing());
569 : static_assert((JSVAL_TAG_STRING & 0x03) == size_t(JS::TraceKind::String),
570 : "Value type tags must correspond with JS::TraceKinds.");
571 : static_assert((JSVAL_TAG_SYMBOL & 0x03) == size_t(JS::TraceKind::Symbol),
572 : "Value type tags must correspond with JS::TraceKinds.");
573 : static_assert((JSVAL_TAG_OBJECT & 0x03) == size_t(JS::TraceKind::Object),
574 : "Value type tags must correspond with JS::TraceKinds.");
575 6063 : if (MOZ_UNLIKELY(isPrivateGCThing()))
576 6063 : return JS::GCThingTraceKind(toGCThing());
577 0 : return JS::TraceKind(toTag() & 0x03);
578 : }
579 :
580 1529 : JSWhyMagic whyMagic() const {
581 1529 : MOZ_ASSERT(isMagic());
582 1529 : return data.s.payload.why;
583 : }
584 :
585 0 : uint32_t magicUint32() const {
586 0 : MOZ_ASSERT(isMagic());
587 0 : return data.s.payload.u32;
588 : }
589 :
590 : /*** Comparison ***/
591 :
592 539154 : bool operator==(const Value& rhs) const {
593 539154 : return data.asBits == rhs.data.asBits;
594 : }
595 :
596 23774 : bool operator!=(const Value& rhs) const {
597 23774 : return data.asBits != rhs.data.asBits;
598 : }
599 :
600 : friend inline bool SameType(const Value& lhs, const Value& rhs);
601 :
602 : /*** Extract the value's typed payload ***/
603 :
604 121164 : int32_t toInt32() const {
605 121164 : MOZ_ASSERT(isInt32());
606 : #if defined(JS_NUNBOX32)
607 : return data.s.payload.i32;
608 : #elif defined(JS_PUNBOX64)
609 121164 : return int32_t(data.asBits);
610 : #endif
611 : }
612 :
613 6794 : double toDouble() const {
614 6794 : MOZ_ASSERT(isDouble());
615 6794 : return data.asDouble;
616 : }
617 :
618 23715 : double toNumber() const {
619 23715 : MOZ_ASSERT(isNumber());
620 23715 : return isDouble() ? toDouble() : double(toInt32());
621 : }
622 :
623 297234 : JSString* toString() const {
624 297234 : MOZ_ASSERT(isString());
625 : #if defined(JS_NUNBOX32)
626 : return data.s.payload.str;
627 : #elif defined(JS_PUNBOX64)
628 297231 : return reinterpret_cast<JSString*>(data.asBits & JSVAL_PAYLOAD_MASK);
629 : #endif
630 : }
631 :
632 2248 : JS::Symbol* toSymbol() const {
633 2248 : MOZ_ASSERT(isSymbol());
634 : #if defined(JS_NUNBOX32)
635 : return data.s.payload.sym;
636 : #elif defined(JS_PUNBOX64)
637 2248 : return reinterpret_cast<JS::Symbol*>(data.asBits & JSVAL_PAYLOAD_MASK);
638 : #endif
639 : }
640 :
641 2181900 : JSObject& toObject() const {
642 2181900 : MOZ_ASSERT(isObject());
643 : #if defined(JS_NUNBOX32)
644 : return *data.s.payload.obj;
645 : #elif defined(JS_PUNBOX64)
646 2181895 : return *toObjectOrNull();
647 : #endif
648 : }
649 :
650 2277463 : JSObject* toObjectOrNull() const {
651 2277463 : MOZ_ASSERT(isObjectOrNull());
652 : #if defined(JS_NUNBOX32)
653 : return data.s.payload.obj;
654 : #elif defined(JS_PUNBOX64)
655 2277464 : uint64_t ptrBits = data.asBits & JSVAL_PAYLOAD_MASK;
656 2277464 : MOZ_ASSERT((ptrBits & 0x7) == 0);
657 2277464 : return reinterpret_cast<JSObject*>(ptrBits);
658 : #endif
659 : }
660 :
661 466592 : js::gc::Cell* toGCThing() const {
662 466592 : MOZ_ASSERT(isGCThing());
663 : #if defined(JS_NUNBOX32)
664 : return data.s.payload.cell;
665 : #elif defined(JS_PUNBOX64)
666 466593 : uint64_t ptrBits = data.asBits & JSVAL_PAYLOAD_MASK;
667 466593 : MOZ_ASSERT((ptrBits & 0x7) == 0);
668 466593 : return reinterpret_cast<js::gc::Cell*>(ptrBits);
669 : #endif
670 : }
671 :
672 1144 : GCCellPtr toGCCellPtr() const {
673 1144 : return GCCellPtr(toGCThing(), traceKind());
674 : }
675 :
676 30807 : bool toBoolean() const {
677 30807 : MOZ_ASSERT(isBoolean());
678 : #if defined(JS_NUNBOX32)
679 : return bool(data.s.payload.boo);
680 : #elif defined(JS_PUNBOX64)
681 30807 : return bool(data.asBits & JSVAL_PAYLOAD_MASK);
682 : #endif
683 : }
684 :
685 4578 : uint32_t payloadAsRawUint32() const {
686 4578 : MOZ_ASSERT(!isDouble());
687 4578 : return data.s.payload.u32;
688 : }
689 :
690 17283 : uint64_t asRawBits() const {
691 17283 : return data.asBits;
692 : }
693 :
694 105320 : JSValueType extractNonDoubleType() const {
695 105320 : uint32_t type = toTag() & 0xF;
696 105320 : MOZ_ASSERT(type > JSVAL_TYPE_DOUBLE);
697 105320 : return JSValueType(type);
698 : }
699 :
700 : /*
701 : * Private API
702 : *
703 : * Private setters/getters allow the caller to read/write arbitrary types
704 : * that fit in the 64-bit payload. It is the caller's responsibility, after
705 : * storing to a value with setPrivateX to read only using getPrivateX.
706 : * Privates values are given a type which ensures they are not marked.
707 : */
708 :
709 11137 : void setPrivate(void* ptr) {
710 11137 : MOZ_ASSERT((uintptr_t(ptr) & 1) == 0);
711 : #if defined(JS_NUNBOX32)
712 : data.s.tag = JSValueTag(0);
713 : data.s.payload.ptr = ptr;
714 : #elif defined(JS_PUNBOX64)
715 11137 : data.asBits = uintptr_t(ptr) >> 1;
716 : #endif
717 11137 : MOZ_ASSERT(isDouble());
718 11137 : }
719 :
720 95318 : void* toPrivate() const {
721 95318 : MOZ_ASSERT(isDouble());
722 : #if defined(JS_NUNBOX32)
723 : return data.s.payload.ptr;
724 : #elif defined(JS_PUNBOX64)
725 95318 : MOZ_ASSERT((data.asBits & 0x8000000000000000ULL) == 0);
726 95318 : return reinterpret_cast<void*>(data.asBits << 1);
727 : #endif
728 : }
729 :
730 4068 : void setPrivateUint32(uint32_t ui) {
731 : MOZ_ASSERT(uint32_t(int32_t(ui)) == ui);
732 4068 : setInt32(int32_t(ui));
733 4068 : }
734 :
735 54481 : uint32_t toPrivateUint32() const {
736 54481 : return uint32_t(toInt32());
737 : }
738 :
739 : /*
740 : * Private GC Thing API
741 : *
742 : * Non-JSObject, JSString, and JS::Symbol cells may be put into the 64-bit
743 : * payload as private GC things. Such Values are considered isGCThing(), and
744 : * as such, automatically marked. Their traceKind() is gotten via their
745 : * cells.
746 : */
747 :
748 3584 : void setPrivateGCThing(js::gc::Cell* cell) {
749 3584 : MOZ_ASSERT(JS::GCThingTraceKind(cell) != JS::TraceKind::String,
750 : "Private GC thing Values must not be strings. Make a StringValue instead.");
751 3584 : MOZ_ASSERT(JS::GCThingTraceKind(cell) != JS::TraceKind::Symbol,
752 : "Private GC thing Values must not be symbols. Make a SymbolValue instead.");
753 3584 : MOZ_ASSERT(JS::GCThingTraceKind(cell) != JS::TraceKind::Object,
754 : "Private GC thing Values must not be objects. Make an ObjectValue instead.");
755 :
756 3584 : MOZ_ASSERT(uintptr_t(cell) > 0x1000);
757 : #if defined(JS_PUNBOX64)
758 : // VisualStudio cannot contain parenthesized C++ style cast and shift
759 : // inside decltype in template parameter:
760 : // AssertionConditionType<decltype((uintptr_t(x) >> 1))>
761 : // It throws syntax error.
762 3584 : MOZ_ASSERT((((uintptr_t)cell) >> JSVAL_TAG_SHIFT) == 0);
763 : #endif
764 3584 : data.asBits = bitsFromTagAndPayload(JSVAL_TAG_PRIVATE_GCTHING, PayloadType(cell));
765 3584 : }
766 :
767 292633 : bool isPrivateGCThing() const {
768 292633 : return toTag() == JSVAL_TAG_PRIVATE_GCTHING;
769 : }
770 :
771 : const size_t* payloadWord() const {
772 : #if defined(JS_NUNBOX32)
773 : return &data.s.payload.word;
774 : #elif defined(JS_PUNBOX64)
775 : return &data.asWord;
776 : #endif
777 : }
778 :
779 0 : const uintptr_t* payloadUIntPtr() const {
780 : #if defined(JS_NUNBOX32)
781 : return &data.s.payload.uintptr;
782 : #elif defined(JS_PUNBOX64)
783 0 : return &data.asUIntPtr;
784 : #endif
785 : }
786 :
787 : #if !defined(_MSC_VER) && !defined(__sparc)
788 : // Value must be POD so that MSVC will pass it by value and not in memory
789 : // (bug 689101); the same is true for SPARC as well (bug 737344). More
790 : // precisely, we don't want Value return values compiled as out params.
791 : private:
792 : #endif
793 :
794 : #if MOZ_LITTLE_ENDIAN
795 : # if defined(JS_NUNBOX32)
796 : union layout {
797 : uint64_t asBits;
798 : struct {
799 : union {
800 : int32_t i32;
801 : uint32_t u32;
802 : uint32_t boo; // Don't use |bool| -- it must be four bytes.
803 : JSString* str;
804 : JS::Symbol* sym;
805 : JSObject* obj;
806 : js::gc::Cell* cell;
807 : void* ptr;
808 : JSWhyMagic why;
809 : size_t word;
810 : uintptr_t uintptr;
811 : } payload;
812 : JSValueTag tag;
813 : } s;
814 : double asDouble;
815 : void* asPtr;
816 :
817 : layout() = default;
818 : explicit constexpr layout(uint64_t bits) : asBits(bits) {}
819 : explicit constexpr layout(double d) : asDouble(d) {}
820 : } data;
821 : # elif defined(JS_PUNBOX64)
822 : union layout {
823 : uint64_t asBits;
824 : #if !defined(_WIN64)
825 : /* MSVC does not pack these correctly :-( */
826 : struct {
827 : uint64_t payload47 : 47;
828 : JSValueTag tag : 17;
829 : } debugView;
830 : #endif
831 : struct {
832 : union {
833 : int32_t i32;
834 : uint32_t u32;
835 : JSWhyMagic why;
836 : } payload;
837 : } s;
838 : double asDouble;
839 : void* asPtr;
840 : size_t asWord;
841 : uintptr_t asUIntPtr;
842 :
843 477038 : layout() = default;
844 962309 : explicit constexpr layout(uint64_t bits) : asBits(bits) {}
845 2631 : explicit constexpr layout(double d) : asDouble(d) {}
846 : } data;
847 : # endif /* JS_PUNBOX64 */
848 : #else /* MOZ_LITTLE_ENDIAN */
849 : # if defined(JS_NUNBOX32)
850 : union layout {
851 : uint64_t asBits;
852 : struct {
853 : JSValueTag tag;
854 : union {
855 : int32_t i32;
856 : uint32_t u32;
857 : uint32_t boo; // Don't use |bool| -- it must be four bytes.
858 : JSString* str;
859 : JS::Symbol* sym;
860 : JSObject* obj;
861 : js::gc::Cell* cell;
862 : void* ptr;
863 : JSWhyMagic why;
864 : size_t word;
865 : uintptr_t uintptr;
866 : } payload;
867 : } s;
868 : double asDouble;
869 : void* asPtr;
870 :
871 : layout() = default;
872 : explicit constexpr layout(uint64_t bits) : asBits(bits) {}
873 : explicit constexpr layout(double d) : asDouble(d) {}
874 : } data;
875 : # elif defined(JS_PUNBOX64)
876 : union layout {
877 : uint64_t asBits;
878 : struct {
879 : JSValueTag tag : 17;
880 : uint64_t payload47 : 47;
881 : } debugView;
882 : struct {
883 : uint32_t padding;
884 : union {
885 : int32_t i32;
886 : uint32_t u32;
887 : JSWhyMagic why;
888 : } payload;
889 : } s;
890 : double asDouble;
891 : void* asPtr;
892 : size_t asWord;
893 : uintptr_t asUIntPtr;
894 :
895 : layout() = default;
896 : explicit constexpr layout(uint64_t bits) : asBits(bits) {}
897 : explicit constexpr layout(double d) : asDouble(d) {}
898 : } data;
899 : # endif /* JS_PUNBOX64 */
900 : #endif /* MOZ_LITTLE_ENDIAN */
901 :
902 : private:
903 962308 : explicit constexpr Value(uint64_t asBits) : data(asBits) {}
904 13 : explicit constexpr Value(double d) : data(d) {}
905 :
906 : void staticAssertions() {
907 : JS_STATIC_ASSERT(sizeof(JSValueType) == 1);
908 : JS_STATIC_ASSERT(sizeof(JSValueTag) == 4);
909 : JS_STATIC_ASSERT(sizeof(JSWhyMagic) <= 4);
910 : JS_STATIC_ASSERT(sizeof(Value) == 8);
911 : }
912 :
913 : friend constexpr Value JS::UndefinedValue();
914 :
915 : public:
916 : static constexpr uint64_t
917 2078701 : bitsFromTagAndPayload(JSValueTag tag, PayloadType payload)
918 : {
919 : #if defined(JS_NUNBOX32)
920 : return (uint64_t(uint32_t(tag)) << 32) | payload;
921 : #elif defined(JS_PUNBOX64)
922 2078701 : return (uint64_t(uint32_t(tag)) << JSVAL_TAG_SHIFT) | payload;
923 : #endif
924 : }
925 :
926 : static constexpr Value
927 962307 : fromTagAndPayload(JSValueTag tag, PayloadType payload)
928 : {
929 962307 : return fromRawBits(bitsFromTagAndPayload(tag, payload));
930 : }
931 :
932 : static constexpr Value
933 962308 : fromRawBits(uint64_t asBits) {
934 962315 : return Value(asBits);
935 : }
936 :
937 : static constexpr Value
938 14370 : fromInt32(int32_t i) {
939 14370 : return fromTagAndPayload(JSVAL_TAG_INT32, uint32_t(i));
940 : }
941 :
942 : static constexpr Value
943 13 : fromDouble(double d) {
944 13 : return Value(d);
945 : }
946 : } JS_HAZ_GC_POINTER;
947 :
948 : static_assert(sizeof(Value) == 8, "Value size must leave three tag bits, be a binary power, and is ubiquitously depended upon everywhere");
949 :
950 : inline bool
951 0 : IsOptimizedPlaceholderMagicValue(const Value& v)
952 : {
953 0 : if (v.isMagic()) {
954 0 : MOZ_ASSERT(v.whyMagic() == JS_OPTIMIZED_ARGUMENTS || v.whyMagic() == JS_OPTIMIZED_OUT);
955 0 : return true;
956 : }
957 0 : return false;
958 : }
959 :
960 : static MOZ_ALWAYS_INLINE void
961 4986 : ExposeValueToActiveJS(const Value& v)
962 : {
963 : #ifdef DEBUG
964 4986 : Value tmp = v;
965 4986 : MOZ_ASSERT(!js::gc::EdgeNeedsSweepUnbarrieredSlow(&tmp));
966 : #endif
967 4986 : if (v.isGCThing())
968 4687 : js::gc::ExposeGCThingToActiveJS(GCCellPtr(v));
969 4986 : }
970 :
971 : /************************************************************************/
972 :
973 : static inline MOZ_MAY_CALL_AFTER_MUST_RETURN Value
974 15544 : NullValue()
975 : {
976 15544 : Value v;
977 15544 : v.setNull();
978 15544 : return v;
979 : }
980 :
981 : static inline constexpr Value
982 944484 : UndefinedValue()
983 : {
984 1906792 : return Value::fromTagAndPayload(JSVAL_TAG_UNDEFINED, 0);
985 : }
986 :
987 : static inline constexpr Value
988 14316 : Int32Value(int32_t i32)
989 : {
990 14316 : return Value::fromInt32(i32);
991 : }
992 :
993 : static inline Value
994 1521 : DoubleValue(double dbl)
995 : {
996 1521 : Value v;
997 1521 : v.setDouble(dbl);
998 1521 : return v;
999 : }
1000 :
1001 : static inline Value
1002 3 : CanonicalizedDoubleValue(double d)
1003 : {
1004 3 : return MOZ_UNLIKELY(mozilla::IsNaN(d))
1005 : ? Value::fromRawBits(detail::CanonicalizedNaNBits)
1006 3 : : Value::fromDouble(d);
1007 : }
1008 :
1009 : static inline bool
1010 33 : IsCanonicalized(double d)
1011 : {
1012 33 : if (mozilla::IsInfinite(d) || mozilla::IsFinite(d))
1013 33 : return true;
1014 :
1015 : uint64_t bits;
1016 0 : mozilla::BitwiseCast<uint64_t>(d, &bits);
1017 0 : return (bits & ~mozilla::DoubleTypeTraits::kSignBit) == detail::CanonicalizedNaNBits;
1018 : }
1019 :
1020 : static inline Value
1021 4 : DoubleNaNValue()
1022 : {
1023 4 : Value v;
1024 4 : v.setNaN();
1025 4 : return v;
1026 : }
1027 :
1028 : static inline Value
1029 0 : Float32Value(float f)
1030 : {
1031 0 : Value v;
1032 0 : v.setDouble(f);
1033 0 : return v;
1034 : }
1035 :
1036 : static inline Value
1037 76757 : StringValue(JSString* str)
1038 : {
1039 76757 : Value v;
1040 76757 : v.setString(str);
1041 76757 : return v;
1042 : }
1043 :
1044 : static inline Value
1045 204 : SymbolValue(JS::Symbol* sym)
1046 : {
1047 204 : Value v;
1048 204 : v.setSymbol(sym);
1049 204 : return v;
1050 : }
1051 :
1052 : static inline Value
1053 6059 : BooleanValue(bool boo)
1054 : {
1055 6059 : Value v;
1056 6059 : v.setBoolean(boo);
1057 6059 : return v;
1058 : }
1059 :
1060 : static inline Value
1061 2 : TrueValue()
1062 : {
1063 2 : Value v;
1064 2 : v.setBoolean(true);
1065 2 : return v;
1066 : }
1067 :
1068 : static inline Value
1069 : FalseValue()
1070 : {
1071 : Value v;
1072 : v.setBoolean(false);
1073 : return v;
1074 : }
1075 :
1076 : static inline Value
1077 247024 : ObjectValue(JSObject& obj)
1078 : {
1079 247024 : Value v;
1080 247024 : v.setObject(obj);
1081 247024 : return v;
1082 : }
1083 :
1084 : static inline Value
1085 : ObjectValueCrashOnTouch()
1086 : {
1087 : Value v;
1088 : v.setObject(*reinterpret_cast<JSObject*>(0x48));
1089 : return v;
1090 : }
1091 :
1092 : static inline Value
1093 25993 : MagicValue(JSWhyMagic why)
1094 : {
1095 25993 : Value v;
1096 25993 : v.setMagic(why);
1097 25993 : return v;
1098 : }
1099 :
1100 : static inline Value
1101 14 : MagicValueUint32(uint32_t payload)
1102 : {
1103 14 : Value v;
1104 14 : v.setMagicUint32(payload);
1105 14 : return v;
1106 : }
1107 :
1108 : static inline Value
1109 0 : NumberValue(float f)
1110 : {
1111 0 : Value v;
1112 0 : v.setNumber(f);
1113 0 : return v;
1114 : }
1115 :
1116 : static inline Value
1117 380 : NumberValue(double dbl)
1118 : {
1119 380 : Value v;
1120 380 : v.setNumber(dbl);
1121 380 : return v;
1122 : }
1123 :
1124 : static inline Value
1125 0 : NumberValue(int8_t i)
1126 : {
1127 0 : return Int32Value(i);
1128 : }
1129 :
1130 : static inline Value
1131 0 : NumberValue(uint8_t i)
1132 : {
1133 0 : return Int32Value(i);
1134 : }
1135 :
1136 : static inline Value
1137 0 : NumberValue(int16_t i)
1138 : {
1139 0 : return Int32Value(i);
1140 : }
1141 :
1142 : static inline Value
1143 0 : NumberValue(uint16_t i)
1144 : {
1145 0 : return Int32Value(i);
1146 : }
1147 :
1148 : static inline Value
1149 0 : NumberValue(int32_t i)
1150 : {
1151 0 : return Int32Value(i);
1152 : }
1153 :
1154 : static inline constexpr Value
1155 456 : NumberValue(uint32_t i)
1156 : {
1157 456 : return i <= JSVAL_INT_MAX
1158 446 : ? Int32Value(int32_t(i))
1159 902 : : Value::fromDouble(double(i));
1160 : }
1161 :
1162 : namespace detail {
1163 :
1164 : template <bool Signed>
1165 : class MakeNumberValue
1166 : {
1167 : public:
1168 : template<typename T>
1169 : static inline Value create(const T t)
1170 : {
1171 : Value v;
1172 : if (JSVAL_INT_MIN <= t && t <= JSVAL_INT_MAX)
1173 : v.setInt32(int32_t(t));
1174 : else
1175 : v.setDouble(double(t));
1176 : return v;
1177 : }
1178 : };
1179 :
1180 : template <>
1181 : class MakeNumberValue<false>
1182 : {
1183 : public:
1184 : template<typename T>
1185 64 : static inline Value create(const T t)
1186 : {
1187 64 : Value v;
1188 64 : if (t <= JSVAL_INT_MAX)
1189 64 : v.setInt32(int32_t(t));
1190 : else
1191 0 : v.setDouble(double(t));
1192 64 : return v;
1193 : }
1194 : };
1195 :
1196 : } // namespace detail
1197 :
1198 : template <typename T>
1199 : static inline Value
1200 64 : NumberValue(const T t)
1201 : {
1202 64 : MOZ_ASSERT(Value::isNumberRepresentable(t), "value creation would be lossy");
1203 64 : return detail::MakeNumberValue<std::numeric_limits<T>::is_signed>::create(t);
1204 : }
1205 :
1206 : static inline Value
1207 60598 : ObjectOrNullValue(JSObject* obj)
1208 : {
1209 60598 : Value v;
1210 60598 : v.setObjectOrNull(obj);
1211 60598 : return v;
1212 : }
1213 :
1214 : static inline Value
1215 11116 : PrivateValue(void* ptr)
1216 : {
1217 11116 : Value v;
1218 11116 : v.setPrivate(ptr);
1219 11116 : return v;
1220 : }
1221 :
1222 : static inline Value
1223 4068 : PrivateUint32Value(uint32_t ui)
1224 : {
1225 4068 : Value v;
1226 4068 : v.setPrivateUint32(ui);
1227 4068 : return v;
1228 : }
1229 :
1230 : static inline Value
1231 3584 : PrivateGCThingValue(js::gc::Cell* cell)
1232 : {
1233 3584 : Value v;
1234 3584 : v.setPrivateGCThing(cell);
1235 3584 : return v;
1236 : }
1237 :
1238 : static inline Value
1239 0 : PoisonedObjectValue(JSObject* obj)
1240 : {
1241 0 : Value v;
1242 0 : v.setObjectNoCheck(obj);
1243 0 : return v;
1244 : }
1245 :
1246 : inline bool
1247 18771 : SameType(const Value& lhs, const Value& rhs)
1248 : {
1249 : #if defined(JS_NUNBOX32)
1250 : JSValueTag ltag = lhs.toTag(), rtag = rhs.toTag();
1251 : return ltag == rtag || (ltag < JSVAL_TAG_CLEAR && rtag < JSVAL_TAG_CLEAR);
1252 : #elif defined(JS_PUNBOX64)
1253 37478 : return (lhs.isDouble() && rhs.isDouble()) ||
1254 37478 : (((lhs.data.asBits ^ rhs.data.asBits) & 0xFFFF800000000000ULL) == 0);
1255 : #endif
1256 : }
1257 :
1258 : } // namespace JS
1259 :
1260 : /************************************************************************/
1261 :
1262 : namespace JS {
1263 : JS_PUBLIC_API(void) HeapValuePostBarrier(Value* valuep, const Value& prev, const Value& next);
1264 :
1265 : template <>
1266 : struct GCPolicy<JS::Value>
1267 : {
1268 387686 : static Value initial() { return UndefinedValue(); }
1269 320 : static void trace(JSTracer* trc, Value* v, const char* name) {
1270 320 : js::UnsafeTraceManuallyBarrieredEdge(trc, v, name);
1271 320 : }
1272 6222 : static bool isTenured(const Value& thing) {
1273 6222 : return !thing.isGCThing() || !IsInsideNursery(thing.toGCThing());
1274 : }
1275 : };
1276 :
1277 : } // namespace JS
1278 :
1279 : namespace js {
1280 :
1281 : template <>
1282 : struct BarrierMethods<JS::Value>
1283 : {
1284 11 : static gc::Cell* asGCThingOrNull(const JS::Value& v) {
1285 11 : return v.isGCThing() ? v.toGCThing() : nullptr;
1286 : }
1287 2223 : static void postBarrier(JS::Value* v, const JS::Value& prev, const JS::Value& next) {
1288 2223 : JS::HeapValuePostBarrier(v, prev, next);
1289 2223 : }
1290 89 : static void exposeToJS(const JS::Value& v) {
1291 89 : JS::ExposeValueToActiveJS(v);
1292 89 : }
1293 : };
1294 :
1295 : template <class Wrapper> class MutableValueOperations;
1296 :
1297 : /**
1298 : * A class designed for CRTP use in implementing the non-mutating parts of the
1299 : * Value interface in Value-like classes. Wrapper must be a class inheriting
1300 : * ValueOperations<Wrapper> with a visible get() method returning a const
1301 : * reference to the Value abstracted by Wrapper.
1302 : */
1303 : template <class Wrapper>
1304 3315028 : class WrappedPtrOperations<JS::Value, Wrapper>
1305 : {
1306 1942324 : const JS::Value& value() const { return static_cast<const Wrapper*>(this)->get(); }
1307 :
1308 : public:
1309 83238 : bool isUndefined() const { return value().isUndefined(); }
1310 16947 : bool isNull() const { return value().isNull(); }
1311 38326 : bool isBoolean() const { return value().isBoolean(); }
1312 2577 : bool isTrue() const { return value().isTrue(); }
1313 2581 : bool isFalse() const { return value().isFalse(); }
1314 32894 : bool isNumber() const { return value().isNumber(); }
1315 71988 : bool isInt32() const { return value().isInt32(); }
1316 : bool isInt32(int32_t i32) const { return value().isInt32(i32); }
1317 21532 : bool isDouble() const { return value().isDouble(); }
1318 151777 : bool isString() const { return value().isString(); }
1319 33287 : bool isSymbol() const { return value().isSymbol(); }
1320 286699 : bool isObject() const { return value().isObject(); }
1321 34182 : bool isMagic() const { return value().isMagic(); }
1322 92054 : bool isMagic(JSWhyMagic why) const { return value().isMagic(why); }
1323 53594 : bool isGCThing() const { return value().isGCThing(); }
1324 124746 : bool isPrimitive() const { return value().isPrimitive(); }
1325 :
1326 23734 : bool isNullOrUndefined() const { return value().isNullOrUndefined(); }
1327 2339 : bool isObjectOrNull() const { return value().isObjectOrNull(); }
1328 :
1329 28435 : bool toBoolean() const { return value().toBoolean(); }
1330 23685 : double toNumber() const { return value().toNumber(); }
1331 30652 : int32_t toInt32() const { return value().toInt32(); }
1332 190 : double toDouble() const { return value().toDouble(); }
1333 128161 : JSString* toString() const { return value().toString(); }
1334 86 : JS::Symbol* toSymbol() const { return value().toSymbol(); }
1335 601550 : JSObject& toObject() const { return value().toObject(); }
1336 5124 : JSObject* toObjectOrNull() const { return value().toObjectOrNull(); }
1337 10349 : gc::Cell* toGCThing() const { return value().toGCThing(); }
1338 0 : JS::TraceKind traceKind() const { return value().traceKind(); }
1339 0 : void* toPrivate() const { return value().toPrivate(); }
1340 25945 : uint32_t toPrivateUint32() const { return value().toPrivateUint32(); }
1341 :
1342 6161 : uint64_t asRawBits() const { return value().asRawBits(); }
1343 8249 : JSValueType extractNonDoubleType() const { return value().extractNonDoubleType(); }
1344 :
1345 1 : JSWhyMagic whyMagic() const { return value().whyMagic(); }
1346 : uint32_t magicUint32() const { return value().magicUint32(); }
1347 : };
1348 :
1349 : /**
1350 : * A class designed for CRTP use in implementing all the mutating parts of the
1351 : * Value interface in Value-like classes. Wrapper must be a class inheriting
1352 : * MutableWrappedPtrOperations<Wrapper> with visible get() methods returning const and
1353 : * non-const references to the Value abstracted by Wrapper.
1354 : */
1355 : template <class Wrapper>
1356 1580138 : class MutableWrappedPtrOperations<JS::Value, Wrapper> : public WrappedPtrOperations<JS::Value, Wrapper>
1357 : {
1358 272766 : JS::Value& value() { return static_cast<Wrapper*>(this)->get(); }
1359 :
1360 : public:
1361 10721 : void setNull() { value().setNull(); }
1362 73754 : void setUndefined() { value().setUndefined(); }
1363 29162 : void setInt32(int32_t i) { value().setInt32(i); }
1364 0 : void setDouble(double d) { value().setDouble(d); }
1365 0 : void setNaN() { setDouble(JS::GenericNaN()); }
1366 30979 : void setBoolean(bool b) { value().setBoolean(b); }
1367 41 : void setMagic(JSWhyMagic why) { value().setMagic(why); }
1368 4046 : bool setNumber(uint32_t ui) { return value().setNumber(ui); }
1369 17329 : bool setNumber(double d) { return value().setNumber(d); }
1370 24664 : void setString(JSString* str) { this->value().setString(str); }
1371 198 : void setSymbol(JS::Symbol* sym) { this->value().setSymbol(sym); }
1372 72940 : void setObject(JSObject& obj) { this->value().setObject(obj); }
1373 8923 : void setObjectOrNull(JSObject* arg) { this->value().setObjectOrNull(arg); }
1374 : void setPrivate(void* ptr) { this->value().setPrivate(ptr); }
1375 : void setPrivateUint32(uint32_t ui) { this->value().setPrivateUint32(ui); }
1376 : void setPrivateGCThing(js::gc::Cell* cell) { this->value().setPrivateGCThing(cell); }
1377 : };
1378 :
1379 : /*
1380 : * Augment the generic Heap<T> interface when T = Value with
1381 : * type-querying, value-extracting, and mutating operations.
1382 : */
1383 : template <typename Wrapper>
1384 2112 : class HeapBase<JS::Value, Wrapper> : public WrappedPtrOperations<JS::Value, Wrapper>
1385 : {
1386 16 : void setBarriered(const JS::Value& v) {
1387 16 : *static_cast<JS::Heap<JS::Value>*>(this) = v;
1388 16 : }
1389 :
1390 : public:
1391 0 : void setNull() { setBarriered(JS::NullValue()); }
1392 8 : void setUndefined() { setBarriered(JS::UndefinedValue()); }
1393 : void setInt32(int32_t i) { setBarriered(JS::Int32Value(i)); }
1394 : void setDouble(double d) { setBarriered(JS::DoubleValue(d)); }
1395 : void setNaN() { setDouble(JS::GenericNaN()); }
1396 : void setBoolean(bool b) { setBarriered(JS::BooleanValue(b)); }
1397 : void setMagic(JSWhyMagic why) { setBarriered(JS::MagicValue(why)); }
1398 0 : void setString(JSString* str) { setBarriered(JS::StringValue(str)); }
1399 : void setSymbol(JS::Symbol* sym) { setBarriered(JS::SymbolValue(sym)); }
1400 8 : void setObject(JSObject& obj) { setBarriered(JS::ObjectValue(obj)); }
1401 : void setPrivateGCThing(js::gc::Cell* cell) { setBarriered(JS::PrivateGCThingValue(cell)); }
1402 :
1403 : bool setNumber(uint32_t ui) {
1404 : if (ui > JSVAL_INT_MAX) {
1405 : setDouble((double)ui);
1406 : return false;
1407 : } else {
1408 : setInt32((int32_t)ui);
1409 : return true;
1410 : }
1411 : }
1412 :
1413 : bool setNumber(double d) {
1414 : int32_t i;
1415 : if (mozilla::NumberIsInt32(d, &i)) {
1416 : setInt32(i);
1417 : return true;
1418 : }
1419 :
1420 : setDouble(d);
1421 : return false;
1422 : }
1423 :
1424 : void setObjectOrNull(JSObject* arg) {
1425 : if (arg)
1426 : setObject(*arg);
1427 : else
1428 : setNull();
1429 : }
1430 : };
1431 :
1432 : /*
1433 : * If the Value is a GC pointer type, convert to that type and call |f| with
1434 : * the pointer. If the Value is not a GC type, calls F::defaultValue.
1435 : */
1436 : template <typename F, typename... Args>
1437 : auto
1438 342712 : DispatchTyped(F f, const JS::Value& val, Args&&... args)
1439 : -> decltype(f(static_cast<JSObject*>(nullptr), mozilla::Forward<Args>(args)...))
1440 : {
1441 342712 : if (val.isString())
1442 10330 : return f(val.toString(), mozilla::Forward<Args>(args)...);
1443 332383 : if (val.isObject())
1444 68010 : return f(&val.toObject(), mozilla::Forward<Args>(args)...);
1445 264373 : if (val.isSymbol())
1446 3 : return f(val.toSymbol(), mozilla::Forward<Args>(args)...);
1447 264369 : if (MOZ_UNLIKELY(val.isPrivateGCThing()))
1448 1143 : return DispatchTyped(f, val.toGCCellPtr(), mozilla::Forward<Args>(args)...);
1449 263226 : MOZ_ASSERT(!val.isGCThing());
1450 263226 : return F::defaultValue(val);
1451 : }
1452 :
1453 248851 : template <class S> struct VoidDefaultAdaptor { static void defaultValue(const S&) {} };
1454 15675 : template <class S> struct IdentityDefaultAdaptor { static S defaultValue(const S& v) {return v;} };
1455 0 : template <class S, bool v> struct BoolDefaultAdaptor { static bool defaultValue(const S&) { return v; } };
1456 :
1457 : } // namespace js
1458 :
1459 : #ifdef DEBUG
1460 : namespace JS {
1461 :
1462 : MOZ_ALWAYS_INLINE bool
1463 759566 : ValueIsNotGray(const Value& value)
1464 : {
1465 759566 : if (!value.isGCThing())
1466 333438 : return true;
1467 :
1468 426131 : return CellIsNotGray(value.toGCThing());
1469 : }
1470 :
1471 : MOZ_ALWAYS_INLINE bool
1472 : ValueIsNotGray(const Heap<Value>& value)
1473 : {
1474 : return ValueIsNotGray(value.unbarrieredGet());
1475 : }
1476 :
1477 : } // namespace JS
1478 : #endif
1479 :
1480 : /************************************************************************/
1481 :
1482 : namespace JS {
1483 :
1484 : extern JS_PUBLIC_DATA(const HandleValue) NullHandleValue;
1485 : extern JS_PUBLIC_DATA(const HandleValue) UndefinedHandleValue;
1486 : extern JS_PUBLIC_DATA(const HandleValue) TrueHandleValue;
1487 : extern JS_PUBLIC_DATA(const HandleValue) FalseHandleValue;
1488 :
1489 : } // namespace JS
1490 :
1491 : #endif /* js_Value_h */
|