Merge mozilla-central and tracemonkey. (a=blockers)
[mozilla-central.git] / js / src / jsvalue.h
blob7baa2c4aa2231de3d900355a9c2da0deb32b5c91
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2 * vim: set ts=8 sw=4 et tw=99 ft=cpp:
4 * ***** BEGIN LICENSE BLOCK *****
5 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
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/
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.
17 * The Original Code is Mozilla SpiderMonkey JavaScript 1.9 code, released
18 * June 30, 2010
20 * The Initial Developer of the Original Code is
21 * the Mozilla Corporation.
23 * Contributor(s):
24 * Luke Wagner <lw@mozilla.com>
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.
38 * ***** END LICENSE BLOCK ***** */
40 #ifndef jsvalue_h__
41 #define jsvalue_h__
43 * Private value interface.
45 #include "jsprvtd.h"
46 #include "jsstdint.h"
49 * js::Value is a C++-ified version of jsval that provides more information and
50 * helper functions than the basic jsval interface exposed by jsapi.h. A few
51 * general notes on js::Value:
53 * - Since js::Value and jsval have the same representation, values of these
54 * types, function pointer types differing only in these types, and structs
55 * differing only in these types can be converted back and forth at no cost
56 * using the Jsvalify() and Valueify(). See Jsvalify comment below.
58 * - js::Value has setX() and isX() members for X in
60 * { Int32, Double, String, Boolean, Undefined, Null, Object, Magic }
62 * js::Value also contains toX() for each of the non-singleton types.
64 * - Magic is a singleton type whose payload contains a JSWhyMagic "reason" for
65 * the magic value. By providing JSWhyMagic values when creating and checking
66 * for magic values, it is possible to assert, at runtime, that only magic
67 * values with the expected reason flow through a particular value. For
68 * example, if cx->exception has a magic value, the reason must be
69 * JS_GENERATOR_CLOSING.
71 * - A key difference between jsval and js::Value is that js::Value gives null
72 * a separate type. Thus
74 * JSVAL_IS_OBJECT(v) === v.isObjectOrNull()
75 * !JSVAL_IS_PRIMITIVE(v) === v.isObject()
77 * To help prevent mistakenly boxing a nullable JSObject* as an object,
78 * Value::setObject takes a JSObject&. (Conversely, Value::asObject returns a
79 * JSObject&. A convenience member Value::setObjectOrNull is provided.
81 * - JSVAL_VOID is the same as the singleton value of the Undefined type.
83 * - Note that js::Value is always 64-bit. Thus, on 32-bit user code should
84 * avoid copying jsval/js::Value as much as possible, preferring to pass by
85 * const Value &.
88 /******************************************************************************/
90 /* To avoid a circular dependency, pull in the necessary pieces of jsnum.h. */
92 #include <math.h>
93 #if defined(XP_WIN) || defined(XP_OS2)
94 #include <float.h>
95 #endif
96 #ifdef SOLARIS
97 #include <ieeefp.h>
98 #endif
100 static inline int
101 JSDOUBLE_IS_NEGZERO(jsdouble d)
103 #ifdef WIN32
104 return (d == 0 && (_fpclass(d) & _FPCLASS_NZ));
105 #elif defined(SOLARIS)
106 return (d == 0 && copysign(1, d) < 0);
107 #else
108 return (d == 0 && signbit(d));
109 #endif
112 static inline bool
113 JSDOUBLE_IS_INT32(jsdouble d, int32_t* pi)
115 if (JSDOUBLE_IS_NEGZERO(d))
116 return false;
117 return d == (*pi = int32_t(d));
120 /******************************************************************************/
122 /* Additional value operations used in js::Value but not in jsapi.h. */
124 #if JS_BITS_PER_WORD == 32
126 static JS_ALWAYS_INLINE JSBool
127 JSVAL_IS_SPECIFIC_INT32_IMPL(jsval_layout l, int32 i32)
129 return l.s.tag == JSVAL_TAG_INT32 && l.s.payload.i32 == i32;
132 static JS_ALWAYS_INLINE JSBool
133 JSVAL_IS_SPECIFIC_BOOLEAN(jsval_layout l, JSBool b)
135 return (l.s.tag == JSVAL_TAG_BOOLEAN) && (l.s.payload.boo == b);
138 static JS_ALWAYS_INLINE jsval_layout
139 MAGIC_TO_JSVAL_IMPL(JSWhyMagic why)
141 jsval_layout l;
142 l.s.tag = JSVAL_TAG_MAGIC;
143 l.s.payload.why = why;
144 return l;
147 static JS_ALWAYS_INLINE jsval_layout
148 MAGIC_TO_JSVAL_IMPL(JSObject *obj)
150 jsval_layout l;
151 l.s.tag = JSVAL_TAG_MAGIC;
152 l.s.payload.obj = obj;
153 return l;
156 static JS_ALWAYS_INLINE JSBool
157 JSVAL_SAME_TYPE_IMPL(jsval_layout lhs, jsval_layout rhs)
159 JSValueTag ltag = lhs.s.tag, rtag = rhs.s.tag;
160 return ltag == rtag || (ltag < JSVAL_TAG_CLEAR && rtag < JSVAL_TAG_CLEAR);
163 static JS_ALWAYS_INLINE jsval_layout
164 PRIVATE_UINT32_TO_JSVAL_IMPL(uint32 ui)
166 jsval_layout l;
167 l.s.tag = (JSValueTag)0;
168 l.s.payload.u32 = ui;
169 JS_ASSERT(JSVAL_IS_DOUBLE_IMPL(l));
170 return l;
173 static JS_ALWAYS_INLINE uint32
174 JSVAL_TO_PRIVATE_UINT32_IMPL(jsval_layout l)
176 return l.s.payload.u32;
179 static JS_ALWAYS_INLINE JSValueType
180 JSVAL_EXTRACT_NON_DOUBLE_TYPE_IMPL(jsval_layout l)
182 uint32 type = l.s.tag & 0xF;
183 JS_ASSERT(type > JSVAL_TYPE_DOUBLE);
184 return (JSValueType)type;
187 static JS_ALWAYS_INLINE JSValueTag
188 JSVAL_EXTRACT_NON_DOUBLE_TAG_IMPL(jsval_layout l)
190 JSValueTag tag = l.s.tag;
191 JS_ASSERT(tag >= JSVAL_TAG_INT32);
192 return tag;
195 #ifdef __cplusplus
196 JS_STATIC_ASSERT((JSVAL_TYPE_NONFUNOBJ & 0xF) == JSVAL_TYPE_OBJECT);
197 JS_STATIC_ASSERT((JSVAL_TYPE_FUNOBJ & 0xF) == JSVAL_TYPE_OBJECT);
198 #endif
200 static JS_ALWAYS_INLINE jsval_layout
201 BOX_NON_DOUBLE_JSVAL(JSValueType type, uint64 *slot)
203 jsval_layout l;
204 JS_ASSERT(type > JSVAL_TYPE_DOUBLE && type <= JSVAL_UPPER_INCL_TYPE_OF_BOXABLE_SET);
205 JS_ASSERT_IF(type == JSVAL_TYPE_STRING ||
206 type == JSVAL_TYPE_OBJECT ||
207 type == JSVAL_TYPE_NONFUNOBJ ||
208 type == JSVAL_TYPE_FUNOBJ,
209 *(uint32 *)slot != 0);
210 l.s.tag = JSVAL_TYPE_TO_TAG(type & 0xF);
211 /* A 32-bit value in a 64-bit slot always occupies the low-addressed end. */
212 l.s.payload.u32 = *(uint32 *)slot;
213 return l;
216 static JS_ALWAYS_INLINE void
217 UNBOX_NON_DOUBLE_JSVAL(jsval_layout l, uint64 *out)
219 JS_ASSERT(!JSVAL_IS_DOUBLE_IMPL(l));
220 *(uint32 *)out = l.s.payload.u32;
223 #elif JS_BITS_PER_WORD == 64
225 static JS_ALWAYS_INLINE JSBool
226 JSVAL_IS_SPECIFIC_INT32_IMPL(jsval_layout l, int32 i32)
228 return l.asBits == (((uint64)(uint32)i32) | JSVAL_SHIFTED_TAG_INT32);
231 static JS_ALWAYS_INLINE JSBool
232 JSVAL_IS_SPECIFIC_BOOLEAN(jsval_layout l, JSBool b)
234 return l.asBits == (((uint64)(uint32)b) | JSVAL_SHIFTED_TAG_BOOLEAN);
237 static JS_ALWAYS_INLINE jsval_layout
238 MAGIC_TO_JSVAL_IMPL(JSWhyMagic why)
240 jsval_layout l;
241 l.asBits = ((uint64)(uint32)why) | JSVAL_SHIFTED_TAG_MAGIC;
242 return l;
245 static JS_ALWAYS_INLINE jsval_layout
246 MAGIC_TO_JSVAL_IMPL(JSObject *obj)
248 jsval_layout l;
249 l.asBits = ((uint64)obj) | JSVAL_SHIFTED_TAG_MAGIC;
250 return l;
253 static JS_ALWAYS_INLINE JSBool
254 JSVAL_SAME_TYPE_IMPL(jsval_layout lhs, jsval_layout rhs)
256 uint64 lbits = lhs.asBits, rbits = rhs.asBits;
257 return (lbits <= JSVAL_TAG_MAX_DOUBLE && rbits <= JSVAL_TAG_MAX_DOUBLE) ||
258 (((lbits ^ rbits) & 0xFFFF800000000000LL) == 0);
261 static JS_ALWAYS_INLINE jsval_layout
262 PRIVATE_UINT32_TO_JSVAL_IMPL(uint32 ui)
264 jsval_layout l;
265 l.asBits = (uint64)ui;
266 JS_ASSERT(JSVAL_IS_DOUBLE_IMPL(l));
267 return l;
270 static JS_ALWAYS_INLINE uint32
271 JSVAL_TO_PRIVATE_UINT32_IMPL(jsval_layout l)
273 JS_ASSERT((l.asBits >> 32) == 0);
274 return (uint32)l.asBits;
277 static JS_ALWAYS_INLINE JSValueType
278 JSVAL_EXTRACT_NON_DOUBLE_TYPE_IMPL(jsval_layout l)
280 uint64 type = (l.asBits >> JSVAL_TAG_SHIFT) & 0xF;
281 JS_ASSERT(type > JSVAL_TYPE_DOUBLE);
282 return (JSValueType)type;
285 static JS_ALWAYS_INLINE JSValueTag
286 JSVAL_EXTRACT_NON_DOUBLE_TAG_IMPL(jsval_layout l)
288 uint64 tag = l.asBits >> JSVAL_TAG_SHIFT;
289 JS_ASSERT(tag > JSVAL_TAG_MAX_DOUBLE);
290 return (JSValueTag)tag;
293 #ifdef __cplusplus
294 JS_STATIC_ASSERT(offsetof(jsval_layout, s.payload) == 0);
295 JS_STATIC_ASSERT((JSVAL_TYPE_NONFUNOBJ & 0xF) == JSVAL_TYPE_OBJECT);
296 JS_STATIC_ASSERT((JSVAL_TYPE_FUNOBJ & 0xF) == JSVAL_TYPE_OBJECT);
297 #endif
299 static JS_ALWAYS_INLINE jsval_layout
300 BOX_NON_DOUBLE_JSVAL(JSValueType type, uint64 *slot)
302 /* N.B. for 32-bit payloads, the high 32 bits of the slot are trash. */
303 jsval_layout l;
304 JS_ASSERT(type > JSVAL_TYPE_DOUBLE && type <= JSVAL_UPPER_INCL_TYPE_OF_BOXABLE_SET);
305 uint32 isI32 = (uint32)(type < JSVAL_LOWER_INCL_TYPE_OF_PTR_PAYLOAD_SET);
306 uint32 shift = isI32 * 32;
307 uint64 mask = ((uint64)-1) >> shift;
308 uint64 payload = *slot & mask;
309 JS_ASSERT_IF(type == JSVAL_TYPE_STRING ||
310 type == JSVAL_TYPE_OBJECT ||
311 type == JSVAL_TYPE_NONFUNOBJ ||
312 type == JSVAL_TYPE_FUNOBJ,
313 payload != 0);
314 l.asBits = payload | JSVAL_TYPE_TO_SHIFTED_TAG(type & 0xF);
315 return l;
318 static JS_ALWAYS_INLINE void
319 UNBOX_NON_DOUBLE_JSVAL(jsval_layout l, uint64 *out)
321 JS_ASSERT(!JSVAL_IS_DOUBLE_IMPL(l));
322 *out = (l.asBits & JSVAL_PAYLOAD_MASK);
325 #endif
327 /******************************************************************************/
329 namespace js {
331 class Value
333 public:
335 * N.B. the default constructor leaves Value unitialized. Adding a default
336 * constructor prevents Value from being stored in a union.
339 /*** Mutatators ***/
341 JS_ALWAYS_INLINE
342 void setNull() {
343 data.asBits = JSVAL_BITS(JSVAL_NULL);
346 JS_ALWAYS_INLINE
347 void setUndefined() {
348 data.asBits = JSVAL_BITS(JSVAL_VOID);
351 JS_ALWAYS_INLINE
352 void setInt32(int32 i) {
353 data = INT32_TO_JSVAL_IMPL(i);
356 JS_ALWAYS_INLINE
357 int32 &getInt32Ref() {
358 JS_ASSERT(isInt32());
359 return data.s.payload.i32;
362 JS_ALWAYS_INLINE
363 void setDouble(double d) {
364 data = DOUBLE_TO_JSVAL_IMPL(d);
367 JS_ALWAYS_INLINE
368 double &getDoubleRef() {
369 JS_ASSERT(isDouble());
370 return data.asDouble;
373 JS_ALWAYS_INLINE
374 void setString(JSString *str) {
375 data = STRING_TO_JSVAL_IMPL(str);
378 JS_ALWAYS_INLINE
379 void setObject(JSObject &obj) {
380 data = OBJECT_TO_JSVAL_IMPL(&obj);
383 JS_ALWAYS_INLINE
384 void setBoolean(bool b) {
385 data = BOOLEAN_TO_JSVAL_IMPL(b);
388 JS_ALWAYS_INLINE
389 void setMagic(JSWhyMagic why) {
390 data = MAGIC_TO_JSVAL_IMPL(why);
393 JS_ALWAYS_INLINE
394 void setMagicWithObjectOrNullPayload(JSObject *obj) {
395 data = MAGIC_TO_JSVAL_IMPL(obj);
398 JS_ALWAYS_INLINE
399 JSObject *getMagicObjectOrNullPayload() const {
400 return MAGIC_JSVAL_TO_OBJECT_OR_NULL_IMPL(data);
403 JS_ALWAYS_INLINE
404 void setNumber(uint32 ui) {
405 if (ui > JSVAL_INT_MAX)
406 setDouble((double)ui);
407 else
408 setInt32((int32)ui);
411 JS_ALWAYS_INLINE
412 void setNumber(double d) {
413 int32_t i;
414 if (JSDOUBLE_IS_INT32(d, &i))
415 setInt32(i);
416 else
417 setDouble(d);
420 JS_ALWAYS_INLINE
421 void setObjectOrNull(JSObject *arg) {
422 if (arg)
423 setObject(*arg);
424 else
425 setNull();
428 JS_ALWAYS_INLINE
429 void setObjectOrUndefined(JSObject *arg) {
430 if (arg)
431 setObject(*arg);
432 else
433 setUndefined();
436 JS_ALWAYS_INLINE
437 void swap(Value &rhs) {
438 uint64 tmp = rhs.data.asBits;
439 rhs.data.asBits = data.asBits;
440 data.asBits = tmp;
443 /*** Value type queries ***/
445 JS_ALWAYS_INLINE
446 bool isUndefined() const {
447 return JSVAL_IS_UNDEFINED_IMPL(data);
450 JS_ALWAYS_INLINE
451 bool isNull() const {
452 return JSVAL_IS_NULL_IMPL(data);
455 JS_ALWAYS_INLINE
456 bool isNullOrUndefined() const {
457 return isNull() || isUndefined();
460 JS_ALWAYS_INLINE
461 bool isInt32() const {
462 return JSVAL_IS_INT32_IMPL(data);
465 JS_ALWAYS_INLINE
466 bool isInt32(int32 i32) const {
467 return JSVAL_IS_SPECIFIC_INT32_IMPL(data, i32);
470 JS_ALWAYS_INLINE
471 bool isDouble() const {
472 return JSVAL_IS_DOUBLE_IMPL(data);
475 JS_ALWAYS_INLINE
476 bool isNumber() const {
477 return JSVAL_IS_NUMBER_IMPL(data);
480 JS_ALWAYS_INLINE
481 bool isString() const {
482 return JSVAL_IS_STRING_IMPL(data);
485 JS_ALWAYS_INLINE
486 bool isObject() const {
487 return JSVAL_IS_OBJECT_IMPL(data);
490 JS_ALWAYS_INLINE
491 bool isPrimitive() const {
492 return JSVAL_IS_PRIMITIVE_IMPL(data);
495 JS_ALWAYS_INLINE
496 bool isObjectOrNull() const {
497 return JSVAL_IS_OBJECT_OR_NULL_IMPL(data);
500 JS_ALWAYS_INLINE
501 bool isGCThing() const {
502 return JSVAL_IS_GCTHING_IMPL(data);
505 JS_ALWAYS_INLINE
506 bool isBoolean() const {
507 return JSVAL_IS_BOOLEAN_IMPL(data);
510 JS_ALWAYS_INLINE
511 bool isTrue() const {
512 return JSVAL_IS_SPECIFIC_BOOLEAN(data, true);
515 JS_ALWAYS_INLINE
516 bool isFalse() const {
517 return JSVAL_IS_SPECIFIC_BOOLEAN(data, false);
520 JS_ALWAYS_INLINE
521 bool isMagic() const {
522 return JSVAL_IS_MAGIC_IMPL(data);
525 JS_ALWAYS_INLINE
526 bool isMagic(JSWhyMagic why) const {
527 JS_ASSERT_IF(isMagic(), data.s.payload.why == why);
528 return JSVAL_IS_MAGIC_IMPL(data);
531 #if JS_BITS_PER_WORD == 64
532 JS_ALWAYS_INLINE
533 bool hasPtrPayload() const {
534 return data.asBits >= JSVAL_LOWER_INCL_SHIFTED_TAG_OF_PTR_PAYLOAD_SET;
536 #endif
538 JS_ALWAYS_INLINE
539 bool isMarkable() const {
540 return JSVAL_IS_TRACEABLE_IMPL(data);
543 JS_ALWAYS_INLINE
544 int32 gcKind() const {
545 JS_ASSERT(isMarkable());
546 return JSVAL_TRACE_KIND_IMPL(data);
549 #ifdef DEBUG
550 JS_ALWAYS_INLINE
551 JSWhyMagic whyMagic() const {
552 JS_ASSERT(isMagic());
553 return data.s.payload.why;
555 #endif
557 /*** Comparison ***/
559 JS_ALWAYS_INLINE
560 bool operator==(const Value &rhs) const {
561 return data.asBits == rhs.data.asBits;
564 JS_ALWAYS_INLINE
565 bool operator!=(const Value &rhs) const {
566 return data.asBits != rhs.data.asBits;
569 /* This function used to be inlined here, but this triggered a gcc bug
570 due to SameType being used in a template method.
571 See http://gcc.gnu.org/bugzilla/show_bug.cgi?id=38850 */
572 friend bool SameType(const Value &lhs, const Value &rhs);
574 /*** Extract the value's typed payload ***/
576 JS_ALWAYS_INLINE
577 int32 toInt32() const {
578 JS_ASSERT(isInt32());
579 return JSVAL_TO_INT32_IMPL(data);
582 JS_ALWAYS_INLINE
583 double toDouble() const {
584 JS_ASSERT(isDouble());
585 return data.asDouble;
588 JS_ALWAYS_INLINE
589 double toNumber() const {
590 JS_ASSERT(isNumber());
591 return isDouble() ? toDouble() : double(toInt32());
594 JS_ALWAYS_INLINE
595 JSString *toString() const {
596 JS_ASSERT(isString());
597 return JSVAL_TO_STRING_IMPL(data);
600 JS_ALWAYS_INLINE
601 JSObject &toObject() const {
602 JS_ASSERT(isObject());
603 return *JSVAL_TO_OBJECT_IMPL(data);
606 JS_ALWAYS_INLINE
607 JSObject *toObjectOrNull() const {
608 JS_ASSERT(isObjectOrNull());
609 return JSVAL_TO_OBJECT_IMPL(data);
612 JS_ALWAYS_INLINE
613 void *toGCThing() const {
614 JS_ASSERT(isGCThing());
615 return JSVAL_TO_GCTHING_IMPL(data);
618 JS_ALWAYS_INLINE
619 bool toBoolean() const {
620 JS_ASSERT(isBoolean());
621 return JSVAL_TO_BOOLEAN_IMPL(data);
624 JS_ALWAYS_INLINE
625 uint32 payloadAsRawUint32() const {
626 JS_ASSERT(!isDouble());
627 return data.s.payload.u32;
630 JS_ALWAYS_INLINE
631 uint64 asRawBits() const {
632 return data.asBits;
636 * In the extract/box/unbox functions below, "NonDouble" means this
637 * functions must not be called on a value that is a double. This allows
638 * these operations to be implemented more efficiently, since doubles
639 * generally already require special handling by the caller.
641 JS_ALWAYS_INLINE
642 JSValueType extractNonDoubleType() const {
643 return JSVAL_EXTRACT_NON_DOUBLE_TYPE_IMPL(data);
646 JS_ALWAYS_INLINE
647 JSValueTag extractNonDoubleTag() const {
648 return JSVAL_EXTRACT_NON_DOUBLE_TAG_IMPL(data);
651 JS_ALWAYS_INLINE
652 void unboxNonDoubleTo(uint64 *out) const {
653 UNBOX_NON_DOUBLE_JSVAL(data, out);
656 JS_ALWAYS_INLINE
657 void boxNonDoubleFrom(JSValueType type, uint64 *out) {
658 data = BOX_NON_DOUBLE_JSVAL(type, out);
662 * The trace-jit specializes JSVAL_TYPE_OBJECT into JSVAL_TYPE_FUNOBJ and
663 * JSVAL_TYPE_NONFUNOBJ. Since these two operations just return the type of
664 * a value, the caller must handle JSVAL_TYPE_OBJECT separately.
666 JS_ALWAYS_INLINE
667 JSValueType extractNonDoubleObjectTraceType() const {
668 JS_ASSERT(!isObject());
669 return JSVAL_EXTRACT_NON_DOUBLE_TYPE_IMPL(data);
672 JS_ALWAYS_INLINE
673 JSValueTag extractNonDoubleObjectTraceTag() const {
674 JS_ASSERT(!isObject());
675 return JSVAL_EXTRACT_NON_DOUBLE_TAG_IMPL(data);
679 * Private API
681 * Private setters/getters allow the caller to read/write arbitrary types
682 * that fit in the 64-bit payload. It is the caller's responsibility, after
683 * storing to a value with setPrivateX to read only using getPrivateX.
684 * Privates values are given a type type which ensures they are not marked.
687 JS_ALWAYS_INLINE
688 void setPrivate(void *ptr) {
689 data = PRIVATE_PTR_TO_JSVAL_IMPL(ptr);
692 JS_ALWAYS_INLINE
693 void *toPrivate() const {
694 JS_ASSERT(JSVAL_IS_DOUBLE_IMPL(data));
695 return JSVAL_TO_PRIVATE_PTR_IMPL(data);
698 JS_ALWAYS_INLINE
699 void setPrivateUint32(uint32 ui) {
700 data = PRIVATE_UINT32_TO_JSVAL_IMPL(ui);
703 JS_ALWAYS_INLINE
704 uint32 toPrivateUint32() const {
705 JS_ASSERT(JSVAL_IS_DOUBLE_IMPL(data));
706 return JSVAL_TO_PRIVATE_UINT32_IMPL(data);
709 JS_ALWAYS_INLINE
710 uint32 &getPrivateUint32Ref() {
711 JS_ASSERT(isDouble());
712 return data.s.payload.u32;
716 * An unmarked value is just a void* cast as a Value. Thus, the Value is
717 * not safe for GC and must not be marked. This API avoids raw casts
718 * and the ensuing strict-aliasing warnings.
721 JS_ALWAYS_INLINE
722 void setUnmarkedPtr(void *ptr) {
723 data.asPtr = ptr;
726 JS_ALWAYS_INLINE
727 void *toUnmarkedPtr() const {
728 return data.asPtr;
731 const jsuword *payloadWord() const {
732 return &data.s.payload.word;
735 private:
736 void staticAssertions() {
737 JS_STATIC_ASSERT(sizeof(JSValueType) == 1);
738 JS_STATIC_ASSERT(sizeof(JSValueTag) == 4);
739 JS_STATIC_ASSERT(sizeof(JSBool) == 4);
740 JS_STATIC_ASSERT(sizeof(JSWhyMagic) <= 4);
741 JS_STATIC_ASSERT(sizeof(jsval) == 8);
744 jsval_layout data;
745 } JSVAL_ALIGNMENT;
747 JS_ALWAYS_INLINE bool
748 SameType(const Value &lhs, const Value &rhs)
750 return JSVAL_SAME_TYPE_IMPL(lhs.data, rhs.data);
753 static JS_ALWAYS_INLINE Value
754 NullValue()
756 Value v;
757 v.setNull();
758 return v;
761 static JS_ALWAYS_INLINE Value
762 UndefinedValue()
764 Value v;
765 v.setUndefined();
766 return v;
769 static JS_ALWAYS_INLINE Value
770 Int32Value(int32 i32)
772 Value v;
773 v.setInt32(i32);
774 return v;
777 static JS_ALWAYS_INLINE Value
778 DoubleValue(double dbl)
780 Value v;
781 v.setDouble(dbl);
782 return v;
785 static JS_ALWAYS_INLINE Value
786 StringValue(JSString *str)
788 Value v;
789 v.setString(str);
790 return v;
793 static JS_ALWAYS_INLINE Value
794 BooleanValue(bool boo)
796 Value v;
797 v.setBoolean(boo);
798 return v;
801 static JS_ALWAYS_INLINE Value
802 ObjectValue(JSObject &obj)
804 Value v;
805 v.setObject(obj);
806 return v;
809 static JS_ALWAYS_INLINE Value
810 MagicValue(JSWhyMagic why)
812 Value v;
813 v.setMagic(why);
814 return v;
817 static JS_ALWAYS_INLINE Value
818 NumberValue(double dbl)
820 Value v;
821 v.setNumber(dbl);
822 return v;
825 static JS_ALWAYS_INLINE Value
826 ObjectOrNullValue(JSObject *obj)
828 Value v;
829 v.setObjectOrNull(obj);
830 return v;
833 static JS_ALWAYS_INLINE Value
834 PrivateValue(void *ptr)
836 Value v;
837 v.setPrivate(ptr);
838 return v;
841 static JS_ALWAYS_INLINE void
842 ClearValueRange(Value *vec, uintN len, bool useHoles)
844 if (useHoles) {
845 for (uintN i = 0; i < len; i++)
846 vec[i].setMagic(JS_ARRAY_HOLE);
847 } else {
848 for (uintN i = 0; i < len; i++)
849 vec[i].setUndefined();
853 /******************************************************************************/
856 * As asserted above, js::Value and jsval are layout equivalent. This means:
857 * - an instance of jsval may be reinterpreted as a js::Value and vice versa;
858 * - a pointer to a function taking jsval arguments may be reinterpreted as a
859 * function taking the same arguments, s/jsval/js::Value/, and vice versa;
860 * - a struct containing jsval members may be reinterpreted as a struct with
861 * the same members, s/jsval/js::Value/, and vice versa.
863 * To prevent widespread conversion using casts, which would effectively
864 * disable the C++ typesystem in places where we want it, a set of safe
865 * conversions between known-equivalent types is provided below. Given a type
866 * JsvalT expressedin terms of jsval and an equivalent type ValueT expressed in
867 * terms of js::Value, instances may be converted back and forth using:
869 * JsvalT *x = ...
870 * ValueT *y = js::Valueify(x);
871 * JsvalT *z = js::Jsvalify(y);
872 * assert(x == z);
874 * Conversions between references is also provided for some types. If it seems
875 * like a cast is needed to convert between jsval/js::Value, consider adding a
876 * new safe overload to Jsvalify/Valueify.
879 static inline jsval * Jsvalify(Value *v) { return (jsval *)v; }
880 static inline const jsval * Jsvalify(const Value *v) { return (const jsval *)v; }
881 static inline jsval & Jsvalify(Value &v) { return (jsval &)v; }
882 static inline const jsval & Jsvalify(const Value &v) { return (const jsval &)v; }
883 static inline Value * Valueify(jsval *v) { return (Value *)v; }
884 static inline const Value * Valueify(const jsval *v) { return (const Value *)v; }
885 static inline Value ** Valueify(jsval **v) { return (Value **)v; }
886 static inline Value & Valueify(jsval &v) { return (Value &)v; }
887 static inline const Value & Valueify(const jsval &v) { return (const Value &)v; }
889 struct Class;
891 typedef JSBool
892 (* Native)(JSContext *cx, uintN argc, Value *vp);
893 typedef JSBool
894 (* PropertyOp)(JSContext *cx, JSObject *obj, jsid id, Value *vp);
895 typedef JSBool
896 (* StrictPropertyOp)(JSContext *cx, JSObject *obj, jsid id, JSBool strict, Value *vp);
897 typedef JSBool
898 (* ConvertOp)(JSContext *cx, JSObject *obj, JSType type, Value *vp);
899 typedef JSBool
900 (* NewEnumerateOp)(JSContext *cx, JSObject *obj, JSIterateOp enum_op,
901 Value *statep, jsid *idp);
902 typedef JSBool
903 (* HasInstanceOp)(JSContext *cx, JSObject *obj, const Value *v, JSBool *bp);
904 typedef JSBool
905 (* CheckAccessOp)(JSContext *cx, JSObject *obj, jsid id, JSAccessMode mode,
906 Value *vp);
907 typedef JSBool
908 (* EqualityOp)(JSContext *cx, JSObject *obj, const Value *v, JSBool *bp);
909 typedef JSBool
910 (* DefinePropOp)(JSContext *cx, JSObject *obj, jsid id, const Value *value,
911 PropertyOp getter, StrictPropertyOp setter, uintN attrs);
912 typedef JSBool
913 (* PropertyIdOp)(JSContext *cx, JSObject *obj, JSObject *receiver, jsid id, Value *vp);
914 typedef JSBool
915 (* StrictPropertyIdOp)(JSContext *cx, JSObject *obj, jsid id, Value *vp, JSBool strict);
916 typedef JSBool
917 (* DeleteIdOp)(JSContext *cx, JSObject *obj, jsid id, Value *vp, JSBool strict);
918 typedef JSBool
919 (* CallOp)(JSContext *cx, uintN argc, Value *vp);
920 typedef JSBool
921 (* LookupPropOp)(JSContext *cx, JSObject *obj, jsid id, JSObject **objp,
922 JSProperty **propp);
923 typedef JSBool
924 (* AttributesOp)(JSContext *cx, JSObject *obj, jsid id, uintN *attrsp);
925 typedef JSType
926 (* TypeOfOp)(JSContext *cx, JSObject *obj);
927 typedef void
928 (* TraceOp)(JSTracer *trc, JSObject *obj);
929 typedef JSObject *
930 (* ObjectOp)(JSContext *cx, JSObject *obj);
931 typedef void
932 (* FinalizeOp)(JSContext *cx, JSObject *obj);
934 class AutoIdVector;
937 * Prepare to make |obj| non-extensible; in particular, fully resolve its properties.
938 * On error, return false.
939 * If |obj| is now ready to become non-extensible, set |*fixed| to true and return true.
940 * If |obj| refuses to become non-extensible, set |*fixed| to false and return true; the
941 * caller will throw an appropriate error.
943 typedef JSBool
944 (* FixOp)(JSContext *cx, JSObject *obj, bool *fixed, AutoIdVector *props);
946 static inline Native Valueify(JSNative f) { return (Native)f; }
947 static inline JSNative Jsvalify(Native f) { return (JSNative)f; }
948 static inline PropertyOp Valueify(JSPropertyOp f) { return (PropertyOp)f; }
949 static inline JSPropertyOp Jsvalify(PropertyOp f) { return (JSPropertyOp)f; }
950 static inline StrictPropertyOp Valueify(JSStrictPropertyOp f) { return (StrictPropertyOp)f; }
951 static inline JSStrictPropertyOp Jsvalify(StrictPropertyOp f) { return (JSStrictPropertyOp)f; }
952 static inline ConvertOp Valueify(JSConvertOp f) { return (ConvertOp)f; }
953 static inline JSConvertOp Jsvalify(ConvertOp f) { return (JSConvertOp)f; }
954 static inline NewEnumerateOp Valueify(JSNewEnumerateOp f) { return (NewEnumerateOp)f; }
955 static inline JSNewEnumerateOp Jsvalify(NewEnumerateOp f) { return (JSNewEnumerateOp)f; }
956 static inline HasInstanceOp Valueify(JSHasInstanceOp f) { return (HasInstanceOp)f; }
957 static inline JSHasInstanceOp Jsvalify(HasInstanceOp f) { return (JSHasInstanceOp)f; }
958 static inline CheckAccessOp Valueify(JSCheckAccessOp f) { return (CheckAccessOp)f; }
959 static inline JSCheckAccessOp Jsvalify(CheckAccessOp f) { return (JSCheckAccessOp)f; }
960 static inline EqualityOp Valueify(JSEqualityOp f); /* Same type as JSHasInstanceOp */
961 static inline JSEqualityOp Jsvalify(EqualityOp f); /* Same type as HasInstanceOp */
963 static const PropertyOp PropertyStub = (PropertyOp)JS_PropertyStub;
964 static const StrictPropertyOp StrictPropertyStub = (StrictPropertyOp)JS_StrictPropertyStub;
965 static const JSEnumerateOp EnumerateStub = JS_EnumerateStub;
966 static const JSResolveOp ResolveStub = JS_ResolveStub;
967 static const ConvertOp ConvertStub = (ConvertOp)JS_ConvertStub;
968 static const JSFinalizeOp FinalizeStub = JS_FinalizeStub;
970 #define JS_CLASS_MEMBERS \
971 const char *name; \
972 uint32 flags; \
974 /* Mandatory non-null function pointer members. */ \
975 PropertyOp addProperty; \
976 PropertyOp delProperty; \
977 PropertyOp getProperty; \
978 StrictPropertyOp setProperty; \
979 JSEnumerateOp enumerate; \
980 JSResolveOp resolve; \
981 ConvertOp convert; \
982 JSFinalizeOp finalize; \
984 /* Optionally non-null members start here. */ \
985 JSClassInternal reserved0; \
986 CheckAccessOp checkAccess; \
987 Native call; \
988 Native construct; \
989 JSXDRObjectOp xdrObject; \
990 HasInstanceOp hasInstance; \
991 JSMarkOp mark
995 * The helper struct to measure the size of JS_CLASS_MEMBERS to know how much
996 * we have to padd js::Class to match the size of JSClass;
998 struct ClassSizeMeasurement {
999 JS_CLASS_MEMBERS;
1002 struct ClassExtension {
1003 EqualityOp equality;
1004 JSObjectOp outerObject;
1005 JSObjectOp innerObject;
1006 JSIteratorOp iteratorObject;
1007 void *unused;
1010 #define JS_NULL_CLASS_EXT {NULL,NULL,NULL,NULL,NULL}
1012 struct ObjectOps {
1013 js::LookupPropOp lookupProperty;
1014 js::DefinePropOp defineProperty;
1015 js::PropertyIdOp getProperty;
1016 js::StrictPropertyIdOp setProperty;
1017 js::AttributesOp getAttributes;
1018 js::AttributesOp setAttributes;
1019 js::DeleteIdOp deleteProperty;
1020 js::NewEnumerateOp enumerate;
1021 js::TypeOfOp typeOf;
1022 js::TraceOp trace;
1023 js::FixOp fix;
1024 js::ObjectOp thisObject;
1025 js::FinalizeOp clear;
1028 #define JS_NULL_OBJECT_OPS {NULL,NULL,NULL,NULL,NULL,NULL, NULL,NULL,NULL,NULL,NULL,NULL}
1030 struct Class {
1031 JS_CLASS_MEMBERS;
1032 ClassExtension ext;
1033 ObjectOps ops;
1034 uint8 pad[sizeof(JSClass) - sizeof(ClassSizeMeasurement) -
1035 sizeof(ClassExtension) - sizeof(ObjectOps)];
1037 /* Class is not native and its map is not a scope. */
1038 static const uint32 NON_NATIVE = JSCLASS_INTERNAL_FLAG2;
1040 bool isNative() const {
1041 return !(flags & NON_NATIVE);
1045 JS_STATIC_ASSERT(offsetof(JSClass, name) == offsetof(Class, name));
1046 JS_STATIC_ASSERT(offsetof(JSClass, flags) == offsetof(Class, flags));
1047 JS_STATIC_ASSERT(offsetof(JSClass, addProperty) == offsetof(Class, addProperty));
1048 JS_STATIC_ASSERT(offsetof(JSClass, delProperty) == offsetof(Class, delProperty));
1049 JS_STATIC_ASSERT(offsetof(JSClass, getProperty) == offsetof(Class, getProperty));
1050 JS_STATIC_ASSERT(offsetof(JSClass, setProperty) == offsetof(Class, setProperty));
1051 JS_STATIC_ASSERT(offsetof(JSClass, enumerate) == offsetof(Class, enumerate));
1052 JS_STATIC_ASSERT(offsetof(JSClass, resolve) == offsetof(Class, resolve));
1053 JS_STATIC_ASSERT(offsetof(JSClass, convert) == offsetof(Class, convert));
1054 JS_STATIC_ASSERT(offsetof(JSClass, finalize) == offsetof(Class, finalize));
1055 JS_STATIC_ASSERT(offsetof(JSClass, reserved0) == offsetof(Class, reserved0));
1056 JS_STATIC_ASSERT(offsetof(JSClass, checkAccess) == offsetof(Class, checkAccess));
1057 JS_STATIC_ASSERT(offsetof(JSClass, call) == offsetof(Class, call));
1058 JS_STATIC_ASSERT(offsetof(JSClass, construct) == offsetof(Class, construct));
1059 JS_STATIC_ASSERT(offsetof(JSClass, xdrObject) == offsetof(Class, xdrObject));
1060 JS_STATIC_ASSERT(offsetof(JSClass, hasInstance) == offsetof(Class, hasInstance));
1061 JS_STATIC_ASSERT(offsetof(JSClass, mark) == offsetof(Class, mark));
1062 JS_STATIC_ASSERT(sizeof(JSClass) == sizeof(Class));
1064 struct PropertyDescriptor {
1065 JSObject *obj;
1066 uintN attrs;
1067 PropertyOp getter;
1068 StrictPropertyOp setter;
1069 Value value;
1070 uintN shortid;
1072 JS_STATIC_ASSERT(offsetof(JSPropertyDescriptor, obj) == offsetof(PropertyDescriptor, obj));
1073 JS_STATIC_ASSERT(offsetof(JSPropertyDescriptor, attrs) == offsetof(PropertyDescriptor, attrs));
1074 JS_STATIC_ASSERT(offsetof(JSPropertyDescriptor, getter) == offsetof(PropertyDescriptor, getter));
1075 JS_STATIC_ASSERT(offsetof(JSPropertyDescriptor, setter) == offsetof(PropertyDescriptor, setter));
1076 JS_STATIC_ASSERT(offsetof(JSPropertyDescriptor, value) == offsetof(PropertyDescriptor, value));
1077 JS_STATIC_ASSERT(offsetof(JSPropertyDescriptor, shortid) == offsetof(PropertyDescriptor, shortid));
1078 JS_STATIC_ASSERT(sizeof(JSPropertyDescriptor) == sizeof(PropertyDescriptor));
1080 static JS_ALWAYS_INLINE JSClass * Jsvalify(Class *c) { return (JSClass *)c; }
1081 static JS_ALWAYS_INLINE Class * Valueify(JSClass *c) { return (Class *)c; }
1082 static JS_ALWAYS_INLINE JSPropertyDescriptor * Jsvalify(PropertyDescriptor *p) { return (JSPropertyDescriptor *) p; }
1083 static JS_ALWAYS_INLINE PropertyDescriptor * Valueify(JSPropertyDescriptor *p) { return (PropertyDescriptor *) p; }
1085 /******************************************************************************/
1088 * Any cast-via-function-call, inlined or not, will cause initialization to
1089 * happen at startup, rather than statically, so just cast in release builds.
1091 #ifdef DEBUG
1093 # define JS_VALUEIFY(type, v) js::Valueify(v)
1094 # define JS_JSVALIFY(type, v) js::Jsvalify(v)
1096 static inline JSNative JsvalifyNative(Native n) { return (JSNative)n; }
1097 static inline JSNative JsvalifyNative(JSNative n) { return n; }
1098 static inline Native ValueifyNative(JSNative n) { return (Native)n; }
1099 static inline Native ValueifyNative(Native n) { return n; }
1101 # define JS_VALUEIFY_NATIVE(n) js::ValueifyNative(n)
1102 # define JS_JSVALIFY_NATIVE(n) js::JsvalifyNative(n)
1104 #else
1106 # define JS_VALUEIFY(type, v) ((type)(v))
1107 # define JS_JSVALIFY(type, v) ((type)(v))
1109 # define JS_VALUEIFY_NATIVE(n) ((js::Native)(n))
1110 # define JS_JSVALIFY_NATIVE(n) ((JSNative)(n))
1112 #endif
1115 * JSFunctionSpec uses JSAPI jsval in function signatures whereas the engine
1116 * uses js::Value. To avoid widespread (JSNative) casting, have JS_FN perfom a
1117 * type-safe cast.
1119 #undef JS_FN
1120 #define JS_FN(name,call,nargs,flags) \
1121 {name, JS_JSVALIFY_NATIVE(call), nargs, (flags) | JSFUN_STUB_GSOPS}
1123 /******************************************************************************/
1126 * In some cases (quickstubs) we want to take a value in whatever manner is
1127 * appropriate for the architecture and normalize to a const js::Value &. On
1128 * x64, passing a js::Value may cause the to unnecessarily be passed through
1129 * memory instead of registers, so jsval, which is a builtin uint64 is used.
1131 #if JS_BITS_PER_WORD == 32
1132 typedef const js::Value *ValueArgType;
1134 static JS_ALWAYS_INLINE const js::Value &
1135 ValueArgToConstRef(const js::Value *arg)
1137 return *arg;
1140 #elif JS_BITS_PER_WORD == 64
1141 typedef js::Value ValueArgType;
1143 static JS_ALWAYS_INLINE const Value &
1144 ValueArgToConstRef(const Value &v)
1146 return v;
1148 #endif
1150 /******************************************************************************/
1152 static JS_ALWAYS_INLINE void
1153 MakeRangeGCSafe(Value *vec, size_t len)
1155 PodZero(vec, len);
1158 static JS_ALWAYS_INLINE void
1159 MakeRangeGCSafe(Value *beg, Value *end)
1161 PodZero(beg, end - beg);
1164 static JS_ALWAYS_INLINE void
1165 MakeRangeGCSafe(jsid *beg, jsid *end)
1167 for (jsid *id = beg; id != end; ++id)
1168 *id = INT_TO_JSID(0);
1171 static JS_ALWAYS_INLINE void
1172 MakeRangeGCSafe(jsid *vec, size_t len)
1174 MakeRangeGCSafe(vec, vec + len);
1177 static JS_ALWAYS_INLINE void
1178 MakeRangeGCSafe(const Shape **beg, const Shape **end)
1180 PodZero(beg, end - beg);
1183 static JS_ALWAYS_INLINE void
1184 MakeRangeGCSafe(const Shape **vec, size_t len)
1186 PodZero(vec, len);
1189 static JS_ALWAYS_INLINE void
1190 SetValueRangeToUndefined(Value *beg, Value *end)
1192 for (Value *v = beg; v != end; ++v)
1193 v->setUndefined();
1196 static JS_ALWAYS_INLINE void
1197 SetValueRangeToUndefined(Value *vec, size_t len)
1199 SetValueRangeToUndefined(vec, vec + len);
1202 static JS_ALWAYS_INLINE void
1203 SetValueRangeToNull(Value *beg, Value *end)
1205 for (Value *v = beg; v != end; ++v)
1206 v->setNull();
1209 static JS_ALWAYS_INLINE void
1210 SetValueRangeToNull(Value *vec, size_t len)
1212 SetValueRangeToNull(vec, vec + len);
1216 * To really poison a set of values, using 'magic' or 'undefined' isn't good
1217 * enough since often these will just be ignored by buggy code (see bug 629974)
1218 * in debug builds and crash in release builds. Instead, we use a safe-for-crash
1219 * pointer.
1221 static JS_ALWAYS_INLINE void
1222 Debug_SetValueRangeToCrashOnTouch(Value *beg, Value *end)
1224 #ifdef DEBUG
1225 for (Value *v = beg; v != end; ++v)
1226 v->setObject(*reinterpret_cast<JSObject *>(0x42));
1227 #endif
1230 static JS_ALWAYS_INLINE void
1231 Debug_SetValueRangeToCrashOnTouch(Value *vec, size_t len)
1233 #ifdef DEBUG
1234 Debug_SetValueRangeToCrashOnTouch(vec, vec + len);
1235 #endif
1238 } /* namespace js */
1239 #endif /* jsvalue_h__ */