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
17 * The Original Code is Mozilla SpiderMonkey JavaScript 1.9 code, released
20 * The Initial Developer of the Original Code is
21 * the Mozilla Corporation.
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 ***** */
43 * Private value interface.
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
88 /******************************************************************************/
90 /* To avoid a circular dependency, pull in the necessary pieces of jsnum.h. */
93 #if defined(XP_WIN) || defined(XP_OS2)
101 JSDOUBLE_IS_NEGZERO(jsdouble d
)
104 return (d
== 0 && (_fpclass(d
) & _FPCLASS_NZ
));
105 #elif defined(SOLARIS)
106 return (d
== 0 && copysign(1, d
) < 0);
108 return (d
== 0 && signbit(d
));
113 JSDOUBLE_IS_INT32(jsdouble d
, int32_t* pi
)
115 if (JSDOUBLE_IS_NEGZERO(d
))
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
)
142 l
.s
.tag
= JSVAL_TAG_MAGIC
;
143 l
.s
.payload
.why
= why
;
147 static JS_ALWAYS_INLINE jsval_layout
148 MAGIC_TO_JSVAL_IMPL(JSObject
*obj
)
151 l
.s
.tag
= JSVAL_TAG_MAGIC
;
152 l
.s
.payload
.obj
= obj
;
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
)
167 l
.s
.tag
= (JSValueTag
)0;
168 l
.s
.payload
.u32
= ui
;
169 JS_ASSERT(JSVAL_IS_DOUBLE_IMPL(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
);
196 JS_STATIC_ASSERT((JSVAL_TYPE_NONFUNOBJ
& 0xF) == JSVAL_TYPE_OBJECT
);
197 JS_STATIC_ASSERT((JSVAL_TYPE_FUNOBJ
& 0xF) == JSVAL_TYPE_OBJECT
);
200 static JS_ALWAYS_INLINE jsval_layout
201 BOX_NON_DOUBLE_JSVAL(JSValueType type
, uint64
*slot
)
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
;
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
)
241 l
.asBits
= ((uint64
)(uint32
)why
) | JSVAL_SHIFTED_TAG_MAGIC
;
245 static JS_ALWAYS_INLINE jsval_layout
246 MAGIC_TO_JSVAL_IMPL(JSObject
*obj
)
249 l
.asBits
= ((uint64
)obj
) | JSVAL_SHIFTED_TAG_MAGIC
;
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
)
265 l
.asBits
= (uint64
)ui
;
266 JS_ASSERT(JSVAL_IS_DOUBLE_IMPL(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
;
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
);
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. */
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
,
314 l
.asBits
= payload
| JSVAL_TYPE_TO_SHIFTED_TAG(type
& 0xF);
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
);
327 /******************************************************************************/
335 * N.B. the default constructor leaves Value unitialized. Adding a default
336 * constructor prevents Value from being stored in a union.
343 data
.asBits
= JSVAL_BITS(JSVAL_NULL
);
347 void setUndefined() {
348 data
.asBits
= JSVAL_BITS(JSVAL_VOID
);
352 void setInt32(int32 i
) {
353 data
= INT32_TO_JSVAL_IMPL(i
);
357 int32
&getInt32Ref() {
358 JS_ASSERT(isInt32());
359 return data
.s
.payload
.i32
;
363 void setDouble(double d
) {
364 data
= DOUBLE_TO_JSVAL_IMPL(d
);
368 double &getDoubleRef() {
369 JS_ASSERT(isDouble());
370 return data
.asDouble
;
374 void setString(JSString
*str
) {
375 data
= STRING_TO_JSVAL_IMPL(str
);
379 void setObject(JSObject
&obj
) {
380 data
= OBJECT_TO_JSVAL_IMPL(&obj
);
384 void setBoolean(bool b
) {
385 data
= BOOLEAN_TO_JSVAL_IMPL(b
);
389 void setMagic(JSWhyMagic why
) {
390 data
= MAGIC_TO_JSVAL_IMPL(why
);
394 void setMagicWithObjectOrNullPayload(JSObject
*obj
) {
395 data
= MAGIC_TO_JSVAL_IMPL(obj
);
399 JSObject
*getMagicObjectOrNullPayload() const {
400 return MAGIC_JSVAL_TO_OBJECT_OR_NULL_IMPL(data
);
404 void setNumber(uint32 ui
) {
405 if (ui
> JSVAL_INT_MAX
)
406 setDouble((double)ui
);
412 void setNumber(double d
) {
414 if (JSDOUBLE_IS_INT32(d
, &i
))
421 void setObjectOrNull(JSObject
*arg
) {
429 void setObjectOrUndefined(JSObject
*arg
) {
437 void swap(Value
&rhs
) {
438 uint64 tmp
= rhs
.data
.asBits
;
439 rhs
.data
.asBits
= data
.asBits
;
443 /*** Value type queries ***/
446 bool isUndefined() const {
447 return JSVAL_IS_UNDEFINED_IMPL(data
);
451 bool isNull() const {
452 return JSVAL_IS_NULL_IMPL(data
);
456 bool isNullOrUndefined() const {
457 return isNull() || isUndefined();
461 bool isInt32() const {
462 return JSVAL_IS_INT32_IMPL(data
);
466 bool isInt32(int32 i32
) const {
467 return JSVAL_IS_SPECIFIC_INT32_IMPL(data
, i32
);
471 bool isDouble() const {
472 return JSVAL_IS_DOUBLE_IMPL(data
);
476 bool isNumber() const {
477 return JSVAL_IS_NUMBER_IMPL(data
);
481 bool isString() const {
482 return JSVAL_IS_STRING_IMPL(data
);
486 bool isObject() const {
487 return JSVAL_IS_OBJECT_IMPL(data
);
491 bool isPrimitive() const {
492 return JSVAL_IS_PRIMITIVE_IMPL(data
);
496 bool isObjectOrNull() const {
497 return JSVAL_IS_OBJECT_OR_NULL_IMPL(data
);
501 bool isGCThing() const {
502 return JSVAL_IS_GCTHING_IMPL(data
);
506 bool isBoolean() const {
507 return JSVAL_IS_BOOLEAN_IMPL(data
);
511 bool isTrue() const {
512 return JSVAL_IS_SPECIFIC_BOOLEAN(data
, true);
516 bool isFalse() const {
517 return JSVAL_IS_SPECIFIC_BOOLEAN(data
, false);
521 bool isMagic() const {
522 return JSVAL_IS_MAGIC_IMPL(data
);
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
533 bool hasPtrPayload() const {
534 return data
.asBits
>= JSVAL_LOWER_INCL_SHIFTED_TAG_OF_PTR_PAYLOAD_SET
;
539 bool isMarkable() const {
540 return JSVAL_IS_TRACEABLE_IMPL(data
);
544 int32
gcKind() const {
545 JS_ASSERT(isMarkable());
546 return JSVAL_TRACE_KIND_IMPL(data
);
551 JSWhyMagic
whyMagic() const {
552 JS_ASSERT(isMagic());
553 return data
.s
.payload
.why
;
560 bool operator==(const Value
&rhs
) const {
561 return data
.asBits
== rhs
.data
.asBits
;
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 ***/
577 int32
toInt32() const {
578 JS_ASSERT(isInt32());
579 return JSVAL_TO_INT32_IMPL(data
);
583 double toDouble() const {
584 JS_ASSERT(isDouble());
585 return data
.asDouble
;
589 double toNumber() const {
590 JS_ASSERT(isNumber());
591 return isDouble() ? toDouble() : double(toInt32());
595 JSString
*toString() const {
596 JS_ASSERT(isString());
597 return JSVAL_TO_STRING_IMPL(data
);
601 JSObject
&toObject() const {
602 JS_ASSERT(isObject());
603 return *JSVAL_TO_OBJECT_IMPL(data
);
607 JSObject
*toObjectOrNull() const {
608 JS_ASSERT(isObjectOrNull());
609 return JSVAL_TO_OBJECT_IMPL(data
);
613 void *toGCThing() const {
614 JS_ASSERT(isGCThing());
615 return JSVAL_TO_GCTHING_IMPL(data
);
619 bool toBoolean() const {
620 JS_ASSERT(isBoolean());
621 return JSVAL_TO_BOOLEAN_IMPL(data
);
625 uint32
payloadAsRawUint32() const {
626 JS_ASSERT(!isDouble());
627 return data
.s
.payload
.u32
;
631 uint64
asRawBits() const {
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.
642 JSValueType
extractNonDoubleType() const {
643 return JSVAL_EXTRACT_NON_DOUBLE_TYPE_IMPL(data
);
647 JSValueTag
extractNonDoubleTag() const {
648 return JSVAL_EXTRACT_NON_DOUBLE_TAG_IMPL(data
);
652 void unboxNonDoubleTo(uint64
*out
) const {
653 UNBOX_NON_DOUBLE_JSVAL(data
, out
);
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.
667 JSValueType
extractNonDoubleObjectTraceType() const {
668 JS_ASSERT(!isObject());
669 return JSVAL_EXTRACT_NON_DOUBLE_TYPE_IMPL(data
);
673 JSValueTag
extractNonDoubleObjectTraceTag() const {
674 JS_ASSERT(!isObject());
675 return JSVAL_EXTRACT_NON_DOUBLE_TAG_IMPL(data
);
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.
688 void setPrivate(void *ptr
) {
689 data
= PRIVATE_PTR_TO_JSVAL_IMPL(ptr
);
693 void *toPrivate() const {
694 JS_ASSERT(JSVAL_IS_DOUBLE_IMPL(data
));
695 return JSVAL_TO_PRIVATE_PTR_IMPL(data
);
699 void setPrivateUint32(uint32 ui
) {
700 data
= PRIVATE_UINT32_TO_JSVAL_IMPL(ui
);
704 uint32
toPrivateUint32() const {
705 JS_ASSERT(JSVAL_IS_DOUBLE_IMPL(data
));
706 return JSVAL_TO_PRIVATE_UINT32_IMPL(data
);
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.
722 void setUnmarkedPtr(void *ptr
) {
727 void *toUnmarkedPtr() const {
731 const jsuword
*payloadWord() const {
732 return &data
.s
.payload
.word
;
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);
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
761 static JS_ALWAYS_INLINE Value
769 static JS_ALWAYS_INLINE Value
770 Int32Value(int32 i32
)
777 static JS_ALWAYS_INLINE Value
778 DoubleValue(double dbl
)
785 static JS_ALWAYS_INLINE Value
786 StringValue(JSString
*str
)
793 static JS_ALWAYS_INLINE Value
794 BooleanValue(bool boo
)
801 static JS_ALWAYS_INLINE Value
802 ObjectValue(JSObject
&obj
)
809 static JS_ALWAYS_INLINE Value
810 MagicValue(JSWhyMagic why
)
817 static JS_ALWAYS_INLINE Value
818 NumberValue(double dbl
)
825 static JS_ALWAYS_INLINE Value
826 ObjectOrNullValue(JSObject
*obj
)
829 v
.setObjectOrNull(obj
);
833 static JS_ALWAYS_INLINE Value
834 PrivateValue(void *ptr
)
841 static JS_ALWAYS_INLINE
void
842 ClearValueRange(Value
*vec
, uintN len
, bool useHoles
)
845 for (uintN i
= 0; i
< len
; i
++)
846 vec
[i
].setMagic(JS_ARRAY_HOLE
);
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:
870 * ValueT *y = js::Valueify(x);
871 * JsvalT *z = js::Jsvalify(y);
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
; }
892 (* Native
)(JSContext
*cx
, uintN argc
, Value
*vp
);
894 (* PropertyOp
)(JSContext
*cx
, JSObject
*obj
, jsid id
, Value
*vp
);
896 (* StrictPropertyOp
)(JSContext
*cx
, JSObject
*obj
, jsid id
, JSBool strict
, Value
*vp
);
898 (* ConvertOp
)(JSContext
*cx
, JSObject
*obj
, JSType type
, Value
*vp
);
900 (* NewEnumerateOp
)(JSContext
*cx
, JSObject
*obj
, JSIterateOp enum_op
,
901 Value
*statep
, jsid
*idp
);
903 (* HasInstanceOp
)(JSContext
*cx
, JSObject
*obj
, const Value
*v
, JSBool
*bp
);
905 (* CheckAccessOp
)(JSContext
*cx
, JSObject
*obj
, jsid id
, JSAccessMode mode
,
908 (* EqualityOp
)(JSContext
*cx
, JSObject
*obj
, const Value
*v
, JSBool
*bp
);
910 (* DefinePropOp
)(JSContext
*cx
, JSObject
*obj
, jsid id
, const Value
*value
,
911 PropertyOp getter
, StrictPropertyOp setter
, uintN attrs
);
913 (* PropertyIdOp
)(JSContext
*cx
, JSObject
*obj
, JSObject
*receiver
, jsid id
, Value
*vp
);
915 (* StrictPropertyIdOp
)(JSContext
*cx
, JSObject
*obj
, jsid id
, Value
*vp
, JSBool strict
);
917 (* DeleteIdOp
)(JSContext
*cx
, JSObject
*obj
, jsid id
, Value
*vp
, JSBool strict
);
919 (* CallOp
)(JSContext
*cx
, uintN argc
, Value
*vp
);
921 (* LookupPropOp
)(JSContext
*cx
, JSObject
*obj
, jsid id
, JSObject
**objp
,
924 (* AttributesOp
)(JSContext
*cx
, JSObject
*obj
, jsid id
, uintN
*attrsp
);
926 (* TypeOfOp
)(JSContext
*cx
, JSObject
*obj
);
928 (* TraceOp
)(JSTracer
*trc
, JSObject
*obj
);
930 (* ObjectOp
)(JSContext
*cx
, JSObject
*obj
);
932 (* FinalizeOp
)(JSContext
*cx
, JSObject
*obj
);
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.
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 \
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; \
982 JSFinalizeOp finalize; \
984 /* Optionally non-null members start here. */ \
985 JSClassInternal reserved0; \
986 CheckAccessOp checkAccess; \
989 JSXDRObjectOp xdrObject; \
990 HasInstanceOp hasInstance; \
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
{
1002 struct ClassExtension
{
1003 EqualityOp equality
;
1004 JSObjectOp outerObject
;
1005 JSObjectOp innerObject
;
1006 JSIteratorOp iteratorObject
;
1010 #define JS_NULL_CLASS_EXT {NULL,NULL,NULL,NULL,NULL}
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
;
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}
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
{
1068 StrictPropertyOp setter
;
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.
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)
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))
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
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
)
1140 #elif JS_BITS_PER_WORD == 64
1141 typedef js::Value ValueArgType
;
1143 static JS_ALWAYS_INLINE
const Value
&
1144 ValueArgToConstRef(const Value
&v
)
1150 /******************************************************************************/
1152 static JS_ALWAYS_INLINE
void
1153 MakeRangeGCSafe(Value
*vec
, size_t 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
)
1189 static JS_ALWAYS_INLINE
void
1190 SetValueRangeToUndefined(Value
*beg
, Value
*end
)
1192 for (Value
*v
= beg
; v
!= end
; ++v
)
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
)
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
1221 static JS_ALWAYS_INLINE
void
1222 Debug_SetValueRangeToCrashOnTouch(Value
*beg
, Value
*end
)
1225 for (Value
*v
= beg
; v
!= end
; ++v
)
1226 v
->setObject(*reinterpret_cast<JSObject
*>(0x42));
1230 static JS_ALWAYS_INLINE
void
1231 Debug_SetValueRangeToCrashOnTouch(Value
*vec
, size_t len
)
1234 Debug_SetValueRangeToCrashOnTouch(vec
, vec
+ len
);
1238 } /* namespace js */
1239 #endif /* jsvalue_h__ */