do-not-enforce-wrong-arm-flags
[platform/upstream/js.git] / js / src / jsval.h
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  * JS value implementation details for operations on jsval and jsid.
44  * Embeddings should not rely on any of the definitions in this file. For a
45  * description of the value representation and the engine-internal C++ value
46  * interface, js::Value, see jsvalue.h.
47  */
48 #include "jsutil.h"
49
50 JS_BEGIN_EXTERN_C
51
52 /*
53  * Try to get jsvals 64-bit aligned. We could almost assert that all values are
54  * aligned, but MSVC and GCC occasionally break alignment.
55  */
56 #ifdef __GNUC__
57 # define JSVAL_ALIGNMENT        __attribute__((aligned (8)))
58 #elif defined(_MSC_VER)
59   /*
60    * Structs can be aligned with MSVC, but not if they are used as parameters,
61    * so we just don't try to align.
62    */
63 # define JSVAL_ALIGNMENT
64 #elif defined(__SUNPRO_C) || defined(__SUNPRO_CC)
65 # define JSVAL_ALIGNMENT
66 #endif
67
68 #if JS_BITS_PER_WORD == 64
69 # define JSVAL_TAG_SHIFT 47
70 #endif
71
72 /*
73  * We try to use enums so that printing a jsval_layout in the debugger shows
74  * nice symbolic type tags, however we can only do this when we can force the
75  * underlying type of the enum to be the desired size.
76  */
77 #if defined(__cplusplus) && !defined(__SUNPRO_CC)
78
79 #if defined(_MSC_VER)
80 # define JS_ENUM_HEADER(id, type)              enum id : type
81 # define JS_ENUM_MEMBER(id, type, value)       id = (type)value,
82 # define JS_LAST_ENUM_MEMBER(id, type, value)  id = (type)value
83 # define JS_ENUM_FOOTER(id)
84 #else
85 # define JS_ENUM_HEADER(id, type)              enum id
86 # define JS_ENUM_MEMBER(id, type, value)       id = (type)value,
87 # define JS_LAST_ENUM_MEMBER(id, type, value)  id = (type)value
88 # define JS_ENUM_FOOTER(id)                    __attribute__((packed))
89 #endif
90
91 /* Remember to propagate changes to the C defines below. */
92 JS_ENUM_HEADER(JSValueType, uint8)
93 {
94     JSVAL_TYPE_DOUBLE              = 0x00,
95     JSVAL_TYPE_INT32               = 0x01,
96     JSVAL_TYPE_UNDEFINED           = 0x02,
97     JSVAL_TYPE_BOOLEAN             = 0x03,
98     JSVAL_TYPE_MAGIC               = 0x04,
99     JSVAL_TYPE_STRING              = 0x05,
100     JSVAL_TYPE_NULL                = 0x06,
101     JSVAL_TYPE_OBJECT              = 0x07,
102
103     /* The below types never appear in a jsval; they are only used in tracing. */
104
105     JSVAL_TYPE_NONFUNOBJ           = 0x57,
106     JSVAL_TYPE_FUNOBJ              = 0x67,
107
108     JSVAL_TYPE_STRORNULL           = 0x97,
109     JSVAL_TYPE_OBJORNULL           = 0x98,
110
111     JSVAL_TYPE_BOXED               = 0x99
112 } JS_ENUM_FOOTER(JSValueType);
113
114 JS_STATIC_ASSERT(sizeof(JSValueType) == 1);
115
116 #if JS_BITS_PER_WORD == 32
117
118 /* Remember to propagate changes to the C defines below. */
119 JS_ENUM_HEADER(JSValueTag, uint32)
120 {
121     JSVAL_TAG_CLEAR                = 0xFFFF0000,
122     JSVAL_TAG_INT32                = JSVAL_TAG_CLEAR | JSVAL_TYPE_INT32,
123     JSVAL_TAG_UNDEFINED            = JSVAL_TAG_CLEAR | JSVAL_TYPE_UNDEFINED,
124     JSVAL_TAG_STRING               = JSVAL_TAG_CLEAR | JSVAL_TYPE_STRING,
125     JSVAL_TAG_BOOLEAN              = JSVAL_TAG_CLEAR | JSVAL_TYPE_BOOLEAN,
126     JSVAL_TAG_MAGIC                = JSVAL_TAG_CLEAR | JSVAL_TYPE_MAGIC,
127     JSVAL_TAG_NULL                 = JSVAL_TAG_CLEAR | JSVAL_TYPE_NULL,
128     JSVAL_TAG_OBJECT               = JSVAL_TAG_CLEAR | JSVAL_TYPE_OBJECT
129 } JS_ENUM_FOOTER(JSValueTag);
130
131 JS_STATIC_ASSERT(sizeof(JSValueTag) == 4);
132
133 #elif JS_BITS_PER_WORD == 64
134
135 /* Remember to propagate changes to the C defines below. */
136 JS_ENUM_HEADER(JSValueTag, uint32)
137 {
138     JSVAL_TAG_MAX_DOUBLE           = 0x1FFF0,
139     JSVAL_TAG_INT32                = JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_INT32,
140     JSVAL_TAG_UNDEFINED            = JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_UNDEFINED,
141     JSVAL_TAG_STRING               = JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_STRING,
142     JSVAL_TAG_BOOLEAN              = JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_BOOLEAN,
143     JSVAL_TAG_MAGIC                = JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_MAGIC,
144     JSVAL_TAG_NULL                 = JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_NULL,
145     JSVAL_TAG_OBJECT               = JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_OBJECT
146 } JS_ENUM_FOOTER(JSValueTag);
147
148 JS_STATIC_ASSERT(sizeof(JSValueTag) == sizeof(uint32));
149
150 JS_ENUM_HEADER(JSValueShiftedTag, uint64)
151 {
152     JSVAL_SHIFTED_TAG_MAX_DOUBLE   = ((((uint64)JSVAL_TAG_MAX_DOUBLE) << JSVAL_TAG_SHIFT) | 0xFFFFFFFF),
153     JSVAL_SHIFTED_TAG_INT32        = (((uint64)JSVAL_TAG_INT32)      << JSVAL_TAG_SHIFT),
154     JSVAL_SHIFTED_TAG_UNDEFINED    = (((uint64)JSVAL_TAG_UNDEFINED)  << JSVAL_TAG_SHIFT),
155     JSVAL_SHIFTED_TAG_STRING       = (((uint64)JSVAL_TAG_STRING)     << JSVAL_TAG_SHIFT),
156     JSVAL_SHIFTED_TAG_BOOLEAN      = (((uint64)JSVAL_TAG_BOOLEAN)    << JSVAL_TAG_SHIFT),
157     JSVAL_SHIFTED_TAG_MAGIC        = (((uint64)JSVAL_TAG_MAGIC)      << JSVAL_TAG_SHIFT),
158     JSVAL_SHIFTED_TAG_NULL         = (((uint64)JSVAL_TAG_NULL)       << JSVAL_TAG_SHIFT),
159     JSVAL_SHIFTED_TAG_OBJECT       = (((uint64)JSVAL_TAG_OBJECT)     << JSVAL_TAG_SHIFT)
160 } JS_ENUM_FOOTER(JSValueShiftedTag);
161
162 JS_STATIC_ASSERT(sizeof(JSValueShiftedTag) == sizeof(uint64));
163
164 #endif
165
166 #else  /* defined(__cplusplus) */
167
168 typedef uint8 JSValueType;
169 #define JSVAL_TYPE_DOUBLE            ((uint8)0x00)
170 #define JSVAL_TYPE_INT32             ((uint8)0x01)
171 #define JSVAL_TYPE_UNDEFINED         ((uint8)0x02)
172 #define JSVAL_TYPE_BOOLEAN           ((uint8)0x03)
173 #define JSVAL_TYPE_MAGIC             ((uint8)0x04)
174 #define JSVAL_TYPE_STRING            ((uint8)0x05)
175 #define JSVAL_TYPE_NULL              ((uint8)0x06)
176 #define JSVAL_TYPE_OBJECT            ((uint8)0x07)
177 #define JSVAL_TYPE_NONFUNOBJ         ((uint8)0x57)
178 #define JSVAL_TYPE_FUNOBJ            ((uint8)0x67)
179 #define JSVAL_TYPE_STRORNULL         ((uint8)0x97)
180 #define JSVAL_TYPE_OBJORNULL         ((uint8)0x98)
181 #define JSVAL_TYPE_BOXED             ((uint8)0x99)
182 #define JSVAL_TYPE_UNINITIALIZED     ((uint8)0xcd)
183
184 #if JS_BITS_PER_WORD == 32
185
186 typedef uint32 JSValueTag;
187 #define JSVAL_TAG_CLEAR              ((uint32)(0xFFFF0000))
188 #define JSVAL_TAG_INT32              ((uint32)(JSVAL_TAG_CLEAR | JSVAL_TYPE_INT32))
189 #define JSVAL_TAG_UNDEFINED          ((uint32)(JSVAL_TAG_CLEAR | JSVAL_TYPE_UNDEFINED))
190 #define JSVAL_TAG_STRING             ((uint32)(JSVAL_TAG_CLEAR | JSVAL_TYPE_STRING))
191 #define JSVAL_TAG_BOOLEAN            ((uint32)(JSVAL_TAG_CLEAR | JSVAL_TYPE_BOOLEAN))
192 #define JSVAL_TAG_MAGIC              ((uint32)(JSVAL_TAG_CLEAR | JSVAL_TYPE_MAGIC))
193 #define JSVAL_TAG_NULL               ((uint32)(JSVAL_TAG_CLEAR | JSVAL_TYPE_NULL))
194 #define JSVAL_TAG_OBJECT             ((uint32)(JSVAL_TAG_CLEAR | JSVAL_TYPE_OBJECT))
195
196 #elif JS_BITS_PER_WORD == 64
197
198 typedef uint32 JSValueTag;
199 #define JSVAL_TAG_MAX_DOUBLE         ((uint32)(0x1FFF0))
200 #define JSVAL_TAG_INT32              (uint32)(JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_INT32)
201 #define JSVAL_TAG_UNDEFINED          (uint32)(JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_UNDEFINED)
202 #define JSVAL_TAG_STRING             (uint32)(JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_STRING)
203 #define JSVAL_TAG_BOOLEAN            (uint32)(JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_BOOLEAN)
204 #define JSVAL_TAG_MAGIC              (uint32)(JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_MAGIC)
205 #define JSVAL_TAG_NULL               (uint32)(JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_NULL)
206 #define JSVAL_TAG_OBJECT             (uint32)(JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_OBJECT)
207
208 typedef uint64 JSValueShiftedTag;
209 #define JSVAL_SHIFTED_TAG_MAX_DOUBLE ((((uint64)JSVAL_TAG_MAX_DOUBLE) << JSVAL_TAG_SHIFT) | 0xFFFFFFFF)
210 #define JSVAL_SHIFTED_TAG_INT32      (((uint64)JSVAL_TAG_INT32)      << JSVAL_TAG_SHIFT)
211 #define JSVAL_SHIFTED_TAG_UNDEFINED  (((uint64)JSVAL_TAG_UNDEFINED)  << JSVAL_TAG_SHIFT)
212 #define JSVAL_SHIFTED_TAG_STRING     (((uint64)JSVAL_TAG_STRING)     << JSVAL_TAG_SHIFT)
213 #define JSVAL_SHIFTED_TAG_BOOLEAN    (((uint64)JSVAL_TAG_BOOLEAN)    << JSVAL_TAG_SHIFT)
214 #define JSVAL_SHIFTED_TAG_MAGIC      (((uint64)JSVAL_TAG_MAGIC)      << JSVAL_TAG_SHIFT)
215 #define JSVAL_SHIFTED_TAG_NULL       (((uint64)JSVAL_TAG_NULL)       << JSVAL_TAG_SHIFT)
216 #define JSVAL_SHIFTED_TAG_OBJECT     (((uint64)JSVAL_TAG_OBJECT)     << JSVAL_TAG_SHIFT)
217
218 #endif  /* JS_BITS_PER_WORD */
219 #endif  /* defined(__cplusplus) && !defined(__SUNPRO_CC) */
220
221 #define JSVAL_LOWER_INCL_TYPE_OF_OBJ_OR_NULL_SET        JSVAL_TYPE_NULL
222 #define JSVAL_UPPER_EXCL_TYPE_OF_PRIMITIVE_SET          JSVAL_TYPE_OBJECT
223 #define JSVAL_UPPER_INCL_TYPE_OF_NUMBER_SET             JSVAL_TYPE_INT32
224 #define JSVAL_LOWER_INCL_TYPE_OF_PTR_PAYLOAD_SET        JSVAL_TYPE_MAGIC
225 #define JSVAL_UPPER_INCL_TYPE_OF_VALUE_SET              JSVAL_TYPE_OBJECT
226 #define JSVAL_UPPER_INCL_TYPE_OF_BOXABLE_SET            JSVAL_TYPE_FUNOBJ
227
228 #if JS_BITS_PER_WORD == 32
229
230 #define JSVAL_TYPE_TO_TAG(type)      ((JSValueTag)(JSVAL_TAG_CLEAR | (type)))
231
232 #define JSVAL_LOWER_INCL_TAG_OF_OBJ_OR_NULL_SET         JSVAL_TAG_NULL
233 #define JSVAL_UPPER_EXCL_TAG_OF_PRIMITIVE_SET           JSVAL_TAG_OBJECT
234 #define JSVAL_UPPER_INCL_TAG_OF_NUMBER_SET              JSVAL_TAG_INT32
235 #define JSVAL_LOWER_INCL_TAG_OF_GCTHING_SET             JSVAL_TAG_STRING
236
237 #elif JS_BITS_PER_WORD == 64
238
239 #define JSVAL_PAYLOAD_MASK           0x00007FFFFFFFFFFFLL
240 #define JSVAL_TAG_MASK               0xFFFF800000000000LL
241 #define JSVAL_TYPE_TO_TAG(type)      ((JSValueTag)(JSVAL_TAG_MAX_DOUBLE | (type)))
242 #define JSVAL_TYPE_TO_SHIFTED_TAG(type) (((uint64)JSVAL_TYPE_TO_TAG(type)) << JSVAL_TAG_SHIFT)
243
244 #define JSVAL_LOWER_INCL_SHIFTED_TAG_OF_OBJ_OR_NULL_SET  JSVAL_SHIFTED_TAG_NULL
245 #define JSVAL_UPPER_EXCL_SHIFTED_TAG_OF_PRIMITIVE_SET    JSVAL_SHIFTED_TAG_OBJECT
246 #define JSVAL_UPPER_EXCL_SHIFTED_TAG_OF_NUMBER_SET       JSVAL_SHIFTED_TAG_UNDEFINED
247 #define JSVAL_LOWER_INCL_SHIFTED_TAG_OF_PTR_PAYLOAD_SET  JSVAL_SHIFTED_TAG_MAGIC
248 #define JSVAL_LOWER_INCL_SHIFTED_TAG_OF_GCTHING_SET      JSVAL_SHIFTED_TAG_STRING
249
250 #endif /* JS_BITS_PER_WORD */
251
252 typedef enum JSWhyMagic
253 {
254     JS_ARRAY_HOLE,               /* a hole in a dense array */
255     JS_ARGS_HOLE,                /* a hole in the args object's array */
256     JS_NATIVE_ENUMERATE,         /* indicates that a custom enumerate hook forwarded
257                                   * to js_Enumerate, which really means the object can be
258                                   * enumerated like a native object. */
259     JS_NO_ITER_VALUE,            /* there is not a pending iterator value */
260     JS_GENERATOR_CLOSING,        /* exception value thrown when closing a generator */
261     JS_NO_CONSTANT,              /* compiler sentinel value */
262     JS_THIS_POISON,              /* used in debug builds to catch tracing errors */
263     JS_ARG_POISON,               /* used in debug builds to catch tracing errors */
264     JS_SERIALIZE_NO_NODE,        /* an empty subnode in the AST serializer */
265     JS_GENERIC_MAGIC             /* for local use */
266 } JSWhyMagic;
267
268 typedef struct JSString     JSString;
269 typedef struct JSFlatString JSFlatString;
270 typedef struct JSObject     JSObject;
271
272 #if defined(IS_LITTLE_ENDIAN)
273 # if JS_BITS_PER_WORD == 32
274 typedef union jsval_layout
275 {
276     uint64 asBits;
277     struct {
278         union {
279             int32          i32;
280             uint32         u32;
281             JSBool         boo;
282             JSString       *str;
283             JSObject       *obj;
284             void           *ptr;
285             JSWhyMagic     why;
286             jsuword        word;
287         } payload;
288         JSValueTag tag;
289     } s;
290     double asDouble;
291     void *asPtr;
292 } jsval_layout;
293 # elif JS_BITS_PER_WORD == 64
294 typedef union jsval_layout
295 {
296     uint64 asBits;
297 #if (!defined(_WIN64) && defined(__cplusplus))
298     /* MSVC does not pack these correctly :-( */
299     struct {
300         uint64             payload47 : 47;
301         JSValueTag         tag : 17;
302     } debugView;
303 #endif
304     struct {
305         union {
306             int32          i32;
307             uint32         u32;
308             JSWhyMagic     why;
309             jsuword        word;
310         } payload;
311     } s;
312     double asDouble;
313     void *asPtr;
314 } jsval_layout;
315 # endif  /* JS_BITS_PER_WORD */
316 #else   /* defined(IS_LITTLE_ENDIAN) */
317 # if JS_BITS_PER_WORD == 32
318 typedef union jsval_layout
319 {
320     uint64 asBits;
321     struct {
322         JSValueTag tag;
323         union {
324             int32          i32;
325             uint32         u32;
326             JSBool         boo;
327             JSString       *str;
328             JSObject       *obj;
329             void           *ptr;
330             JSWhyMagic     why;
331             jsuword        word;
332         } payload;
333     } s;
334     double asDouble;
335     void *asPtr;
336 } jsval_layout;
337 # elif JS_BITS_PER_WORD == 64
338 typedef union jsval_layout
339 {
340     uint64 asBits;
341     struct {
342         JSValueTag         tag : 17;
343         uint64             payload47 : 47;
344     } debugView;
345     struct {
346         union {
347             int32          i32;
348             uint32         u32;
349             JSWhyMagic     why;
350         } payload;
351     } s;
352     double asDouble;
353     void *asPtr;
354 } jsval_layout;
355 # endif /* JS_BITS_PER_WORD */
356 #endif  /* defined(IS_LITTLE_ENDIAN) */
357
358 #if JS_BITS_PER_WORD == 32
359
360 /*
361  * N.B. GCC, in some but not all cases, chooses to emit signed comparison of
362  * JSValueTag even though its underlying type has been forced to be uint32.
363  * Thus, all comparisons should explicitly cast operands to uint32.
364  */
365
366 #define BUILD_JSVAL(tag, payload) \
367     ((((uint64)(uint32)(tag)) << 32) | (uint32)(payload))
368
369 static JS_ALWAYS_INLINE JSBool
370 JSVAL_IS_DOUBLE_IMPL(jsval_layout l)
371 {
372     return (uint32)l.s.tag <= (uint32)JSVAL_TAG_CLEAR;
373 }
374
375 static JS_ALWAYS_INLINE jsval_layout
376 DOUBLE_TO_JSVAL_IMPL(double d)
377 {
378     jsval_layout l;
379     l.asDouble = d;
380     JS_ASSERT(JSVAL_IS_DOUBLE_IMPL(l));
381     return l;
382 }
383
384 static JS_ALWAYS_INLINE JSBool
385 JSVAL_IS_INT32_IMPL(jsval_layout l)
386 {
387     return l.s.tag == JSVAL_TAG_INT32;
388 }
389
390 static JS_ALWAYS_INLINE int32
391 JSVAL_TO_INT32_IMPL(jsval_layout l)
392 {
393     return l.s.payload.i32;
394 }
395
396 static JS_ALWAYS_INLINE jsval_layout
397 INT32_TO_JSVAL_IMPL(int32 i)
398 {
399     jsval_layout l;
400     l.s.tag = JSVAL_TAG_INT32;
401     l.s.payload.i32 = i;
402     return l;
403 }
404
405 static JS_ALWAYS_INLINE JSBool
406 JSVAL_IS_NUMBER_IMPL(jsval_layout l)
407 {
408     JSValueTag tag = l.s.tag;
409     JS_ASSERT(tag != JSVAL_TAG_CLEAR);
410     return (uint32)tag <= (uint32)JSVAL_UPPER_INCL_TAG_OF_NUMBER_SET;
411 }
412
413 static JS_ALWAYS_INLINE JSBool
414 JSVAL_IS_UNDEFINED_IMPL(jsval_layout l)
415 {
416     return l.s.tag == JSVAL_TAG_UNDEFINED;
417 }
418
419 static JS_ALWAYS_INLINE JSBool
420 JSVAL_IS_STRING_IMPL(jsval_layout l)
421 {
422     return l.s.tag == JSVAL_TAG_STRING;
423 }
424
425 static JS_ALWAYS_INLINE jsval_layout
426 STRING_TO_JSVAL_IMPL(JSString *str)
427 {
428     jsval_layout l;
429     JS_ASSERT(str);
430     l.s.tag = JSVAL_TAG_STRING;
431     l.s.payload.str = str;
432     return l;
433 }
434
435 static JS_ALWAYS_INLINE JSString *
436 JSVAL_TO_STRING_IMPL(jsval_layout l)
437 {
438     return l.s.payload.str;
439 }
440
441 static JS_ALWAYS_INLINE JSBool
442 JSVAL_IS_BOOLEAN_IMPL(jsval_layout l)
443 {
444     return l.s.tag == JSVAL_TAG_BOOLEAN;
445 }
446
447 static JS_ALWAYS_INLINE JSBool
448 JSVAL_TO_BOOLEAN_IMPL(jsval_layout l)
449 {
450     return l.s.payload.boo;
451 }
452
453 static JS_ALWAYS_INLINE jsval_layout
454 BOOLEAN_TO_JSVAL_IMPL(JSBool b)
455 {
456     jsval_layout l;
457     l.s.tag = JSVAL_TAG_BOOLEAN;
458     l.s.payload.boo = b;
459     return l;
460 }
461
462 static JS_ALWAYS_INLINE JSBool
463 JSVAL_IS_MAGIC_IMPL(jsval_layout l)
464 {
465     return l.s.tag == JSVAL_TAG_MAGIC;
466 }
467
468 static JS_ALWAYS_INLINE JSObject *
469 MAGIC_JSVAL_TO_OBJECT_OR_NULL_IMPL(jsval_layout l)
470 {
471     JS_ASSERT(JSVAL_IS_MAGIC_IMPL(l));
472     return l.s.payload.obj;
473 }
474
475 static JS_ALWAYS_INLINE JSBool
476 JSVAL_IS_OBJECT_IMPL(jsval_layout l)
477 {
478     return l.s.tag == JSVAL_TAG_OBJECT;
479 }
480
481 static JS_ALWAYS_INLINE JSBool
482 JSVAL_IS_PRIMITIVE_IMPL(jsval_layout l)
483 {
484     return (uint32)l.s.tag < (uint32)JSVAL_UPPER_EXCL_TAG_OF_PRIMITIVE_SET;
485 }
486
487 static JS_ALWAYS_INLINE JSBool
488 JSVAL_IS_OBJECT_OR_NULL_IMPL(jsval_layout l)
489 {
490     JS_ASSERT((uint32)l.s.tag <= (uint32)JSVAL_TAG_OBJECT);
491     return (uint32)l.s.tag >= (uint32)JSVAL_LOWER_INCL_TAG_OF_OBJ_OR_NULL_SET;
492 }
493
494 static JS_ALWAYS_INLINE JSObject *
495 JSVAL_TO_OBJECT_IMPL(jsval_layout l)
496 {
497     return l.s.payload.obj;
498 }
499
500 static JS_ALWAYS_INLINE jsval_layout
501 OBJECT_TO_JSVAL_IMPL(JSObject *obj)
502 {
503     jsval_layout l;
504     JS_ASSERT(obj);
505     l.s.tag = JSVAL_TAG_OBJECT;
506     l.s.payload.obj = obj;
507     return l;
508 }
509
510 static JS_ALWAYS_INLINE JSBool
511 JSVAL_IS_NULL_IMPL(jsval_layout l)
512 {
513     return l.s.tag == JSVAL_TAG_NULL;
514 }
515
516 static JS_ALWAYS_INLINE jsval_layout
517 PRIVATE_PTR_TO_JSVAL_IMPL(void *ptr)
518 {
519     jsval_layout l;
520     JS_ASSERT(((uint32)ptr & 1) == 0);
521     l.s.tag = (JSValueTag)0;
522     l.s.payload.ptr = ptr;
523     JS_ASSERT(JSVAL_IS_DOUBLE_IMPL(l));
524     return l;
525 }
526
527 static JS_ALWAYS_INLINE void *
528 JSVAL_TO_PRIVATE_PTR_IMPL(jsval_layout l)
529 {
530     return l.s.payload.ptr;
531 }
532
533 static JS_ALWAYS_INLINE JSBool
534 JSVAL_IS_GCTHING_IMPL(jsval_layout l)
535 {
536     /* gcc sometimes generates signed < without explicit casts. */
537     return (uint32)l.s.tag >= (uint32)JSVAL_LOWER_INCL_TAG_OF_GCTHING_SET;
538 }
539
540 static JS_ALWAYS_INLINE void *
541 JSVAL_TO_GCTHING_IMPL(jsval_layout l)
542 {
543     return l.s.payload.ptr;
544 }
545
546 static JS_ALWAYS_INLINE JSBool
547 JSVAL_IS_TRACEABLE_IMPL(jsval_layout l)
548 {
549     return l.s.tag == JSVAL_TAG_STRING || l.s.tag == JSVAL_TAG_OBJECT;
550 }
551
552 static JS_ALWAYS_INLINE uint32
553 JSVAL_TRACE_KIND_IMPL(jsval_layout l)
554 {
555     return (uint32)(JSBool)JSVAL_IS_STRING_IMPL(l);
556 }
557
558 #elif JS_BITS_PER_WORD == 64
559
560 #define BUILD_JSVAL(tag, payload) \
561     ((((uint64)(uint32)(tag)) << JSVAL_TAG_SHIFT) | (payload))
562
563 static JS_ALWAYS_INLINE JSBool
564 JSVAL_IS_DOUBLE_IMPL(jsval_layout l)
565 {
566     return l.asBits <= JSVAL_SHIFTED_TAG_MAX_DOUBLE;
567 }
568
569 static JS_ALWAYS_INLINE jsval_layout
570 DOUBLE_TO_JSVAL_IMPL(double d)
571 {
572     jsval_layout l;
573     l.asDouble = d;
574     JS_ASSERT(l.asBits <= JSVAL_SHIFTED_TAG_MAX_DOUBLE);
575     return l;
576 }
577
578 static JS_ALWAYS_INLINE JSBool
579 JSVAL_IS_INT32_IMPL(jsval_layout l)
580 {
581     return (uint32)(l.asBits >> JSVAL_TAG_SHIFT) == JSVAL_TAG_INT32;
582 }
583
584 static JS_ALWAYS_INLINE int32
585 JSVAL_TO_INT32_IMPL(jsval_layout l)
586 {
587     return (int32)l.asBits;
588 }
589
590 static JS_ALWAYS_INLINE jsval_layout
591 INT32_TO_JSVAL_IMPL(int32 i32)
592 {
593     jsval_layout l;
594     l.asBits = ((uint64)(uint32)i32) | JSVAL_SHIFTED_TAG_INT32;
595     return l;
596 }
597
598 static JS_ALWAYS_INLINE JSBool
599 JSVAL_IS_NUMBER_IMPL(jsval_layout l)
600 {
601     return l.asBits < JSVAL_UPPER_EXCL_SHIFTED_TAG_OF_NUMBER_SET;
602 }
603
604 static JS_ALWAYS_INLINE JSBool
605 JSVAL_IS_UNDEFINED_IMPL(jsval_layout l)
606 {
607     return l.asBits == JSVAL_SHIFTED_TAG_UNDEFINED;
608 }
609
610 static JS_ALWAYS_INLINE JSBool
611 JSVAL_IS_STRING_IMPL(jsval_layout l)
612 {
613     return (uint32)(l.asBits >> JSVAL_TAG_SHIFT) == JSVAL_TAG_STRING;
614 }
615
616 static JS_ALWAYS_INLINE jsval_layout
617 STRING_TO_JSVAL_IMPL(JSString *str)
618 {
619     jsval_layout l;
620     uint64 strBits = (uint64)str;
621     JS_ASSERT(str);
622     JS_ASSERT((strBits >> JSVAL_TAG_SHIFT) == 0);
623     l.asBits = strBits | JSVAL_SHIFTED_TAG_STRING;
624     return l;
625 }
626
627 static JS_ALWAYS_INLINE JSString *
628 JSVAL_TO_STRING_IMPL(jsval_layout l)
629 {
630     return (JSString *)(l.asBits & JSVAL_PAYLOAD_MASK);
631 }
632
633 static JS_ALWAYS_INLINE JSBool
634 JSVAL_IS_BOOLEAN_IMPL(jsval_layout l)
635 {
636     return (uint32)(l.asBits >> JSVAL_TAG_SHIFT) == JSVAL_TAG_BOOLEAN;
637 }
638
639 static JS_ALWAYS_INLINE JSBool
640 JSVAL_TO_BOOLEAN_IMPL(jsval_layout l)
641 {
642     return (JSBool)l.asBits;
643 }
644
645 static JS_ALWAYS_INLINE jsval_layout
646 BOOLEAN_TO_JSVAL_IMPL(JSBool b)
647 {
648     jsval_layout l;
649     l.asBits = ((uint64)(uint32)b) | JSVAL_SHIFTED_TAG_BOOLEAN;
650     return l;
651 }
652
653 static JS_ALWAYS_INLINE JSBool
654 JSVAL_IS_MAGIC_IMPL(jsval_layout l)
655 {
656     return (l.asBits >> JSVAL_TAG_SHIFT) == JSVAL_TAG_MAGIC;
657 }
658
659 static JS_ALWAYS_INLINE JSObject *
660 MAGIC_JSVAL_TO_OBJECT_OR_NULL_IMPL(jsval_layout l)
661 {
662     uint64 ptrBits = l.asBits & JSVAL_PAYLOAD_MASK;
663     JS_ASSERT(JSVAL_IS_MAGIC_IMPL(l));
664     JS_ASSERT((ptrBits >> JSVAL_TAG_SHIFT) == 0);
665     return (JSObject *)ptrBits;
666 }
667
668 static JS_ALWAYS_INLINE JSBool
669 JSVAL_IS_PRIMITIVE_IMPL(jsval_layout l)
670 {
671     return l.asBits < JSVAL_UPPER_EXCL_SHIFTED_TAG_OF_PRIMITIVE_SET;
672 }
673
674 static JS_ALWAYS_INLINE JSBool
675 JSVAL_IS_OBJECT_IMPL(jsval_layout l)
676 {
677     JS_ASSERT((l.asBits >> JSVAL_TAG_SHIFT) <= JSVAL_SHIFTED_TAG_OBJECT);
678     return l.asBits >= JSVAL_SHIFTED_TAG_OBJECT;
679 }
680
681 static JS_ALWAYS_INLINE JSBool
682 JSVAL_IS_OBJECT_OR_NULL_IMPL(jsval_layout l)
683 {
684     JS_ASSERT((l.asBits >> JSVAL_TAG_SHIFT) <= JSVAL_TAG_OBJECT);
685     return l.asBits >= JSVAL_LOWER_INCL_SHIFTED_TAG_OF_OBJ_OR_NULL_SET;
686 }
687
688 static JS_ALWAYS_INLINE JSObject *
689 JSVAL_TO_OBJECT_IMPL(jsval_layout l)
690 {
691     uint64 ptrBits = l.asBits & JSVAL_PAYLOAD_MASK;
692     JS_ASSERT((ptrBits & 0x7) == 0);
693     return (JSObject *)ptrBits;
694 }
695
696 static JS_ALWAYS_INLINE jsval_layout
697 OBJECT_TO_JSVAL_IMPL(JSObject *obj)
698 {
699     jsval_layout l;
700     uint64 objBits = (uint64)obj;
701     JS_ASSERT(obj);
702     JS_ASSERT((objBits >> JSVAL_TAG_SHIFT) == 0);
703     l.asBits = objBits | JSVAL_SHIFTED_TAG_OBJECT;
704     return l;
705 }
706
707 static JS_ALWAYS_INLINE JSBool
708 JSVAL_IS_NULL_IMPL(jsval_layout l)
709 {
710     return l.asBits == JSVAL_SHIFTED_TAG_NULL;
711 }
712
713 static JS_ALWAYS_INLINE JSBool
714 JSVAL_IS_GCTHING_IMPL(jsval_layout l)
715 {
716     return l.asBits >= JSVAL_LOWER_INCL_SHIFTED_TAG_OF_GCTHING_SET;
717 }
718
719 static JS_ALWAYS_INLINE void *
720 JSVAL_TO_GCTHING_IMPL(jsval_layout l)
721 {
722     uint64 ptrBits = l.asBits & JSVAL_PAYLOAD_MASK;
723     JS_ASSERT((ptrBits & 0x7) == 0);
724     return (void *)ptrBits;
725 }
726
727 static JS_ALWAYS_INLINE JSBool
728 JSVAL_IS_TRACEABLE_IMPL(jsval_layout l)
729 {
730     return JSVAL_IS_GCTHING_IMPL(l) && !JSVAL_IS_NULL_IMPL(l);
731 }
732
733 static JS_ALWAYS_INLINE uint32
734 JSVAL_TRACE_KIND_IMPL(jsval_layout l)
735 {
736     return (uint32)(JSBool)!(JSVAL_IS_OBJECT_IMPL(l));
737 }
738
739 static JS_ALWAYS_INLINE jsval_layout
740 PRIVATE_PTR_TO_JSVAL_IMPL(void *ptr)
741 {
742     jsval_layout l;
743     uint64 ptrBits = (uint64)ptr;
744     JS_ASSERT((ptrBits & 1) == 0);
745     l.asBits = ptrBits >> 1;
746     JS_ASSERT(JSVAL_IS_DOUBLE_IMPL(l));
747     return l;
748 }
749
750 static JS_ALWAYS_INLINE void *
751 JSVAL_TO_PRIVATE_PTR_IMPL(jsval_layout l)
752 {
753     JS_ASSERT((l.asBits & 0x8000000000000000LL) == 0);
754     return (void *)(l.asBits << 1);
755 }
756
757 #endif
758
759 static JS_ALWAYS_INLINE double
760 JS_CANONICALIZE_NAN(double d)
761 {
762     if (JS_UNLIKELY(d != d)) {
763         jsval_layout l;
764         l.asBits = 0x7FF8000000000000LL;
765         return l.asDouble;
766     }
767     return d;
768 }
769
770 /* See JS_USE_JSVAL_JSID_STRUCT_TYPES comment in jsapi.h. */
771 #if defined(DEBUG) && !defined(JS_NO_JSVAL_JSID_STRUCT_TYPES)
772 # define JS_USE_JSVAL_JSID_STRUCT_TYPES
773 #endif
774
775 #ifdef JS_USE_JSVAL_JSID_STRUCT_TYPES
776
777 typedef JSVAL_ALIGNMENT jsval_layout   jsval;
778 typedef struct jsid { size_t asBits; } jsid;
779
780 #if defined(__cplusplus)
781 extern "C++"
782 {
783     static JS_ALWAYS_INLINE bool
784     operator==(jsid lhs, jsid rhs)
785     {
786         return lhs.asBits == rhs.asBits;
787     }
788
789     static JS_ALWAYS_INLINE bool
790     operator!=(jsid lhs, jsid rhs)
791     {
792         return lhs.asBits != rhs.asBits;
793     }
794
795     static JS_ALWAYS_INLINE bool
796     operator==(jsval lhs, jsval rhs)
797     {
798         return lhs.asBits == rhs.asBits;
799     }
800
801     static JS_ALWAYS_INLINE bool
802     operator!=(jsval lhs, jsval rhs)
803     {
804         return lhs.asBits != rhs.asBits;
805     }
806 }
807 # endif /* defined(__cplusplus) */
808
809 /* Internal helper macros */
810 #define JSVAL_BITS(v)    ((v).asBits)
811 #define JSVAL_FROM_LAYOUT(l) (l)
812 #define IMPL_TO_JSVAL(v) (v)
813 #define JSID_BITS(id)    ((id).asBits)
814
815 #else /* defined(JS_USE_JSVAL_JSID_STRUCT_TYPES) */
816
817 /* Use different primitive types so overloading works. */
818 typedef JSVAL_ALIGNMENT uint64 jsval;
819 typedef ptrdiff_t              jsid;
820
821 /* Internal helper macros */
822 #define JSVAL_BITS(v)    (v)
823 #define JSVAL_FROM_LAYOUT(l) ((l).asBits)
824 #define IMPL_TO_JSVAL(v) ((v).asBits)
825 #define JSID_BITS(id)    (id)
826
827 #endif /* defined(JS_USE_JSVAL_JSID_STRUCT_TYPES) */
828
829 JS_END_EXTERN_C
830
831 #endif /* jsvalimpl_h__ */