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 JSCell_h
     24 #define JSCell_h
     25 
     26 #include "Collector.h"
     27 #include "JSImmediate.h"
     28 #include "JSValue.h"
     29 #include "MarkStack.h"
     30 #include "Structure.h"
     31 #include <wtf/Noncopyable.h>
     32 
     33 namespace JSC {
     34 
     35     class JSCell : public NoncopyableCustomAllocated {
     36         friend class GetterSetter;
     37         friend class Heap;
     38         friend class JIT;
     39         friend class JSNumberCell;
     40         friend class JSObject;
     41         friend class JSPropertyNameIterator;
     42         friend class JSString;
     43         friend class JSValue;
     44         friend class JSAPIValueWrapper;
     45         friend class JSZombie;
     46         friend class JSGlobalData;
     47 
     48     private:
     49         explicit JSCell(Structure*);
     50         virtual ~JSCell();
     51 
     52     public:
     53         static PassRefPtr<Structure> createDummyStructure()
     54         {
     55             return Structure::create(jsNull(), TypeInfo(UnspecifiedType), AnonymousSlotCount);
     56         }
     57 
     58         // Querying the type.
     59 #if USE(JSVALUE32)
     60         bool isNumber() const;
     61 #endif
     62         bool isString() const;
     63         bool isObject() const;
     64         virtual bool isGetterSetter() const;
     65         bool inherits(const ClassInfo*) const;
     66         virtual bool isAPIValueWrapper() const { return false; }
     67         virtual bool isPropertyNameIterator() const { return false; }
     68 
     69         Structure* structure() const;
     70 
     71         // Extracting the value.
     72         bool getString(ExecState* exec, UString&) const;
     73         UString getString(ExecState* exec) const; // null string if not a string
     74         JSObject* getObject(); // NULL if not an object
     75         const JSObject* getObject() const; // NULL if not an object
     76 
     77         virtual CallType getCallData(CallData&);
     78         virtual ConstructType getConstructData(ConstructData&);
     79 
     80         // Extracting integer values.
     81         // FIXME: remove these methods, can check isNumberCell in JSValue && then call asNumberCell::*.
     82         virtual bool getUInt32(uint32_t&) const;
     83 
     84         // Basic conversions.
     85         virtual JSValue toPrimitive(ExecState*, PreferredPrimitiveType) const;
     86         virtual bool getPrimitiveNumber(ExecState*, double& number, JSValue&);
     87         virtual bool toBoolean(ExecState*) const;
     88         virtual double toNumber(ExecState*) const;
     89         virtual UString toString(ExecState*) const;
     90         virtual JSObject* toObject(ExecState*) const;
     91 
     92         // Garbage collection.
     93         void* operator new(size_t, ExecState*);
     94         void* operator new(size_t, JSGlobalData*);
     95         void* operator new(size_t, void* placementNewDestination) { return placementNewDestination; }
     96 
     97         virtual void markChildren(MarkStack&);
     98 #if ENABLE(JSC_ZOMBIES)
     99         virtual bool isZombie() const { return false; }
    100 #endif
    101 
    102         // Object operations, with the toObject operation included.
    103         virtual const ClassInfo* classInfo() const;
    104         virtual void put(ExecState*, const Identifier& propertyName, JSValue, PutPropertySlot&);
    105         virtual void put(ExecState*, unsigned propertyName, JSValue);
    106         virtual bool deleteProperty(ExecState*, const Identifier& propertyName);
    107         virtual bool deleteProperty(ExecState*, unsigned propertyName);
    108 
    109         virtual JSObject* toThisObject(ExecState*) const;
    110         virtual UString toThisString(ExecState*) const;
    111         virtual JSString* toThisJSString(ExecState*);
    112         virtual JSValue getJSNumber();
    113         void* vptr() { return *reinterpret_cast<void**>(this); }
    114         void setVPtr(void* vptr) { *reinterpret_cast<void**>(this) = vptr; }
    115 
    116     protected:
    117         static const unsigned AnonymousSlotCount = 0;
    118 
    119     private:
    120         // Base implementation; for non-object classes implements getPropertySlot.
    121         bool fastGetOwnPropertySlot(ExecState*, const Identifier& propertyName, PropertySlot&);
    122         virtual bool getOwnPropertySlot(ExecState*, const Identifier& propertyName, PropertySlot&);
    123         virtual bool getOwnPropertySlot(ExecState*, unsigned propertyName, PropertySlot&);
    124 
    125         Structure* m_structure;
    126     };
    127 
    128     inline JSCell::JSCell(Structure* structure)
    129         : m_structure(structure)
    130     {
    131     }
    132 
    133     inline JSCell::~JSCell()
    134     {
    135     }
    136 
    137 #if USE(JSVALUE32)
    138     inline bool JSCell::isNumber() const
    139     {
    140         return m_structure->typeInfo().type() == NumberType;
    141     }
    142 #endif
    143 
    144     inline bool JSCell::isObject() const
    145     {
    146         return m_structure->typeInfo().type() == ObjectType;
    147     }
    148 
    149     inline bool JSCell::isString() const
    150     {
    151         return m_structure->typeInfo().type() == StringType;
    152     }
    153 
    154     inline Structure* JSCell::structure() const
    155     {
    156         return m_structure;
    157     }
    158 
    159     inline void JSCell::markChildren(MarkStack&)
    160     {
    161     }
    162 
    163     inline void* JSCell::operator new(size_t size, JSGlobalData* globalData)
    164     {
    165         return globalData->heap.allocate(size);
    166     }
    167 
    168     inline void* JSCell::operator new(size_t size, ExecState* exec)
    169     {
    170         return exec->heap()->allocate(size);
    171     }
    172 
    173     // --- JSValue inlines ----------------------------
    174 
    175     inline bool JSValue::isString() const
    176     {
    177         return isCell() && asCell()->isString();
    178     }
    179 
    180     inline bool JSValue::isGetterSetter() const
    181     {
    182         return isCell() && asCell()->isGetterSetter();
    183     }
    184 
    185     inline bool JSValue::isObject() const
    186     {
    187         return isCell() && asCell()->isObject();
    188     }
    189 
    190     inline bool JSValue::getString(ExecState* exec, UString& s) const
    191     {
    192         return isCell() && asCell()->getString(exec, s);
    193     }
    194 
    195     inline UString JSValue::getString(ExecState* exec) const
    196     {
    197         return isCell() ? asCell()->getString(exec) : UString();
    198     }
    199 
    200     inline JSObject* JSValue::getObject() const
    201     {
    202         return isCell() ? asCell()->getObject() : 0;
    203     }
    204 
    205     inline CallType JSValue::getCallData(CallData& callData)
    206     {
    207         return isCell() ? asCell()->getCallData(callData) : CallTypeNone;
    208     }
    209 
    210     inline ConstructType JSValue::getConstructData(ConstructData& constructData)
    211     {
    212         return isCell() ? asCell()->getConstructData(constructData) : ConstructTypeNone;
    213     }
    214 
    215     ALWAYS_INLINE bool JSValue::getUInt32(uint32_t& v) const
    216     {
    217         if (isInt32()) {
    218             int32_t i = asInt32();
    219             v = static_cast<uint32_t>(i);
    220             return i >= 0;
    221         }
    222         if (isDouble()) {
    223             double d = asDouble();
    224             v = static_cast<uint32_t>(d);
    225             return v == d;
    226         }
    227         return false;
    228     }
    229 
    230 #if !USE(JSVALUE32_64)
    231     ALWAYS_INLINE JSCell* JSValue::asCell() const
    232     {
    233         ASSERT(isCell());
    234         return m_ptr;
    235     }
    236 #endif // !USE(JSVALUE32_64)
    237 
    238     inline JSValue JSValue::toPrimitive(ExecState* exec, PreferredPrimitiveType preferredType) const
    239     {
    240         return isCell() ? asCell()->toPrimitive(exec, preferredType) : asValue();
    241     }
    242 
    243     inline bool JSValue::getPrimitiveNumber(ExecState* exec, double& number, JSValue& value)
    244     {
    245         if (isInt32()) {
    246             number = asInt32();
    247             value = *this;
    248             return true;
    249         }
    250         if (isDouble()) {
    251             number = asDouble();
    252             value = *this;
    253             return true;
    254         }
    255         if (isCell())
    256             return asCell()->getPrimitiveNumber(exec, number, value);
    257         if (isTrue()) {
    258             number = 1.0;
    259             value = *this;
    260             return true;
    261         }
    262         if (isFalse() || isNull()) {
    263             number = 0.0;
    264             value = *this;
    265             return true;
    266         }
    267         ASSERT(isUndefined());
    268         number = nonInlineNaN();
    269         value = *this;
    270         return true;
    271     }
    272 
    273     inline bool JSValue::toBoolean(ExecState* exec) const
    274     {
    275         if (isInt32())
    276             return asInt32() != 0;
    277         if (isDouble())
    278             return asDouble() > 0.0 || asDouble() < 0.0; // false for NaN
    279         if (isCell())
    280             return asCell()->toBoolean(exec);
    281         return isTrue(); // false, null, and undefined all convert to false.
    282     }
    283 
    284     ALWAYS_INLINE double JSValue::toNumber(ExecState* exec) const
    285     {
    286         if (isInt32())
    287             return asInt32();
    288         if (isDouble())
    289             return asDouble();
    290         if (isCell())
    291             return asCell()->toNumber(exec);
    292         if (isTrue())
    293             return 1.0;
    294         return isUndefined() ? nonInlineNaN() : 0; // null and false both convert to 0.
    295     }
    296 
    297     inline bool JSValue::needsThisConversion() const
    298     {
    299         if (UNLIKELY(!isCell()))
    300             return true;
    301         return asCell()->structure()->typeInfo().needsThisConversion();
    302     }
    303 
    304     inline UString JSValue::toThisString(ExecState* exec) const
    305     {
    306         return isCell() ? asCell()->toThisString(exec) : toString(exec);
    307     }
    308 
    309     inline JSValue JSValue::getJSNumber()
    310     {
    311         if (isInt32() || isDouble())
    312             return *this;
    313         if (isCell())
    314             return asCell()->getJSNumber();
    315         return JSValue();
    316     }
    317 
    318     inline JSObject* JSValue::toObject(ExecState* exec) const
    319     {
    320         return isCell() ? asCell()->toObject(exec) : toObjectSlowCase(exec);
    321     }
    322 
    323     inline JSObject* JSValue::toThisObject(ExecState* exec) const
    324     {
    325         return isCell() ? asCell()->toThisObject(exec) : toThisObjectSlowCase(exec);
    326     }
    327 
    328     ALWAYS_INLINE void MarkStack::append(JSCell* cell)
    329     {
    330         ASSERT(!m_isCheckingForDefaultMarkViolation);
    331         ASSERT(cell);
    332         if (Heap::isCellMarked(cell))
    333             return;
    334         Heap::markCell(cell);
    335         if (cell->structure()->typeInfo().type() >= CompoundType)
    336             m_values.append(cell);
    337     }
    338 
    339     ALWAYS_INLINE void MarkStack::append(JSValue value)
    340     {
    341         ASSERT(value);
    342         if (value.isCell())
    343             append(value.asCell());
    344     }
    345 
    346     inline Heap* Heap::heap(JSValue v)
    347     {
    348         if (!v.isCell())
    349             return 0;
    350         return heap(v.asCell());
    351     }
    352 
    353     inline Heap* Heap::heap(JSCell* c)
    354     {
    355         return cellBlock(c)->heap;
    356     }
    357 
    358 #if ENABLE(JSC_ZOMBIES)
    359     inline bool JSValue::isZombie() const
    360     {
    361         return isCell() && asCell() && asCell()->isZombie();
    362     }
    363 #endif
    364 } // namespace JSC
    365 
    366 #endif // JSCell_h
    367