| /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- |
| * vim: set ts=8 sts=4 et sw=4 tw=99: |
| * This Source Code Form is subject to the terms of the Mozilla Public |
| * License, v. 2.0. If a copy of the MPL was not distributed with this |
| * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
| |
| /* JS::Value implementation. */ |
| |
| #ifndef js_Value_h |
| #define js_Value_h |
| |
| #include "mozilla/Attributes.h" |
| #include "mozilla/FloatingPoint.h" |
| #include "mozilla/Likely.h" |
| |
| #include <limits> /* for std::numeric_limits */ |
| |
| #include "js-config.h" |
| #include "jstypes.h" |
| |
| #include "js/GCAPI.h" |
| #include "js/RootingAPI.h" |
| #include "js/Utility.h" |
| |
| namespace JS { class Value; } |
| |
| /* JS::Value can store a full int32_t. */ |
| #define JSVAL_INT_BITS 32 |
| #define JSVAL_INT_MIN ((int32_t)0x80000000) |
| #define JSVAL_INT_MAX ((int32_t)0x7fffffff) |
| |
| /* |
| * Try to get jsvals 64-bit aligned. We could almost assert that all values are |
| * aligned, but MSVC and GCC occasionally break alignment. |
| */ |
| #if defined(__GNUC__) || defined(__xlc__) || defined(__xlC__) |
| # define JSVAL_ALIGNMENT __attribute__((aligned (8))) |
| #elif defined(_MSC_VER) |
| /* |
| * Structs can be aligned with MSVC, but not if they are used as parameters, |
| * so we just don't try to align. |
| */ |
| # define JSVAL_ALIGNMENT |
| #elif defined(__SUNPRO_C) || defined(__SUNPRO_CC) |
| # define JSVAL_ALIGNMENT |
| #elif defined(__HP_cc) || defined(__HP_aCC) |
| # define JSVAL_ALIGNMENT |
| #endif |
| |
| #if defined(JS_PUNBOX64) |
| # define JSVAL_TAG_SHIFT 47 |
| #endif |
| |
| /* |
| * We try to use enums so that printing a jsval_layout in the debugger shows |
| * nice symbolic type tags, however we can only do this when we can force the |
| * underlying type of the enum to be the desired size. |
| */ |
| #if !defined(__SUNPRO_CC) && !defined(__xlC__) |
| |
| #if defined(_MSC_VER) |
| # define JS_ENUM_HEADER(id, type) enum id : type |
| # define JS_ENUM_FOOTER(id) |
| #else |
| # define JS_ENUM_HEADER(id, type) enum id |
| # define JS_ENUM_FOOTER(id) __attribute__((packed)) |
| #endif |
| |
| /* Remember to propagate changes to the C defines below. */ |
| JS_ENUM_HEADER(JSValueType, uint8_t) |
| { |
| JSVAL_TYPE_DOUBLE = 0x00, |
| JSVAL_TYPE_INT32 = 0x01, |
| JSVAL_TYPE_UNDEFINED = 0x02, |
| JSVAL_TYPE_BOOLEAN = 0x03, |
| JSVAL_TYPE_MAGIC = 0x04, |
| JSVAL_TYPE_STRING = 0x05, |
| JSVAL_TYPE_SYMBOL = 0x06, |
| JSVAL_TYPE_NULL = 0x07, |
| JSVAL_TYPE_OBJECT = 0x08, |
| |
| /* These never appear in a jsval; they are only provided as an out-of-band value. */ |
| JSVAL_TYPE_UNKNOWN = 0x20, |
| JSVAL_TYPE_MISSING = 0x21 |
| } JS_ENUM_FOOTER(JSValueType); |
| |
| static_assert(sizeof(JSValueType) == 1, |
| "compiler typed enum support is apparently buggy"); |
| |
| #if defined(JS_NUNBOX32) |
| |
| /* Remember to propagate changes to the C defines below. */ |
| JS_ENUM_HEADER(JSValueTag, uint32_t) |
| { |
| JSVAL_TAG_CLEAR = 0xFFFFFF80, |
| JSVAL_TAG_INT32 = JSVAL_TAG_CLEAR | JSVAL_TYPE_INT32, |
| JSVAL_TAG_UNDEFINED = JSVAL_TAG_CLEAR | JSVAL_TYPE_UNDEFINED, |
| JSVAL_TAG_STRING = JSVAL_TAG_CLEAR | JSVAL_TYPE_STRING, |
| JSVAL_TAG_SYMBOL = JSVAL_TAG_CLEAR | JSVAL_TYPE_SYMBOL, |
| JSVAL_TAG_BOOLEAN = JSVAL_TAG_CLEAR | JSVAL_TYPE_BOOLEAN, |
| JSVAL_TAG_MAGIC = JSVAL_TAG_CLEAR | JSVAL_TYPE_MAGIC, |
| JSVAL_TAG_NULL = JSVAL_TAG_CLEAR | JSVAL_TYPE_NULL, |
| JSVAL_TAG_OBJECT = JSVAL_TAG_CLEAR | JSVAL_TYPE_OBJECT |
| } JS_ENUM_FOOTER(JSValueTag); |
| |
| static_assert(sizeof(JSValueTag) == sizeof(uint32_t), |
| "compiler typed enum support is apparently buggy"); |
| |
| #elif defined(JS_PUNBOX64) |
| |
| /* Remember to propagate changes to the C defines below. */ |
| JS_ENUM_HEADER(JSValueTag, uint32_t) |
| { |
| JSVAL_TAG_MAX_DOUBLE = 0x1FFF0, |
| JSVAL_TAG_INT32 = JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_INT32, |
| JSVAL_TAG_UNDEFINED = JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_UNDEFINED, |
| JSVAL_TAG_STRING = JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_STRING, |
| JSVAL_TAG_SYMBOL = JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_SYMBOL, |
| JSVAL_TAG_BOOLEAN = JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_BOOLEAN, |
| JSVAL_TAG_MAGIC = JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_MAGIC, |
| JSVAL_TAG_NULL = JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_NULL, |
| JSVAL_TAG_OBJECT = JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_OBJECT |
| } JS_ENUM_FOOTER(JSValueTag); |
| |
| static_assert(sizeof(JSValueTag) == sizeof(uint32_t), |
| "compiler typed enum support is apparently buggy"); |
| |
| JS_ENUM_HEADER(JSValueShiftedTag, uint64_t) |
| { |
| JSVAL_SHIFTED_TAG_MAX_DOUBLE = ((((uint64_t)JSVAL_TAG_MAX_DOUBLE) << JSVAL_TAG_SHIFT) | 0xFFFFFFFF), |
| JSVAL_SHIFTED_TAG_INT32 = (((uint64_t)JSVAL_TAG_INT32) << JSVAL_TAG_SHIFT), |
| JSVAL_SHIFTED_TAG_UNDEFINED = (((uint64_t)JSVAL_TAG_UNDEFINED) << JSVAL_TAG_SHIFT), |
| JSVAL_SHIFTED_TAG_STRING = (((uint64_t)JSVAL_TAG_STRING) << JSVAL_TAG_SHIFT), |
| JSVAL_SHIFTED_TAG_SYMBOL = (((uint64_t)JSVAL_TAG_SYMBOL) << JSVAL_TAG_SHIFT), |
| JSVAL_SHIFTED_TAG_BOOLEAN = (((uint64_t)JSVAL_TAG_BOOLEAN) << JSVAL_TAG_SHIFT), |
| JSVAL_SHIFTED_TAG_MAGIC = (((uint64_t)JSVAL_TAG_MAGIC) << JSVAL_TAG_SHIFT), |
| JSVAL_SHIFTED_TAG_NULL = (((uint64_t)JSVAL_TAG_NULL) << JSVAL_TAG_SHIFT), |
| JSVAL_SHIFTED_TAG_OBJECT = (((uint64_t)JSVAL_TAG_OBJECT) << JSVAL_TAG_SHIFT) |
| } JS_ENUM_FOOTER(JSValueShiftedTag); |
| |
| static_assert(sizeof(JSValueShiftedTag) == sizeof(uint64_t), |
| "compiler typed enum support is apparently buggy"); |
| |
| #endif |
| |
| /* |
| * All our supported compilers implement C++11 |enum Foo : T| syntax, so don't |
| * expose these macros. (This macro exists *only* because gcc bug 51242 |
| * <https://gcc.gnu.org/bugzilla/show_bug.cgi?id=51242> makes bit-fields of |
| * typed enums trigger a warning that can't be turned off. Don't expose it |
| * beyond this file!) |
| */ |
| #undef JS_ENUM_HEADER |
| #undef JS_ENUM_FOOTER |
| |
| #else /* !defined(__SUNPRO_CC) && !defined(__xlC__) */ |
| |
| typedef uint8_t JSValueType; |
| #define JSVAL_TYPE_DOUBLE ((uint8_t)0x00) |
| #define JSVAL_TYPE_INT32 ((uint8_t)0x01) |
| #define JSVAL_TYPE_UNDEFINED ((uint8_t)0x02) |
| #define JSVAL_TYPE_BOOLEAN ((uint8_t)0x03) |
| #define JSVAL_TYPE_MAGIC ((uint8_t)0x04) |
| #define JSVAL_TYPE_STRING ((uint8_t)0x05) |
| #define JSVAL_TYPE_SYMBOL ((uint8_t)0x06) |
| #define JSVAL_TYPE_NULL ((uint8_t)0x07) |
| #define JSVAL_TYPE_OBJECT ((uint8_t)0x08) |
| #define JSVAL_TYPE_UNKNOWN ((uint8_t)0x20) |
| |
| #if defined(JS_NUNBOX32) |
| |
| typedef uint32_t JSValueTag; |
| #define JSVAL_TAG_CLEAR ((uint32_t)(0xFFFFFF80)) |
| #define JSVAL_TAG_INT32 ((uint32_t)(JSVAL_TAG_CLEAR | JSVAL_TYPE_INT32)) |
| #define JSVAL_TAG_UNDEFINED ((uint32_t)(JSVAL_TAG_CLEAR | JSVAL_TYPE_UNDEFINED)) |
| #define JSVAL_TAG_STRING ((uint32_t)(JSVAL_TAG_CLEAR | JSVAL_TYPE_STRING)) |
| #define JSVAL_TAG_SYMBOL ((uint32_t)(JSVAL_TAG_CLEAR | JSVAL_TYPE_SYMBOL)) |
| #define JSVAL_TAG_BOOLEAN ((uint32_t)(JSVAL_TAG_CLEAR | JSVAL_TYPE_BOOLEAN)) |
| #define JSVAL_TAG_MAGIC ((uint32_t)(JSVAL_TAG_CLEAR | JSVAL_TYPE_MAGIC)) |
| #define JSVAL_TAG_NULL ((uint32_t)(JSVAL_TAG_CLEAR | JSVAL_TYPE_NULL)) |
| #define JSVAL_TAG_OBJECT ((uint32_t)(JSVAL_TAG_CLEAR | JSVAL_TYPE_OBJECT)) |
| |
| #elif defined(JS_PUNBOX64) |
| |
| typedef uint32_t JSValueTag; |
| #define JSVAL_TAG_MAX_DOUBLE ((uint32_t)(0x1FFF0)) |
| #define JSVAL_TAG_INT32 (uint32_t)(JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_INT32) |
| #define JSVAL_TAG_UNDEFINED (uint32_t)(JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_UNDEFINED) |
| #define JSVAL_TAG_STRING (uint32_t)(JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_STRING) |
| #define JSVAL_TAG_SYMBOL (uint32_t)(JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_SYMBOL) |
| #define JSVAL_TAG_BOOLEAN (uint32_t)(JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_BOOLEAN) |
| #define JSVAL_TAG_MAGIC (uint32_t)(JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_MAGIC) |
| #define JSVAL_TAG_NULL (uint32_t)(JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_NULL) |
| #define JSVAL_TAG_OBJECT (uint32_t)(JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_OBJECT) |
| |
| typedef uint64_t JSValueShiftedTag; |
| #define JSVAL_SHIFTED_TAG_MAX_DOUBLE ((((uint64_t)JSVAL_TAG_MAX_DOUBLE) << JSVAL_TAG_SHIFT) | 0xFFFFFFFF) |
| #define JSVAL_SHIFTED_TAG_INT32 (((uint64_t)JSVAL_TAG_INT32) << JSVAL_TAG_SHIFT) |
| #define JSVAL_SHIFTED_TAG_UNDEFINED (((uint64_t)JSVAL_TAG_UNDEFINED) << JSVAL_TAG_SHIFT) |
| #define JSVAL_SHIFTED_TAG_STRING (((uint64_t)JSVAL_TAG_STRING) << JSVAL_TAG_SHIFT) |
| #define JSVAL_SHIFTED_TAG_SYMBOL (((uint64_t)JSVAL_TAG_SYMBOL) << JSVAL_TAG_SHIFT) |
| #define JSVAL_SHIFTED_TAG_BOOLEAN (((uint64_t)JSVAL_TAG_BOOLEAN) << JSVAL_TAG_SHIFT) |
| #define JSVAL_SHIFTED_TAG_MAGIC (((uint64_t)JSVAL_TAG_MAGIC) << JSVAL_TAG_SHIFT) |
| #define JSVAL_SHIFTED_TAG_NULL (((uint64_t)JSVAL_TAG_NULL) << JSVAL_TAG_SHIFT) |
| #define JSVAL_SHIFTED_TAG_OBJECT (((uint64_t)JSVAL_TAG_OBJECT) << JSVAL_TAG_SHIFT) |
| |
| #endif /* JS_PUNBOX64 */ |
| #endif /* !defined(__SUNPRO_CC) && !defined(__xlC__) */ |
| |
| #if defined(JS_NUNBOX32) |
| |
| #define JSVAL_TYPE_TO_TAG(type) ((JSValueTag)(JSVAL_TAG_CLEAR | (type))) |
| |
| #define JSVAL_LOWER_INCL_TAG_OF_OBJ_OR_NULL_SET JSVAL_TAG_NULL |
| #define JSVAL_UPPER_EXCL_TAG_OF_PRIMITIVE_SET JSVAL_TAG_OBJECT |
| #define JSVAL_UPPER_INCL_TAG_OF_NUMBER_SET JSVAL_TAG_INT32 |
| #define JSVAL_LOWER_INCL_TAG_OF_GCTHING_SET JSVAL_TAG_STRING |
| |
| #elif defined(JS_PUNBOX64) |
| |
| #define JSVAL_PAYLOAD_MASK 0x00007FFFFFFFFFFFLL |
| #define JSVAL_TAG_MASK 0xFFFF800000000000LL |
| #define JSVAL_TYPE_TO_TAG(type) ((JSValueTag)(JSVAL_TAG_MAX_DOUBLE | (type))) |
| #define JSVAL_TYPE_TO_SHIFTED_TAG(type) (((uint64_t)JSVAL_TYPE_TO_TAG(type)) << JSVAL_TAG_SHIFT) |
| |
| #define JSVAL_LOWER_INCL_TAG_OF_OBJ_OR_NULL_SET JSVAL_TAG_NULL |
| #define JSVAL_UPPER_EXCL_TAG_OF_PRIMITIVE_SET JSVAL_TAG_OBJECT |
| #define JSVAL_UPPER_INCL_TAG_OF_NUMBER_SET JSVAL_TAG_INT32 |
| #define JSVAL_LOWER_INCL_TAG_OF_GCTHING_SET JSVAL_TAG_STRING |
| |
| #define JSVAL_LOWER_INCL_SHIFTED_TAG_OF_OBJ_OR_NULL_SET JSVAL_SHIFTED_TAG_NULL |
| #define JSVAL_UPPER_EXCL_SHIFTED_TAG_OF_PRIMITIVE_SET JSVAL_SHIFTED_TAG_OBJECT |
| #define JSVAL_UPPER_EXCL_SHIFTED_TAG_OF_NUMBER_SET JSVAL_SHIFTED_TAG_UNDEFINED |
| #define JSVAL_LOWER_INCL_SHIFTED_TAG_OF_GCTHING_SET JSVAL_SHIFTED_TAG_STRING |
| |
| #endif /* JS_PUNBOX64 */ |
| |
| typedef enum JSWhyMagic |
| { |
| /** a hole in a native object's elements */ |
| JS_ELEMENTS_HOLE, |
| |
| /** there is not a pending iterator value */ |
| JS_NO_ITER_VALUE, |
| |
| /** exception value thrown when closing a generator */ |
| JS_GENERATOR_CLOSING, |
| |
| /** compiler sentinel value */ |
| JS_NO_CONSTANT, |
| |
| /** used in debug builds to catch tracing errors */ |
| JS_THIS_POISON, |
| |
| /** used in debug builds to catch tracing errors */ |
| JS_ARG_POISON, |
| |
| /** an empty subnode in the AST serializer */ |
| JS_SERIALIZE_NO_NODE, |
| |
| /** lazy arguments value on the stack */ |
| JS_LAZY_ARGUMENTS, |
| |
| /** optimized-away 'arguments' value */ |
| JS_OPTIMIZED_ARGUMENTS, |
| |
| /** magic value passed to natives to indicate construction */ |
| JS_IS_CONSTRUCTING, |
| |
| /** arguments.callee has been overwritten */ |
| JS_OVERWRITTEN_CALLEE, |
| |
| /** value of static block object slot */ |
| JS_BLOCK_NEEDS_CLONE, |
| |
| /** see class js::HashableValue */ |
| JS_HASH_KEY_EMPTY, |
| |
| /** error while running Ion code */ |
| JS_ION_ERROR, |
| |
| /** missing recover instruction result */ |
| JS_ION_BAILOUT, |
| |
| /** optimized out slot */ |
| JS_OPTIMIZED_OUT, |
| |
| /** uninitialized lexical bindings that produce ReferenceError on touch. */ |
| JS_UNINITIALIZED_LEXICAL, |
| |
| /** for local use */ |
| JS_GENERIC_MAGIC, |
| |
| JS_WHY_MAGIC_COUNT |
| } JSWhyMagic; |
| |
| #if defined(IS_LITTLE_ENDIAN) |
| # if defined(JS_NUNBOX32) |
| typedef union jsval_layout |
| { |
| uint64_t asBits; |
| struct { |
| union { |
| int32_t i32; |
| uint32_t u32; |
| uint32_t boo; // Don't use |bool| -- it must be four bytes. |
| JSString* str; |
| JS::Symbol* sym; |
| JSObject* obj; |
| js::gc::Cell* cell; |
| void* ptr; |
| JSWhyMagic why; |
| size_t word; |
| uintptr_t uintptr; |
| } payload; |
| JSValueTag tag; |
| } s; |
| double asDouble; |
| void* asPtr; |
| } JSVAL_ALIGNMENT jsval_layout; |
| # elif defined(JS_PUNBOX64) |
| typedef union jsval_layout |
| { |
| uint64_t asBits; |
| #if !defined(_WIN64) |
| /* MSVC does not pack these correctly :-( */ |
| struct { |
| uint64_t payload47 : 47; |
| JSValueTag tag : 17; |
| } debugView; |
| #endif |
| struct { |
| union { |
| int32_t i32; |
| uint32_t u32; |
| JSWhyMagic why; |
| } payload; |
| } s; |
| double asDouble; |
| void* asPtr; |
| size_t asWord; |
| uintptr_t asUIntPtr; |
| } JSVAL_ALIGNMENT jsval_layout; |
| # endif /* JS_PUNBOX64 */ |
| #else /* defined(IS_LITTLE_ENDIAN) */ |
| # if defined(JS_NUNBOX32) |
| typedef union jsval_layout |
| { |
| uint64_t asBits; |
| struct { |
| JSValueTag tag; |
| union { |
| int32_t i32; |
| uint32_t u32; |
| uint32_t boo; // Don't use |bool| -- it must be four bytes. |
| JSString* str; |
| JS::Symbol* sym; |
| JSObject* obj; |
| js::gc::Cell* cell; |
| void* ptr; |
| JSWhyMagic why; |
| size_t word; |
| uintptr_t uintptr; |
| } payload; |
| } s; |
| double asDouble; |
| void* asPtr; |
| } JSVAL_ALIGNMENT jsval_layout; |
| # elif defined(JS_PUNBOX64) |
| typedef union jsval_layout |
| { |
| uint64_t asBits; |
| struct { |
| JSValueTag tag : 17; |
| uint64_t payload47 : 47; |
| } debugView; |
| struct { |
| uint32_t padding; |
| union { |
| int32_t i32; |
| uint32_t u32; |
| JSWhyMagic why; |
| } payload; |
| } s; |
| double asDouble; |
| void* asPtr; |
| size_t asWord; |
| uintptr_t asUIntPtr; |
| } JSVAL_ALIGNMENT jsval_layout; |
| # endif /* JS_PUNBOX64 */ |
| #endif /* defined(IS_LITTLE_ENDIAN) */ |
| |
| JS_STATIC_ASSERT(sizeof(jsval_layout) == 8); |
| |
| /* |
| * For codesize purposes on some platforms, it's important that the |
| * compiler know that JS::Values constructed from constant values can be |
| * folded to constant bit patterns at compile time, rather than |
| * constructed at runtime. Doing this requires a fair amount of C++11 |
| * features, which are not supported on all of our compilers. Set up |
| * some defines and helper macros in an attempt to confine the ugliness |
| * here, rather than scattering it all about the file. The important |
| * features are: |
| * |
| * - constexpr; |
| * - defaulted functions; |
| * - C99-style designated initializers. |
| */ |
| #if defined(__clang__) |
| # if __has_feature(cxx_constexpr) && __has_feature(cxx_defaulted_functions) |
| # define JS_VALUE_IS_CONSTEXPR |
| # endif |
| #elif defined(__GNUC__) |
| /* |
| * We need 4.5 for defaulted functions, 4.6 for constexpr, 4.7 because 4.6 |
| * doesn't understand |(X) { .field = ... }| syntax, and 4.7.3 because |
| * versions prior to that have bugs in the C++ front-end that cause crashes. |
| */ |
| # if MOZ_GCC_VERSION_AT_LEAST(4, 7, 3) |
| # define JS_VALUE_IS_CONSTEXPR |
| # endif |
| #endif |
| |
| #if defined(JS_VALUE_IS_CONSTEXPR) |
| # define JS_RETURN_LAYOUT_FROM_BITS(BITS) \ |
| return (jsval_layout) { .asBits = (BITS) } |
| # define JS_VALUE_CONSTEXPR MOZ_CONSTEXPR |
| # define JS_VALUE_CONSTEXPR_VAR MOZ_CONSTEXPR_VAR |
| #else |
| # define JS_RETURN_LAYOUT_FROM_BITS(BITS) \ |
| jsval_layout l; \ |
| l.asBits = (BITS); \ |
| return l; |
| # define JS_VALUE_CONSTEXPR |
| # define JS_VALUE_CONSTEXPR_VAR const |
| #endif |
| |
| #if defined(JS_NUNBOX32) |
| |
| /* |
| * N.B. GCC, in some but not all cases, chooses to emit signed comparison of |
| * JSValueTag even though its underlying type has been forced to be uint32_t. |
| * Thus, all comparisons should explicitly cast operands to uint32_t. |
| */ |
| |
| static inline JS_VALUE_CONSTEXPR jsval_layout |
| BUILD_JSVAL(JSValueTag tag, uint32_t payload) |
| { |
| JS_RETURN_LAYOUT_FROM_BITS((((uint64_t)(uint32_t)tag) << 32) | payload); |
| } |
| |
| static inline bool |
| JSVAL_IS_DOUBLE_IMPL(jsval_layout l) |
| { |
| return (uint32_t)l.s.tag <= (uint32_t)JSVAL_TAG_CLEAR; |
| } |
| |
| static inline jsval_layout |
| DOUBLE_TO_JSVAL_IMPL(double d) |
| { |
| jsval_layout l; |
| l.asDouble = d; |
| MOZ_ASSERT(JSVAL_IS_DOUBLE_IMPL(l)); |
| return l; |
| } |
| |
| static inline bool |
| JSVAL_IS_INT32_IMPL(jsval_layout l) |
| { |
| return l.s.tag == JSVAL_TAG_INT32; |
| } |
| |
| static inline int32_t |
| JSVAL_TO_INT32_IMPL(jsval_layout l) |
| { |
| return l.s.payload.i32; |
| } |
| |
| static inline JS_VALUE_CONSTEXPR jsval_layout |
| INT32_TO_JSVAL_IMPL(int32_t i) |
| { |
| #if defined(JS_VALUE_IS_CONSTEXPR) |
| return BUILD_JSVAL(JSVAL_TAG_INT32, i); |
| #else |
| jsval_layout l; |
| l.s.tag = JSVAL_TAG_INT32; |
| l.s.payload.i32 = i; |
| return l; |
| #endif |
| } |
| |
| static inline bool |
| JSVAL_IS_NUMBER_IMPL(jsval_layout l) |
| { |
| JSValueTag tag = l.s.tag; |
| MOZ_ASSERT(tag != JSVAL_TAG_CLEAR); |
| return (uint32_t)tag <= (uint32_t)JSVAL_UPPER_INCL_TAG_OF_NUMBER_SET; |
| } |
| |
| static inline bool |
| JSVAL_IS_UNDEFINED_IMPL(jsval_layout l) |
| { |
| return l.s.tag == JSVAL_TAG_UNDEFINED; |
| } |
| |
| static inline bool |
| JSVAL_IS_STRING_IMPL(jsval_layout l) |
| { |
| return l.s.tag == JSVAL_TAG_STRING; |
| } |
| |
| static inline jsval_layout |
| STRING_TO_JSVAL_IMPL(JSString* str) |
| { |
| jsval_layout l; |
| MOZ_ASSERT(uintptr_t(str) > 0x1000); |
| l.s.tag = JSVAL_TAG_STRING; |
| l.s.payload.str = str; |
| return l; |
| } |
| |
| static inline JSString* |
| JSVAL_TO_STRING_IMPL(jsval_layout l) |
| { |
| return l.s.payload.str; |
| } |
| |
| static inline bool |
| JSVAL_IS_SYMBOL_IMPL(jsval_layout l) |
| { |
| return l.s.tag == JSVAL_TAG_SYMBOL; |
| } |
| |
| static inline jsval_layout |
| SYMBOL_TO_JSVAL_IMPL(JS::Symbol* sym) |
| { |
| jsval_layout l; |
| MOZ_ASSERT(uintptr_t(sym) > 0x1000); |
| l.s.tag = JSVAL_TAG_SYMBOL; |
| l.s.payload.sym = sym; |
| return l; |
| } |
| |
| static inline JS::Symbol* |
| JSVAL_TO_SYMBOL_IMPL(jsval_layout l) |
| { |
| return l.s.payload.sym; |
| } |
| |
| static inline bool |
| JSVAL_IS_BOOLEAN_IMPL(jsval_layout l) |
| { |
| return l.s.tag == JSVAL_TAG_BOOLEAN; |
| } |
| |
| static inline bool |
| JSVAL_TO_BOOLEAN_IMPL(jsval_layout l) |
| { |
| return l.s.payload.boo; |
| } |
| |
| static inline jsval_layout |
| BOOLEAN_TO_JSVAL_IMPL(bool b) |
| { |
| jsval_layout l; |
| l.s.tag = JSVAL_TAG_BOOLEAN; |
| l.s.payload.boo = b; |
| return l; |
| } |
| |
| static inline bool |
| JSVAL_IS_MAGIC_IMPL(jsval_layout l) |
| { |
| return l.s.tag == JSVAL_TAG_MAGIC; |
| } |
| |
| static inline bool |
| JSVAL_IS_OBJECT_IMPL(jsval_layout l) |
| { |
| return l.s.tag == JSVAL_TAG_OBJECT; |
| } |
| |
| static inline bool |
| JSVAL_IS_PRIMITIVE_IMPL(jsval_layout l) |
| { |
| return (uint32_t)l.s.tag < (uint32_t)JSVAL_UPPER_EXCL_TAG_OF_PRIMITIVE_SET; |
| } |
| |
| static inline bool |
| JSVAL_IS_OBJECT_OR_NULL_IMPL(jsval_layout l) |
| { |
| MOZ_ASSERT((uint32_t)l.s.tag <= (uint32_t)JSVAL_TAG_OBJECT); |
| return (uint32_t)l.s.tag >= (uint32_t)JSVAL_LOWER_INCL_TAG_OF_OBJ_OR_NULL_SET; |
| } |
| |
| static inline JSObject* |
| JSVAL_TO_OBJECT_IMPL(jsval_layout l) |
| { |
| return l.s.payload.obj; |
| } |
| |
| static inline jsval_layout |
| OBJECT_TO_JSVAL_IMPL(JSObject* obj) |
| { |
| jsval_layout l; |
| MOZ_ASSERT(uintptr_t(obj) > 0x1000 || uintptr_t(obj) == 0x42); |
| l.s.tag = JSVAL_TAG_OBJECT; |
| l.s.payload.obj = obj; |
| return l; |
| } |
| |
| static inline bool |
| JSVAL_IS_NULL_IMPL(jsval_layout l) |
| { |
| return l.s.tag == JSVAL_TAG_NULL; |
| } |
| |
| static inline jsval_layout |
| PRIVATE_PTR_TO_JSVAL_IMPL(void* ptr) |
| { |
| jsval_layout l; |
| MOZ_ASSERT(((uint32_t)ptr & 1) == 0); |
| l.s.tag = (JSValueTag)0; |
| l.s.payload.ptr = ptr; |
| MOZ_ASSERT(JSVAL_IS_DOUBLE_IMPL(l)); |
| return l; |
| } |
| |
| static inline void* |
| JSVAL_TO_PRIVATE_PTR_IMPL(jsval_layout l) |
| { |
| return l.s.payload.ptr; |
| } |
| |
| static inline bool |
| JSVAL_IS_GCTHING_IMPL(jsval_layout l) |
| { |
| /* gcc sometimes generates signed < without explicit casts. */ |
| return (uint32_t)l.s.tag >= (uint32_t)JSVAL_LOWER_INCL_TAG_OF_GCTHING_SET; |
| } |
| |
| static inline js::gc::Cell* |
| JSVAL_TO_GCTHING_IMPL(jsval_layout l) |
| { |
| return l.s.payload.cell; |
| } |
| |
| static inline uint32_t |
| JSVAL_TRACE_KIND_IMPL(jsval_layout l) |
| { |
| static_assert((JSVAL_TAG_STRING & 0x03) == size_t(JS::TraceKind::String), |
| "Value type tags must correspond with JS::TraceKinds."); |
| static_assert((JSVAL_TAG_SYMBOL & 0x03) == size_t(JS::TraceKind::Symbol), |
| "Value type tags must correspond with JS::TraceKinds."); |
| static_assert((JSVAL_TAG_OBJECT & 0x03) == size_t(JS::TraceKind::Object), |
| "Value type tags must correspond with JS::TraceKinds."); |
| return l.s.tag & 0x03; |
| } |
| |
| static inline bool |
| JSVAL_IS_SPECIFIC_INT32_IMPL(jsval_layout l, int32_t i32) |
| { |
| return l.s.tag == JSVAL_TAG_INT32 && l.s.payload.i32 == i32; |
| } |
| |
| static inline bool |
| JSVAL_IS_SPECIFIC_BOOLEAN_IMPL(jsval_layout l, bool b) |
| { |
| return (l.s.tag == JSVAL_TAG_BOOLEAN) && (l.s.payload.boo == uint32_t(b)); |
| } |
| |
| static inline jsval_layout |
| MAGIC_TO_JSVAL_IMPL(JSWhyMagic why) |
| { |
| jsval_layout l; |
| l.s.tag = JSVAL_TAG_MAGIC; |
| l.s.payload.why = why; |
| return l; |
| } |
| |
| static inline jsval_layout |
| MAGIC_UINT32_TO_JSVAL_IMPL(uint32_t payload) |
| { |
| jsval_layout l; |
| l.s.tag = JSVAL_TAG_MAGIC; |
| l.s.payload.u32 = payload; |
| return l; |
| } |
| |
| static inline bool |
| JSVAL_SAME_TYPE_IMPL(jsval_layout lhs, jsval_layout rhs) |
| { |
| JSValueTag ltag = lhs.s.tag, rtag = rhs.s.tag; |
| return ltag == rtag || (ltag < JSVAL_TAG_CLEAR && rtag < JSVAL_TAG_CLEAR); |
| } |
| |
| static inline JSValueType |
| JSVAL_EXTRACT_NON_DOUBLE_TYPE_IMPL(jsval_layout l) |
| { |
| uint32_t type = l.s.tag & 0xF; |
| MOZ_ASSERT(type > JSVAL_TYPE_DOUBLE); |
| return (JSValueType)type; |
| } |
| |
| #elif defined(JS_PUNBOX64) |
| |
| static inline JS_VALUE_CONSTEXPR jsval_layout |
| BUILD_JSVAL(JSValueTag tag, uint64_t payload) |
| { |
| JS_RETURN_LAYOUT_FROM_BITS((((uint64_t)(uint32_t)tag) << JSVAL_TAG_SHIFT) | payload); |
| } |
| |
| static inline bool |
| JSVAL_IS_DOUBLE_IMPL(jsval_layout l) |
| { |
| return l.asBits <= JSVAL_SHIFTED_TAG_MAX_DOUBLE; |
| } |
| |
| static inline jsval_layout |
| DOUBLE_TO_JSVAL_IMPL(double d) |
| { |
| jsval_layout l; |
| l.asDouble = d; |
| MOZ_ASSERT(l.asBits <= JSVAL_SHIFTED_TAG_MAX_DOUBLE); |
| return l; |
| } |
| |
| static inline bool |
| JSVAL_IS_INT32_IMPL(jsval_layout l) |
| { |
| return (uint32_t)(l.asBits >> JSVAL_TAG_SHIFT) == JSVAL_TAG_INT32; |
| } |
| |
| static inline int32_t |
| JSVAL_TO_INT32_IMPL(jsval_layout l) |
| { |
| return (int32_t)l.asBits; |
| } |
| |
| static inline JS_VALUE_CONSTEXPR jsval_layout |
| INT32_TO_JSVAL_IMPL(int32_t i32) |
| { |
| JS_RETURN_LAYOUT_FROM_BITS(((uint64_t)(uint32_t)i32) | JSVAL_SHIFTED_TAG_INT32); |
| } |
| |
| static inline bool |
| JSVAL_IS_NUMBER_IMPL(jsval_layout l) |
| { |
| return l.asBits < JSVAL_UPPER_EXCL_SHIFTED_TAG_OF_NUMBER_SET; |
| } |
| |
| static inline bool |
| JSVAL_IS_UNDEFINED_IMPL(jsval_layout l) |
| { |
| return l.asBits == JSVAL_SHIFTED_TAG_UNDEFINED; |
| } |
| |
| static inline bool |
| JSVAL_IS_STRING_IMPL(jsval_layout l) |
| { |
| return (uint32_t)(l.asBits >> JSVAL_TAG_SHIFT) == JSVAL_TAG_STRING; |
| } |
| |
| static inline jsval_layout |
| STRING_TO_JSVAL_IMPL(JSString* str) |
| { |
| jsval_layout l; |
| uint64_t strBits = (uint64_t)str; |
| MOZ_ASSERT(uintptr_t(str) > 0x1000); |
| MOZ_ASSERT((strBits >> JSVAL_TAG_SHIFT) == 0); |
| l.asBits = strBits | JSVAL_SHIFTED_TAG_STRING; |
| return l; |
| } |
| |
| static inline JSString* |
| JSVAL_TO_STRING_IMPL(jsval_layout l) |
| { |
| return (JSString*)(l.asBits & JSVAL_PAYLOAD_MASK); |
| } |
| |
| static inline bool |
| JSVAL_IS_SYMBOL_IMPL(jsval_layout l) |
| { |
| return (uint32_t)(l.asBits >> JSVAL_TAG_SHIFT) == JSVAL_TAG_SYMBOL; |
| } |
| |
| static inline jsval_layout |
| SYMBOL_TO_JSVAL_IMPL(JS::Symbol* sym) |
| { |
| jsval_layout l; |
| uint64_t symBits = (uint64_t)sym; |
| MOZ_ASSERT(uintptr_t(sym) > 0x1000); |
| MOZ_ASSERT((symBits >> JSVAL_TAG_SHIFT) == 0); |
| l.asBits = symBits | JSVAL_SHIFTED_TAG_SYMBOL; |
| return l; |
| } |
| |
| static inline JS::Symbol* |
| JSVAL_TO_SYMBOL_IMPL(jsval_layout l) |
| { |
| return (JS::Symbol*)(l.asBits & JSVAL_PAYLOAD_MASK); |
| } |
| |
| static inline bool |
| JSVAL_IS_BOOLEAN_IMPL(jsval_layout l) |
| { |
| return (uint32_t)(l.asBits >> JSVAL_TAG_SHIFT) == JSVAL_TAG_BOOLEAN; |
| } |
| |
| static inline bool |
| JSVAL_TO_BOOLEAN_IMPL(jsval_layout l) |
| { |
| return (bool)(l.asBits & JSVAL_PAYLOAD_MASK); |
| } |
| |
| static inline jsval_layout |
| BOOLEAN_TO_JSVAL_IMPL(bool b) |
| { |
| jsval_layout l; |
| l.asBits = ((uint64_t)(uint32_t)b) | JSVAL_SHIFTED_TAG_BOOLEAN; |
| return l; |
| } |
| |
| static inline bool |
| JSVAL_IS_MAGIC_IMPL(jsval_layout l) |
| { |
| return (l.asBits >> JSVAL_TAG_SHIFT) == JSVAL_TAG_MAGIC; |
| } |
| |
| static inline bool |
| JSVAL_IS_PRIMITIVE_IMPL(jsval_layout l) |
| { |
| return l.asBits < JSVAL_UPPER_EXCL_SHIFTED_TAG_OF_PRIMITIVE_SET; |
| } |
| |
| static inline bool |
| JSVAL_IS_OBJECT_IMPL(jsval_layout l) |
| { |
| MOZ_ASSERT((l.asBits >> JSVAL_TAG_SHIFT) <= JSVAL_TAG_OBJECT); |
| return l.asBits >= JSVAL_SHIFTED_TAG_OBJECT; |
| } |
| |
| static inline bool |
| JSVAL_IS_OBJECT_OR_NULL_IMPL(jsval_layout l) |
| { |
| MOZ_ASSERT((l.asBits >> JSVAL_TAG_SHIFT) <= JSVAL_TAG_OBJECT); |
| return l.asBits >= JSVAL_LOWER_INCL_SHIFTED_TAG_OF_OBJ_OR_NULL_SET; |
| } |
| |
| static inline JSObject* |
| JSVAL_TO_OBJECT_IMPL(jsval_layout l) |
| { |
| uint64_t ptrBits = l.asBits & JSVAL_PAYLOAD_MASK; |
| MOZ_ASSERT((ptrBits & 0x7) == 0); |
| return (JSObject*)ptrBits; |
| } |
| |
| static inline jsval_layout |
| OBJECT_TO_JSVAL_IMPL(JSObject* obj) |
| { |
| jsval_layout l; |
| uint64_t objBits = (uint64_t)obj; |
| MOZ_ASSERT(uintptr_t(obj) > 0x1000 || uintptr_t(obj) == 0x42); |
| MOZ_ASSERT((objBits >> JSVAL_TAG_SHIFT) == 0); |
| l.asBits = objBits | JSVAL_SHIFTED_TAG_OBJECT; |
| return l; |
| } |
| |
| static inline bool |
| JSVAL_IS_NULL_IMPL(jsval_layout l) |
| { |
| return l.asBits == JSVAL_SHIFTED_TAG_NULL; |
| } |
| |
| static inline bool |
| JSVAL_IS_GCTHING_IMPL(jsval_layout l) |
| { |
| return l.asBits >= JSVAL_LOWER_INCL_SHIFTED_TAG_OF_GCTHING_SET; |
| } |
| |
| static inline js::gc::Cell* |
| JSVAL_TO_GCTHING_IMPL(jsval_layout l) |
| { |
| uint64_t ptrBits = l.asBits & JSVAL_PAYLOAD_MASK; |
| MOZ_ASSERT((ptrBits & 0x7) == 0); |
| return reinterpret_cast<js::gc::Cell*>(ptrBits); |
| } |
| |
| static inline uint32_t |
| JSVAL_TRACE_KIND_IMPL(jsval_layout l) |
| { |
| static_assert((JSVAL_TAG_STRING & 0x03) == size_t(JS::TraceKind::String), |
| "Value type tags must correspond with JS::TraceKinds."); |
| static_assert((JSVAL_TAG_SYMBOL & 0x03) == size_t(JS::TraceKind::Symbol), |
| "Value type tags must correspond with JS::TraceKinds."); |
| static_assert((JSVAL_TAG_OBJECT & 0x03) == size_t(JS::TraceKind::Object), |
| "Value type tags must correspond with JS::TraceKinds."); |
| return (uint32_t)(l.asBits >> JSVAL_TAG_SHIFT) & 0x03; |
| } |
| |
| static inline jsval_layout |
| PRIVATE_PTR_TO_JSVAL_IMPL(void* ptr) |
| { |
| jsval_layout l; |
| uint64_t ptrBits = (uint64_t)ptr; |
| MOZ_ASSERT((ptrBits & 1) == 0); |
| l.asBits = ptrBits >> 1; |
| MOZ_ASSERT(JSVAL_IS_DOUBLE_IMPL(l)); |
| return l; |
| } |
| |
| static inline void* |
| JSVAL_TO_PRIVATE_PTR_IMPL(jsval_layout l) |
| { |
| MOZ_ASSERT((l.asBits & 0x8000000000000000LL) == 0); |
| return (void*)(l.asBits << 1); |
| } |
| |
| static inline bool |
| JSVAL_IS_SPECIFIC_INT32_IMPL(jsval_layout l, int32_t i32) |
| { |
| return l.asBits == (((uint64_t)(uint32_t)i32) | JSVAL_SHIFTED_TAG_INT32); |
| } |
| |
| static inline bool |
| JSVAL_IS_SPECIFIC_BOOLEAN_IMPL(jsval_layout l, bool b) |
| { |
| return l.asBits == (((uint64_t)(uint32_t)b) | JSVAL_SHIFTED_TAG_BOOLEAN); |
| } |
| |
| static inline jsval_layout |
| MAGIC_TO_JSVAL_IMPL(JSWhyMagic why) |
| { |
| jsval_layout l; |
| l.asBits = ((uint64_t)(uint32_t)why) | JSVAL_SHIFTED_TAG_MAGIC; |
| return l; |
| } |
| |
| static inline jsval_layout |
| MAGIC_UINT32_TO_JSVAL_IMPL(uint32_t payload) |
| { |
| jsval_layout l; |
| l.asBits = ((uint64_t)payload) | JSVAL_SHIFTED_TAG_MAGIC; |
| return l; |
| } |
| |
| static inline bool |
| JSVAL_SAME_TYPE_IMPL(jsval_layout lhs, jsval_layout rhs) |
| { |
| uint64_t lbits = lhs.asBits, rbits = rhs.asBits; |
| return (lbits <= JSVAL_SHIFTED_TAG_MAX_DOUBLE && rbits <= JSVAL_SHIFTED_TAG_MAX_DOUBLE) || |
| (((lbits ^ rbits) & 0xFFFF800000000000LL) == 0); |
| } |
| |
| static inline JSValueType |
| JSVAL_EXTRACT_NON_DOUBLE_TYPE_IMPL(jsval_layout l) |
| { |
| uint64_t type = (l.asBits >> JSVAL_TAG_SHIFT) & 0xF; |
| MOZ_ASSERT(type > JSVAL_TYPE_DOUBLE); |
| return (JSValueType)type; |
| } |
| |
| #endif /* JS_PUNBOX64 */ |
| |
| static inline bool |
| JSVAL_IS_TRACEABLE_IMPL(jsval_layout l) |
| { |
| return JSVAL_IS_GCTHING_IMPL(l) && !JSVAL_IS_NULL_IMPL(l); |
| } |
| |
| #if defined(STARBOARD) && SB_IS(COMPILER_MSVC) |
| // Note that the Value class's data member is private |
| // if !defined(_MSC_VER) && !defined(__sparc) and is public otherwise. |
| #define JSVAL_TO_IMPL(v) ((v).data) |
| #else |
| static inline jsval_layout JSVAL_TO_IMPL(JS::Value v); |
| #endif |
| static inline JS_VALUE_CONSTEXPR JS::Value IMPL_TO_JSVAL(jsval_layout l); |
| |
| namespace JS { |
| |
| static inline JS_VALUE_CONSTEXPR JS::Value UndefinedValue(); |
| |
| /** |
| * Returns a generic quiet NaN value, with all payload bits set to zero. |
| * |
| * Among other properties, this NaN's bit pattern conforms to JS::Value's |
| * bit pattern restrictions. |
| */ |
| static MOZ_ALWAYS_INLINE double |
| GenericNaN() |
| { |
| return mozilla::SpecificNaN<double>(0, 0x8000000000000ULL); |
| } |
| |
| /* MSVC with PGO miscompiles this function. */ |
| #if defined(_MSC_VER) |
| # pragma optimize("g", off) |
| #endif |
| static inline double |
| CanonicalizeNaN(double d) |
| { |
| if (MOZ_UNLIKELY(mozilla::IsNaN(d))) |
| return GenericNaN(); |
| return d; |
| } |
| #if defined(_MSC_VER) |
| # pragma optimize("", on) |
| #endif |
| |
| /** |
| * JS::Value is the interface for a single JavaScript Engine value. A few |
| * general notes on JS::Value: |
| * |
| * - JS::Value has setX() and isX() members for X in |
| * |
| * { Int32, Double, String, Symbol, Boolean, Undefined, Null, Object, Magic } |
| * |
| * JS::Value also contains toX() for each of the non-singleton types. |
| * |
| * - Magic is a singleton type whose payload contains either a JSWhyMagic "reason" for |
| * the magic value or a uint32_t value. By providing JSWhyMagic values when |
| * creating and checking for magic values, it is possible to assert, at |
| * runtime, that only magic values with the expected reason flow through a |
| * particular value. For example, if cx->exception has a magic value, the |
| * reason must be JS_GENERATOR_CLOSING. |
| * |
| * - The JS::Value operations are preferred. The JSVAL_* operations remain for |
| * compatibility; they may be removed at some point. These operations mostly |
| * provide similar functionality. But there are a few key differences. One |
| * is that JS::Value gives null a separate type. |
| * Also, to help prevent mistakenly boxing a nullable JSObject* as an object, |
| * Value::setObject takes a JSObject&. (Conversely, Value::toObject returns a |
| * JSObject&.) A convenience member Value::setObjectOrNull is provided. |
| * |
| * - JSVAL_VOID is the same as the singleton value of the Undefined type. |
| * |
| * - Note that JS::Value is 8 bytes on 32 and 64-bit architectures. Thus, on |
| * 32-bit user code should avoid copying jsval/JS::Value as much as possible, |
| * preferring to pass by const Value&. |
| */ |
| class Value |
| { |
| public: |
| /* |
| * N.B. the default constructor leaves Value unitialized. Adding a default |
| * constructor prevents Value from being stored in a union. |
| */ |
| #if defined(JS_VALUE_IS_CONSTEXPR) |
| Value() = default; |
| Value(const Value& v) = default; |
| #endif |
| |
| /** |
| * Returns false if creating a NumberValue containing the given type would |
| * be lossy, true otherwise. |
| */ |
| template <typename T> |
| static bool isNumberRepresentable(const T t) { |
| return T(double(t)) == t; |
| } |
| |
| /*** Mutators ***/ |
| |
| void setNull() { |
| data.asBits = BUILD_JSVAL(JSVAL_TAG_NULL, 0).asBits; |
| } |
| |
| void setUndefined() { |
| data.asBits = BUILD_JSVAL(JSVAL_TAG_UNDEFINED, 0).asBits; |
| } |
| |
| void setInt32(int32_t i) { |
| data = INT32_TO_JSVAL_IMPL(i); |
| } |
| |
| int32_t& getInt32Ref() { |
| MOZ_ASSERT(isInt32()); |
| return data.s.payload.i32; |
| } |
| |
| void setDouble(double d) { |
| data = DOUBLE_TO_JSVAL_IMPL(d); |
| } |
| |
| void setNaN() { |
| setDouble(GenericNaN()); |
| } |
| |
| double& getDoubleRef() { |
| MOZ_ASSERT(isDouble()); |
| return data.asDouble; |
| } |
| |
| void setString(JSString* str) { |
| data = STRING_TO_JSVAL_IMPL(str); |
| } |
| |
| void setSymbol(JS::Symbol* sym) { |
| data = SYMBOL_TO_JSVAL_IMPL(sym); |
| } |
| |
| void setObject(JSObject& obj) { |
| data = OBJECT_TO_JSVAL_IMPL(&obj); |
| } |
| |
| void setBoolean(bool b) { |
| data = BOOLEAN_TO_JSVAL_IMPL(b); |
| } |
| |
| void setMagic(JSWhyMagic why) { |
| data = MAGIC_TO_JSVAL_IMPL(why); |
| } |
| |
| void setMagicUint32(uint32_t payload) { |
| data = MAGIC_UINT32_TO_JSVAL_IMPL(payload); |
| } |
| |
| bool setNumber(uint32_t ui) { |
| if (ui > JSVAL_INT_MAX) { |
| setDouble((double)ui); |
| return false; |
| } else { |
| setInt32((int32_t)ui); |
| return true; |
| } |
| } |
| |
| bool setNumber(double d) { |
| int32_t i; |
| if (mozilla::NumberIsInt32(d, &i)) { |
| setInt32(i); |
| return true; |
| } |
| |
| setDouble(d); |
| return false; |
| } |
| |
| void setObjectOrNull(JSObject* arg) { |
| if (arg) |
| setObject(*arg); |
| else |
| setNull(); |
| } |
| |
| void swap(Value& rhs) { |
| uint64_t tmp = rhs.data.asBits; |
| rhs.data.asBits = data.asBits; |
| data.asBits = tmp; |
| } |
| |
| /*** Value type queries ***/ |
| |
| bool isUndefined() const { |
| return JSVAL_IS_UNDEFINED_IMPL(data); |
| } |
| |
| bool isNull() const { |
| return JSVAL_IS_NULL_IMPL(data); |
| } |
| |
| bool isNullOrUndefined() const { |
| return isNull() || isUndefined(); |
| } |
| |
| bool isInt32() const { |
| return JSVAL_IS_INT32_IMPL(data); |
| } |
| |
| bool isInt32(int32_t i32) const { |
| return JSVAL_IS_SPECIFIC_INT32_IMPL(data, i32); |
| } |
| |
| bool isDouble() const { |
| return JSVAL_IS_DOUBLE_IMPL(data); |
| } |
| |
| bool isNumber() const { |
| return JSVAL_IS_NUMBER_IMPL(data); |
| } |
| |
| bool isString() const { |
| return JSVAL_IS_STRING_IMPL(data); |
| } |
| |
| bool isSymbol() const { |
| return JSVAL_IS_SYMBOL_IMPL(data); |
| } |
| |
| bool isObject() const { |
| return JSVAL_IS_OBJECT_IMPL(data); |
| } |
| |
| bool isPrimitive() const { |
| return JSVAL_IS_PRIMITIVE_IMPL(data); |
| } |
| |
| bool isObjectOrNull() const { |
| return JSVAL_IS_OBJECT_OR_NULL_IMPL(data); |
| } |
| |
| bool isGCThing() const { |
| return JSVAL_IS_GCTHING_IMPL(data); |
| } |
| |
| bool isBoolean() const { |
| return JSVAL_IS_BOOLEAN_IMPL(data); |
| } |
| |
| bool isTrue() const { |
| return JSVAL_IS_SPECIFIC_BOOLEAN_IMPL(data, true); |
| } |
| |
| bool isFalse() const { |
| return JSVAL_IS_SPECIFIC_BOOLEAN_IMPL(data, false); |
| } |
| |
| bool isMagic() const { |
| return JSVAL_IS_MAGIC_IMPL(data); |
| } |
| |
| bool isMagic(JSWhyMagic why) const { |
| MOZ_ASSERT_IF(isMagic(), data.s.payload.why == why); |
| return JSVAL_IS_MAGIC_IMPL(data); |
| } |
| |
| bool isMarkable() const { |
| return JSVAL_IS_TRACEABLE_IMPL(data); |
| } |
| |
| JS::TraceKind traceKind() const { |
| MOZ_ASSERT(isMarkable()); |
| return JS::TraceKind(JSVAL_TRACE_KIND_IMPL(data)); |
| } |
| |
| JSWhyMagic whyMagic() const { |
| MOZ_ASSERT(isMagic()); |
| return data.s.payload.why; |
| } |
| |
| uint32_t magicUint32() const { |
| MOZ_ASSERT(isMagic()); |
| return data.s.payload.u32; |
| } |
| |
| /*** Comparison ***/ |
| |
| bool operator==(const Value& rhs) const { |
| return data.asBits == rhs.data.asBits; |
| } |
| |
| bool operator!=(const Value& rhs) const { |
| return data.asBits != rhs.data.asBits; |
| } |
| |
| friend inline bool SameType(const Value& lhs, const Value& rhs); |
| |
| /*** Extract the value's typed payload ***/ |
| |
| int32_t toInt32() const { |
| MOZ_ASSERT(isInt32()); |
| return JSVAL_TO_INT32_IMPL(data); |
| } |
| |
| double toDouble() const { |
| MOZ_ASSERT(isDouble()); |
| return data.asDouble; |
| } |
| |
| double toNumber() const { |
| MOZ_ASSERT(isNumber()); |
| return isDouble() ? toDouble() : double(toInt32()); |
| } |
| |
| JSString* toString() const { |
| MOZ_ASSERT(isString()); |
| return JSVAL_TO_STRING_IMPL(data); |
| } |
| |
| JS::Symbol* toSymbol() const { |
| MOZ_ASSERT(isSymbol()); |
| return JSVAL_TO_SYMBOL_IMPL(data); |
| } |
| |
| JSObject& toObject() const { |
| MOZ_ASSERT(isObject()); |
| return *JSVAL_TO_OBJECT_IMPL(data); |
| } |
| |
| JSObject* toObjectOrNull() const { |
| MOZ_ASSERT(isObjectOrNull()); |
| return JSVAL_TO_OBJECT_IMPL(data); |
| } |
| |
| js::gc::Cell* toGCThing() const { |
| MOZ_ASSERT(isGCThing()); |
| return JSVAL_TO_GCTHING_IMPL(data); |
| } |
| |
| GCCellPtr toGCCellPtr() const { |
| return GCCellPtr(toGCThing(), traceKind()); |
| } |
| |
| bool toBoolean() const { |
| MOZ_ASSERT(isBoolean()); |
| return JSVAL_TO_BOOLEAN_IMPL(data); |
| } |
| |
| uint32_t payloadAsRawUint32() const { |
| MOZ_ASSERT(!isDouble()); |
| return data.s.payload.u32; |
| } |
| |
| uint64_t asRawBits() const { |
| return data.asBits; |
| } |
| |
| JSValueType extractNonDoubleType() const { |
| return JSVAL_EXTRACT_NON_DOUBLE_TYPE_IMPL(data); |
| } |
| |
| /* |
| * Private API |
| * |
| * Private setters/getters allow the caller to read/write arbitrary types |
| * that fit in the 64-bit payload. It is the caller's responsibility, after |
| * storing to a value with setPrivateX to read only using getPrivateX. |
| * Privates values are given a type which ensures they are not marked. |
| */ |
| |
| void setPrivate(void* ptr) { |
| data = PRIVATE_PTR_TO_JSVAL_IMPL(ptr); |
| } |
| |
| void* toPrivate() const { |
| MOZ_ASSERT(JSVAL_IS_DOUBLE_IMPL(data)); |
| return JSVAL_TO_PRIVATE_PTR_IMPL(data); |
| } |
| |
| void setPrivateUint32(uint32_t ui) { |
| MOZ_ASSERT(uint32_t(int32_t(ui)) == ui); |
| setInt32(int32_t(ui)); |
| } |
| |
| uint32_t toPrivateUint32() const { |
| return uint32_t(toInt32()); |
| } |
| |
| /* |
| * An unmarked value is just a void* cast as a Value. Thus, the Value is |
| * not safe for GC and must not be marked. This API avoids raw casts |
| * and the ensuing strict-aliasing warnings. |
| */ |
| |
| void setUnmarkedPtr(void* ptr) { |
| data.asPtr = ptr; |
| } |
| |
| void* toUnmarkedPtr() const { |
| return data.asPtr; |
| } |
| |
| const size_t* payloadWord() const { |
| #if defined(JS_NUNBOX32) |
| return &data.s.payload.word; |
| #elif defined(JS_PUNBOX64) |
| return &data.asWord; |
| #endif |
| } |
| |
| const uintptr_t* payloadUIntPtr() const { |
| #if defined(JS_NUNBOX32) |
| return &data.s.payload.uintptr; |
| #elif defined(JS_PUNBOX64) |
| return &data.asUIntPtr; |
| #endif |
| } |
| |
| #if !defined(_MSC_VER) && !defined(__sparc) |
| // Value must be POD so that MSVC will pass it by value and not in memory |
| // (bug 689101); the same is true for SPARC as well (bug 737344). More |
| // precisely, we don't want Value return values compiled as out params. |
| private: |
| #endif |
| |
| jsval_layout data; |
| |
| private: |
| #if defined(JS_VALUE_IS_CONSTEXPR) |
| MOZ_IMPLICIT JS_VALUE_CONSTEXPR Value(jsval_layout layout) : data(layout) {} |
| #endif |
| |
| void staticAssertions() { |
| JS_STATIC_ASSERT(sizeof(JSValueType) == 1); |
| JS_STATIC_ASSERT(sizeof(JSValueTag) == 4); |
| JS_STATIC_ASSERT(sizeof(JSWhyMagic) <= 4); |
| JS_STATIC_ASSERT(sizeof(Value) == 8); |
| } |
| |
| #if defined(STARBOARD) && SB_IS(COMPILER_MSVC) |
| // Do not declare JSVAL_TO_IMPL a friend. It is a macro. |
| #else |
| friend jsval_layout (::JSVAL_TO_IMPL)(Value); |
| #endif |
| friend Value JS_VALUE_CONSTEXPR (::IMPL_TO_JSVAL)(jsval_layout l); |
| friend Value JS_VALUE_CONSTEXPR (JS::UndefinedValue)(); |
| }; |
| |
| inline bool |
| IsOptimizedPlaceholderMagicValue(const Value& v) |
| { |
| if (v.isMagic()) { |
| MOZ_ASSERT(v.whyMagic() == JS_OPTIMIZED_ARGUMENTS || v.whyMagic() == JS_OPTIMIZED_OUT); |
| return true; |
| } |
| return false; |
| } |
| |
| static MOZ_ALWAYS_INLINE void |
| ExposeValueToActiveJS(const Value& v) |
| { |
| if (v.isMarkable()) |
| js::gc::ExposeGCThingToActiveJS(GCCellPtr(v)); |
| } |
| |
| /************************************************************************/ |
| |
| static inline Value |
| NullValue() |
| { |
| Value v; |
| v.setNull(); |
| return v; |
| } |
| |
| static inline JS_VALUE_CONSTEXPR Value |
| UndefinedValue() |
| { |
| #if defined(JS_VALUE_IS_CONSTEXPR) |
| return Value(BUILD_JSVAL(JSVAL_TAG_UNDEFINED, 0)); |
| #else |
| JS::Value v; |
| v.setUndefined(); |
| return v; |
| #endif |
| } |
| |
| static inline JS_VALUE_CONSTEXPR Value |
| Int32Value(int32_t i32) |
| { |
| return IMPL_TO_JSVAL(INT32_TO_JSVAL_IMPL(i32)); |
| } |
| |
| static inline Value |
| DoubleValue(double dbl) |
| { |
| Value v; |
| v.setDouble(dbl); |
| return v; |
| } |
| |
| static inline JS_VALUE_CONSTEXPR Value |
| CanonicalizedDoubleValue(double d) |
| { |
| /* |
| * This is a manually inlined version of: |
| * d = JS_CANONICALIZE_NAN(d); |
| * return IMPL_TO_JSVAL(DOUBLE_TO_JSVAL_IMPL(d)); |
| * because GCC from XCode 3.1.4 miscompiles the above code. |
| */ |
| #if defined(JS_VALUE_IS_CONSTEXPR) |
| return IMPL_TO_JSVAL(MOZ_UNLIKELY(mozilla::IsNaN(d)) |
| ? (jsval_layout) { .asBits = 0x7FF8000000000000LL } |
| : (jsval_layout) { .asDouble = d }); |
| #else |
| jsval_layout l; |
| if (MOZ_UNLIKELY(d != d)) |
| l.asBits = 0x7FF8000000000000LL; |
| else |
| l.asDouble = d; |
| return IMPL_TO_JSVAL(l); |
| #endif |
| } |
| |
| static inline Value |
| DoubleNaNValue() |
| { |
| Value v; |
| v.setNaN(); |
| return v; |
| } |
| |
| static inline Value |
| Float32Value(float f) |
| { |
| Value v; |
| v.setDouble(f); |
| return v; |
| } |
| |
| static inline Value |
| StringValue(JSString* str) |
| { |
| Value v; |
| v.setString(str); |
| return v; |
| } |
| |
| static inline Value |
| SymbolValue(JS::Symbol* sym) |
| { |
| Value v; |
| v.setSymbol(sym); |
| return v; |
| } |
| |
| static inline Value |
| BooleanValue(bool boo) |
| { |
| Value v; |
| v.setBoolean(boo); |
| return v; |
| } |
| |
| static inline Value |
| TrueValue() |
| { |
| Value v; |
| v.setBoolean(true); |
| return v; |
| } |
| |
| static inline Value |
| FalseValue() |
| { |
| Value v; |
| v.setBoolean(false); |
| return v; |
| } |
| |
| static inline Value |
| ObjectValue(JSObject& obj) |
| { |
| Value v; |
| v.setObject(obj); |
| return v; |
| } |
| |
| static inline Value |
| ObjectValueCrashOnTouch() |
| { |
| Value v; |
| v.setObject(*reinterpret_cast<JSObject*>(0x42)); |
| return v; |
| } |
| |
| static inline Value |
| MagicValue(JSWhyMagic why) |
| { |
| Value v; |
| v.setMagic(why); |
| return v; |
| } |
| |
| static inline Value |
| MagicValueUint32(uint32_t payload) |
| { |
| Value v; |
| v.setMagicUint32(payload); |
| return v; |
| } |
| |
| static inline Value |
| NumberValue(float f) |
| { |
| Value v; |
| v.setNumber(f); |
| return v; |
| } |
| |
| static inline Value |
| NumberValue(double dbl) |
| { |
| Value v; |
| v.setNumber(dbl); |
| return v; |
| } |
| |
| static inline Value |
| NumberValue(int8_t i) |
| { |
| return Int32Value(i); |
| } |
| |
| static inline Value |
| NumberValue(uint8_t i) |
| { |
| return Int32Value(i); |
| } |
| |
| static inline Value |
| NumberValue(int16_t i) |
| { |
| return Int32Value(i); |
| } |
| |
| static inline Value |
| NumberValue(uint16_t i) |
| { |
| return Int32Value(i); |
| } |
| |
| static inline Value |
| NumberValue(int32_t i) |
| { |
| return Int32Value(i); |
| } |
| |
| static inline JS_VALUE_CONSTEXPR Value |
| NumberValue(uint32_t i) |
| { |
| return i <= JSVAL_INT_MAX |
| ? Int32Value(int32_t(i)) |
| : CanonicalizedDoubleValue(double(i)); |
| } |
| |
| namespace detail { |
| |
| template <bool Signed> |
| class MakeNumberValue |
| { |
| public: |
| template<typename T> |
| static inline Value create(const T t) |
| { |
| Value v; |
| if (JSVAL_INT_MIN <= t && t <= JSVAL_INT_MAX) |
| v.setInt32(int32_t(t)); |
| else |
| v.setDouble(double(t)); |
| return v; |
| } |
| }; |
| |
| template <> |
| class MakeNumberValue<false> |
| { |
| public: |
| template<typename T> |
| static inline Value create(const T t) |
| { |
| Value v; |
| if (t <= JSVAL_INT_MAX) |
| v.setInt32(int32_t(t)); |
| else |
| v.setDouble(double(t)); |
| return v; |
| } |
| }; |
| |
| } // namespace detail |
| |
| template <typename T> |
| static inline Value |
| NumberValue(const T t) |
| { |
| MOZ_ASSERT(Value::isNumberRepresentable(t), "value creation would be lossy"); |
| return detail::MakeNumberValue<std::numeric_limits<T>::is_signed>::create(t); |
| } |
| |
| static inline Value |
| ObjectOrNullValue(JSObject* obj) |
| { |
| Value v; |
| v.setObjectOrNull(obj); |
| return v; |
| } |
| |
| static inline Value |
| PrivateValue(void* ptr) |
| { |
| Value v; |
| v.setPrivate(ptr); |
| return v; |
| } |
| |
| static inline Value |
| PrivateUint32Value(uint32_t ui) |
| { |
| Value v; |
| v.setPrivateUint32(ui); |
| return v; |
| } |
| |
| inline bool |
| SameType(const Value& lhs, const Value& rhs) |
| { |
| return JSVAL_SAME_TYPE_IMPL(lhs.data, rhs.data); |
| } |
| |
| } // namespace JS |
| |
| /************************************************************************/ |
| |
| namespace JS { |
| JS_PUBLIC_API(void) HeapValuePostBarrier(Value* valuep, const Value& prev, const Value& next); |
| } // namespace JS |
| |
| namespace js { |
| |
| template <> struct GCMethods<const JS::Value> |
| { |
| static JS::Value initial() { return JS::UndefinedValue(); } |
| }; |
| |
| template <> struct GCMethods<JS::Value> |
| { |
| static JS::Value initial() { return JS::UndefinedValue(); } |
| static gc::Cell* asGCThingOrNull(const JS::Value& v) { |
| return v.isMarkable() ? v.toGCThing() : nullptr; |
| } |
| static void postBarrier(JS::Value* v, const JS::Value& prev, const JS::Value& next) { |
| JS::HeapValuePostBarrier(v, prev, next); |
| } |
| }; |
| |
| template <class Outer> class MutableValueOperations; |
| |
| /** |
| * A class designed for CRTP use in implementing the non-mutating parts of the |
| * Value interface in Value-like classes. Outer must be a class inheriting |
| * ValueOperations<Outer> with a visible get() method returning a const |
| * reference to the Value abstracted by Outer. |
| */ |
| template <class Outer> |
| class ValueOperations |
| { |
| friend class MutableValueOperations<Outer>; |
| |
| const JS::Value& value() const { return static_cast<const Outer*>(this)->get(); } |
| |
| public: |
| bool isUndefined() const { return value().isUndefined(); } |
| bool isNull() const { return value().isNull(); } |
| bool isBoolean() const { return value().isBoolean(); } |
| bool isTrue() const { return value().isTrue(); } |
| bool isFalse() const { return value().isFalse(); } |
| bool isNumber() const { return value().isNumber(); } |
| bool isInt32() const { return value().isInt32(); } |
| bool isInt32(int32_t i32) const { return value().isInt32(i32); } |
| bool isDouble() const { return value().isDouble(); } |
| bool isString() const { return value().isString(); } |
| bool isSymbol() const { return value().isSymbol(); } |
| bool isObject() const { return value().isObject(); } |
| bool isMagic() const { return value().isMagic(); } |
| bool isMagic(JSWhyMagic why) const { return value().isMagic(why); } |
| bool isMarkable() const { return value().isMarkable(); } |
| bool isPrimitive() const { return value().isPrimitive(); } |
| bool isGCThing() const { return value().isGCThing(); } |
| |
| bool isNullOrUndefined() const { return value().isNullOrUndefined(); } |
| bool isObjectOrNull() const { return value().isObjectOrNull(); } |
| |
| bool toBoolean() const { return value().toBoolean(); } |
| double toNumber() const { return value().toNumber(); } |
| int32_t toInt32() const { return value().toInt32(); } |
| double toDouble() const { return value().toDouble(); } |
| JSString* toString() const { return value().toString(); } |
| JS::Symbol* toSymbol() const { return value().toSymbol(); } |
| JSObject& toObject() const { return value().toObject(); } |
| JSObject* toObjectOrNull() const { return value().toObjectOrNull(); } |
| gc::Cell* toGCThing() const { return value().toGCThing(); } |
| JS::TraceKind traceKind() const { return value().traceKind(); } |
| uint64_t asRawBits() const { return value().asRawBits(); } |
| |
| JSValueType extractNonDoubleType() const { return value().extractNonDoubleType(); } |
| uint32_t toPrivateUint32() const { return value().toPrivateUint32(); } |
| |
| JSWhyMagic whyMagic() const { return value().whyMagic(); } |
| uint32_t magicUint32() const { return value().magicUint32(); } |
| }; |
| |
| /** |
| * A class designed for CRTP use in implementing all the mutating parts of the |
| * Value interface in Value-like classes. Outer must be a class inheriting |
| * MutableValueOperations<Outer> with visible get() methods returning const and |
| * non-const references to the Value abstracted by Outer. |
| */ |
| template <class Outer> |
| class MutableValueOperations : public ValueOperations<Outer> |
| { |
| JS::Value& value() { return static_cast<Outer*>(this)->get(); } |
| |
| public: |
| void setNull() { value().setNull(); } |
| void setUndefined() { value().setUndefined(); } |
| void setInt32(int32_t i) { value().setInt32(i); } |
| void setDouble(double d) { value().setDouble(d); } |
| void setNaN() { setDouble(JS::GenericNaN()); } |
| void setBoolean(bool b) { value().setBoolean(b); } |
| void setMagic(JSWhyMagic why) { value().setMagic(why); } |
| bool setNumber(uint32_t ui) { return value().setNumber(ui); } |
| bool setNumber(double d) { return value().setNumber(d); } |
| void setString(JSString* str) { this->value().setString(str); } |
| void setSymbol(JS::Symbol* sym) { this->value().setSymbol(sym); } |
| void setObject(JSObject& obj) { this->value().setObject(obj); } |
| void setObjectOrNull(JSObject* arg) { this->value().setObjectOrNull(arg); } |
| }; |
| |
| /* |
| * Augment the generic Heap<T> interface when T = Value with |
| * type-querying, value-extracting, and mutating operations. |
| */ |
| template <> |
| class HeapBase<JS::Value> : public ValueOperations<JS::Heap<JS::Value> > |
| { |
| typedef JS::Heap<JS::Value> Outer; |
| |
| friend class ValueOperations<Outer>; |
| |
| void setBarriered(const JS::Value& v) { |
| *static_cast<JS::Heap<JS::Value>*>(this) = v; |
| } |
| |
| public: |
| void setNull() { setBarriered(JS::NullValue()); } |
| void setUndefined() { setBarriered(JS::UndefinedValue()); } |
| void setInt32(int32_t i) { setBarriered(JS::Int32Value(i)); } |
| void setDouble(double d) { setBarriered(JS::DoubleValue(d)); } |
| void setNaN() { setDouble(JS::GenericNaN()); } |
| void setBoolean(bool b) { setBarriered(JS::BooleanValue(b)); } |
| void setMagic(JSWhyMagic why) { setBarriered(JS::MagicValue(why)); } |
| void setString(JSString* str) { setBarriered(JS::StringValue(str)); } |
| void setSymbol(JS::Symbol* sym) { setBarriered(JS::SymbolValue(sym)); } |
| void setObject(JSObject& obj) { setBarriered(JS::ObjectValue(obj)); } |
| |
| bool setNumber(uint32_t ui) { |
| if (ui > JSVAL_INT_MAX) { |
| setDouble((double)ui); |
| return false; |
| } else { |
| setInt32((int32_t)ui); |
| return true; |
| } |
| } |
| |
| bool setNumber(double d) { |
| int32_t i; |
| if (mozilla::NumberIsInt32(d, &i)) { |
| setInt32(i); |
| return true; |
| } |
| |
| setDouble(d); |
| return false; |
| } |
| |
| void setObjectOrNull(JSObject* arg) { |
| if (arg) |
| setObject(*arg); |
| else |
| setNull(); |
| } |
| }; |
| |
| template <> |
| class HandleBase<JS::Value> : public ValueOperations<JS::Handle<JS::Value> > |
| {}; |
| |
| template <> |
| class MutableHandleBase<JS::Value> : public MutableValueOperations<JS::MutableHandle<JS::Value> > |
| {}; |
| |
| template <> |
| class RootedBase<JS::Value> : public MutableValueOperations<JS::Rooted<JS::Value> > |
| {}; |
| |
| template <> |
| class PersistentRootedBase<JS::Value> : public MutableValueOperations<JS::PersistentRooted<JS::Value>> |
| {}; |
| |
| /* |
| * If the Value is a GC pointer type, convert to that type and call |f| with |
| * the pointer. If the Value is not a GC type, calls F::defaultValue. |
| */ |
| template <typename F, typename... Args> |
| auto |
| DispatchTyped(F f, const JS::Value& val, Args&&... args) |
| -> decltype(f(static_cast<JSObject*>(nullptr), mozilla::Forward<Args>(args)...)) |
| { |
| if (val.isString()) |
| return f(val.toString(), mozilla::Forward<Args>(args)...); |
| if (val.isObject()) |
| return f(&val.toObject(), mozilla::Forward<Args>(args)...); |
| if (val.isSymbol()) |
| return f(val.toSymbol(), mozilla::Forward<Args>(args)...); |
| MOZ_ASSERT(!val.isMarkable()); |
| return F::defaultValue(val); |
| } |
| |
| template <class S> struct VoidDefaultAdaptor { static void defaultValue(S) {} }; |
| template <class S> struct IdentityDefaultAdaptor { static S defaultValue(const S& v) {return v;} }; |
| template <class S, bool v> struct BoolDefaultAdaptor { static bool defaultValue(S) { return v; } }; |
| |
| } // namespace js |
| |
| #if defined(STARBOARD) && SB_IS(COMPILER_MSVC) |
| // Do not define JSVAL_TO_IMPL as a function. It is a macro. |
| #else |
| inline jsval_layout |
| JSVAL_TO_IMPL(JS::Value v) |
| { |
| return v.data; |
| } |
| #endif |
| |
| inline JS_VALUE_CONSTEXPR JS::Value |
| IMPL_TO_JSVAL(jsval_layout l) |
| { |
| #if defined(JS_VALUE_IS_CONSTEXPR) |
| return JS::Value(l); |
| #else |
| JS::Value v; |
| v.data = l; |
| return v; |
| #endif |
| } |
| |
| namespace JS { |
| |
| #ifdef JS_DEBUG |
| namespace detail { |
| |
| struct ValueAlignmentTester { char c; JS::Value v; }; |
| static_assert(sizeof(ValueAlignmentTester) == 16, |
| "JS::Value must be 16-byte-aligned"); |
| |
| struct LayoutAlignmentTester { char c; jsval_layout l; }; |
| static_assert(sizeof(LayoutAlignmentTester) == 16, |
| "jsval_layout must be 16-byte-aligned"); |
| |
| } // namespace detail |
| #endif /* JS_DEBUG */ |
| |
| } // namespace JS |
| |
| static_assert(sizeof(jsval_layout) == sizeof(JS::Value), |
| "jsval_layout and JS::Value must have identical layouts"); |
| |
| /************************************************************************/ |
| |
| namespace JS { |
| |
| extern JS_PUBLIC_DATA(const HandleValue) NullHandleValue; |
| extern JS_PUBLIC_DATA(const HandleValue) UndefinedHandleValue; |
| extern JS_PUBLIC_DATA(const HandleValue) TrueHandleValue; |
| extern JS_PUBLIC_DATA(const HandleValue) FalseHandleValue; |
| |
| } // namespace JS |
| |
| #undef JS_VALUE_IS_CONSTEXPR |
| #undef JS_RETURN_LAYOUT_FROM_BITS |
| |
| #endif /* js_Value_h */ |