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