1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2 : * vim: set ts=4 sw=4 et tw=99 ft=cpp:
3 : *
4 : * ***** BEGIN LICENSE BLOCK *****
5 : * Version: MPL 1.1/GPL 2.0/LGPL 2.1
6 : *
7 : * The contents of this file are subject to the Mozilla Public License Version
8 : * 1.1 (the "License"); you may not use this file except in compliance with
9 : * the License. You may obtain a copy of the License at
10 : * http://www.mozilla.org/MPL/
11 : *
12 : * Software distributed under the License is distributed on an "AS IS" basis,
13 : * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
14 : * for the specific language governing rights and limitations under the
15 : * License.
16 : *
17 : * The Original Code is Mozilla SpiderMonkey JavaScript 1.9 code, released
18 : * June 30, 2010
19 : *
20 : * The Initial Developer of the Original Code is
21 : * the Mozilla Corporation.
22 : *
23 : * Contributor(s):
24 : * Luke Wagner <lw@mozilla.com>
25 : *
26 : * Alternatively, the contents of this file may be used under the terms of
27 : * either of the GNU General Public License Version 2 or later (the "GPL"),
28 : * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
29 : * in which case the provisions of the GPL or the LGPL are applicable instead
30 : * of those above. If you wish to allow use of your version of this file only
31 : * under the terms of either the GPL or the LGPL, and not to allow others to
32 : * use your version of this file under the terms of the MPL, indicate your
33 : * decision by deleting the provisions above and replace them with the notice
34 : * and other provisions required by the GPL or the LGPL. If you do not delete
35 : * the provisions above, a recipient may use your version of this file under
36 : * the terms of any one of the MPL, the GPL or the LGPL.
37 : *
38 : * ***** END LICENSE BLOCK ***** */
39 :
40 : #ifndef jsvalimpl_h__
41 : #define jsvalimpl_h__
42 : /*
43 : * Implementation details for js::Value in jsapi.h.
44 : */
45 : #include "js/Utility.h"
46 :
47 : JS_BEGIN_EXTERN_C
48 :
49 : /******************************************************************************/
50 :
51 : /* To avoid a circular dependency, pull in the necessary pieces of jsnum.h. */
52 :
53 : #define JSDOUBLE_SIGNBIT (((uint64_t) 1) << 63)
54 : #define JSDOUBLE_EXPMASK (((uint64_t) 0x7ff) << 52)
55 : #define JSDOUBLE_MANTMASK ((((uint64_t) 1) << 52) - 1)
56 : #define JSDOUBLE_HI32_SIGNBIT 0x80000000
57 :
58 : static JS_ALWAYS_INLINE JSBool
59 65960491 : JSDOUBLE_IS_NEGZERO(double d)
60 : {
61 : union {
62 : struct {
63 : #if defined(IS_LITTLE_ENDIAN) && !defined(FPU_IS_ARM_FPA)
64 : uint32_t lo, hi;
65 : #else
66 : uint32_t hi, lo;
67 : #endif
68 : } s;
69 : double d;
70 : } x;
71 65960491 : if (d != 0)
72 63557900 : return JS_FALSE;
73 2402591 : x.d = d;
74 2402591 : return (x.s.hi & JSDOUBLE_HI32_SIGNBIT) != 0;
75 : }
76 :
77 : static JS_ALWAYS_INLINE JSBool
78 65877820 : JSDOUBLE_IS_INT32(double d, int32_t* pi)
79 : {
80 65877820 : if (JSDOUBLE_IS_NEGZERO(d))
81 233602 : return JS_FALSE;
82 65644218 : return d == (*pi = (int32_t)d);
83 : }
84 :
85 : /******************************************************************************/
86 :
87 : /*
88 : * Try to get jsvals 64-bit aligned. We could almost assert that all values are
89 : * aligned, but MSVC and GCC occasionally break alignment.
90 : */
91 : #if defined(__GNUC__) || defined(__xlc__) || defined(__xlC__)
92 : # define JSVAL_ALIGNMENT __attribute__((aligned (8)))
93 : #elif defined(_MSC_VER)
94 : /*
95 : * Structs can be aligned with MSVC, but not if they are used as parameters,
96 : * so we just don't try to align.
97 : */
98 : # define JSVAL_ALIGNMENT
99 : #elif defined(__SUNPRO_C) || defined(__SUNPRO_CC)
100 : # define JSVAL_ALIGNMENT
101 : #elif defined(__HP_cc) || defined(__HP_aCC)
102 : # define JSVAL_ALIGNMENT
103 : #endif
104 :
105 : #if JS_BITS_PER_WORD == 64
106 : # define JSVAL_TAG_SHIFT 47
107 : #endif
108 :
109 : /*
110 : * We try to use enums so that printing a jsval_layout in the debugger shows
111 : * nice symbolic type tags, however we can only do this when we can force the
112 : * underlying type of the enum to be the desired size.
113 : */
114 : #if defined(__cplusplus) && !defined(__SUNPRO_CC) && !defined(__xlC__)
115 :
116 : #if defined(_MSC_VER)
117 : # define JS_ENUM_HEADER(id, type) enum id : type
118 : # define JS_ENUM_FOOTER(id)
119 : #else
120 : # define JS_ENUM_HEADER(id, type) enum id
121 : # define JS_ENUM_FOOTER(id) __attribute__((packed))
122 : #endif
123 :
124 : /* Remember to propagate changes to the C defines below. */
125 : JS_ENUM_HEADER(JSValueType, uint8_t)
126 : {
127 : JSVAL_TYPE_DOUBLE = 0x00,
128 : JSVAL_TYPE_INT32 = 0x01,
129 : JSVAL_TYPE_UNDEFINED = 0x02,
130 : JSVAL_TYPE_BOOLEAN = 0x03,
131 : JSVAL_TYPE_MAGIC = 0x04,
132 : JSVAL_TYPE_STRING = 0x05,
133 : JSVAL_TYPE_NULL = 0x06,
134 : JSVAL_TYPE_OBJECT = 0x07,
135 :
136 : /* These never appear in a jsval; they are only provided as an out-of-band value. */
137 : JSVAL_TYPE_UNKNOWN = 0x20,
138 : JSVAL_TYPE_MISSING = 0x21
139 : } JS_ENUM_FOOTER(JSValueType);
140 :
141 : JS_STATIC_ASSERT(sizeof(JSValueType) == 1);
142 :
143 : #if JS_BITS_PER_WORD == 32
144 :
145 : /* Remember to propagate changes to the C defines below. */
146 : JS_ENUM_HEADER(JSValueTag, uint32_t)
147 : {
148 : JSVAL_TAG_CLEAR = 0xFFFFFF80,
149 : JSVAL_TAG_INT32 = JSVAL_TAG_CLEAR | JSVAL_TYPE_INT32,
150 : JSVAL_TAG_UNDEFINED = JSVAL_TAG_CLEAR | JSVAL_TYPE_UNDEFINED,
151 : JSVAL_TAG_STRING = JSVAL_TAG_CLEAR | JSVAL_TYPE_STRING,
152 : JSVAL_TAG_BOOLEAN = JSVAL_TAG_CLEAR | JSVAL_TYPE_BOOLEAN,
153 : JSVAL_TAG_MAGIC = JSVAL_TAG_CLEAR | JSVAL_TYPE_MAGIC,
154 : JSVAL_TAG_NULL = JSVAL_TAG_CLEAR | JSVAL_TYPE_NULL,
155 : JSVAL_TAG_OBJECT = JSVAL_TAG_CLEAR | JSVAL_TYPE_OBJECT
156 : } JS_ENUM_FOOTER(JSValueTag);
157 :
158 : JS_STATIC_ASSERT(sizeof(JSValueTag) == 4);
159 :
160 : #elif JS_BITS_PER_WORD == 64
161 :
162 : /* Remember to propagate changes to the C defines below. */
163 : JS_ENUM_HEADER(JSValueTag, uint32_t)
164 : {
165 : JSVAL_TAG_MAX_DOUBLE = 0x1FFF0,
166 : JSVAL_TAG_INT32 = JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_INT32,
167 : JSVAL_TAG_UNDEFINED = JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_UNDEFINED,
168 : JSVAL_TAG_STRING = JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_STRING,
169 : JSVAL_TAG_BOOLEAN = JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_BOOLEAN,
170 : JSVAL_TAG_MAGIC = JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_MAGIC,
171 : JSVAL_TAG_NULL = JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_NULL,
172 : JSVAL_TAG_OBJECT = JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_OBJECT
173 : } JS_ENUM_FOOTER(JSValueTag);
174 :
175 : JS_STATIC_ASSERT(sizeof(JSValueTag) == sizeof(uint32_t));
176 :
177 : JS_ENUM_HEADER(JSValueShiftedTag, uint64_t)
178 : {
179 : JSVAL_SHIFTED_TAG_MAX_DOUBLE = ((((uint64_t)JSVAL_TAG_MAX_DOUBLE) << JSVAL_TAG_SHIFT) | 0xFFFFFFFF),
180 : JSVAL_SHIFTED_TAG_INT32 = (((uint64_t)JSVAL_TAG_INT32) << JSVAL_TAG_SHIFT),
181 : JSVAL_SHIFTED_TAG_UNDEFINED = (((uint64_t)JSVAL_TAG_UNDEFINED) << JSVAL_TAG_SHIFT),
182 : JSVAL_SHIFTED_TAG_STRING = (((uint64_t)JSVAL_TAG_STRING) << JSVAL_TAG_SHIFT),
183 : JSVAL_SHIFTED_TAG_BOOLEAN = (((uint64_t)JSVAL_TAG_BOOLEAN) << JSVAL_TAG_SHIFT),
184 : JSVAL_SHIFTED_TAG_MAGIC = (((uint64_t)JSVAL_TAG_MAGIC) << JSVAL_TAG_SHIFT),
185 : JSVAL_SHIFTED_TAG_NULL = (((uint64_t)JSVAL_TAG_NULL) << JSVAL_TAG_SHIFT),
186 : JSVAL_SHIFTED_TAG_OBJECT = (((uint64_t)JSVAL_TAG_OBJECT) << JSVAL_TAG_SHIFT)
187 : } JS_ENUM_FOOTER(JSValueShiftedTag);
188 :
189 : JS_STATIC_ASSERT(sizeof(JSValueShiftedTag) == sizeof(uint64_t));
190 :
191 : #endif
192 :
193 : #else /* defined(__cplusplus) */
194 :
195 : typedef uint8_t JSValueType;
196 : #define JSVAL_TYPE_DOUBLE ((uint8_t)0x00)
197 : #define JSVAL_TYPE_INT32 ((uint8_t)0x01)
198 : #define JSVAL_TYPE_UNDEFINED ((uint8_t)0x02)
199 : #define JSVAL_TYPE_BOOLEAN ((uint8_t)0x03)
200 : #define JSVAL_TYPE_MAGIC ((uint8_t)0x04)
201 : #define JSVAL_TYPE_STRING ((uint8_t)0x05)
202 : #define JSVAL_TYPE_NULL ((uint8_t)0x06)
203 : #define JSVAL_TYPE_OBJECT ((uint8_t)0x07)
204 : #define JSVAL_TYPE_UNKNOWN ((uint8_t)0x20)
205 :
206 : #if JS_BITS_PER_WORD == 32
207 :
208 : typedef uint32_t JSValueTag;
209 : #define JSVAL_TAG_CLEAR ((uint32_t)(0xFFFFFF80))
210 : #define JSVAL_TAG_INT32 ((uint32_t)(JSVAL_TAG_CLEAR | JSVAL_TYPE_INT32))
211 : #define JSVAL_TAG_UNDEFINED ((uint32_t)(JSVAL_TAG_CLEAR | JSVAL_TYPE_UNDEFINED))
212 : #define JSVAL_TAG_STRING ((uint32_t)(JSVAL_TAG_CLEAR | JSVAL_TYPE_STRING))
213 : #define JSVAL_TAG_BOOLEAN ((uint32_t)(JSVAL_TAG_CLEAR | JSVAL_TYPE_BOOLEAN))
214 : #define JSVAL_TAG_MAGIC ((uint32_t)(JSVAL_TAG_CLEAR | JSVAL_TYPE_MAGIC))
215 : #define JSVAL_TAG_NULL ((uint32_t)(JSVAL_TAG_CLEAR | JSVAL_TYPE_NULL))
216 : #define JSVAL_TAG_OBJECT ((uint32_t)(JSVAL_TAG_CLEAR | JSVAL_TYPE_OBJECT))
217 :
218 : #elif JS_BITS_PER_WORD == 64
219 :
220 : typedef uint32_t JSValueTag;
221 : #define JSVAL_TAG_MAX_DOUBLE ((uint32_t)(0x1FFF0))
222 : #define JSVAL_TAG_INT32 (uint32_t)(JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_INT32)
223 : #define JSVAL_TAG_UNDEFINED (uint32_t)(JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_UNDEFINED)
224 : #define JSVAL_TAG_STRING (uint32_t)(JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_STRING)
225 : #define JSVAL_TAG_BOOLEAN (uint32_t)(JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_BOOLEAN)
226 : #define JSVAL_TAG_MAGIC (uint32_t)(JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_MAGIC)
227 : #define JSVAL_TAG_NULL (uint32_t)(JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_NULL)
228 : #define JSVAL_TAG_OBJECT (uint32_t)(JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_OBJECT)
229 :
230 : typedef uint64_t JSValueShiftedTag;
231 : #define JSVAL_SHIFTED_TAG_MAX_DOUBLE ((((uint64_t)JSVAL_TAG_MAX_DOUBLE) << JSVAL_TAG_SHIFT) | 0xFFFFFFFF)
232 : #define JSVAL_SHIFTED_TAG_INT32 (((uint64_t)JSVAL_TAG_INT32) << JSVAL_TAG_SHIFT)
233 : #define JSVAL_SHIFTED_TAG_UNDEFINED (((uint64_t)JSVAL_TAG_UNDEFINED) << JSVAL_TAG_SHIFT)
234 : #define JSVAL_SHIFTED_TAG_STRING (((uint64_t)JSVAL_TAG_STRING) << JSVAL_TAG_SHIFT)
235 : #define JSVAL_SHIFTED_TAG_BOOLEAN (((uint64_t)JSVAL_TAG_BOOLEAN) << JSVAL_TAG_SHIFT)
236 : #define JSVAL_SHIFTED_TAG_MAGIC (((uint64_t)JSVAL_TAG_MAGIC) << JSVAL_TAG_SHIFT)
237 : #define JSVAL_SHIFTED_TAG_NULL (((uint64_t)JSVAL_TAG_NULL) << JSVAL_TAG_SHIFT)
238 : #define JSVAL_SHIFTED_TAG_OBJECT (((uint64_t)JSVAL_TAG_OBJECT) << JSVAL_TAG_SHIFT)
239 :
240 : #endif /* JS_BITS_PER_WORD */
241 : #endif /* defined(__cplusplus) && !defined(__SUNPRO_CC) */
242 :
243 : #define JSVAL_LOWER_INCL_TYPE_OF_OBJ_OR_NULL_SET JSVAL_TYPE_NULL
244 : #define JSVAL_UPPER_EXCL_TYPE_OF_PRIMITIVE_SET JSVAL_TYPE_OBJECT
245 : #define JSVAL_UPPER_INCL_TYPE_OF_NUMBER_SET JSVAL_TYPE_INT32
246 : #define JSVAL_LOWER_INCL_TYPE_OF_PTR_PAYLOAD_SET JSVAL_TYPE_MAGIC
247 :
248 : #if JS_BITS_PER_WORD == 32
249 :
250 : #define JSVAL_TYPE_TO_TAG(type) ((JSValueTag)(JSVAL_TAG_CLEAR | (type)))
251 :
252 : #define JSVAL_LOWER_INCL_TAG_OF_OBJ_OR_NULL_SET JSVAL_TAG_NULL
253 : #define JSVAL_UPPER_EXCL_TAG_OF_PRIMITIVE_SET JSVAL_TAG_OBJECT
254 : #define JSVAL_UPPER_INCL_TAG_OF_NUMBER_SET JSVAL_TAG_INT32
255 : #define JSVAL_LOWER_INCL_TAG_OF_GCTHING_SET JSVAL_TAG_STRING
256 :
257 : #elif JS_BITS_PER_WORD == 64
258 :
259 : #define JSVAL_PAYLOAD_MASK 0x00007FFFFFFFFFFFLL
260 : #define JSVAL_TAG_MASK 0xFFFF800000000000LL
261 : #define JSVAL_TYPE_TO_TAG(type) ((JSValueTag)(JSVAL_TAG_MAX_DOUBLE | (type)))
262 : #define JSVAL_TYPE_TO_SHIFTED_TAG(type) (((uint64_t)JSVAL_TYPE_TO_TAG(type)) << JSVAL_TAG_SHIFT)
263 :
264 : #define JSVAL_LOWER_INCL_SHIFTED_TAG_OF_OBJ_OR_NULL_SET JSVAL_SHIFTED_TAG_NULL
265 : #define JSVAL_UPPER_EXCL_SHIFTED_TAG_OF_PRIMITIVE_SET JSVAL_SHIFTED_TAG_OBJECT
266 : #define JSVAL_UPPER_EXCL_SHIFTED_TAG_OF_NUMBER_SET JSVAL_SHIFTED_TAG_UNDEFINED
267 : #define JSVAL_LOWER_INCL_SHIFTED_TAG_OF_GCTHING_SET JSVAL_SHIFTED_TAG_STRING
268 :
269 : #endif /* JS_BITS_PER_WORD */
270 :
271 : typedef enum JSWhyMagic
272 : {
273 : JS_ARRAY_HOLE, /* a hole in a dense array */
274 : JS_NATIVE_ENUMERATE, /* indicates that a custom enumerate hook forwarded
275 : * to JS_EnumerateState, which really means the object can be
276 : * enumerated like a native object. */
277 : JS_NO_ITER_VALUE, /* there is not a pending iterator value */
278 : JS_GENERATOR_CLOSING, /* exception value thrown when closing a generator */
279 : JS_NO_CONSTANT, /* compiler sentinel value */
280 : JS_THIS_POISON, /* used in debug builds to catch tracing errors */
281 : JS_ARG_POISON, /* used in debug builds to catch tracing errors */
282 : JS_SERIALIZE_NO_NODE, /* an empty subnode in the AST serializer */
283 : JS_LAZY_ARGUMENTS, /* lazy arguments value on the stack */
284 : JS_UNASSIGNED_ARGUMENTS, /* the initial value of callobj.arguments */
285 : JS_OPTIMIZED_ARGUMENTS, /* optimized-away 'arguments' value */
286 : JS_IS_CONSTRUCTING, /* magic value passed to natives to indicate construction */
287 : JS_OVERWRITTEN_CALLEE, /* arguments.callee has been overwritten */
288 : JS_GENERIC_MAGIC /* for local use */
289 : } JSWhyMagic;
290 :
291 : #if defined(IS_LITTLE_ENDIAN)
292 : # if JS_BITS_PER_WORD == 32
293 : typedef union jsval_layout
294 : {
295 : uint64_t asBits;
296 : struct {
297 : union {
298 : int32_t i32;
299 : uint32_t u32;
300 : JSBool boo;
301 : JSString *str;
302 : JSObject *obj;
303 : void *ptr;
304 : JSWhyMagic why;
305 : size_t word;
306 : } payload;
307 : JSValueTag tag;
308 : } s;
309 : double asDouble;
310 : void *asPtr;
311 : } JSVAL_ALIGNMENT jsval_layout;
312 : # elif JS_BITS_PER_WORD == 64
313 : typedef union jsval_layout
314 : {
315 : uint64_t asBits;
316 : #if (!defined(_WIN64) && defined(__cplusplus))
317 : /* MSVC does not pack these correctly :-( */
318 : struct {
319 : uint64_t payload47 : 47;
320 : JSValueTag tag : 17;
321 : } debugView;
322 : #endif
323 : struct {
324 : union {
325 : int32_t i32;
326 : uint32_t u32;
327 : JSWhyMagic why;
328 : } payload;
329 : } s;
330 : double asDouble;
331 : void *asPtr;
332 : size_t asWord;
333 : } JSVAL_ALIGNMENT jsval_layout;
334 : # endif /* JS_BITS_PER_WORD */
335 : #else /* defined(IS_LITTLE_ENDIAN) */
336 : # if JS_BITS_PER_WORD == 32
337 : typedef union jsval_layout
338 : {
339 : uint64_t asBits;
340 : struct {
341 : JSValueTag tag;
342 : union {
343 : int32_t i32;
344 : uint32_t u32;
345 : JSBool boo;
346 : JSString *str;
347 : JSObject *obj;
348 : void *ptr;
349 : JSWhyMagic why;
350 : size_t word;
351 : } payload;
352 : } s;
353 : double asDouble;
354 : void *asPtr;
355 : } JSVAL_ALIGNMENT jsval_layout;
356 : # elif JS_BITS_PER_WORD == 64
357 : typedef union jsval_layout
358 : {
359 : uint64_t asBits;
360 : struct {
361 : JSValueTag tag : 17;
362 : uint64_t payload47 : 47;
363 : } debugView;
364 : struct {
365 : uint32_t padding;
366 : union {
367 : int32_t i32;
368 : uint32_t u32;
369 : JSWhyMagic why;
370 : } payload;
371 : } s;
372 : double asDouble;
373 : void *asPtr;
374 : size_t asWord;
375 : } JSVAL_ALIGNMENT jsval_layout;
376 : # endif /* JS_BITS_PER_WORD */
377 : #endif /* defined(IS_LITTLE_ENDIAN) */
378 :
379 : JS_STATIC_ASSERT(sizeof(jsval_layout) == 8);
380 :
381 : #if JS_BITS_PER_WORD == 32
382 :
383 : /*
384 : * N.B. GCC, in some but not all cases, chooses to emit signed comparison of
385 : * JSValueTag even though its underlying type has been forced to be uint32_t.
386 : * Thus, all comparisons should explicitly cast operands to uint32_t.
387 : */
388 :
389 : static JS_ALWAYS_INLINE jsval_layout
390 168251037 : BUILD_JSVAL(JSValueTag tag, uint32_t payload)
391 : {
392 : jsval_layout l;
393 168251037 : l.asBits = (((uint64_t)(uint32_t)tag) << 32) | payload;
394 : return l;
395 : }
396 :
397 : static JS_ALWAYS_INLINE JSBool
398 403998296 : JSVAL_IS_DOUBLE_IMPL(jsval_layout l)
399 : {
400 403998296 : return (uint32_t)l.s.tag <= (uint32_t)JSVAL_TAG_CLEAR;
401 : }
402 :
403 : static JS_ALWAYS_INLINE jsval_layout
404 17662549 : DOUBLE_TO_JSVAL_IMPL(double d)
405 : {
406 : jsval_layout l;
407 17662549 : l.asDouble = d;
408 17662549 : JS_ASSERT(JSVAL_IS_DOUBLE_IMPL(l));
409 : return l;
410 : }
411 :
412 : static JS_ALWAYS_INLINE JSBool
413 1971117360 : JSVAL_IS_INT32_IMPL(jsval_layout l)
414 : {
415 1971117360 : return l.s.tag == JSVAL_TAG_INT32;
416 : }
417 :
418 : static JS_ALWAYS_INLINE int32_t
419 1055163544 : JSVAL_TO_INT32_IMPL(jsval_layout l)
420 : {
421 1055163544 : return l.s.payload.i32;
422 : }
423 :
424 : static JS_ALWAYS_INLINE jsval_layout
425 683418925 : INT32_TO_JSVAL_IMPL(int32_t i)
426 : {
427 : jsval_layout l;
428 683418925 : l.s.tag = JSVAL_TAG_INT32;
429 683418925 : l.s.payload.i32 = i;
430 : return l;
431 : }
432 :
433 : static JS_ALWAYS_INLINE JSBool
434 183677485 : JSVAL_IS_NUMBER_IMPL(jsval_layout l)
435 : {
436 183677485 : JSValueTag tag = l.s.tag;
437 183677485 : JS_ASSERT(tag != JSVAL_TAG_CLEAR);
438 183677485 : return (uint32_t)tag <= (uint32_t)JSVAL_UPPER_INCL_TAG_OF_NUMBER_SET;
439 : }
440 :
441 : static JS_ALWAYS_INLINE JSBool
442 62842279 : JSVAL_IS_UNDEFINED_IMPL(jsval_layout l)
443 : {
444 62842279 : return l.s.tag == JSVAL_TAG_UNDEFINED;
445 : }
446 :
447 : static JS_ALWAYS_INLINE JSBool
448 1345190888 : JSVAL_IS_STRING_IMPL(jsval_layout l)
449 : {
450 1345190888 : return l.s.tag == JSVAL_TAG_STRING;
451 : }
452 :
453 : static JS_ALWAYS_INLINE jsval_layout
454 123774046 : STRING_TO_JSVAL_IMPL(JSString *str)
455 : {
456 : jsval_layout l;
457 123774046 : JS_ASSERT(str);
458 123774046 : l.s.tag = JSVAL_TAG_STRING;
459 123774046 : l.s.payload.str = str;
460 : return l;
461 : }
462 :
463 : static JS_ALWAYS_INLINE JSString *
464 152083934 : JSVAL_TO_STRING_IMPL(jsval_layout l)
465 : {
466 152083934 : return l.s.payload.str;
467 : }
468 :
469 : static JS_ALWAYS_INLINE JSBool
470 40958360 : JSVAL_IS_BOOLEAN_IMPL(jsval_layout l)
471 : {
472 40958360 : return l.s.tag == JSVAL_TAG_BOOLEAN;
473 : }
474 :
475 : static JS_ALWAYS_INLINE JSBool
476 22808908 : JSVAL_TO_BOOLEAN_IMPL(jsval_layout l)
477 : {
478 22808908 : return l.s.payload.boo;
479 : }
480 :
481 : static JS_ALWAYS_INLINE jsval_layout
482 32118119 : BOOLEAN_TO_JSVAL_IMPL(JSBool b)
483 : {
484 : jsval_layout l;
485 32118119 : JS_ASSERT(b == JS_TRUE || b == JS_FALSE);
486 32118119 : l.s.tag = JSVAL_TAG_BOOLEAN;
487 32118119 : l.s.payload.boo = b;
488 : return l;
489 : }
490 :
491 : static JS_ALWAYS_INLINE JSBool
492 312567205 : JSVAL_IS_MAGIC_IMPL(jsval_layout l)
493 : {
494 312567205 : return l.s.tag == JSVAL_TAG_MAGIC;
495 : }
496 :
497 : static JS_ALWAYS_INLINE JSBool
498 -2006412904 : JSVAL_IS_OBJECT_IMPL(jsval_layout l)
499 : {
500 -2006412904 : return l.s.tag == JSVAL_TAG_OBJECT;
501 : }
502 :
503 : static JS_ALWAYS_INLINE JSBool
504 54390492 : JSVAL_IS_PRIMITIVE_IMPL(jsval_layout l)
505 : {
506 54390492 : return (uint32_t)l.s.tag < (uint32_t)JSVAL_UPPER_EXCL_TAG_OF_PRIMITIVE_SET;
507 : }
508 :
509 : static JS_ALWAYS_INLINE JSBool
510 3735981 : JSVAL_IS_OBJECT_OR_NULL_IMPL(jsval_layout l)
511 : {
512 3735981 : JS_ASSERT((uint32_t)l.s.tag <= (uint32_t)JSVAL_TAG_OBJECT);
513 3735981 : return (uint32_t)l.s.tag >= (uint32_t)JSVAL_LOWER_INCL_TAG_OF_OBJ_OR_NULL_SET;
514 : }
515 :
516 : static JS_ALWAYS_INLINE JSObject *
517 638829691 : JSVAL_TO_OBJECT_IMPL(jsval_layout l)
518 : {
519 638829691 : return l.s.payload.obj;
520 : }
521 :
522 : static JS_ALWAYS_INLINE jsval_layout
523 111782739 : OBJECT_TO_JSVAL_IMPL(JSObject *obj)
524 : {
525 : jsval_layout l;
526 111782739 : JS_ASSERT(obj);
527 111782739 : l.s.tag = JSVAL_TAG_OBJECT;
528 111782739 : l.s.payload.obj = obj;
529 : return l;
530 : }
531 :
532 : static JS_ALWAYS_INLINE JSBool
533 62584542 : JSVAL_IS_NULL_IMPL(jsval_layout l)
534 : {
535 62584542 : return l.s.tag == JSVAL_TAG_NULL;
536 : }
537 :
538 : static JS_ALWAYS_INLINE jsval_layout
539 3298317 : PRIVATE_PTR_TO_JSVAL_IMPL(void *ptr)
540 : {
541 : jsval_layout l;
542 3298317 : JS_ASSERT(((uint32_t)ptr & 1) == 0);
543 3298317 : l.s.tag = (JSValueTag)0;
544 3298317 : l.s.payload.ptr = ptr;
545 3298317 : JS_ASSERT(JSVAL_IS_DOUBLE_IMPL(l));
546 : return l;
547 : }
548 :
549 : static JS_ALWAYS_INLINE void *
550 3979268 : JSVAL_TO_PRIVATE_PTR_IMPL(jsval_layout l)
551 : {
552 3979268 : return l.s.payload.ptr;
553 : }
554 :
555 : static JS_ALWAYS_INLINE JSBool
556 21042820 : JSVAL_IS_GCTHING_IMPL(jsval_layout l)
557 : {
558 : /* gcc sometimes generates signed < without explicit casts. */
559 21042820 : return (uint32_t)l.s.tag >= (uint32_t)JSVAL_LOWER_INCL_TAG_OF_GCTHING_SET;
560 : }
561 :
562 : static JS_ALWAYS_INLINE void *
563 21042772 : JSVAL_TO_GCTHING_IMPL(jsval_layout l)
564 : {
565 21042772 : return l.s.payload.ptr;
566 : }
567 :
568 : static JS_ALWAYS_INLINE JSBool
569 131789308 : JSVAL_IS_TRACEABLE_IMPL(jsval_layout l)
570 : {
571 131789308 : return l.s.tag == JSVAL_TAG_STRING || l.s.tag == JSVAL_TAG_OBJECT;
572 : }
573 :
574 : static JS_ALWAYS_INLINE uint32_t
575 6957567 : JSVAL_TRACE_KIND_IMPL(jsval_layout l)
576 : {
577 6957567 : return (uint32_t)(JSBool)JSVAL_IS_STRING_IMPL(l);
578 : }
579 :
580 : static JS_ALWAYS_INLINE JSBool
581 306 : JSVAL_IS_SPECIFIC_INT32_IMPL(jsval_layout l, int32_t i32)
582 : {
583 306 : return l.s.tag == JSVAL_TAG_INT32 && l.s.payload.i32 == i32;
584 : }
585 :
586 : static JS_ALWAYS_INLINE JSBool
587 44282328 : JSVAL_IS_SPECIFIC_BOOLEAN(jsval_layout l, JSBool b)
588 : {
589 44282328 : return (l.s.tag == JSVAL_TAG_BOOLEAN) && (l.s.payload.boo == b);
590 : }
591 :
592 : static JS_ALWAYS_INLINE jsval_layout
593 26795126 : MAGIC_TO_JSVAL_IMPL(JSWhyMagic why)
594 : {
595 : jsval_layout l;
596 26795126 : l.s.tag = JSVAL_TAG_MAGIC;
597 26795126 : l.s.payload.why = why;
598 : return l;
599 : }
600 :
601 : static JS_ALWAYS_INLINE JSBool
602 14958488 : JSVAL_SAME_TYPE_IMPL(jsval_layout lhs, jsval_layout rhs)
603 : {
604 14958488 : JSValueTag ltag = lhs.s.tag, rtag = rhs.s.tag;
605 14958488 : return ltag == rtag || (ltag < JSVAL_TAG_CLEAR && rtag < JSVAL_TAG_CLEAR);
606 : }
607 :
608 : static JS_ALWAYS_INLINE jsval_layout
609 108780 : PRIVATE_UINT32_TO_JSVAL_IMPL(uint32_t ui)
610 : {
611 : jsval_layout l;
612 108780 : l.s.tag = (JSValueTag)0;
613 108780 : l.s.payload.u32 = ui;
614 108780 : JS_ASSERT(JSVAL_IS_DOUBLE_IMPL(l));
615 : return l;
616 : }
617 :
618 : static JS_ALWAYS_INLINE uint32_t
619 180092 : JSVAL_TO_PRIVATE_UINT32_IMPL(jsval_layout l)
620 : {
621 180092 : return l.s.payload.u32;
622 : }
623 :
624 : static JS_ALWAYS_INLINE JSValueType
625 116057337 : JSVAL_EXTRACT_NON_DOUBLE_TYPE_IMPL(jsval_layout l)
626 : {
627 116057337 : uint32_t type = l.s.tag & 0xF;
628 116057337 : JS_ASSERT(type > JSVAL_TYPE_DOUBLE);
629 116057337 : return (JSValueType)type;
630 : }
631 :
632 : #elif JS_BITS_PER_WORD == 64
633 :
634 : static JS_ALWAYS_INLINE jsval_layout
635 : BUILD_JSVAL(JSValueTag tag, uint64_t payload)
636 : {
637 : jsval_layout l;
638 : l.asBits = (((uint64_t)(uint32_t)tag) << JSVAL_TAG_SHIFT) | payload;
639 : return l;
640 : }
641 :
642 : static JS_ALWAYS_INLINE JSBool
643 : JSVAL_IS_DOUBLE_IMPL(jsval_layout l)
644 : {
645 : return l.asBits <= JSVAL_SHIFTED_TAG_MAX_DOUBLE;
646 : }
647 :
648 : static JS_ALWAYS_INLINE jsval_layout
649 : DOUBLE_TO_JSVAL_IMPL(double d)
650 : {
651 : jsval_layout l;
652 : l.asDouble = d;
653 : JS_ASSERT(l.asBits <= JSVAL_SHIFTED_TAG_MAX_DOUBLE);
654 : return l;
655 : }
656 :
657 : static JS_ALWAYS_INLINE JSBool
658 : JSVAL_IS_INT32_IMPL(jsval_layout l)
659 : {
660 : return (uint32_t)(l.asBits >> JSVAL_TAG_SHIFT) == JSVAL_TAG_INT32;
661 : }
662 :
663 : static JS_ALWAYS_INLINE int32_t
664 : JSVAL_TO_INT32_IMPL(jsval_layout l)
665 : {
666 : return (int32_t)l.asBits;
667 : }
668 :
669 : static JS_ALWAYS_INLINE jsval_layout
670 : INT32_TO_JSVAL_IMPL(int32_t i32)
671 : {
672 : jsval_layout l;
673 : l.asBits = ((uint64_t)(uint32_t)i32) | JSVAL_SHIFTED_TAG_INT32;
674 : return l;
675 : }
676 :
677 : static JS_ALWAYS_INLINE JSBool
678 : JSVAL_IS_NUMBER_IMPL(jsval_layout l)
679 : {
680 : return l.asBits < JSVAL_UPPER_EXCL_SHIFTED_TAG_OF_NUMBER_SET;
681 : }
682 :
683 : static JS_ALWAYS_INLINE JSBool
684 : JSVAL_IS_UNDEFINED_IMPL(jsval_layout l)
685 : {
686 : return l.asBits == JSVAL_SHIFTED_TAG_UNDEFINED;
687 : }
688 :
689 : static JS_ALWAYS_INLINE JSBool
690 : JSVAL_IS_STRING_IMPL(jsval_layout l)
691 : {
692 : return (uint32_t)(l.asBits >> JSVAL_TAG_SHIFT) == JSVAL_TAG_STRING;
693 : }
694 :
695 : static JS_ALWAYS_INLINE jsval_layout
696 : STRING_TO_JSVAL_IMPL(JSString *str)
697 : {
698 : jsval_layout l;
699 : uint64_t strBits = (uint64_t)str;
700 : JS_ASSERT(str);
701 : JS_ASSERT((strBits >> JSVAL_TAG_SHIFT) == 0);
702 : l.asBits = strBits | JSVAL_SHIFTED_TAG_STRING;
703 : return l;
704 : }
705 :
706 : static JS_ALWAYS_INLINE JSString *
707 : JSVAL_TO_STRING_IMPL(jsval_layout l)
708 : {
709 : return (JSString *)(l.asBits & JSVAL_PAYLOAD_MASK);
710 : }
711 :
712 : static JS_ALWAYS_INLINE JSBool
713 : JSVAL_IS_BOOLEAN_IMPL(jsval_layout l)
714 : {
715 : return (uint32_t)(l.asBits >> JSVAL_TAG_SHIFT) == JSVAL_TAG_BOOLEAN;
716 : }
717 :
718 : static JS_ALWAYS_INLINE JSBool
719 : JSVAL_TO_BOOLEAN_IMPL(jsval_layout l)
720 : {
721 : return (JSBool)l.asBits;
722 : }
723 :
724 : static JS_ALWAYS_INLINE jsval_layout
725 : BOOLEAN_TO_JSVAL_IMPL(JSBool b)
726 : {
727 : jsval_layout l;
728 : JS_ASSERT(b == JS_TRUE || b == JS_FALSE);
729 : l.asBits = ((uint64_t)(uint32_t)b) | JSVAL_SHIFTED_TAG_BOOLEAN;
730 : return l;
731 : }
732 :
733 : static JS_ALWAYS_INLINE JSBool
734 : JSVAL_IS_MAGIC_IMPL(jsval_layout l)
735 : {
736 : return (l.asBits >> JSVAL_TAG_SHIFT) == JSVAL_TAG_MAGIC;
737 : }
738 :
739 : static JS_ALWAYS_INLINE JSBool
740 : JSVAL_IS_PRIMITIVE_IMPL(jsval_layout l)
741 : {
742 : return l.asBits < JSVAL_UPPER_EXCL_SHIFTED_TAG_OF_PRIMITIVE_SET;
743 : }
744 :
745 : static JS_ALWAYS_INLINE JSBool
746 : JSVAL_IS_OBJECT_IMPL(jsval_layout l)
747 : {
748 : JS_ASSERT((l.asBits >> JSVAL_TAG_SHIFT) <= JSVAL_SHIFTED_TAG_OBJECT);
749 : return l.asBits >= JSVAL_SHIFTED_TAG_OBJECT;
750 : }
751 :
752 : static JS_ALWAYS_INLINE JSBool
753 : JSVAL_IS_OBJECT_OR_NULL_IMPL(jsval_layout l)
754 : {
755 : JS_ASSERT((l.asBits >> JSVAL_TAG_SHIFT) <= JSVAL_TAG_OBJECT);
756 : return l.asBits >= JSVAL_LOWER_INCL_SHIFTED_TAG_OF_OBJ_OR_NULL_SET;
757 : }
758 :
759 : static JS_ALWAYS_INLINE JSObject *
760 : JSVAL_TO_OBJECT_IMPL(jsval_layout l)
761 : {
762 : uint64_t ptrBits = l.asBits & JSVAL_PAYLOAD_MASK;
763 : JS_ASSERT((ptrBits & 0x7) == 0);
764 : return (JSObject *)ptrBits;
765 : }
766 :
767 : static JS_ALWAYS_INLINE jsval_layout
768 : OBJECT_TO_JSVAL_IMPL(JSObject *obj)
769 : {
770 : jsval_layout l;
771 : uint64_t objBits = (uint64_t)obj;
772 : JS_ASSERT(obj);
773 : JS_ASSERT((objBits >> JSVAL_TAG_SHIFT) == 0);
774 : l.asBits = objBits | JSVAL_SHIFTED_TAG_OBJECT;
775 : return l;
776 : }
777 :
778 : static JS_ALWAYS_INLINE JSBool
779 : JSVAL_IS_NULL_IMPL(jsval_layout l)
780 : {
781 : return l.asBits == JSVAL_SHIFTED_TAG_NULL;
782 : }
783 :
784 : static JS_ALWAYS_INLINE JSBool
785 : JSVAL_IS_GCTHING_IMPL(jsval_layout l)
786 : {
787 : return l.asBits >= JSVAL_LOWER_INCL_SHIFTED_TAG_OF_GCTHING_SET;
788 : }
789 :
790 : static JS_ALWAYS_INLINE void *
791 : JSVAL_TO_GCTHING_IMPL(jsval_layout l)
792 : {
793 : uint64_t ptrBits = l.asBits & JSVAL_PAYLOAD_MASK;
794 : JS_ASSERT((ptrBits & 0x7) == 0);
795 : return (void *)ptrBits;
796 : }
797 :
798 : static JS_ALWAYS_INLINE JSBool
799 : JSVAL_IS_TRACEABLE_IMPL(jsval_layout l)
800 : {
801 : return JSVAL_IS_GCTHING_IMPL(l) && !JSVAL_IS_NULL_IMPL(l);
802 : }
803 :
804 : static JS_ALWAYS_INLINE uint32_t
805 : JSVAL_TRACE_KIND_IMPL(jsval_layout l)
806 : {
807 : return (uint32_t)(JSBool)!(JSVAL_IS_OBJECT_IMPL(l));
808 : }
809 :
810 : static JS_ALWAYS_INLINE jsval_layout
811 : PRIVATE_PTR_TO_JSVAL_IMPL(void *ptr)
812 : {
813 : jsval_layout l;
814 : uint64_t ptrBits = (uint64_t)ptr;
815 : JS_ASSERT((ptrBits & 1) == 0);
816 : l.asBits = ptrBits >> 1;
817 : JS_ASSERT(JSVAL_IS_DOUBLE_IMPL(l));
818 : return l;
819 : }
820 :
821 : static JS_ALWAYS_INLINE void *
822 : JSVAL_TO_PRIVATE_PTR_IMPL(jsval_layout l)
823 : {
824 : JS_ASSERT((l.asBits & 0x8000000000000000LL) == 0);
825 : return (void *)(l.asBits << 1);
826 : }
827 :
828 : static JS_ALWAYS_INLINE JSBool
829 : JSVAL_IS_SPECIFIC_INT32_IMPL(jsval_layout l, int32_t i32)
830 : {
831 : return l.asBits == (((uint64_t)(uint32_t)i32) | JSVAL_SHIFTED_TAG_INT32);
832 : }
833 :
834 : static JS_ALWAYS_INLINE JSBool
835 : JSVAL_IS_SPECIFIC_BOOLEAN(jsval_layout l, JSBool b)
836 : {
837 : return l.asBits == (((uint64_t)(uint32_t)b) | JSVAL_SHIFTED_TAG_BOOLEAN);
838 : }
839 :
840 : static JS_ALWAYS_INLINE jsval_layout
841 : MAGIC_TO_JSVAL_IMPL(JSWhyMagic why)
842 : {
843 : jsval_layout l;
844 : l.asBits = ((uint64_t)(uint32_t)why) | JSVAL_SHIFTED_TAG_MAGIC;
845 : return l;
846 : }
847 :
848 : static JS_ALWAYS_INLINE JSBool
849 : JSVAL_SAME_TYPE_IMPL(jsval_layout lhs, jsval_layout rhs)
850 : {
851 : uint64_t lbits = lhs.asBits, rbits = rhs.asBits;
852 : return (lbits <= JSVAL_SHIFTED_TAG_MAX_DOUBLE && rbits <= JSVAL_SHIFTED_TAG_MAX_DOUBLE) ||
853 : (((lbits ^ rbits) & 0xFFFF800000000000LL) == 0);
854 : }
855 :
856 : static JS_ALWAYS_INLINE jsval_layout
857 : PRIVATE_UINT32_TO_JSVAL_IMPL(uint32_t ui)
858 : {
859 : jsval_layout l;
860 : l.asBits = (uint64_t)ui;
861 : JS_ASSERT(JSVAL_IS_DOUBLE_IMPL(l));
862 : return l;
863 : }
864 :
865 : static JS_ALWAYS_INLINE uint32_t
866 : JSVAL_TO_PRIVATE_UINT32_IMPL(jsval_layout l)
867 : {
868 : JS_ASSERT((l.asBits >> 32) == 0);
869 : return (uint32_t)l.asBits;
870 : }
871 :
872 : static JS_ALWAYS_INLINE JSValueType
873 : JSVAL_EXTRACT_NON_DOUBLE_TYPE_IMPL(jsval_layout l)
874 : {
875 : uint64_t type = (l.asBits >> JSVAL_TAG_SHIFT) & 0xF;
876 : JS_ASSERT(type > JSVAL_TYPE_DOUBLE);
877 : return (JSValueType)type;
878 : }
879 :
880 : #endif /* JS_BITS_PER_WORD */
881 :
882 : static JS_ALWAYS_INLINE double
883 432 : JS_CANONICALIZE_NAN(double d)
884 : {
885 432 : if (JS_UNLIKELY(d != d)) {
886 : jsval_layout l;
887 18 : l.asBits = 0x7FF8000000000000LL;
888 18 : return l.asDouble;
889 : }
890 414 : return d;
891 : }
892 :
893 : JS_END_EXTERN_C
894 :
895 : #ifdef __cplusplus
896 : static jsval_layout JSVAL_TO_IMPL(JS::Value);
897 : static JS::Value IMPL_TO_JSVAL(jsval_layout);
898 : #endif
899 :
900 : #endif /* jsvalimpl_h__ */
|