diff options
author | Ben Murdoch <benm@google.com> | 2011-06-02 12:07:03 +0100 |
---|---|---|
committer | Ben Murdoch <benm@google.com> | 2011-06-10 10:47:21 +0100 |
commit | 2daae5fd11344eaa88a0d92b0f6d65f8d2255c00 (patch) | |
tree | e4964fbd1cb70599f7718ff03e50ea1dab33890b /Source/JavaScriptCore/runtime/JSValue.h | |
parent | 87bdf0060a247bfbe668342b87e0874182e0ffa9 (diff) | |
download | external_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.h | 545 |
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 |