Fri, 16 Jan 2015 18:13:44 +0100
Integrate suggestion from review to improve consistency with existing code.
michael@0 | 1 | /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- |
michael@0 | 2 | * vim: set ts=8 sts=4 et sw=4 tw=99: |
michael@0 | 3 | * This Source Code Form is subject to the terms of the Mozilla Public |
michael@0 | 4 | * License, v. 2.0. If a copy of the MPL was not distributed with this |
michael@0 | 5 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
michael@0 | 6 | |
michael@0 | 7 | /* JS::Value implementation. */ |
michael@0 | 8 | |
michael@0 | 9 | #ifndef js_Value_h |
michael@0 | 10 | #define js_Value_h |
michael@0 | 11 | |
michael@0 | 12 | #include "mozilla/Attributes.h" |
michael@0 | 13 | #include "mozilla/FloatingPoint.h" |
michael@0 | 14 | #include "mozilla/Likely.h" |
michael@0 | 15 | |
michael@0 | 16 | #include <limits> /* for std::numeric_limits */ |
michael@0 | 17 | |
michael@0 | 18 | #include "jstypes.h" |
michael@0 | 19 | |
michael@0 | 20 | #include "js/Anchor.h" |
michael@0 | 21 | #include "js/RootingAPI.h" |
michael@0 | 22 | #include "js/Utility.h" |
michael@0 | 23 | |
michael@0 | 24 | namespace JS { class Value; } |
michael@0 | 25 | |
michael@0 | 26 | /* JS::Value can store a full int32_t. */ |
michael@0 | 27 | #define JSVAL_INT_BITS 32 |
michael@0 | 28 | #define JSVAL_INT_MIN ((int32_t)0x80000000) |
michael@0 | 29 | #define JSVAL_INT_MAX ((int32_t)0x7fffffff) |
michael@0 | 30 | |
michael@0 | 31 | /* |
michael@0 | 32 | * Try to get jsvals 64-bit aligned. We could almost assert that all values are |
michael@0 | 33 | * aligned, but MSVC and GCC occasionally break alignment. |
michael@0 | 34 | */ |
michael@0 | 35 | #if defined(__GNUC__) || defined(__xlc__) || defined(__xlC__) |
michael@0 | 36 | # define JSVAL_ALIGNMENT __attribute__((aligned (8))) |
michael@0 | 37 | #elif defined(_MSC_VER) |
michael@0 | 38 | /* |
michael@0 | 39 | * Structs can be aligned with MSVC, but not if they are used as parameters, |
michael@0 | 40 | * so we just don't try to align. |
michael@0 | 41 | */ |
michael@0 | 42 | # define JSVAL_ALIGNMENT |
michael@0 | 43 | #elif defined(__SUNPRO_C) || defined(__SUNPRO_CC) |
michael@0 | 44 | # define JSVAL_ALIGNMENT |
michael@0 | 45 | #elif defined(__HP_cc) || defined(__HP_aCC) |
michael@0 | 46 | # define JSVAL_ALIGNMENT |
michael@0 | 47 | #endif |
michael@0 | 48 | |
michael@0 | 49 | #if JS_BITS_PER_WORD == 64 |
michael@0 | 50 | # define JSVAL_TAG_SHIFT 47 |
michael@0 | 51 | #endif |
michael@0 | 52 | |
michael@0 | 53 | /* |
michael@0 | 54 | * We try to use enums so that printing a jsval_layout in the debugger shows |
michael@0 | 55 | * nice symbolic type tags, however we can only do this when we can force the |
michael@0 | 56 | * underlying type of the enum to be the desired size. |
michael@0 | 57 | */ |
michael@0 | 58 | #if !defined(__SUNPRO_CC) && !defined(__xlC__) |
michael@0 | 59 | |
michael@0 | 60 | #if defined(_MSC_VER) |
michael@0 | 61 | # define JS_ENUM_HEADER(id, type) enum id : type |
michael@0 | 62 | # define JS_ENUM_FOOTER(id) |
michael@0 | 63 | #else |
michael@0 | 64 | # define JS_ENUM_HEADER(id, type) enum id |
michael@0 | 65 | # define JS_ENUM_FOOTER(id) __attribute__((packed)) |
michael@0 | 66 | #endif |
michael@0 | 67 | |
michael@0 | 68 | /* Remember to propagate changes to the C defines below. */ |
michael@0 | 69 | JS_ENUM_HEADER(JSValueType, uint8_t) |
michael@0 | 70 | { |
michael@0 | 71 | JSVAL_TYPE_DOUBLE = 0x00, |
michael@0 | 72 | JSVAL_TYPE_INT32 = 0x01, |
michael@0 | 73 | JSVAL_TYPE_UNDEFINED = 0x02, |
michael@0 | 74 | JSVAL_TYPE_BOOLEAN = 0x03, |
michael@0 | 75 | JSVAL_TYPE_MAGIC = 0x04, |
michael@0 | 76 | JSVAL_TYPE_STRING = 0x05, |
michael@0 | 77 | JSVAL_TYPE_NULL = 0x06, |
michael@0 | 78 | JSVAL_TYPE_OBJECT = 0x07, |
michael@0 | 79 | |
michael@0 | 80 | /* These never appear in a jsval; they are only provided as an out-of-band value. */ |
michael@0 | 81 | JSVAL_TYPE_UNKNOWN = 0x20, |
michael@0 | 82 | JSVAL_TYPE_MISSING = 0x21 |
michael@0 | 83 | } JS_ENUM_FOOTER(JSValueType); |
michael@0 | 84 | |
michael@0 | 85 | JS_STATIC_ASSERT(sizeof(JSValueType) == 1); |
michael@0 | 86 | |
michael@0 | 87 | #if JS_BITS_PER_WORD == 32 |
michael@0 | 88 | |
michael@0 | 89 | /* Remember to propagate changes to the C defines below. */ |
michael@0 | 90 | JS_ENUM_HEADER(JSValueTag, uint32_t) |
michael@0 | 91 | { |
michael@0 | 92 | JSVAL_TAG_CLEAR = 0xFFFFFF80, |
michael@0 | 93 | JSVAL_TAG_INT32 = JSVAL_TAG_CLEAR | JSVAL_TYPE_INT32, |
michael@0 | 94 | JSVAL_TAG_UNDEFINED = JSVAL_TAG_CLEAR | JSVAL_TYPE_UNDEFINED, |
michael@0 | 95 | JSVAL_TAG_STRING = JSVAL_TAG_CLEAR | JSVAL_TYPE_STRING, |
michael@0 | 96 | JSVAL_TAG_BOOLEAN = JSVAL_TAG_CLEAR | JSVAL_TYPE_BOOLEAN, |
michael@0 | 97 | JSVAL_TAG_MAGIC = JSVAL_TAG_CLEAR | JSVAL_TYPE_MAGIC, |
michael@0 | 98 | JSVAL_TAG_NULL = JSVAL_TAG_CLEAR | JSVAL_TYPE_NULL, |
michael@0 | 99 | JSVAL_TAG_OBJECT = JSVAL_TAG_CLEAR | JSVAL_TYPE_OBJECT |
michael@0 | 100 | } JS_ENUM_FOOTER(JSValueTag); |
michael@0 | 101 | |
michael@0 | 102 | JS_STATIC_ASSERT(sizeof(JSValueTag) == 4); |
michael@0 | 103 | |
michael@0 | 104 | #elif JS_BITS_PER_WORD == 64 |
michael@0 | 105 | |
michael@0 | 106 | /* Remember to propagate changes to the C defines below. */ |
michael@0 | 107 | JS_ENUM_HEADER(JSValueTag, uint32_t) |
michael@0 | 108 | { |
michael@0 | 109 | JSVAL_TAG_MAX_DOUBLE = 0x1FFF0, |
michael@0 | 110 | JSVAL_TAG_INT32 = JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_INT32, |
michael@0 | 111 | JSVAL_TAG_UNDEFINED = JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_UNDEFINED, |
michael@0 | 112 | JSVAL_TAG_STRING = JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_STRING, |
michael@0 | 113 | JSVAL_TAG_BOOLEAN = JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_BOOLEAN, |
michael@0 | 114 | JSVAL_TAG_MAGIC = JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_MAGIC, |
michael@0 | 115 | JSVAL_TAG_NULL = JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_NULL, |
michael@0 | 116 | JSVAL_TAG_OBJECT = JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_OBJECT |
michael@0 | 117 | } JS_ENUM_FOOTER(JSValueTag); |
michael@0 | 118 | |
michael@0 | 119 | JS_STATIC_ASSERT(sizeof(JSValueTag) == sizeof(uint32_t)); |
michael@0 | 120 | |
michael@0 | 121 | JS_ENUM_HEADER(JSValueShiftedTag, uint64_t) |
michael@0 | 122 | { |
michael@0 | 123 | JSVAL_SHIFTED_TAG_MAX_DOUBLE = ((((uint64_t)JSVAL_TAG_MAX_DOUBLE) << JSVAL_TAG_SHIFT) | 0xFFFFFFFF), |
michael@0 | 124 | JSVAL_SHIFTED_TAG_INT32 = (((uint64_t)JSVAL_TAG_INT32) << JSVAL_TAG_SHIFT), |
michael@0 | 125 | JSVAL_SHIFTED_TAG_UNDEFINED = (((uint64_t)JSVAL_TAG_UNDEFINED) << JSVAL_TAG_SHIFT), |
michael@0 | 126 | JSVAL_SHIFTED_TAG_STRING = (((uint64_t)JSVAL_TAG_STRING) << JSVAL_TAG_SHIFT), |
michael@0 | 127 | JSVAL_SHIFTED_TAG_BOOLEAN = (((uint64_t)JSVAL_TAG_BOOLEAN) << JSVAL_TAG_SHIFT), |
michael@0 | 128 | JSVAL_SHIFTED_TAG_MAGIC = (((uint64_t)JSVAL_TAG_MAGIC) << JSVAL_TAG_SHIFT), |
michael@0 | 129 | JSVAL_SHIFTED_TAG_NULL = (((uint64_t)JSVAL_TAG_NULL) << JSVAL_TAG_SHIFT), |
michael@0 | 130 | JSVAL_SHIFTED_TAG_OBJECT = (((uint64_t)JSVAL_TAG_OBJECT) << JSVAL_TAG_SHIFT) |
michael@0 | 131 | } JS_ENUM_FOOTER(JSValueShiftedTag); |
michael@0 | 132 | |
michael@0 | 133 | JS_STATIC_ASSERT(sizeof(JSValueShiftedTag) == sizeof(uint64_t)); |
michael@0 | 134 | |
michael@0 | 135 | #endif |
michael@0 | 136 | |
michael@0 | 137 | #else /* !defined(__SUNPRO_CC) && !defined(__xlC__) */ |
michael@0 | 138 | |
michael@0 | 139 | typedef uint8_t JSValueType; |
michael@0 | 140 | #define JSVAL_TYPE_DOUBLE ((uint8_t)0x00) |
michael@0 | 141 | #define JSVAL_TYPE_INT32 ((uint8_t)0x01) |
michael@0 | 142 | #define JSVAL_TYPE_UNDEFINED ((uint8_t)0x02) |
michael@0 | 143 | #define JSVAL_TYPE_BOOLEAN ((uint8_t)0x03) |
michael@0 | 144 | #define JSVAL_TYPE_MAGIC ((uint8_t)0x04) |
michael@0 | 145 | #define JSVAL_TYPE_STRING ((uint8_t)0x05) |
michael@0 | 146 | #define JSVAL_TYPE_NULL ((uint8_t)0x06) |
michael@0 | 147 | #define JSVAL_TYPE_OBJECT ((uint8_t)0x07) |
michael@0 | 148 | #define JSVAL_TYPE_UNKNOWN ((uint8_t)0x20) |
michael@0 | 149 | |
michael@0 | 150 | #if JS_BITS_PER_WORD == 32 |
michael@0 | 151 | |
michael@0 | 152 | typedef uint32_t JSValueTag; |
michael@0 | 153 | #define JSVAL_TAG_CLEAR ((uint32_t)(0xFFFFFF80)) |
michael@0 | 154 | #define JSVAL_TAG_INT32 ((uint32_t)(JSVAL_TAG_CLEAR | JSVAL_TYPE_INT32)) |
michael@0 | 155 | #define JSVAL_TAG_UNDEFINED ((uint32_t)(JSVAL_TAG_CLEAR | JSVAL_TYPE_UNDEFINED)) |
michael@0 | 156 | #define JSVAL_TAG_STRING ((uint32_t)(JSVAL_TAG_CLEAR | JSVAL_TYPE_STRING)) |
michael@0 | 157 | #define JSVAL_TAG_BOOLEAN ((uint32_t)(JSVAL_TAG_CLEAR | JSVAL_TYPE_BOOLEAN)) |
michael@0 | 158 | #define JSVAL_TAG_MAGIC ((uint32_t)(JSVAL_TAG_CLEAR | JSVAL_TYPE_MAGIC)) |
michael@0 | 159 | #define JSVAL_TAG_NULL ((uint32_t)(JSVAL_TAG_CLEAR | JSVAL_TYPE_NULL)) |
michael@0 | 160 | #define JSVAL_TAG_OBJECT ((uint32_t)(JSVAL_TAG_CLEAR | JSVAL_TYPE_OBJECT)) |
michael@0 | 161 | |
michael@0 | 162 | #elif JS_BITS_PER_WORD == 64 |
michael@0 | 163 | |
michael@0 | 164 | typedef uint32_t JSValueTag; |
michael@0 | 165 | #define JSVAL_TAG_MAX_DOUBLE ((uint32_t)(0x1FFF0)) |
michael@0 | 166 | #define JSVAL_TAG_INT32 (uint32_t)(JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_INT32) |
michael@0 | 167 | #define JSVAL_TAG_UNDEFINED (uint32_t)(JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_UNDEFINED) |
michael@0 | 168 | #define JSVAL_TAG_STRING (uint32_t)(JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_STRING) |
michael@0 | 169 | #define JSVAL_TAG_BOOLEAN (uint32_t)(JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_BOOLEAN) |
michael@0 | 170 | #define JSVAL_TAG_MAGIC (uint32_t)(JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_MAGIC) |
michael@0 | 171 | #define JSVAL_TAG_NULL (uint32_t)(JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_NULL) |
michael@0 | 172 | #define JSVAL_TAG_OBJECT (uint32_t)(JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_OBJECT) |
michael@0 | 173 | |
michael@0 | 174 | typedef uint64_t JSValueShiftedTag; |
michael@0 | 175 | #define JSVAL_SHIFTED_TAG_MAX_DOUBLE ((((uint64_t)JSVAL_TAG_MAX_DOUBLE) << JSVAL_TAG_SHIFT) | 0xFFFFFFFF) |
michael@0 | 176 | #define JSVAL_SHIFTED_TAG_INT32 (((uint64_t)JSVAL_TAG_INT32) << JSVAL_TAG_SHIFT) |
michael@0 | 177 | #define JSVAL_SHIFTED_TAG_UNDEFINED (((uint64_t)JSVAL_TAG_UNDEFINED) << JSVAL_TAG_SHIFT) |
michael@0 | 178 | #define JSVAL_SHIFTED_TAG_STRING (((uint64_t)JSVAL_TAG_STRING) << JSVAL_TAG_SHIFT) |
michael@0 | 179 | #define JSVAL_SHIFTED_TAG_BOOLEAN (((uint64_t)JSVAL_TAG_BOOLEAN) << JSVAL_TAG_SHIFT) |
michael@0 | 180 | #define JSVAL_SHIFTED_TAG_MAGIC (((uint64_t)JSVAL_TAG_MAGIC) << JSVAL_TAG_SHIFT) |
michael@0 | 181 | #define JSVAL_SHIFTED_TAG_NULL (((uint64_t)JSVAL_TAG_NULL) << JSVAL_TAG_SHIFT) |
michael@0 | 182 | #define JSVAL_SHIFTED_TAG_OBJECT (((uint64_t)JSVAL_TAG_OBJECT) << JSVAL_TAG_SHIFT) |
michael@0 | 183 | |
michael@0 | 184 | #endif /* JS_BITS_PER_WORD */ |
michael@0 | 185 | #endif /* !defined(__SUNPRO_CC) && !defined(__xlC__) */ |
michael@0 | 186 | |
michael@0 | 187 | #define JSVAL_LOWER_INCL_TYPE_OF_OBJ_OR_NULL_SET JSVAL_TYPE_NULL |
michael@0 | 188 | #define JSVAL_UPPER_EXCL_TYPE_OF_PRIMITIVE_SET JSVAL_TYPE_OBJECT |
michael@0 | 189 | #define JSVAL_UPPER_INCL_TYPE_OF_NUMBER_SET JSVAL_TYPE_INT32 |
michael@0 | 190 | #define JSVAL_LOWER_INCL_TYPE_OF_PTR_PAYLOAD_SET JSVAL_TYPE_MAGIC |
michael@0 | 191 | |
michael@0 | 192 | #if JS_BITS_PER_WORD == 32 |
michael@0 | 193 | |
michael@0 | 194 | #define JSVAL_TYPE_TO_TAG(type) ((JSValueTag)(JSVAL_TAG_CLEAR | (type))) |
michael@0 | 195 | |
michael@0 | 196 | #define JSVAL_LOWER_INCL_TAG_OF_OBJ_OR_NULL_SET JSVAL_TAG_NULL |
michael@0 | 197 | #define JSVAL_UPPER_EXCL_TAG_OF_PRIMITIVE_SET JSVAL_TAG_OBJECT |
michael@0 | 198 | #define JSVAL_UPPER_INCL_TAG_OF_NUMBER_SET JSVAL_TAG_INT32 |
michael@0 | 199 | #define JSVAL_LOWER_INCL_TAG_OF_GCTHING_SET JSVAL_TAG_STRING |
michael@0 | 200 | |
michael@0 | 201 | #elif JS_BITS_PER_WORD == 64 |
michael@0 | 202 | |
michael@0 | 203 | #define JSVAL_PAYLOAD_MASK 0x00007FFFFFFFFFFFLL |
michael@0 | 204 | #define JSVAL_TAG_MASK 0xFFFF800000000000LL |
michael@0 | 205 | #define JSVAL_TYPE_TO_TAG(type) ((JSValueTag)(JSVAL_TAG_MAX_DOUBLE | (type))) |
michael@0 | 206 | #define JSVAL_TYPE_TO_SHIFTED_TAG(type) (((uint64_t)JSVAL_TYPE_TO_TAG(type)) << JSVAL_TAG_SHIFT) |
michael@0 | 207 | |
michael@0 | 208 | #define JSVAL_LOWER_INCL_TAG_OF_OBJ_OR_NULL_SET JSVAL_TAG_NULL |
michael@0 | 209 | #define JSVAL_UPPER_EXCL_TAG_OF_PRIMITIVE_SET JSVAL_TAG_OBJECT |
michael@0 | 210 | #define JSVAL_UPPER_INCL_TAG_OF_NUMBER_SET JSVAL_TAG_INT32 |
michael@0 | 211 | #define JSVAL_LOWER_INCL_TAG_OF_GCTHING_SET JSVAL_TAG_STRING |
michael@0 | 212 | |
michael@0 | 213 | #define JSVAL_LOWER_INCL_SHIFTED_TAG_OF_OBJ_OR_NULL_SET JSVAL_SHIFTED_TAG_NULL |
michael@0 | 214 | #define JSVAL_UPPER_EXCL_SHIFTED_TAG_OF_PRIMITIVE_SET JSVAL_SHIFTED_TAG_OBJECT |
michael@0 | 215 | #define JSVAL_UPPER_EXCL_SHIFTED_TAG_OF_NUMBER_SET JSVAL_SHIFTED_TAG_UNDEFINED |
michael@0 | 216 | #define JSVAL_LOWER_INCL_SHIFTED_TAG_OF_GCTHING_SET JSVAL_SHIFTED_TAG_STRING |
michael@0 | 217 | |
michael@0 | 218 | #endif /* JS_BITS_PER_WORD */ |
michael@0 | 219 | |
michael@0 | 220 | typedef enum JSWhyMagic |
michael@0 | 221 | { |
michael@0 | 222 | JS_ELEMENTS_HOLE, /* a hole in a native object's elements */ |
michael@0 | 223 | JS_NATIVE_ENUMERATE, /* indicates that a custom enumerate hook forwarded |
michael@0 | 224 | * to JS_EnumerateState, which really means the object can be |
michael@0 | 225 | * enumerated like a native object. */ |
michael@0 | 226 | JS_NO_ITER_VALUE, /* there is not a pending iterator value */ |
michael@0 | 227 | JS_GENERATOR_CLOSING, /* exception value thrown when closing a generator */ |
michael@0 | 228 | JS_NO_CONSTANT, /* compiler sentinel value */ |
michael@0 | 229 | JS_THIS_POISON, /* used in debug builds to catch tracing errors */ |
michael@0 | 230 | JS_ARG_POISON, /* used in debug builds to catch tracing errors */ |
michael@0 | 231 | JS_SERIALIZE_NO_NODE, /* an empty subnode in the AST serializer */ |
michael@0 | 232 | JS_LAZY_ARGUMENTS, /* lazy arguments value on the stack */ |
michael@0 | 233 | JS_OPTIMIZED_ARGUMENTS, /* optimized-away 'arguments' value */ |
michael@0 | 234 | JS_IS_CONSTRUCTING, /* magic value passed to natives to indicate construction */ |
michael@0 | 235 | JS_OVERWRITTEN_CALLEE, /* arguments.callee has been overwritten */ |
michael@0 | 236 | JS_BLOCK_NEEDS_CLONE, /* value of static block object slot */ |
michael@0 | 237 | JS_HASH_KEY_EMPTY, /* see class js::HashableValue */ |
michael@0 | 238 | JS_ION_ERROR, /* error while running Ion code */ |
michael@0 | 239 | JS_ION_BAILOUT, /* status code to signal EnterIon will OSR into Interpret */ |
michael@0 | 240 | JS_OPTIMIZED_OUT, /* optimized out slot */ |
michael@0 | 241 | JS_GENERIC_MAGIC /* for local use */ |
michael@0 | 242 | } JSWhyMagic; |
michael@0 | 243 | |
michael@0 | 244 | #if defined(IS_LITTLE_ENDIAN) |
michael@0 | 245 | # if JS_BITS_PER_WORD == 32 |
michael@0 | 246 | typedef union jsval_layout |
michael@0 | 247 | { |
michael@0 | 248 | uint64_t asBits; |
michael@0 | 249 | struct { |
michael@0 | 250 | union { |
michael@0 | 251 | int32_t i32; |
michael@0 | 252 | uint32_t u32; |
michael@0 | 253 | uint32_t boo; // Don't use |bool| -- it must be four bytes. |
michael@0 | 254 | JSString *str; |
michael@0 | 255 | JSObject *obj; |
michael@0 | 256 | void *ptr; |
michael@0 | 257 | JSWhyMagic why; |
michael@0 | 258 | size_t word; |
michael@0 | 259 | uintptr_t uintptr; |
michael@0 | 260 | } payload; |
michael@0 | 261 | JSValueTag tag; |
michael@0 | 262 | } s; |
michael@0 | 263 | double asDouble; |
michael@0 | 264 | void *asPtr; |
michael@0 | 265 | } JSVAL_ALIGNMENT jsval_layout; |
michael@0 | 266 | # elif JS_BITS_PER_WORD == 64 |
michael@0 | 267 | typedef union jsval_layout |
michael@0 | 268 | { |
michael@0 | 269 | uint64_t asBits; |
michael@0 | 270 | #if !defined(_WIN64) |
michael@0 | 271 | /* MSVC does not pack these correctly :-( */ |
michael@0 | 272 | struct { |
michael@0 | 273 | uint64_t payload47 : 47; |
michael@0 | 274 | JSValueTag tag : 17; |
michael@0 | 275 | } debugView; |
michael@0 | 276 | #endif |
michael@0 | 277 | struct { |
michael@0 | 278 | union { |
michael@0 | 279 | int32_t i32; |
michael@0 | 280 | uint32_t u32; |
michael@0 | 281 | JSWhyMagic why; |
michael@0 | 282 | } payload; |
michael@0 | 283 | } s; |
michael@0 | 284 | double asDouble; |
michael@0 | 285 | void *asPtr; |
michael@0 | 286 | size_t asWord; |
michael@0 | 287 | uintptr_t asUIntPtr; |
michael@0 | 288 | } JSVAL_ALIGNMENT jsval_layout; |
michael@0 | 289 | # endif /* JS_BITS_PER_WORD */ |
michael@0 | 290 | #else /* defined(IS_LITTLE_ENDIAN) */ |
michael@0 | 291 | # if JS_BITS_PER_WORD == 32 |
michael@0 | 292 | typedef union jsval_layout |
michael@0 | 293 | { |
michael@0 | 294 | uint64_t asBits; |
michael@0 | 295 | struct { |
michael@0 | 296 | JSValueTag tag; |
michael@0 | 297 | union { |
michael@0 | 298 | int32_t i32; |
michael@0 | 299 | uint32_t u32; |
michael@0 | 300 | uint32_t boo; // Don't use |bool| -- it must be four bytes. |
michael@0 | 301 | JSString *str; |
michael@0 | 302 | JSObject *obj; |
michael@0 | 303 | void *ptr; |
michael@0 | 304 | JSWhyMagic why; |
michael@0 | 305 | size_t word; |
michael@0 | 306 | uintptr_t uintptr; |
michael@0 | 307 | } payload; |
michael@0 | 308 | } s; |
michael@0 | 309 | double asDouble; |
michael@0 | 310 | void *asPtr; |
michael@0 | 311 | } JSVAL_ALIGNMENT jsval_layout; |
michael@0 | 312 | # elif JS_BITS_PER_WORD == 64 |
michael@0 | 313 | typedef union jsval_layout |
michael@0 | 314 | { |
michael@0 | 315 | uint64_t asBits; |
michael@0 | 316 | struct { |
michael@0 | 317 | JSValueTag tag : 17; |
michael@0 | 318 | uint64_t payload47 : 47; |
michael@0 | 319 | } debugView; |
michael@0 | 320 | struct { |
michael@0 | 321 | uint32_t padding; |
michael@0 | 322 | union { |
michael@0 | 323 | int32_t i32; |
michael@0 | 324 | uint32_t u32; |
michael@0 | 325 | JSWhyMagic why; |
michael@0 | 326 | } payload; |
michael@0 | 327 | } s; |
michael@0 | 328 | double asDouble; |
michael@0 | 329 | void *asPtr; |
michael@0 | 330 | size_t asWord; |
michael@0 | 331 | uintptr_t asUIntPtr; |
michael@0 | 332 | } JSVAL_ALIGNMENT jsval_layout; |
michael@0 | 333 | # endif /* JS_BITS_PER_WORD */ |
michael@0 | 334 | #endif /* defined(IS_LITTLE_ENDIAN) */ |
michael@0 | 335 | |
michael@0 | 336 | JS_STATIC_ASSERT(sizeof(jsval_layout) == 8); |
michael@0 | 337 | |
michael@0 | 338 | /* |
michael@0 | 339 | * For codesize purposes on some platforms, it's important that the |
michael@0 | 340 | * compiler know that JS::Values constructed from constant values can be |
michael@0 | 341 | * folded to constant bit patterns at compile time, rather than |
michael@0 | 342 | * constructed at runtime. Doing this requires a fair amount of C++11 |
michael@0 | 343 | * features, which are not supported on all of our compilers. Set up |
michael@0 | 344 | * some defines and helper macros in an attempt to confine the ugliness |
michael@0 | 345 | * here, rather than scattering it all about the file. The important |
michael@0 | 346 | * features are: |
michael@0 | 347 | * |
michael@0 | 348 | * - constexpr; |
michael@0 | 349 | * - defaulted functions; |
michael@0 | 350 | * - C99-style designated initializers. |
michael@0 | 351 | */ |
michael@0 | 352 | #if defined(__clang__) |
michael@0 | 353 | # if __has_feature(cxx_constexpr) && __has_feature(cxx_defaulted_functions) |
michael@0 | 354 | # define JS_VALUE_IS_CONSTEXPR |
michael@0 | 355 | # endif |
michael@0 | 356 | #elif defined(__GNUC__) |
michael@0 | 357 | /* |
michael@0 | 358 | * We need 4.5 for defaulted functions, 4.6 for constexpr, 4.7 because 4.6 |
michael@0 | 359 | * doesn't understand |(X) { .field = ... }| syntax, and 4.7.3 because |
michael@0 | 360 | * versions prior to that have bugs in the C++ front-end that cause crashes. |
michael@0 | 361 | */ |
michael@0 | 362 | # if MOZ_GCC_VERSION_AT_LEAST(4, 7, 3) |
michael@0 | 363 | # define JS_VALUE_IS_CONSTEXPR |
michael@0 | 364 | # endif |
michael@0 | 365 | #endif |
michael@0 | 366 | |
michael@0 | 367 | #if defined(JS_VALUE_IS_CONSTEXPR) |
michael@0 | 368 | # define JS_RETURN_LAYOUT_FROM_BITS(BITS) \ |
michael@0 | 369 | return (jsval_layout) { .asBits = (BITS) } |
michael@0 | 370 | # define JS_VALUE_CONSTEXPR MOZ_CONSTEXPR |
michael@0 | 371 | # define JS_VALUE_CONSTEXPR_VAR MOZ_CONSTEXPR_VAR |
michael@0 | 372 | #else |
michael@0 | 373 | # define JS_RETURN_LAYOUT_FROM_BITS(BITS) \ |
michael@0 | 374 | jsval_layout l; \ |
michael@0 | 375 | l.asBits = (BITS); \ |
michael@0 | 376 | return l; |
michael@0 | 377 | # define JS_VALUE_CONSTEXPR |
michael@0 | 378 | # define JS_VALUE_CONSTEXPR_VAR const |
michael@0 | 379 | #endif |
michael@0 | 380 | |
michael@0 | 381 | #if JS_BITS_PER_WORD == 32 |
michael@0 | 382 | |
michael@0 | 383 | /* |
michael@0 | 384 | * N.B. GCC, in some but not all cases, chooses to emit signed comparison of |
michael@0 | 385 | * JSValueTag even though its underlying type has been forced to be uint32_t. |
michael@0 | 386 | * Thus, all comparisons should explicitly cast operands to uint32_t. |
michael@0 | 387 | */ |
michael@0 | 388 | |
michael@0 | 389 | static inline JS_VALUE_CONSTEXPR jsval_layout |
michael@0 | 390 | BUILD_JSVAL(JSValueTag tag, uint32_t payload) |
michael@0 | 391 | { |
michael@0 | 392 | JS_RETURN_LAYOUT_FROM_BITS((((uint64_t)(uint32_t)tag) << 32) | payload); |
michael@0 | 393 | } |
michael@0 | 394 | |
michael@0 | 395 | static inline bool |
michael@0 | 396 | JSVAL_IS_DOUBLE_IMPL(jsval_layout l) |
michael@0 | 397 | { |
michael@0 | 398 | return (uint32_t)l.s.tag <= (uint32_t)JSVAL_TAG_CLEAR; |
michael@0 | 399 | } |
michael@0 | 400 | |
michael@0 | 401 | static inline jsval_layout |
michael@0 | 402 | DOUBLE_TO_JSVAL_IMPL(double d) |
michael@0 | 403 | { |
michael@0 | 404 | jsval_layout l; |
michael@0 | 405 | l.asDouble = d; |
michael@0 | 406 | MOZ_ASSERT(JSVAL_IS_DOUBLE_IMPL(l)); |
michael@0 | 407 | return l; |
michael@0 | 408 | } |
michael@0 | 409 | |
michael@0 | 410 | static inline bool |
michael@0 | 411 | JSVAL_IS_INT32_IMPL(jsval_layout l) |
michael@0 | 412 | { |
michael@0 | 413 | return l.s.tag == JSVAL_TAG_INT32; |
michael@0 | 414 | } |
michael@0 | 415 | |
michael@0 | 416 | static inline int32_t |
michael@0 | 417 | JSVAL_TO_INT32_IMPL(jsval_layout l) |
michael@0 | 418 | { |
michael@0 | 419 | return l.s.payload.i32; |
michael@0 | 420 | } |
michael@0 | 421 | |
michael@0 | 422 | static inline JS_VALUE_CONSTEXPR jsval_layout |
michael@0 | 423 | INT32_TO_JSVAL_IMPL(int32_t i) |
michael@0 | 424 | { |
michael@0 | 425 | #if defined(JS_VALUE_IS_CONSTEXPR) |
michael@0 | 426 | return BUILD_JSVAL(JSVAL_TAG_INT32, i); |
michael@0 | 427 | #else |
michael@0 | 428 | jsval_layout l; |
michael@0 | 429 | l.s.tag = JSVAL_TAG_INT32; |
michael@0 | 430 | l.s.payload.i32 = i; |
michael@0 | 431 | return l; |
michael@0 | 432 | #endif |
michael@0 | 433 | } |
michael@0 | 434 | |
michael@0 | 435 | static inline bool |
michael@0 | 436 | JSVAL_IS_NUMBER_IMPL(jsval_layout l) |
michael@0 | 437 | { |
michael@0 | 438 | JSValueTag tag = l.s.tag; |
michael@0 | 439 | MOZ_ASSERT(tag != JSVAL_TAG_CLEAR); |
michael@0 | 440 | return (uint32_t)tag <= (uint32_t)JSVAL_UPPER_INCL_TAG_OF_NUMBER_SET; |
michael@0 | 441 | } |
michael@0 | 442 | |
michael@0 | 443 | static inline bool |
michael@0 | 444 | JSVAL_IS_UNDEFINED_IMPL(jsval_layout l) |
michael@0 | 445 | { |
michael@0 | 446 | return l.s.tag == JSVAL_TAG_UNDEFINED; |
michael@0 | 447 | } |
michael@0 | 448 | |
michael@0 | 449 | static inline bool |
michael@0 | 450 | JSVAL_IS_STRING_IMPL(jsval_layout l) |
michael@0 | 451 | { |
michael@0 | 452 | return l.s.tag == JSVAL_TAG_STRING; |
michael@0 | 453 | } |
michael@0 | 454 | |
michael@0 | 455 | static inline jsval_layout |
michael@0 | 456 | STRING_TO_JSVAL_IMPL(JSString *str) |
michael@0 | 457 | { |
michael@0 | 458 | jsval_layout l; |
michael@0 | 459 | MOZ_ASSERT(uintptr_t(str) > 0x1000); |
michael@0 | 460 | l.s.tag = JSVAL_TAG_STRING; |
michael@0 | 461 | l.s.payload.str = str; |
michael@0 | 462 | return l; |
michael@0 | 463 | } |
michael@0 | 464 | |
michael@0 | 465 | static inline JSString * |
michael@0 | 466 | JSVAL_TO_STRING_IMPL(jsval_layout l) |
michael@0 | 467 | { |
michael@0 | 468 | return l.s.payload.str; |
michael@0 | 469 | } |
michael@0 | 470 | |
michael@0 | 471 | static inline bool |
michael@0 | 472 | JSVAL_IS_BOOLEAN_IMPL(jsval_layout l) |
michael@0 | 473 | { |
michael@0 | 474 | return l.s.tag == JSVAL_TAG_BOOLEAN; |
michael@0 | 475 | } |
michael@0 | 476 | |
michael@0 | 477 | static inline bool |
michael@0 | 478 | JSVAL_TO_BOOLEAN_IMPL(jsval_layout l) |
michael@0 | 479 | { |
michael@0 | 480 | return l.s.payload.boo; |
michael@0 | 481 | } |
michael@0 | 482 | |
michael@0 | 483 | static inline jsval_layout |
michael@0 | 484 | BOOLEAN_TO_JSVAL_IMPL(bool b) |
michael@0 | 485 | { |
michael@0 | 486 | jsval_layout l; |
michael@0 | 487 | l.s.tag = JSVAL_TAG_BOOLEAN; |
michael@0 | 488 | l.s.payload.boo = b; |
michael@0 | 489 | return l; |
michael@0 | 490 | } |
michael@0 | 491 | |
michael@0 | 492 | static inline bool |
michael@0 | 493 | JSVAL_IS_MAGIC_IMPL(jsval_layout l) |
michael@0 | 494 | { |
michael@0 | 495 | return l.s.tag == JSVAL_TAG_MAGIC; |
michael@0 | 496 | } |
michael@0 | 497 | |
michael@0 | 498 | static inline bool |
michael@0 | 499 | JSVAL_IS_OBJECT_IMPL(jsval_layout l) |
michael@0 | 500 | { |
michael@0 | 501 | return l.s.tag == JSVAL_TAG_OBJECT; |
michael@0 | 502 | } |
michael@0 | 503 | |
michael@0 | 504 | static inline bool |
michael@0 | 505 | JSVAL_IS_PRIMITIVE_IMPL(jsval_layout l) |
michael@0 | 506 | { |
michael@0 | 507 | return (uint32_t)l.s.tag < (uint32_t)JSVAL_UPPER_EXCL_TAG_OF_PRIMITIVE_SET; |
michael@0 | 508 | } |
michael@0 | 509 | |
michael@0 | 510 | static inline bool |
michael@0 | 511 | JSVAL_IS_OBJECT_OR_NULL_IMPL(jsval_layout l) |
michael@0 | 512 | { |
michael@0 | 513 | MOZ_ASSERT((uint32_t)l.s.tag <= (uint32_t)JSVAL_TAG_OBJECT); |
michael@0 | 514 | return (uint32_t)l.s.tag >= (uint32_t)JSVAL_LOWER_INCL_TAG_OF_OBJ_OR_NULL_SET; |
michael@0 | 515 | } |
michael@0 | 516 | |
michael@0 | 517 | static inline JSObject * |
michael@0 | 518 | JSVAL_TO_OBJECT_IMPL(jsval_layout l) |
michael@0 | 519 | { |
michael@0 | 520 | return l.s.payload.obj; |
michael@0 | 521 | } |
michael@0 | 522 | |
michael@0 | 523 | static inline jsval_layout |
michael@0 | 524 | OBJECT_TO_JSVAL_IMPL(JSObject *obj) |
michael@0 | 525 | { |
michael@0 | 526 | jsval_layout l; |
michael@0 | 527 | MOZ_ASSERT(uintptr_t(obj) > 0x1000 || uintptr_t(obj) == 0x42); |
michael@0 | 528 | l.s.tag = JSVAL_TAG_OBJECT; |
michael@0 | 529 | l.s.payload.obj = obj; |
michael@0 | 530 | return l; |
michael@0 | 531 | } |
michael@0 | 532 | |
michael@0 | 533 | static inline bool |
michael@0 | 534 | JSVAL_IS_NULL_IMPL(jsval_layout l) |
michael@0 | 535 | { |
michael@0 | 536 | return l.s.tag == JSVAL_TAG_NULL; |
michael@0 | 537 | } |
michael@0 | 538 | |
michael@0 | 539 | static inline jsval_layout |
michael@0 | 540 | PRIVATE_PTR_TO_JSVAL_IMPL(void *ptr) |
michael@0 | 541 | { |
michael@0 | 542 | jsval_layout l; |
michael@0 | 543 | MOZ_ASSERT(((uint32_t)ptr & 1) == 0); |
michael@0 | 544 | l.s.tag = (JSValueTag)0; |
michael@0 | 545 | l.s.payload.ptr = ptr; |
michael@0 | 546 | MOZ_ASSERT(JSVAL_IS_DOUBLE_IMPL(l)); |
michael@0 | 547 | return l; |
michael@0 | 548 | } |
michael@0 | 549 | |
michael@0 | 550 | static inline void * |
michael@0 | 551 | JSVAL_TO_PRIVATE_PTR_IMPL(jsval_layout l) |
michael@0 | 552 | { |
michael@0 | 553 | return l.s.payload.ptr; |
michael@0 | 554 | } |
michael@0 | 555 | |
michael@0 | 556 | static inline bool |
michael@0 | 557 | JSVAL_IS_GCTHING_IMPL(jsval_layout l) |
michael@0 | 558 | { |
michael@0 | 559 | /* gcc sometimes generates signed < without explicit casts. */ |
michael@0 | 560 | return (uint32_t)l.s.tag >= (uint32_t)JSVAL_LOWER_INCL_TAG_OF_GCTHING_SET; |
michael@0 | 561 | } |
michael@0 | 562 | |
michael@0 | 563 | static inline void * |
michael@0 | 564 | JSVAL_TO_GCTHING_IMPL(jsval_layout l) |
michael@0 | 565 | { |
michael@0 | 566 | return l.s.payload.ptr; |
michael@0 | 567 | } |
michael@0 | 568 | |
michael@0 | 569 | static inline bool |
michael@0 | 570 | JSVAL_IS_TRACEABLE_IMPL(jsval_layout l) |
michael@0 | 571 | { |
michael@0 | 572 | return l.s.tag == JSVAL_TAG_STRING || l.s.tag == JSVAL_TAG_OBJECT; |
michael@0 | 573 | } |
michael@0 | 574 | |
michael@0 | 575 | static inline uint32_t |
michael@0 | 576 | JSVAL_TRACE_KIND_IMPL(jsval_layout l) |
michael@0 | 577 | { |
michael@0 | 578 | return (uint32_t)(bool)JSVAL_IS_STRING_IMPL(l); |
michael@0 | 579 | } |
michael@0 | 580 | |
michael@0 | 581 | static inline bool |
michael@0 | 582 | JSVAL_IS_SPECIFIC_INT32_IMPL(jsval_layout l, int32_t i32) |
michael@0 | 583 | { |
michael@0 | 584 | return l.s.tag == JSVAL_TAG_INT32 && l.s.payload.i32 == i32; |
michael@0 | 585 | } |
michael@0 | 586 | |
michael@0 | 587 | static inline bool |
michael@0 | 588 | JSVAL_IS_SPECIFIC_BOOLEAN(jsval_layout l, bool b) |
michael@0 | 589 | { |
michael@0 | 590 | return (l.s.tag == JSVAL_TAG_BOOLEAN) && (l.s.payload.boo == uint32_t(b)); |
michael@0 | 591 | } |
michael@0 | 592 | |
michael@0 | 593 | static inline jsval_layout |
michael@0 | 594 | MAGIC_TO_JSVAL_IMPL(JSWhyMagic why) |
michael@0 | 595 | { |
michael@0 | 596 | jsval_layout l; |
michael@0 | 597 | l.s.tag = JSVAL_TAG_MAGIC; |
michael@0 | 598 | l.s.payload.why = why; |
michael@0 | 599 | return l; |
michael@0 | 600 | } |
michael@0 | 601 | |
michael@0 | 602 | static inline jsval_layout |
michael@0 | 603 | MAGIC_UINT32_TO_JSVAL_IMPL(uint32_t payload) |
michael@0 | 604 | { |
michael@0 | 605 | jsval_layout l; |
michael@0 | 606 | l.s.tag = JSVAL_TAG_MAGIC; |
michael@0 | 607 | l.s.payload.u32 = payload; |
michael@0 | 608 | return l; |
michael@0 | 609 | } |
michael@0 | 610 | |
michael@0 | 611 | static inline bool |
michael@0 | 612 | JSVAL_SAME_TYPE_IMPL(jsval_layout lhs, jsval_layout rhs) |
michael@0 | 613 | { |
michael@0 | 614 | JSValueTag ltag = lhs.s.tag, rtag = rhs.s.tag; |
michael@0 | 615 | return ltag == rtag || (ltag < JSVAL_TAG_CLEAR && rtag < JSVAL_TAG_CLEAR); |
michael@0 | 616 | } |
michael@0 | 617 | |
michael@0 | 618 | static inline JSValueType |
michael@0 | 619 | JSVAL_EXTRACT_NON_DOUBLE_TYPE_IMPL(jsval_layout l) |
michael@0 | 620 | { |
michael@0 | 621 | uint32_t type = l.s.tag & 0xF; |
michael@0 | 622 | MOZ_ASSERT(type > JSVAL_TYPE_DOUBLE); |
michael@0 | 623 | return (JSValueType)type; |
michael@0 | 624 | } |
michael@0 | 625 | |
michael@0 | 626 | #elif JS_BITS_PER_WORD == 64 |
michael@0 | 627 | |
michael@0 | 628 | static inline JS_VALUE_CONSTEXPR jsval_layout |
michael@0 | 629 | BUILD_JSVAL(JSValueTag tag, uint64_t payload) |
michael@0 | 630 | { |
michael@0 | 631 | JS_RETURN_LAYOUT_FROM_BITS((((uint64_t)(uint32_t)tag) << JSVAL_TAG_SHIFT) | payload); |
michael@0 | 632 | } |
michael@0 | 633 | |
michael@0 | 634 | static inline bool |
michael@0 | 635 | JSVAL_IS_DOUBLE_IMPL(jsval_layout l) |
michael@0 | 636 | { |
michael@0 | 637 | return l.asBits <= JSVAL_SHIFTED_TAG_MAX_DOUBLE; |
michael@0 | 638 | } |
michael@0 | 639 | |
michael@0 | 640 | static inline jsval_layout |
michael@0 | 641 | DOUBLE_TO_JSVAL_IMPL(double d) |
michael@0 | 642 | { |
michael@0 | 643 | jsval_layout l; |
michael@0 | 644 | l.asDouble = d; |
michael@0 | 645 | MOZ_ASSERT(l.asBits <= JSVAL_SHIFTED_TAG_MAX_DOUBLE); |
michael@0 | 646 | return l; |
michael@0 | 647 | } |
michael@0 | 648 | |
michael@0 | 649 | static inline bool |
michael@0 | 650 | JSVAL_IS_INT32_IMPL(jsval_layout l) |
michael@0 | 651 | { |
michael@0 | 652 | return (uint32_t)(l.asBits >> JSVAL_TAG_SHIFT) == JSVAL_TAG_INT32; |
michael@0 | 653 | } |
michael@0 | 654 | |
michael@0 | 655 | static inline int32_t |
michael@0 | 656 | JSVAL_TO_INT32_IMPL(jsval_layout l) |
michael@0 | 657 | { |
michael@0 | 658 | return (int32_t)l.asBits; |
michael@0 | 659 | } |
michael@0 | 660 | |
michael@0 | 661 | static inline JS_VALUE_CONSTEXPR jsval_layout |
michael@0 | 662 | INT32_TO_JSVAL_IMPL(int32_t i32) |
michael@0 | 663 | { |
michael@0 | 664 | JS_RETURN_LAYOUT_FROM_BITS(((uint64_t)(uint32_t)i32) | JSVAL_SHIFTED_TAG_INT32); |
michael@0 | 665 | } |
michael@0 | 666 | |
michael@0 | 667 | static inline bool |
michael@0 | 668 | JSVAL_IS_NUMBER_IMPL(jsval_layout l) |
michael@0 | 669 | { |
michael@0 | 670 | return l.asBits < JSVAL_UPPER_EXCL_SHIFTED_TAG_OF_NUMBER_SET; |
michael@0 | 671 | } |
michael@0 | 672 | |
michael@0 | 673 | static inline bool |
michael@0 | 674 | JSVAL_IS_UNDEFINED_IMPL(jsval_layout l) |
michael@0 | 675 | { |
michael@0 | 676 | return l.asBits == JSVAL_SHIFTED_TAG_UNDEFINED; |
michael@0 | 677 | } |
michael@0 | 678 | |
michael@0 | 679 | static inline bool |
michael@0 | 680 | JSVAL_IS_STRING_IMPL(jsval_layout l) |
michael@0 | 681 | { |
michael@0 | 682 | return (uint32_t)(l.asBits >> JSVAL_TAG_SHIFT) == JSVAL_TAG_STRING; |
michael@0 | 683 | } |
michael@0 | 684 | |
michael@0 | 685 | static inline jsval_layout |
michael@0 | 686 | STRING_TO_JSVAL_IMPL(JSString *str) |
michael@0 | 687 | { |
michael@0 | 688 | jsval_layout l; |
michael@0 | 689 | uint64_t strBits = (uint64_t)str; |
michael@0 | 690 | MOZ_ASSERT(uintptr_t(str) > 0x1000); |
michael@0 | 691 | MOZ_ASSERT((strBits >> JSVAL_TAG_SHIFT) == 0); |
michael@0 | 692 | l.asBits = strBits | JSVAL_SHIFTED_TAG_STRING; |
michael@0 | 693 | return l; |
michael@0 | 694 | } |
michael@0 | 695 | |
michael@0 | 696 | static inline JSString * |
michael@0 | 697 | JSVAL_TO_STRING_IMPL(jsval_layout l) |
michael@0 | 698 | { |
michael@0 | 699 | return (JSString *)(l.asBits & JSVAL_PAYLOAD_MASK); |
michael@0 | 700 | } |
michael@0 | 701 | |
michael@0 | 702 | static inline bool |
michael@0 | 703 | JSVAL_IS_BOOLEAN_IMPL(jsval_layout l) |
michael@0 | 704 | { |
michael@0 | 705 | return (uint32_t)(l.asBits >> JSVAL_TAG_SHIFT) == JSVAL_TAG_BOOLEAN; |
michael@0 | 706 | } |
michael@0 | 707 | |
michael@0 | 708 | static inline bool |
michael@0 | 709 | JSVAL_TO_BOOLEAN_IMPL(jsval_layout l) |
michael@0 | 710 | { |
michael@0 | 711 | return (bool)(l.asBits & JSVAL_PAYLOAD_MASK); |
michael@0 | 712 | } |
michael@0 | 713 | |
michael@0 | 714 | static inline jsval_layout |
michael@0 | 715 | BOOLEAN_TO_JSVAL_IMPL(bool b) |
michael@0 | 716 | { |
michael@0 | 717 | jsval_layout l; |
michael@0 | 718 | l.asBits = ((uint64_t)(uint32_t)b) | JSVAL_SHIFTED_TAG_BOOLEAN; |
michael@0 | 719 | return l; |
michael@0 | 720 | } |
michael@0 | 721 | |
michael@0 | 722 | static inline bool |
michael@0 | 723 | JSVAL_IS_MAGIC_IMPL(jsval_layout l) |
michael@0 | 724 | { |
michael@0 | 725 | return (l.asBits >> JSVAL_TAG_SHIFT) == JSVAL_TAG_MAGIC; |
michael@0 | 726 | } |
michael@0 | 727 | |
michael@0 | 728 | static inline bool |
michael@0 | 729 | JSVAL_IS_PRIMITIVE_IMPL(jsval_layout l) |
michael@0 | 730 | { |
michael@0 | 731 | return l.asBits < JSVAL_UPPER_EXCL_SHIFTED_TAG_OF_PRIMITIVE_SET; |
michael@0 | 732 | } |
michael@0 | 733 | |
michael@0 | 734 | static inline bool |
michael@0 | 735 | JSVAL_IS_OBJECT_IMPL(jsval_layout l) |
michael@0 | 736 | { |
michael@0 | 737 | MOZ_ASSERT((l.asBits >> JSVAL_TAG_SHIFT) <= JSVAL_TAG_OBJECT); |
michael@0 | 738 | return l.asBits >= JSVAL_SHIFTED_TAG_OBJECT; |
michael@0 | 739 | } |
michael@0 | 740 | |
michael@0 | 741 | static inline bool |
michael@0 | 742 | JSVAL_IS_OBJECT_OR_NULL_IMPL(jsval_layout l) |
michael@0 | 743 | { |
michael@0 | 744 | MOZ_ASSERT((l.asBits >> JSVAL_TAG_SHIFT) <= JSVAL_TAG_OBJECT); |
michael@0 | 745 | return l.asBits >= JSVAL_LOWER_INCL_SHIFTED_TAG_OF_OBJ_OR_NULL_SET; |
michael@0 | 746 | } |
michael@0 | 747 | |
michael@0 | 748 | static inline JSObject * |
michael@0 | 749 | JSVAL_TO_OBJECT_IMPL(jsval_layout l) |
michael@0 | 750 | { |
michael@0 | 751 | uint64_t ptrBits = l.asBits & JSVAL_PAYLOAD_MASK; |
michael@0 | 752 | MOZ_ASSERT((ptrBits & 0x7) == 0); |
michael@0 | 753 | return (JSObject *)ptrBits; |
michael@0 | 754 | } |
michael@0 | 755 | |
michael@0 | 756 | static inline jsval_layout |
michael@0 | 757 | OBJECT_TO_JSVAL_IMPL(JSObject *obj) |
michael@0 | 758 | { |
michael@0 | 759 | jsval_layout l; |
michael@0 | 760 | uint64_t objBits = (uint64_t)obj; |
michael@0 | 761 | MOZ_ASSERT(uintptr_t(obj) > 0x1000 || uintptr_t(obj) == 0x42); |
michael@0 | 762 | MOZ_ASSERT((objBits >> JSVAL_TAG_SHIFT) == 0); |
michael@0 | 763 | l.asBits = objBits | JSVAL_SHIFTED_TAG_OBJECT; |
michael@0 | 764 | return l; |
michael@0 | 765 | } |
michael@0 | 766 | |
michael@0 | 767 | static inline bool |
michael@0 | 768 | JSVAL_IS_NULL_IMPL(jsval_layout l) |
michael@0 | 769 | { |
michael@0 | 770 | return l.asBits == JSVAL_SHIFTED_TAG_NULL; |
michael@0 | 771 | } |
michael@0 | 772 | |
michael@0 | 773 | static inline bool |
michael@0 | 774 | JSVAL_IS_GCTHING_IMPL(jsval_layout l) |
michael@0 | 775 | { |
michael@0 | 776 | return l.asBits >= JSVAL_LOWER_INCL_SHIFTED_TAG_OF_GCTHING_SET; |
michael@0 | 777 | } |
michael@0 | 778 | |
michael@0 | 779 | static inline void * |
michael@0 | 780 | JSVAL_TO_GCTHING_IMPL(jsval_layout l) |
michael@0 | 781 | { |
michael@0 | 782 | uint64_t ptrBits = l.asBits & JSVAL_PAYLOAD_MASK; |
michael@0 | 783 | MOZ_ASSERT((ptrBits & 0x7) == 0); |
michael@0 | 784 | return (void *)ptrBits; |
michael@0 | 785 | } |
michael@0 | 786 | |
michael@0 | 787 | static inline bool |
michael@0 | 788 | JSVAL_IS_TRACEABLE_IMPL(jsval_layout l) |
michael@0 | 789 | { |
michael@0 | 790 | return JSVAL_IS_GCTHING_IMPL(l) && !JSVAL_IS_NULL_IMPL(l); |
michael@0 | 791 | } |
michael@0 | 792 | |
michael@0 | 793 | static inline uint32_t |
michael@0 | 794 | JSVAL_TRACE_KIND_IMPL(jsval_layout l) |
michael@0 | 795 | { |
michael@0 | 796 | return (uint32_t)(bool)!(JSVAL_IS_OBJECT_IMPL(l)); |
michael@0 | 797 | } |
michael@0 | 798 | |
michael@0 | 799 | static inline jsval_layout |
michael@0 | 800 | PRIVATE_PTR_TO_JSVAL_IMPL(void *ptr) |
michael@0 | 801 | { |
michael@0 | 802 | jsval_layout l; |
michael@0 | 803 | uint64_t ptrBits = (uint64_t)ptr; |
michael@0 | 804 | MOZ_ASSERT((ptrBits & 1) == 0); |
michael@0 | 805 | l.asBits = ptrBits >> 1; |
michael@0 | 806 | MOZ_ASSERT(JSVAL_IS_DOUBLE_IMPL(l)); |
michael@0 | 807 | return l; |
michael@0 | 808 | } |
michael@0 | 809 | |
michael@0 | 810 | static inline void * |
michael@0 | 811 | JSVAL_TO_PRIVATE_PTR_IMPL(jsval_layout l) |
michael@0 | 812 | { |
michael@0 | 813 | MOZ_ASSERT((l.asBits & 0x8000000000000000LL) == 0); |
michael@0 | 814 | return (void *)(l.asBits << 1); |
michael@0 | 815 | } |
michael@0 | 816 | |
michael@0 | 817 | static inline bool |
michael@0 | 818 | JSVAL_IS_SPECIFIC_INT32_IMPL(jsval_layout l, int32_t i32) |
michael@0 | 819 | { |
michael@0 | 820 | return l.asBits == (((uint64_t)(uint32_t)i32) | JSVAL_SHIFTED_TAG_INT32); |
michael@0 | 821 | } |
michael@0 | 822 | |
michael@0 | 823 | static inline bool |
michael@0 | 824 | JSVAL_IS_SPECIFIC_BOOLEAN(jsval_layout l, bool b) |
michael@0 | 825 | { |
michael@0 | 826 | return l.asBits == (((uint64_t)(uint32_t)b) | JSVAL_SHIFTED_TAG_BOOLEAN); |
michael@0 | 827 | } |
michael@0 | 828 | |
michael@0 | 829 | static inline jsval_layout |
michael@0 | 830 | MAGIC_TO_JSVAL_IMPL(JSWhyMagic why) |
michael@0 | 831 | { |
michael@0 | 832 | jsval_layout l; |
michael@0 | 833 | l.asBits = ((uint64_t)(uint32_t)why) | JSVAL_SHIFTED_TAG_MAGIC; |
michael@0 | 834 | return l; |
michael@0 | 835 | } |
michael@0 | 836 | |
michael@0 | 837 | static inline jsval_layout |
michael@0 | 838 | MAGIC_UINT32_TO_JSVAL_IMPL(uint32_t payload) |
michael@0 | 839 | { |
michael@0 | 840 | jsval_layout l; |
michael@0 | 841 | l.asBits = ((uint64_t)payload) | JSVAL_SHIFTED_TAG_MAGIC; |
michael@0 | 842 | return l; |
michael@0 | 843 | } |
michael@0 | 844 | |
michael@0 | 845 | static inline bool |
michael@0 | 846 | JSVAL_SAME_TYPE_IMPL(jsval_layout lhs, jsval_layout rhs) |
michael@0 | 847 | { |
michael@0 | 848 | uint64_t lbits = lhs.asBits, rbits = rhs.asBits; |
michael@0 | 849 | return (lbits <= JSVAL_SHIFTED_TAG_MAX_DOUBLE && rbits <= JSVAL_SHIFTED_TAG_MAX_DOUBLE) || |
michael@0 | 850 | (((lbits ^ rbits) & 0xFFFF800000000000LL) == 0); |
michael@0 | 851 | } |
michael@0 | 852 | |
michael@0 | 853 | static inline JSValueType |
michael@0 | 854 | JSVAL_EXTRACT_NON_DOUBLE_TYPE_IMPL(jsval_layout l) |
michael@0 | 855 | { |
michael@0 | 856 | uint64_t type = (l.asBits >> JSVAL_TAG_SHIFT) & 0xF; |
michael@0 | 857 | MOZ_ASSERT(type > JSVAL_TYPE_DOUBLE); |
michael@0 | 858 | return (JSValueType)type; |
michael@0 | 859 | } |
michael@0 | 860 | |
michael@0 | 861 | #endif /* JS_BITS_PER_WORD */ |
michael@0 | 862 | |
michael@0 | 863 | static inline jsval_layout JSVAL_TO_IMPL(JS::Value v); |
michael@0 | 864 | static inline JS_VALUE_CONSTEXPR JS::Value IMPL_TO_JSVAL(jsval_layout l); |
michael@0 | 865 | |
michael@0 | 866 | namespace JS { |
michael@0 | 867 | |
michael@0 | 868 | static inline JS_VALUE_CONSTEXPR JS::Value UndefinedValue(); |
michael@0 | 869 | |
michael@0 | 870 | /** |
michael@0 | 871 | * Returns a generic quiet NaN value, with all payload bits set to zero. |
michael@0 | 872 | * |
michael@0 | 873 | * Among other properties, this NaN's bit pattern conforms to JS::Value's |
michael@0 | 874 | * bit pattern restrictions. |
michael@0 | 875 | */ |
michael@0 | 876 | static MOZ_ALWAYS_INLINE double |
michael@0 | 877 | GenericNaN() |
michael@0 | 878 | { |
michael@0 | 879 | return mozilla::SpecificNaN<double>(0, 0x8000000000000ULL); |
michael@0 | 880 | } |
michael@0 | 881 | |
michael@0 | 882 | /* MSVC with PGO miscompiles this function. */ |
michael@0 | 883 | #if defined(_MSC_VER) |
michael@0 | 884 | # pragma optimize("g", off) |
michael@0 | 885 | #endif |
michael@0 | 886 | static inline double |
michael@0 | 887 | CanonicalizeNaN(double d) |
michael@0 | 888 | { |
michael@0 | 889 | if (MOZ_UNLIKELY(mozilla::IsNaN(d))) |
michael@0 | 890 | return GenericNaN(); |
michael@0 | 891 | return d; |
michael@0 | 892 | } |
michael@0 | 893 | #if defined(_MSC_VER) |
michael@0 | 894 | # pragma optimize("", on) |
michael@0 | 895 | #endif |
michael@0 | 896 | |
michael@0 | 897 | /* |
michael@0 | 898 | * JS::Value is the interface for a single JavaScript Engine value. A few |
michael@0 | 899 | * general notes on JS::Value: |
michael@0 | 900 | * |
michael@0 | 901 | * - JS::Value has setX() and isX() members for X in |
michael@0 | 902 | * |
michael@0 | 903 | * { Int32, Double, String, Boolean, Undefined, Null, Object, Magic } |
michael@0 | 904 | * |
michael@0 | 905 | * JS::Value also contains toX() for each of the non-singleton types. |
michael@0 | 906 | * |
michael@0 | 907 | * - Magic is a singleton type whose payload contains either a JSWhyMagic "reason" for |
michael@0 | 908 | * the magic value or a uint32_t value. By providing JSWhyMagic values when |
michael@0 | 909 | * creating and checking for magic values, it is possible to assert, at |
michael@0 | 910 | * runtime, that only magic values with the expected reason flow through a |
michael@0 | 911 | * particular value. For example, if cx->exception has a magic value, the |
michael@0 | 912 | * reason must be JS_GENERATOR_CLOSING. |
michael@0 | 913 | * |
michael@0 | 914 | * - The JS::Value operations are preferred. The JSVAL_* operations remain for |
michael@0 | 915 | * compatibility; they may be removed at some point. These operations mostly |
michael@0 | 916 | * provide similar functionality. But there are a few key differences. One |
michael@0 | 917 | * is that JS::Value gives null a separate type. Thus |
michael@0 | 918 | * |
michael@0 | 919 | * JSVAL_IS_OBJECT(v) === v.isObjectOrNull() |
michael@0 | 920 | * !JSVAL_IS_PRIMITIVE(v) === v.isObject() |
michael@0 | 921 | * |
michael@0 | 922 | * Also, to help prevent mistakenly boxing a nullable JSObject* as an object, |
michael@0 | 923 | * Value::setObject takes a JSObject&. (Conversely, Value::toObject returns a |
michael@0 | 924 | * JSObject&.) A convenience member Value::setObjectOrNull is provided. |
michael@0 | 925 | * |
michael@0 | 926 | * - JSVAL_VOID is the same as the singleton value of the Undefined type. |
michael@0 | 927 | * |
michael@0 | 928 | * - Note that JS::Value is 8 bytes on 32 and 64-bit architectures. Thus, on |
michael@0 | 929 | * 32-bit user code should avoid copying jsval/JS::Value as much as possible, |
michael@0 | 930 | * preferring to pass by const Value &. |
michael@0 | 931 | */ |
michael@0 | 932 | class Value |
michael@0 | 933 | { |
michael@0 | 934 | public: |
michael@0 | 935 | /* |
michael@0 | 936 | * N.B. the default constructor leaves Value unitialized. Adding a default |
michael@0 | 937 | * constructor prevents Value from being stored in a union. |
michael@0 | 938 | */ |
michael@0 | 939 | #if defined(JS_VALUE_IS_CONSTEXPR) |
michael@0 | 940 | Value() = default; |
michael@0 | 941 | Value(const Value& v) = default; |
michael@0 | 942 | #endif |
michael@0 | 943 | |
michael@0 | 944 | /*** Mutators ***/ |
michael@0 | 945 | |
michael@0 | 946 | void setNull() { |
michael@0 | 947 | data.asBits = BUILD_JSVAL(JSVAL_TAG_NULL, 0).asBits; |
michael@0 | 948 | } |
michael@0 | 949 | |
michael@0 | 950 | void setUndefined() { |
michael@0 | 951 | data.asBits = BUILD_JSVAL(JSVAL_TAG_UNDEFINED, 0).asBits; |
michael@0 | 952 | } |
michael@0 | 953 | |
michael@0 | 954 | void setInt32(int32_t i) { |
michael@0 | 955 | data = INT32_TO_JSVAL_IMPL(i); |
michael@0 | 956 | } |
michael@0 | 957 | |
michael@0 | 958 | int32_t &getInt32Ref() { |
michael@0 | 959 | MOZ_ASSERT(isInt32()); |
michael@0 | 960 | return data.s.payload.i32; |
michael@0 | 961 | } |
michael@0 | 962 | |
michael@0 | 963 | void setDouble(double d) { |
michael@0 | 964 | data = DOUBLE_TO_JSVAL_IMPL(d); |
michael@0 | 965 | } |
michael@0 | 966 | |
michael@0 | 967 | void setNaN() { |
michael@0 | 968 | setDouble(GenericNaN()); |
michael@0 | 969 | } |
michael@0 | 970 | |
michael@0 | 971 | double &getDoubleRef() { |
michael@0 | 972 | MOZ_ASSERT(isDouble()); |
michael@0 | 973 | return data.asDouble; |
michael@0 | 974 | } |
michael@0 | 975 | |
michael@0 | 976 | void setString(JSString *str) { |
michael@0 | 977 | MOZ_ASSERT(!IsPoisonedPtr(str)); |
michael@0 | 978 | data = STRING_TO_JSVAL_IMPL(str); |
michael@0 | 979 | } |
michael@0 | 980 | |
michael@0 | 981 | void setObject(JSObject &obj) { |
michael@0 | 982 | MOZ_ASSERT(!IsPoisonedPtr(&obj)); |
michael@0 | 983 | data = OBJECT_TO_JSVAL_IMPL(&obj); |
michael@0 | 984 | } |
michael@0 | 985 | |
michael@0 | 986 | void setBoolean(bool b) { |
michael@0 | 987 | data = BOOLEAN_TO_JSVAL_IMPL(b); |
michael@0 | 988 | } |
michael@0 | 989 | |
michael@0 | 990 | void setMagic(JSWhyMagic why) { |
michael@0 | 991 | data = MAGIC_TO_JSVAL_IMPL(why); |
michael@0 | 992 | } |
michael@0 | 993 | |
michael@0 | 994 | void setMagicUint32(uint32_t payload) { |
michael@0 | 995 | data = MAGIC_UINT32_TO_JSVAL_IMPL(payload); |
michael@0 | 996 | } |
michael@0 | 997 | |
michael@0 | 998 | bool setNumber(uint32_t ui) { |
michael@0 | 999 | if (ui > JSVAL_INT_MAX) { |
michael@0 | 1000 | setDouble((double)ui); |
michael@0 | 1001 | return false; |
michael@0 | 1002 | } else { |
michael@0 | 1003 | setInt32((int32_t)ui); |
michael@0 | 1004 | return true; |
michael@0 | 1005 | } |
michael@0 | 1006 | } |
michael@0 | 1007 | |
michael@0 | 1008 | bool setNumber(double d) { |
michael@0 | 1009 | int32_t i; |
michael@0 | 1010 | if (mozilla::NumberIsInt32(d, &i)) { |
michael@0 | 1011 | setInt32(i); |
michael@0 | 1012 | return true; |
michael@0 | 1013 | } |
michael@0 | 1014 | |
michael@0 | 1015 | setDouble(d); |
michael@0 | 1016 | return false; |
michael@0 | 1017 | } |
michael@0 | 1018 | |
michael@0 | 1019 | void setObjectOrNull(JSObject *arg) { |
michael@0 | 1020 | if (arg) |
michael@0 | 1021 | setObject(*arg); |
michael@0 | 1022 | else |
michael@0 | 1023 | setNull(); |
michael@0 | 1024 | } |
michael@0 | 1025 | |
michael@0 | 1026 | void swap(Value &rhs) { |
michael@0 | 1027 | uint64_t tmp = rhs.data.asBits; |
michael@0 | 1028 | rhs.data.asBits = data.asBits; |
michael@0 | 1029 | data.asBits = tmp; |
michael@0 | 1030 | } |
michael@0 | 1031 | |
michael@0 | 1032 | /*** Value type queries ***/ |
michael@0 | 1033 | |
michael@0 | 1034 | bool isUndefined() const { |
michael@0 | 1035 | return JSVAL_IS_UNDEFINED_IMPL(data); |
michael@0 | 1036 | } |
michael@0 | 1037 | |
michael@0 | 1038 | bool isNull() const { |
michael@0 | 1039 | return JSVAL_IS_NULL_IMPL(data); |
michael@0 | 1040 | } |
michael@0 | 1041 | |
michael@0 | 1042 | bool isNullOrUndefined() const { |
michael@0 | 1043 | return isNull() || isUndefined(); |
michael@0 | 1044 | } |
michael@0 | 1045 | |
michael@0 | 1046 | bool isInt32() const { |
michael@0 | 1047 | return JSVAL_IS_INT32_IMPL(data); |
michael@0 | 1048 | } |
michael@0 | 1049 | |
michael@0 | 1050 | bool isInt32(int32_t i32) const { |
michael@0 | 1051 | return JSVAL_IS_SPECIFIC_INT32_IMPL(data, i32); |
michael@0 | 1052 | } |
michael@0 | 1053 | |
michael@0 | 1054 | bool isDouble() const { |
michael@0 | 1055 | return JSVAL_IS_DOUBLE_IMPL(data); |
michael@0 | 1056 | } |
michael@0 | 1057 | |
michael@0 | 1058 | bool isNumber() const { |
michael@0 | 1059 | return JSVAL_IS_NUMBER_IMPL(data); |
michael@0 | 1060 | } |
michael@0 | 1061 | |
michael@0 | 1062 | bool isString() const { |
michael@0 | 1063 | return JSVAL_IS_STRING_IMPL(data); |
michael@0 | 1064 | } |
michael@0 | 1065 | |
michael@0 | 1066 | bool isObject() const { |
michael@0 | 1067 | return JSVAL_IS_OBJECT_IMPL(data); |
michael@0 | 1068 | } |
michael@0 | 1069 | |
michael@0 | 1070 | bool isPrimitive() const { |
michael@0 | 1071 | return JSVAL_IS_PRIMITIVE_IMPL(data); |
michael@0 | 1072 | } |
michael@0 | 1073 | |
michael@0 | 1074 | bool isObjectOrNull() const { |
michael@0 | 1075 | return JSVAL_IS_OBJECT_OR_NULL_IMPL(data); |
michael@0 | 1076 | } |
michael@0 | 1077 | |
michael@0 | 1078 | bool isGCThing() const { |
michael@0 | 1079 | return JSVAL_IS_GCTHING_IMPL(data); |
michael@0 | 1080 | } |
michael@0 | 1081 | |
michael@0 | 1082 | bool isBoolean() const { |
michael@0 | 1083 | return JSVAL_IS_BOOLEAN_IMPL(data); |
michael@0 | 1084 | } |
michael@0 | 1085 | |
michael@0 | 1086 | bool isTrue() const { |
michael@0 | 1087 | return JSVAL_IS_SPECIFIC_BOOLEAN(data, true); |
michael@0 | 1088 | } |
michael@0 | 1089 | |
michael@0 | 1090 | bool isFalse() const { |
michael@0 | 1091 | return JSVAL_IS_SPECIFIC_BOOLEAN(data, false); |
michael@0 | 1092 | } |
michael@0 | 1093 | |
michael@0 | 1094 | bool isMagic() const { |
michael@0 | 1095 | return JSVAL_IS_MAGIC_IMPL(data); |
michael@0 | 1096 | } |
michael@0 | 1097 | |
michael@0 | 1098 | bool isMagic(JSWhyMagic why) const { |
michael@0 | 1099 | MOZ_ASSERT_IF(isMagic(), data.s.payload.why == why); |
michael@0 | 1100 | return JSVAL_IS_MAGIC_IMPL(data); |
michael@0 | 1101 | } |
michael@0 | 1102 | |
michael@0 | 1103 | bool isMarkable() const { |
michael@0 | 1104 | return JSVAL_IS_TRACEABLE_IMPL(data); |
michael@0 | 1105 | } |
michael@0 | 1106 | |
michael@0 | 1107 | JSGCTraceKind gcKind() const { |
michael@0 | 1108 | MOZ_ASSERT(isMarkable()); |
michael@0 | 1109 | return JSGCTraceKind(JSVAL_TRACE_KIND_IMPL(data)); |
michael@0 | 1110 | } |
michael@0 | 1111 | |
michael@0 | 1112 | JSWhyMagic whyMagic() const { |
michael@0 | 1113 | MOZ_ASSERT(isMagic()); |
michael@0 | 1114 | return data.s.payload.why; |
michael@0 | 1115 | } |
michael@0 | 1116 | |
michael@0 | 1117 | uint32_t magicUint32() const { |
michael@0 | 1118 | MOZ_ASSERT(isMagic()); |
michael@0 | 1119 | return data.s.payload.u32; |
michael@0 | 1120 | } |
michael@0 | 1121 | |
michael@0 | 1122 | /*** Comparison ***/ |
michael@0 | 1123 | |
michael@0 | 1124 | bool operator==(const Value &rhs) const { |
michael@0 | 1125 | return data.asBits == rhs.data.asBits; |
michael@0 | 1126 | } |
michael@0 | 1127 | |
michael@0 | 1128 | bool operator!=(const Value &rhs) const { |
michael@0 | 1129 | return data.asBits != rhs.data.asBits; |
michael@0 | 1130 | } |
michael@0 | 1131 | |
michael@0 | 1132 | friend inline bool SameType(const Value &lhs, const Value &rhs); |
michael@0 | 1133 | |
michael@0 | 1134 | /*** Extract the value's typed payload ***/ |
michael@0 | 1135 | |
michael@0 | 1136 | int32_t toInt32() const { |
michael@0 | 1137 | MOZ_ASSERT(isInt32()); |
michael@0 | 1138 | return JSVAL_TO_INT32_IMPL(data); |
michael@0 | 1139 | } |
michael@0 | 1140 | |
michael@0 | 1141 | double toDouble() const { |
michael@0 | 1142 | MOZ_ASSERT(isDouble()); |
michael@0 | 1143 | return data.asDouble; |
michael@0 | 1144 | } |
michael@0 | 1145 | |
michael@0 | 1146 | double toNumber() const { |
michael@0 | 1147 | MOZ_ASSERT(isNumber()); |
michael@0 | 1148 | return isDouble() ? toDouble() : double(toInt32()); |
michael@0 | 1149 | } |
michael@0 | 1150 | |
michael@0 | 1151 | JSString *toString() const { |
michael@0 | 1152 | MOZ_ASSERT(isString()); |
michael@0 | 1153 | return JSVAL_TO_STRING_IMPL(data); |
michael@0 | 1154 | } |
michael@0 | 1155 | |
michael@0 | 1156 | JSObject &toObject() const { |
michael@0 | 1157 | MOZ_ASSERT(isObject()); |
michael@0 | 1158 | return *JSVAL_TO_OBJECT_IMPL(data); |
michael@0 | 1159 | } |
michael@0 | 1160 | |
michael@0 | 1161 | JSObject *toObjectOrNull() const { |
michael@0 | 1162 | MOZ_ASSERT(isObjectOrNull()); |
michael@0 | 1163 | return JSVAL_TO_OBJECT_IMPL(data); |
michael@0 | 1164 | } |
michael@0 | 1165 | |
michael@0 | 1166 | void *toGCThing() const { |
michael@0 | 1167 | MOZ_ASSERT(isGCThing()); |
michael@0 | 1168 | return JSVAL_TO_GCTHING_IMPL(data); |
michael@0 | 1169 | } |
michael@0 | 1170 | |
michael@0 | 1171 | bool toBoolean() const { |
michael@0 | 1172 | MOZ_ASSERT(isBoolean()); |
michael@0 | 1173 | return JSVAL_TO_BOOLEAN_IMPL(data); |
michael@0 | 1174 | } |
michael@0 | 1175 | |
michael@0 | 1176 | uint32_t payloadAsRawUint32() const { |
michael@0 | 1177 | MOZ_ASSERT(!isDouble()); |
michael@0 | 1178 | return data.s.payload.u32; |
michael@0 | 1179 | } |
michael@0 | 1180 | |
michael@0 | 1181 | uint64_t asRawBits() const { |
michael@0 | 1182 | return data.asBits; |
michael@0 | 1183 | } |
michael@0 | 1184 | |
michael@0 | 1185 | JSValueType extractNonDoubleType() const { |
michael@0 | 1186 | return JSVAL_EXTRACT_NON_DOUBLE_TYPE_IMPL(data); |
michael@0 | 1187 | } |
michael@0 | 1188 | |
michael@0 | 1189 | /* |
michael@0 | 1190 | * Private API |
michael@0 | 1191 | * |
michael@0 | 1192 | * Private setters/getters allow the caller to read/write arbitrary types |
michael@0 | 1193 | * that fit in the 64-bit payload. It is the caller's responsibility, after |
michael@0 | 1194 | * storing to a value with setPrivateX to read only using getPrivateX. |
michael@0 | 1195 | * Privates values are given a type which ensures they are not marked. |
michael@0 | 1196 | */ |
michael@0 | 1197 | |
michael@0 | 1198 | void setPrivate(void *ptr) { |
michael@0 | 1199 | data = PRIVATE_PTR_TO_JSVAL_IMPL(ptr); |
michael@0 | 1200 | } |
michael@0 | 1201 | |
michael@0 | 1202 | void *toPrivate() const { |
michael@0 | 1203 | MOZ_ASSERT(JSVAL_IS_DOUBLE_IMPL(data)); |
michael@0 | 1204 | return JSVAL_TO_PRIVATE_PTR_IMPL(data); |
michael@0 | 1205 | } |
michael@0 | 1206 | |
michael@0 | 1207 | void setPrivateUint32(uint32_t ui) { |
michael@0 | 1208 | MOZ_ASSERT(uint32_t(int32_t(ui)) == ui); |
michael@0 | 1209 | setInt32(int32_t(ui)); |
michael@0 | 1210 | } |
michael@0 | 1211 | |
michael@0 | 1212 | uint32_t toPrivateUint32() const { |
michael@0 | 1213 | return uint32_t(toInt32()); |
michael@0 | 1214 | } |
michael@0 | 1215 | |
michael@0 | 1216 | /* |
michael@0 | 1217 | * An unmarked value is just a void* cast as a Value. Thus, the Value is |
michael@0 | 1218 | * not safe for GC and must not be marked. This API avoids raw casts |
michael@0 | 1219 | * and the ensuing strict-aliasing warnings. |
michael@0 | 1220 | */ |
michael@0 | 1221 | |
michael@0 | 1222 | void setUnmarkedPtr(void *ptr) { |
michael@0 | 1223 | data.asPtr = ptr; |
michael@0 | 1224 | } |
michael@0 | 1225 | |
michael@0 | 1226 | void *toUnmarkedPtr() const { |
michael@0 | 1227 | return data.asPtr; |
michael@0 | 1228 | } |
michael@0 | 1229 | |
michael@0 | 1230 | const size_t *payloadWord() const { |
michael@0 | 1231 | #if JS_BITS_PER_WORD == 32 |
michael@0 | 1232 | return &data.s.payload.word; |
michael@0 | 1233 | #elif JS_BITS_PER_WORD == 64 |
michael@0 | 1234 | return &data.asWord; |
michael@0 | 1235 | #endif |
michael@0 | 1236 | } |
michael@0 | 1237 | |
michael@0 | 1238 | const uintptr_t *payloadUIntPtr() const { |
michael@0 | 1239 | #if JS_BITS_PER_WORD == 32 |
michael@0 | 1240 | return &data.s.payload.uintptr; |
michael@0 | 1241 | #elif JS_BITS_PER_WORD == 64 |
michael@0 | 1242 | return &data.asUIntPtr; |
michael@0 | 1243 | #endif |
michael@0 | 1244 | } |
michael@0 | 1245 | |
michael@0 | 1246 | #if !defined(_MSC_VER) && !defined(__sparc) |
michael@0 | 1247 | // Value must be POD so that MSVC will pass it by value and not in memory |
michael@0 | 1248 | // (bug 689101); the same is true for SPARC as well (bug 737344). More |
michael@0 | 1249 | // precisely, we don't want Value return values compiled as out params. |
michael@0 | 1250 | private: |
michael@0 | 1251 | #endif |
michael@0 | 1252 | |
michael@0 | 1253 | jsval_layout data; |
michael@0 | 1254 | |
michael@0 | 1255 | private: |
michael@0 | 1256 | #if defined(JS_VALUE_IS_CONSTEXPR) |
michael@0 | 1257 | JS_VALUE_CONSTEXPR Value(jsval_layout layout) : data(layout) {} |
michael@0 | 1258 | #endif |
michael@0 | 1259 | |
michael@0 | 1260 | void staticAssertions() { |
michael@0 | 1261 | JS_STATIC_ASSERT(sizeof(JSValueType) == 1); |
michael@0 | 1262 | JS_STATIC_ASSERT(sizeof(JSValueTag) == 4); |
michael@0 | 1263 | JS_STATIC_ASSERT(sizeof(JSWhyMagic) <= 4); |
michael@0 | 1264 | JS_STATIC_ASSERT(sizeof(Value) == 8); |
michael@0 | 1265 | } |
michael@0 | 1266 | |
michael@0 | 1267 | friend jsval_layout (::JSVAL_TO_IMPL)(Value); |
michael@0 | 1268 | friend Value JS_VALUE_CONSTEXPR (::IMPL_TO_JSVAL)(jsval_layout l); |
michael@0 | 1269 | friend Value JS_VALUE_CONSTEXPR (JS::UndefinedValue)(); |
michael@0 | 1270 | }; |
michael@0 | 1271 | |
michael@0 | 1272 | inline bool |
michael@0 | 1273 | IsPoisonedValue(const Value &v) |
michael@0 | 1274 | { |
michael@0 | 1275 | if (v.isString()) |
michael@0 | 1276 | return IsPoisonedPtr(v.toString()); |
michael@0 | 1277 | if (v.isObject()) |
michael@0 | 1278 | return IsPoisonedPtr(&v.toObject()); |
michael@0 | 1279 | return false; |
michael@0 | 1280 | } |
michael@0 | 1281 | |
michael@0 | 1282 | inline bool |
michael@0 | 1283 | IsOptimizedPlaceholderMagicValue(const Value &v) |
michael@0 | 1284 | { |
michael@0 | 1285 | if (v.isMagic()) { |
michael@0 | 1286 | MOZ_ASSERT(v.whyMagic() == JS_OPTIMIZED_ARGUMENTS || v.whyMagic() == JS_OPTIMIZED_OUT); |
michael@0 | 1287 | return true; |
michael@0 | 1288 | } |
michael@0 | 1289 | return false; |
michael@0 | 1290 | } |
michael@0 | 1291 | |
michael@0 | 1292 | /************************************************************************/ |
michael@0 | 1293 | |
michael@0 | 1294 | static inline Value |
michael@0 | 1295 | NullValue() |
michael@0 | 1296 | { |
michael@0 | 1297 | Value v; |
michael@0 | 1298 | v.setNull(); |
michael@0 | 1299 | return v; |
michael@0 | 1300 | } |
michael@0 | 1301 | |
michael@0 | 1302 | static inline JS_VALUE_CONSTEXPR Value |
michael@0 | 1303 | UndefinedValue() |
michael@0 | 1304 | { |
michael@0 | 1305 | #if defined(JS_VALUE_IS_CONSTEXPR) |
michael@0 | 1306 | return Value(BUILD_JSVAL(JSVAL_TAG_UNDEFINED, 0)); |
michael@0 | 1307 | #else |
michael@0 | 1308 | JS::Value v; |
michael@0 | 1309 | v.setUndefined(); |
michael@0 | 1310 | return v; |
michael@0 | 1311 | #endif |
michael@0 | 1312 | } |
michael@0 | 1313 | |
michael@0 | 1314 | static inline Value |
michael@0 | 1315 | Int32Value(int32_t i32) |
michael@0 | 1316 | { |
michael@0 | 1317 | Value v; |
michael@0 | 1318 | v.setInt32(i32); |
michael@0 | 1319 | return v; |
michael@0 | 1320 | } |
michael@0 | 1321 | |
michael@0 | 1322 | static inline Value |
michael@0 | 1323 | DoubleValue(double dbl) |
michael@0 | 1324 | { |
michael@0 | 1325 | Value v; |
michael@0 | 1326 | v.setDouble(dbl); |
michael@0 | 1327 | return v; |
michael@0 | 1328 | } |
michael@0 | 1329 | |
michael@0 | 1330 | static inline Value |
michael@0 | 1331 | DoubleNaNValue() |
michael@0 | 1332 | { |
michael@0 | 1333 | Value v; |
michael@0 | 1334 | v.setNaN(); |
michael@0 | 1335 | return v; |
michael@0 | 1336 | } |
michael@0 | 1337 | |
michael@0 | 1338 | static inline Value |
michael@0 | 1339 | Float32Value(float f) |
michael@0 | 1340 | { |
michael@0 | 1341 | Value v; |
michael@0 | 1342 | v.setDouble(f); |
michael@0 | 1343 | return v; |
michael@0 | 1344 | } |
michael@0 | 1345 | |
michael@0 | 1346 | static inline Value |
michael@0 | 1347 | StringValue(JSString *str) |
michael@0 | 1348 | { |
michael@0 | 1349 | Value v; |
michael@0 | 1350 | v.setString(str); |
michael@0 | 1351 | return v; |
michael@0 | 1352 | } |
michael@0 | 1353 | |
michael@0 | 1354 | static inline Value |
michael@0 | 1355 | BooleanValue(bool boo) |
michael@0 | 1356 | { |
michael@0 | 1357 | Value v; |
michael@0 | 1358 | v.setBoolean(boo); |
michael@0 | 1359 | return v; |
michael@0 | 1360 | } |
michael@0 | 1361 | |
michael@0 | 1362 | static inline Value |
michael@0 | 1363 | TrueValue() |
michael@0 | 1364 | { |
michael@0 | 1365 | Value v; |
michael@0 | 1366 | v.setBoolean(true); |
michael@0 | 1367 | return v; |
michael@0 | 1368 | } |
michael@0 | 1369 | |
michael@0 | 1370 | static inline Value |
michael@0 | 1371 | FalseValue() |
michael@0 | 1372 | { |
michael@0 | 1373 | Value v; |
michael@0 | 1374 | v.setBoolean(false); |
michael@0 | 1375 | return v; |
michael@0 | 1376 | } |
michael@0 | 1377 | |
michael@0 | 1378 | static inline Value |
michael@0 | 1379 | ObjectValue(JSObject &obj) |
michael@0 | 1380 | { |
michael@0 | 1381 | Value v; |
michael@0 | 1382 | v.setObject(obj); |
michael@0 | 1383 | return v; |
michael@0 | 1384 | } |
michael@0 | 1385 | |
michael@0 | 1386 | static inline Value |
michael@0 | 1387 | ObjectValueCrashOnTouch() |
michael@0 | 1388 | { |
michael@0 | 1389 | Value v; |
michael@0 | 1390 | v.setObject(*reinterpret_cast<JSObject *>(0x42)); |
michael@0 | 1391 | return v; |
michael@0 | 1392 | } |
michael@0 | 1393 | |
michael@0 | 1394 | static inline Value |
michael@0 | 1395 | MagicValue(JSWhyMagic why) |
michael@0 | 1396 | { |
michael@0 | 1397 | Value v; |
michael@0 | 1398 | v.setMagic(why); |
michael@0 | 1399 | return v; |
michael@0 | 1400 | } |
michael@0 | 1401 | |
michael@0 | 1402 | static inline Value |
michael@0 | 1403 | MagicValueUint32(uint32_t payload) |
michael@0 | 1404 | { |
michael@0 | 1405 | Value v; |
michael@0 | 1406 | v.setMagicUint32(payload); |
michael@0 | 1407 | return v; |
michael@0 | 1408 | } |
michael@0 | 1409 | |
michael@0 | 1410 | static inline Value |
michael@0 | 1411 | NumberValue(float f) |
michael@0 | 1412 | { |
michael@0 | 1413 | Value v; |
michael@0 | 1414 | v.setNumber(f); |
michael@0 | 1415 | return v; |
michael@0 | 1416 | } |
michael@0 | 1417 | |
michael@0 | 1418 | static inline Value |
michael@0 | 1419 | NumberValue(double dbl) |
michael@0 | 1420 | { |
michael@0 | 1421 | Value v; |
michael@0 | 1422 | v.setNumber(dbl); |
michael@0 | 1423 | return v; |
michael@0 | 1424 | } |
michael@0 | 1425 | |
michael@0 | 1426 | static inline Value |
michael@0 | 1427 | NumberValue(int8_t i) |
michael@0 | 1428 | { |
michael@0 | 1429 | return Int32Value(i); |
michael@0 | 1430 | } |
michael@0 | 1431 | |
michael@0 | 1432 | static inline Value |
michael@0 | 1433 | NumberValue(uint8_t i) |
michael@0 | 1434 | { |
michael@0 | 1435 | return Int32Value(i); |
michael@0 | 1436 | } |
michael@0 | 1437 | |
michael@0 | 1438 | static inline Value |
michael@0 | 1439 | NumberValue(int16_t i) |
michael@0 | 1440 | { |
michael@0 | 1441 | return Int32Value(i); |
michael@0 | 1442 | } |
michael@0 | 1443 | |
michael@0 | 1444 | static inline Value |
michael@0 | 1445 | NumberValue(uint16_t i) |
michael@0 | 1446 | { |
michael@0 | 1447 | return Int32Value(i); |
michael@0 | 1448 | } |
michael@0 | 1449 | |
michael@0 | 1450 | static inline Value |
michael@0 | 1451 | NumberValue(int32_t i) |
michael@0 | 1452 | { |
michael@0 | 1453 | return Int32Value(i); |
michael@0 | 1454 | } |
michael@0 | 1455 | |
michael@0 | 1456 | static inline Value |
michael@0 | 1457 | NumberValue(uint32_t i) |
michael@0 | 1458 | { |
michael@0 | 1459 | Value v; |
michael@0 | 1460 | v.setNumber(i); |
michael@0 | 1461 | return v; |
michael@0 | 1462 | } |
michael@0 | 1463 | |
michael@0 | 1464 | namespace detail { |
michael@0 | 1465 | |
michael@0 | 1466 | template <bool Signed> |
michael@0 | 1467 | class MakeNumberValue |
michael@0 | 1468 | { |
michael@0 | 1469 | public: |
michael@0 | 1470 | template<typename T> |
michael@0 | 1471 | static inline Value create(const T t) |
michael@0 | 1472 | { |
michael@0 | 1473 | Value v; |
michael@0 | 1474 | if (JSVAL_INT_MIN <= t && t <= JSVAL_INT_MAX) |
michael@0 | 1475 | v.setInt32(int32_t(t)); |
michael@0 | 1476 | else |
michael@0 | 1477 | v.setDouble(double(t)); |
michael@0 | 1478 | return v; |
michael@0 | 1479 | } |
michael@0 | 1480 | }; |
michael@0 | 1481 | |
michael@0 | 1482 | template <> |
michael@0 | 1483 | class MakeNumberValue<false> |
michael@0 | 1484 | { |
michael@0 | 1485 | public: |
michael@0 | 1486 | template<typename T> |
michael@0 | 1487 | static inline Value create(const T t) |
michael@0 | 1488 | { |
michael@0 | 1489 | Value v; |
michael@0 | 1490 | if (t <= JSVAL_INT_MAX) |
michael@0 | 1491 | v.setInt32(int32_t(t)); |
michael@0 | 1492 | else |
michael@0 | 1493 | v.setDouble(double(t)); |
michael@0 | 1494 | return v; |
michael@0 | 1495 | } |
michael@0 | 1496 | }; |
michael@0 | 1497 | |
michael@0 | 1498 | } // namespace detail |
michael@0 | 1499 | |
michael@0 | 1500 | template <typename T> |
michael@0 | 1501 | static inline Value |
michael@0 | 1502 | NumberValue(const T t) |
michael@0 | 1503 | { |
michael@0 | 1504 | MOZ_ASSERT(T(double(t)) == t, "value creation would be lossy"); |
michael@0 | 1505 | return detail::MakeNumberValue<std::numeric_limits<T>::is_signed>::create(t); |
michael@0 | 1506 | } |
michael@0 | 1507 | |
michael@0 | 1508 | static inline Value |
michael@0 | 1509 | ObjectOrNullValue(JSObject *obj) |
michael@0 | 1510 | { |
michael@0 | 1511 | Value v; |
michael@0 | 1512 | v.setObjectOrNull(obj); |
michael@0 | 1513 | return v; |
michael@0 | 1514 | } |
michael@0 | 1515 | |
michael@0 | 1516 | static inline Value |
michael@0 | 1517 | PrivateValue(void *ptr) |
michael@0 | 1518 | { |
michael@0 | 1519 | Value v; |
michael@0 | 1520 | v.setPrivate(ptr); |
michael@0 | 1521 | return v; |
michael@0 | 1522 | } |
michael@0 | 1523 | |
michael@0 | 1524 | static inline Value |
michael@0 | 1525 | PrivateUint32Value(uint32_t ui) |
michael@0 | 1526 | { |
michael@0 | 1527 | Value v; |
michael@0 | 1528 | v.setPrivateUint32(ui); |
michael@0 | 1529 | return v; |
michael@0 | 1530 | } |
michael@0 | 1531 | |
michael@0 | 1532 | inline bool |
michael@0 | 1533 | SameType(const Value &lhs, const Value &rhs) |
michael@0 | 1534 | { |
michael@0 | 1535 | return JSVAL_SAME_TYPE_IMPL(lhs.data, rhs.data); |
michael@0 | 1536 | } |
michael@0 | 1537 | |
michael@0 | 1538 | } // namespace JS |
michael@0 | 1539 | |
michael@0 | 1540 | /************************************************************************/ |
michael@0 | 1541 | |
michael@0 | 1542 | #ifdef JSGC_GENERATIONAL |
michael@0 | 1543 | namespace JS { |
michael@0 | 1544 | JS_PUBLIC_API(void) HeapValuePostBarrier(Value *valuep); |
michael@0 | 1545 | JS_PUBLIC_API(void) HeapValueRelocate(Value *valuep); |
michael@0 | 1546 | } |
michael@0 | 1547 | #endif |
michael@0 | 1548 | |
michael@0 | 1549 | namespace js { |
michael@0 | 1550 | |
michael@0 | 1551 | template <> struct GCMethods<const JS::Value> |
michael@0 | 1552 | { |
michael@0 | 1553 | static JS::Value initial() { return JS::UndefinedValue(); } |
michael@0 | 1554 | static ThingRootKind kind() { return THING_ROOT_VALUE; } |
michael@0 | 1555 | static bool poisoned(const JS::Value &v) { return JS::IsPoisonedValue(v); } |
michael@0 | 1556 | }; |
michael@0 | 1557 | |
michael@0 | 1558 | template <> struct GCMethods<JS::Value> |
michael@0 | 1559 | { |
michael@0 | 1560 | static JS::Value initial() { return JS::UndefinedValue(); } |
michael@0 | 1561 | static ThingRootKind kind() { return THING_ROOT_VALUE; } |
michael@0 | 1562 | static bool poisoned(const JS::Value &v) { return JS::IsPoisonedValue(v); } |
michael@0 | 1563 | static bool needsPostBarrier(const JS::Value &v) { return v.isMarkable(); } |
michael@0 | 1564 | #ifdef JSGC_GENERATIONAL |
michael@0 | 1565 | static void postBarrier(JS::Value *v) { JS::HeapValuePostBarrier(v); } |
michael@0 | 1566 | static void relocate(JS::Value *v) { JS::HeapValueRelocate(v); } |
michael@0 | 1567 | #endif |
michael@0 | 1568 | }; |
michael@0 | 1569 | |
michael@0 | 1570 | template <class Outer> class MutableValueOperations; |
michael@0 | 1571 | |
michael@0 | 1572 | /* |
michael@0 | 1573 | * A class designed for CRTP use in implementing the non-mutating parts of the |
michael@0 | 1574 | * Value interface in Value-like classes. Outer must be a class inheriting |
michael@0 | 1575 | * ValueOperations<Outer> with a visible extract() method returning the |
michael@0 | 1576 | * const Value* abstracted by Outer. |
michael@0 | 1577 | */ |
michael@0 | 1578 | template <class Outer> |
michael@0 | 1579 | class ValueOperations |
michael@0 | 1580 | { |
michael@0 | 1581 | friend class MutableValueOperations<Outer>; |
michael@0 | 1582 | |
michael@0 | 1583 | const JS::Value * value() const { return static_cast<const Outer*>(this)->extract(); } |
michael@0 | 1584 | |
michael@0 | 1585 | public: |
michael@0 | 1586 | bool isUndefined() const { return value()->isUndefined(); } |
michael@0 | 1587 | bool isNull() const { return value()->isNull(); } |
michael@0 | 1588 | bool isBoolean() const { return value()->isBoolean(); } |
michael@0 | 1589 | bool isTrue() const { return value()->isTrue(); } |
michael@0 | 1590 | bool isFalse() const { return value()->isFalse(); } |
michael@0 | 1591 | bool isNumber() const { return value()->isNumber(); } |
michael@0 | 1592 | bool isInt32() const { return value()->isInt32(); } |
michael@0 | 1593 | bool isDouble() const { return value()->isDouble(); } |
michael@0 | 1594 | bool isString() const { return value()->isString(); } |
michael@0 | 1595 | bool isObject() const { return value()->isObject(); } |
michael@0 | 1596 | bool isMagic() const { return value()->isMagic(); } |
michael@0 | 1597 | bool isMagic(JSWhyMagic why) const { return value()->isMagic(why); } |
michael@0 | 1598 | bool isMarkable() const { return value()->isMarkable(); } |
michael@0 | 1599 | bool isPrimitive() const { return value()->isPrimitive(); } |
michael@0 | 1600 | bool isGCThing() const { return value()->isGCThing(); } |
michael@0 | 1601 | |
michael@0 | 1602 | bool isNullOrUndefined() const { return value()->isNullOrUndefined(); } |
michael@0 | 1603 | bool isObjectOrNull() const { return value()->isObjectOrNull(); } |
michael@0 | 1604 | |
michael@0 | 1605 | bool toBoolean() const { return value()->toBoolean(); } |
michael@0 | 1606 | double toNumber() const { return value()->toNumber(); } |
michael@0 | 1607 | int32_t toInt32() const { return value()->toInt32(); } |
michael@0 | 1608 | double toDouble() const { return value()->toDouble(); } |
michael@0 | 1609 | JSString *toString() const { return value()->toString(); } |
michael@0 | 1610 | JSObject &toObject() const { return value()->toObject(); } |
michael@0 | 1611 | JSObject *toObjectOrNull() const { return value()->toObjectOrNull(); } |
michael@0 | 1612 | void *toGCThing() const { return value()->toGCThing(); } |
michael@0 | 1613 | |
michael@0 | 1614 | JSValueType extractNonDoubleType() const { return value()->extractNonDoubleType(); } |
michael@0 | 1615 | uint32_t toPrivateUint32() const { return value()->toPrivateUint32(); } |
michael@0 | 1616 | |
michael@0 | 1617 | JSWhyMagic whyMagic() const { return value()->whyMagic(); } |
michael@0 | 1618 | uint32_t magicUint32() const { return value()->magicUint32(); } |
michael@0 | 1619 | }; |
michael@0 | 1620 | |
michael@0 | 1621 | /* |
michael@0 | 1622 | * A class designed for CRTP use in implementing all the mutating parts of the |
michael@0 | 1623 | * Value interface in Value-like classes. Outer must be a class inheriting |
michael@0 | 1624 | * MutableValueOperations<Outer> with visible extractMutable() and extract() |
michael@0 | 1625 | * methods returning the const Value* and Value* abstracted by Outer. |
michael@0 | 1626 | */ |
michael@0 | 1627 | template <class Outer> |
michael@0 | 1628 | class MutableValueOperations : public ValueOperations<Outer> |
michael@0 | 1629 | { |
michael@0 | 1630 | JS::Value * value() { return static_cast<Outer*>(this)->extractMutable(); } |
michael@0 | 1631 | |
michael@0 | 1632 | public: |
michael@0 | 1633 | void setNull() { value()->setNull(); } |
michael@0 | 1634 | void setUndefined() { value()->setUndefined(); } |
michael@0 | 1635 | void setInt32(int32_t i) { value()->setInt32(i); } |
michael@0 | 1636 | void setDouble(double d) { value()->setDouble(d); } |
michael@0 | 1637 | void setNaN() { setDouble(JS::GenericNaN()); } |
michael@0 | 1638 | void setBoolean(bool b) { value()->setBoolean(b); } |
michael@0 | 1639 | void setMagic(JSWhyMagic why) { value()->setMagic(why); } |
michael@0 | 1640 | bool setNumber(uint32_t ui) { return value()->setNumber(ui); } |
michael@0 | 1641 | bool setNumber(double d) { return value()->setNumber(d); } |
michael@0 | 1642 | void setString(JSString *str) { this->value()->setString(str); } |
michael@0 | 1643 | void setObject(JSObject &obj) { this->value()->setObject(obj); } |
michael@0 | 1644 | void setObjectOrNull(JSObject *arg) { this->value()->setObjectOrNull(arg); } |
michael@0 | 1645 | }; |
michael@0 | 1646 | |
michael@0 | 1647 | /* |
michael@0 | 1648 | * Augment the generic Heap<T> interface when T = Value with |
michael@0 | 1649 | * type-querying, value-extracting, and mutating operations. |
michael@0 | 1650 | */ |
michael@0 | 1651 | template <> |
michael@0 | 1652 | class HeapBase<JS::Value> : public ValueOperations<JS::Heap<JS::Value> > |
michael@0 | 1653 | { |
michael@0 | 1654 | typedef JS::Heap<JS::Value> Outer; |
michael@0 | 1655 | |
michael@0 | 1656 | friend class ValueOperations<Outer>; |
michael@0 | 1657 | |
michael@0 | 1658 | const JS::Value * extract() const { return static_cast<const Outer*>(this)->address(); } |
michael@0 | 1659 | |
michael@0 | 1660 | void setBarriered(const JS::Value &v) { |
michael@0 | 1661 | static_cast<JS::Heap<JS::Value> *>(this)->set(v); |
michael@0 | 1662 | } |
michael@0 | 1663 | |
michael@0 | 1664 | public: |
michael@0 | 1665 | void setNull() { setBarriered(JS::NullValue()); } |
michael@0 | 1666 | void setUndefined() { setBarriered(JS::UndefinedValue()); } |
michael@0 | 1667 | void setInt32(int32_t i) { setBarriered(JS::Int32Value(i)); } |
michael@0 | 1668 | void setDouble(double d) { setBarriered(JS::DoubleValue(d)); } |
michael@0 | 1669 | void setNaN() { setDouble(JS::GenericNaN()); } |
michael@0 | 1670 | void setBoolean(bool b) { setBarriered(JS::BooleanValue(b)); } |
michael@0 | 1671 | void setMagic(JSWhyMagic why) { setBarriered(JS::MagicValue(why)); } |
michael@0 | 1672 | void setString(JSString *str) { setBarriered(JS::StringValue(str)); } |
michael@0 | 1673 | void setObject(JSObject &obj) { setBarriered(JS::ObjectValue(obj)); } |
michael@0 | 1674 | |
michael@0 | 1675 | bool setNumber(uint32_t ui) { |
michael@0 | 1676 | if (ui > JSVAL_INT_MAX) { |
michael@0 | 1677 | setDouble((double)ui); |
michael@0 | 1678 | return false; |
michael@0 | 1679 | } else { |
michael@0 | 1680 | setInt32((int32_t)ui); |
michael@0 | 1681 | return true; |
michael@0 | 1682 | } |
michael@0 | 1683 | } |
michael@0 | 1684 | |
michael@0 | 1685 | bool setNumber(double d) { |
michael@0 | 1686 | int32_t i; |
michael@0 | 1687 | if (mozilla::NumberIsInt32(d, &i)) { |
michael@0 | 1688 | setInt32(i); |
michael@0 | 1689 | return true; |
michael@0 | 1690 | } |
michael@0 | 1691 | |
michael@0 | 1692 | setDouble(d); |
michael@0 | 1693 | return false; |
michael@0 | 1694 | } |
michael@0 | 1695 | |
michael@0 | 1696 | void setObjectOrNull(JSObject *arg) { |
michael@0 | 1697 | if (arg) |
michael@0 | 1698 | setObject(*arg); |
michael@0 | 1699 | else |
michael@0 | 1700 | setNull(); |
michael@0 | 1701 | } |
michael@0 | 1702 | }; |
michael@0 | 1703 | |
michael@0 | 1704 | /* |
michael@0 | 1705 | * Augment the generic Handle<T> interface when T = Value with type-querying |
michael@0 | 1706 | * and value-extracting operations. |
michael@0 | 1707 | */ |
michael@0 | 1708 | template <> |
michael@0 | 1709 | class HandleBase<JS::Value> : public ValueOperations<JS::Handle<JS::Value> > |
michael@0 | 1710 | { |
michael@0 | 1711 | friend class ValueOperations<JS::Handle<JS::Value> >; |
michael@0 | 1712 | const JS::Value * extract() const { |
michael@0 | 1713 | return static_cast<const JS::Handle<JS::Value>*>(this)->address(); |
michael@0 | 1714 | } |
michael@0 | 1715 | }; |
michael@0 | 1716 | |
michael@0 | 1717 | /* |
michael@0 | 1718 | * Augment the generic MutableHandle<T> interface when T = Value with |
michael@0 | 1719 | * type-querying, value-extracting, and mutating operations. |
michael@0 | 1720 | */ |
michael@0 | 1721 | template <> |
michael@0 | 1722 | class MutableHandleBase<JS::Value> : public MutableValueOperations<JS::MutableHandle<JS::Value> > |
michael@0 | 1723 | { |
michael@0 | 1724 | friend class ValueOperations<JS::MutableHandle<JS::Value> >; |
michael@0 | 1725 | const JS::Value * extract() const { |
michael@0 | 1726 | return static_cast<const JS::MutableHandle<JS::Value>*>(this)->address(); |
michael@0 | 1727 | } |
michael@0 | 1728 | |
michael@0 | 1729 | friend class MutableValueOperations<JS::MutableHandle<JS::Value> >; |
michael@0 | 1730 | JS::Value * extractMutable() { |
michael@0 | 1731 | return static_cast<JS::MutableHandle<JS::Value>*>(this)->address(); |
michael@0 | 1732 | } |
michael@0 | 1733 | }; |
michael@0 | 1734 | |
michael@0 | 1735 | /* |
michael@0 | 1736 | * Augment the generic Rooted<T> interface when T = Value with type-querying, |
michael@0 | 1737 | * value-extracting, and mutating operations. |
michael@0 | 1738 | */ |
michael@0 | 1739 | template <> |
michael@0 | 1740 | class RootedBase<JS::Value> : public MutableValueOperations<JS::Rooted<JS::Value> > |
michael@0 | 1741 | { |
michael@0 | 1742 | friend class ValueOperations<JS::Rooted<JS::Value> >; |
michael@0 | 1743 | const JS::Value * extract() const { |
michael@0 | 1744 | return static_cast<const JS::Rooted<JS::Value>*>(this)->address(); |
michael@0 | 1745 | } |
michael@0 | 1746 | |
michael@0 | 1747 | friend class MutableValueOperations<JS::Rooted<JS::Value> >; |
michael@0 | 1748 | JS::Value * extractMutable() { |
michael@0 | 1749 | return static_cast<JS::Rooted<JS::Value>*>(this)->address(); |
michael@0 | 1750 | } |
michael@0 | 1751 | }; |
michael@0 | 1752 | |
michael@0 | 1753 | } // namespace js |
michael@0 | 1754 | |
michael@0 | 1755 | inline jsval_layout |
michael@0 | 1756 | JSVAL_TO_IMPL(JS::Value v) |
michael@0 | 1757 | { |
michael@0 | 1758 | return v.data; |
michael@0 | 1759 | } |
michael@0 | 1760 | |
michael@0 | 1761 | inline JS_VALUE_CONSTEXPR JS::Value |
michael@0 | 1762 | IMPL_TO_JSVAL(jsval_layout l) |
michael@0 | 1763 | { |
michael@0 | 1764 | #if defined(JS_VALUE_IS_CONSTEXPR) |
michael@0 | 1765 | return JS::Value(l); |
michael@0 | 1766 | #else |
michael@0 | 1767 | JS::Value v; |
michael@0 | 1768 | v.data = l; |
michael@0 | 1769 | return v; |
michael@0 | 1770 | #endif |
michael@0 | 1771 | } |
michael@0 | 1772 | |
michael@0 | 1773 | namespace JS { |
michael@0 | 1774 | |
michael@0 | 1775 | #ifndef __GNUC__ |
michael@0 | 1776 | /* |
michael@0 | 1777 | * The default assignment operator for |struct C| has the signature: |
michael@0 | 1778 | * |
michael@0 | 1779 | * C& C::operator=(const C&) |
michael@0 | 1780 | * |
michael@0 | 1781 | * And in particular requires implicit conversion of |this| to type |C| for the |
michael@0 | 1782 | * return value. But |volatile C| cannot thus be converted to |C|, so just |
michael@0 | 1783 | * doing |sink = hold| as in the non-specialized version would fail to compile. |
michael@0 | 1784 | * Do the assignment on asBits instead, since I don't think we want to give |
michael@0 | 1785 | * jsval_layout an assignment operator returning |volatile jsval_layout|. |
michael@0 | 1786 | */ |
michael@0 | 1787 | template<> |
michael@0 | 1788 | inline Anchor<Value>::~Anchor() |
michael@0 | 1789 | { |
michael@0 | 1790 | volatile uint64_t bits; |
michael@0 | 1791 | bits = JSVAL_TO_IMPL(hold).asBits; |
michael@0 | 1792 | } |
michael@0 | 1793 | #endif |
michael@0 | 1794 | |
michael@0 | 1795 | #ifdef JS_DEBUG |
michael@0 | 1796 | namespace detail { |
michael@0 | 1797 | |
michael@0 | 1798 | struct ValueAlignmentTester { char c; JS::Value v; }; |
michael@0 | 1799 | static_assert(sizeof(ValueAlignmentTester) == 16, |
michael@0 | 1800 | "JS::Value must be 16-byte-aligned"); |
michael@0 | 1801 | |
michael@0 | 1802 | struct LayoutAlignmentTester { char c; jsval_layout l; }; |
michael@0 | 1803 | static_assert(sizeof(LayoutAlignmentTester) == 16, |
michael@0 | 1804 | "jsval_layout must be 16-byte-aligned"); |
michael@0 | 1805 | |
michael@0 | 1806 | } // namespace detail |
michael@0 | 1807 | #endif /* JS_DEBUG */ |
michael@0 | 1808 | |
michael@0 | 1809 | } // namespace JS |
michael@0 | 1810 | |
michael@0 | 1811 | /* |
michael@0 | 1812 | * JS::Value and jsval are the same type; jsval is the old name, kept around |
michael@0 | 1813 | * for backwards compatibility along with all the JSVAL_* operations below. |
michael@0 | 1814 | * jsval_layout is an implementation detail and should not be used externally. |
michael@0 | 1815 | */ |
michael@0 | 1816 | typedef JS::Value jsval; |
michael@0 | 1817 | |
michael@0 | 1818 | static_assert(sizeof(jsval_layout) == sizeof(JS::Value), |
michael@0 | 1819 | "jsval_layout and JS::Value must have identical layouts"); |
michael@0 | 1820 | |
michael@0 | 1821 | /************************************************************************/ |
michael@0 | 1822 | |
michael@0 | 1823 | static inline bool |
michael@0 | 1824 | JSVAL_IS_NULL(jsval v) |
michael@0 | 1825 | { |
michael@0 | 1826 | return JSVAL_IS_NULL_IMPL(JSVAL_TO_IMPL(v)); |
michael@0 | 1827 | } |
michael@0 | 1828 | |
michael@0 | 1829 | static inline bool |
michael@0 | 1830 | JSVAL_IS_VOID(jsval v) |
michael@0 | 1831 | { |
michael@0 | 1832 | return JSVAL_IS_UNDEFINED_IMPL(JSVAL_TO_IMPL(v)); |
michael@0 | 1833 | } |
michael@0 | 1834 | |
michael@0 | 1835 | static inline bool |
michael@0 | 1836 | JSVAL_IS_INT(jsval v) |
michael@0 | 1837 | { |
michael@0 | 1838 | return JSVAL_IS_INT32_IMPL(JSVAL_TO_IMPL(v)); |
michael@0 | 1839 | } |
michael@0 | 1840 | |
michael@0 | 1841 | static inline int32_t |
michael@0 | 1842 | JSVAL_TO_INT(jsval v) |
michael@0 | 1843 | { |
michael@0 | 1844 | MOZ_ASSERT(JSVAL_IS_INT(v)); |
michael@0 | 1845 | return JSVAL_TO_INT32_IMPL(JSVAL_TO_IMPL(v)); |
michael@0 | 1846 | } |
michael@0 | 1847 | |
michael@0 | 1848 | static inline JS_VALUE_CONSTEXPR jsval |
michael@0 | 1849 | INT_TO_JSVAL(int32_t i) |
michael@0 | 1850 | { |
michael@0 | 1851 | return IMPL_TO_JSVAL(INT32_TO_JSVAL_IMPL(i)); |
michael@0 | 1852 | } |
michael@0 | 1853 | |
michael@0 | 1854 | static inline bool |
michael@0 | 1855 | JSVAL_IS_DOUBLE(jsval v) |
michael@0 | 1856 | { |
michael@0 | 1857 | return JSVAL_IS_DOUBLE_IMPL(JSVAL_TO_IMPL(v)); |
michael@0 | 1858 | } |
michael@0 | 1859 | |
michael@0 | 1860 | static inline double |
michael@0 | 1861 | JSVAL_TO_DOUBLE(jsval v) |
michael@0 | 1862 | { |
michael@0 | 1863 | jsval_layout l; |
michael@0 | 1864 | MOZ_ASSERT(JSVAL_IS_DOUBLE(v)); |
michael@0 | 1865 | l = JSVAL_TO_IMPL(v); |
michael@0 | 1866 | return l.asDouble; |
michael@0 | 1867 | } |
michael@0 | 1868 | |
michael@0 | 1869 | static inline JS_VALUE_CONSTEXPR jsval |
michael@0 | 1870 | DOUBLE_TO_JSVAL(double d) |
michael@0 | 1871 | { |
michael@0 | 1872 | /* |
michael@0 | 1873 | * This is a manually inlined version of: |
michael@0 | 1874 | * d = JS_CANONICALIZE_NAN(d); |
michael@0 | 1875 | * return IMPL_TO_JSVAL(DOUBLE_TO_JSVAL_IMPL(d)); |
michael@0 | 1876 | * because GCC from XCode 3.1.4 miscompiles the above code. |
michael@0 | 1877 | */ |
michael@0 | 1878 | #if defined(JS_VALUE_IS_CONSTEXPR) |
michael@0 | 1879 | return IMPL_TO_JSVAL(MOZ_UNLIKELY(d != d) |
michael@0 | 1880 | ? (jsval_layout) { .asBits = 0x7FF8000000000000LL } |
michael@0 | 1881 | : (jsval_layout) { .asDouble = d }); |
michael@0 | 1882 | #else |
michael@0 | 1883 | jsval_layout l; |
michael@0 | 1884 | if (MOZ_UNLIKELY(d != d)) |
michael@0 | 1885 | l.asBits = 0x7FF8000000000000LL; |
michael@0 | 1886 | else |
michael@0 | 1887 | l.asDouble = d; |
michael@0 | 1888 | return IMPL_TO_JSVAL(l); |
michael@0 | 1889 | #endif |
michael@0 | 1890 | } |
michael@0 | 1891 | |
michael@0 | 1892 | static inline JS_VALUE_CONSTEXPR jsval |
michael@0 | 1893 | UINT_TO_JSVAL(uint32_t i) |
michael@0 | 1894 | { |
michael@0 | 1895 | return (i <= JSVAL_INT_MAX |
michael@0 | 1896 | ? INT_TO_JSVAL((int32_t)i) |
michael@0 | 1897 | : DOUBLE_TO_JSVAL((double)i)); |
michael@0 | 1898 | } |
michael@0 | 1899 | |
michael@0 | 1900 | static inline bool |
michael@0 | 1901 | JSVAL_IS_NUMBER(jsval v) |
michael@0 | 1902 | { |
michael@0 | 1903 | return JSVAL_IS_NUMBER_IMPL(JSVAL_TO_IMPL(v)); |
michael@0 | 1904 | } |
michael@0 | 1905 | |
michael@0 | 1906 | static inline bool |
michael@0 | 1907 | JSVAL_IS_STRING(jsval v) |
michael@0 | 1908 | { |
michael@0 | 1909 | return JSVAL_IS_STRING_IMPL(JSVAL_TO_IMPL(v)); |
michael@0 | 1910 | } |
michael@0 | 1911 | |
michael@0 | 1912 | static inline JSString * |
michael@0 | 1913 | JSVAL_TO_STRING(jsval v) |
michael@0 | 1914 | { |
michael@0 | 1915 | MOZ_ASSERT(JSVAL_IS_STRING(v)); |
michael@0 | 1916 | return JSVAL_TO_STRING_IMPL(JSVAL_TO_IMPL(v)); |
michael@0 | 1917 | } |
michael@0 | 1918 | |
michael@0 | 1919 | static inline jsval |
michael@0 | 1920 | STRING_TO_JSVAL(JSString *str) |
michael@0 | 1921 | { |
michael@0 | 1922 | return IMPL_TO_JSVAL(STRING_TO_JSVAL_IMPL(str)); |
michael@0 | 1923 | } |
michael@0 | 1924 | |
michael@0 | 1925 | static inline JSObject * |
michael@0 | 1926 | JSVAL_TO_OBJECT(jsval v) |
michael@0 | 1927 | { |
michael@0 | 1928 | MOZ_ASSERT(JSVAL_IS_OBJECT_OR_NULL_IMPL(JSVAL_TO_IMPL(v))); |
michael@0 | 1929 | return JSVAL_TO_OBJECT_IMPL(JSVAL_TO_IMPL(v)); |
michael@0 | 1930 | } |
michael@0 | 1931 | |
michael@0 | 1932 | static inline jsval |
michael@0 | 1933 | OBJECT_TO_JSVAL(JSObject *obj) |
michael@0 | 1934 | { |
michael@0 | 1935 | if (obj) |
michael@0 | 1936 | return IMPL_TO_JSVAL(OBJECT_TO_JSVAL_IMPL(obj)); |
michael@0 | 1937 | return IMPL_TO_JSVAL(BUILD_JSVAL(JSVAL_TAG_NULL, 0)); |
michael@0 | 1938 | } |
michael@0 | 1939 | |
michael@0 | 1940 | static inline bool |
michael@0 | 1941 | JSVAL_IS_BOOLEAN(jsval v) |
michael@0 | 1942 | { |
michael@0 | 1943 | return JSVAL_IS_BOOLEAN_IMPL(JSVAL_TO_IMPL(v)); |
michael@0 | 1944 | } |
michael@0 | 1945 | |
michael@0 | 1946 | static inline bool |
michael@0 | 1947 | JSVAL_TO_BOOLEAN(jsval v) |
michael@0 | 1948 | { |
michael@0 | 1949 | MOZ_ASSERT(JSVAL_IS_BOOLEAN(v)); |
michael@0 | 1950 | return JSVAL_TO_BOOLEAN_IMPL(JSVAL_TO_IMPL(v)); |
michael@0 | 1951 | } |
michael@0 | 1952 | |
michael@0 | 1953 | static inline jsval |
michael@0 | 1954 | BOOLEAN_TO_JSVAL(bool b) |
michael@0 | 1955 | { |
michael@0 | 1956 | return IMPL_TO_JSVAL(BOOLEAN_TO_JSVAL_IMPL(b)); |
michael@0 | 1957 | } |
michael@0 | 1958 | |
michael@0 | 1959 | static inline bool |
michael@0 | 1960 | JSVAL_IS_PRIMITIVE(jsval v) |
michael@0 | 1961 | { |
michael@0 | 1962 | return JSVAL_IS_PRIMITIVE_IMPL(JSVAL_TO_IMPL(v)); |
michael@0 | 1963 | } |
michael@0 | 1964 | |
michael@0 | 1965 | static inline bool |
michael@0 | 1966 | JSVAL_IS_GCTHING(jsval v) |
michael@0 | 1967 | { |
michael@0 | 1968 | return JSVAL_IS_GCTHING_IMPL(JSVAL_TO_IMPL(v)); |
michael@0 | 1969 | } |
michael@0 | 1970 | |
michael@0 | 1971 | static inline void * |
michael@0 | 1972 | JSVAL_TO_GCTHING(jsval v) |
michael@0 | 1973 | { |
michael@0 | 1974 | MOZ_ASSERT(JSVAL_IS_GCTHING(v)); |
michael@0 | 1975 | return JSVAL_TO_GCTHING_IMPL(JSVAL_TO_IMPL(v)); |
michael@0 | 1976 | } |
michael@0 | 1977 | |
michael@0 | 1978 | /* To be GC-safe, privates are tagged as doubles. */ |
michael@0 | 1979 | |
michael@0 | 1980 | static inline jsval |
michael@0 | 1981 | PRIVATE_TO_JSVAL(void *ptr) |
michael@0 | 1982 | { |
michael@0 | 1983 | return IMPL_TO_JSVAL(PRIVATE_PTR_TO_JSVAL_IMPL(ptr)); |
michael@0 | 1984 | } |
michael@0 | 1985 | |
michael@0 | 1986 | static inline void * |
michael@0 | 1987 | JSVAL_TO_PRIVATE(jsval v) |
michael@0 | 1988 | { |
michael@0 | 1989 | MOZ_ASSERT(JSVAL_IS_DOUBLE(v)); |
michael@0 | 1990 | return JSVAL_TO_PRIVATE_PTR_IMPL(JSVAL_TO_IMPL(v)); |
michael@0 | 1991 | } |
michael@0 | 1992 | |
michael@0 | 1993 | // JS constants. For efficiency, prefer predicates (e.g. v.isNull()) and |
michael@0 | 1994 | // constructing values from scratch (e.g. Int32Value(0)). These constants are |
michael@0 | 1995 | // stored in memory and initialized at startup, so testing against them and |
michael@0 | 1996 | // using them requires memory loads and will be correspondingly slow. |
michael@0 | 1997 | extern JS_PUBLIC_DATA(const jsval) JSVAL_NULL; |
michael@0 | 1998 | extern JS_PUBLIC_DATA(const jsval) JSVAL_ZERO; |
michael@0 | 1999 | extern JS_PUBLIC_DATA(const jsval) JSVAL_ONE; |
michael@0 | 2000 | extern JS_PUBLIC_DATA(const jsval) JSVAL_FALSE; |
michael@0 | 2001 | extern JS_PUBLIC_DATA(const jsval) JSVAL_TRUE; |
michael@0 | 2002 | extern JS_PUBLIC_DATA(const jsval) JSVAL_VOID; |
michael@0 | 2003 | |
michael@0 | 2004 | namespace JS { |
michael@0 | 2005 | |
michael@0 | 2006 | extern JS_PUBLIC_DATA(const HandleValue) NullHandleValue; |
michael@0 | 2007 | extern JS_PUBLIC_DATA(const HandleValue) UndefinedHandleValue; |
michael@0 | 2008 | |
michael@0 | 2009 | } |
michael@0 | 2010 | |
michael@0 | 2011 | #undef JS_VALUE_IS_CONSTEXPR |
michael@0 | 2012 | #undef JS_RETURN_LAYOUT_FROM_BITS |
michael@0 | 2013 | |
michael@0 | 2014 | #endif /* js_Value_h */ |