js/public/Value.h

Fri, 16 Jan 2015 18:13:44 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Fri, 16 Jan 2015 18:13:44 +0100
branch
TOR_BUG_9701
changeset 14
925c144e1f1f
permissions
-rw-r--r--

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 */

mercurial