1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/js/public/Value.h Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,2014 @@ 1.4 +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- 1.5 + * vim: set ts=8 sts=4 et sw=4 tw=99: 1.6 + * This Source Code Form is subject to the terms of the Mozilla Public 1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.8 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.9 + 1.10 +/* JS::Value implementation. */ 1.11 + 1.12 +#ifndef js_Value_h 1.13 +#define js_Value_h 1.14 + 1.15 +#include "mozilla/Attributes.h" 1.16 +#include "mozilla/FloatingPoint.h" 1.17 +#include "mozilla/Likely.h" 1.18 + 1.19 +#include <limits> /* for std::numeric_limits */ 1.20 + 1.21 +#include "jstypes.h" 1.22 + 1.23 +#include "js/Anchor.h" 1.24 +#include "js/RootingAPI.h" 1.25 +#include "js/Utility.h" 1.26 + 1.27 +namespace JS { class Value; } 1.28 + 1.29 +/* JS::Value can store a full int32_t. */ 1.30 +#define JSVAL_INT_BITS 32 1.31 +#define JSVAL_INT_MIN ((int32_t)0x80000000) 1.32 +#define JSVAL_INT_MAX ((int32_t)0x7fffffff) 1.33 + 1.34 +/* 1.35 + * Try to get jsvals 64-bit aligned. We could almost assert that all values are 1.36 + * aligned, but MSVC and GCC occasionally break alignment. 1.37 + */ 1.38 +#if defined(__GNUC__) || defined(__xlc__) || defined(__xlC__) 1.39 +# define JSVAL_ALIGNMENT __attribute__((aligned (8))) 1.40 +#elif defined(_MSC_VER) 1.41 + /* 1.42 + * Structs can be aligned with MSVC, but not if they are used as parameters, 1.43 + * so we just don't try to align. 1.44 + */ 1.45 +# define JSVAL_ALIGNMENT 1.46 +#elif defined(__SUNPRO_C) || defined(__SUNPRO_CC) 1.47 +# define JSVAL_ALIGNMENT 1.48 +#elif defined(__HP_cc) || defined(__HP_aCC) 1.49 +# define JSVAL_ALIGNMENT 1.50 +#endif 1.51 + 1.52 +#if JS_BITS_PER_WORD == 64 1.53 +# define JSVAL_TAG_SHIFT 47 1.54 +#endif 1.55 + 1.56 +/* 1.57 + * We try to use enums so that printing a jsval_layout in the debugger shows 1.58 + * nice symbolic type tags, however we can only do this when we can force the 1.59 + * underlying type of the enum to be the desired size. 1.60 + */ 1.61 +#if !defined(__SUNPRO_CC) && !defined(__xlC__) 1.62 + 1.63 +#if defined(_MSC_VER) 1.64 +# define JS_ENUM_HEADER(id, type) enum id : type 1.65 +# define JS_ENUM_FOOTER(id) 1.66 +#else 1.67 +# define JS_ENUM_HEADER(id, type) enum id 1.68 +# define JS_ENUM_FOOTER(id) __attribute__((packed)) 1.69 +#endif 1.70 + 1.71 +/* Remember to propagate changes to the C defines below. */ 1.72 +JS_ENUM_HEADER(JSValueType, uint8_t) 1.73 +{ 1.74 + JSVAL_TYPE_DOUBLE = 0x00, 1.75 + JSVAL_TYPE_INT32 = 0x01, 1.76 + JSVAL_TYPE_UNDEFINED = 0x02, 1.77 + JSVAL_TYPE_BOOLEAN = 0x03, 1.78 + JSVAL_TYPE_MAGIC = 0x04, 1.79 + JSVAL_TYPE_STRING = 0x05, 1.80 + JSVAL_TYPE_NULL = 0x06, 1.81 + JSVAL_TYPE_OBJECT = 0x07, 1.82 + 1.83 + /* These never appear in a jsval; they are only provided as an out-of-band value. */ 1.84 + JSVAL_TYPE_UNKNOWN = 0x20, 1.85 + JSVAL_TYPE_MISSING = 0x21 1.86 +} JS_ENUM_FOOTER(JSValueType); 1.87 + 1.88 +JS_STATIC_ASSERT(sizeof(JSValueType) == 1); 1.89 + 1.90 +#if JS_BITS_PER_WORD == 32 1.91 + 1.92 +/* Remember to propagate changes to the C defines below. */ 1.93 +JS_ENUM_HEADER(JSValueTag, uint32_t) 1.94 +{ 1.95 + JSVAL_TAG_CLEAR = 0xFFFFFF80, 1.96 + JSVAL_TAG_INT32 = JSVAL_TAG_CLEAR | JSVAL_TYPE_INT32, 1.97 + JSVAL_TAG_UNDEFINED = JSVAL_TAG_CLEAR | JSVAL_TYPE_UNDEFINED, 1.98 + JSVAL_TAG_STRING = JSVAL_TAG_CLEAR | JSVAL_TYPE_STRING, 1.99 + JSVAL_TAG_BOOLEAN = JSVAL_TAG_CLEAR | JSVAL_TYPE_BOOLEAN, 1.100 + JSVAL_TAG_MAGIC = JSVAL_TAG_CLEAR | JSVAL_TYPE_MAGIC, 1.101 + JSVAL_TAG_NULL = JSVAL_TAG_CLEAR | JSVAL_TYPE_NULL, 1.102 + JSVAL_TAG_OBJECT = JSVAL_TAG_CLEAR | JSVAL_TYPE_OBJECT 1.103 +} JS_ENUM_FOOTER(JSValueTag); 1.104 + 1.105 +JS_STATIC_ASSERT(sizeof(JSValueTag) == 4); 1.106 + 1.107 +#elif JS_BITS_PER_WORD == 64 1.108 + 1.109 +/* Remember to propagate changes to the C defines below. */ 1.110 +JS_ENUM_HEADER(JSValueTag, uint32_t) 1.111 +{ 1.112 + JSVAL_TAG_MAX_DOUBLE = 0x1FFF0, 1.113 + JSVAL_TAG_INT32 = JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_INT32, 1.114 + JSVAL_TAG_UNDEFINED = JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_UNDEFINED, 1.115 + JSVAL_TAG_STRING = JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_STRING, 1.116 + JSVAL_TAG_BOOLEAN = JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_BOOLEAN, 1.117 + JSVAL_TAG_MAGIC = JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_MAGIC, 1.118 + JSVAL_TAG_NULL = JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_NULL, 1.119 + JSVAL_TAG_OBJECT = JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_OBJECT 1.120 +} JS_ENUM_FOOTER(JSValueTag); 1.121 + 1.122 +JS_STATIC_ASSERT(sizeof(JSValueTag) == sizeof(uint32_t)); 1.123 + 1.124 +JS_ENUM_HEADER(JSValueShiftedTag, uint64_t) 1.125 +{ 1.126 + JSVAL_SHIFTED_TAG_MAX_DOUBLE = ((((uint64_t)JSVAL_TAG_MAX_DOUBLE) << JSVAL_TAG_SHIFT) | 0xFFFFFFFF), 1.127 + JSVAL_SHIFTED_TAG_INT32 = (((uint64_t)JSVAL_TAG_INT32) << JSVAL_TAG_SHIFT), 1.128 + JSVAL_SHIFTED_TAG_UNDEFINED = (((uint64_t)JSVAL_TAG_UNDEFINED) << JSVAL_TAG_SHIFT), 1.129 + JSVAL_SHIFTED_TAG_STRING = (((uint64_t)JSVAL_TAG_STRING) << JSVAL_TAG_SHIFT), 1.130 + JSVAL_SHIFTED_TAG_BOOLEAN = (((uint64_t)JSVAL_TAG_BOOLEAN) << JSVAL_TAG_SHIFT), 1.131 + JSVAL_SHIFTED_TAG_MAGIC = (((uint64_t)JSVAL_TAG_MAGIC) << JSVAL_TAG_SHIFT), 1.132 + JSVAL_SHIFTED_TAG_NULL = (((uint64_t)JSVAL_TAG_NULL) << JSVAL_TAG_SHIFT), 1.133 + JSVAL_SHIFTED_TAG_OBJECT = (((uint64_t)JSVAL_TAG_OBJECT) << JSVAL_TAG_SHIFT) 1.134 +} JS_ENUM_FOOTER(JSValueShiftedTag); 1.135 + 1.136 +JS_STATIC_ASSERT(sizeof(JSValueShiftedTag) == sizeof(uint64_t)); 1.137 + 1.138 +#endif 1.139 + 1.140 +#else /* !defined(__SUNPRO_CC) && !defined(__xlC__) */ 1.141 + 1.142 +typedef uint8_t JSValueType; 1.143 +#define JSVAL_TYPE_DOUBLE ((uint8_t)0x00) 1.144 +#define JSVAL_TYPE_INT32 ((uint8_t)0x01) 1.145 +#define JSVAL_TYPE_UNDEFINED ((uint8_t)0x02) 1.146 +#define JSVAL_TYPE_BOOLEAN ((uint8_t)0x03) 1.147 +#define JSVAL_TYPE_MAGIC ((uint8_t)0x04) 1.148 +#define JSVAL_TYPE_STRING ((uint8_t)0x05) 1.149 +#define JSVAL_TYPE_NULL ((uint8_t)0x06) 1.150 +#define JSVAL_TYPE_OBJECT ((uint8_t)0x07) 1.151 +#define JSVAL_TYPE_UNKNOWN ((uint8_t)0x20) 1.152 + 1.153 +#if JS_BITS_PER_WORD == 32 1.154 + 1.155 +typedef uint32_t JSValueTag; 1.156 +#define JSVAL_TAG_CLEAR ((uint32_t)(0xFFFFFF80)) 1.157 +#define JSVAL_TAG_INT32 ((uint32_t)(JSVAL_TAG_CLEAR | JSVAL_TYPE_INT32)) 1.158 +#define JSVAL_TAG_UNDEFINED ((uint32_t)(JSVAL_TAG_CLEAR | JSVAL_TYPE_UNDEFINED)) 1.159 +#define JSVAL_TAG_STRING ((uint32_t)(JSVAL_TAG_CLEAR | JSVAL_TYPE_STRING)) 1.160 +#define JSVAL_TAG_BOOLEAN ((uint32_t)(JSVAL_TAG_CLEAR | JSVAL_TYPE_BOOLEAN)) 1.161 +#define JSVAL_TAG_MAGIC ((uint32_t)(JSVAL_TAG_CLEAR | JSVAL_TYPE_MAGIC)) 1.162 +#define JSVAL_TAG_NULL ((uint32_t)(JSVAL_TAG_CLEAR | JSVAL_TYPE_NULL)) 1.163 +#define JSVAL_TAG_OBJECT ((uint32_t)(JSVAL_TAG_CLEAR | JSVAL_TYPE_OBJECT)) 1.164 + 1.165 +#elif JS_BITS_PER_WORD == 64 1.166 + 1.167 +typedef uint32_t JSValueTag; 1.168 +#define JSVAL_TAG_MAX_DOUBLE ((uint32_t)(0x1FFF0)) 1.169 +#define JSVAL_TAG_INT32 (uint32_t)(JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_INT32) 1.170 +#define JSVAL_TAG_UNDEFINED (uint32_t)(JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_UNDEFINED) 1.171 +#define JSVAL_TAG_STRING (uint32_t)(JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_STRING) 1.172 +#define JSVAL_TAG_BOOLEAN (uint32_t)(JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_BOOLEAN) 1.173 +#define JSVAL_TAG_MAGIC (uint32_t)(JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_MAGIC) 1.174 +#define JSVAL_TAG_NULL (uint32_t)(JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_NULL) 1.175 +#define JSVAL_TAG_OBJECT (uint32_t)(JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_OBJECT) 1.176 + 1.177 +typedef uint64_t JSValueShiftedTag; 1.178 +#define JSVAL_SHIFTED_TAG_MAX_DOUBLE ((((uint64_t)JSVAL_TAG_MAX_DOUBLE) << JSVAL_TAG_SHIFT) | 0xFFFFFFFF) 1.179 +#define JSVAL_SHIFTED_TAG_INT32 (((uint64_t)JSVAL_TAG_INT32) << JSVAL_TAG_SHIFT) 1.180 +#define JSVAL_SHIFTED_TAG_UNDEFINED (((uint64_t)JSVAL_TAG_UNDEFINED) << JSVAL_TAG_SHIFT) 1.181 +#define JSVAL_SHIFTED_TAG_STRING (((uint64_t)JSVAL_TAG_STRING) << JSVAL_TAG_SHIFT) 1.182 +#define JSVAL_SHIFTED_TAG_BOOLEAN (((uint64_t)JSVAL_TAG_BOOLEAN) << JSVAL_TAG_SHIFT) 1.183 +#define JSVAL_SHIFTED_TAG_MAGIC (((uint64_t)JSVAL_TAG_MAGIC) << JSVAL_TAG_SHIFT) 1.184 +#define JSVAL_SHIFTED_TAG_NULL (((uint64_t)JSVAL_TAG_NULL) << JSVAL_TAG_SHIFT) 1.185 +#define JSVAL_SHIFTED_TAG_OBJECT (((uint64_t)JSVAL_TAG_OBJECT) << JSVAL_TAG_SHIFT) 1.186 + 1.187 +#endif /* JS_BITS_PER_WORD */ 1.188 +#endif /* !defined(__SUNPRO_CC) && !defined(__xlC__) */ 1.189 + 1.190 +#define JSVAL_LOWER_INCL_TYPE_OF_OBJ_OR_NULL_SET JSVAL_TYPE_NULL 1.191 +#define JSVAL_UPPER_EXCL_TYPE_OF_PRIMITIVE_SET JSVAL_TYPE_OBJECT 1.192 +#define JSVAL_UPPER_INCL_TYPE_OF_NUMBER_SET JSVAL_TYPE_INT32 1.193 +#define JSVAL_LOWER_INCL_TYPE_OF_PTR_PAYLOAD_SET JSVAL_TYPE_MAGIC 1.194 + 1.195 +#if JS_BITS_PER_WORD == 32 1.196 + 1.197 +#define JSVAL_TYPE_TO_TAG(type) ((JSValueTag)(JSVAL_TAG_CLEAR | (type))) 1.198 + 1.199 +#define JSVAL_LOWER_INCL_TAG_OF_OBJ_OR_NULL_SET JSVAL_TAG_NULL 1.200 +#define JSVAL_UPPER_EXCL_TAG_OF_PRIMITIVE_SET JSVAL_TAG_OBJECT 1.201 +#define JSVAL_UPPER_INCL_TAG_OF_NUMBER_SET JSVAL_TAG_INT32 1.202 +#define JSVAL_LOWER_INCL_TAG_OF_GCTHING_SET JSVAL_TAG_STRING 1.203 + 1.204 +#elif JS_BITS_PER_WORD == 64 1.205 + 1.206 +#define JSVAL_PAYLOAD_MASK 0x00007FFFFFFFFFFFLL 1.207 +#define JSVAL_TAG_MASK 0xFFFF800000000000LL 1.208 +#define JSVAL_TYPE_TO_TAG(type) ((JSValueTag)(JSVAL_TAG_MAX_DOUBLE | (type))) 1.209 +#define JSVAL_TYPE_TO_SHIFTED_TAG(type) (((uint64_t)JSVAL_TYPE_TO_TAG(type)) << JSVAL_TAG_SHIFT) 1.210 + 1.211 +#define JSVAL_LOWER_INCL_TAG_OF_OBJ_OR_NULL_SET JSVAL_TAG_NULL 1.212 +#define JSVAL_UPPER_EXCL_TAG_OF_PRIMITIVE_SET JSVAL_TAG_OBJECT 1.213 +#define JSVAL_UPPER_INCL_TAG_OF_NUMBER_SET JSVAL_TAG_INT32 1.214 +#define JSVAL_LOWER_INCL_TAG_OF_GCTHING_SET JSVAL_TAG_STRING 1.215 + 1.216 +#define JSVAL_LOWER_INCL_SHIFTED_TAG_OF_OBJ_OR_NULL_SET JSVAL_SHIFTED_TAG_NULL 1.217 +#define JSVAL_UPPER_EXCL_SHIFTED_TAG_OF_PRIMITIVE_SET JSVAL_SHIFTED_TAG_OBJECT 1.218 +#define JSVAL_UPPER_EXCL_SHIFTED_TAG_OF_NUMBER_SET JSVAL_SHIFTED_TAG_UNDEFINED 1.219 +#define JSVAL_LOWER_INCL_SHIFTED_TAG_OF_GCTHING_SET JSVAL_SHIFTED_TAG_STRING 1.220 + 1.221 +#endif /* JS_BITS_PER_WORD */ 1.222 + 1.223 +typedef enum JSWhyMagic 1.224 +{ 1.225 + JS_ELEMENTS_HOLE, /* a hole in a native object's elements */ 1.226 + JS_NATIVE_ENUMERATE, /* indicates that a custom enumerate hook forwarded 1.227 + * to JS_EnumerateState, which really means the object can be 1.228 + * enumerated like a native object. */ 1.229 + JS_NO_ITER_VALUE, /* there is not a pending iterator value */ 1.230 + JS_GENERATOR_CLOSING, /* exception value thrown when closing a generator */ 1.231 + JS_NO_CONSTANT, /* compiler sentinel value */ 1.232 + JS_THIS_POISON, /* used in debug builds to catch tracing errors */ 1.233 + JS_ARG_POISON, /* used in debug builds to catch tracing errors */ 1.234 + JS_SERIALIZE_NO_NODE, /* an empty subnode in the AST serializer */ 1.235 + JS_LAZY_ARGUMENTS, /* lazy arguments value on the stack */ 1.236 + JS_OPTIMIZED_ARGUMENTS, /* optimized-away 'arguments' value */ 1.237 + JS_IS_CONSTRUCTING, /* magic value passed to natives to indicate construction */ 1.238 + JS_OVERWRITTEN_CALLEE, /* arguments.callee has been overwritten */ 1.239 + JS_BLOCK_NEEDS_CLONE, /* value of static block object slot */ 1.240 + JS_HASH_KEY_EMPTY, /* see class js::HashableValue */ 1.241 + JS_ION_ERROR, /* error while running Ion code */ 1.242 + JS_ION_BAILOUT, /* status code to signal EnterIon will OSR into Interpret */ 1.243 + JS_OPTIMIZED_OUT, /* optimized out slot */ 1.244 + JS_GENERIC_MAGIC /* for local use */ 1.245 +} JSWhyMagic; 1.246 + 1.247 +#if defined(IS_LITTLE_ENDIAN) 1.248 +# if JS_BITS_PER_WORD == 32 1.249 +typedef union jsval_layout 1.250 +{ 1.251 + uint64_t asBits; 1.252 + struct { 1.253 + union { 1.254 + int32_t i32; 1.255 + uint32_t u32; 1.256 + uint32_t boo; // Don't use |bool| -- it must be four bytes. 1.257 + JSString *str; 1.258 + JSObject *obj; 1.259 + void *ptr; 1.260 + JSWhyMagic why; 1.261 + size_t word; 1.262 + uintptr_t uintptr; 1.263 + } payload; 1.264 + JSValueTag tag; 1.265 + } s; 1.266 + double asDouble; 1.267 + void *asPtr; 1.268 +} JSVAL_ALIGNMENT jsval_layout; 1.269 +# elif JS_BITS_PER_WORD == 64 1.270 +typedef union jsval_layout 1.271 +{ 1.272 + uint64_t asBits; 1.273 +#if !defined(_WIN64) 1.274 + /* MSVC does not pack these correctly :-( */ 1.275 + struct { 1.276 + uint64_t payload47 : 47; 1.277 + JSValueTag tag : 17; 1.278 + } debugView; 1.279 +#endif 1.280 + struct { 1.281 + union { 1.282 + int32_t i32; 1.283 + uint32_t u32; 1.284 + JSWhyMagic why; 1.285 + } payload; 1.286 + } s; 1.287 + double asDouble; 1.288 + void *asPtr; 1.289 + size_t asWord; 1.290 + uintptr_t asUIntPtr; 1.291 +} JSVAL_ALIGNMENT jsval_layout; 1.292 +# endif /* JS_BITS_PER_WORD */ 1.293 +#else /* defined(IS_LITTLE_ENDIAN) */ 1.294 +# if JS_BITS_PER_WORD == 32 1.295 +typedef union jsval_layout 1.296 +{ 1.297 + uint64_t asBits; 1.298 + struct { 1.299 + JSValueTag tag; 1.300 + union { 1.301 + int32_t i32; 1.302 + uint32_t u32; 1.303 + uint32_t boo; // Don't use |bool| -- it must be four bytes. 1.304 + JSString *str; 1.305 + JSObject *obj; 1.306 + void *ptr; 1.307 + JSWhyMagic why; 1.308 + size_t word; 1.309 + uintptr_t uintptr; 1.310 + } payload; 1.311 + } s; 1.312 + double asDouble; 1.313 + void *asPtr; 1.314 +} JSVAL_ALIGNMENT jsval_layout; 1.315 +# elif JS_BITS_PER_WORD == 64 1.316 +typedef union jsval_layout 1.317 +{ 1.318 + uint64_t asBits; 1.319 + struct { 1.320 + JSValueTag tag : 17; 1.321 + uint64_t payload47 : 47; 1.322 + } debugView; 1.323 + struct { 1.324 + uint32_t padding; 1.325 + union { 1.326 + int32_t i32; 1.327 + uint32_t u32; 1.328 + JSWhyMagic why; 1.329 + } payload; 1.330 + } s; 1.331 + double asDouble; 1.332 + void *asPtr; 1.333 + size_t asWord; 1.334 + uintptr_t asUIntPtr; 1.335 +} JSVAL_ALIGNMENT jsval_layout; 1.336 +# endif /* JS_BITS_PER_WORD */ 1.337 +#endif /* defined(IS_LITTLE_ENDIAN) */ 1.338 + 1.339 +JS_STATIC_ASSERT(sizeof(jsval_layout) == 8); 1.340 + 1.341 +/* 1.342 + * For codesize purposes on some platforms, it's important that the 1.343 + * compiler know that JS::Values constructed from constant values can be 1.344 + * folded to constant bit patterns at compile time, rather than 1.345 + * constructed at runtime. Doing this requires a fair amount of C++11 1.346 + * features, which are not supported on all of our compilers. Set up 1.347 + * some defines and helper macros in an attempt to confine the ugliness 1.348 + * here, rather than scattering it all about the file. The important 1.349 + * features are: 1.350 + * 1.351 + * - constexpr; 1.352 + * - defaulted functions; 1.353 + * - C99-style designated initializers. 1.354 + */ 1.355 +#if defined(__clang__) 1.356 +# if __has_feature(cxx_constexpr) && __has_feature(cxx_defaulted_functions) 1.357 +# define JS_VALUE_IS_CONSTEXPR 1.358 +# endif 1.359 +#elif defined(__GNUC__) 1.360 +/* 1.361 + * We need 4.5 for defaulted functions, 4.6 for constexpr, 4.7 because 4.6 1.362 + * doesn't understand |(X) { .field = ... }| syntax, and 4.7.3 because 1.363 + * versions prior to that have bugs in the C++ front-end that cause crashes. 1.364 + */ 1.365 +# if MOZ_GCC_VERSION_AT_LEAST(4, 7, 3) 1.366 +# define JS_VALUE_IS_CONSTEXPR 1.367 +# endif 1.368 +#endif 1.369 + 1.370 +#if defined(JS_VALUE_IS_CONSTEXPR) 1.371 +# define JS_RETURN_LAYOUT_FROM_BITS(BITS) \ 1.372 + return (jsval_layout) { .asBits = (BITS) } 1.373 +# define JS_VALUE_CONSTEXPR MOZ_CONSTEXPR 1.374 +# define JS_VALUE_CONSTEXPR_VAR MOZ_CONSTEXPR_VAR 1.375 +#else 1.376 +# define JS_RETURN_LAYOUT_FROM_BITS(BITS) \ 1.377 + jsval_layout l; \ 1.378 + l.asBits = (BITS); \ 1.379 + return l; 1.380 +# define JS_VALUE_CONSTEXPR 1.381 +# define JS_VALUE_CONSTEXPR_VAR const 1.382 +#endif 1.383 + 1.384 +#if JS_BITS_PER_WORD == 32 1.385 + 1.386 +/* 1.387 + * N.B. GCC, in some but not all cases, chooses to emit signed comparison of 1.388 + * JSValueTag even though its underlying type has been forced to be uint32_t. 1.389 + * Thus, all comparisons should explicitly cast operands to uint32_t. 1.390 + */ 1.391 + 1.392 +static inline JS_VALUE_CONSTEXPR jsval_layout 1.393 +BUILD_JSVAL(JSValueTag tag, uint32_t payload) 1.394 +{ 1.395 + JS_RETURN_LAYOUT_FROM_BITS((((uint64_t)(uint32_t)tag) << 32) | payload); 1.396 +} 1.397 + 1.398 +static inline bool 1.399 +JSVAL_IS_DOUBLE_IMPL(jsval_layout l) 1.400 +{ 1.401 + return (uint32_t)l.s.tag <= (uint32_t)JSVAL_TAG_CLEAR; 1.402 +} 1.403 + 1.404 +static inline jsval_layout 1.405 +DOUBLE_TO_JSVAL_IMPL(double d) 1.406 +{ 1.407 + jsval_layout l; 1.408 + l.asDouble = d; 1.409 + MOZ_ASSERT(JSVAL_IS_DOUBLE_IMPL(l)); 1.410 + return l; 1.411 +} 1.412 + 1.413 +static inline bool 1.414 +JSVAL_IS_INT32_IMPL(jsval_layout l) 1.415 +{ 1.416 + return l.s.tag == JSVAL_TAG_INT32; 1.417 +} 1.418 + 1.419 +static inline int32_t 1.420 +JSVAL_TO_INT32_IMPL(jsval_layout l) 1.421 +{ 1.422 + return l.s.payload.i32; 1.423 +} 1.424 + 1.425 +static inline JS_VALUE_CONSTEXPR jsval_layout 1.426 +INT32_TO_JSVAL_IMPL(int32_t i) 1.427 +{ 1.428 +#if defined(JS_VALUE_IS_CONSTEXPR) 1.429 + return BUILD_JSVAL(JSVAL_TAG_INT32, i); 1.430 +#else 1.431 + jsval_layout l; 1.432 + l.s.tag = JSVAL_TAG_INT32; 1.433 + l.s.payload.i32 = i; 1.434 + return l; 1.435 +#endif 1.436 +} 1.437 + 1.438 +static inline bool 1.439 +JSVAL_IS_NUMBER_IMPL(jsval_layout l) 1.440 +{ 1.441 + JSValueTag tag = l.s.tag; 1.442 + MOZ_ASSERT(tag != JSVAL_TAG_CLEAR); 1.443 + return (uint32_t)tag <= (uint32_t)JSVAL_UPPER_INCL_TAG_OF_NUMBER_SET; 1.444 +} 1.445 + 1.446 +static inline bool 1.447 +JSVAL_IS_UNDEFINED_IMPL(jsval_layout l) 1.448 +{ 1.449 + return l.s.tag == JSVAL_TAG_UNDEFINED; 1.450 +} 1.451 + 1.452 +static inline bool 1.453 +JSVAL_IS_STRING_IMPL(jsval_layout l) 1.454 +{ 1.455 + return l.s.tag == JSVAL_TAG_STRING; 1.456 +} 1.457 + 1.458 +static inline jsval_layout 1.459 +STRING_TO_JSVAL_IMPL(JSString *str) 1.460 +{ 1.461 + jsval_layout l; 1.462 + MOZ_ASSERT(uintptr_t(str) > 0x1000); 1.463 + l.s.tag = JSVAL_TAG_STRING; 1.464 + l.s.payload.str = str; 1.465 + return l; 1.466 +} 1.467 + 1.468 +static inline JSString * 1.469 +JSVAL_TO_STRING_IMPL(jsval_layout l) 1.470 +{ 1.471 + return l.s.payload.str; 1.472 +} 1.473 + 1.474 +static inline bool 1.475 +JSVAL_IS_BOOLEAN_IMPL(jsval_layout l) 1.476 +{ 1.477 + return l.s.tag == JSVAL_TAG_BOOLEAN; 1.478 +} 1.479 + 1.480 +static inline bool 1.481 +JSVAL_TO_BOOLEAN_IMPL(jsval_layout l) 1.482 +{ 1.483 + return l.s.payload.boo; 1.484 +} 1.485 + 1.486 +static inline jsval_layout 1.487 +BOOLEAN_TO_JSVAL_IMPL(bool b) 1.488 +{ 1.489 + jsval_layout l; 1.490 + l.s.tag = JSVAL_TAG_BOOLEAN; 1.491 + l.s.payload.boo = b; 1.492 + return l; 1.493 +} 1.494 + 1.495 +static inline bool 1.496 +JSVAL_IS_MAGIC_IMPL(jsval_layout l) 1.497 +{ 1.498 + return l.s.tag == JSVAL_TAG_MAGIC; 1.499 +} 1.500 + 1.501 +static inline bool 1.502 +JSVAL_IS_OBJECT_IMPL(jsval_layout l) 1.503 +{ 1.504 + return l.s.tag == JSVAL_TAG_OBJECT; 1.505 +} 1.506 + 1.507 +static inline bool 1.508 +JSVAL_IS_PRIMITIVE_IMPL(jsval_layout l) 1.509 +{ 1.510 + return (uint32_t)l.s.tag < (uint32_t)JSVAL_UPPER_EXCL_TAG_OF_PRIMITIVE_SET; 1.511 +} 1.512 + 1.513 +static inline bool 1.514 +JSVAL_IS_OBJECT_OR_NULL_IMPL(jsval_layout l) 1.515 +{ 1.516 + MOZ_ASSERT((uint32_t)l.s.tag <= (uint32_t)JSVAL_TAG_OBJECT); 1.517 + return (uint32_t)l.s.tag >= (uint32_t)JSVAL_LOWER_INCL_TAG_OF_OBJ_OR_NULL_SET; 1.518 +} 1.519 + 1.520 +static inline JSObject * 1.521 +JSVAL_TO_OBJECT_IMPL(jsval_layout l) 1.522 +{ 1.523 + return l.s.payload.obj; 1.524 +} 1.525 + 1.526 +static inline jsval_layout 1.527 +OBJECT_TO_JSVAL_IMPL(JSObject *obj) 1.528 +{ 1.529 + jsval_layout l; 1.530 + MOZ_ASSERT(uintptr_t(obj) > 0x1000 || uintptr_t(obj) == 0x42); 1.531 + l.s.tag = JSVAL_TAG_OBJECT; 1.532 + l.s.payload.obj = obj; 1.533 + return l; 1.534 +} 1.535 + 1.536 +static inline bool 1.537 +JSVAL_IS_NULL_IMPL(jsval_layout l) 1.538 +{ 1.539 + return l.s.tag == JSVAL_TAG_NULL; 1.540 +} 1.541 + 1.542 +static inline jsval_layout 1.543 +PRIVATE_PTR_TO_JSVAL_IMPL(void *ptr) 1.544 +{ 1.545 + jsval_layout l; 1.546 + MOZ_ASSERT(((uint32_t)ptr & 1) == 0); 1.547 + l.s.tag = (JSValueTag)0; 1.548 + l.s.payload.ptr = ptr; 1.549 + MOZ_ASSERT(JSVAL_IS_DOUBLE_IMPL(l)); 1.550 + return l; 1.551 +} 1.552 + 1.553 +static inline void * 1.554 +JSVAL_TO_PRIVATE_PTR_IMPL(jsval_layout l) 1.555 +{ 1.556 + return l.s.payload.ptr; 1.557 +} 1.558 + 1.559 +static inline bool 1.560 +JSVAL_IS_GCTHING_IMPL(jsval_layout l) 1.561 +{ 1.562 + /* gcc sometimes generates signed < without explicit casts. */ 1.563 + return (uint32_t)l.s.tag >= (uint32_t)JSVAL_LOWER_INCL_TAG_OF_GCTHING_SET; 1.564 +} 1.565 + 1.566 +static inline void * 1.567 +JSVAL_TO_GCTHING_IMPL(jsval_layout l) 1.568 +{ 1.569 + return l.s.payload.ptr; 1.570 +} 1.571 + 1.572 +static inline bool 1.573 +JSVAL_IS_TRACEABLE_IMPL(jsval_layout l) 1.574 +{ 1.575 + return l.s.tag == JSVAL_TAG_STRING || l.s.tag == JSVAL_TAG_OBJECT; 1.576 +} 1.577 + 1.578 +static inline uint32_t 1.579 +JSVAL_TRACE_KIND_IMPL(jsval_layout l) 1.580 +{ 1.581 + return (uint32_t)(bool)JSVAL_IS_STRING_IMPL(l); 1.582 +} 1.583 + 1.584 +static inline bool 1.585 +JSVAL_IS_SPECIFIC_INT32_IMPL(jsval_layout l, int32_t i32) 1.586 +{ 1.587 + return l.s.tag == JSVAL_TAG_INT32 && l.s.payload.i32 == i32; 1.588 +} 1.589 + 1.590 +static inline bool 1.591 +JSVAL_IS_SPECIFIC_BOOLEAN(jsval_layout l, bool b) 1.592 +{ 1.593 + return (l.s.tag == JSVAL_TAG_BOOLEAN) && (l.s.payload.boo == uint32_t(b)); 1.594 +} 1.595 + 1.596 +static inline jsval_layout 1.597 +MAGIC_TO_JSVAL_IMPL(JSWhyMagic why) 1.598 +{ 1.599 + jsval_layout l; 1.600 + l.s.tag = JSVAL_TAG_MAGIC; 1.601 + l.s.payload.why = why; 1.602 + return l; 1.603 +} 1.604 + 1.605 +static inline jsval_layout 1.606 +MAGIC_UINT32_TO_JSVAL_IMPL(uint32_t payload) 1.607 +{ 1.608 + jsval_layout l; 1.609 + l.s.tag = JSVAL_TAG_MAGIC; 1.610 + l.s.payload.u32 = payload; 1.611 + return l; 1.612 +} 1.613 + 1.614 +static inline bool 1.615 +JSVAL_SAME_TYPE_IMPL(jsval_layout lhs, jsval_layout rhs) 1.616 +{ 1.617 + JSValueTag ltag = lhs.s.tag, rtag = rhs.s.tag; 1.618 + return ltag == rtag || (ltag < JSVAL_TAG_CLEAR && rtag < JSVAL_TAG_CLEAR); 1.619 +} 1.620 + 1.621 +static inline JSValueType 1.622 +JSVAL_EXTRACT_NON_DOUBLE_TYPE_IMPL(jsval_layout l) 1.623 +{ 1.624 + uint32_t type = l.s.tag & 0xF; 1.625 + MOZ_ASSERT(type > JSVAL_TYPE_DOUBLE); 1.626 + return (JSValueType)type; 1.627 +} 1.628 + 1.629 +#elif JS_BITS_PER_WORD == 64 1.630 + 1.631 +static inline JS_VALUE_CONSTEXPR jsval_layout 1.632 +BUILD_JSVAL(JSValueTag tag, uint64_t payload) 1.633 +{ 1.634 + JS_RETURN_LAYOUT_FROM_BITS((((uint64_t)(uint32_t)tag) << JSVAL_TAG_SHIFT) | payload); 1.635 +} 1.636 + 1.637 +static inline bool 1.638 +JSVAL_IS_DOUBLE_IMPL(jsval_layout l) 1.639 +{ 1.640 + return l.asBits <= JSVAL_SHIFTED_TAG_MAX_DOUBLE; 1.641 +} 1.642 + 1.643 +static inline jsval_layout 1.644 +DOUBLE_TO_JSVAL_IMPL(double d) 1.645 +{ 1.646 + jsval_layout l; 1.647 + l.asDouble = d; 1.648 + MOZ_ASSERT(l.asBits <= JSVAL_SHIFTED_TAG_MAX_DOUBLE); 1.649 + return l; 1.650 +} 1.651 + 1.652 +static inline bool 1.653 +JSVAL_IS_INT32_IMPL(jsval_layout l) 1.654 +{ 1.655 + return (uint32_t)(l.asBits >> JSVAL_TAG_SHIFT) == JSVAL_TAG_INT32; 1.656 +} 1.657 + 1.658 +static inline int32_t 1.659 +JSVAL_TO_INT32_IMPL(jsval_layout l) 1.660 +{ 1.661 + return (int32_t)l.asBits; 1.662 +} 1.663 + 1.664 +static inline JS_VALUE_CONSTEXPR jsval_layout 1.665 +INT32_TO_JSVAL_IMPL(int32_t i32) 1.666 +{ 1.667 + JS_RETURN_LAYOUT_FROM_BITS(((uint64_t)(uint32_t)i32) | JSVAL_SHIFTED_TAG_INT32); 1.668 +} 1.669 + 1.670 +static inline bool 1.671 +JSVAL_IS_NUMBER_IMPL(jsval_layout l) 1.672 +{ 1.673 + return l.asBits < JSVAL_UPPER_EXCL_SHIFTED_TAG_OF_NUMBER_SET; 1.674 +} 1.675 + 1.676 +static inline bool 1.677 +JSVAL_IS_UNDEFINED_IMPL(jsval_layout l) 1.678 +{ 1.679 + return l.asBits == JSVAL_SHIFTED_TAG_UNDEFINED; 1.680 +} 1.681 + 1.682 +static inline bool 1.683 +JSVAL_IS_STRING_IMPL(jsval_layout l) 1.684 +{ 1.685 + return (uint32_t)(l.asBits >> JSVAL_TAG_SHIFT) == JSVAL_TAG_STRING; 1.686 +} 1.687 + 1.688 +static inline jsval_layout 1.689 +STRING_TO_JSVAL_IMPL(JSString *str) 1.690 +{ 1.691 + jsval_layout l; 1.692 + uint64_t strBits = (uint64_t)str; 1.693 + MOZ_ASSERT(uintptr_t(str) > 0x1000); 1.694 + MOZ_ASSERT((strBits >> JSVAL_TAG_SHIFT) == 0); 1.695 + l.asBits = strBits | JSVAL_SHIFTED_TAG_STRING; 1.696 + return l; 1.697 +} 1.698 + 1.699 +static inline JSString * 1.700 +JSVAL_TO_STRING_IMPL(jsval_layout l) 1.701 +{ 1.702 + return (JSString *)(l.asBits & JSVAL_PAYLOAD_MASK); 1.703 +} 1.704 + 1.705 +static inline bool 1.706 +JSVAL_IS_BOOLEAN_IMPL(jsval_layout l) 1.707 +{ 1.708 + return (uint32_t)(l.asBits >> JSVAL_TAG_SHIFT) == JSVAL_TAG_BOOLEAN; 1.709 +} 1.710 + 1.711 +static inline bool 1.712 +JSVAL_TO_BOOLEAN_IMPL(jsval_layout l) 1.713 +{ 1.714 + return (bool)(l.asBits & JSVAL_PAYLOAD_MASK); 1.715 +} 1.716 + 1.717 +static inline jsval_layout 1.718 +BOOLEAN_TO_JSVAL_IMPL(bool b) 1.719 +{ 1.720 + jsval_layout l; 1.721 + l.asBits = ((uint64_t)(uint32_t)b) | JSVAL_SHIFTED_TAG_BOOLEAN; 1.722 + return l; 1.723 +} 1.724 + 1.725 +static inline bool 1.726 +JSVAL_IS_MAGIC_IMPL(jsval_layout l) 1.727 +{ 1.728 + return (l.asBits >> JSVAL_TAG_SHIFT) == JSVAL_TAG_MAGIC; 1.729 +} 1.730 + 1.731 +static inline bool 1.732 +JSVAL_IS_PRIMITIVE_IMPL(jsval_layout l) 1.733 +{ 1.734 + return l.asBits < JSVAL_UPPER_EXCL_SHIFTED_TAG_OF_PRIMITIVE_SET; 1.735 +} 1.736 + 1.737 +static inline bool 1.738 +JSVAL_IS_OBJECT_IMPL(jsval_layout l) 1.739 +{ 1.740 + MOZ_ASSERT((l.asBits >> JSVAL_TAG_SHIFT) <= JSVAL_TAG_OBJECT); 1.741 + return l.asBits >= JSVAL_SHIFTED_TAG_OBJECT; 1.742 +} 1.743 + 1.744 +static inline bool 1.745 +JSVAL_IS_OBJECT_OR_NULL_IMPL(jsval_layout l) 1.746 +{ 1.747 + MOZ_ASSERT((l.asBits >> JSVAL_TAG_SHIFT) <= JSVAL_TAG_OBJECT); 1.748 + return l.asBits >= JSVAL_LOWER_INCL_SHIFTED_TAG_OF_OBJ_OR_NULL_SET; 1.749 +} 1.750 + 1.751 +static inline JSObject * 1.752 +JSVAL_TO_OBJECT_IMPL(jsval_layout l) 1.753 +{ 1.754 + uint64_t ptrBits = l.asBits & JSVAL_PAYLOAD_MASK; 1.755 + MOZ_ASSERT((ptrBits & 0x7) == 0); 1.756 + return (JSObject *)ptrBits; 1.757 +} 1.758 + 1.759 +static inline jsval_layout 1.760 +OBJECT_TO_JSVAL_IMPL(JSObject *obj) 1.761 +{ 1.762 + jsval_layout l; 1.763 + uint64_t objBits = (uint64_t)obj; 1.764 + MOZ_ASSERT(uintptr_t(obj) > 0x1000 || uintptr_t(obj) == 0x42); 1.765 + MOZ_ASSERT((objBits >> JSVAL_TAG_SHIFT) == 0); 1.766 + l.asBits = objBits | JSVAL_SHIFTED_TAG_OBJECT; 1.767 + return l; 1.768 +} 1.769 + 1.770 +static inline bool 1.771 +JSVAL_IS_NULL_IMPL(jsval_layout l) 1.772 +{ 1.773 + return l.asBits == JSVAL_SHIFTED_TAG_NULL; 1.774 +} 1.775 + 1.776 +static inline bool 1.777 +JSVAL_IS_GCTHING_IMPL(jsval_layout l) 1.778 +{ 1.779 + return l.asBits >= JSVAL_LOWER_INCL_SHIFTED_TAG_OF_GCTHING_SET; 1.780 +} 1.781 + 1.782 +static inline void * 1.783 +JSVAL_TO_GCTHING_IMPL(jsval_layout l) 1.784 +{ 1.785 + uint64_t ptrBits = l.asBits & JSVAL_PAYLOAD_MASK; 1.786 + MOZ_ASSERT((ptrBits & 0x7) == 0); 1.787 + return (void *)ptrBits; 1.788 +} 1.789 + 1.790 +static inline bool 1.791 +JSVAL_IS_TRACEABLE_IMPL(jsval_layout l) 1.792 +{ 1.793 + return JSVAL_IS_GCTHING_IMPL(l) && !JSVAL_IS_NULL_IMPL(l); 1.794 +} 1.795 + 1.796 +static inline uint32_t 1.797 +JSVAL_TRACE_KIND_IMPL(jsval_layout l) 1.798 +{ 1.799 + return (uint32_t)(bool)!(JSVAL_IS_OBJECT_IMPL(l)); 1.800 +} 1.801 + 1.802 +static inline jsval_layout 1.803 +PRIVATE_PTR_TO_JSVAL_IMPL(void *ptr) 1.804 +{ 1.805 + jsval_layout l; 1.806 + uint64_t ptrBits = (uint64_t)ptr; 1.807 + MOZ_ASSERT((ptrBits & 1) == 0); 1.808 + l.asBits = ptrBits >> 1; 1.809 + MOZ_ASSERT(JSVAL_IS_DOUBLE_IMPL(l)); 1.810 + return l; 1.811 +} 1.812 + 1.813 +static inline void * 1.814 +JSVAL_TO_PRIVATE_PTR_IMPL(jsval_layout l) 1.815 +{ 1.816 + MOZ_ASSERT((l.asBits & 0x8000000000000000LL) == 0); 1.817 + return (void *)(l.asBits << 1); 1.818 +} 1.819 + 1.820 +static inline bool 1.821 +JSVAL_IS_SPECIFIC_INT32_IMPL(jsval_layout l, int32_t i32) 1.822 +{ 1.823 + return l.asBits == (((uint64_t)(uint32_t)i32) | JSVAL_SHIFTED_TAG_INT32); 1.824 +} 1.825 + 1.826 +static inline bool 1.827 +JSVAL_IS_SPECIFIC_BOOLEAN(jsval_layout l, bool b) 1.828 +{ 1.829 + return l.asBits == (((uint64_t)(uint32_t)b) | JSVAL_SHIFTED_TAG_BOOLEAN); 1.830 +} 1.831 + 1.832 +static inline jsval_layout 1.833 +MAGIC_TO_JSVAL_IMPL(JSWhyMagic why) 1.834 +{ 1.835 + jsval_layout l; 1.836 + l.asBits = ((uint64_t)(uint32_t)why) | JSVAL_SHIFTED_TAG_MAGIC; 1.837 + return l; 1.838 +} 1.839 + 1.840 +static inline jsval_layout 1.841 +MAGIC_UINT32_TO_JSVAL_IMPL(uint32_t payload) 1.842 +{ 1.843 + jsval_layout l; 1.844 + l.asBits = ((uint64_t)payload) | JSVAL_SHIFTED_TAG_MAGIC; 1.845 + return l; 1.846 +} 1.847 + 1.848 +static inline bool 1.849 +JSVAL_SAME_TYPE_IMPL(jsval_layout lhs, jsval_layout rhs) 1.850 +{ 1.851 + uint64_t lbits = lhs.asBits, rbits = rhs.asBits; 1.852 + return (lbits <= JSVAL_SHIFTED_TAG_MAX_DOUBLE && rbits <= JSVAL_SHIFTED_TAG_MAX_DOUBLE) || 1.853 + (((lbits ^ rbits) & 0xFFFF800000000000LL) == 0); 1.854 +} 1.855 + 1.856 +static inline JSValueType 1.857 +JSVAL_EXTRACT_NON_DOUBLE_TYPE_IMPL(jsval_layout l) 1.858 +{ 1.859 + uint64_t type = (l.asBits >> JSVAL_TAG_SHIFT) & 0xF; 1.860 + MOZ_ASSERT(type > JSVAL_TYPE_DOUBLE); 1.861 + return (JSValueType)type; 1.862 +} 1.863 + 1.864 +#endif /* JS_BITS_PER_WORD */ 1.865 + 1.866 +static inline jsval_layout JSVAL_TO_IMPL(JS::Value v); 1.867 +static inline JS_VALUE_CONSTEXPR JS::Value IMPL_TO_JSVAL(jsval_layout l); 1.868 + 1.869 +namespace JS { 1.870 + 1.871 +static inline JS_VALUE_CONSTEXPR JS::Value UndefinedValue(); 1.872 + 1.873 +/** 1.874 + * Returns a generic quiet NaN value, with all payload bits set to zero. 1.875 + * 1.876 + * Among other properties, this NaN's bit pattern conforms to JS::Value's 1.877 + * bit pattern restrictions. 1.878 + */ 1.879 +static MOZ_ALWAYS_INLINE double 1.880 +GenericNaN() 1.881 +{ 1.882 + return mozilla::SpecificNaN<double>(0, 0x8000000000000ULL); 1.883 +} 1.884 + 1.885 +/* MSVC with PGO miscompiles this function. */ 1.886 +#if defined(_MSC_VER) 1.887 +# pragma optimize("g", off) 1.888 +#endif 1.889 +static inline double 1.890 +CanonicalizeNaN(double d) 1.891 +{ 1.892 + if (MOZ_UNLIKELY(mozilla::IsNaN(d))) 1.893 + return GenericNaN(); 1.894 + return d; 1.895 +} 1.896 +#if defined(_MSC_VER) 1.897 +# pragma optimize("", on) 1.898 +#endif 1.899 + 1.900 +/* 1.901 + * JS::Value is the interface for a single JavaScript Engine value. A few 1.902 + * general notes on JS::Value: 1.903 + * 1.904 + * - JS::Value has setX() and isX() members for X in 1.905 + * 1.906 + * { Int32, Double, String, Boolean, Undefined, Null, Object, Magic } 1.907 + * 1.908 + * JS::Value also contains toX() for each of the non-singleton types. 1.909 + * 1.910 + * - Magic is a singleton type whose payload contains either a JSWhyMagic "reason" for 1.911 + * the magic value or a uint32_t value. By providing JSWhyMagic values when 1.912 + * creating and checking for magic values, it is possible to assert, at 1.913 + * runtime, that only magic values with the expected reason flow through a 1.914 + * particular value. For example, if cx->exception has a magic value, the 1.915 + * reason must be JS_GENERATOR_CLOSING. 1.916 + * 1.917 + * - The JS::Value operations are preferred. The JSVAL_* operations remain for 1.918 + * compatibility; they may be removed at some point. These operations mostly 1.919 + * provide similar functionality. But there are a few key differences. One 1.920 + * is that JS::Value gives null a separate type. Thus 1.921 + * 1.922 + * JSVAL_IS_OBJECT(v) === v.isObjectOrNull() 1.923 + * !JSVAL_IS_PRIMITIVE(v) === v.isObject() 1.924 + * 1.925 + * Also, to help prevent mistakenly boxing a nullable JSObject* as an object, 1.926 + * Value::setObject takes a JSObject&. (Conversely, Value::toObject returns a 1.927 + * JSObject&.) A convenience member Value::setObjectOrNull is provided. 1.928 + * 1.929 + * - JSVAL_VOID is the same as the singleton value of the Undefined type. 1.930 + * 1.931 + * - Note that JS::Value is 8 bytes on 32 and 64-bit architectures. Thus, on 1.932 + * 32-bit user code should avoid copying jsval/JS::Value as much as possible, 1.933 + * preferring to pass by const Value &. 1.934 + */ 1.935 +class Value 1.936 +{ 1.937 + public: 1.938 + /* 1.939 + * N.B. the default constructor leaves Value unitialized. Adding a default 1.940 + * constructor prevents Value from being stored in a union. 1.941 + */ 1.942 +#if defined(JS_VALUE_IS_CONSTEXPR) 1.943 + Value() = default; 1.944 + Value(const Value& v) = default; 1.945 +#endif 1.946 + 1.947 + /*** Mutators ***/ 1.948 + 1.949 + void setNull() { 1.950 + data.asBits = BUILD_JSVAL(JSVAL_TAG_NULL, 0).asBits; 1.951 + } 1.952 + 1.953 + void setUndefined() { 1.954 + data.asBits = BUILD_JSVAL(JSVAL_TAG_UNDEFINED, 0).asBits; 1.955 + } 1.956 + 1.957 + void setInt32(int32_t i) { 1.958 + data = INT32_TO_JSVAL_IMPL(i); 1.959 + } 1.960 + 1.961 + int32_t &getInt32Ref() { 1.962 + MOZ_ASSERT(isInt32()); 1.963 + return data.s.payload.i32; 1.964 + } 1.965 + 1.966 + void setDouble(double d) { 1.967 + data = DOUBLE_TO_JSVAL_IMPL(d); 1.968 + } 1.969 + 1.970 + void setNaN() { 1.971 + setDouble(GenericNaN()); 1.972 + } 1.973 + 1.974 + double &getDoubleRef() { 1.975 + MOZ_ASSERT(isDouble()); 1.976 + return data.asDouble; 1.977 + } 1.978 + 1.979 + void setString(JSString *str) { 1.980 + MOZ_ASSERT(!IsPoisonedPtr(str)); 1.981 + data = STRING_TO_JSVAL_IMPL(str); 1.982 + } 1.983 + 1.984 + void setObject(JSObject &obj) { 1.985 + MOZ_ASSERT(!IsPoisonedPtr(&obj)); 1.986 + data = OBJECT_TO_JSVAL_IMPL(&obj); 1.987 + } 1.988 + 1.989 + void setBoolean(bool b) { 1.990 + data = BOOLEAN_TO_JSVAL_IMPL(b); 1.991 + } 1.992 + 1.993 + void setMagic(JSWhyMagic why) { 1.994 + data = MAGIC_TO_JSVAL_IMPL(why); 1.995 + } 1.996 + 1.997 + void setMagicUint32(uint32_t payload) { 1.998 + data = MAGIC_UINT32_TO_JSVAL_IMPL(payload); 1.999 + } 1.1000 + 1.1001 + bool setNumber(uint32_t ui) { 1.1002 + if (ui > JSVAL_INT_MAX) { 1.1003 + setDouble((double)ui); 1.1004 + return false; 1.1005 + } else { 1.1006 + setInt32((int32_t)ui); 1.1007 + return true; 1.1008 + } 1.1009 + } 1.1010 + 1.1011 + bool setNumber(double d) { 1.1012 + int32_t i; 1.1013 + if (mozilla::NumberIsInt32(d, &i)) { 1.1014 + setInt32(i); 1.1015 + return true; 1.1016 + } 1.1017 + 1.1018 + setDouble(d); 1.1019 + return false; 1.1020 + } 1.1021 + 1.1022 + void setObjectOrNull(JSObject *arg) { 1.1023 + if (arg) 1.1024 + setObject(*arg); 1.1025 + else 1.1026 + setNull(); 1.1027 + } 1.1028 + 1.1029 + void swap(Value &rhs) { 1.1030 + uint64_t tmp = rhs.data.asBits; 1.1031 + rhs.data.asBits = data.asBits; 1.1032 + data.asBits = tmp; 1.1033 + } 1.1034 + 1.1035 + /*** Value type queries ***/ 1.1036 + 1.1037 + bool isUndefined() const { 1.1038 + return JSVAL_IS_UNDEFINED_IMPL(data); 1.1039 + } 1.1040 + 1.1041 + bool isNull() const { 1.1042 + return JSVAL_IS_NULL_IMPL(data); 1.1043 + } 1.1044 + 1.1045 + bool isNullOrUndefined() const { 1.1046 + return isNull() || isUndefined(); 1.1047 + } 1.1048 + 1.1049 + bool isInt32() const { 1.1050 + return JSVAL_IS_INT32_IMPL(data); 1.1051 + } 1.1052 + 1.1053 + bool isInt32(int32_t i32) const { 1.1054 + return JSVAL_IS_SPECIFIC_INT32_IMPL(data, i32); 1.1055 + } 1.1056 + 1.1057 + bool isDouble() const { 1.1058 + return JSVAL_IS_DOUBLE_IMPL(data); 1.1059 + } 1.1060 + 1.1061 + bool isNumber() const { 1.1062 + return JSVAL_IS_NUMBER_IMPL(data); 1.1063 + } 1.1064 + 1.1065 + bool isString() const { 1.1066 + return JSVAL_IS_STRING_IMPL(data); 1.1067 + } 1.1068 + 1.1069 + bool isObject() const { 1.1070 + return JSVAL_IS_OBJECT_IMPL(data); 1.1071 + } 1.1072 + 1.1073 + bool isPrimitive() const { 1.1074 + return JSVAL_IS_PRIMITIVE_IMPL(data); 1.1075 + } 1.1076 + 1.1077 + bool isObjectOrNull() const { 1.1078 + return JSVAL_IS_OBJECT_OR_NULL_IMPL(data); 1.1079 + } 1.1080 + 1.1081 + bool isGCThing() const { 1.1082 + return JSVAL_IS_GCTHING_IMPL(data); 1.1083 + } 1.1084 + 1.1085 + bool isBoolean() const { 1.1086 + return JSVAL_IS_BOOLEAN_IMPL(data); 1.1087 + } 1.1088 + 1.1089 + bool isTrue() const { 1.1090 + return JSVAL_IS_SPECIFIC_BOOLEAN(data, true); 1.1091 + } 1.1092 + 1.1093 + bool isFalse() const { 1.1094 + return JSVAL_IS_SPECIFIC_BOOLEAN(data, false); 1.1095 + } 1.1096 + 1.1097 + bool isMagic() const { 1.1098 + return JSVAL_IS_MAGIC_IMPL(data); 1.1099 + } 1.1100 + 1.1101 + bool isMagic(JSWhyMagic why) const { 1.1102 + MOZ_ASSERT_IF(isMagic(), data.s.payload.why == why); 1.1103 + return JSVAL_IS_MAGIC_IMPL(data); 1.1104 + } 1.1105 + 1.1106 + bool isMarkable() const { 1.1107 + return JSVAL_IS_TRACEABLE_IMPL(data); 1.1108 + } 1.1109 + 1.1110 + JSGCTraceKind gcKind() const { 1.1111 + MOZ_ASSERT(isMarkable()); 1.1112 + return JSGCTraceKind(JSVAL_TRACE_KIND_IMPL(data)); 1.1113 + } 1.1114 + 1.1115 + JSWhyMagic whyMagic() const { 1.1116 + MOZ_ASSERT(isMagic()); 1.1117 + return data.s.payload.why; 1.1118 + } 1.1119 + 1.1120 + uint32_t magicUint32() const { 1.1121 + MOZ_ASSERT(isMagic()); 1.1122 + return data.s.payload.u32; 1.1123 + } 1.1124 + 1.1125 + /*** Comparison ***/ 1.1126 + 1.1127 + bool operator==(const Value &rhs) const { 1.1128 + return data.asBits == rhs.data.asBits; 1.1129 + } 1.1130 + 1.1131 + bool operator!=(const Value &rhs) const { 1.1132 + return data.asBits != rhs.data.asBits; 1.1133 + } 1.1134 + 1.1135 + friend inline bool SameType(const Value &lhs, const Value &rhs); 1.1136 + 1.1137 + /*** Extract the value's typed payload ***/ 1.1138 + 1.1139 + int32_t toInt32() const { 1.1140 + MOZ_ASSERT(isInt32()); 1.1141 + return JSVAL_TO_INT32_IMPL(data); 1.1142 + } 1.1143 + 1.1144 + double toDouble() const { 1.1145 + MOZ_ASSERT(isDouble()); 1.1146 + return data.asDouble; 1.1147 + } 1.1148 + 1.1149 + double toNumber() const { 1.1150 + MOZ_ASSERT(isNumber()); 1.1151 + return isDouble() ? toDouble() : double(toInt32()); 1.1152 + } 1.1153 + 1.1154 + JSString *toString() const { 1.1155 + MOZ_ASSERT(isString()); 1.1156 + return JSVAL_TO_STRING_IMPL(data); 1.1157 + } 1.1158 + 1.1159 + JSObject &toObject() const { 1.1160 + MOZ_ASSERT(isObject()); 1.1161 + return *JSVAL_TO_OBJECT_IMPL(data); 1.1162 + } 1.1163 + 1.1164 + JSObject *toObjectOrNull() const { 1.1165 + MOZ_ASSERT(isObjectOrNull()); 1.1166 + return JSVAL_TO_OBJECT_IMPL(data); 1.1167 + } 1.1168 + 1.1169 + void *toGCThing() const { 1.1170 + MOZ_ASSERT(isGCThing()); 1.1171 + return JSVAL_TO_GCTHING_IMPL(data); 1.1172 + } 1.1173 + 1.1174 + bool toBoolean() const { 1.1175 + MOZ_ASSERT(isBoolean()); 1.1176 + return JSVAL_TO_BOOLEAN_IMPL(data); 1.1177 + } 1.1178 + 1.1179 + uint32_t payloadAsRawUint32() const { 1.1180 + MOZ_ASSERT(!isDouble()); 1.1181 + return data.s.payload.u32; 1.1182 + } 1.1183 + 1.1184 + uint64_t asRawBits() const { 1.1185 + return data.asBits; 1.1186 + } 1.1187 + 1.1188 + JSValueType extractNonDoubleType() const { 1.1189 + return JSVAL_EXTRACT_NON_DOUBLE_TYPE_IMPL(data); 1.1190 + } 1.1191 + 1.1192 + /* 1.1193 + * Private API 1.1194 + * 1.1195 + * Private setters/getters allow the caller to read/write arbitrary types 1.1196 + * that fit in the 64-bit payload. It is the caller's responsibility, after 1.1197 + * storing to a value with setPrivateX to read only using getPrivateX. 1.1198 + * Privates values are given a type which ensures they are not marked. 1.1199 + */ 1.1200 + 1.1201 + void setPrivate(void *ptr) { 1.1202 + data = PRIVATE_PTR_TO_JSVAL_IMPL(ptr); 1.1203 + } 1.1204 + 1.1205 + void *toPrivate() const { 1.1206 + MOZ_ASSERT(JSVAL_IS_DOUBLE_IMPL(data)); 1.1207 + return JSVAL_TO_PRIVATE_PTR_IMPL(data); 1.1208 + } 1.1209 + 1.1210 + void setPrivateUint32(uint32_t ui) { 1.1211 + MOZ_ASSERT(uint32_t(int32_t(ui)) == ui); 1.1212 + setInt32(int32_t(ui)); 1.1213 + } 1.1214 + 1.1215 + uint32_t toPrivateUint32() const { 1.1216 + return uint32_t(toInt32()); 1.1217 + } 1.1218 + 1.1219 + /* 1.1220 + * An unmarked value is just a void* cast as a Value. Thus, the Value is 1.1221 + * not safe for GC and must not be marked. This API avoids raw casts 1.1222 + * and the ensuing strict-aliasing warnings. 1.1223 + */ 1.1224 + 1.1225 + void setUnmarkedPtr(void *ptr) { 1.1226 + data.asPtr = ptr; 1.1227 + } 1.1228 + 1.1229 + void *toUnmarkedPtr() const { 1.1230 + return data.asPtr; 1.1231 + } 1.1232 + 1.1233 + const size_t *payloadWord() const { 1.1234 +#if JS_BITS_PER_WORD == 32 1.1235 + return &data.s.payload.word; 1.1236 +#elif JS_BITS_PER_WORD == 64 1.1237 + return &data.asWord; 1.1238 +#endif 1.1239 + } 1.1240 + 1.1241 + const uintptr_t *payloadUIntPtr() const { 1.1242 +#if JS_BITS_PER_WORD == 32 1.1243 + return &data.s.payload.uintptr; 1.1244 +#elif JS_BITS_PER_WORD == 64 1.1245 + return &data.asUIntPtr; 1.1246 +#endif 1.1247 + } 1.1248 + 1.1249 +#if !defined(_MSC_VER) && !defined(__sparc) 1.1250 + // Value must be POD so that MSVC will pass it by value and not in memory 1.1251 + // (bug 689101); the same is true for SPARC as well (bug 737344). More 1.1252 + // precisely, we don't want Value return values compiled as out params. 1.1253 + private: 1.1254 +#endif 1.1255 + 1.1256 + jsval_layout data; 1.1257 + 1.1258 + private: 1.1259 +#if defined(JS_VALUE_IS_CONSTEXPR) 1.1260 + JS_VALUE_CONSTEXPR Value(jsval_layout layout) : data(layout) {} 1.1261 +#endif 1.1262 + 1.1263 + void staticAssertions() { 1.1264 + JS_STATIC_ASSERT(sizeof(JSValueType) == 1); 1.1265 + JS_STATIC_ASSERT(sizeof(JSValueTag) == 4); 1.1266 + JS_STATIC_ASSERT(sizeof(JSWhyMagic) <= 4); 1.1267 + JS_STATIC_ASSERT(sizeof(Value) == 8); 1.1268 + } 1.1269 + 1.1270 + friend jsval_layout (::JSVAL_TO_IMPL)(Value); 1.1271 + friend Value JS_VALUE_CONSTEXPR (::IMPL_TO_JSVAL)(jsval_layout l); 1.1272 + friend Value JS_VALUE_CONSTEXPR (JS::UndefinedValue)(); 1.1273 +}; 1.1274 + 1.1275 +inline bool 1.1276 +IsPoisonedValue(const Value &v) 1.1277 +{ 1.1278 + if (v.isString()) 1.1279 + return IsPoisonedPtr(v.toString()); 1.1280 + if (v.isObject()) 1.1281 + return IsPoisonedPtr(&v.toObject()); 1.1282 + return false; 1.1283 +} 1.1284 + 1.1285 +inline bool 1.1286 +IsOptimizedPlaceholderMagicValue(const Value &v) 1.1287 +{ 1.1288 + if (v.isMagic()) { 1.1289 + MOZ_ASSERT(v.whyMagic() == JS_OPTIMIZED_ARGUMENTS || v.whyMagic() == JS_OPTIMIZED_OUT); 1.1290 + return true; 1.1291 + } 1.1292 + return false; 1.1293 +} 1.1294 + 1.1295 +/************************************************************************/ 1.1296 + 1.1297 +static inline Value 1.1298 +NullValue() 1.1299 +{ 1.1300 + Value v; 1.1301 + v.setNull(); 1.1302 + return v; 1.1303 +} 1.1304 + 1.1305 +static inline JS_VALUE_CONSTEXPR Value 1.1306 +UndefinedValue() 1.1307 +{ 1.1308 +#if defined(JS_VALUE_IS_CONSTEXPR) 1.1309 + return Value(BUILD_JSVAL(JSVAL_TAG_UNDEFINED, 0)); 1.1310 +#else 1.1311 + JS::Value v; 1.1312 + v.setUndefined(); 1.1313 + return v; 1.1314 +#endif 1.1315 +} 1.1316 + 1.1317 +static inline Value 1.1318 +Int32Value(int32_t i32) 1.1319 +{ 1.1320 + Value v; 1.1321 + v.setInt32(i32); 1.1322 + return v; 1.1323 +} 1.1324 + 1.1325 +static inline Value 1.1326 +DoubleValue(double dbl) 1.1327 +{ 1.1328 + Value v; 1.1329 + v.setDouble(dbl); 1.1330 + return v; 1.1331 +} 1.1332 + 1.1333 +static inline Value 1.1334 +DoubleNaNValue() 1.1335 +{ 1.1336 + Value v; 1.1337 + v.setNaN(); 1.1338 + return v; 1.1339 +} 1.1340 + 1.1341 +static inline Value 1.1342 +Float32Value(float f) 1.1343 +{ 1.1344 + Value v; 1.1345 + v.setDouble(f); 1.1346 + return v; 1.1347 +} 1.1348 + 1.1349 +static inline Value 1.1350 +StringValue(JSString *str) 1.1351 +{ 1.1352 + Value v; 1.1353 + v.setString(str); 1.1354 + return v; 1.1355 +} 1.1356 + 1.1357 +static inline Value 1.1358 +BooleanValue(bool boo) 1.1359 +{ 1.1360 + Value v; 1.1361 + v.setBoolean(boo); 1.1362 + return v; 1.1363 +} 1.1364 + 1.1365 +static inline Value 1.1366 +TrueValue() 1.1367 +{ 1.1368 + Value v; 1.1369 + v.setBoolean(true); 1.1370 + return v; 1.1371 +} 1.1372 + 1.1373 +static inline Value 1.1374 +FalseValue() 1.1375 +{ 1.1376 + Value v; 1.1377 + v.setBoolean(false); 1.1378 + return v; 1.1379 +} 1.1380 + 1.1381 +static inline Value 1.1382 +ObjectValue(JSObject &obj) 1.1383 +{ 1.1384 + Value v; 1.1385 + v.setObject(obj); 1.1386 + return v; 1.1387 +} 1.1388 + 1.1389 +static inline Value 1.1390 +ObjectValueCrashOnTouch() 1.1391 +{ 1.1392 + Value v; 1.1393 + v.setObject(*reinterpret_cast<JSObject *>(0x42)); 1.1394 + return v; 1.1395 +} 1.1396 + 1.1397 +static inline Value 1.1398 +MagicValue(JSWhyMagic why) 1.1399 +{ 1.1400 + Value v; 1.1401 + v.setMagic(why); 1.1402 + return v; 1.1403 +} 1.1404 + 1.1405 +static inline Value 1.1406 +MagicValueUint32(uint32_t payload) 1.1407 +{ 1.1408 + Value v; 1.1409 + v.setMagicUint32(payload); 1.1410 + return v; 1.1411 +} 1.1412 + 1.1413 +static inline Value 1.1414 +NumberValue(float f) 1.1415 +{ 1.1416 + Value v; 1.1417 + v.setNumber(f); 1.1418 + return v; 1.1419 +} 1.1420 + 1.1421 +static inline Value 1.1422 +NumberValue(double dbl) 1.1423 +{ 1.1424 + Value v; 1.1425 + v.setNumber(dbl); 1.1426 + return v; 1.1427 +} 1.1428 + 1.1429 +static inline Value 1.1430 +NumberValue(int8_t i) 1.1431 +{ 1.1432 + return Int32Value(i); 1.1433 +} 1.1434 + 1.1435 +static inline Value 1.1436 +NumberValue(uint8_t i) 1.1437 +{ 1.1438 + return Int32Value(i); 1.1439 +} 1.1440 + 1.1441 +static inline Value 1.1442 +NumberValue(int16_t i) 1.1443 +{ 1.1444 + return Int32Value(i); 1.1445 +} 1.1446 + 1.1447 +static inline Value 1.1448 +NumberValue(uint16_t i) 1.1449 +{ 1.1450 + return Int32Value(i); 1.1451 +} 1.1452 + 1.1453 +static inline Value 1.1454 +NumberValue(int32_t i) 1.1455 +{ 1.1456 + return Int32Value(i); 1.1457 +} 1.1458 + 1.1459 +static inline Value 1.1460 +NumberValue(uint32_t i) 1.1461 +{ 1.1462 + Value v; 1.1463 + v.setNumber(i); 1.1464 + return v; 1.1465 +} 1.1466 + 1.1467 +namespace detail { 1.1468 + 1.1469 +template <bool Signed> 1.1470 +class MakeNumberValue 1.1471 +{ 1.1472 + public: 1.1473 + template<typename T> 1.1474 + static inline Value create(const T t) 1.1475 + { 1.1476 + Value v; 1.1477 + if (JSVAL_INT_MIN <= t && t <= JSVAL_INT_MAX) 1.1478 + v.setInt32(int32_t(t)); 1.1479 + else 1.1480 + v.setDouble(double(t)); 1.1481 + return v; 1.1482 + } 1.1483 +}; 1.1484 + 1.1485 +template <> 1.1486 +class MakeNumberValue<false> 1.1487 +{ 1.1488 + public: 1.1489 + template<typename T> 1.1490 + static inline Value create(const T t) 1.1491 + { 1.1492 + Value v; 1.1493 + if (t <= JSVAL_INT_MAX) 1.1494 + v.setInt32(int32_t(t)); 1.1495 + else 1.1496 + v.setDouble(double(t)); 1.1497 + return v; 1.1498 + } 1.1499 +}; 1.1500 + 1.1501 +} // namespace detail 1.1502 + 1.1503 +template <typename T> 1.1504 +static inline Value 1.1505 +NumberValue(const T t) 1.1506 +{ 1.1507 + MOZ_ASSERT(T(double(t)) == t, "value creation would be lossy"); 1.1508 + return detail::MakeNumberValue<std::numeric_limits<T>::is_signed>::create(t); 1.1509 +} 1.1510 + 1.1511 +static inline Value 1.1512 +ObjectOrNullValue(JSObject *obj) 1.1513 +{ 1.1514 + Value v; 1.1515 + v.setObjectOrNull(obj); 1.1516 + return v; 1.1517 +} 1.1518 + 1.1519 +static inline Value 1.1520 +PrivateValue(void *ptr) 1.1521 +{ 1.1522 + Value v; 1.1523 + v.setPrivate(ptr); 1.1524 + return v; 1.1525 +} 1.1526 + 1.1527 +static inline Value 1.1528 +PrivateUint32Value(uint32_t ui) 1.1529 +{ 1.1530 + Value v; 1.1531 + v.setPrivateUint32(ui); 1.1532 + return v; 1.1533 +} 1.1534 + 1.1535 +inline bool 1.1536 +SameType(const Value &lhs, const Value &rhs) 1.1537 +{ 1.1538 + return JSVAL_SAME_TYPE_IMPL(lhs.data, rhs.data); 1.1539 +} 1.1540 + 1.1541 +} // namespace JS 1.1542 + 1.1543 +/************************************************************************/ 1.1544 + 1.1545 +#ifdef JSGC_GENERATIONAL 1.1546 +namespace JS { 1.1547 +JS_PUBLIC_API(void) HeapValuePostBarrier(Value *valuep); 1.1548 +JS_PUBLIC_API(void) HeapValueRelocate(Value *valuep); 1.1549 +} 1.1550 +#endif 1.1551 + 1.1552 +namespace js { 1.1553 + 1.1554 +template <> struct GCMethods<const JS::Value> 1.1555 +{ 1.1556 + static JS::Value initial() { return JS::UndefinedValue(); } 1.1557 + static ThingRootKind kind() { return THING_ROOT_VALUE; } 1.1558 + static bool poisoned(const JS::Value &v) { return JS::IsPoisonedValue(v); } 1.1559 +}; 1.1560 + 1.1561 +template <> struct GCMethods<JS::Value> 1.1562 +{ 1.1563 + static JS::Value initial() { return JS::UndefinedValue(); } 1.1564 + static ThingRootKind kind() { return THING_ROOT_VALUE; } 1.1565 + static bool poisoned(const JS::Value &v) { return JS::IsPoisonedValue(v); } 1.1566 + static bool needsPostBarrier(const JS::Value &v) { return v.isMarkable(); } 1.1567 +#ifdef JSGC_GENERATIONAL 1.1568 + static void postBarrier(JS::Value *v) { JS::HeapValuePostBarrier(v); } 1.1569 + static void relocate(JS::Value *v) { JS::HeapValueRelocate(v); } 1.1570 +#endif 1.1571 +}; 1.1572 + 1.1573 +template <class Outer> class MutableValueOperations; 1.1574 + 1.1575 +/* 1.1576 + * A class designed for CRTP use in implementing the non-mutating parts of the 1.1577 + * Value interface in Value-like classes. Outer must be a class inheriting 1.1578 + * ValueOperations<Outer> with a visible extract() method returning the 1.1579 + * const Value* abstracted by Outer. 1.1580 + */ 1.1581 +template <class Outer> 1.1582 +class ValueOperations 1.1583 +{ 1.1584 + friend class MutableValueOperations<Outer>; 1.1585 + 1.1586 + const JS::Value * value() const { return static_cast<const Outer*>(this)->extract(); } 1.1587 + 1.1588 + public: 1.1589 + bool isUndefined() const { return value()->isUndefined(); } 1.1590 + bool isNull() const { return value()->isNull(); } 1.1591 + bool isBoolean() const { return value()->isBoolean(); } 1.1592 + bool isTrue() const { return value()->isTrue(); } 1.1593 + bool isFalse() const { return value()->isFalse(); } 1.1594 + bool isNumber() const { return value()->isNumber(); } 1.1595 + bool isInt32() const { return value()->isInt32(); } 1.1596 + bool isDouble() const { return value()->isDouble(); } 1.1597 + bool isString() const { return value()->isString(); } 1.1598 + bool isObject() const { return value()->isObject(); } 1.1599 + bool isMagic() const { return value()->isMagic(); } 1.1600 + bool isMagic(JSWhyMagic why) const { return value()->isMagic(why); } 1.1601 + bool isMarkable() const { return value()->isMarkable(); } 1.1602 + bool isPrimitive() const { return value()->isPrimitive(); } 1.1603 + bool isGCThing() const { return value()->isGCThing(); } 1.1604 + 1.1605 + bool isNullOrUndefined() const { return value()->isNullOrUndefined(); } 1.1606 + bool isObjectOrNull() const { return value()->isObjectOrNull(); } 1.1607 + 1.1608 + bool toBoolean() const { return value()->toBoolean(); } 1.1609 + double toNumber() const { return value()->toNumber(); } 1.1610 + int32_t toInt32() const { return value()->toInt32(); } 1.1611 + double toDouble() const { return value()->toDouble(); } 1.1612 + JSString *toString() const { return value()->toString(); } 1.1613 + JSObject &toObject() const { return value()->toObject(); } 1.1614 + JSObject *toObjectOrNull() const { return value()->toObjectOrNull(); } 1.1615 + void *toGCThing() const { return value()->toGCThing(); } 1.1616 + 1.1617 + JSValueType extractNonDoubleType() const { return value()->extractNonDoubleType(); } 1.1618 + uint32_t toPrivateUint32() const { return value()->toPrivateUint32(); } 1.1619 + 1.1620 + JSWhyMagic whyMagic() const { return value()->whyMagic(); } 1.1621 + uint32_t magicUint32() const { return value()->magicUint32(); } 1.1622 +}; 1.1623 + 1.1624 +/* 1.1625 + * A class designed for CRTP use in implementing all the mutating parts of the 1.1626 + * Value interface in Value-like classes. Outer must be a class inheriting 1.1627 + * MutableValueOperations<Outer> with visible extractMutable() and extract() 1.1628 + * methods returning the const Value* and Value* abstracted by Outer. 1.1629 + */ 1.1630 +template <class Outer> 1.1631 +class MutableValueOperations : public ValueOperations<Outer> 1.1632 +{ 1.1633 + JS::Value * value() { return static_cast<Outer*>(this)->extractMutable(); } 1.1634 + 1.1635 + public: 1.1636 + void setNull() { value()->setNull(); } 1.1637 + void setUndefined() { value()->setUndefined(); } 1.1638 + void setInt32(int32_t i) { value()->setInt32(i); } 1.1639 + void setDouble(double d) { value()->setDouble(d); } 1.1640 + void setNaN() { setDouble(JS::GenericNaN()); } 1.1641 + void setBoolean(bool b) { value()->setBoolean(b); } 1.1642 + void setMagic(JSWhyMagic why) { value()->setMagic(why); } 1.1643 + bool setNumber(uint32_t ui) { return value()->setNumber(ui); } 1.1644 + bool setNumber(double d) { return value()->setNumber(d); } 1.1645 + void setString(JSString *str) { this->value()->setString(str); } 1.1646 + void setObject(JSObject &obj) { this->value()->setObject(obj); } 1.1647 + void setObjectOrNull(JSObject *arg) { this->value()->setObjectOrNull(arg); } 1.1648 +}; 1.1649 + 1.1650 +/* 1.1651 + * Augment the generic Heap<T> interface when T = Value with 1.1652 + * type-querying, value-extracting, and mutating operations. 1.1653 + */ 1.1654 +template <> 1.1655 +class HeapBase<JS::Value> : public ValueOperations<JS::Heap<JS::Value> > 1.1656 +{ 1.1657 + typedef JS::Heap<JS::Value> Outer; 1.1658 + 1.1659 + friend class ValueOperations<Outer>; 1.1660 + 1.1661 + const JS::Value * extract() const { return static_cast<const Outer*>(this)->address(); } 1.1662 + 1.1663 + void setBarriered(const JS::Value &v) { 1.1664 + static_cast<JS::Heap<JS::Value> *>(this)->set(v); 1.1665 + } 1.1666 + 1.1667 + public: 1.1668 + void setNull() { setBarriered(JS::NullValue()); } 1.1669 + void setUndefined() { setBarriered(JS::UndefinedValue()); } 1.1670 + void setInt32(int32_t i) { setBarriered(JS::Int32Value(i)); } 1.1671 + void setDouble(double d) { setBarriered(JS::DoubleValue(d)); } 1.1672 + void setNaN() { setDouble(JS::GenericNaN()); } 1.1673 + void setBoolean(bool b) { setBarriered(JS::BooleanValue(b)); } 1.1674 + void setMagic(JSWhyMagic why) { setBarriered(JS::MagicValue(why)); } 1.1675 + void setString(JSString *str) { setBarriered(JS::StringValue(str)); } 1.1676 + void setObject(JSObject &obj) { setBarriered(JS::ObjectValue(obj)); } 1.1677 + 1.1678 + bool setNumber(uint32_t ui) { 1.1679 + if (ui > JSVAL_INT_MAX) { 1.1680 + setDouble((double)ui); 1.1681 + return false; 1.1682 + } else { 1.1683 + setInt32((int32_t)ui); 1.1684 + return true; 1.1685 + } 1.1686 + } 1.1687 + 1.1688 + bool setNumber(double d) { 1.1689 + int32_t i; 1.1690 + if (mozilla::NumberIsInt32(d, &i)) { 1.1691 + setInt32(i); 1.1692 + return true; 1.1693 + } 1.1694 + 1.1695 + setDouble(d); 1.1696 + return false; 1.1697 + } 1.1698 + 1.1699 + void setObjectOrNull(JSObject *arg) { 1.1700 + if (arg) 1.1701 + setObject(*arg); 1.1702 + else 1.1703 + setNull(); 1.1704 + } 1.1705 +}; 1.1706 + 1.1707 +/* 1.1708 + * Augment the generic Handle<T> interface when T = Value with type-querying 1.1709 + * and value-extracting operations. 1.1710 + */ 1.1711 +template <> 1.1712 +class HandleBase<JS::Value> : public ValueOperations<JS::Handle<JS::Value> > 1.1713 +{ 1.1714 + friend class ValueOperations<JS::Handle<JS::Value> >; 1.1715 + const JS::Value * extract() const { 1.1716 + return static_cast<const JS::Handle<JS::Value>*>(this)->address(); 1.1717 + } 1.1718 +}; 1.1719 + 1.1720 +/* 1.1721 + * Augment the generic MutableHandle<T> interface when T = Value with 1.1722 + * type-querying, value-extracting, and mutating operations. 1.1723 + */ 1.1724 +template <> 1.1725 +class MutableHandleBase<JS::Value> : public MutableValueOperations<JS::MutableHandle<JS::Value> > 1.1726 +{ 1.1727 + friend class ValueOperations<JS::MutableHandle<JS::Value> >; 1.1728 + const JS::Value * extract() const { 1.1729 + return static_cast<const JS::MutableHandle<JS::Value>*>(this)->address(); 1.1730 + } 1.1731 + 1.1732 + friend class MutableValueOperations<JS::MutableHandle<JS::Value> >; 1.1733 + JS::Value * extractMutable() { 1.1734 + return static_cast<JS::MutableHandle<JS::Value>*>(this)->address(); 1.1735 + } 1.1736 +}; 1.1737 + 1.1738 +/* 1.1739 + * Augment the generic Rooted<T> interface when T = Value with type-querying, 1.1740 + * value-extracting, and mutating operations. 1.1741 + */ 1.1742 +template <> 1.1743 +class RootedBase<JS::Value> : public MutableValueOperations<JS::Rooted<JS::Value> > 1.1744 +{ 1.1745 + friend class ValueOperations<JS::Rooted<JS::Value> >; 1.1746 + const JS::Value * extract() const { 1.1747 + return static_cast<const JS::Rooted<JS::Value>*>(this)->address(); 1.1748 + } 1.1749 + 1.1750 + friend class MutableValueOperations<JS::Rooted<JS::Value> >; 1.1751 + JS::Value * extractMutable() { 1.1752 + return static_cast<JS::Rooted<JS::Value>*>(this)->address(); 1.1753 + } 1.1754 +}; 1.1755 + 1.1756 +} // namespace js 1.1757 + 1.1758 +inline jsval_layout 1.1759 +JSVAL_TO_IMPL(JS::Value v) 1.1760 +{ 1.1761 + return v.data; 1.1762 +} 1.1763 + 1.1764 +inline JS_VALUE_CONSTEXPR JS::Value 1.1765 +IMPL_TO_JSVAL(jsval_layout l) 1.1766 +{ 1.1767 +#if defined(JS_VALUE_IS_CONSTEXPR) 1.1768 + return JS::Value(l); 1.1769 +#else 1.1770 + JS::Value v; 1.1771 + v.data = l; 1.1772 + return v; 1.1773 +#endif 1.1774 +} 1.1775 + 1.1776 +namespace JS { 1.1777 + 1.1778 +#ifndef __GNUC__ 1.1779 +/* 1.1780 + * The default assignment operator for |struct C| has the signature: 1.1781 + * 1.1782 + * C& C::operator=(const C&) 1.1783 + * 1.1784 + * And in particular requires implicit conversion of |this| to type |C| for the 1.1785 + * return value. But |volatile C| cannot thus be converted to |C|, so just 1.1786 + * doing |sink = hold| as in the non-specialized version would fail to compile. 1.1787 + * Do the assignment on asBits instead, since I don't think we want to give 1.1788 + * jsval_layout an assignment operator returning |volatile jsval_layout|. 1.1789 + */ 1.1790 +template<> 1.1791 +inline Anchor<Value>::~Anchor() 1.1792 +{ 1.1793 + volatile uint64_t bits; 1.1794 + bits = JSVAL_TO_IMPL(hold).asBits; 1.1795 +} 1.1796 +#endif 1.1797 + 1.1798 +#ifdef JS_DEBUG 1.1799 +namespace detail { 1.1800 + 1.1801 +struct ValueAlignmentTester { char c; JS::Value v; }; 1.1802 +static_assert(sizeof(ValueAlignmentTester) == 16, 1.1803 + "JS::Value must be 16-byte-aligned"); 1.1804 + 1.1805 +struct LayoutAlignmentTester { char c; jsval_layout l; }; 1.1806 +static_assert(sizeof(LayoutAlignmentTester) == 16, 1.1807 + "jsval_layout must be 16-byte-aligned"); 1.1808 + 1.1809 +} // namespace detail 1.1810 +#endif /* JS_DEBUG */ 1.1811 + 1.1812 +} // namespace JS 1.1813 + 1.1814 +/* 1.1815 + * JS::Value and jsval are the same type; jsval is the old name, kept around 1.1816 + * for backwards compatibility along with all the JSVAL_* operations below. 1.1817 + * jsval_layout is an implementation detail and should not be used externally. 1.1818 + */ 1.1819 +typedef JS::Value jsval; 1.1820 + 1.1821 +static_assert(sizeof(jsval_layout) == sizeof(JS::Value), 1.1822 + "jsval_layout and JS::Value must have identical layouts"); 1.1823 + 1.1824 +/************************************************************************/ 1.1825 + 1.1826 +static inline bool 1.1827 +JSVAL_IS_NULL(jsval v) 1.1828 +{ 1.1829 + return JSVAL_IS_NULL_IMPL(JSVAL_TO_IMPL(v)); 1.1830 +} 1.1831 + 1.1832 +static inline bool 1.1833 +JSVAL_IS_VOID(jsval v) 1.1834 +{ 1.1835 + return JSVAL_IS_UNDEFINED_IMPL(JSVAL_TO_IMPL(v)); 1.1836 +} 1.1837 + 1.1838 +static inline bool 1.1839 +JSVAL_IS_INT(jsval v) 1.1840 +{ 1.1841 + return JSVAL_IS_INT32_IMPL(JSVAL_TO_IMPL(v)); 1.1842 +} 1.1843 + 1.1844 +static inline int32_t 1.1845 +JSVAL_TO_INT(jsval v) 1.1846 +{ 1.1847 + MOZ_ASSERT(JSVAL_IS_INT(v)); 1.1848 + return JSVAL_TO_INT32_IMPL(JSVAL_TO_IMPL(v)); 1.1849 +} 1.1850 + 1.1851 +static inline JS_VALUE_CONSTEXPR jsval 1.1852 +INT_TO_JSVAL(int32_t i) 1.1853 +{ 1.1854 + return IMPL_TO_JSVAL(INT32_TO_JSVAL_IMPL(i)); 1.1855 +} 1.1856 + 1.1857 +static inline bool 1.1858 +JSVAL_IS_DOUBLE(jsval v) 1.1859 +{ 1.1860 + return JSVAL_IS_DOUBLE_IMPL(JSVAL_TO_IMPL(v)); 1.1861 +} 1.1862 + 1.1863 +static inline double 1.1864 +JSVAL_TO_DOUBLE(jsval v) 1.1865 +{ 1.1866 + jsval_layout l; 1.1867 + MOZ_ASSERT(JSVAL_IS_DOUBLE(v)); 1.1868 + l = JSVAL_TO_IMPL(v); 1.1869 + return l.asDouble; 1.1870 +} 1.1871 + 1.1872 +static inline JS_VALUE_CONSTEXPR jsval 1.1873 +DOUBLE_TO_JSVAL(double d) 1.1874 +{ 1.1875 + /* 1.1876 + * This is a manually inlined version of: 1.1877 + * d = JS_CANONICALIZE_NAN(d); 1.1878 + * return IMPL_TO_JSVAL(DOUBLE_TO_JSVAL_IMPL(d)); 1.1879 + * because GCC from XCode 3.1.4 miscompiles the above code. 1.1880 + */ 1.1881 +#if defined(JS_VALUE_IS_CONSTEXPR) 1.1882 + return IMPL_TO_JSVAL(MOZ_UNLIKELY(d != d) 1.1883 + ? (jsval_layout) { .asBits = 0x7FF8000000000000LL } 1.1884 + : (jsval_layout) { .asDouble = d }); 1.1885 +#else 1.1886 + jsval_layout l; 1.1887 + if (MOZ_UNLIKELY(d != d)) 1.1888 + l.asBits = 0x7FF8000000000000LL; 1.1889 + else 1.1890 + l.asDouble = d; 1.1891 + return IMPL_TO_JSVAL(l); 1.1892 +#endif 1.1893 +} 1.1894 + 1.1895 +static inline JS_VALUE_CONSTEXPR jsval 1.1896 +UINT_TO_JSVAL(uint32_t i) 1.1897 +{ 1.1898 + return (i <= JSVAL_INT_MAX 1.1899 + ? INT_TO_JSVAL((int32_t)i) 1.1900 + : DOUBLE_TO_JSVAL((double)i)); 1.1901 +} 1.1902 + 1.1903 +static inline bool 1.1904 +JSVAL_IS_NUMBER(jsval v) 1.1905 +{ 1.1906 + return JSVAL_IS_NUMBER_IMPL(JSVAL_TO_IMPL(v)); 1.1907 +} 1.1908 + 1.1909 +static inline bool 1.1910 +JSVAL_IS_STRING(jsval v) 1.1911 +{ 1.1912 + return JSVAL_IS_STRING_IMPL(JSVAL_TO_IMPL(v)); 1.1913 +} 1.1914 + 1.1915 +static inline JSString * 1.1916 +JSVAL_TO_STRING(jsval v) 1.1917 +{ 1.1918 + MOZ_ASSERT(JSVAL_IS_STRING(v)); 1.1919 + return JSVAL_TO_STRING_IMPL(JSVAL_TO_IMPL(v)); 1.1920 +} 1.1921 + 1.1922 +static inline jsval 1.1923 +STRING_TO_JSVAL(JSString *str) 1.1924 +{ 1.1925 + return IMPL_TO_JSVAL(STRING_TO_JSVAL_IMPL(str)); 1.1926 +} 1.1927 + 1.1928 +static inline JSObject * 1.1929 +JSVAL_TO_OBJECT(jsval v) 1.1930 +{ 1.1931 + MOZ_ASSERT(JSVAL_IS_OBJECT_OR_NULL_IMPL(JSVAL_TO_IMPL(v))); 1.1932 + return JSVAL_TO_OBJECT_IMPL(JSVAL_TO_IMPL(v)); 1.1933 +} 1.1934 + 1.1935 +static inline jsval 1.1936 +OBJECT_TO_JSVAL(JSObject *obj) 1.1937 +{ 1.1938 + if (obj) 1.1939 + return IMPL_TO_JSVAL(OBJECT_TO_JSVAL_IMPL(obj)); 1.1940 + return IMPL_TO_JSVAL(BUILD_JSVAL(JSVAL_TAG_NULL, 0)); 1.1941 +} 1.1942 + 1.1943 +static inline bool 1.1944 +JSVAL_IS_BOOLEAN(jsval v) 1.1945 +{ 1.1946 + return JSVAL_IS_BOOLEAN_IMPL(JSVAL_TO_IMPL(v)); 1.1947 +} 1.1948 + 1.1949 +static inline bool 1.1950 +JSVAL_TO_BOOLEAN(jsval v) 1.1951 +{ 1.1952 + MOZ_ASSERT(JSVAL_IS_BOOLEAN(v)); 1.1953 + return JSVAL_TO_BOOLEAN_IMPL(JSVAL_TO_IMPL(v)); 1.1954 +} 1.1955 + 1.1956 +static inline jsval 1.1957 +BOOLEAN_TO_JSVAL(bool b) 1.1958 +{ 1.1959 + return IMPL_TO_JSVAL(BOOLEAN_TO_JSVAL_IMPL(b)); 1.1960 +} 1.1961 + 1.1962 +static inline bool 1.1963 +JSVAL_IS_PRIMITIVE(jsval v) 1.1964 +{ 1.1965 + return JSVAL_IS_PRIMITIVE_IMPL(JSVAL_TO_IMPL(v)); 1.1966 +} 1.1967 + 1.1968 +static inline bool 1.1969 +JSVAL_IS_GCTHING(jsval v) 1.1970 +{ 1.1971 + return JSVAL_IS_GCTHING_IMPL(JSVAL_TO_IMPL(v)); 1.1972 +} 1.1973 + 1.1974 +static inline void * 1.1975 +JSVAL_TO_GCTHING(jsval v) 1.1976 +{ 1.1977 + MOZ_ASSERT(JSVAL_IS_GCTHING(v)); 1.1978 + return JSVAL_TO_GCTHING_IMPL(JSVAL_TO_IMPL(v)); 1.1979 +} 1.1980 + 1.1981 +/* To be GC-safe, privates are tagged as doubles. */ 1.1982 + 1.1983 +static inline jsval 1.1984 +PRIVATE_TO_JSVAL(void *ptr) 1.1985 +{ 1.1986 + return IMPL_TO_JSVAL(PRIVATE_PTR_TO_JSVAL_IMPL(ptr)); 1.1987 +} 1.1988 + 1.1989 +static inline void * 1.1990 +JSVAL_TO_PRIVATE(jsval v) 1.1991 +{ 1.1992 + MOZ_ASSERT(JSVAL_IS_DOUBLE(v)); 1.1993 + return JSVAL_TO_PRIVATE_PTR_IMPL(JSVAL_TO_IMPL(v)); 1.1994 +} 1.1995 + 1.1996 +// JS constants. For efficiency, prefer predicates (e.g. v.isNull()) and 1.1997 +// constructing values from scratch (e.g. Int32Value(0)). These constants are 1.1998 +// stored in memory and initialized at startup, so testing against them and 1.1999 +// using them requires memory loads and will be correspondingly slow. 1.2000 +extern JS_PUBLIC_DATA(const jsval) JSVAL_NULL; 1.2001 +extern JS_PUBLIC_DATA(const jsval) JSVAL_ZERO; 1.2002 +extern JS_PUBLIC_DATA(const jsval) JSVAL_ONE; 1.2003 +extern JS_PUBLIC_DATA(const jsval) JSVAL_FALSE; 1.2004 +extern JS_PUBLIC_DATA(const jsval) JSVAL_TRUE; 1.2005 +extern JS_PUBLIC_DATA(const jsval) JSVAL_VOID; 1.2006 + 1.2007 +namespace JS { 1.2008 + 1.2009 +extern JS_PUBLIC_DATA(const HandleValue) NullHandleValue; 1.2010 +extern JS_PUBLIC_DATA(const HandleValue) UndefinedHandleValue; 1.2011 + 1.2012 +} 1.2013 + 1.2014 +#undef JS_VALUE_IS_CONSTEXPR 1.2015 +#undef JS_RETURN_LAYOUT_FROM_BITS 1.2016 + 1.2017 +#endif /* js_Value_h */