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 76938846 : 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 76938846 : if (d != 0)
72 72462979 : return JS_FALSE;
73 4475867 : x.d = d;
74 4475867 : return (x.s.hi & JSDOUBLE_HI32_SIGNBIT) != 0;
75 : }
76 :
77 : static JS_ALWAYS_INLINE JSBool
78 76856067 : JSDOUBLE_IS_INT32(double d, int32_t* pi)
79 : {
80 76856067 : if (JSDOUBLE_IS_NEGZERO(d))
81 233675 : return JS_FALSE;
82 76622392 : 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_MEMBER(id, type, value) id = (type)value,
119 : # define JS_LAST_ENUM_MEMBER(id, type, value) id = (type)value
120 : # define JS_ENUM_FOOTER(id)
121 : #else
122 : # define JS_ENUM_HEADER(id, type) enum id
123 : # define JS_ENUM_MEMBER(id, type, value) id = (type)value,
124 : # define JS_LAST_ENUM_MEMBER(id, type, value) id = (type)value
125 : # define JS_ENUM_FOOTER(id) __attribute__((packed))
126 : #endif
127 :
128 : /* Remember to propagate changes to the C defines below. */
129 : JS_ENUM_HEADER(JSValueType, uint8_t)
130 : {
131 : JSVAL_TYPE_DOUBLE = 0x00,
132 : JSVAL_TYPE_INT32 = 0x01,
133 : JSVAL_TYPE_UNDEFINED = 0x02,
134 : JSVAL_TYPE_BOOLEAN = 0x03,
135 : JSVAL_TYPE_MAGIC = 0x04,
136 : JSVAL_TYPE_STRING = 0x05,
137 : JSVAL_TYPE_NULL = 0x06,
138 : JSVAL_TYPE_OBJECT = 0x07,
139 :
140 : /* These never appear in a jsval; they are only provided as an out-of-band value. */
141 : JSVAL_TYPE_UNKNOWN = 0x20,
142 : JSVAL_TYPE_MISSING = 0x21
143 : } JS_ENUM_FOOTER(JSValueType);
144 :
145 : JS_STATIC_ASSERT(sizeof(JSValueType) == 1);
146 :
147 : #if JS_BITS_PER_WORD == 32
148 :
149 : /* Remember to propagate changes to the C defines below. */
150 : JS_ENUM_HEADER(JSValueTag, uint32_t)
151 : {
152 : JSVAL_TAG_CLEAR = 0xFFFFFF80,
153 : JSVAL_TAG_INT32 = JSVAL_TAG_CLEAR | JSVAL_TYPE_INT32,
154 : JSVAL_TAG_UNDEFINED = JSVAL_TAG_CLEAR | JSVAL_TYPE_UNDEFINED,
155 : JSVAL_TAG_STRING = JSVAL_TAG_CLEAR | JSVAL_TYPE_STRING,
156 : JSVAL_TAG_BOOLEAN = JSVAL_TAG_CLEAR | JSVAL_TYPE_BOOLEAN,
157 : JSVAL_TAG_MAGIC = JSVAL_TAG_CLEAR | JSVAL_TYPE_MAGIC,
158 : JSVAL_TAG_NULL = JSVAL_TAG_CLEAR | JSVAL_TYPE_NULL,
159 : JSVAL_TAG_OBJECT = JSVAL_TAG_CLEAR | JSVAL_TYPE_OBJECT
160 : } JS_ENUM_FOOTER(JSValueTag);
161 :
162 : JS_STATIC_ASSERT(sizeof(JSValueTag) == 4);
163 :
164 : #elif JS_BITS_PER_WORD == 64
165 :
166 : /* Remember to propagate changes to the C defines below. */
167 : JS_ENUM_HEADER(JSValueTag, uint32_t)
168 : {
169 : JSVAL_TAG_MAX_DOUBLE = 0x1FFF0,
170 : JSVAL_TAG_INT32 = JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_INT32,
171 : JSVAL_TAG_UNDEFINED = JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_UNDEFINED,
172 : JSVAL_TAG_STRING = JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_STRING,
173 : JSVAL_TAG_BOOLEAN = JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_BOOLEAN,
174 : JSVAL_TAG_MAGIC = JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_MAGIC,
175 : JSVAL_TAG_NULL = JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_NULL,
176 : JSVAL_TAG_OBJECT = JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_OBJECT
177 : } JS_ENUM_FOOTER(JSValueTag);
178 :
179 : JS_STATIC_ASSERT(sizeof(JSValueTag) == sizeof(uint32_t));
180 :
181 : JS_ENUM_HEADER(JSValueShiftedTag, uint64_t)
182 : {
183 : JSVAL_SHIFTED_TAG_MAX_DOUBLE = ((((uint64_t)JSVAL_TAG_MAX_DOUBLE) << JSVAL_TAG_SHIFT) | 0xFFFFFFFF),
184 : JSVAL_SHIFTED_TAG_INT32 = (((uint64_t)JSVAL_TAG_INT32) << JSVAL_TAG_SHIFT),
185 : JSVAL_SHIFTED_TAG_UNDEFINED = (((uint64_t)JSVAL_TAG_UNDEFINED) << JSVAL_TAG_SHIFT),
186 : JSVAL_SHIFTED_TAG_STRING = (((uint64_t)JSVAL_TAG_STRING) << JSVAL_TAG_SHIFT),
187 : JSVAL_SHIFTED_TAG_BOOLEAN = (((uint64_t)JSVAL_TAG_BOOLEAN) << JSVAL_TAG_SHIFT),
188 : JSVAL_SHIFTED_TAG_MAGIC = (((uint64_t)JSVAL_TAG_MAGIC) << JSVAL_TAG_SHIFT),
189 : JSVAL_SHIFTED_TAG_NULL = (((uint64_t)JSVAL_TAG_NULL) << JSVAL_TAG_SHIFT),
190 : JSVAL_SHIFTED_TAG_OBJECT = (((uint64_t)JSVAL_TAG_OBJECT) << JSVAL_TAG_SHIFT)
191 : } JS_ENUM_FOOTER(JSValueShiftedTag);
192 :
193 : JS_STATIC_ASSERT(sizeof(JSValueShiftedTag) == sizeof(uint64_t));
194 :
195 : #endif
196 :
197 : #else /* defined(__cplusplus) */
198 :
199 : typedef uint8_t JSValueType;
200 : #define JSVAL_TYPE_DOUBLE ((uint8_t)0x00)
201 : #define JSVAL_TYPE_INT32 ((uint8_t)0x01)
202 : #define JSVAL_TYPE_UNDEFINED ((uint8_t)0x02)
203 : #define JSVAL_TYPE_BOOLEAN ((uint8_t)0x03)
204 : #define JSVAL_TYPE_MAGIC ((uint8_t)0x04)
205 : #define JSVAL_TYPE_STRING ((uint8_t)0x05)
206 : #define JSVAL_TYPE_NULL ((uint8_t)0x06)
207 : #define JSVAL_TYPE_OBJECT ((uint8_t)0x07)
208 : #define JSVAL_TYPE_UNKNOWN ((uint8_t)0x20)
209 :
210 : #if JS_BITS_PER_WORD == 32
211 :
212 : typedef uint32_t JSValueTag;
213 : #define JSVAL_TAG_CLEAR ((uint32_t)(0xFFFFFF80))
214 : #define JSVAL_TAG_INT32 ((uint32_t)(JSVAL_TAG_CLEAR | JSVAL_TYPE_INT32))
215 : #define JSVAL_TAG_UNDEFINED ((uint32_t)(JSVAL_TAG_CLEAR | JSVAL_TYPE_UNDEFINED))
216 : #define JSVAL_TAG_STRING ((uint32_t)(JSVAL_TAG_CLEAR | JSVAL_TYPE_STRING))
217 : #define JSVAL_TAG_BOOLEAN ((uint32_t)(JSVAL_TAG_CLEAR | JSVAL_TYPE_BOOLEAN))
218 : #define JSVAL_TAG_MAGIC ((uint32_t)(JSVAL_TAG_CLEAR | JSVAL_TYPE_MAGIC))
219 : #define JSVAL_TAG_NULL ((uint32_t)(JSVAL_TAG_CLEAR | JSVAL_TYPE_NULL))
220 : #define JSVAL_TAG_OBJECT ((uint32_t)(JSVAL_TAG_CLEAR | JSVAL_TYPE_OBJECT))
221 :
222 : #elif JS_BITS_PER_WORD == 64
223 :
224 : typedef uint32_t JSValueTag;
225 : #define JSVAL_TAG_MAX_DOUBLE ((uint32_t)(0x1FFF0))
226 : #define JSVAL_TAG_INT32 (uint32_t)(JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_INT32)
227 : #define JSVAL_TAG_UNDEFINED (uint32_t)(JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_UNDEFINED)
228 : #define JSVAL_TAG_STRING (uint32_t)(JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_STRING)
229 : #define JSVAL_TAG_BOOLEAN (uint32_t)(JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_BOOLEAN)
230 : #define JSVAL_TAG_MAGIC (uint32_t)(JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_MAGIC)
231 : #define JSVAL_TAG_NULL (uint32_t)(JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_NULL)
232 : #define JSVAL_TAG_OBJECT (uint32_t)(JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_OBJECT)
233 :
234 : typedef uint64_t JSValueShiftedTag;
235 : #define JSVAL_SHIFTED_TAG_MAX_DOUBLE ((((uint64_t)JSVAL_TAG_MAX_DOUBLE) << JSVAL_TAG_SHIFT) | 0xFFFFFFFF)
236 : #define JSVAL_SHIFTED_TAG_INT32 (((uint64_t)JSVAL_TAG_INT32) << JSVAL_TAG_SHIFT)
237 : #define JSVAL_SHIFTED_TAG_UNDEFINED (((uint64_t)JSVAL_TAG_UNDEFINED) << JSVAL_TAG_SHIFT)
238 : #define JSVAL_SHIFTED_TAG_STRING (((uint64_t)JSVAL_TAG_STRING) << JSVAL_TAG_SHIFT)
239 : #define JSVAL_SHIFTED_TAG_BOOLEAN (((uint64_t)JSVAL_TAG_BOOLEAN) << JSVAL_TAG_SHIFT)
240 : #define JSVAL_SHIFTED_TAG_MAGIC (((uint64_t)JSVAL_TAG_MAGIC) << JSVAL_TAG_SHIFT)
241 : #define JSVAL_SHIFTED_TAG_NULL (((uint64_t)JSVAL_TAG_NULL) << JSVAL_TAG_SHIFT)
242 : #define JSVAL_SHIFTED_TAG_OBJECT (((uint64_t)JSVAL_TAG_OBJECT) << JSVAL_TAG_SHIFT)
243 :
244 : #endif /* JS_BITS_PER_WORD */
245 : #endif /* defined(__cplusplus) && !defined(__SUNPRO_CC) */
246 :
247 : #define JSVAL_LOWER_INCL_TYPE_OF_OBJ_OR_NULL_SET JSVAL_TYPE_NULL
248 : #define JSVAL_UPPER_EXCL_TYPE_OF_PRIMITIVE_SET JSVAL_TYPE_OBJECT
249 : #define JSVAL_UPPER_INCL_TYPE_OF_NUMBER_SET JSVAL_TYPE_INT32
250 : #define JSVAL_LOWER_INCL_TYPE_OF_PTR_PAYLOAD_SET JSVAL_TYPE_MAGIC
251 :
252 : #if JS_BITS_PER_WORD == 32
253 :
254 : #define JSVAL_TYPE_TO_TAG(type) ((JSValueTag)(JSVAL_TAG_CLEAR | (type)))
255 :
256 : #define JSVAL_LOWER_INCL_TAG_OF_OBJ_OR_NULL_SET JSVAL_TAG_NULL
257 : #define JSVAL_UPPER_EXCL_TAG_OF_PRIMITIVE_SET JSVAL_TAG_OBJECT
258 : #define JSVAL_UPPER_INCL_TAG_OF_NUMBER_SET JSVAL_TAG_INT32
259 : #define JSVAL_LOWER_INCL_TAG_OF_GCTHING_SET JSVAL_TAG_STRING
260 :
261 : #elif JS_BITS_PER_WORD == 64
262 :
263 : #define JSVAL_PAYLOAD_MASK 0x00007FFFFFFFFFFFLL
264 : #define JSVAL_TAG_MASK 0xFFFF800000000000LL
265 : #define JSVAL_TYPE_TO_TAG(type) ((JSValueTag)(JSVAL_TAG_MAX_DOUBLE | (type)))
266 : #define JSVAL_TYPE_TO_SHIFTED_TAG(type) (((uint64_t)JSVAL_TYPE_TO_TAG(type)) << JSVAL_TAG_SHIFT)
267 :
268 : #define JSVAL_LOWER_INCL_SHIFTED_TAG_OF_OBJ_OR_NULL_SET JSVAL_SHIFTED_TAG_NULL
269 : #define JSVAL_UPPER_EXCL_SHIFTED_TAG_OF_PRIMITIVE_SET JSVAL_SHIFTED_TAG_OBJECT
270 : #define JSVAL_UPPER_EXCL_SHIFTED_TAG_OF_NUMBER_SET JSVAL_SHIFTED_TAG_UNDEFINED
271 : #define JSVAL_LOWER_INCL_SHIFTED_TAG_OF_GCTHING_SET JSVAL_SHIFTED_TAG_STRING
272 :
273 : #endif /* JS_BITS_PER_WORD */
274 :
275 : typedef enum JSWhyMagic
276 : {
277 : JS_ARRAY_HOLE, /* a hole in a dense array */
278 : JS_ARGS_HOLE, /* a hole in the args object's array */
279 : JS_NATIVE_ENUMERATE, /* indicates that a custom enumerate hook forwarded
280 : * to JS_EnumerateState, which really means the object can be
281 : * enumerated like a native object. */
282 : JS_NO_ITER_VALUE, /* there is not a pending iterator value */
283 : JS_GENERATOR_CLOSING, /* exception value thrown when closing a generator */
284 : JS_NO_CONSTANT, /* compiler sentinel value */
285 : JS_THIS_POISON, /* used in debug builds to catch tracing errors */
286 : JS_ARG_POISON, /* used in debug builds to catch tracing errors */
287 : JS_SERIALIZE_NO_NODE, /* an empty subnode in the AST serializer */
288 : JS_LAZY_ARGUMENTS, /* lazy arguments value on the stack */
289 : JS_UNASSIGNED_ARGUMENTS, /* the initial value of callobj.arguments */
290 : JS_IS_CONSTRUCTING, /* magic value passed to natives to indicate construction */
291 : JS_GENERIC_MAGIC /* for local use */
292 : } JSWhyMagic;
293 :
294 : #if defined(IS_LITTLE_ENDIAN)
295 : # if JS_BITS_PER_WORD == 32
296 : typedef union jsval_layout
297 : {
298 : uint64_t asBits;
299 : struct {
300 : union {
301 : int32_t i32;
302 : uint32_t u32;
303 : JSBool boo;
304 : JSString *str;
305 : JSObject *obj;
306 : void *ptr;
307 : JSWhyMagic why;
308 : size_t word;
309 : } payload;
310 : JSValueTag tag;
311 : } s;
312 : double asDouble;
313 : void *asPtr;
314 : } JSVAL_ALIGNMENT jsval_layout;
315 : # elif JS_BITS_PER_WORD == 64
316 : typedef union jsval_layout
317 : {
318 : uint64_t asBits;
319 : #if (!defined(_WIN64) && defined(__cplusplus))
320 : /* MSVC does not pack these correctly :-( */
321 : struct {
322 : uint64_t payload47 : 47;
323 : JSValueTag tag : 17;
324 : } debugView;
325 : #endif
326 : struct {
327 : union {
328 : int32_t i32;
329 : uint32_t u32;
330 : JSWhyMagic why;
331 : } payload;
332 : } s;
333 : double asDouble;
334 : void *asPtr;
335 : size_t asWord;
336 : } JSVAL_ALIGNMENT jsval_layout;
337 : # endif /* JS_BITS_PER_WORD */
338 : #else /* defined(IS_LITTLE_ENDIAN) */
339 : # if JS_BITS_PER_WORD == 32
340 : typedef union jsval_layout
341 : {
342 : uint64_t asBits;
343 : struct {
344 : JSValueTag tag;
345 : union {
346 : int32_t i32;
347 : uint32_t u32;
348 : JSBool boo;
349 : JSString *str;
350 : JSObject *obj;
351 : void *ptr;
352 : JSWhyMagic why;
353 : size_t word;
354 : } payload;
355 : } s;
356 : double asDouble;
357 : void *asPtr;
358 : } JSVAL_ALIGNMENT jsval_layout;
359 : # elif JS_BITS_PER_WORD == 64
360 : typedef union jsval_layout
361 : {
362 : uint64_t asBits;
363 : struct {
364 : JSValueTag tag : 17;
365 : uint64_t payload47 : 47;
366 : } debugView;
367 : struct {
368 : uint32_t padding;
369 : union {
370 : int32_t i32;
371 : uint32_t u32;
372 : JSWhyMagic why;
373 : } payload;
374 : } s;
375 : double asDouble;
376 : void *asPtr;
377 : size_t asWord;
378 : } JSVAL_ALIGNMENT jsval_layout;
379 : # endif /* JS_BITS_PER_WORD */
380 : #endif /* defined(IS_LITTLE_ENDIAN) */
381 :
382 : JS_STATIC_ASSERT(sizeof(jsval_layout) == 8);
383 :
384 : #if JS_BITS_PER_WORD == 32
385 :
386 : /*
387 : * N.B. GCC, in some but not all cases, chooses to emit signed comparison of
388 : * JSValueTag even though its underlying type has been forced to be uint32_t.
389 : * Thus, all comparisons should explicitly cast operands to uint32_t.
390 : */
391 :
392 : static JS_ALWAYS_INLINE jsval_layout
393 165102824 : BUILD_JSVAL(JSValueTag tag, uint32_t payload)
394 : {
395 : jsval_layout l;
396 165102824 : l.asBits = (((uint64_t)(uint32_t)tag) << 32) | payload;
397 : return l;
398 : }
399 :
400 : static JS_ALWAYS_INLINE JSBool
401 408119577 : JSVAL_IS_DOUBLE_IMPL(jsval_layout l)
402 : {
403 408119577 : return (uint32_t)l.s.tag <= (uint32_t)JSVAL_TAG_CLEAR;
404 : }
405 :
406 : static JS_ALWAYS_INLINE jsval_layout
407 17660707 : DOUBLE_TO_JSVAL_IMPL(double d)
408 : {
409 : jsval_layout l;
410 17660707 : l.asDouble = d;
411 17660707 : JS_ASSERT(JSVAL_IS_DOUBLE_IMPL(l));
412 : return l;
413 : }
414 :
415 : static JS_ALWAYS_INLINE JSBool
416 1973026168 : JSVAL_IS_INT32_IMPL(jsval_layout l)
417 : {
418 1973026168 : return l.s.tag == JSVAL_TAG_INT32;
419 : }
420 :
421 : static JS_ALWAYS_INLINE int32_t
422 1057346885 : JSVAL_TO_INT32_IMPL(jsval_layout l)
423 : {
424 1057346885 : return l.s.payload.i32;
425 : }
426 :
427 : static JS_ALWAYS_INLINE jsval_layout
428 683640013 : INT32_TO_JSVAL_IMPL(int32_t i)
429 : {
430 : jsval_layout l;
431 683640013 : l.s.tag = JSVAL_TAG_INT32;
432 683640013 : l.s.payload.i32 = i;
433 : return l;
434 : }
435 :
436 : static JS_ALWAYS_INLINE JSBool
437 183672686 : JSVAL_IS_NUMBER_IMPL(jsval_layout l)
438 : {
439 183672686 : JSValueTag tag = l.s.tag;
440 183672686 : JS_ASSERT(tag != JSVAL_TAG_CLEAR);
441 183672686 : return (uint32_t)tag <= (uint32_t)JSVAL_UPPER_INCL_TAG_OF_NUMBER_SET;
442 : }
443 :
444 : static JS_ALWAYS_INLINE JSBool
445 67629518 : JSVAL_IS_UNDEFINED_IMPL(jsval_layout l)
446 : {
447 67629518 : return l.s.tag == JSVAL_TAG_UNDEFINED;
448 : }
449 :
450 : static JS_ALWAYS_INLINE JSBool
451 1140388285 : JSVAL_IS_STRING_IMPL(jsval_layout l)
452 : {
453 1140388285 : return l.s.tag == JSVAL_TAG_STRING;
454 : }
455 :
456 : static JS_ALWAYS_INLINE jsval_layout
457 121103590 : STRING_TO_JSVAL_IMPL(JSString *str)
458 : {
459 : jsval_layout l;
460 121103590 : JS_ASSERT(str);
461 121103590 : l.s.tag = JSVAL_TAG_STRING;
462 121103590 : l.s.payload.str = str;
463 : return l;
464 : }
465 :
466 : static JS_ALWAYS_INLINE JSString *
467 148991617 : JSVAL_TO_STRING_IMPL(jsval_layout l)
468 : {
469 148991617 : return l.s.payload.str;
470 : }
471 :
472 : static JS_ALWAYS_INLINE JSBool
473 58984169 : JSVAL_IS_BOOLEAN_IMPL(jsval_layout l)
474 : {
475 58984169 : return l.s.tag == JSVAL_TAG_BOOLEAN;
476 : }
477 :
478 : static JS_ALWAYS_INLINE JSBool
479 32929620 : JSVAL_TO_BOOLEAN_IMPL(jsval_layout l)
480 : {
481 32929620 : return l.s.payload.boo;
482 : }
483 :
484 : static JS_ALWAYS_INLINE jsval_layout
485 31728600 : BOOLEAN_TO_JSVAL_IMPL(JSBool b)
486 : {
487 : jsval_layout l;
488 31728600 : JS_ASSERT(b == JS_TRUE || b == JS_FALSE);
489 31728600 : l.s.tag = JSVAL_TAG_BOOLEAN;
490 31728600 : l.s.payload.boo = b;
491 : return l;
492 : }
493 :
494 : static JS_ALWAYS_INLINE JSBool
495 493814485 : JSVAL_IS_MAGIC_IMPL(jsval_layout l)
496 : {
497 493814485 : return l.s.tag == JSVAL_TAG_MAGIC;
498 : }
499 :
500 : static JS_ALWAYS_INLINE JSBool
501 2079048232 : JSVAL_IS_OBJECT_IMPL(jsval_layout l)
502 : {
503 2079048232 : return l.s.tag == JSVAL_TAG_OBJECT;
504 : }
505 :
506 : static JS_ALWAYS_INLINE JSBool
507 77608048 : JSVAL_IS_PRIMITIVE_IMPL(jsval_layout l)
508 : {
509 77608048 : return (uint32_t)l.s.tag < (uint32_t)JSVAL_UPPER_EXCL_TAG_OF_PRIMITIVE_SET;
510 : }
511 :
512 : static JS_ALWAYS_INLINE JSBool
513 3306558 : JSVAL_IS_OBJECT_OR_NULL_IMPL(jsval_layout l)
514 : {
515 3306558 : JS_ASSERT((uint32_t)l.s.tag <= (uint32_t)JSVAL_TAG_OBJECT);
516 3306558 : return (uint32_t)l.s.tag >= (uint32_t)JSVAL_LOWER_INCL_TAG_OF_OBJ_OR_NULL_SET;
517 : }
518 :
519 : static JS_ALWAYS_INLINE JSObject *
520 627103880 : JSVAL_TO_OBJECT_IMPL(jsval_layout l)
521 : {
522 627103880 : return l.s.payload.obj;
523 : }
524 :
525 : static JS_ALWAYS_INLINE jsval_layout
526 104073540 : OBJECT_TO_JSVAL_IMPL(JSObject *obj)
527 : {
528 : jsval_layout l;
529 104073540 : JS_ASSERT(obj);
530 104073540 : l.s.tag = JSVAL_TAG_OBJECT;
531 104073540 : l.s.payload.obj = obj;
532 : return l;
533 : }
534 :
535 : static JS_ALWAYS_INLINE JSBool
536 80406136 : JSVAL_IS_NULL_IMPL(jsval_layout l)
537 : {
538 80406136 : return l.s.tag == JSVAL_TAG_NULL;
539 : }
540 :
541 : static JS_ALWAYS_INLINE jsval_layout
542 4485935 : PRIVATE_PTR_TO_JSVAL_IMPL(void *ptr)
543 : {
544 : jsval_layout l;
545 4485935 : JS_ASSERT(((uint32_t)ptr & 1) == 0);
546 4485935 : l.s.tag = (JSValueTag)0;
547 4485935 : l.s.payload.ptr = ptr;
548 4485935 : JS_ASSERT(JSVAL_IS_DOUBLE_IMPL(l));
549 : return l;
550 : }
551 :
552 : static JS_ALWAYS_INLINE void *
553 5867162 : JSVAL_TO_PRIVATE_PTR_IMPL(jsval_layout l)
554 : {
555 5867162 : return l.s.payload.ptr;
556 : }
557 :
558 : static JS_ALWAYS_INLINE JSBool
559 29886311 : JSVAL_IS_GCTHING_IMPL(jsval_layout l)
560 : {
561 : /* gcc sometimes generates signed < without explicit casts. */
562 29886311 : return (uint32_t)l.s.tag >= (uint32_t)JSVAL_LOWER_INCL_TAG_OF_GCTHING_SET;
563 : }
564 :
565 : static JS_ALWAYS_INLINE void *
566 29886017 : JSVAL_TO_GCTHING_IMPL(jsval_layout l)
567 : {
568 29886017 : return l.s.payload.ptr;
569 : }
570 :
571 : static JS_ALWAYS_INLINE JSBool
572 128324141 : JSVAL_IS_TRACEABLE_IMPL(jsval_layout l)
573 : {
574 128324141 : return l.s.tag == JSVAL_TAG_STRING || l.s.tag == JSVAL_TAG_OBJECT;
575 : }
576 :
577 : static JS_ALWAYS_INLINE uint32_t
578 10203631 : JSVAL_TRACE_KIND_IMPL(jsval_layout l)
579 : {
580 10203631 : return (uint32_t)(JSBool)JSVAL_IS_STRING_IMPL(l);
581 : }
582 :
583 : static JS_ALWAYS_INLINE JSBool
584 306 : JSVAL_IS_SPECIFIC_INT32_IMPL(jsval_layout l, int32_t i32)
585 : {
586 306 : return l.s.tag == JSVAL_TAG_INT32 && l.s.payload.i32 == i32;
587 : }
588 :
589 : static JS_ALWAYS_INLINE JSBool
590 45966853 : JSVAL_IS_SPECIFIC_BOOLEAN(jsval_layout l, JSBool b)
591 : {
592 45966853 : return (l.s.tag == JSVAL_TAG_BOOLEAN) && (l.s.payload.boo == b);
593 : }
594 :
595 : static JS_ALWAYS_INLINE jsval_layout
596 59409121 : MAGIC_TO_JSVAL_IMPL(JSWhyMagic why)
597 : {
598 : jsval_layout l;
599 59409121 : l.s.tag = JSVAL_TAG_MAGIC;
600 59409121 : l.s.payload.why = why;
601 : return l;
602 : }
603 :
604 : static JS_ALWAYS_INLINE JSBool
605 18123089 : JSVAL_SAME_TYPE_IMPL(jsval_layout lhs, jsval_layout rhs)
606 : {
607 18123089 : JSValueTag ltag = lhs.s.tag, rtag = rhs.s.tag;
608 18123089 : return ltag == rtag || (ltag < JSVAL_TAG_CLEAR && rtag < JSVAL_TAG_CLEAR);
609 : }
610 :
611 : static JS_ALWAYS_INLINE jsval_layout
612 108194 : PRIVATE_UINT32_TO_JSVAL_IMPL(uint32_t ui)
613 : {
614 : jsval_layout l;
615 108194 : l.s.tag = (JSValueTag)0;
616 108194 : l.s.payload.u32 = ui;
617 108194 : JS_ASSERT(JSVAL_IS_DOUBLE_IMPL(l));
618 : return l;
619 : }
620 :
621 : static JS_ALWAYS_INLINE uint32_t
622 178052 : JSVAL_TO_PRIVATE_UINT32_IMPL(jsval_layout l)
623 : {
624 178052 : return l.s.payload.u32;
625 : }
626 :
627 : static JS_ALWAYS_INLINE JSValueType
628 118259049 : JSVAL_EXTRACT_NON_DOUBLE_TYPE_IMPL(jsval_layout l)
629 : {
630 118259049 : uint32_t type = l.s.tag & 0xF;
631 118259049 : JS_ASSERT(type > JSVAL_TYPE_DOUBLE);
632 118259049 : return (JSValueType)type;
633 : }
634 :
635 : #elif JS_BITS_PER_WORD == 64
636 :
637 : static JS_ALWAYS_INLINE jsval_layout
638 : BUILD_JSVAL(JSValueTag tag, uint64_t payload)
639 : {
640 : jsval_layout l;
641 : l.asBits = (((uint64_t)(uint32_t)tag) << JSVAL_TAG_SHIFT) | payload;
642 : return l;
643 : }
644 :
645 : static JS_ALWAYS_INLINE JSBool
646 : JSVAL_IS_DOUBLE_IMPL(jsval_layout l)
647 : {
648 : return l.asBits <= JSVAL_SHIFTED_TAG_MAX_DOUBLE;
649 : }
650 :
651 : static JS_ALWAYS_INLINE jsval_layout
652 : DOUBLE_TO_JSVAL_IMPL(double d)
653 : {
654 : jsval_layout l;
655 : l.asDouble = d;
656 : JS_ASSERT(l.asBits <= JSVAL_SHIFTED_TAG_MAX_DOUBLE);
657 : return l;
658 : }
659 :
660 : static JS_ALWAYS_INLINE JSBool
661 : JSVAL_IS_INT32_IMPL(jsval_layout l)
662 : {
663 : return (uint32_t)(l.asBits >> JSVAL_TAG_SHIFT) == JSVAL_TAG_INT32;
664 : }
665 :
666 : static JS_ALWAYS_INLINE int32_t
667 : JSVAL_TO_INT32_IMPL(jsval_layout l)
668 : {
669 : return (int32_t)l.asBits;
670 : }
671 :
672 : static JS_ALWAYS_INLINE jsval_layout
673 : INT32_TO_JSVAL_IMPL(int32_t i32)
674 : {
675 : jsval_layout l;
676 : l.asBits = ((uint64_t)(uint32_t)i32) | JSVAL_SHIFTED_TAG_INT32;
677 : return l;
678 : }
679 :
680 : static JS_ALWAYS_INLINE JSBool
681 : JSVAL_IS_NUMBER_IMPL(jsval_layout l)
682 : {
683 : return l.asBits < JSVAL_UPPER_EXCL_SHIFTED_TAG_OF_NUMBER_SET;
684 : }
685 :
686 : static JS_ALWAYS_INLINE JSBool
687 : JSVAL_IS_UNDEFINED_IMPL(jsval_layout l)
688 : {
689 : return l.asBits == JSVAL_SHIFTED_TAG_UNDEFINED;
690 : }
691 :
692 : static JS_ALWAYS_INLINE JSBool
693 : JSVAL_IS_STRING_IMPL(jsval_layout l)
694 : {
695 : return (uint32_t)(l.asBits >> JSVAL_TAG_SHIFT) == JSVAL_TAG_STRING;
696 : }
697 :
698 : static JS_ALWAYS_INLINE jsval_layout
699 : STRING_TO_JSVAL_IMPL(JSString *str)
700 : {
701 : jsval_layout l;
702 : uint64_t strBits = (uint64_t)str;
703 : JS_ASSERT(str);
704 : JS_ASSERT((strBits >> JSVAL_TAG_SHIFT) == 0);
705 : l.asBits = strBits | JSVAL_SHIFTED_TAG_STRING;
706 : return l;
707 : }
708 :
709 : static JS_ALWAYS_INLINE JSString *
710 : JSVAL_TO_STRING_IMPL(jsval_layout l)
711 : {
712 : return (JSString *)(l.asBits & JSVAL_PAYLOAD_MASK);
713 : }
714 :
715 : static JS_ALWAYS_INLINE JSBool
716 : JSVAL_IS_BOOLEAN_IMPL(jsval_layout l)
717 : {
718 : return (uint32_t)(l.asBits >> JSVAL_TAG_SHIFT) == JSVAL_TAG_BOOLEAN;
719 : }
720 :
721 : static JS_ALWAYS_INLINE JSBool
722 : JSVAL_TO_BOOLEAN_IMPL(jsval_layout l)
723 : {
724 : return (JSBool)l.asBits;
725 : }
726 :
727 : static JS_ALWAYS_INLINE jsval_layout
728 : BOOLEAN_TO_JSVAL_IMPL(JSBool b)
729 : {
730 : jsval_layout l;
731 : JS_ASSERT(b == JS_TRUE || b == JS_FALSE);
732 : l.asBits = ((uint64_t)(uint32_t)b) | JSVAL_SHIFTED_TAG_BOOLEAN;
733 : return l;
734 : }
735 :
736 : static JS_ALWAYS_INLINE JSBool
737 : JSVAL_IS_MAGIC_IMPL(jsval_layout l)
738 : {
739 : return (l.asBits >> JSVAL_TAG_SHIFT) == JSVAL_TAG_MAGIC;
740 : }
741 :
742 : static JS_ALWAYS_INLINE JSBool
743 : JSVAL_IS_PRIMITIVE_IMPL(jsval_layout l)
744 : {
745 : return l.asBits < JSVAL_UPPER_EXCL_SHIFTED_TAG_OF_PRIMITIVE_SET;
746 : }
747 :
748 : static JS_ALWAYS_INLINE JSBool
749 : JSVAL_IS_OBJECT_IMPL(jsval_layout l)
750 : {
751 : JS_ASSERT((l.asBits >> JSVAL_TAG_SHIFT) <= JSVAL_SHIFTED_TAG_OBJECT);
752 : return l.asBits >= JSVAL_SHIFTED_TAG_OBJECT;
753 : }
754 :
755 : static JS_ALWAYS_INLINE JSBool
756 : JSVAL_IS_OBJECT_OR_NULL_IMPL(jsval_layout l)
757 : {
758 : JS_ASSERT((l.asBits >> JSVAL_TAG_SHIFT) <= JSVAL_TAG_OBJECT);
759 : return l.asBits >= JSVAL_LOWER_INCL_SHIFTED_TAG_OF_OBJ_OR_NULL_SET;
760 : }
761 :
762 : static JS_ALWAYS_INLINE JSObject *
763 : JSVAL_TO_OBJECT_IMPL(jsval_layout l)
764 : {
765 : uint64_t ptrBits = l.asBits & JSVAL_PAYLOAD_MASK;
766 : JS_ASSERT((ptrBits & 0x7) == 0);
767 : return (JSObject *)ptrBits;
768 : }
769 :
770 : static JS_ALWAYS_INLINE jsval_layout
771 : OBJECT_TO_JSVAL_IMPL(JSObject *obj)
772 : {
773 : jsval_layout l;
774 : uint64_t objBits = (uint64_t)obj;
775 : JS_ASSERT(obj);
776 : JS_ASSERT((objBits >> JSVAL_TAG_SHIFT) == 0);
777 : l.asBits = objBits | JSVAL_SHIFTED_TAG_OBJECT;
778 : return l;
779 : }
780 :
781 : static JS_ALWAYS_INLINE JSBool
782 : JSVAL_IS_NULL_IMPL(jsval_layout l)
783 : {
784 : return l.asBits == JSVAL_SHIFTED_TAG_NULL;
785 : }
786 :
787 : static JS_ALWAYS_INLINE JSBool
788 : JSVAL_IS_GCTHING_IMPL(jsval_layout l)
789 : {
790 : return l.asBits >= JSVAL_LOWER_INCL_SHIFTED_TAG_OF_GCTHING_SET;
791 : }
792 :
793 : static JS_ALWAYS_INLINE void *
794 : JSVAL_TO_GCTHING_IMPL(jsval_layout l)
795 : {
796 : uint64_t ptrBits = l.asBits & JSVAL_PAYLOAD_MASK;
797 : JS_ASSERT((ptrBits & 0x7) == 0);
798 : return (void *)ptrBits;
799 : }
800 :
801 : static JS_ALWAYS_INLINE JSBool
802 : JSVAL_IS_TRACEABLE_IMPL(jsval_layout l)
803 : {
804 : return JSVAL_IS_GCTHING_IMPL(l) && !JSVAL_IS_NULL_IMPL(l);
805 : }
806 :
807 : static JS_ALWAYS_INLINE uint32_t
808 : JSVAL_TRACE_KIND_IMPL(jsval_layout l)
809 : {
810 : return (uint32_t)(JSBool)!(JSVAL_IS_OBJECT_IMPL(l));
811 : }
812 :
813 : static JS_ALWAYS_INLINE jsval_layout
814 : PRIVATE_PTR_TO_JSVAL_IMPL(void *ptr)
815 : {
816 : jsval_layout l;
817 : uint64_t ptrBits = (uint64_t)ptr;
818 : JS_ASSERT((ptrBits & 1) == 0);
819 : l.asBits = ptrBits >> 1;
820 : JS_ASSERT(JSVAL_IS_DOUBLE_IMPL(l));
821 : return l;
822 : }
823 :
824 : static JS_ALWAYS_INLINE void *
825 : JSVAL_TO_PRIVATE_PTR_IMPL(jsval_layout l)
826 : {
827 : JS_ASSERT((l.asBits & 0x8000000000000000LL) == 0);
828 : return (void *)(l.asBits << 1);
829 : }
830 :
831 : static JS_ALWAYS_INLINE JSBool
832 : JSVAL_IS_SPECIFIC_INT32_IMPL(jsval_layout l, int32_t i32)
833 : {
834 : return l.asBits == (((uint64_t)(uint32_t)i32) | JSVAL_SHIFTED_TAG_INT32);
835 : }
836 :
837 : static JS_ALWAYS_INLINE JSBool
838 : JSVAL_IS_SPECIFIC_BOOLEAN(jsval_layout l, JSBool b)
839 : {
840 : return l.asBits == (((uint64_t)(uint32_t)b) | JSVAL_SHIFTED_TAG_BOOLEAN);
841 : }
842 :
843 : static JS_ALWAYS_INLINE jsval_layout
844 : MAGIC_TO_JSVAL_IMPL(JSWhyMagic why)
845 : {
846 : jsval_layout l;
847 : l.asBits = ((uint64_t)(uint32_t)why) | JSVAL_SHIFTED_TAG_MAGIC;
848 : return l;
849 : }
850 :
851 : static JS_ALWAYS_INLINE JSBool
852 : JSVAL_SAME_TYPE_IMPL(jsval_layout lhs, jsval_layout rhs)
853 : {
854 : uint64_t lbits = lhs.asBits, rbits = rhs.asBits;
855 : return (lbits <= JSVAL_SHIFTED_TAG_MAX_DOUBLE && rbits <= JSVAL_SHIFTED_TAG_MAX_DOUBLE) ||
856 : (((lbits ^ rbits) & 0xFFFF800000000000LL) == 0);
857 : }
858 :
859 : static JS_ALWAYS_INLINE jsval_layout
860 : PRIVATE_UINT32_TO_JSVAL_IMPL(uint32_t ui)
861 : {
862 : jsval_layout l;
863 : l.asBits = (uint64_t)ui;
864 : JS_ASSERT(JSVAL_IS_DOUBLE_IMPL(l));
865 : return l;
866 : }
867 :
868 : static JS_ALWAYS_INLINE uint32_t
869 : JSVAL_TO_PRIVATE_UINT32_IMPL(jsval_layout l)
870 : {
871 : JS_ASSERT((l.asBits >> 32) == 0);
872 : return (uint32_t)l.asBits;
873 : }
874 :
875 : static JS_ALWAYS_INLINE JSValueType
876 : JSVAL_EXTRACT_NON_DOUBLE_TYPE_IMPL(jsval_layout l)
877 : {
878 : uint64_t type = (l.asBits >> JSVAL_TAG_SHIFT) & 0xF;
879 : JS_ASSERT(type > JSVAL_TYPE_DOUBLE);
880 : return (JSValueType)type;
881 : }
882 :
883 : #endif /* JS_BITS_PER_WORD */
884 :
885 : static JS_ALWAYS_INLINE double
886 91545 : JS_CANONICALIZE_NAN(double d)
887 : {
888 91545 : if (JS_UNLIKELY(d != d)) {
889 : jsval_layout l;
890 22 : l.asBits = 0x7FF8000000000000LL;
891 22 : return l.asDouble;
892 : }
893 91523 : return d;
894 : }
895 :
896 : JS_END_EXTERN_C
897 :
898 : #ifdef __cplusplus
899 : static jsval_layout JSVAL_TO_IMPL(JS::Value);
900 : static JS::Value IMPL_TO_JSVAL(jsval_layout);
901 : #endif
902 :
903 : #endif /* jsvalimpl_h__ */
|