summaryrefslogtreecommitdiffstats
path: root/Source/JavaScriptCore/runtime/JSValue.h
diff options
context:
space:
mode:
authorBen Murdoch <benm@google.com>2011-06-02 12:07:03 +0100
committerBen Murdoch <benm@google.com>2011-06-10 10:47:21 +0100
commit2daae5fd11344eaa88a0d92b0f6d65f8d2255c00 (patch)
treee4964fbd1cb70599f7718ff03e50ea1dab33890b /Source/JavaScriptCore/runtime/JSValue.h
parent87bdf0060a247bfbe668342b87e0874182e0ffa9 (diff)
downloadexternal_webkit-2daae5fd11344eaa88a0d92b0f6d65f8d2255c00.zip
external_webkit-2daae5fd11344eaa88a0d92b0f6d65f8d2255c00.tar.gz
external_webkit-2daae5fd11344eaa88a0d92b0f6d65f8d2255c00.tar.bz2
Merge WebKit at r84325: Initial merge by git.
Change-Id: Ic1a909300ecc0a13ddc6b4e784371d2ac6e3d59b
Diffstat (limited to 'Source/JavaScriptCore/runtime/JSValue.h')
-rw-r--r--Source/JavaScriptCore/runtime/JSValue.h545
1 files changed, 117 insertions, 428 deletions
diff --git a/Source/JavaScriptCore/runtime/JSValue.h b/Source/JavaScriptCore/runtime/JSValue.h
index 098123e..de50011 100644
--- a/Source/JavaScriptCore/runtime/JSValue.h
+++ b/Source/JavaScriptCore/runtime/JSValue.h
@@ -30,15 +30,18 @@
#include <wtf/Assertions.h>
#include <wtf/HashTraits.h>
#include <wtf/MathExtras.h>
+#include <wtf/StdLibExtras.h>
namespace JSC {
+ extern const double NaN;
+ extern const double Inf;
+
class ExecState;
class Identifier;
class JSCell;
class JSGlobalData;
class JSGlobalObject;
- class JSImmediate;
class JSObject;
class JSString;
class PropertySlot;
@@ -48,7 +51,6 @@ namespace JSC {
struct ClassInfo;
struct Instruction;
- template <class T> class DeprecatedPtr;
template <class T> class WriteBarrierBase;
enum PreferredPrimitiveType { NoPreference, PreferNumber, PreferString };
@@ -61,7 +63,7 @@ namespace JSC {
#endif
union EncodedValueDescriptor {
- EncodedJSValue asEncodedJSValue;
+ int64_t asInt64;
#if USE(JSVALUE32_64)
double asDouble;
#elif USE(JSVALUE64)
@@ -95,7 +97,6 @@ namespace JSC {
}
class JSValue {
- friend class JSImmediate;
friend struct EncodedJSValueHashTraits;
friend class JIT;
friend class JITStubs;
@@ -104,14 +105,9 @@ namespace JSC {
friend class SpecializedThunkJIT;
public:
- static EncodedJSValue encode(JSValue value);
- static JSValue decode(EncodedJSValue ptr);
-#if USE(JSVALUE64)
- private:
- static JSValue makeImmediate(intptr_t value);
- intptr_t immediateValue();
- public:
-#endif
+ static EncodedJSValue encode(JSValue);
+ static JSValue decode(EncodedJSValue);
+
enum JSNullTag { JSNull };
enum JSUndefinedTag { JSUndefined };
enum JSTrueTag { JSTrue };
@@ -239,7 +235,6 @@ namespace JSC {
#endif
private:
- template <class T> JSValue(DeprecatedPtr<T>);
template <class T> JSValue(WriteBarrierBase<T>);
enum HashTableDeletedValueTag { HashTableDeletedValue };
@@ -253,24 +248,120 @@ namespace JSC {
JSObject* synthesizeObject(ExecState*) const;
#if USE(JSVALUE32_64)
- enum { NullTag = 0xffffffff };
- enum { UndefinedTag = 0xfffffffe };
- enum { Int32Tag = 0xfffffffd };
- enum { CellTag = 0xfffffffc };
- enum { TrueTag = 0xfffffffb };
- enum { FalseTag = 0xfffffffa };
- enum { EmptyValueTag = 0xfffffff9 };
- enum { DeletedValueTag = 0xfffffff8 };
-
+ /*
+ * On 32-bit platforms USE(JSVALUE32_64) should be defined, and we use a NaN-encoded
+ * form for immediates.
+ *
+ * The encoding makes use of unused NaN space in the IEEE754 representation. Any value
+ * with the top 13 bits set represents a QNaN (with the sign bit set). QNaN values
+ * can encode a 51-bit payload. Hardware produced and C-library payloads typically
+ * have a payload of zero. We assume that non-zero payloads are available to encode
+ * pointer and integer values. Since any 64-bit bit pattern where the top 15 bits are
+ * all set represents a NaN with a non-zero payload, we can use this space in the NaN
+ * ranges to encode other values (however there are also other ranges of NaN space that
+ * could have been selected).
+ *
+ * For JSValues that do not contain a double value, the high 32 bits contain the tag
+ * values listed in the enums below, which all correspond to NaN-space. In the case of
+ * cell, integer and bool values the lower 32 bits (the 'payload') contain the pointer
+ * integer or boolean value; in the case of all other tags the payload is 0.
+ */
+ enum { Int32Tag = 0xffffffff };
+ enum { BooleanTag = 0xfffffffe };
+ enum { NullTag = 0xfffffffd };
+ enum { UndefinedTag = 0xfffffffc };
+ enum { CellTag = 0xfffffffb };
+ enum { EmptyValueTag = 0xfffffffa };
+ enum { DeletedValueTag = 0xfffffff9 };
+
enum { LowestTag = DeletedValueTag };
uint32_t tag() const;
int32_t payload() const;
-
- EncodedValueDescriptor u;
#elif USE(JSVALUE64)
- JSCell* m_ptr;
+ /*
+ * On 64-bit platforms USE(JSVALUE64) should be defined, and we use a NaN-encoded
+ * form for immediates.
+ *
+ * The encoding makes use of unused NaN space in the IEEE754 representation. Any value
+ * with the top 13 bits set represents a QNaN (with the sign bit set). QNaN values
+ * can encode a 51-bit payload. Hardware produced and C-library payloads typically
+ * have a payload of zero. We assume that non-zero payloads are available to encode
+ * pointer and integer values. Since any 64-bit bit pattern where the top 15 bits are
+ * all set represents a NaN with a non-zero payload, we can use this space in the NaN
+ * ranges to encode other values (however there are also other ranges of NaN space that
+ * could have been selected).
+ *
+ * This range of NaN space is represented by 64-bit numbers begining with the 16-bit
+ * hex patterns 0xFFFE and 0xFFFF - we rely on the fact that no valid double-precision
+ * numbers will begin fall in these ranges.
+ *
+ * The top 16-bits denote the type of the encoded JSValue:
+ *
+ * Pointer { 0000:PPPP:PPPP:PPPP
+ * / 0001:****:****:****
+ * Double { ...
+ * \ FFFE:****:****:****
+ * Integer { FFFF:0000:IIII:IIII
+ *
+ * The scheme we have implemented encodes double precision values by performing a
+ * 64-bit integer addition of the value 2^48 to the number. After this manipulation
+ * no encoded double-precision value will begin with the pattern 0x0000 or 0xFFFF.
+ * Values must be decoded by reversing this operation before subsequent floating point
+ * operations my be peformed.
+ *
+ * 32-bit signed integers are marked with the 16-bit tag 0xFFFF.
+ *
+ * The tag 0x0000 denotes a pointer, or another form of tagged immediate. Boolean,
+ * null and undefined values are represented by specific, invalid pointer values:
+ *
+ * False: 0x06
+ * True: 0x07
+ * Undefined: 0x0a
+ * Null: 0x02
+ *
+ * These values have the following properties:
+ * - Bit 1 (TagBitTypeOther) is set for all four values, allowing real pointers to be
+ * quickly distinguished from all immediate values, including these invalid pointers.
+ * - With bit 3 is masked out (TagBitUndefined) Undefined and Null share the
+ * same value, allowing null & undefined to be quickly detected.
+ *
+ * No valid JSValue will have the bit pattern 0x0, this is used to represent array
+ * holes, and as a C++ 'no value' result (e.g. JSValue() has an internal value of 0).
+ */
+
+ // These values are #defines since using static const integers here is a ~1% regression!
+
+ // This value is 2^48, used to encode doubles such that the encoded value will begin
+ // with a 16-bit pattern within the range 0x0001..0xFFFE.
+ #define DoubleEncodeOffset 0x1000000000000ll
+ // If all bits in the mask are set, this indicates an integer number,
+ // if any but not all are set this value is a double precision number.
+ #define TagTypeNumber 0xffff000000000000ll
+
+ // All non-numeric (bool, null, undefined) immediates have bit 2 set.
+ #define TagBitTypeOther 0x2ll
+ #define TagBitBool 0x4ll
+ #define TagBitUndefined 0x8ll
+ // Combined integer value for non-numeric immediates.
+ #define ValueFalse (TagBitTypeOther | TagBitBool | false)
+ #define ValueTrue (TagBitTypeOther | TagBitBool | true)
+ #define ValueUndefined (TagBitTypeOther | TagBitUndefined)
+ #define ValueNull (TagBitTypeOther)
+
+ // TagMask is used to check for all types of immediate values (either number or 'other').
+ #define TagMask (TagTypeNumber | TagBitTypeOther)
+
+ // These special values are never visible to JavaScript code; Empty is used to represent
+ // Array holes, and for uninitialized JSValues. Deleted is used in hash table code.
+ // These values would map to cell types in the JSValue encoding, but not valid GC cell
+ // pointer should have either of these values (Empty is null, deleted is at an invalid
+ // alignment for a GC cell, and in the zero page).
+ #define ValueEmpty 0x0ll
+ #define ValueDeleted 0x4ll
#endif
+
+ EncodedValueDescriptor u;
};
#if USE(JSVALUE32_64)
@@ -373,409 +464,7 @@ namespace JSC {
inline bool operator!=(const JSValue a, const JSCell* b) { return a != JSValue(b); }
inline bool operator!=(const JSCell* a, const JSValue b) { return JSValue(a) != b; }
- ALWAYS_INLINE int32_t JSValue::toInt32(ExecState* exec) const
- {
- if (isInt32())
- return asInt32();
- return JSC::toInt32(toNumber(exec));
- }
-
- inline uint32_t JSValue::toUInt32(ExecState* exec) const
- {
- // See comment on JSC::toUInt32, above.
- return toInt32(exec);
- }
-
-#if USE(JSVALUE32_64)
- inline JSValue jsNaN()
- {
- return JSValue(nonInlineNaN());
- }
-
- // JSValue member functions.
- inline EncodedJSValue JSValue::encode(JSValue value)
- {
- return value.u.asEncodedJSValue;
- }
-
- inline JSValue JSValue::decode(EncodedJSValue encodedJSValue)
- {
- JSValue v;
- v.u.asEncodedJSValue = encodedJSValue;
- return v;
- }
-
- inline JSValue::JSValue()
- {
- u.asBits.tag = EmptyValueTag;
- u.asBits.payload = 0;
- }
-
- inline JSValue::JSValue(JSNullTag)
- {
- u.asBits.tag = NullTag;
- u.asBits.payload = 0;
- }
-
- inline JSValue::JSValue(JSUndefinedTag)
- {
- u.asBits.tag = UndefinedTag;
- u.asBits.payload = 0;
- }
-
- inline JSValue::JSValue(JSTrueTag)
- {
- u.asBits.tag = TrueTag;
- u.asBits.payload = 0;
- }
-
- inline JSValue::JSValue(JSFalseTag)
- {
- u.asBits.tag = FalseTag;
- u.asBits.payload = 0;
- }
-
- inline JSValue::JSValue(HashTableDeletedValueTag)
- {
- u.asBits.tag = DeletedValueTag;
- u.asBits.payload = 0;
- }
-
- inline JSValue::JSValue(JSCell* ptr)
- {
- if (ptr)
- u.asBits.tag = CellTag;
- else
- u.asBits.tag = EmptyValueTag;
- u.asBits.payload = reinterpret_cast<int32_t>(ptr);
-#if ENABLE(JSC_ZOMBIES)
- ASSERT(!isZombie());
-#endif
- }
-
- inline JSValue::JSValue(const JSCell* ptr)
- {
- if (ptr)
- u.asBits.tag = CellTag;
- else
- u.asBits.tag = EmptyValueTag;
- u.asBits.payload = reinterpret_cast<int32_t>(const_cast<JSCell*>(ptr));
-#if ENABLE(JSC_ZOMBIES)
- ASSERT(!isZombie());
-#endif
- }
-
- inline JSValue::operator bool() const
- {
- ASSERT(tag() != DeletedValueTag);
- return tag() != EmptyValueTag;
- }
-
- inline bool JSValue::operator==(const JSValue& other) const
- {
- return u.asEncodedJSValue == other.u.asEncodedJSValue;
- }
-
- inline bool JSValue::operator!=(const JSValue& other) const
- {
- return u.asEncodedJSValue != other.u.asEncodedJSValue;
- }
-
- inline bool JSValue::isUndefined() const
- {
- return tag() == UndefinedTag;
- }
-
- inline bool JSValue::isNull() const
- {
- return tag() == NullTag;
- }
-
- inline bool JSValue::isUndefinedOrNull() const
- {
- return isUndefined() || isNull();
- }
-
- inline bool JSValue::isCell() const
- {
- return tag() == CellTag;
- }
-
- inline bool JSValue::isInt32() const
- {
- return tag() == Int32Tag;
- }
-
- inline bool JSValue::isUInt32() const
- {
- return tag() == Int32Tag && asInt32() > -1;
- }
-
- inline bool JSValue::isDouble() const
- {
- return tag() < LowestTag;
- }
-
- inline bool JSValue::isTrue() const
- {
- return tag() == TrueTag;
- }
-
- inline bool JSValue::isFalse() const
- {
- return tag() == FalseTag;
- }
-
- inline uint32_t JSValue::tag() const
- {
- return u.asBits.tag;
- }
-
- inline int32_t JSValue::payload() const
- {
- return u.asBits.payload;
- }
-
- inline int32_t JSValue::asInt32() const
- {
- ASSERT(isInt32());
- return u.asBits.payload;
- }
-
- inline uint32_t JSValue::asUInt32() const
- {
- ASSERT(isUInt32());
- return u.asBits.payload;
- }
-
- inline double JSValue::asDouble() const
- {
- ASSERT(isDouble());
- return u.asDouble;
- }
-
- ALWAYS_INLINE JSCell* JSValue::asCell() const
- {
- ASSERT(isCell());
- return reinterpret_cast<JSCell*>(u.asBits.payload);
- }
-
- ALWAYS_INLINE JSValue::JSValue(EncodeAsDoubleTag, double d)
- {
- u.asDouble = d;
- }
-
- inline JSValue::JSValue(double d)
- {
- const int32_t asInt32 = static_cast<int32_t>(d);
- if (asInt32 != d || (!asInt32 && signbit(d))) { // true for -0.0
- u.asDouble = d;
- return;
- }
- *this = JSValue(static_cast<int32_t>(d));
- }
-
- inline JSValue::JSValue(char i)
- {
- *this = JSValue(static_cast<int32_t>(i));
- }
-
- inline JSValue::JSValue(unsigned char i)
- {
- *this = JSValue(static_cast<int32_t>(i));
- }
-
- inline JSValue::JSValue(short i)
- {
- *this = JSValue(static_cast<int32_t>(i));
- }
-
- inline JSValue::JSValue(unsigned short i)
- {
- *this = JSValue(static_cast<int32_t>(i));
- }
-
- inline JSValue::JSValue(int i)
- {
- u.asBits.tag = Int32Tag;
- u.asBits.payload = i;
- }
-
- inline JSValue::JSValue(unsigned i)
- {
- if (static_cast<int32_t>(i) < 0) {
- *this = JSValue(static_cast<double>(i));
- return;
- }
- *this = JSValue(static_cast<int32_t>(i));
- }
-
- inline JSValue::JSValue(long i)
- {
- if (static_cast<int32_t>(i) != i) {
- *this = JSValue(static_cast<double>(i));
- return;
- }
- *this = JSValue(static_cast<int32_t>(i));
- }
-
- inline JSValue::JSValue(unsigned long i)
- {
- if (static_cast<uint32_t>(i) != i) {
- *this = JSValue(static_cast<double>(i));
- return;
- }
- *this = JSValue(static_cast<uint32_t>(i));
- }
-
- inline JSValue::JSValue(long long i)
- {
- if (static_cast<int32_t>(i) != i) {
- *this = JSValue(static_cast<double>(i));
- return;
- }
- *this = JSValue(static_cast<int32_t>(i));
- }
-
- inline JSValue::JSValue(unsigned long long i)
- {
- if (static_cast<uint32_t>(i) != i) {
- *this = JSValue(static_cast<double>(i));
- return;
- }
- *this = JSValue(static_cast<uint32_t>(i));
- }
-
- inline bool JSValue::isNumber() const
- {
- return isInt32() || isDouble();
- }
-
- inline bool JSValue::isBoolean() const
- {
- return isTrue() || isFalse();
- }
-
- inline bool JSValue::getBoolean(bool& v) const
- {
- if (isTrue()) {
- v = true;
- return true;
- }
- if (isFalse()) {
- v = false;
- return true;
- }
-
- return false;
- }
-
- inline bool JSValue::getBoolean() const
- {
- ASSERT(isBoolean());
- return tag() == TrueTag;
- }
-
- inline double JSValue::uncheckedGetNumber() const
- {
- ASSERT(isNumber());
- return isInt32() ? asInt32() : asDouble();
- }
-
- ALWAYS_INLINE JSValue JSValue::toJSNumber(ExecState* exec) const
- {
- return isNumber() ? asValue() : jsNumber(this->toNumber(exec));
- }
-
- inline bool JSValue::getNumber(double& result) const
- {
- if (isInt32()) {
- result = asInt32();
- return true;
- }
- if (isDouble()) {
- result = asDouble();
- return true;
- }
- return false;
- }
-
-#else // USE(JSVALUE32_64)
-
- // JSValue member functions.
- inline EncodedJSValue JSValue::encode(JSValue value)
- {
- return reinterpret_cast<EncodedJSValue>(value.m_ptr);
- }
-
- inline JSValue JSValue::decode(EncodedJSValue ptr)
- {
- return JSValue(reinterpret_cast<JSCell*>(ptr));
- }
-
- inline JSValue JSValue::makeImmediate(intptr_t value)
- {
- return JSValue(reinterpret_cast<JSCell*>(value));
- }
-
- inline intptr_t JSValue::immediateValue()
- {
- return reinterpret_cast<intptr_t>(m_ptr);
- }
-
- // 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.
- inline JSValue::JSValue()
- : m_ptr(0)
- {
- }
-
- // 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.
- inline JSValue::JSValue(HashTableDeletedValueTag)
- : m_ptr(reinterpret_cast<JSCell*>(0x4))
- {
- }
-
- inline JSValue::JSValue(JSCell* ptr)
- : m_ptr(ptr)
- {
-#if ENABLE(JSC_ZOMBIES)
- ASSERT(!isZombie());
-#endif
- }
-
- inline JSValue::JSValue(const JSCell* ptr)
- : m_ptr(const_cast<JSCell*>(ptr))
- {
-#if ENABLE(JSC_ZOMBIES)
- ASSERT(!isZombie());
-#endif
- }
-
- inline JSValue::operator bool() const
- {
- return m_ptr;
- }
-
- inline bool JSValue::operator==(const JSValue& other) const
- {
- return m_ptr == other.m_ptr;
- }
-
- inline bool JSValue::operator!=(const JSValue& other) const
- {
- return m_ptr != other.m_ptr;
- }
-
- inline bool JSValue::isUndefined() const
- {
- return asValue() == jsUndefined();
- }
-
- inline bool JSValue::isNull() const
- {
- return asValue() == jsNull();
- }
-#endif // USE(JSVALUE32_64)
+ bool isZombie(const JSCell*);
} // namespace JSC