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, 2006, 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 JSObject_h
     24 #define JSObject_h
     25 
     26 #include "ArgList.h"
     27 #include "ClassInfo.h"
     28 #include "CommonIdentifiers.h"
     29 #include "CallFrame.h"
     30 #include "JSCell.h"
     31 #include "JSNumberCell.h"
     32 #include "MarkStack.h"
     33 #include "PropertySlot.h"
     34 #include "PutPropertySlot.h"
     35 #include "ScopeChain.h"
     36 #include "Structure.h"
     37 #include "JSGlobalData.h"
     38 #include <wtf/StdLibExtras.h>
     39 
     40 namespace JSC {
     41 
     42     inline JSCell* getJSFunction(JSGlobalData& globalData, JSValue value)
     43     {
     44         if (value.isCell() && (value.asCell()->vptr() == globalData.jsFunctionVPtr))
     45             return value.asCell();
     46         return 0;
     47     }
     48 
     49     class HashEntry;
     50     class InternalFunction;
     51     class PropertyDescriptor;
     52     class PropertyNameArray;
     53     class Structure;
     54     struct HashTable;
     55 
     56     // ECMA 262-3 8.6.1
     57     // Property attributes
     58     enum Attribute {
     59         None         = 0,
     60         ReadOnly     = 1 << 1,  // property can be only read, not written
     61         DontEnum     = 1 << 2,  // property doesn't appear in (for .. in ..)
     62         DontDelete   = 1 << 3,  // property can't be deleted
     63         Function     = 1 << 4,  // property is a function - only used by static hashtables
     64         Getter       = 1 << 5,  // property is a getter
     65         Setter       = 1 << 6   // property is a setter
     66     };
     67 
     68     typedef EncodedJSValue* PropertyStorage;
     69     typedef const EncodedJSValue* ConstPropertyStorage;
     70 
     71     class JSObject : public JSCell {
     72         friend class BatchedTransitionOptimizer;
     73         friend class JIT;
     74         friend class JSCell;
     75 
     76     public:
     77         explicit JSObject(NonNullPassRefPtr<Structure>);
     78 
     79         virtual void markChildren(MarkStack&);
     80         ALWAYS_INLINE void markChildrenDirect(MarkStack& markStack);
     81 
     82         // The inline virtual destructor cannot be the first virtual function declared
     83         // in the class as it results in the vtable being generated as a weak symbol
     84         virtual ~JSObject();
     85 
     86         JSValue prototype() const;
     87         void setPrototype(JSValue prototype);
     88 
     89         void setStructure(NonNullPassRefPtr<Structure>);
     90         Structure* inheritorID();
     91 
     92         virtual UString className() const;
     93 
     94         JSValue get(ExecState*, const Identifier& propertyName) const;
     95         JSValue get(ExecState*, unsigned propertyName) const;
     96 
     97         bool getPropertySlot(ExecState*, const Identifier& propertyName, PropertySlot&);
     98         bool getPropertySlot(ExecState*, unsigned propertyName, PropertySlot&);
     99         bool getPropertyDescriptor(ExecState*, const Identifier& propertyName, PropertyDescriptor&);
    100 
    101         virtual bool getOwnPropertySlot(ExecState*, const Identifier& propertyName, PropertySlot&);
    102         virtual bool getOwnPropertySlot(ExecState*, unsigned propertyName, PropertySlot&);
    103         virtual bool getOwnPropertyDescriptor(ExecState*, const Identifier&, PropertyDescriptor&);
    104 
    105         virtual void put(ExecState*, const Identifier& propertyName, JSValue value, PutPropertySlot&);
    106         virtual void put(ExecState*, unsigned propertyName, JSValue value);
    107 
    108         virtual void putWithAttributes(ExecState*, const Identifier& propertyName, JSValue value, unsigned attributes, bool checkReadOnly, PutPropertySlot& slot);
    109         virtual void putWithAttributes(ExecState*, const Identifier& propertyName, JSValue value, unsigned attributes);
    110         virtual void putWithAttributes(ExecState*, unsigned propertyName, JSValue value, unsigned attributes);
    111 
    112         bool propertyIsEnumerable(ExecState*, const Identifier& propertyName) const;
    113 
    114         bool hasProperty(ExecState*, const Identifier& propertyName) const;
    115         bool hasProperty(ExecState*, unsigned propertyName) const;
    116         bool hasOwnProperty(ExecState*, const Identifier& propertyName) const;
    117 
    118         virtual bool deleteProperty(ExecState*, const Identifier& propertyName);
    119         virtual bool deleteProperty(ExecState*, unsigned propertyName);
    120 
    121         virtual JSValue defaultValue(ExecState*, PreferredPrimitiveType) const;
    122 
    123         virtual bool hasInstance(ExecState*, JSValue, JSValue prototypeProperty);
    124 
    125         virtual void getPropertyNames(ExecState*, PropertyNameArray&, EnumerationMode mode = ExcludeDontEnumProperties);
    126         virtual void getOwnPropertyNames(ExecState*, PropertyNameArray&, EnumerationMode mode = ExcludeDontEnumProperties);
    127 
    128         virtual JSValue toPrimitive(ExecState*, PreferredPrimitiveType = NoPreference) const;
    129         virtual bool getPrimitiveNumber(ExecState*, double& number, JSValue& value);
    130         virtual bool toBoolean(ExecState*) const;
    131         virtual double toNumber(ExecState*) const;
    132         virtual UString toString(ExecState*) const;
    133         virtual JSObject* toObject(ExecState*) const;
    134 
    135         virtual JSObject* toThisObject(ExecState*) const;
    136         virtual JSObject* unwrappedObject();
    137 
    138         bool getPropertySpecificValue(ExecState* exec, const Identifier& propertyName, JSCell*& specificFunction) const;
    139 
    140         // This get function only looks at the property map.
    141         JSValue getDirect(const Identifier& propertyName) const
    142         {
    143             size_t offset = m_structure->get(propertyName);
    144             return offset != WTF::notFound ? getDirectOffset(offset) : JSValue();
    145         }
    146 
    147         JSValue* getDirectLocation(const Identifier& propertyName)
    148         {
    149             size_t offset = m_structure->get(propertyName);
    150             return offset != WTF::notFound ? locationForOffset(offset) : 0;
    151         }
    152 
    153         JSValue* getDirectLocation(const Identifier& propertyName, unsigned& attributes)
    154         {
    155             JSCell* specificFunction;
    156             size_t offset = m_structure->get(propertyName, attributes, specificFunction);
    157             return offset != WTF::notFound ? locationForOffset(offset) : 0;
    158         }
    159 
    160         size_t offsetForLocation(JSValue* location) const
    161         {
    162             return location - reinterpret_cast<const JSValue*>(propertyStorage());
    163         }
    164 
    165         void transitionTo(Structure*);
    166 
    167         void removeDirect(const Identifier& propertyName);
    168         bool hasCustomProperties() { return !m_structure->isEmpty(); }
    169         bool hasGetterSetterProperties() { return m_structure->hasGetterSetterProperties(); }
    170 
    171         void putDirect(const Identifier& propertyName, JSValue value, unsigned attr, bool checkReadOnly, PutPropertySlot& slot);
    172         void putDirect(const Identifier& propertyName, JSValue value, unsigned attr = 0);
    173 
    174         void putDirectFunction(const Identifier& propertyName, JSCell* value, unsigned attr = 0);
    175         void putDirectFunction(const Identifier& propertyName, JSCell* value, unsigned attr, bool checkReadOnly, PutPropertySlot& slot);
    176         void putDirectFunction(ExecState* exec, InternalFunction* function, unsigned attr = 0);
    177 
    178         void putDirectWithoutTransition(const Identifier& propertyName, JSValue value, unsigned attr = 0);
    179         void putDirectFunctionWithoutTransition(const Identifier& propertyName, JSCell* value, unsigned attr = 0);
    180         void putDirectFunctionWithoutTransition(ExecState* exec, InternalFunction* function, unsigned attr = 0);
    181 
    182         // Fast access to known property offsets.
    183         JSValue getDirectOffset(size_t offset) const { return JSValue::decode(propertyStorage()[offset]); }
    184         void putDirectOffset(size_t offset, JSValue value) { propertyStorage()[offset] = JSValue::encode(value); }
    185 
    186         void fillGetterPropertySlot(PropertySlot&, JSValue* location);
    187 
    188         virtual void defineGetter(ExecState*, const Identifier& propertyName, JSObject* getterFunction, unsigned attributes = 0);
    189         virtual void defineSetter(ExecState*, const Identifier& propertyName, JSObject* setterFunction, unsigned attributes = 0);
    190         virtual JSValue lookupGetter(ExecState*, const Identifier& propertyName);
    191         virtual JSValue lookupSetter(ExecState*, const Identifier& propertyName);
    192         virtual bool defineOwnProperty(ExecState*, const Identifier& propertyName, PropertyDescriptor&, bool shouldThrow);
    193 
    194         virtual bool isGlobalObject() const { return false; }
    195         virtual bool isVariableObject() const { return false; }
    196         virtual bool isActivationObject() const { return false; }
    197         virtual bool isWatchdogException() const { return false; }
    198         virtual bool isNotAnObjectErrorStub() const { return false; }
    199 
    200         void allocatePropertyStorage(size_t oldSize, size_t newSize);
    201         void allocatePropertyStorageInline(size_t oldSize, size_t newSize);
    202         bool isUsingInlineStorage() const { return m_structure->isUsingInlineStorage(); }
    203 
    204         static const unsigned inlineStorageCapacity = sizeof(EncodedJSValue) == 2 * sizeof(void*) ? 4 : 3;
    205         static const unsigned nonInlineBaseStorageCapacity = 16;
    206 
    207         static PassRefPtr<Structure> createStructure(JSValue prototype)
    208         {
    209             return Structure::create(prototype, TypeInfo(ObjectType, StructureFlags), AnonymousSlotCount);
    210         }
    211 
    212         void flattenDictionaryObject()
    213         {
    214             m_structure->flattenDictionaryStructure(this);
    215         }
    216 
    217     protected:
    218         static const unsigned StructureFlags = 0;
    219 
    220         void putAnonymousValue(unsigned index, JSValue value)
    221         {
    222             ASSERT(index < m_structure->anonymousSlotCount());
    223             *locationForOffset(index) = value;
    224         }
    225         JSValue getAnonymousValue(unsigned index) const
    226         {
    227             ASSERT(index < m_structure->anonymousSlotCount());
    228             return *locationForOffset(index);
    229         }
    230 
    231     private:
    232         // Nobody should ever ask any of these questions on something already known to be a JSObject.
    233         using JSCell::isAPIValueWrapper;
    234         using JSCell::isGetterSetter;
    235         using JSCell::toObject;
    236         void getObject();
    237         void getString(ExecState* exec);
    238         void isObject();
    239         void isString();
    240 #if USE(JSVALUE32)
    241         void isNumber();
    242 #endif
    243 
    244         ConstPropertyStorage propertyStorage() const { return (isUsingInlineStorage() ? m_inlineStorage : m_externalStorage); }
    245         PropertyStorage propertyStorage() { return (isUsingInlineStorage() ? m_inlineStorage : m_externalStorage); }
    246 
    247         const JSValue* locationForOffset(size_t offset) const
    248         {
    249             return reinterpret_cast<const JSValue*>(&propertyStorage()[offset]);
    250         }
    251 
    252         JSValue* locationForOffset(size_t offset)
    253         {
    254             return reinterpret_cast<JSValue*>(&propertyStorage()[offset]);
    255         }
    256 
    257         void putDirectInternal(const Identifier& propertyName, JSValue value, unsigned attr, bool checkReadOnly, PutPropertySlot& slot, JSCell*);
    258         void putDirectInternal(JSGlobalData&, const Identifier& propertyName, JSValue value, unsigned attr, bool checkReadOnly, PutPropertySlot& slot);
    259         void putDirectInternal(JSGlobalData&, const Identifier& propertyName, JSValue value, unsigned attr = 0);
    260 
    261         bool inlineGetOwnPropertySlot(ExecState*, const Identifier& propertyName, PropertySlot&);
    262 
    263         const HashEntry* findPropertyHashEntry(ExecState*, const Identifier& propertyName) const;
    264         Structure* createInheritorID();
    265 
    266         union {
    267             PropertyStorage m_externalStorage;
    268             EncodedJSValue m_inlineStorage[inlineStorageCapacity];
    269         };
    270 
    271         RefPtr<Structure> m_inheritorID;
    272     };
    273 
    274 inline JSObject* asObject(JSCell* cell)
    275 {
    276     ASSERT(cell->isObject());
    277     return static_cast<JSObject*>(cell);
    278 }
    279 
    280 inline JSObject* asObject(JSValue value)
    281 {
    282     return asObject(value.asCell());
    283 }
    284 
    285 inline JSObject::JSObject(NonNullPassRefPtr<Structure> structure)
    286     : JSCell(structure.releaseRef()) // ~JSObject balances this ref()
    287 {
    288     ASSERT(m_structure->propertyStorageCapacity() == inlineStorageCapacity);
    289     ASSERT(m_structure->isEmpty());
    290     ASSERT(prototype().isNull() || Heap::heap(this) == Heap::heap(prototype()));
    291 #if USE(JSVALUE64) || USE(JSVALUE32_64)
    292     ASSERT(OBJECT_OFFSETOF(JSObject, m_inlineStorage) % sizeof(double) == 0);
    293 #endif
    294 }
    295 
    296 inline JSObject::~JSObject()
    297 {
    298     ASSERT(m_structure);
    299     if (!isUsingInlineStorage())
    300         delete [] m_externalStorage;
    301     m_structure->deref();
    302 }
    303 
    304 inline JSValue JSObject::prototype() const
    305 {
    306     return m_structure->storedPrototype();
    307 }
    308 
    309 inline void JSObject::setPrototype(JSValue prototype)
    310 {
    311     ASSERT(prototype);
    312     RefPtr<Structure> newStructure = Structure::changePrototypeTransition(m_structure, prototype);
    313     setStructure(newStructure.release());
    314 }
    315 
    316 inline void JSObject::setStructure(NonNullPassRefPtr<Structure> structure)
    317 {
    318     m_structure->deref();
    319     m_structure = structure.releaseRef(); // ~JSObject balances this ref()
    320 }
    321 
    322 inline Structure* JSObject::inheritorID()
    323 {
    324     if (m_inheritorID)
    325         return m_inheritorID.get();
    326     return createInheritorID();
    327 }
    328 
    329 inline bool Structure::isUsingInlineStorage() const
    330 {
    331     return (propertyStorageCapacity() == JSObject::inlineStorageCapacity);
    332 }
    333 
    334 inline bool JSCell::inherits(const ClassInfo* info) const
    335 {
    336     for (const ClassInfo* ci = classInfo(); ci; ci = ci->parentClass) {
    337         if (ci == info)
    338             return true;
    339     }
    340     return false;
    341 }
    342 
    343 // this method is here to be after the inline declaration of JSCell::inherits
    344 inline bool JSValue::inherits(const ClassInfo* classInfo) const
    345 {
    346     return isCell() && asCell()->inherits(classInfo);
    347 }
    348 
    349 ALWAYS_INLINE bool JSObject::inlineGetOwnPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot)
    350 {
    351     if (JSValue* location = getDirectLocation(propertyName)) {
    352         if (m_structure->hasGetterSetterProperties() && location[0].isGetterSetter())
    353             fillGetterPropertySlot(slot, location);
    354         else
    355             slot.setValueSlot(this, location, offsetForLocation(location));
    356         return true;
    357     }
    358 
    359     // non-standard Netscape extension
    360     if (propertyName == exec->propertyNames().underscoreProto) {
    361         slot.setValue(prototype());
    362         return true;
    363     }
    364 
    365     return false;
    366 }
    367 
    368 // It may seem crazy to inline a function this large, especially a virtual function,
    369 // but it makes a big difference to property lookup that derived classes can inline their
    370 // base class call to this.
    371 ALWAYS_INLINE bool JSObject::getOwnPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot)
    372 {
    373     return inlineGetOwnPropertySlot(exec, propertyName, slot);
    374 }
    375 
    376 ALWAYS_INLINE bool JSCell::fastGetOwnPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot)
    377 {
    378     if (!structure()->typeInfo().overridesGetOwnPropertySlot())
    379         return asObject(this)->inlineGetOwnPropertySlot(exec, propertyName, slot);
    380     return getOwnPropertySlot(exec, propertyName, slot);
    381 }
    382 
    383 // It may seem crazy to inline a function this large but it makes a big difference
    384 // since this is function very hot in variable lookup
    385 ALWAYS_INLINE bool JSObject::getPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot)
    386 {
    387     JSObject* object = this;
    388     while (true) {
    389         if (object->fastGetOwnPropertySlot(exec, propertyName, slot))
    390             return true;
    391         JSValue prototype = object->prototype();
    392         if (!prototype.isObject())
    393             return false;
    394         object = asObject(prototype);
    395     }
    396 }
    397 
    398 ALWAYS_INLINE bool JSObject::getPropertySlot(ExecState* exec, unsigned propertyName, PropertySlot& slot)
    399 {
    400     JSObject* object = this;
    401     while (true) {
    402         if (object->getOwnPropertySlot(exec, propertyName, slot))
    403             return true;
    404         JSValue prototype = object->prototype();
    405         if (!prototype.isObject())
    406             return false;
    407         object = asObject(prototype);
    408     }
    409 }
    410 
    411 inline JSValue JSObject::get(ExecState* exec, const Identifier& propertyName) const
    412 {
    413     PropertySlot slot(this);
    414     if (const_cast<JSObject*>(this)->getPropertySlot(exec, propertyName, slot))
    415         return slot.getValue(exec, propertyName);
    416 
    417     return jsUndefined();
    418 }
    419 
    420 inline JSValue JSObject::get(ExecState* exec, unsigned propertyName) const
    421 {
    422     PropertySlot slot(this);
    423     if (const_cast<JSObject*>(this)->getPropertySlot(exec, propertyName, slot))
    424         return slot.getValue(exec, propertyName);
    425 
    426     return jsUndefined();
    427 }
    428 
    429 inline void JSObject::putDirectInternal(const Identifier& propertyName, JSValue value, unsigned attributes, bool checkReadOnly, PutPropertySlot& slot, JSCell* specificFunction)
    430 {
    431     ASSERT(value);
    432     ASSERT(!Heap::heap(value) || Heap::heap(value) == Heap::heap(this));
    433 
    434     if (m_structure->isDictionary()) {
    435         unsigned currentAttributes;
    436         JSCell* currentSpecificFunction;
    437         size_t offset = m_structure->get(propertyName, currentAttributes, currentSpecificFunction);
    438         if (offset != WTF::notFound) {
    439             if (currentSpecificFunction && (specificFunction != currentSpecificFunction))
    440                 m_structure->despecifyDictionaryFunction(propertyName);
    441             if (checkReadOnly && currentAttributes & ReadOnly)
    442                 return;
    443             putDirectOffset(offset, value);
    444             if (!specificFunction && !currentSpecificFunction)
    445                 slot.setExistingProperty(this, offset);
    446             return;
    447         }
    448 
    449         size_t currentCapacity = m_structure->propertyStorageCapacity();
    450         offset = m_structure->addPropertyWithoutTransition(propertyName, attributes, specificFunction);
    451         if (currentCapacity != m_structure->propertyStorageCapacity())
    452             allocatePropertyStorage(currentCapacity, m_structure->propertyStorageCapacity());
    453 
    454         ASSERT(offset < m_structure->propertyStorageCapacity());
    455         putDirectOffset(offset, value);
    456         // See comment on setNewProperty call below.
    457         if (!specificFunction)
    458             slot.setNewProperty(this, offset);
    459         return;
    460     }
    461 
    462     size_t offset;
    463     size_t currentCapacity = m_structure->propertyStorageCapacity();
    464     if (RefPtr<Structure> structure = Structure::addPropertyTransitionToExistingStructure(m_structure, propertyName, attributes, specificFunction, offset)) {
    465         if (currentCapacity != structure->propertyStorageCapacity())
    466             allocatePropertyStorage(currentCapacity, structure->propertyStorageCapacity());
    467 
    468         ASSERT(offset < structure->propertyStorageCapacity());
    469         setStructure(structure.release());
    470         putDirectOffset(offset, value);
    471         // See comment on setNewProperty call below.
    472         if (!specificFunction)
    473             slot.setNewProperty(this, offset);
    474         return;
    475     }
    476 
    477     unsigned currentAttributes;
    478     JSCell* currentSpecificFunction;
    479     offset = m_structure->get(propertyName, currentAttributes, currentSpecificFunction);
    480     if (offset != WTF::notFound) {
    481         if (checkReadOnly && currentAttributes & ReadOnly)
    482             return;
    483 
    484         if (currentSpecificFunction && (specificFunction != currentSpecificFunction)) {
    485             setStructure(Structure::despecifyFunctionTransition(m_structure, propertyName));
    486             putDirectOffset(offset, value);
    487             // Function transitions are not currently cachable, so leave the slot in an uncachable state.
    488             return;
    489         }
    490         putDirectOffset(offset, value);
    491         slot.setExistingProperty(this, offset);
    492         return;
    493     }
    494 
    495     // If we have a specific function, we may have got to this point if there is
    496     // already a transition with the correct property name and attributes, but
    497     // specialized to a different function.  In this case we just want to give up
    498     // and despecialize the transition.
    499     // In this case we clear the value of specificFunction which will result
    500     // in us adding a non-specific transition, and any subsequent lookup in
    501     // Structure::addPropertyTransitionToExistingStructure will just use that.
    502     if (specificFunction && m_structure->hasTransition(propertyName, attributes))
    503         specificFunction = 0;
    504 
    505     RefPtr<Structure> structure = Structure::addPropertyTransition(m_structure, propertyName, attributes, specificFunction, offset);
    506 
    507     if (currentCapacity != structure->propertyStorageCapacity())
    508         allocatePropertyStorage(currentCapacity, structure->propertyStorageCapacity());
    509 
    510     ASSERT(offset < structure->propertyStorageCapacity());
    511     setStructure(structure.release());
    512     putDirectOffset(offset, value);
    513     // Function transitions are not currently cachable, so leave the slot in an uncachable state.
    514     if (!specificFunction)
    515         slot.setNewProperty(this, offset);
    516 }
    517 
    518 inline void JSObject::putDirectInternal(JSGlobalData& globalData, const Identifier& propertyName, JSValue value, unsigned attributes, bool checkReadOnly, PutPropertySlot& slot)
    519 {
    520     ASSERT(value);
    521     ASSERT(!Heap::heap(value) || Heap::heap(value) == Heap::heap(this));
    522 
    523     putDirectInternal(propertyName, value, attributes, checkReadOnly, slot, getJSFunction(globalData, value));
    524 }
    525 
    526 inline void JSObject::putDirectInternal(JSGlobalData& globalData, const Identifier& propertyName, JSValue value, unsigned attributes)
    527 {
    528     PutPropertySlot slot;
    529     putDirectInternal(propertyName, value, attributes, false, slot, getJSFunction(globalData, value));
    530 }
    531 
    532 inline void JSObject::putDirect(const Identifier& propertyName, JSValue value, unsigned attributes, bool checkReadOnly, PutPropertySlot& slot)
    533 {
    534     ASSERT(value);
    535     ASSERT(!Heap::heap(value) || Heap::heap(value) == Heap::heap(this));
    536 
    537     putDirectInternal(propertyName, value, attributes, checkReadOnly, slot, 0);
    538 }
    539 
    540 inline void JSObject::putDirect(const Identifier& propertyName, JSValue value, unsigned attributes)
    541 {
    542     PutPropertySlot slot;
    543     putDirectInternal(propertyName, value, attributes, false, slot, 0);
    544 }
    545 
    546 inline void JSObject::putDirectFunction(const Identifier& propertyName, JSCell* value, unsigned attributes, bool checkReadOnly, PutPropertySlot& slot)
    547 {
    548     putDirectInternal(propertyName, value, attributes, checkReadOnly, slot, value);
    549 }
    550 
    551 inline void JSObject::putDirectFunction(const Identifier& propertyName, JSCell* value, unsigned attr)
    552 {
    553     PutPropertySlot slot;
    554     putDirectInternal(propertyName, value, attr, false, slot, value);
    555 }
    556 
    557 inline void JSObject::putDirectWithoutTransition(const Identifier& propertyName, JSValue value, unsigned attributes)
    558 {
    559     size_t currentCapacity = m_structure->propertyStorageCapacity();
    560     size_t offset = m_structure->addPropertyWithoutTransition(propertyName, attributes, 0);
    561     if (currentCapacity != m_structure->propertyStorageCapacity())
    562         allocatePropertyStorage(currentCapacity, m_structure->propertyStorageCapacity());
    563     putDirectOffset(offset, value);
    564 }
    565 
    566 inline void JSObject::putDirectFunctionWithoutTransition(const Identifier& propertyName, JSCell* value, unsigned attributes)
    567 {
    568     size_t currentCapacity = m_structure->propertyStorageCapacity();
    569     size_t offset = m_structure->addPropertyWithoutTransition(propertyName, attributes, value);
    570     if (currentCapacity != m_structure->propertyStorageCapacity())
    571         allocatePropertyStorage(currentCapacity, m_structure->propertyStorageCapacity());
    572     putDirectOffset(offset, value);
    573 }
    574 
    575 inline void JSObject::transitionTo(Structure* newStructure)
    576 {
    577     if (m_structure->propertyStorageCapacity() != newStructure->propertyStorageCapacity())
    578         allocatePropertyStorage(m_structure->propertyStorageCapacity(), newStructure->propertyStorageCapacity());
    579     setStructure(newStructure);
    580 }
    581 
    582 inline JSValue JSObject::toPrimitive(ExecState* exec, PreferredPrimitiveType preferredType) const
    583 {
    584     return defaultValue(exec, preferredType);
    585 }
    586 
    587 inline JSValue JSValue::get(ExecState* exec, const Identifier& propertyName) const
    588 {
    589     PropertySlot slot(asValue());
    590     return get(exec, propertyName, slot);
    591 }
    592 
    593 inline JSValue JSValue::get(ExecState* exec, const Identifier& propertyName, PropertySlot& slot) const
    594 {
    595     if (UNLIKELY(!isCell())) {
    596         JSObject* prototype = synthesizePrototype(exec);
    597         if (propertyName == exec->propertyNames().underscoreProto)
    598             return prototype;
    599         if (!prototype->getPropertySlot(exec, propertyName, slot))
    600             return jsUndefined();
    601         return slot.getValue(exec, propertyName);
    602     }
    603     JSCell* cell = asCell();
    604     while (true) {
    605         if (cell->fastGetOwnPropertySlot(exec, propertyName, slot))
    606             return slot.getValue(exec, propertyName);
    607         JSValue prototype = asObject(cell)->prototype();
    608         if (!prototype.isObject())
    609             return jsUndefined();
    610         cell = asObject(prototype);
    611     }
    612 }
    613 
    614 inline JSValue JSValue::get(ExecState* exec, unsigned propertyName) const
    615 {
    616     PropertySlot slot(asValue());
    617     return get(exec, propertyName, slot);
    618 }
    619 
    620 inline JSValue JSValue::get(ExecState* exec, unsigned propertyName, PropertySlot& slot) const
    621 {
    622     if (UNLIKELY(!isCell())) {
    623         JSObject* prototype = synthesizePrototype(exec);
    624         if (!prototype->getPropertySlot(exec, propertyName, slot))
    625             return jsUndefined();
    626         return slot.getValue(exec, propertyName);
    627     }
    628     JSCell* cell = const_cast<JSCell*>(asCell());
    629     while (true) {
    630         if (cell->getOwnPropertySlot(exec, propertyName, slot))
    631             return slot.getValue(exec, propertyName);
    632         JSValue prototype = asObject(cell)->prototype();
    633         if (!prototype.isObject())
    634             return jsUndefined();
    635         cell = prototype.asCell();
    636     }
    637 }
    638 
    639 inline void JSValue::put(ExecState* exec, const Identifier& propertyName, JSValue value, PutPropertySlot& slot)
    640 {
    641     if (UNLIKELY(!isCell())) {
    642         synthesizeObject(exec)->put(exec, propertyName, value, slot);
    643         return;
    644     }
    645     asCell()->put(exec, propertyName, value, slot);
    646 }
    647 
    648 inline void JSValue::put(ExecState* exec, unsigned propertyName, JSValue value)
    649 {
    650     if (UNLIKELY(!isCell())) {
    651         synthesizeObject(exec)->put(exec, propertyName, value);
    652         return;
    653     }
    654     asCell()->put(exec, propertyName, value);
    655 }
    656 
    657 ALWAYS_INLINE void JSObject::allocatePropertyStorageInline(size_t oldSize, size_t newSize)
    658 {
    659     ASSERT(newSize > oldSize);
    660 
    661     // It's important that this function not rely on m_structure, since
    662     // we might be in the middle of a transition.
    663     bool wasInline = (oldSize == JSObject::inlineStorageCapacity);
    664 
    665     PropertyStorage oldPropertyStorage = (wasInline ? m_inlineStorage : m_externalStorage);
    666     PropertyStorage newPropertyStorage = new EncodedJSValue[newSize];
    667 
    668     for (unsigned i = 0; i < oldSize; ++i)
    669        newPropertyStorage[i] = oldPropertyStorage[i];
    670 
    671     if (!wasInline)
    672         delete [] oldPropertyStorage;
    673 
    674     m_externalStorage = newPropertyStorage;
    675 }
    676 
    677 ALWAYS_INLINE void JSObject::markChildrenDirect(MarkStack& markStack)
    678 {
    679     JSCell::markChildren(markStack);
    680 
    681     markStack.append(prototype());
    682 
    683     PropertyStorage storage = propertyStorage();
    684     size_t storageSize = m_structure->propertyStorageSize();
    685     markStack.appendValues(reinterpret_cast<JSValue*>(storage), storageSize);
    686 }
    687 
    688 } // namespace JSC
    689 
    690 #endif // JSObject_h
    691