2 * Copyright (C) 1999-2001 Harri Porten (porten@kde.org)
3 * Copyright (C) 2001 Peter Kelly (pmk@post.com)
4 * Copyright (C) 2003, 2004, 2005, 2007, 2008, 2009 Apple Inc. All rights reserved.
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Library General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Library General Public License for more details.
16 * You should have received a copy of the GNU Library General Public License
17 * along with this library; see the file COPYING.LIB. If not, write to
18 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19 * Boston, MA 02110-1301, USA.
27 #include "ConstructData.h"
29 #include <stddef.h> // for size_t
31 #include <wtf/AlwaysInline.h>
32 #include <wtf/Assertions.h>
33 #include <wtf/HashTraits.h>
34 #include <wtf/MathExtras.h>
45 class PutPropertySlot
;
51 enum PreferredPrimitiveType
{ NoPreference
, PreferNumber
, PreferString
};
54 typedef int64_t EncodedJSValue
;
56 typedef void* EncodedJSValue
;
59 double nonInlineNaN();
60 int32_t toInt32SlowCase(double, bool& ok
);
61 uint32_t toUInt32SlowCase(double, bool& ok
);
64 friend class JSImmediate
;
65 friend struct EncodedJSValueHashTraits
;
67 friend class JITStubs
;
68 friend class JITStubCall
;
69 friend class JSInterfaceJIT
;
70 friend class SpecializedThunkJIT
;
73 static EncodedJSValue
encode(JSValue value
);
74 static JSValue
decode(EncodedJSValue ptr
);
75 #if !USE(JSVALUE32_64)
77 static JSValue
makeImmediate(intptr_t value
);
78 intptr_t immediateValue();
81 enum JSNullTag
{ JSNull
};
82 enum JSUndefinedTag
{ JSUndefined
};
83 enum JSTrueTag
{ JSTrue
};
84 enum JSFalseTag
{ JSFalse
};
85 enum EncodeAsDoubleTag
{ EncodeAsDouble
};
89 JSValue(JSUndefinedTag
);
93 JSValue(const JSCell
* ptr
);
96 JSValue(EncodeAsDoubleTag
, ExecState
*, double);
97 JSValue(ExecState
*, double);
98 JSValue(ExecState
*, char);
99 JSValue(ExecState
*, unsigned char);
100 JSValue(ExecState
*, short);
101 JSValue(ExecState
*, unsigned short);
102 JSValue(ExecState
*, int);
103 JSValue(ExecState
*, unsigned);
104 JSValue(ExecState
*, long);
105 JSValue(ExecState
*, unsigned long);
106 JSValue(ExecState
*, long long);
107 JSValue(ExecState
*, unsigned long long);
108 JSValue(JSGlobalData
*, double);
109 JSValue(JSGlobalData
*, int);
110 JSValue(JSGlobalData
*, unsigned);
112 operator bool() const;
113 bool operator==(const JSValue
& other
) const;
114 bool operator!=(const JSValue
& other
) const;
116 bool isInt32() const;
117 bool isUInt32() const;
118 bool isDouble() const;
120 bool isFalse() const;
122 int32_t asInt32() const;
123 uint32_t asUInt32() const;
124 double asDouble() const;
126 // Querying the type.
127 bool isUndefined() const;
129 bool isUndefinedOrNull() const;
130 bool isBoolean() const;
131 bool isNumber() const;
132 bool isString() const;
133 bool isGetterSetter() const;
134 bool isObject() const;
135 bool inherits(const ClassInfo
*) const;
137 // Extracting the value.
138 bool getBoolean(bool&) const;
139 bool getBoolean() const; // false if not a boolean
140 bool getNumber(double&) const;
141 double uncheckedGetNumber() const;
142 bool getString(ExecState
* exec
, UString
&) const;
143 UString
getString(ExecState
* exec
) const; // null string if not a string
144 JSObject
* getObject() const; // 0 if not an object
146 CallType
getCallData(CallData
&);
147 ConstructType
getConstructData(ConstructData
&);
149 // Extracting integer values.
150 bool getUInt32(uint32_t&) const;
152 // Basic conversions.
153 JSValue
toPrimitive(ExecState
*, PreferredPrimitiveType
= NoPreference
) const;
154 bool getPrimitiveNumber(ExecState
*, double& number
, JSValue
&);
156 bool toBoolean(ExecState
*) const;
158 // toNumber conversion is expected to be side effect free if an exception has
159 // been set in the ExecState already.
160 double toNumber(ExecState
*) const;
161 JSValue
toJSNumber(ExecState
*) const; // Fast path for when you expect that the value is an immediate number.
162 UString
toString(ExecState
*) const;
163 UString
toPrimitiveString(ExecState
*) const;
164 JSObject
* toObject(ExecState
*) const;
166 // Integer conversions.
167 double toInteger(ExecState
*) const;
168 double toIntegerPreserveNaN(ExecState
*) const;
169 int32_t toInt32(ExecState
*) const;
170 int32_t toInt32(ExecState
*, bool& ok
) const;
171 uint32_t toUInt32(ExecState
*) const;
172 uint32_t toUInt32(ExecState
*, bool& ok
) const;
174 #if ENABLE(JSC_ZOMBIES)
175 bool isZombie() const;
178 // Floating point conversions (this is a convenience method for webcore;
179 // signle precision float is not a representation used in JS or JSC).
180 float toFloat(ExecState
* exec
) const { return static_cast<float>(toNumber(exec
)); }
182 // Object operations, with the toObject operation included.
183 JSValue
get(ExecState
*, const Identifier
& propertyName
) const;
184 JSValue
get(ExecState
*, const Identifier
& propertyName
, PropertySlot
&) const;
185 JSValue
get(ExecState
*, unsigned propertyName
) const;
186 JSValue
get(ExecState
*, unsigned propertyName
, PropertySlot
&) const;
187 void put(ExecState
*, const Identifier
& propertyName
, JSValue
, PutPropertySlot
&);
188 void putDirect(ExecState
*, const Identifier
& propertyName
, JSValue
, PutPropertySlot
&);
189 void put(ExecState
*, unsigned propertyName
, JSValue
);
191 bool needsThisConversion() const;
192 JSObject
* toThisObject(ExecState
*) const;
193 UString
toThisString(ExecState
*) const;
194 JSString
* toThisJSString(ExecState
*) const;
196 static bool equal(ExecState
* exec
, JSValue v1
, JSValue v2
);
197 static bool equalSlowCase(ExecState
* exec
, JSValue v1
, JSValue v2
);
198 static bool equalSlowCaseInline(ExecState
* exec
, JSValue v1
, JSValue v2
);
199 static bool strictEqual(ExecState
* exec
, JSValue v1
, JSValue v2
);
200 static bool strictEqualSlowCase(ExecState
* exec
, JSValue v1
, JSValue v2
);
201 static bool strictEqualSlowCaseInline(ExecState
* exec
, JSValue v1
, JSValue v2
);
203 JSValue
getJSNumber(); // JSValue() if this is not a JSNumber or number object
206 JSCell
* asCell() const;
213 enum HashTableDeletedValueTag
{ HashTableDeletedValue
};
214 JSValue(HashTableDeletedValueTag
);
216 inline const JSValue
asValue() const { return *this; }
217 JSObject
* toObjectSlowCase(ExecState
*) const;
218 JSObject
* toThisObjectSlowCase(ExecState
*) const;
220 JSObject
* synthesizePrototype(ExecState
*) const;
221 JSObject
* synthesizeObject(ExecState
*) const;
223 #if USE(JSVALUE32_64)
224 enum { Int32Tag
= 0xffffffff };
225 enum { CellTag
= 0xfffffffe };
226 enum { TrueTag
= 0xfffffffd };
227 enum { FalseTag
= 0xfffffffc };
228 enum { NullTag
= 0xfffffffb };
229 enum { UndefinedTag
= 0xfffffffa };
230 enum { EmptyValueTag
= 0xfffffff9 };
231 enum { DeletedValueTag
= 0xfffffff8 };
233 enum { LowestTag
= DeletedValueTag
};
235 uint32_t tag() const;
236 int32_t payload() const;
239 EncodedJSValue asEncodedJSValue
;
253 #else // USE(JSVALUE32_64)
255 #endif // USE(JSVALUE32_64)
258 #if USE(JSVALUE32_64)
259 typedef IntHash
<EncodedJSValue
> EncodedJSValueHash
;
261 struct EncodedJSValueHashTraits
: HashTraits
<EncodedJSValue
> {
262 static const bool emptyValueIsZero
= false;
263 static EncodedJSValue
emptyValue() { return JSValue::encode(JSValue()); }
264 static void constructDeletedValue(EncodedJSValue
& slot
) { slot
= JSValue::encode(JSValue(JSValue::HashTableDeletedValue
)); }
265 static bool isDeletedValue(EncodedJSValue value
) { return value
== JSValue::encode(JSValue(JSValue::HashTableDeletedValue
)); }
268 typedef PtrHash
<EncodedJSValue
> EncodedJSValueHash
;
270 struct EncodedJSValueHashTraits
: HashTraits
<EncodedJSValue
> {
271 static void constructDeletedValue(EncodedJSValue
& slot
) { slot
= JSValue::encode(JSValue(JSValue::HashTableDeletedValue
)); }
272 static bool isDeletedValue(EncodedJSValue value
) { return value
== JSValue::encode(JSValue(JSValue::HashTableDeletedValue
)); }
276 // Stand-alone helper functions.
277 inline JSValue
jsNull()
279 return JSValue(JSValue::JSNull
);
282 inline JSValue
jsUndefined()
284 return JSValue(JSValue::JSUndefined
);
287 inline JSValue
jsBoolean(bool b
)
289 return b
? JSValue(JSValue::JSTrue
) : JSValue(JSValue::JSFalse
);
292 ALWAYS_INLINE JSValue
jsDoubleNumber(ExecState
* exec
, double d
)
294 return JSValue(JSValue::EncodeAsDouble
, exec
, d
);
297 ALWAYS_INLINE JSValue
jsNumber(ExecState
* exec
, double d
)
299 return JSValue(exec
, d
);
302 ALWAYS_INLINE JSValue
jsNumber(ExecState
* exec
, char i
)
304 return JSValue(exec
, i
);
307 ALWAYS_INLINE JSValue
jsNumber(ExecState
* exec
, unsigned char i
)
309 return JSValue(exec
, i
);
312 ALWAYS_INLINE JSValue
jsNumber(ExecState
* exec
, short i
)
314 return JSValue(exec
, i
);
317 ALWAYS_INLINE JSValue
jsNumber(ExecState
* exec
, unsigned short i
)
319 return JSValue(exec
, i
);
322 ALWAYS_INLINE JSValue
jsNumber(ExecState
* exec
, int i
)
324 return JSValue(exec
, i
);
327 ALWAYS_INLINE JSValue
jsNumber(ExecState
* exec
, unsigned i
)
329 return JSValue(exec
, i
);
332 ALWAYS_INLINE JSValue
jsNumber(ExecState
* exec
, long i
)
334 return JSValue(exec
, i
);
337 ALWAYS_INLINE JSValue
jsNumber(ExecState
* exec
, unsigned long i
)
339 return JSValue(exec
, i
);
342 ALWAYS_INLINE JSValue
jsNumber(ExecState
* exec
, long long i
)
344 return JSValue(exec
, i
);
347 ALWAYS_INLINE JSValue
jsNumber(ExecState
* exec
, unsigned long long i
)
349 return JSValue(exec
, i
);
352 ALWAYS_INLINE JSValue
jsNumber(JSGlobalData
* globalData
, double d
)
354 return JSValue(globalData
, d
);
357 ALWAYS_INLINE JSValue
jsNumber(JSGlobalData
* globalData
, int i
)
359 return JSValue(globalData
, i
);
362 ALWAYS_INLINE JSValue
jsNumber(JSGlobalData
* globalData
, unsigned i
)
364 return JSValue(globalData
, i
);
367 inline bool operator==(const JSValue a
, const JSCell
* b
) { return a
== JSValue(b
); }
368 inline bool operator==(const JSCell
* a
, const JSValue b
) { return JSValue(a
) == b
; }
370 inline bool operator!=(const JSValue a
, const JSCell
* b
) { return a
!= JSValue(b
); }
371 inline bool operator!=(const JSCell
* a
, const JSValue b
) { return JSValue(a
) != b
; }
373 inline int32_t toInt32(double val
)
375 if (!(val
>= -2147483648.0 && val
< 2147483648.0)) {
377 return toInt32SlowCase(val
, ignored
);
379 return static_cast<int32_t>(val
);
382 inline uint32_t toUInt32(double val
)
384 if (!(val
>= 0.0 && val
< 4294967296.0)) {
386 return toUInt32SlowCase(val
, ignored
);
388 return static_cast<uint32_t>(val
);
391 // FIXME: We should deprecate this and just use JSValue::asCell() instead.
392 JSCell
* asCell(JSValue
);
394 inline JSCell
* asCell(JSValue value
)
396 return value
.asCell();
399 ALWAYS_INLINE
int32_t JSValue::toInt32(ExecState
* exec
) const
404 return toInt32SlowCase(toNumber(exec
), ignored
);
407 inline uint32_t JSValue::toUInt32(ExecState
* exec
) const
412 return toUInt32SlowCase(toNumber(exec
), ignored
);
415 inline int32_t JSValue::toInt32(ExecState
* exec
, bool& ok
) const
421 return toInt32SlowCase(toNumber(exec
), ok
);
424 inline uint32_t JSValue::toUInt32(ExecState
* exec
, bool& ok
) const
430 return toUInt32SlowCase(toNumber(exec
), ok
);
433 #if USE(JSVALUE32_64)
434 inline JSValue
jsNaN(ExecState
* exec
)
436 return JSValue(exec
, nonInlineNaN());
439 // JSValue member functions.
440 inline EncodedJSValue
JSValue::encode(JSValue value
)
442 return value
.u
.asEncodedJSValue
;
445 inline JSValue
JSValue::decode(EncodedJSValue encodedJSValue
)
448 v
.u
.asEncodedJSValue
= encodedJSValue
;
449 #if ENABLE(JSC_ZOMBIES)
450 ASSERT(!v
.isZombie());
455 inline JSValue::JSValue()
457 u
.asBits
.tag
= EmptyValueTag
;
458 u
.asBits
.payload
= 0;
461 inline JSValue::JSValue(JSNullTag
)
463 u
.asBits
.tag
= NullTag
;
464 u
.asBits
.payload
= 0;
467 inline JSValue::JSValue(JSUndefinedTag
)
469 u
.asBits
.tag
= UndefinedTag
;
470 u
.asBits
.payload
= 0;
473 inline JSValue::JSValue(JSTrueTag
)
475 u
.asBits
.tag
= TrueTag
;
476 u
.asBits
.payload
= 0;
479 inline JSValue::JSValue(JSFalseTag
)
481 u
.asBits
.tag
= FalseTag
;
482 u
.asBits
.payload
= 0;
485 inline JSValue::JSValue(HashTableDeletedValueTag
)
487 u
.asBits
.tag
= DeletedValueTag
;
488 u
.asBits
.payload
= 0;
491 inline JSValue::JSValue(JSCell
* ptr
)
494 u
.asBits
.tag
= CellTag
;
496 u
.asBits
.tag
= EmptyValueTag
;
497 u
.asBits
.payload
= reinterpret_cast<int32_t>(ptr
);
498 #if ENABLE(JSC_ZOMBIES)
503 inline JSValue::JSValue(const JSCell
* ptr
)
506 u
.asBits
.tag
= CellTag
;
508 u
.asBits
.tag
= EmptyValueTag
;
509 u
.asBits
.payload
= reinterpret_cast<int32_t>(const_cast<JSCell
*>(ptr
));
510 #if ENABLE(JSC_ZOMBIES)
515 inline JSValue::operator bool() const
517 ASSERT(tag() != DeletedValueTag
);
518 return tag() != EmptyValueTag
;
521 inline bool JSValue::operator==(const JSValue
& other
) const
523 return u
.asEncodedJSValue
== other
.u
.asEncodedJSValue
;
526 inline bool JSValue::operator!=(const JSValue
& other
) const
528 return u
.asEncodedJSValue
!= other
.u
.asEncodedJSValue
;
531 inline bool JSValue::isUndefined() const
533 return tag() == UndefinedTag
;
536 inline bool JSValue::isNull() const
538 return tag() == NullTag
;
541 inline bool JSValue::isUndefinedOrNull() const
543 return isUndefined() || isNull();
546 inline bool JSValue::isCell() const
548 return tag() == CellTag
;
551 inline bool JSValue::isInt32() const
553 return tag() == Int32Tag
;
556 inline bool JSValue::isUInt32() const
558 return tag() == Int32Tag
&& asInt32() > -1;
561 inline bool JSValue::isDouble() const
563 return tag() < LowestTag
;
566 inline bool JSValue::isTrue() const
568 return tag() == TrueTag
;
571 inline bool JSValue::isFalse() const
573 return tag() == FalseTag
;
576 inline uint32_t JSValue::tag() const
581 inline int32_t JSValue::payload() const
583 return u
.asBits
.payload
;
586 inline int32_t JSValue::asInt32() const
589 return u
.asBits
.payload
;
592 inline uint32_t JSValue::asUInt32() const
595 return u
.asBits
.payload
;
598 inline double JSValue::asDouble() const
604 ALWAYS_INLINE JSCell
* JSValue::asCell() const
607 return reinterpret_cast<JSCell
*>(u
.asBits
.payload
);
610 ALWAYS_INLINE
JSValue::JSValue(EncodeAsDoubleTag
, ExecState
*, double d
)
615 inline JSValue::JSValue(ExecState
* exec
, double d
)
617 const int32_t asInt32
= static_cast<int32_t>(d
);
618 if (asInt32
!= d
|| (!asInt32
&& signbit(d
))) { // true for -0.0
622 *this = JSValue(exec
, static_cast<int32_t>(d
));
625 inline JSValue::JSValue(ExecState
* exec
, char i
)
627 *this = JSValue(exec
, static_cast<int32_t>(i
));
630 inline JSValue::JSValue(ExecState
* exec
, unsigned char i
)
632 *this = JSValue(exec
, static_cast<int32_t>(i
));
635 inline JSValue::JSValue(ExecState
* exec
, short i
)
637 *this = JSValue(exec
, static_cast<int32_t>(i
));
640 inline JSValue::JSValue(ExecState
* exec
, unsigned short i
)
642 *this = JSValue(exec
, static_cast<int32_t>(i
));
645 inline JSValue::JSValue(ExecState
*, int i
)
647 u
.asBits
.tag
= Int32Tag
;
648 u
.asBits
.payload
= i
;
651 inline JSValue::JSValue(ExecState
* exec
, unsigned i
)
653 if (static_cast<int32_t>(i
) < 0) {
654 *this = JSValue(exec
, static_cast<double>(i
));
657 *this = JSValue(exec
, static_cast<int32_t>(i
));
660 inline JSValue::JSValue(ExecState
* exec
, long i
)
662 if (static_cast<int32_t>(i
) != i
) {
663 *this = JSValue(exec
, static_cast<double>(i
));
666 *this = JSValue(exec
, static_cast<int32_t>(i
));
669 inline JSValue::JSValue(ExecState
* exec
, unsigned long i
)
671 if (static_cast<uint32_t>(i
) != i
) {
672 *this = JSValue(exec
, static_cast<double>(i
));
675 *this = JSValue(exec
, static_cast<uint32_t>(i
));
678 inline JSValue::JSValue(ExecState
* exec
, long long i
)
680 if (static_cast<int32_t>(i
) != i
) {
681 *this = JSValue(exec
, static_cast<double>(i
));
684 *this = JSValue(exec
, static_cast<int32_t>(i
));
687 inline JSValue::JSValue(ExecState
* exec
, unsigned long long i
)
689 if (static_cast<uint32_t>(i
) != i
) {
690 *this = JSValue(exec
, static_cast<double>(i
));
693 *this = JSValue(exec
, static_cast<uint32_t>(i
));
696 inline JSValue::JSValue(JSGlobalData
* globalData
, double d
)
698 const int32_t asInt32
= static_cast<int32_t>(d
);
699 if (asInt32
!= d
|| (!asInt32
&& signbit(d
))) { // true for -0.0
703 *this = JSValue(globalData
, static_cast<int32_t>(d
));
706 inline JSValue::JSValue(JSGlobalData
*, int i
)
708 u
.asBits
.tag
= Int32Tag
;
709 u
.asBits
.payload
= i
;
712 inline JSValue::JSValue(JSGlobalData
* globalData
, unsigned i
)
714 if (static_cast<int32_t>(i
) < 0) {
715 *this = JSValue(globalData
, static_cast<double>(i
));
718 *this = JSValue(globalData
, static_cast<int32_t>(i
));
721 inline bool JSValue::isNumber() const
723 return isInt32() || isDouble();
726 inline bool JSValue::isBoolean() const
728 return isTrue() || isFalse();
731 inline bool JSValue::getBoolean(bool& v
) const
745 inline bool JSValue::getBoolean() const
748 return tag() == TrueTag
;
751 inline double JSValue::uncheckedGetNumber() const
754 return isInt32() ? asInt32() : asDouble();
757 ALWAYS_INLINE JSValue
JSValue::toJSNumber(ExecState
* exec
) const
759 return isNumber() ? asValue() : jsNumber(exec
, this->toNumber(exec
));
762 inline bool JSValue::getNumber(double& result
) const
775 #else // USE(JSVALUE32_64)
777 // JSValue member functions.
778 inline EncodedJSValue
JSValue::encode(JSValue value
)
780 return reinterpret_cast<EncodedJSValue
>(value
.m_ptr
);
783 inline JSValue
JSValue::decode(EncodedJSValue ptr
)
785 return JSValue(reinterpret_cast<JSCell
*>(ptr
));
788 inline JSValue
JSValue::makeImmediate(intptr_t value
)
790 return JSValue(reinterpret_cast<JSCell
*>(value
));
793 inline intptr_t JSValue::immediateValue()
795 return reinterpret_cast<intptr_t>(m_ptr
);
798 // 0x0 can never occur naturally because it has a tag of 00, indicating a pointer value, but a payload of 0x0, which is in the (invalid) zero page.
799 inline JSValue::JSValue()
804 // 0x4 can never occur naturally because it has a tag of 00, indicating a pointer value, but a payload of 0x4, which is in the (invalid) zero page.
805 inline JSValue::JSValue(HashTableDeletedValueTag
)
806 : m_ptr(reinterpret_cast<JSCell
*>(0x4))
810 inline JSValue::JSValue(JSCell
* ptr
)
813 #if ENABLE(JSC_ZOMBIES)
818 inline JSValue::JSValue(const JSCell
* ptr
)
819 : m_ptr(const_cast<JSCell
*>(ptr
))
821 #if ENABLE(JSC_ZOMBIES)
826 inline JSValue::operator bool() const
831 inline bool JSValue::operator==(const JSValue
& other
) const
833 return m_ptr
== other
.m_ptr
;
836 inline bool JSValue::operator!=(const JSValue
& other
) const
838 return m_ptr
!= other
.m_ptr
;
841 inline bool JSValue::isUndefined() const
843 return asValue() == jsUndefined();
846 inline bool JSValue::isNull() const
848 return asValue() == jsNull();
850 #endif // USE(JSVALUE32_64)
852 typedef std::pair
<JSValue
, UString
> ValueStringPair
;