Home | History | Annotate | Download | only in runtime
      1 /*
      2  *  Copyright (C) 1999-2001 Harri Porten (porten (at) kde.org)
      3  *  Copyright (C) 2001 Peter Kelly (pmk (at) post.com)
      4  *  Copyright (C) 2003, 2004, 2005, 2007, 2008, 2009 Apple Inc. All rights reserved.
      5  *
      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.
     10  *
     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.
     15  *
     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.
     20  *
     21  */
     22 
     23 #ifndef JSValue_h
     24 #define JSValue_h
     25 
     26 #include <math.h>
     27 #include <stddef.h> // for size_t
     28 #include <stdint.h>
     29 #include <wtf/AlwaysInline.h>
     30 #include <wtf/Assertions.h>
     31 #include <wtf/HashTraits.h>
     32 #include <wtf/MathExtras.h>
     33 #include <wtf/StdLibExtras.h>
     34 
     35 namespace JSC {
     36 
     37     extern const double NaN;
     38     extern const double Inf;
     39 
     40     class ExecState;
     41     class Identifier;
     42     class JSCell;
     43     class JSGlobalData;
     44     class JSGlobalObject;
     45     class JSObject;
     46     class JSString;
     47     class PropertySlot;
     48     class PutPropertySlot;
     49     class UString;
     50 
     51     struct ClassInfo;
     52     struct Instruction;
     53 
     54     template <class T> class WriteBarrierBase;
     55 
     56     enum PreferredPrimitiveType { NoPreference, PreferNumber, PreferString };
     57 
     58 
     59 #if USE(JSVALUE32_64)
     60     typedef int64_t EncodedJSValue;
     61 #else
     62     typedef void* EncodedJSValue;
     63 #endif
     64 
     65     union EncodedValueDescriptor {
     66         int64_t asInt64;
     67 #if USE(JSVALUE32_64)
     68         double asDouble;
     69 #elif USE(JSVALUE64)
     70         JSCell* ptr;
     71 #endif
     72 
     73 #if CPU(BIG_ENDIAN)
     74         struct {
     75             int32_t tag;
     76             int32_t payload;
     77         } asBits;
     78 #else
     79         struct {
     80             int32_t payload;
     81             int32_t tag;
     82         } asBits;
     83 #endif
     84     };
     85 
     86     double nonInlineNaN();
     87 
     88     // This implements ToInt32, defined in ECMA-262 9.5.
     89     int32_t toInt32(double);
     90 
     91     // This implements ToUInt32, defined in ECMA-262 9.6.
     92     inline uint32_t toUInt32(double number)
     93     {
     94         // As commented in the spec, the operation of ToInt32 and ToUint32 only differ
     95         // in how the result is interpreted; see NOTEs in sections 9.5 and 9.6.
     96         return toInt32(number);
     97     }
     98 
     99     class JSValue {
    100         friend struct EncodedJSValueHashTraits;
    101         friend class JIT;
    102         friend class JITStubs;
    103         friend class JITStubCall;
    104         friend class JSInterfaceJIT;
    105         friend class SpecializedThunkJIT;
    106 
    107     public:
    108         static EncodedJSValue encode(JSValue);
    109         static JSValue decode(EncodedJSValue);
    110 
    111         enum JSNullTag { JSNull };
    112         enum JSUndefinedTag { JSUndefined };
    113         enum JSTrueTag { JSTrue };
    114         enum JSFalseTag { JSFalse };
    115         enum EncodeAsDoubleTag { EncodeAsDouble };
    116 
    117         JSValue();
    118         JSValue(JSNullTag);
    119         JSValue(JSUndefinedTag);
    120         JSValue(JSTrueTag);
    121         JSValue(JSFalseTag);
    122         JSValue(JSCell* ptr);
    123         JSValue(const JSCell* ptr);
    124 
    125         // Numbers
    126         JSValue(EncodeAsDoubleTag, double);
    127         explicit JSValue(double);
    128         explicit JSValue(char);
    129         explicit JSValue(unsigned char);
    130         explicit JSValue(short);
    131         explicit JSValue(unsigned short);
    132         explicit JSValue(int);
    133         explicit JSValue(unsigned);
    134         explicit JSValue(long);
    135         explicit JSValue(unsigned long);
    136         explicit JSValue(long long);
    137         explicit JSValue(unsigned long long);
    138 
    139         operator bool() const;
    140         bool operator==(const JSValue& other) const;
    141         bool operator!=(const JSValue& other) const;
    142 
    143         bool isInt32() const;
    144         bool isUInt32() const;
    145         bool isDouble() const;
    146         bool isTrue() const;
    147         bool isFalse() const;
    148 
    149         int32_t asInt32() const;
    150         uint32_t asUInt32() const;
    151         double asDouble() const;
    152 
    153         // Querying the type.
    154         bool isUndefined() const;
    155         bool isNull() const;
    156         bool isUndefinedOrNull() const;
    157         bool isBoolean() const;
    158         bool isNumber() const;
    159         bool isString() const;
    160         bool isGetterSetter() const;
    161         bool isObject() const;
    162         bool inherits(const ClassInfo*) const;
    163 
    164         // Extracting the value.
    165         bool getBoolean(bool&) const;
    166         bool getBoolean() const; // false if not a boolean
    167         bool getNumber(double&) const;
    168         double uncheckedGetNumber() const;
    169         bool getString(ExecState* exec, UString&) const;
    170         UString getString(ExecState* exec) const; // null string if not a string
    171         JSObject* getObject() const; // 0 if not an object
    172 
    173         // Extracting integer values.
    174         bool getUInt32(uint32_t&) const;
    175 
    176         // Basic conversions.
    177         JSValue toPrimitive(ExecState*, PreferredPrimitiveType = NoPreference) const;
    178         bool getPrimitiveNumber(ExecState*, double& number, JSValue&);
    179 
    180         bool toBoolean(ExecState*) const;
    181 
    182         // toNumber conversion is expected to be side effect free if an exception has
    183         // been set in the ExecState already.
    184         double toNumber(ExecState*) const;
    185         JSValue toJSNumber(ExecState*) const; // Fast path for when you expect that the value is an immediate number.
    186         UString toString(ExecState*) const;
    187         UString toPrimitiveString(ExecState*) const;
    188         JSObject* toObject(ExecState*) const;
    189         JSObject* toObject(ExecState*, JSGlobalObject*) const;
    190 
    191         // Integer conversions.
    192         double toInteger(ExecState*) const;
    193         double toIntegerPreserveNaN(ExecState*) const;
    194         int32_t toInt32(ExecState*) const;
    195         uint32_t toUInt32(ExecState*) const;
    196 
    197 #if ENABLE(JSC_ZOMBIES)
    198         bool isZombie() const;
    199 #endif
    200 
    201         // Floating point conversions (this is a convenience method for webcore;
    202         // signle precision float is not a representation used in JS or JSC).
    203         float toFloat(ExecState* exec) const { return static_cast<float>(toNumber(exec)); }
    204 
    205         // Object operations, with the toObject operation included.
    206         JSValue get(ExecState*, const Identifier& propertyName) const;
    207         JSValue get(ExecState*, const Identifier& propertyName, PropertySlot&) const;
    208         JSValue get(ExecState*, unsigned propertyName) const;
    209         JSValue get(ExecState*, unsigned propertyName, PropertySlot&) const;
    210         void put(ExecState*, const Identifier& propertyName, JSValue, PutPropertySlot&);
    211         void putDirect(ExecState*, const Identifier& propertyName, JSValue, PutPropertySlot&);
    212         void put(ExecState*, unsigned propertyName, JSValue);
    213 
    214         bool needsThisConversion() const;
    215         JSObject* toThisObject(ExecState*) const;
    216         JSValue toStrictThisObject(ExecState*) const;
    217         UString toThisString(ExecState*) const;
    218         JSString* toThisJSString(ExecState*) const;
    219 
    220         static bool equal(ExecState* exec, JSValue v1, JSValue v2);
    221         static bool equalSlowCase(ExecState* exec, JSValue v1, JSValue v2);
    222         static bool equalSlowCaseInline(ExecState* exec, JSValue v1, JSValue v2);
    223         static bool strictEqual(ExecState* exec, JSValue v1, JSValue v2);
    224         static bool strictEqualSlowCase(ExecState* exec, JSValue v1, JSValue v2);
    225         static bool strictEqualSlowCaseInline(ExecState* exec, JSValue v1, JSValue v2);
    226 
    227         JSValue getJSNumber(); // JSValue() if this is not a JSNumber or number object
    228 
    229         bool isCell() const;
    230         JSCell* asCell() const;
    231         bool isValidCallee();
    232 
    233 #ifndef NDEBUG
    234         char* description();
    235 #endif
    236 
    237     private:
    238         template <class T> JSValue(WriteBarrierBase<T>);
    239 
    240         enum HashTableDeletedValueTag { HashTableDeletedValue };
    241         JSValue(HashTableDeletedValueTag);
    242 
    243         inline const JSValue asValue() const { return *this; }
    244         JSObject* toObjectSlowCase(ExecState*, JSGlobalObject*) const;
    245         JSObject* toThisObjectSlowCase(ExecState*) const;
    246 
    247         JSObject* synthesizePrototype(ExecState*) const;
    248         JSObject* synthesizeObject(ExecState*) const;
    249 
    250 #if USE(JSVALUE32_64)
    251         /*
    252          * On 32-bit platforms USE(JSVALUE32_64) should be defined, and we use a NaN-encoded
    253          * form for immediates.
    254          *
    255          * The encoding makes use of unused NaN space in the IEEE754 representation.  Any value
    256          * with the top 13 bits set represents a QNaN (with the sign bit set).  QNaN values
    257          * can encode a 51-bit payload.  Hardware produced and C-library payloads typically
    258          * have a payload of zero.  We assume that non-zero payloads are available to encode
    259          * pointer and integer values.  Since any 64-bit bit pattern where the top 15 bits are
    260          * all set represents a NaN with a non-zero payload, we can use this space in the NaN
    261          * ranges to encode other values (however there are also other ranges of NaN space that
    262          * could have been selected).
    263          *
    264          * For JSValues that do not contain a double value, the high 32 bits contain the tag
    265          * values listed in the enums below, which all correspond to NaN-space. In the case of
    266          * cell, integer and bool values the lower 32 bits (the 'payload') contain the pointer
    267          * integer or boolean value; in the case of all other tags the payload is 0.
    268          */
    269         enum { Int32Tag =        0xffffffff };
    270         enum { BooleanTag =      0xfffffffe };
    271         enum { NullTag =         0xfffffffd };
    272         enum { UndefinedTag =    0xfffffffc };
    273         enum { CellTag =         0xfffffffb };
    274         enum { EmptyValueTag =   0xfffffffa };
    275         enum { DeletedValueTag = 0xfffffff9 };
    276 
    277         enum { LowestTag =  DeletedValueTag };
    278 
    279         uint32_t tag() const;
    280         int32_t payload() const;
    281 #elif USE(JSVALUE64)
    282         /*
    283          * On 64-bit platforms USE(JSVALUE64) should be defined, and we use a NaN-encoded
    284          * form for immediates.
    285          *
    286          * The encoding makes use of unused NaN space in the IEEE754 representation.  Any value
    287          * with the top 13 bits set represents a QNaN (with the sign bit set).  QNaN values
    288          * can encode a 51-bit payload.  Hardware produced and C-library payloads typically
    289          * have a payload of zero.  We assume that non-zero payloads are available to encode
    290          * pointer and integer values.  Since any 64-bit bit pattern where the top 15 bits are
    291          * all set represents a NaN with a non-zero payload, we can use this space in the NaN
    292          * ranges to encode other values (however there are also other ranges of NaN space that
    293          * could have been selected).
    294          *
    295          * This range of NaN space is represented by 64-bit numbers begining with the 16-bit
    296          * hex patterns 0xFFFE and 0xFFFF - we rely on the fact that no valid double-precision
    297          * numbers will begin fall in these ranges.
    298          *
    299          * The top 16-bits denote the type of the encoded JSValue:
    300          *
    301          *     Pointer {  0000:PPPP:PPPP:PPPP
    302          *              / 0001:****:****:****
    303          *     Double  {         ...
    304          *              \ FFFE:****:****:****
    305          *     Integer {  FFFF:0000:IIII:IIII
    306          *
    307          * The scheme we have implemented encodes double precision values by performing a
    308          * 64-bit integer addition of the value 2^48 to the number. After this manipulation
    309          * no encoded double-precision value will begin with the pattern 0x0000 or 0xFFFF.
    310          * Values must be decoded by reversing this operation before subsequent floating point
    311          * operations my be peformed.
    312          *
    313          * 32-bit signed integers are marked with the 16-bit tag 0xFFFF.
    314          *
    315          * The tag 0x0000 denotes a pointer, or another form of tagged immediate. Boolean,
    316          * null and undefined values are represented by specific, invalid pointer values:
    317          *
    318          *     False:     0x06
    319          *     True:      0x07
    320          *     Undefined: 0x0a
    321          *     Null:      0x02
    322          *
    323          * These values have the following properties:
    324          * - Bit 1 (TagBitTypeOther) is set for all four values, allowing real pointers to be
    325          *   quickly distinguished from all immediate values, including these invalid pointers.
    326          * - With bit 3 is masked out (TagBitUndefined) Undefined and Null share the
    327          *   same value, allowing null & undefined to be quickly detected.
    328          *
    329          * No valid JSValue will have the bit pattern 0x0, this is used to represent array
    330          * holes, and as a C++ 'no value' result (e.g. JSValue() has an internal value of 0).
    331          */
    332 
    333         // These values are #defines since using static const integers here is a ~1% regression!
    334 
    335         // This value is 2^48, used to encode doubles such that the encoded value will begin
    336         // with a 16-bit pattern within the range 0x0001..0xFFFE.
    337         #define DoubleEncodeOffset 0x1000000000000ll
    338         // If all bits in the mask are set, this indicates an integer number,
    339         // if any but not all are set this value is a double precision number.
    340         #define TagTypeNumber 0xffff000000000000ll
    341 
    342         // All non-numeric (bool, null, undefined) immediates have bit 2 set.
    343         #define TagBitTypeOther 0x2ll
    344         #define TagBitBool      0x4ll
    345         #define TagBitUndefined 0x8ll
    346         // Combined integer value for non-numeric immediates.
    347         #define ValueFalse     (TagBitTypeOther | TagBitBool | false)
    348         #define ValueTrue      (TagBitTypeOther | TagBitBool | true)
    349         #define ValueUndefined (TagBitTypeOther | TagBitUndefined)
    350         #define ValueNull      (TagBitTypeOther)
    351 
    352         // TagMask is used to check for all types of immediate values (either number or 'other').
    353         #define TagMask (TagTypeNumber | TagBitTypeOther)
    354 
    355         // These special values are never visible to JavaScript code; Empty is used to represent
    356         // Array holes, and for uninitialized JSValues. Deleted is used in hash table code.
    357         // These values would map to cell types in the JSValue encoding, but not valid GC cell
    358         // pointer should have either of these values (Empty is null, deleted is at an invalid
    359         // alignment for a GC cell, and in the zero page).
    360         #define ValueEmpty   0x0ll
    361         #define ValueDeleted 0x4ll
    362 #endif
    363 
    364         EncodedValueDescriptor u;
    365     };
    366 
    367 #if USE(JSVALUE32_64)
    368     typedef IntHash<EncodedJSValue> EncodedJSValueHash;
    369 
    370     struct EncodedJSValueHashTraits : HashTraits<EncodedJSValue> {
    371         static const bool emptyValueIsZero = false;
    372         static EncodedJSValue emptyValue() { return JSValue::encode(JSValue()); }
    373         static void constructDeletedValue(EncodedJSValue& slot) { slot = JSValue::encode(JSValue(JSValue::HashTableDeletedValue)); }
    374         static bool isDeletedValue(EncodedJSValue value) { return value == JSValue::encode(JSValue(JSValue::HashTableDeletedValue)); }
    375     };
    376 #else
    377     typedef PtrHash<EncodedJSValue> EncodedJSValueHash;
    378 
    379     struct EncodedJSValueHashTraits : HashTraits<EncodedJSValue> {
    380         static void constructDeletedValue(EncodedJSValue& slot) { slot = JSValue::encode(JSValue(JSValue::HashTableDeletedValue)); }
    381         static bool isDeletedValue(EncodedJSValue value) { return value == JSValue::encode(JSValue(JSValue::HashTableDeletedValue)); }
    382     };
    383 #endif
    384 
    385     // Stand-alone helper functions.
    386     inline JSValue jsNull()
    387     {
    388         return JSValue(JSValue::JSNull);
    389     }
    390 
    391     inline JSValue jsUndefined()
    392     {
    393         return JSValue(JSValue::JSUndefined);
    394     }
    395 
    396     inline JSValue jsBoolean(bool b)
    397     {
    398         return b ? JSValue(JSValue::JSTrue) : JSValue(JSValue::JSFalse);
    399     }
    400 
    401     ALWAYS_INLINE JSValue jsDoubleNumber(double d)
    402     {
    403         return JSValue(JSValue::EncodeAsDouble, d);
    404     }
    405 
    406     ALWAYS_INLINE JSValue jsNumber(double d)
    407     {
    408         return JSValue(d);
    409     }
    410 
    411     ALWAYS_INLINE JSValue jsNumber(char i)
    412     {
    413         return JSValue(i);
    414     }
    415 
    416     ALWAYS_INLINE JSValue jsNumber(unsigned char i)
    417     {
    418         return JSValue(i);
    419     }
    420 
    421     ALWAYS_INLINE JSValue jsNumber(short i)
    422     {
    423         return JSValue(i);
    424     }
    425 
    426     ALWAYS_INLINE JSValue jsNumber(unsigned short i)
    427     {
    428         return JSValue(i);
    429     }
    430 
    431     ALWAYS_INLINE JSValue jsNumber(int i)
    432     {
    433         return JSValue(i);
    434     }
    435 
    436     ALWAYS_INLINE JSValue jsNumber(unsigned i)
    437     {
    438         return JSValue(i);
    439     }
    440 
    441     ALWAYS_INLINE JSValue jsNumber(long i)
    442     {
    443         return JSValue(i);
    444     }
    445 
    446     ALWAYS_INLINE JSValue jsNumber(unsigned long i)
    447     {
    448         return JSValue(i);
    449     }
    450 
    451     ALWAYS_INLINE JSValue jsNumber(long long i)
    452     {
    453         return JSValue(i);
    454     }
    455 
    456     ALWAYS_INLINE JSValue jsNumber(unsigned long long i)
    457     {
    458         return JSValue(i);
    459     }
    460 
    461     inline bool operator==(const JSValue a, const JSCell* b) { return a == JSValue(b); }
    462     inline bool operator==(const JSCell* a, const JSValue b) { return JSValue(a) == b; }
    463 
    464     inline bool operator!=(const JSValue a, const JSCell* b) { return a != JSValue(b); }
    465     inline bool operator!=(const JSCell* a, const JSValue b) { return JSValue(a) != b; }
    466 
    467     bool isZombie(const JSCell*);
    468 
    469 } // namespace JSC
    470 
    471 #endif // JSValue_h
    472