michael@0: /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- michael@0: * vim: set ts=8 sts=4 et sw=4 tw=99: michael@0: * This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: /* JS::Value implementation. */ michael@0: michael@0: #ifndef js_Value_h michael@0: #define js_Value_h michael@0: michael@0: #include "mozilla/Attributes.h" michael@0: #include "mozilla/FloatingPoint.h" michael@0: #include "mozilla/Likely.h" michael@0: michael@0: #include /* for std::numeric_limits */ michael@0: michael@0: #include "jstypes.h" michael@0: michael@0: #include "js/Anchor.h" michael@0: #include "js/RootingAPI.h" michael@0: #include "js/Utility.h" michael@0: michael@0: namespace JS { class Value; } michael@0: michael@0: /* JS::Value can store a full int32_t. */ michael@0: #define JSVAL_INT_BITS 32 michael@0: #define JSVAL_INT_MIN ((int32_t)0x80000000) michael@0: #define JSVAL_INT_MAX ((int32_t)0x7fffffff) michael@0: michael@0: /* michael@0: * Try to get jsvals 64-bit aligned. We could almost assert that all values are michael@0: * aligned, but MSVC and GCC occasionally break alignment. michael@0: */ michael@0: #if defined(__GNUC__) || defined(__xlc__) || defined(__xlC__) michael@0: # define JSVAL_ALIGNMENT __attribute__((aligned (8))) michael@0: #elif defined(_MSC_VER) michael@0: /* michael@0: * Structs can be aligned with MSVC, but not if they are used as parameters, michael@0: * so we just don't try to align. michael@0: */ michael@0: # define JSVAL_ALIGNMENT michael@0: #elif defined(__SUNPRO_C) || defined(__SUNPRO_CC) michael@0: # define JSVAL_ALIGNMENT michael@0: #elif defined(__HP_cc) || defined(__HP_aCC) michael@0: # define JSVAL_ALIGNMENT michael@0: #endif michael@0: michael@0: #if JS_BITS_PER_WORD == 64 michael@0: # define JSVAL_TAG_SHIFT 47 michael@0: #endif michael@0: michael@0: /* michael@0: * We try to use enums so that printing a jsval_layout in the debugger shows michael@0: * nice symbolic type tags, however we can only do this when we can force the michael@0: * underlying type of the enum to be the desired size. michael@0: */ michael@0: #if !defined(__SUNPRO_CC) && !defined(__xlC__) michael@0: michael@0: #if defined(_MSC_VER) michael@0: # define JS_ENUM_HEADER(id, type) enum id : type michael@0: # define JS_ENUM_FOOTER(id) michael@0: #else michael@0: # define JS_ENUM_HEADER(id, type) enum id michael@0: # define JS_ENUM_FOOTER(id) __attribute__((packed)) michael@0: #endif michael@0: michael@0: /* Remember to propagate changes to the C defines below. */ michael@0: JS_ENUM_HEADER(JSValueType, uint8_t) michael@0: { michael@0: JSVAL_TYPE_DOUBLE = 0x00, michael@0: JSVAL_TYPE_INT32 = 0x01, michael@0: JSVAL_TYPE_UNDEFINED = 0x02, michael@0: JSVAL_TYPE_BOOLEAN = 0x03, michael@0: JSVAL_TYPE_MAGIC = 0x04, michael@0: JSVAL_TYPE_STRING = 0x05, michael@0: JSVAL_TYPE_NULL = 0x06, michael@0: JSVAL_TYPE_OBJECT = 0x07, michael@0: michael@0: /* These never appear in a jsval; they are only provided as an out-of-band value. */ michael@0: JSVAL_TYPE_UNKNOWN = 0x20, michael@0: JSVAL_TYPE_MISSING = 0x21 michael@0: } JS_ENUM_FOOTER(JSValueType); michael@0: michael@0: JS_STATIC_ASSERT(sizeof(JSValueType) == 1); michael@0: michael@0: #if JS_BITS_PER_WORD == 32 michael@0: michael@0: /* Remember to propagate changes to the C defines below. */ michael@0: JS_ENUM_HEADER(JSValueTag, uint32_t) michael@0: { michael@0: JSVAL_TAG_CLEAR = 0xFFFFFF80, michael@0: JSVAL_TAG_INT32 = JSVAL_TAG_CLEAR | JSVAL_TYPE_INT32, michael@0: JSVAL_TAG_UNDEFINED = JSVAL_TAG_CLEAR | JSVAL_TYPE_UNDEFINED, michael@0: JSVAL_TAG_STRING = JSVAL_TAG_CLEAR | JSVAL_TYPE_STRING, michael@0: JSVAL_TAG_BOOLEAN = JSVAL_TAG_CLEAR | JSVAL_TYPE_BOOLEAN, michael@0: JSVAL_TAG_MAGIC = JSVAL_TAG_CLEAR | JSVAL_TYPE_MAGIC, michael@0: JSVAL_TAG_NULL = JSVAL_TAG_CLEAR | JSVAL_TYPE_NULL, michael@0: JSVAL_TAG_OBJECT = JSVAL_TAG_CLEAR | JSVAL_TYPE_OBJECT michael@0: } JS_ENUM_FOOTER(JSValueTag); michael@0: michael@0: JS_STATIC_ASSERT(sizeof(JSValueTag) == 4); michael@0: michael@0: #elif JS_BITS_PER_WORD == 64 michael@0: michael@0: /* Remember to propagate changes to the C defines below. */ michael@0: JS_ENUM_HEADER(JSValueTag, uint32_t) michael@0: { michael@0: JSVAL_TAG_MAX_DOUBLE = 0x1FFF0, michael@0: JSVAL_TAG_INT32 = JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_INT32, michael@0: JSVAL_TAG_UNDEFINED = JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_UNDEFINED, michael@0: JSVAL_TAG_STRING = JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_STRING, michael@0: JSVAL_TAG_BOOLEAN = JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_BOOLEAN, michael@0: JSVAL_TAG_MAGIC = JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_MAGIC, michael@0: JSVAL_TAG_NULL = JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_NULL, michael@0: JSVAL_TAG_OBJECT = JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_OBJECT michael@0: } JS_ENUM_FOOTER(JSValueTag); michael@0: michael@0: JS_STATIC_ASSERT(sizeof(JSValueTag) == sizeof(uint32_t)); michael@0: michael@0: JS_ENUM_HEADER(JSValueShiftedTag, uint64_t) michael@0: { michael@0: JSVAL_SHIFTED_TAG_MAX_DOUBLE = ((((uint64_t)JSVAL_TAG_MAX_DOUBLE) << JSVAL_TAG_SHIFT) | 0xFFFFFFFF), michael@0: JSVAL_SHIFTED_TAG_INT32 = (((uint64_t)JSVAL_TAG_INT32) << JSVAL_TAG_SHIFT), michael@0: JSVAL_SHIFTED_TAG_UNDEFINED = (((uint64_t)JSVAL_TAG_UNDEFINED) << JSVAL_TAG_SHIFT), michael@0: JSVAL_SHIFTED_TAG_STRING = (((uint64_t)JSVAL_TAG_STRING) << JSVAL_TAG_SHIFT), michael@0: JSVAL_SHIFTED_TAG_BOOLEAN = (((uint64_t)JSVAL_TAG_BOOLEAN) << JSVAL_TAG_SHIFT), michael@0: JSVAL_SHIFTED_TAG_MAGIC = (((uint64_t)JSVAL_TAG_MAGIC) << JSVAL_TAG_SHIFT), michael@0: JSVAL_SHIFTED_TAG_NULL = (((uint64_t)JSVAL_TAG_NULL) << JSVAL_TAG_SHIFT), michael@0: JSVAL_SHIFTED_TAG_OBJECT = (((uint64_t)JSVAL_TAG_OBJECT) << JSVAL_TAG_SHIFT) michael@0: } JS_ENUM_FOOTER(JSValueShiftedTag); michael@0: michael@0: JS_STATIC_ASSERT(sizeof(JSValueShiftedTag) == sizeof(uint64_t)); michael@0: michael@0: #endif michael@0: michael@0: #else /* !defined(__SUNPRO_CC) && !defined(__xlC__) */ michael@0: michael@0: typedef uint8_t JSValueType; michael@0: #define JSVAL_TYPE_DOUBLE ((uint8_t)0x00) michael@0: #define JSVAL_TYPE_INT32 ((uint8_t)0x01) michael@0: #define JSVAL_TYPE_UNDEFINED ((uint8_t)0x02) michael@0: #define JSVAL_TYPE_BOOLEAN ((uint8_t)0x03) michael@0: #define JSVAL_TYPE_MAGIC ((uint8_t)0x04) michael@0: #define JSVAL_TYPE_STRING ((uint8_t)0x05) michael@0: #define JSVAL_TYPE_NULL ((uint8_t)0x06) michael@0: #define JSVAL_TYPE_OBJECT ((uint8_t)0x07) michael@0: #define JSVAL_TYPE_UNKNOWN ((uint8_t)0x20) michael@0: michael@0: #if JS_BITS_PER_WORD == 32 michael@0: michael@0: typedef uint32_t JSValueTag; michael@0: #define JSVAL_TAG_CLEAR ((uint32_t)(0xFFFFFF80)) michael@0: #define JSVAL_TAG_INT32 ((uint32_t)(JSVAL_TAG_CLEAR | JSVAL_TYPE_INT32)) michael@0: #define JSVAL_TAG_UNDEFINED ((uint32_t)(JSVAL_TAG_CLEAR | JSVAL_TYPE_UNDEFINED)) michael@0: #define JSVAL_TAG_STRING ((uint32_t)(JSVAL_TAG_CLEAR | JSVAL_TYPE_STRING)) michael@0: #define JSVAL_TAG_BOOLEAN ((uint32_t)(JSVAL_TAG_CLEAR | JSVAL_TYPE_BOOLEAN)) michael@0: #define JSVAL_TAG_MAGIC ((uint32_t)(JSVAL_TAG_CLEAR | JSVAL_TYPE_MAGIC)) michael@0: #define JSVAL_TAG_NULL ((uint32_t)(JSVAL_TAG_CLEAR | JSVAL_TYPE_NULL)) michael@0: #define JSVAL_TAG_OBJECT ((uint32_t)(JSVAL_TAG_CLEAR | JSVAL_TYPE_OBJECT)) michael@0: michael@0: #elif JS_BITS_PER_WORD == 64 michael@0: michael@0: typedef uint32_t JSValueTag; michael@0: #define JSVAL_TAG_MAX_DOUBLE ((uint32_t)(0x1FFF0)) michael@0: #define JSVAL_TAG_INT32 (uint32_t)(JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_INT32) michael@0: #define JSVAL_TAG_UNDEFINED (uint32_t)(JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_UNDEFINED) michael@0: #define JSVAL_TAG_STRING (uint32_t)(JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_STRING) michael@0: #define JSVAL_TAG_BOOLEAN (uint32_t)(JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_BOOLEAN) michael@0: #define JSVAL_TAG_MAGIC (uint32_t)(JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_MAGIC) michael@0: #define JSVAL_TAG_NULL (uint32_t)(JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_NULL) michael@0: #define JSVAL_TAG_OBJECT (uint32_t)(JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_OBJECT) michael@0: michael@0: typedef uint64_t JSValueShiftedTag; michael@0: #define JSVAL_SHIFTED_TAG_MAX_DOUBLE ((((uint64_t)JSVAL_TAG_MAX_DOUBLE) << JSVAL_TAG_SHIFT) | 0xFFFFFFFF) michael@0: #define JSVAL_SHIFTED_TAG_INT32 (((uint64_t)JSVAL_TAG_INT32) << JSVAL_TAG_SHIFT) michael@0: #define JSVAL_SHIFTED_TAG_UNDEFINED (((uint64_t)JSVAL_TAG_UNDEFINED) << JSVAL_TAG_SHIFT) michael@0: #define JSVAL_SHIFTED_TAG_STRING (((uint64_t)JSVAL_TAG_STRING) << JSVAL_TAG_SHIFT) michael@0: #define JSVAL_SHIFTED_TAG_BOOLEAN (((uint64_t)JSVAL_TAG_BOOLEAN) << JSVAL_TAG_SHIFT) michael@0: #define JSVAL_SHIFTED_TAG_MAGIC (((uint64_t)JSVAL_TAG_MAGIC) << JSVAL_TAG_SHIFT) michael@0: #define JSVAL_SHIFTED_TAG_NULL (((uint64_t)JSVAL_TAG_NULL) << JSVAL_TAG_SHIFT) michael@0: #define JSVAL_SHIFTED_TAG_OBJECT (((uint64_t)JSVAL_TAG_OBJECT) << JSVAL_TAG_SHIFT) michael@0: michael@0: #endif /* JS_BITS_PER_WORD */ michael@0: #endif /* !defined(__SUNPRO_CC) && !defined(__xlC__) */ michael@0: michael@0: #define JSVAL_LOWER_INCL_TYPE_OF_OBJ_OR_NULL_SET JSVAL_TYPE_NULL michael@0: #define JSVAL_UPPER_EXCL_TYPE_OF_PRIMITIVE_SET JSVAL_TYPE_OBJECT michael@0: #define JSVAL_UPPER_INCL_TYPE_OF_NUMBER_SET JSVAL_TYPE_INT32 michael@0: #define JSVAL_LOWER_INCL_TYPE_OF_PTR_PAYLOAD_SET JSVAL_TYPE_MAGIC michael@0: michael@0: #if JS_BITS_PER_WORD == 32 michael@0: michael@0: #define JSVAL_TYPE_TO_TAG(type) ((JSValueTag)(JSVAL_TAG_CLEAR | (type))) michael@0: michael@0: #define JSVAL_LOWER_INCL_TAG_OF_OBJ_OR_NULL_SET JSVAL_TAG_NULL michael@0: #define JSVAL_UPPER_EXCL_TAG_OF_PRIMITIVE_SET JSVAL_TAG_OBJECT michael@0: #define JSVAL_UPPER_INCL_TAG_OF_NUMBER_SET JSVAL_TAG_INT32 michael@0: #define JSVAL_LOWER_INCL_TAG_OF_GCTHING_SET JSVAL_TAG_STRING michael@0: michael@0: #elif JS_BITS_PER_WORD == 64 michael@0: michael@0: #define JSVAL_PAYLOAD_MASK 0x00007FFFFFFFFFFFLL michael@0: #define JSVAL_TAG_MASK 0xFFFF800000000000LL michael@0: #define JSVAL_TYPE_TO_TAG(type) ((JSValueTag)(JSVAL_TAG_MAX_DOUBLE | (type))) michael@0: #define JSVAL_TYPE_TO_SHIFTED_TAG(type) (((uint64_t)JSVAL_TYPE_TO_TAG(type)) << JSVAL_TAG_SHIFT) michael@0: michael@0: #define JSVAL_LOWER_INCL_TAG_OF_OBJ_OR_NULL_SET JSVAL_TAG_NULL michael@0: #define JSVAL_UPPER_EXCL_TAG_OF_PRIMITIVE_SET JSVAL_TAG_OBJECT michael@0: #define JSVAL_UPPER_INCL_TAG_OF_NUMBER_SET JSVAL_TAG_INT32 michael@0: #define JSVAL_LOWER_INCL_TAG_OF_GCTHING_SET JSVAL_TAG_STRING michael@0: michael@0: #define JSVAL_LOWER_INCL_SHIFTED_TAG_OF_OBJ_OR_NULL_SET JSVAL_SHIFTED_TAG_NULL michael@0: #define JSVAL_UPPER_EXCL_SHIFTED_TAG_OF_PRIMITIVE_SET JSVAL_SHIFTED_TAG_OBJECT michael@0: #define JSVAL_UPPER_EXCL_SHIFTED_TAG_OF_NUMBER_SET JSVAL_SHIFTED_TAG_UNDEFINED michael@0: #define JSVAL_LOWER_INCL_SHIFTED_TAG_OF_GCTHING_SET JSVAL_SHIFTED_TAG_STRING michael@0: michael@0: #endif /* JS_BITS_PER_WORD */ michael@0: michael@0: typedef enum JSWhyMagic michael@0: { michael@0: JS_ELEMENTS_HOLE, /* a hole in a native object's elements */ michael@0: JS_NATIVE_ENUMERATE, /* indicates that a custom enumerate hook forwarded michael@0: * to JS_EnumerateState, which really means the object can be michael@0: * enumerated like a native object. */ michael@0: JS_NO_ITER_VALUE, /* there is not a pending iterator value */ michael@0: JS_GENERATOR_CLOSING, /* exception value thrown when closing a generator */ michael@0: JS_NO_CONSTANT, /* compiler sentinel value */ michael@0: JS_THIS_POISON, /* used in debug builds to catch tracing errors */ michael@0: JS_ARG_POISON, /* used in debug builds to catch tracing errors */ michael@0: JS_SERIALIZE_NO_NODE, /* an empty subnode in the AST serializer */ michael@0: JS_LAZY_ARGUMENTS, /* lazy arguments value on the stack */ michael@0: JS_OPTIMIZED_ARGUMENTS, /* optimized-away 'arguments' value */ michael@0: JS_IS_CONSTRUCTING, /* magic value passed to natives to indicate construction */ michael@0: JS_OVERWRITTEN_CALLEE, /* arguments.callee has been overwritten */ michael@0: JS_BLOCK_NEEDS_CLONE, /* value of static block object slot */ michael@0: JS_HASH_KEY_EMPTY, /* see class js::HashableValue */ michael@0: JS_ION_ERROR, /* error while running Ion code */ michael@0: JS_ION_BAILOUT, /* status code to signal EnterIon will OSR into Interpret */ michael@0: JS_OPTIMIZED_OUT, /* optimized out slot */ michael@0: JS_GENERIC_MAGIC /* for local use */ michael@0: } JSWhyMagic; michael@0: michael@0: #if defined(IS_LITTLE_ENDIAN) michael@0: # if JS_BITS_PER_WORD == 32 michael@0: typedef union jsval_layout michael@0: { michael@0: uint64_t asBits; michael@0: struct { michael@0: union { michael@0: int32_t i32; michael@0: uint32_t u32; michael@0: uint32_t boo; // Don't use |bool| -- it must be four bytes. michael@0: JSString *str; michael@0: JSObject *obj; michael@0: void *ptr; michael@0: JSWhyMagic why; michael@0: size_t word; michael@0: uintptr_t uintptr; michael@0: } payload; michael@0: JSValueTag tag; michael@0: } s; michael@0: double asDouble; michael@0: void *asPtr; michael@0: } JSVAL_ALIGNMENT jsval_layout; michael@0: # elif JS_BITS_PER_WORD == 64 michael@0: typedef union jsval_layout michael@0: { michael@0: uint64_t asBits; michael@0: #if !defined(_WIN64) michael@0: /* MSVC does not pack these correctly :-( */ michael@0: struct { michael@0: uint64_t payload47 : 47; michael@0: JSValueTag tag : 17; michael@0: } debugView; michael@0: #endif michael@0: struct { michael@0: union { michael@0: int32_t i32; michael@0: uint32_t u32; michael@0: JSWhyMagic why; michael@0: } payload; michael@0: } s; michael@0: double asDouble; michael@0: void *asPtr; michael@0: size_t asWord; michael@0: uintptr_t asUIntPtr; michael@0: } JSVAL_ALIGNMENT jsval_layout; michael@0: # endif /* JS_BITS_PER_WORD */ michael@0: #else /* defined(IS_LITTLE_ENDIAN) */ michael@0: # if JS_BITS_PER_WORD == 32 michael@0: typedef union jsval_layout michael@0: { michael@0: uint64_t asBits; michael@0: struct { michael@0: JSValueTag tag; michael@0: union { michael@0: int32_t i32; michael@0: uint32_t u32; michael@0: uint32_t boo; // Don't use |bool| -- it must be four bytes. michael@0: JSString *str; michael@0: JSObject *obj; michael@0: void *ptr; michael@0: JSWhyMagic why; michael@0: size_t word; michael@0: uintptr_t uintptr; michael@0: } payload; michael@0: } s; michael@0: double asDouble; michael@0: void *asPtr; michael@0: } JSVAL_ALIGNMENT jsval_layout; michael@0: # elif JS_BITS_PER_WORD == 64 michael@0: typedef union jsval_layout michael@0: { michael@0: uint64_t asBits; michael@0: struct { michael@0: JSValueTag tag : 17; michael@0: uint64_t payload47 : 47; michael@0: } debugView; michael@0: struct { michael@0: uint32_t padding; michael@0: union { michael@0: int32_t i32; michael@0: uint32_t u32; michael@0: JSWhyMagic why; michael@0: } payload; michael@0: } s; michael@0: double asDouble; michael@0: void *asPtr; michael@0: size_t asWord; michael@0: uintptr_t asUIntPtr; michael@0: } JSVAL_ALIGNMENT jsval_layout; michael@0: # endif /* JS_BITS_PER_WORD */ michael@0: #endif /* defined(IS_LITTLE_ENDIAN) */ michael@0: michael@0: JS_STATIC_ASSERT(sizeof(jsval_layout) == 8); michael@0: michael@0: /* michael@0: * For codesize purposes on some platforms, it's important that the michael@0: * compiler know that JS::Values constructed from constant values can be michael@0: * folded to constant bit patterns at compile time, rather than michael@0: * constructed at runtime. Doing this requires a fair amount of C++11 michael@0: * features, which are not supported on all of our compilers. Set up michael@0: * some defines and helper macros in an attempt to confine the ugliness michael@0: * here, rather than scattering it all about the file. The important michael@0: * features are: michael@0: * michael@0: * - constexpr; michael@0: * - defaulted functions; michael@0: * - C99-style designated initializers. michael@0: */ michael@0: #if defined(__clang__) michael@0: # if __has_feature(cxx_constexpr) && __has_feature(cxx_defaulted_functions) michael@0: # define JS_VALUE_IS_CONSTEXPR michael@0: # endif michael@0: #elif defined(__GNUC__) michael@0: /* michael@0: * We need 4.5 for defaulted functions, 4.6 for constexpr, 4.7 because 4.6 michael@0: * doesn't understand |(X) { .field = ... }| syntax, and 4.7.3 because michael@0: * versions prior to that have bugs in the C++ front-end that cause crashes. michael@0: */ michael@0: # if MOZ_GCC_VERSION_AT_LEAST(4, 7, 3) michael@0: # define JS_VALUE_IS_CONSTEXPR michael@0: # endif michael@0: #endif michael@0: michael@0: #if defined(JS_VALUE_IS_CONSTEXPR) michael@0: # define JS_RETURN_LAYOUT_FROM_BITS(BITS) \ michael@0: return (jsval_layout) { .asBits = (BITS) } michael@0: # define JS_VALUE_CONSTEXPR MOZ_CONSTEXPR michael@0: # define JS_VALUE_CONSTEXPR_VAR MOZ_CONSTEXPR_VAR michael@0: #else michael@0: # define JS_RETURN_LAYOUT_FROM_BITS(BITS) \ michael@0: jsval_layout l; \ michael@0: l.asBits = (BITS); \ michael@0: return l; michael@0: # define JS_VALUE_CONSTEXPR michael@0: # define JS_VALUE_CONSTEXPR_VAR const michael@0: #endif michael@0: michael@0: #if JS_BITS_PER_WORD == 32 michael@0: michael@0: /* michael@0: * N.B. GCC, in some but not all cases, chooses to emit signed comparison of michael@0: * JSValueTag even though its underlying type has been forced to be uint32_t. michael@0: * Thus, all comparisons should explicitly cast operands to uint32_t. michael@0: */ michael@0: michael@0: static inline JS_VALUE_CONSTEXPR jsval_layout michael@0: BUILD_JSVAL(JSValueTag tag, uint32_t payload) michael@0: { michael@0: JS_RETURN_LAYOUT_FROM_BITS((((uint64_t)(uint32_t)tag) << 32) | payload); michael@0: } michael@0: michael@0: static inline bool michael@0: JSVAL_IS_DOUBLE_IMPL(jsval_layout l) michael@0: { michael@0: return (uint32_t)l.s.tag <= (uint32_t)JSVAL_TAG_CLEAR; michael@0: } michael@0: michael@0: static inline jsval_layout michael@0: DOUBLE_TO_JSVAL_IMPL(double d) michael@0: { michael@0: jsval_layout l; michael@0: l.asDouble = d; michael@0: MOZ_ASSERT(JSVAL_IS_DOUBLE_IMPL(l)); michael@0: return l; michael@0: } michael@0: michael@0: static inline bool michael@0: JSVAL_IS_INT32_IMPL(jsval_layout l) michael@0: { michael@0: return l.s.tag == JSVAL_TAG_INT32; michael@0: } michael@0: michael@0: static inline int32_t michael@0: JSVAL_TO_INT32_IMPL(jsval_layout l) michael@0: { michael@0: return l.s.payload.i32; michael@0: } michael@0: michael@0: static inline JS_VALUE_CONSTEXPR jsval_layout michael@0: INT32_TO_JSVAL_IMPL(int32_t i) michael@0: { michael@0: #if defined(JS_VALUE_IS_CONSTEXPR) michael@0: return BUILD_JSVAL(JSVAL_TAG_INT32, i); michael@0: #else michael@0: jsval_layout l; michael@0: l.s.tag = JSVAL_TAG_INT32; michael@0: l.s.payload.i32 = i; michael@0: return l; michael@0: #endif michael@0: } michael@0: michael@0: static inline bool michael@0: JSVAL_IS_NUMBER_IMPL(jsval_layout l) michael@0: { michael@0: JSValueTag tag = l.s.tag; michael@0: MOZ_ASSERT(tag != JSVAL_TAG_CLEAR); michael@0: return (uint32_t)tag <= (uint32_t)JSVAL_UPPER_INCL_TAG_OF_NUMBER_SET; michael@0: } michael@0: michael@0: static inline bool michael@0: JSVAL_IS_UNDEFINED_IMPL(jsval_layout l) michael@0: { michael@0: return l.s.tag == JSVAL_TAG_UNDEFINED; michael@0: } michael@0: michael@0: static inline bool michael@0: JSVAL_IS_STRING_IMPL(jsval_layout l) michael@0: { michael@0: return l.s.tag == JSVAL_TAG_STRING; michael@0: } michael@0: michael@0: static inline jsval_layout michael@0: STRING_TO_JSVAL_IMPL(JSString *str) michael@0: { michael@0: jsval_layout l; michael@0: MOZ_ASSERT(uintptr_t(str) > 0x1000); michael@0: l.s.tag = JSVAL_TAG_STRING; michael@0: l.s.payload.str = str; michael@0: return l; michael@0: } michael@0: michael@0: static inline JSString * michael@0: JSVAL_TO_STRING_IMPL(jsval_layout l) michael@0: { michael@0: return l.s.payload.str; michael@0: } michael@0: michael@0: static inline bool michael@0: JSVAL_IS_BOOLEAN_IMPL(jsval_layout l) michael@0: { michael@0: return l.s.tag == JSVAL_TAG_BOOLEAN; michael@0: } michael@0: michael@0: static inline bool michael@0: JSVAL_TO_BOOLEAN_IMPL(jsval_layout l) michael@0: { michael@0: return l.s.payload.boo; michael@0: } michael@0: michael@0: static inline jsval_layout michael@0: BOOLEAN_TO_JSVAL_IMPL(bool b) michael@0: { michael@0: jsval_layout l; michael@0: l.s.tag = JSVAL_TAG_BOOLEAN; michael@0: l.s.payload.boo = b; michael@0: return l; michael@0: } michael@0: michael@0: static inline bool michael@0: JSVAL_IS_MAGIC_IMPL(jsval_layout l) michael@0: { michael@0: return l.s.tag == JSVAL_TAG_MAGIC; michael@0: } michael@0: michael@0: static inline bool michael@0: JSVAL_IS_OBJECT_IMPL(jsval_layout l) michael@0: { michael@0: return l.s.tag == JSVAL_TAG_OBJECT; michael@0: } michael@0: michael@0: static inline bool michael@0: JSVAL_IS_PRIMITIVE_IMPL(jsval_layout l) michael@0: { michael@0: return (uint32_t)l.s.tag < (uint32_t)JSVAL_UPPER_EXCL_TAG_OF_PRIMITIVE_SET; michael@0: } michael@0: michael@0: static inline bool michael@0: JSVAL_IS_OBJECT_OR_NULL_IMPL(jsval_layout l) michael@0: { michael@0: MOZ_ASSERT((uint32_t)l.s.tag <= (uint32_t)JSVAL_TAG_OBJECT); michael@0: return (uint32_t)l.s.tag >= (uint32_t)JSVAL_LOWER_INCL_TAG_OF_OBJ_OR_NULL_SET; michael@0: } michael@0: michael@0: static inline JSObject * michael@0: JSVAL_TO_OBJECT_IMPL(jsval_layout l) michael@0: { michael@0: return l.s.payload.obj; michael@0: } michael@0: michael@0: static inline jsval_layout michael@0: OBJECT_TO_JSVAL_IMPL(JSObject *obj) michael@0: { michael@0: jsval_layout l; michael@0: MOZ_ASSERT(uintptr_t(obj) > 0x1000 || uintptr_t(obj) == 0x42); michael@0: l.s.tag = JSVAL_TAG_OBJECT; michael@0: l.s.payload.obj = obj; michael@0: return l; michael@0: } michael@0: michael@0: static inline bool michael@0: JSVAL_IS_NULL_IMPL(jsval_layout l) michael@0: { michael@0: return l.s.tag == JSVAL_TAG_NULL; michael@0: } michael@0: michael@0: static inline jsval_layout michael@0: PRIVATE_PTR_TO_JSVAL_IMPL(void *ptr) michael@0: { michael@0: jsval_layout l; michael@0: MOZ_ASSERT(((uint32_t)ptr & 1) == 0); michael@0: l.s.tag = (JSValueTag)0; michael@0: l.s.payload.ptr = ptr; michael@0: MOZ_ASSERT(JSVAL_IS_DOUBLE_IMPL(l)); michael@0: return l; michael@0: } michael@0: michael@0: static inline void * michael@0: JSVAL_TO_PRIVATE_PTR_IMPL(jsval_layout l) michael@0: { michael@0: return l.s.payload.ptr; michael@0: } michael@0: michael@0: static inline bool michael@0: JSVAL_IS_GCTHING_IMPL(jsval_layout l) michael@0: { michael@0: /* gcc sometimes generates signed < without explicit casts. */ michael@0: return (uint32_t)l.s.tag >= (uint32_t)JSVAL_LOWER_INCL_TAG_OF_GCTHING_SET; michael@0: } michael@0: michael@0: static inline void * michael@0: JSVAL_TO_GCTHING_IMPL(jsval_layout l) michael@0: { michael@0: return l.s.payload.ptr; michael@0: } michael@0: michael@0: static inline bool michael@0: JSVAL_IS_TRACEABLE_IMPL(jsval_layout l) michael@0: { michael@0: return l.s.tag == JSVAL_TAG_STRING || l.s.tag == JSVAL_TAG_OBJECT; michael@0: } michael@0: michael@0: static inline uint32_t michael@0: JSVAL_TRACE_KIND_IMPL(jsval_layout l) michael@0: { michael@0: return (uint32_t)(bool)JSVAL_IS_STRING_IMPL(l); michael@0: } michael@0: michael@0: static inline bool michael@0: JSVAL_IS_SPECIFIC_INT32_IMPL(jsval_layout l, int32_t i32) michael@0: { michael@0: return l.s.tag == JSVAL_TAG_INT32 && l.s.payload.i32 == i32; michael@0: } michael@0: michael@0: static inline bool michael@0: JSVAL_IS_SPECIFIC_BOOLEAN(jsval_layout l, bool b) michael@0: { michael@0: return (l.s.tag == JSVAL_TAG_BOOLEAN) && (l.s.payload.boo == uint32_t(b)); michael@0: } michael@0: michael@0: static inline jsval_layout michael@0: MAGIC_TO_JSVAL_IMPL(JSWhyMagic why) michael@0: { michael@0: jsval_layout l; michael@0: l.s.tag = JSVAL_TAG_MAGIC; michael@0: l.s.payload.why = why; michael@0: return l; michael@0: } michael@0: michael@0: static inline jsval_layout michael@0: MAGIC_UINT32_TO_JSVAL_IMPL(uint32_t payload) michael@0: { michael@0: jsval_layout l; michael@0: l.s.tag = JSVAL_TAG_MAGIC; michael@0: l.s.payload.u32 = payload; michael@0: return l; michael@0: } michael@0: michael@0: static inline bool michael@0: JSVAL_SAME_TYPE_IMPL(jsval_layout lhs, jsval_layout rhs) michael@0: { michael@0: JSValueTag ltag = lhs.s.tag, rtag = rhs.s.tag; michael@0: return ltag == rtag || (ltag < JSVAL_TAG_CLEAR && rtag < JSVAL_TAG_CLEAR); michael@0: } michael@0: michael@0: static inline JSValueType michael@0: JSVAL_EXTRACT_NON_DOUBLE_TYPE_IMPL(jsval_layout l) michael@0: { michael@0: uint32_t type = l.s.tag & 0xF; michael@0: MOZ_ASSERT(type > JSVAL_TYPE_DOUBLE); michael@0: return (JSValueType)type; michael@0: } michael@0: michael@0: #elif JS_BITS_PER_WORD == 64 michael@0: michael@0: static inline JS_VALUE_CONSTEXPR jsval_layout michael@0: BUILD_JSVAL(JSValueTag tag, uint64_t payload) michael@0: { michael@0: JS_RETURN_LAYOUT_FROM_BITS((((uint64_t)(uint32_t)tag) << JSVAL_TAG_SHIFT) | payload); michael@0: } michael@0: michael@0: static inline bool michael@0: JSVAL_IS_DOUBLE_IMPL(jsval_layout l) michael@0: { michael@0: return l.asBits <= JSVAL_SHIFTED_TAG_MAX_DOUBLE; michael@0: } michael@0: michael@0: static inline jsval_layout michael@0: DOUBLE_TO_JSVAL_IMPL(double d) michael@0: { michael@0: jsval_layout l; michael@0: l.asDouble = d; michael@0: MOZ_ASSERT(l.asBits <= JSVAL_SHIFTED_TAG_MAX_DOUBLE); michael@0: return l; michael@0: } michael@0: michael@0: static inline bool michael@0: JSVAL_IS_INT32_IMPL(jsval_layout l) michael@0: { michael@0: return (uint32_t)(l.asBits >> JSVAL_TAG_SHIFT) == JSVAL_TAG_INT32; michael@0: } michael@0: michael@0: static inline int32_t michael@0: JSVAL_TO_INT32_IMPL(jsval_layout l) michael@0: { michael@0: return (int32_t)l.asBits; michael@0: } michael@0: michael@0: static inline JS_VALUE_CONSTEXPR jsval_layout michael@0: INT32_TO_JSVAL_IMPL(int32_t i32) michael@0: { michael@0: JS_RETURN_LAYOUT_FROM_BITS(((uint64_t)(uint32_t)i32) | JSVAL_SHIFTED_TAG_INT32); michael@0: } michael@0: michael@0: static inline bool michael@0: JSVAL_IS_NUMBER_IMPL(jsval_layout l) michael@0: { michael@0: return l.asBits < JSVAL_UPPER_EXCL_SHIFTED_TAG_OF_NUMBER_SET; michael@0: } michael@0: michael@0: static inline bool michael@0: JSVAL_IS_UNDEFINED_IMPL(jsval_layout l) michael@0: { michael@0: return l.asBits == JSVAL_SHIFTED_TAG_UNDEFINED; michael@0: } michael@0: michael@0: static inline bool michael@0: JSVAL_IS_STRING_IMPL(jsval_layout l) michael@0: { michael@0: return (uint32_t)(l.asBits >> JSVAL_TAG_SHIFT) == JSVAL_TAG_STRING; michael@0: } michael@0: michael@0: static inline jsval_layout michael@0: STRING_TO_JSVAL_IMPL(JSString *str) michael@0: { michael@0: jsval_layout l; michael@0: uint64_t strBits = (uint64_t)str; michael@0: MOZ_ASSERT(uintptr_t(str) > 0x1000); michael@0: MOZ_ASSERT((strBits >> JSVAL_TAG_SHIFT) == 0); michael@0: l.asBits = strBits | JSVAL_SHIFTED_TAG_STRING; michael@0: return l; michael@0: } michael@0: michael@0: static inline JSString * michael@0: JSVAL_TO_STRING_IMPL(jsval_layout l) michael@0: { michael@0: return (JSString *)(l.asBits & JSVAL_PAYLOAD_MASK); michael@0: } michael@0: michael@0: static inline bool michael@0: JSVAL_IS_BOOLEAN_IMPL(jsval_layout l) michael@0: { michael@0: return (uint32_t)(l.asBits >> JSVAL_TAG_SHIFT) == JSVAL_TAG_BOOLEAN; michael@0: } michael@0: michael@0: static inline bool michael@0: JSVAL_TO_BOOLEAN_IMPL(jsval_layout l) michael@0: { michael@0: return (bool)(l.asBits & JSVAL_PAYLOAD_MASK); michael@0: } michael@0: michael@0: static inline jsval_layout michael@0: BOOLEAN_TO_JSVAL_IMPL(bool b) michael@0: { michael@0: jsval_layout l; michael@0: l.asBits = ((uint64_t)(uint32_t)b) | JSVAL_SHIFTED_TAG_BOOLEAN; michael@0: return l; michael@0: } michael@0: michael@0: static inline bool michael@0: JSVAL_IS_MAGIC_IMPL(jsval_layout l) michael@0: { michael@0: return (l.asBits >> JSVAL_TAG_SHIFT) == JSVAL_TAG_MAGIC; michael@0: } michael@0: michael@0: static inline bool michael@0: JSVAL_IS_PRIMITIVE_IMPL(jsval_layout l) michael@0: { michael@0: return l.asBits < JSVAL_UPPER_EXCL_SHIFTED_TAG_OF_PRIMITIVE_SET; michael@0: } michael@0: michael@0: static inline bool michael@0: JSVAL_IS_OBJECT_IMPL(jsval_layout l) michael@0: { michael@0: MOZ_ASSERT((l.asBits >> JSVAL_TAG_SHIFT) <= JSVAL_TAG_OBJECT); michael@0: return l.asBits >= JSVAL_SHIFTED_TAG_OBJECT; michael@0: } michael@0: michael@0: static inline bool michael@0: JSVAL_IS_OBJECT_OR_NULL_IMPL(jsval_layout l) michael@0: { michael@0: MOZ_ASSERT((l.asBits >> JSVAL_TAG_SHIFT) <= JSVAL_TAG_OBJECT); michael@0: return l.asBits >= JSVAL_LOWER_INCL_SHIFTED_TAG_OF_OBJ_OR_NULL_SET; michael@0: } michael@0: michael@0: static inline JSObject * michael@0: JSVAL_TO_OBJECT_IMPL(jsval_layout l) michael@0: { michael@0: uint64_t ptrBits = l.asBits & JSVAL_PAYLOAD_MASK; michael@0: MOZ_ASSERT((ptrBits & 0x7) == 0); michael@0: return (JSObject *)ptrBits; michael@0: } michael@0: michael@0: static inline jsval_layout michael@0: OBJECT_TO_JSVAL_IMPL(JSObject *obj) michael@0: { michael@0: jsval_layout l; michael@0: uint64_t objBits = (uint64_t)obj; michael@0: MOZ_ASSERT(uintptr_t(obj) > 0x1000 || uintptr_t(obj) == 0x42); michael@0: MOZ_ASSERT((objBits >> JSVAL_TAG_SHIFT) == 0); michael@0: l.asBits = objBits | JSVAL_SHIFTED_TAG_OBJECT; michael@0: return l; michael@0: } michael@0: michael@0: static inline bool michael@0: JSVAL_IS_NULL_IMPL(jsval_layout l) michael@0: { michael@0: return l.asBits == JSVAL_SHIFTED_TAG_NULL; michael@0: } michael@0: michael@0: static inline bool michael@0: JSVAL_IS_GCTHING_IMPL(jsval_layout l) michael@0: { michael@0: return l.asBits >= JSVAL_LOWER_INCL_SHIFTED_TAG_OF_GCTHING_SET; michael@0: } michael@0: michael@0: static inline void * michael@0: JSVAL_TO_GCTHING_IMPL(jsval_layout l) michael@0: { michael@0: uint64_t ptrBits = l.asBits & JSVAL_PAYLOAD_MASK; michael@0: MOZ_ASSERT((ptrBits & 0x7) == 0); michael@0: return (void *)ptrBits; michael@0: } michael@0: michael@0: static inline bool michael@0: JSVAL_IS_TRACEABLE_IMPL(jsval_layout l) michael@0: { michael@0: return JSVAL_IS_GCTHING_IMPL(l) && !JSVAL_IS_NULL_IMPL(l); michael@0: } michael@0: michael@0: static inline uint32_t michael@0: JSVAL_TRACE_KIND_IMPL(jsval_layout l) michael@0: { michael@0: return (uint32_t)(bool)!(JSVAL_IS_OBJECT_IMPL(l)); michael@0: } michael@0: michael@0: static inline jsval_layout michael@0: PRIVATE_PTR_TO_JSVAL_IMPL(void *ptr) michael@0: { michael@0: jsval_layout l; michael@0: uint64_t ptrBits = (uint64_t)ptr; michael@0: MOZ_ASSERT((ptrBits & 1) == 0); michael@0: l.asBits = ptrBits >> 1; michael@0: MOZ_ASSERT(JSVAL_IS_DOUBLE_IMPL(l)); michael@0: return l; michael@0: } michael@0: michael@0: static inline void * michael@0: JSVAL_TO_PRIVATE_PTR_IMPL(jsval_layout l) michael@0: { michael@0: MOZ_ASSERT((l.asBits & 0x8000000000000000LL) == 0); michael@0: return (void *)(l.asBits << 1); michael@0: } michael@0: michael@0: static inline bool michael@0: JSVAL_IS_SPECIFIC_INT32_IMPL(jsval_layout l, int32_t i32) michael@0: { michael@0: return l.asBits == (((uint64_t)(uint32_t)i32) | JSVAL_SHIFTED_TAG_INT32); michael@0: } michael@0: michael@0: static inline bool michael@0: JSVAL_IS_SPECIFIC_BOOLEAN(jsval_layout l, bool b) michael@0: { michael@0: return l.asBits == (((uint64_t)(uint32_t)b) | JSVAL_SHIFTED_TAG_BOOLEAN); michael@0: } michael@0: michael@0: static inline jsval_layout michael@0: MAGIC_TO_JSVAL_IMPL(JSWhyMagic why) michael@0: { michael@0: jsval_layout l; michael@0: l.asBits = ((uint64_t)(uint32_t)why) | JSVAL_SHIFTED_TAG_MAGIC; michael@0: return l; michael@0: } michael@0: michael@0: static inline jsval_layout michael@0: MAGIC_UINT32_TO_JSVAL_IMPL(uint32_t payload) michael@0: { michael@0: jsval_layout l; michael@0: l.asBits = ((uint64_t)payload) | JSVAL_SHIFTED_TAG_MAGIC; michael@0: return l; michael@0: } michael@0: michael@0: static inline bool michael@0: JSVAL_SAME_TYPE_IMPL(jsval_layout lhs, jsval_layout rhs) michael@0: { michael@0: uint64_t lbits = lhs.asBits, rbits = rhs.asBits; michael@0: return (lbits <= JSVAL_SHIFTED_TAG_MAX_DOUBLE && rbits <= JSVAL_SHIFTED_TAG_MAX_DOUBLE) || michael@0: (((lbits ^ rbits) & 0xFFFF800000000000LL) == 0); michael@0: } michael@0: michael@0: static inline JSValueType michael@0: JSVAL_EXTRACT_NON_DOUBLE_TYPE_IMPL(jsval_layout l) michael@0: { michael@0: uint64_t type = (l.asBits >> JSVAL_TAG_SHIFT) & 0xF; michael@0: MOZ_ASSERT(type > JSVAL_TYPE_DOUBLE); michael@0: return (JSValueType)type; michael@0: } michael@0: michael@0: #endif /* JS_BITS_PER_WORD */ michael@0: michael@0: static inline jsval_layout JSVAL_TO_IMPL(JS::Value v); michael@0: static inline JS_VALUE_CONSTEXPR JS::Value IMPL_TO_JSVAL(jsval_layout l); michael@0: michael@0: namespace JS { michael@0: michael@0: static inline JS_VALUE_CONSTEXPR JS::Value UndefinedValue(); michael@0: michael@0: /** michael@0: * Returns a generic quiet NaN value, with all payload bits set to zero. michael@0: * michael@0: * Among other properties, this NaN's bit pattern conforms to JS::Value's michael@0: * bit pattern restrictions. michael@0: */ michael@0: static MOZ_ALWAYS_INLINE double michael@0: GenericNaN() michael@0: { michael@0: return mozilla::SpecificNaN(0, 0x8000000000000ULL); michael@0: } michael@0: michael@0: /* MSVC with PGO miscompiles this function. */ michael@0: #if defined(_MSC_VER) michael@0: # pragma optimize("g", off) michael@0: #endif michael@0: static inline double michael@0: CanonicalizeNaN(double d) michael@0: { michael@0: if (MOZ_UNLIKELY(mozilla::IsNaN(d))) michael@0: return GenericNaN(); michael@0: return d; michael@0: } michael@0: #if defined(_MSC_VER) michael@0: # pragma optimize("", on) michael@0: #endif michael@0: michael@0: /* michael@0: * JS::Value is the interface for a single JavaScript Engine value. A few michael@0: * general notes on JS::Value: michael@0: * michael@0: * - JS::Value has setX() and isX() members for X in michael@0: * michael@0: * { Int32, Double, String, Boolean, Undefined, Null, Object, Magic } michael@0: * michael@0: * JS::Value also contains toX() for each of the non-singleton types. michael@0: * michael@0: * - Magic is a singleton type whose payload contains either a JSWhyMagic "reason" for michael@0: * the magic value or a uint32_t value. By providing JSWhyMagic values when michael@0: * creating and checking for magic values, it is possible to assert, at michael@0: * runtime, that only magic values with the expected reason flow through a michael@0: * particular value. For example, if cx->exception has a magic value, the michael@0: * reason must be JS_GENERATOR_CLOSING. michael@0: * michael@0: * - The JS::Value operations are preferred. The JSVAL_* operations remain for michael@0: * compatibility; they may be removed at some point. These operations mostly michael@0: * provide similar functionality. But there are a few key differences. One michael@0: * is that JS::Value gives null a separate type. Thus michael@0: * michael@0: * JSVAL_IS_OBJECT(v) === v.isObjectOrNull() michael@0: * !JSVAL_IS_PRIMITIVE(v) === v.isObject() michael@0: * michael@0: * Also, to help prevent mistakenly boxing a nullable JSObject* as an object, michael@0: * Value::setObject takes a JSObject&. (Conversely, Value::toObject returns a michael@0: * JSObject&.) A convenience member Value::setObjectOrNull is provided. michael@0: * michael@0: * - JSVAL_VOID is the same as the singleton value of the Undefined type. michael@0: * michael@0: * - Note that JS::Value is 8 bytes on 32 and 64-bit architectures. Thus, on michael@0: * 32-bit user code should avoid copying jsval/JS::Value as much as possible, michael@0: * preferring to pass by const Value &. michael@0: */ michael@0: class Value michael@0: { michael@0: public: michael@0: /* michael@0: * N.B. the default constructor leaves Value unitialized. Adding a default michael@0: * constructor prevents Value from being stored in a union. michael@0: */ michael@0: #if defined(JS_VALUE_IS_CONSTEXPR) michael@0: Value() = default; michael@0: Value(const Value& v) = default; michael@0: #endif michael@0: michael@0: /*** Mutators ***/ michael@0: michael@0: void setNull() { michael@0: data.asBits = BUILD_JSVAL(JSVAL_TAG_NULL, 0).asBits; michael@0: } michael@0: michael@0: void setUndefined() { michael@0: data.asBits = BUILD_JSVAL(JSVAL_TAG_UNDEFINED, 0).asBits; michael@0: } michael@0: michael@0: void setInt32(int32_t i) { michael@0: data = INT32_TO_JSVAL_IMPL(i); michael@0: } michael@0: michael@0: int32_t &getInt32Ref() { michael@0: MOZ_ASSERT(isInt32()); michael@0: return data.s.payload.i32; michael@0: } michael@0: michael@0: void setDouble(double d) { michael@0: data = DOUBLE_TO_JSVAL_IMPL(d); michael@0: } michael@0: michael@0: void setNaN() { michael@0: setDouble(GenericNaN()); michael@0: } michael@0: michael@0: double &getDoubleRef() { michael@0: MOZ_ASSERT(isDouble()); michael@0: return data.asDouble; michael@0: } michael@0: michael@0: void setString(JSString *str) { michael@0: MOZ_ASSERT(!IsPoisonedPtr(str)); michael@0: data = STRING_TO_JSVAL_IMPL(str); michael@0: } michael@0: michael@0: void setObject(JSObject &obj) { michael@0: MOZ_ASSERT(!IsPoisonedPtr(&obj)); michael@0: data = OBJECT_TO_JSVAL_IMPL(&obj); michael@0: } michael@0: michael@0: void setBoolean(bool b) { michael@0: data = BOOLEAN_TO_JSVAL_IMPL(b); michael@0: } michael@0: michael@0: void setMagic(JSWhyMagic why) { michael@0: data = MAGIC_TO_JSVAL_IMPL(why); michael@0: } michael@0: michael@0: void setMagicUint32(uint32_t payload) { michael@0: data = MAGIC_UINT32_TO_JSVAL_IMPL(payload); michael@0: } michael@0: michael@0: bool setNumber(uint32_t ui) { michael@0: if (ui > JSVAL_INT_MAX) { michael@0: setDouble((double)ui); michael@0: return false; michael@0: } else { michael@0: setInt32((int32_t)ui); michael@0: return true; michael@0: } michael@0: } michael@0: michael@0: bool setNumber(double d) { michael@0: int32_t i; michael@0: if (mozilla::NumberIsInt32(d, &i)) { michael@0: setInt32(i); michael@0: return true; michael@0: } michael@0: michael@0: setDouble(d); michael@0: return false; michael@0: } michael@0: michael@0: void setObjectOrNull(JSObject *arg) { michael@0: if (arg) michael@0: setObject(*arg); michael@0: else michael@0: setNull(); michael@0: } michael@0: michael@0: void swap(Value &rhs) { michael@0: uint64_t tmp = rhs.data.asBits; michael@0: rhs.data.asBits = data.asBits; michael@0: data.asBits = tmp; michael@0: } michael@0: michael@0: /*** Value type queries ***/ michael@0: michael@0: bool isUndefined() const { michael@0: return JSVAL_IS_UNDEFINED_IMPL(data); michael@0: } michael@0: michael@0: bool isNull() const { michael@0: return JSVAL_IS_NULL_IMPL(data); michael@0: } michael@0: michael@0: bool isNullOrUndefined() const { michael@0: return isNull() || isUndefined(); michael@0: } michael@0: michael@0: bool isInt32() const { michael@0: return JSVAL_IS_INT32_IMPL(data); michael@0: } michael@0: michael@0: bool isInt32(int32_t i32) const { michael@0: return JSVAL_IS_SPECIFIC_INT32_IMPL(data, i32); michael@0: } michael@0: michael@0: bool isDouble() const { michael@0: return JSVAL_IS_DOUBLE_IMPL(data); michael@0: } michael@0: michael@0: bool isNumber() const { michael@0: return JSVAL_IS_NUMBER_IMPL(data); michael@0: } michael@0: michael@0: bool isString() const { michael@0: return JSVAL_IS_STRING_IMPL(data); michael@0: } michael@0: michael@0: bool isObject() const { michael@0: return JSVAL_IS_OBJECT_IMPL(data); michael@0: } michael@0: michael@0: bool isPrimitive() const { michael@0: return JSVAL_IS_PRIMITIVE_IMPL(data); michael@0: } michael@0: michael@0: bool isObjectOrNull() const { michael@0: return JSVAL_IS_OBJECT_OR_NULL_IMPL(data); michael@0: } michael@0: michael@0: bool isGCThing() const { michael@0: return JSVAL_IS_GCTHING_IMPL(data); michael@0: } michael@0: michael@0: bool isBoolean() const { michael@0: return JSVAL_IS_BOOLEAN_IMPL(data); michael@0: } michael@0: michael@0: bool isTrue() const { michael@0: return JSVAL_IS_SPECIFIC_BOOLEAN(data, true); michael@0: } michael@0: michael@0: bool isFalse() const { michael@0: return JSVAL_IS_SPECIFIC_BOOLEAN(data, false); michael@0: } michael@0: michael@0: bool isMagic() const { michael@0: return JSVAL_IS_MAGIC_IMPL(data); michael@0: } michael@0: michael@0: bool isMagic(JSWhyMagic why) const { michael@0: MOZ_ASSERT_IF(isMagic(), data.s.payload.why == why); michael@0: return JSVAL_IS_MAGIC_IMPL(data); michael@0: } michael@0: michael@0: bool isMarkable() const { michael@0: return JSVAL_IS_TRACEABLE_IMPL(data); michael@0: } michael@0: michael@0: JSGCTraceKind gcKind() const { michael@0: MOZ_ASSERT(isMarkable()); michael@0: return JSGCTraceKind(JSVAL_TRACE_KIND_IMPL(data)); michael@0: } michael@0: michael@0: JSWhyMagic whyMagic() const { michael@0: MOZ_ASSERT(isMagic()); michael@0: return data.s.payload.why; michael@0: } michael@0: michael@0: uint32_t magicUint32() const { michael@0: MOZ_ASSERT(isMagic()); michael@0: return data.s.payload.u32; michael@0: } michael@0: michael@0: /*** Comparison ***/ michael@0: michael@0: bool operator==(const Value &rhs) const { michael@0: return data.asBits == rhs.data.asBits; michael@0: } michael@0: michael@0: bool operator!=(const Value &rhs) const { michael@0: return data.asBits != rhs.data.asBits; michael@0: } michael@0: michael@0: friend inline bool SameType(const Value &lhs, const Value &rhs); michael@0: michael@0: /*** Extract the value's typed payload ***/ michael@0: michael@0: int32_t toInt32() const { michael@0: MOZ_ASSERT(isInt32()); michael@0: return JSVAL_TO_INT32_IMPL(data); michael@0: } michael@0: michael@0: double toDouble() const { michael@0: MOZ_ASSERT(isDouble()); michael@0: return data.asDouble; michael@0: } michael@0: michael@0: double toNumber() const { michael@0: MOZ_ASSERT(isNumber()); michael@0: return isDouble() ? toDouble() : double(toInt32()); michael@0: } michael@0: michael@0: JSString *toString() const { michael@0: MOZ_ASSERT(isString()); michael@0: return JSVAL_TO_STRING_IMPL(data); michael@0: } michael@0: michael@0: JSObject &toObject() const { michael@0: MOZ_ASSERT(isObject()); michael@0: return *JSVAL_TO_OBJECT_IMPL(data); michael@0: } michael@0: michael@0: JSObject *toObjectOrNull() const { michael@0: MOZ_ASSERT(isObjectOrNull()); michael@0: return JSVAL_TO_OBJECT_IMPL(data); michael@0: } michael@0: michael@0: void *toGCThing() const { michael@0: MOZ_ASSERT(isGCThing()); michael@0: return JSVAL_TO_GCTHING_IMPL(data); michael@0: } michael@0: michael@0: bool toBoolean() const { michael@0: MOZ_ASSERT(isBoolean()); michael@0: return JSVAL_TO_BOOLEAN_IMPL(data); michael@0: } michael@0: michael@0: uint32_t payloadAsRawUint32() const { michael@0: MOZ_ASSERT(!isDouble()); michael@0: return data.s.payload.u32; michael@0: } michael@0: michael@0: uint64_t asRawBits() const { michael@0: return data.asBits; michael@0: } michael@0: michael@0: JSValueType extractNonDoubleType() const { michael@0: return JSVAL_EXTRACT_NON_DOUBLE_TYPE_IMPL(data); michael@0: } michael@0: michael@0: /* michael@0: * Private API michael@0: * michael@0: * Private setters/getters allow the caller to read/write arbitrary types michael@0: * that fit in the 64-bit payload. It is the caller's responsibility, after michael@0: * storing to a value with setPrivateX to read only using getPrivateX. michael@0: * Privates values are given a type which ensures they are not marked. michael@0: */ michael@0: michael@0: void setPrivate(void *ptr) { michael@0: data = PRIVATE_PTR_TO_JSVAL_IMPL(ptr); michael@0: } michael@0: michael@0: void *toPrivate() const { michael@0: MOZ_ASSERT(JSVAL_IS_DOUBLE_IMPL(data)); michael@0: return JSVAL_TO_PRIVATE_PTR_IMPL(data); michael@0: } michael@0: michael@0: void setPrivateUint32(uint32_t ui) { michael@0: MOZ_ASSERT(uint32_t(int32_t(ui)) == ui); michael@0: setInt32(int32_t(ui)); michael@0: } michael@0: michael@0: uint32_t toPrivateUint32() const { michael@0: return uint32_t(toInt32()); michael@0: } michael@0: michael@0: /* michael@0: * An unmarked value is just a void* cast as a Value. Thus, the Value is michael@0: * not safe for GC and must not be marked. This API avoids raw casts michael@0: * and the ensuing strict-aliasing warnings. michael@0: */ michael@0: michael@0: void setUnmarkedPtr(void *ptr) { michael@0: data.asPtr = ptr; michael@0: } michael@0: michael@0: void *toUnmarkedPtr() const { michael@0: return data.asPtr; michael@0: } michael@0: michael@0: const size_t *payloadWord() const { michael@0: #if JS_BITS_PER_WORD == 32 michael@0: return &data.s.payload.word; michael@0: #elif JS_BITS_PER_WORD == 64 michael@0: return &data.asWord; michael@0: #endif michael@0: } michael@0: michael@0: const uintptr_t *payloadUIntPtr() const { michael@0: #if JS_BITS_PER_WORD == 32 michael@0: return &data.s.payload.uintptr; michael@0: #elif JS_BITS_PER_WORD == 64 michael@0: return &data.asUIntPtr; michael@0: #endif michael@0: } michael@0: michael@0: #if !defined(_MSC_VER) && !defined(__sparc) michael@0: // Value must be POD so that MSVC will pass it by value and not in memory michael@0: // (bug 689101); the same is true for SPARC as well (bug 737344). More michael@0: // precisely, we don't want Value return values compiled as out params. michael@0: private: michael@0: #endif michael@0: michael@0: jsval_layout data; michael@0: michael@0: private: michael@0: #if defined(JS_VALUE_IS_CONSTEXPR) michael@0: JS_VALUE_CONSTEXPR Value(jsval_layout layout) : data(layout) {} michael@0: #endif michael@0: michael@0: void staticAssertions() { michael@0: JS_STATIC_ASSERT(sizeof(JSValueType) == 1); michael@0: JS_STATIC_ASSERT(sizeof(JSValueTag) == 4); michael@0: JS_STATIC_ASSERT(sizeof(JSWhyMagic) <= 4); michael@0: JS_STATIC_ASSERT(sizeof(Value) == 8); michael@0: } michael@0: michael@0: friend jsval_layout (::JSVAL_TO_IMPL)(Value); michael@0: friend Value JS_VALUE_CONSTEXPR (::IMPL_TO_JSVAL)(jsval_layout l); michael@0: friend Value JS_VALUE_CONSTEXPR (JS::UndefinedValue)(); michael@0: }; michael@0: michael@0: inline bool michael@0: IsPoisonedValue(const Value &v) michael@0: { michael@0: if (v.isString()) michael@0: return IsPoisonedPtr(v.toString()); michael@0: if (v.isObject()) michael@0: return IsPoisonedPtr(&v.toObject()); michael@0: return false; michael@0: } michael@0: michael@0: inline bool michael@0: IsOptimizedPlaceholderMagicValue(const Value &v) michael@0: { michael@0: if (v.isMagic()) { michael@0: MOZ_ASSERT(v.whyMagic() == JS_OPTIMIZED_ARGUMENTS || v.whyMagic() == JS_OPTIMIZED_OUT); michael@0: return true; michael@0: } michael@0: return false; michael@0: } michael@0: michael@0: /************************************************************************/ michael@0: michael@0: static inline Value michael@0: NullValue() michael@0: { michael@0: Value v; michael@0: v.setNull(); michael@0: return v; michael@0: } michael@0: michael@0: static inline JS_VALUE_CONSTEXPR Value michael@0: UndefinedValue() michael@0: { michael@0: #if defined(JS_VALUE_IS_CONSTEXPR) michael@0: return Value(BUILD_JSVAL(JSVAL_TAG_UNDEFINED, 0)); michael@0: #else michael@0: JS::Value v; michael@0: v.setUndefined(); michael@0: return v; michael@0: #endif michael@0: } michael@0: michael@0: static inline Value michael@0: Int32Value(int32_t i32) michael@0: { michael@0: Value v; michael@0: v.setInt32(i32); michael@0: return v; michael@0: } michael@0: michael@0: static inline Value michael@0: DoubleValue(double dbl) michael@0: { michael@0: Value v; michael@0: v.setDouble(dbl); michael@0: return v; michael@0: } michael@0: michael@0: static inline Value michael@0: DoubleNaNValue() michael@0: { michael@0: Value v; michael@0: v.setNaN(); michael@0: return v; michael@0: } michael@0: michael@0: static inline Value michael@0: Float32Value(float f) michael@0: { michael@0: Value v; michael@0: v.setDouble(f); michael@0: return v; michael@0: } michael@0: michael@0: static inline Value michael@0: StringValue(JSString *str) michael@0: { michael@0: Value v; michael@0: v.setString(str); michael@0: return v; michael@0: } michael@0: michael@0: static inline Value michael@0: BooleanValue(bool boo) michael@0: { michael@0: Value v; michael@0: v.setBoolean(boo); michael@0: return v; michael@0: } michael@0: michael@0: static inline Value michael@0: TrueValue() michael@0: { michael@0: Value v; michael@0: v.setBoolean(true); michael@0: return v; michael@0: } michael@0: michael@0: static inline Value michael@0: FalseValue() michael@0: { michael@0: Value v; michael@0: v.setBoolean(false); michael@0: return v; michael@0: } michael@0: michael@0: static inline Value michael@0: ObjectValue(JSObject &obj) michael@0: { michael@0: Value v; michael@0: v.setObject(obj); michael@0: return v; michael@0: } michael@0: michael@0: static inline Value michael@0: ObjectValueCrashOnTouch() michael@0: { michael@0: Value v; michael@0: v.setObject(*reinterpret_cast(0x42)); michael@0: return v; michael@0: } michael@0: michael@0: static inline Value michael@0: MagicValue(JSWhyMagic why) michael@0: { michael@0: Value v; michael@0: v.setMagic(why); michael@0: return v; michael@0: } michael@0: michael@0: static inline Value michael@0: MagicValueUint32(uint32_t payload) michael@0: { michael@0: Value v; michael@0: v.setMagicUint32(payload); michael@0: return v; michael@0: } michael@0: michael@0: static inline Value michael@0: NumberValue(float f) michael@0: { michael@0: Value v; michael@0: v.setNumber(f); michael@0: return v; michael@0: } michael@0: michael@0: static inline Value michael@0: NumberValue(double dbl) michael@0: { michael@0: Value v; michael@0: v.setNumber(dbl); michael@0: return v; michael@0: } michael@0: michael@0: static inline Value michael@0: NumberValue(int8_t i) michael@0: { michael@0: return Int32Value(i); michael@0: } michael@0: michael@0: static inline Value michael@0: NumberValue(uint8_t i) michael@0: { michael@0: return Int32Value(i); michael@0: } michael@0: michael@0: static inline Value michael@0: NumberValue(int16_t i) michael@0: { michael@0: return Int32Value(i); michael@0: } michael@0: michael@0: static inline Value michael@0: NumberValue(uint16_t i) michael@0: { michael@0: return Int32Value(i); michael@0: } michael@0: michael@0: static inline Value michael@0: NumberValue(int32_t i) michael@0: { michael@0: return Int32Value(i); michael@0: } michael@0: michael@0: static inline Value michael@0: NumberValue(uint32_t i) michael@0: { michael@0: Value v; michael@0: v.setNumber(i); michael@0: return v; michael@0: } michael@0: michael@0: namespace detail { michael@0: michael@0: template michael@0: class MakeNumberValue michael@0: { michael@0: public: michael@0: template michael@0: static inline Value create(const T t) michael@0: { michael@0: Value v; michael@0: if (JSVAL_INT_MIN <= t && t <= JSVAL_INT_MAX) michael@0: v.setInt32(int32_t(t)); michael@0: else michael@0: v.setDouble(double(t)); michael@0: return v; michael@0: } michael@0: }; michael@0: michael@0: template <> michael@0: class MakeNumberValue michael@0: { michael@0: public: michael@0: template michael@0: static inline Value create(const T t) michael@0: { michael@0: Value v; michael@0: if (t <= JSVAL_INT_MAX) michael@0: v.setInt32(int32_t(t)); michael@0: else michael@0: v.setDouble(double(t)); michael@0: return v; michael@0: } michael@0: }; michael@0: michael@0: } // namespace detail michael@0: michael@0: template michael@0: static inline Value michael@0: NumberValue(const T t) michael@0: { michael@0: MOZ_ASSERT(T(double(t)) == t, "value creation would be lossy"); michael@0: return detail::MakeNumberValue::is_signed>::create(t); michael@0: } michael@0: michael@0: static inline Value michael@0: ObjectOrNullValue(JSObject *obj) michael@0: { michael@0: Value v; michael@0: v.setObjectOrNull(obj); michael@0: return v; michael@0: } michael@0: michael@0: static inline Value michael@0: PrivateValue(void *ptr) michael@0: { michael@0: Value v; michael@0: v.setPrivate(ptr); michael@0: return v; michael@0: } michael@0: michael@0: static inline Value michael@0: PrivateUint32Value(uint32_t ui) michael@0: { michael@0: Value v; michael@0: v.setPrivateUint32(ui); michael@0: return v; michael@0: } michael@0: michael@0: inline bool michael@0: SameType(const Value &lhs, const Value &rhs) michael@0: { michael@0: return JSVAL_SAME_TYPE_IMPL(lhs.data, rhs.data); michael@0: } michael@0: michael@0: } // namespace JS michael@0: michael@0: /************************************************************************/ michael@0: michael@0: #ifdef JSGC_GENERATIONAL michael@0: namespace JS { michael@0: JS_PUBLIC_API(void) HeapValuePostBarrier(Value *valuep); michael@0: JS_PUBLIC_API(void) HeapValueRelocate(Value *valuep); michael@0: } michael@0: #endif michael@0: michael@0: namespace js { michael@0: michael@0: template <> struct GCMethods michael@0: { michael@0: static JS::Value initial() { return JS::UndefinedValue(); } michael@0: static ThingRootKind kind() { return THING_ROOT_VALUE; } michael@0: static bool poisoned(const JS::Value &v) { return JS::IsPoisonedValue(v); } michael@0: }; michael@0: michael@0: template <> struct GCMethods michael@0: { michael@0: static JS::Value initial() { return JS::UndefinedValue(); } michael@0: static ThingRootKind kind() { return THING_ROOT_VALUE; } michael@0: static bool poisoned(const JS::Value &v) { return JS::IsPoisonedValue(v); } michael@0: static bool needsPostBarrier(const JS::Value &v) { return v.isMarkable(); } michael@0: #ifdef JSGC_GENERATIONAL michael@0: static void postBarrier(JS::Value *v) { JS::HeapValuePostBarrier(v); } michael@0: static void relocate(JS::Value *v) { JS::HeapValueRelocate(v); } michael@0: #endif michael@0: }; michael@0: michael@0: template class MutableValueOperations; michael@0: michael@0: /* michael@0: * A class designed for CRTP use in implementing the non-mutating parts of the michael@0: * Value interface in Value-like classes. Outer must be a class inheriting michael@0: * ValueOperations with a visible extract() method returning the michael@0: * const Value* abstracted by Outer. michael@0: */ michael@0: template michael@0: class ValueOperations michael@0: { michael@0: friend class MutableValueOperations; michael@0: michael@0: const JS::Value * value() const { return static_cast(this)->extract(); } michael@0: michael@0: public: michael@0: bool isUndefined() const { return value()->isUndefined(); } michael@0: bool isNull() const { return value()->isNull(); } michael@0: bool isBoolean() const { return value()->isBoolean(); } michael@0: bool isTrue() const { return value()->isTrue(); } michael@0: bool isFalse() const { return value()->isFalse(); } michael@0: bool isNumber() const { return value()->isNumber(); } michael@0: bool isInt32() const { return value()->isInt32(); } michael@0: bool isDouble() const { return value()->isDouble(); } michael@0: bool isString() const { return value()->isString(); } michael@0: bool isObject() const { return value()->isObject(); } michael@0: bool isMagic() const { return value()->isMagic(); } michael@0: bool isMagic(JSWhyMagic why) const { return value()->isMagic(why); } michael@0: bool isMarkable() const { return value()->isMarkable(); } michael@0: bool isPrimitive() const { return value()->isPrimitive(); } michael@0: bool isGCThing() const { return value()->isGCThing(); } michael@0: michael@0: bool isNullOrUndefined() const { return value()->isNullOrUndefined(); } michael@0: bool isObjectOrNull() const { return value()->isObjectOrNull(); } michael@0: michael@0: bool toBoolean() const { return value()->toBoolean(); } michael@0: double toNumber() const { return value()->toNumber(); } michael@0: int32_t toInt32() const { return value()->toInt32(); } michael@0: double toDouble() const { return value()->toDouble(); } michael@0: JSString *toString() const { return value()->toString(); } michael@0: JSObject &toObject() const { return value()->toObject(); } michael@0: JSObject *toObjectOrNull() const { return value()->toObjectOrNull(); } michael@0: void *toGCThing() const { return value()->toGCThing(); } michael@0: michael@0: JSValueType extractNonDoubleType() const { return value()->extractNonDoubleType(); } michael@0: uint32_t toPrivateUint32() const { return value()->toPrivateUint32(); } michael@0: michael@0: JSWhyMagic whyMagic() const { return value()->whyMagic(); } michael@0: uint32_t magicUint32() const { return value()->magicUint32(); } michael@0: }; michael@0: michael@0: /* michael@0: * A class designed for CRTP use in implementing all the mutating parts of the michael@0: * Value interface in Value-like classes. Outer must be a class inheriting michael@0: * MutableValueOperations with visible extractMutable() and extract() michael@0: * methods returning the const Value* and Value* abstracted by Outer. michael@0: */ michael@0: template michael@0: class MutableValueOperations : public ValueOperations michael@0: { michael@0: JS::Value * value() { return static_cast(this)->extractMutable(); } michael@0: michael@0: public: michael@0: void setNull() { value()->setNull(); } michael@0: void setUndefined() { value()->setUndefined(); } michael@0: void setInt32(int32_t i) { value()->setInt32(i); } michael@0: void setDouble(double d) { value()->setDouble(d); } michael@0: void setNaN() { setDouble(JS::GenericNaN()); } michael@0: void setBoolean(bool b) { value()->setBoolean(b); } michael@0: void setMagic(JSWhyMagic why) { value()->setMagic(why); } michael@0: bool setNumber(uint32_t ui) { return value()->setNumber(ui); } michael@0: bool setNumber(double d) { return value()->setNumber(d); } michael@0: void setString(JSString *str) { this->value()->setString(str); } michael@0: void setObject(JSObject &obj) { this->value()->setObject(obj); } michael@0: void setObjectOrNull(JSObject *arg) { this->value()->setObjectOrNull(arg); } michael@0: }; michael@0: michael@0: /* michael@0: * Augment the generic Heap interface when T = Value with michael@0: * type-querying, value-extracting, and mutating operations. michael@0: */ michael@0: template <> michael@0: class HeapBase : public ValueOperations > michael@0: { michael@0: typedef JS::Heap Outer; michael@0: michael@0: friend class ValueOperations; michael@0: michael@0: const JS::Value * extract() const { return static_cast(this)->address(); } michael@0: michael@0: void setBarriered(const JS::Value &v) { michael@0: static_cast *>(this)->set(v); michael@0: } michael@0: michael@0: public: michael@0: void setNull() { setBarriered(JS::NullValue()); } michael@0: void setUndefined() { setBarriered(JS::UndefinedValue()); } michael@0: void setInt32(int32_t i) { setBarriered(JS::Int32Value(i)); } michael@0: void setDouble(double d) { setBarriered(JS::DoubleValue(d)); } michael@0: void setNaN() { setDouble(JS::GenericNaN()); } michael@0: void setBoolean(bool b) { setBarriered(JS::BooleanValue(b)); } michael@0: void setMagic(JSWhyMagic why) { setBarriered(JS::MagicValue(why)); } michael@0: void setString(JSString *str) { setBarriered(JS::StringValue(str)); } michael@0: void setObject(JSObject &obj) { setBarriered(JS::ObjectValue(obj)); } michael@0: michael@0: bool setNumber(uint32_t ui) { michael@0: if (ui > JSVAL_INT_MAX) { michael@0: setDouble((double)ui); michael@0: return false; michael@0: } else { michael@0: setInt32((int32_t)ui); michael@0: return true; michael@0: } michael@0: } michael@0: michael@0: bool setNumber(double d) { michael@0: int32_t i; michael@0: if (mozilla::NumberIsInt32(d, &i)) { michael@0: setInt32(i); michael@0: return true; michael@0: } michael@0: michael@0: setDouble(d); michael@0: return false; michael@0: } michael@0: michael@0: void setObjectOrNull(JSObject *arg) { michael@0: if (arg) michael@0: setObject(*arg); michael@0: else michael@0: setNull(); michael@0: } michael@0: }; michael@0: michael@0: /* michael@0: * Augment the generic Handle interface when T = Value with type-querying michael@0: * and value-extracting operations. michael@0: */ michael@0: template <> michael@0: class HandleBase : public ValueOperations > michael@0: { michael@0: friend class ValueOperations >; michael@0: const JS::Value * extract() const { michael@0: return static_cast*>(this)->address(); michael@0: } michael@0: }; michael@0: michael@0: /* michael@0: * Augment the generic MutableHandle interface when T = Value with michael@0: * type-querying, value-extracting, and mutating operations. michael@0: */ michael@0: template <> michael@0: class MutableHandleBase : public MutableValueOperations > michael@0: { michael@0: friend class ValueOperations >; michael@0: const JS::Value * extract() const { michael@0: return static_cast*>(this)->address(); michael@0: } michael@0: michael@0: friend class MutableValueOperations >; michael@0: JS::Value * extractMutable() { michael@0: return static_cast*>(this)->address(); michael@0: } michael@0: }; michael@0: michael@0: /* michael@0: * Augment the generic Rooted interface when T = Value with type-querying, michael@0: * value-extracting, and mutating operations. michael@0: */ michael@0: template <> michael@0: class RootedBase : public MutableValueOperations > michael@0: { michael@0: friend class ValueOperations >; michael@0: const JS::Value * extract() const { michael@0: return static_cast*>(this)->address(); michael@0: } michael@0: michael@0: friend class MutableValueOperations >; michael@0: JS::Value * extractMutable() { michael@0: return static_cast*>(this)->address(); michael@0: } michael@0: }; michael@0: michael@0: } // namespace js michael@0: michael@0: inline jsval_layout michael@0: JSVAL_TO_IMPL(JS::Value v) michael@0: { michael@0: return v.data; michael@0: } michael@0: michael@0: inline JS_VALUE_CONSTEXPR JS::Value michael@0: IMPL_TO_JSVAL(jsval_layout l) michael@0: { michael@0: #if defined(JS_VALUE_IS_CONSTEXPR) michael@0: return JS::Value(l); michael@0: #else michael@0: JS::Value v; michael@0: v.data = l; michael@0: return v; michael@0: #endif michael@0: } michael@0: michael@0: namespace JS { michael@0: michael@0: #ifndef __GNUC__ michael@0: /* michael@0: * The default assignment operator for |struct C| has the signature: michael@0: * michael@0: * C& C::operator=(const C&) michael@0: * michael@0: * And in particular requires implicit conversion of |this| to type |C| for the michael@0: * return value. But |volatile C| cannot thus be converted to |C|, so just michael@0: * doing |sink = hold| as in the non-specialized version would fail to compile. michael@0: * Do the assignment on asBits instead, since I don't think we want to give michael@0: * jsval_layout an assignment operator returning |volatile jsval_layout|. michael@0: */ michael@0: template<> michael@0: inline Anchor::~Anchor() michael@0: { michael@0: volatile uint64_t bits; michael@0: bits = JSVAL_TO_IMPL(hold).asBits; michael@0: } michael@0: #endif michael@0: michael@0: #ifdef JS_DEBUG michael@0: namespace detail { michael@0: michael@0: struct ValueAlignmentTester { char c; JS::Value v; }; michael@0: static_assert(sizeof(ValueAlignmentTester) == 16, michael@0: "JS::Value must be 16-byte-aligned"); michael@0: michael@0: struct LayoutAlignmentTester { char c; jsval_layout l; }; michael@0: static_assert(sizeof(LayoutAlignmentTester) == 16, michael@0: "jsval_layout must be 16-byte-aligned"); michael@0: michael@0: } // namespace detail michael@0: #endif /* JS_DEBUG */ michael@0: michael@0: } // namespace JS michael@0: michael@0: /* michael@0: * JS::Value and jsval are the same type; jsval is the old name, kept around michael@0: * for backwards compatibility along with all the JSVAL_* operations below. michael@0: * jsval_layout is an implementation detail and should not be used externally. michael@0: */ michael@0: typedef JS::Value jsval; michael@0: michael@0: static_assert(sizeof(jsval_layout) == sizeof(JS::Value), michael@0: "jsval_layout and JS::Value must have identical layouts"); michael@0: michael@0: /************************************************************************/ michael@0: michael@0: static inline bool michael@0: JSVAL_IS_NULL(jsval v) michael@0: { michael@0: return JSVAL_IS_NULL_IMPL(JSVAL_TO_IMPL(v)); michael@0: } michael@0: michael@0: static inline bool michael@0: JSVAL_IS_VOID(jsval v) michael@0: { michael@0: return JSVAL_IS_UNDEFINED_IMPL(JSVAL_TO_IMPL(v)); michael@0: } michael@0: michael@0: static inline bool michael@0: JSVAL_IS_INT(jsval v) michael@0: { michael@0: return JSVAL_IS_INT32_IMPL(JSVAL_TO_IMPL(v)); michael@0: } michael@0: michael@0: static inline int32_t michael@0: JSVAL_TO_INT(jsval v) michael@0: { michael@0: MOZ_ASSERT(JSVAL_IS_INT(v)); michael@0: return JSVAL_TO_INT32_IMPL(JSVAL_TO_IMPL(v)); michael@0: } michael@0: michael@0: static inline JS_VALUE_CONSTEXPR jsval michael@0: INT_TO_JSVAL(int32_t i) michael@0: { michael@0: return IMPL_TO_JSVAL(INT32_TO_JSVAL_IMPL(i)); michael@0: } michael@0: michael@0: static inline bool michael@0: JSVAL_IS_DOUBLE(jsval v) michael@0: { michael@0: return JSVAL_IS_DOUBLE_IMPL(JSVAL_TO_IMPL(v)); michael@0: } michael@0: michael@0: static inline double michael@0: JSVAL_TO_DOUBLE(jsval v) michael@0: { michael@0: jsval_layout l; michael@0: MOZ_ASSERT(JSVAL_IS_DOUBLE(v)); michael@0: l = JSVAL_TO_IMPL(v); michael@0: return l.asDouble; michael@0: } michael@0: michael@0: static inline JS_VALUE_CONSTEXPR jsval michael@0: DOUBLE_TO_JSVAL(double d) michael@0: { michael@0: /* michael@0: * This is a manually inlined version of: michael@0: * d = JS_CANONICALIZE_NAN(d); michael@0: * return IMPL_TO_JSVAL(DOUBLE_TO_JSVAL_IMPL(d)); michael@0: * because GCC from XCode 3.1.4 miscompiles the above code. michael@0: */ michael@0: #if defined(JS_VALUE_IS_CONSTEXPR) michael@0: return IMPL_TO_JSVAL(MOZ_UNLIKELY(d != d) michael@0: ? (jsval_layout) { .asBits = 0x7FF8000000000000LL } michael@0: : (jsval_layout) { .asDouble = d }); michael@0: #else michael@0: jsval_layout l; michael@0: if (MOZ_UNLIKELY(d != d)) michael@0: l.asBits = 0x7FF8000000000000LL; michael@0: else michael@0: l.asDouble = d; michael@0: return IMPL_TO_JSVAL(l); michael@0: #endif michael@0: } michael@0: michael@0: static inline JS_VALUE_CONSTEXPR jsval michael@0: UINT_TO_JSVAL(uint32_t i) michael@0: { michael@0: return (i <= JSVAL_INT_MAX michael@0: ? INT_TO_JSVAL((int32_t)i) michael@0: : DOUBLE_TO_JSVAL((double)i)); michael@0: } michael@0: michael@0: static inline bool michael@0: JSVAL_IS_NUMBER(jsval v) michael@0: { michael@0: return JSVAL_IS_NUMBER_IMPL(JSVAL_TO_IMPL(v)); michael@0: } michael@0: michael@0: static inline bool michael@0: JSVAL_IS_STRING(jsval v) michael@0: { michael@0: return JSVAL_IS_STRING_IMPL(JSVAL_TO_IMPL(v)); michael@0: } michael@0: michael@0: static inline JSString * michael@0: JSVAL_TO_STRING(jsval v) michael@0: { michael@0: MOZ_ASSERT(JSVAL_IS_STRING(v)); michael@0: return JSVAL_TO_STRING_IMPL(JSVAL_TO_IMPL(v)); michael@0: } michael@0: michael@0: static inline jsval michael@0: STRING_TO_JSVAL(JSString *str) michael@0: { michael@0: return IMPL_TO_JSVAL(STRING_TO_JSVAL_IMPL(str)); michael@0: } michael@0: michael@0: static inline JSObject * michael@0: JSVAL_TO_OBJECT(jsval v) michael@0: { michael@0: MOZ_ASSERT(JSVAL_IS_OBJECT_OR_NULL_IMPL(JSVAL_TO_IMPL(v))); michael@0: return JSVAL_TO_OBJECT_IMPL(JSVAL_TO_IMPL(v)); michael@0: } michael@0: michael@0: static inline jsval michael@0: OBJECT_TO_JSVAL(JSObject *obj) michael@0: { michael@0: if (obj) michael@0: return IMPL_TO_JSVAL(OBJECT_TO_JSVAL_IMPL(obj)); michael@0: return IMPL_TO_JSVAL(BUILD_JSVAL(JSVAL_TAG_NULL, 0)); michael@0: } michael@0: michael@0: static inline bool michael@0: JSVAL_IS_BOOLEAN(jsval v) michael@0: { michael@0: return JSVAL_IS_BOOLEAN_IMPL(JSVAL_TO_IMPL(v)); michael@0: } michael@0: michael@0: static inline bool michael@0: JSVAL_TO_BOOLEAN(jsval v) michael@0: { michael@0: MOZ_ASSERT(JSVAL_IS_BOOLEAN(v)); michael@0: return JSVAL_TO_BOOLEAN_IMPL(JSVAL_TO_IMPL(v)); michael@0: } michael@0: michael@0: static inline jsval michael@0: BOOLEAN_TO_JSVAL(bool b) michael@0: { michael@0: return IMPL_TO_JSVAL(BOOLEAN_TO_JSVAL_IMPL(b)); michael@0: } michael@0: michael@0: static inline bool michael@0: JSVAL_IS_PRIMITIVE(jsval v) michael@0: { michael@0: return JSVAL_IS_PRIMITIVE_IMPL(JSVAL_TO_IMPL(v)); michael@0: } michael@0: michael@0: static inline bool michael@0: JSVAL_IS_GCTHING(jsval v) michael@0: { michael@0: return JSVAL_IS_GCTHING_IMPL(JSVAL_TO_IMPL(v)); michael@0: } michael@0: michael@0: static inline void * michael@0: JSVAL_TO_GCTHING(jsval v) michael@0: { michael@0: MOZ_ASSERT(JSVAL_IS_GCTHING(v)); michael@0: return JSVAL_TO_GCTHING_IMPL(JSVAL_TO_IMPL(v)); michael@0: } michael@0: michael@0: /* To be GC-safe, privates are tagged as doubles. */ michael@0: michael@0: static inline jsval michael@0: PRIVATE_TO_JSVAL(void *ptr) michael@0: { michael@0: return IMPL_TO_JSVAL(PRIVATE_PTR_TO_JSVAL_IMPL(ptr)); michael@0: } michael@0: michael@0: static inline void * michael@0: JSVAL_TO_PRIVATE(jsval v) michael@0: { michael@0: MOZ_ASSERT(JSVAL_IS_DOUBLE(v)); michael@0: return JSVAL_TO_PRIVATE_PTR_IMPL(JSVAL_TO_IMPL(v)); michael@0: } michael@0: michael@0: // JS constants. For efficiency, prefer predicates (e.g. v.isNull()) and michael@0: // constructing values from scratch (e.g. Int32Value(0)). These constants are michael@0: // stored in memory and initialized at startup, so testing against them and michael@0: // using them requires memory loads and will be correspondingly slow. michael@0: extern JS_PUBLIC_DATA(const jsval) JSVAL_NULL; michael@0: extern JS_PUBLIC_DATA(const jsval) JSVAL_ZERO; michael@0: extern JS_PUBLIC_DATA(const jsval) JSVAL_ONE; michael@0: extern JS_PUBLIC_DATA(const jsval) JSVAL_FALSE; michael@0: extern JS_PUBLIC_DATA(const jsval) JSVAL_TRUE; michael@0: extern JS_PUBLIC_DATA(const jsval) JSVAL_VOID; michael@0: michael@0: namespace JS { michael@0: michael@0: extern JS_PUBLIC_DATA(const HandleValue) NullHandleValue; michael@0: extern JS_PUBLIC_DATA(const HandleValue) UndefinedHandleValue; michael@0: michael@0: } michael@0: michael@0: #undef JS_VALUE_IS_CONSTEXPR michael@0: #undef JS_RETURN_LAYOUT_FROM_BITS michael@0: michael@0: #endif /* js_Value_h */