]> git.saurik.com Git - apple/javascriptcore.git/blobdiff - runtime/JSObject.h
JavaScriptCore-1097.13.tar.gz
[apple/javascriptcore.git] / runtime / JSObject.h
index ac4706fb931b04f5ebc0243a186bea1b229e5634..d95860d6214a79df30221daf916851a4b83c0313 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *  Copyright (C) 1999-2001 Harri Porten (porten@kde.org)
  *  Copyright (C) 2001 Peter Kelly (pmk@post.com)
- *  Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved.
+ *  Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved.
  *
  *  This library is free software; you can redistribute it and/or
  *  modify it under the terms of the GNU Library General Public
 #include "ClassInfo.h"
 #include "CommonIdentifiers.h"
 #include "CallFrame.h"
-#include "JSNumberCell.h"
+#include "JSCell.h"
 #include "PropertySlot.h"
 #include "PutPropertySlot.h"
 #include "ScopeChain.h"
+#include "StorageBarrier.h"
 #include "Structure.h"
 #include "JSGlobalData.h"
+#include "JSString.h"
 #include <wtf/StdLibExtras.h>
 
 namespace JSC {
 
-    inline JSCell* getJSFunction(JSGlobalData& globalData, JSValue value)
+    inline JSCell* getJSFunction(JSValue value)
     {
-        if (value.isCell() && (value.asCell()->vptr() == globalData.jsFunctionVPtr))
+        if (value.isCell() && (value.asCell()->structure()->typeInfo().type() == JSFunctionType))
             return value.asCell();
         return 0;
     }
 
+    class GetterSetter;
+    class HashEntry;
     class InternalFunction;
+    class LLIntOffsetsExtractor;
+    class MarkedBlock;
+    class PropertyDescriptor;
     class PropertyNameArray;
     class Structure;
-    struct HashEntry;
     struct HashTable;
 
+    JS_EXPORT_PRIVATE JSObject* throwTypeError(ExecState*, const UString&);
+    extern JS_EXPORTDATA const char* StrictModeReadonlyPropertyWriteError;
+
     // ECMA 262-3 8.6.1
     // Property attributes
     enum Attribute {
@@ -58,274 +67,494 @@ namespace JSC {
         DontEnum     = 1 << 2,  // property doesn't appear in (for .. in ..)
         DontDelete   = 1 << 3,  // property can't be deleted
         Function     = 1 << 4,  // property is a function - only used by static hashtables
-        Getter       = 1 << 5,  // property is a getter
-        Setter       = 1 << 6   // property is a setter
+        Accessor     = 1 << 5,  // property is a getter/setter
     };
 
-    typedef EncodedJSValue* PropertyStorage;
-    typedef const EncodedJSValue* ConstPropertyStorage;
-
     class JSObject : public JSCell {
         friend class BatchedTransitionOptimizer;
         friend class JIT;
         friend class JSCell;
+        friend class MarkedBlock;
+        JS_EXPORT_PRIVATE friend bool setUpStaticFunctionSlot(ExecState* exec, const HashEntry* entry, JSObject* thisObj, const Identifier& propertyName, PropertySlot& slot);
 
-    public:
-        explicit JSObject(PassRefPtr<Structure>);
+        enum PutMode {
+            PutModePut,
+            PutModeDefineOwnProperty,
+        };
 
-        virtual void mark();
+    public:
+        typedef JSCell Base;
 
-        // The inline virtual destructor cannot be the first virtual function declared
-        // in the class as it results in the vtable being generated as a weak symbol
-        virtual ~JSObject();
+        JS_EXPORT_PRIVATE static void visitChildren(JSCell*, SlotVisitor&);
 
-        bool inherits(const ClassInfo* classInfo) const { return JSCell::isObject(classInfo); }
+        JS_EXPORT_PRIVATE static UString className(const JSObject*);
 
         JSValue prototype() const;
-        void setPrototype(JSValue prototype);
+        void setPrototype(JSGlobalData&, JSValue prototype);
+        bool setPrototypeWithCycleCheck(JSGlobalData&, JSValue prototype);
         
-        void setStructure(PassRefPtr<Structure>);
-        Structure* inheritorID();
-
-        virtual UString className() const;
+        Structure* inheritorID(JSGlobalData&);
 
         JSValue get(ExecState*, const Identifier& propertyName) const;
         JSValue get(ExecState*, unsigned propertyName) const;
 
         bool getPropertySlot(ExecState*, const Identifier& propertyName, PropertySlot&);
         bool getPropertySlot(ExecState*, unsigned propertyName, PropertySlot&);
+        JS_EXPORT_PRIVATE bool getPropertyDescriptor(ExecState*, const Identifier& propertyName, PropertyDescriptor&);
 
-        virtual bool getOwnPropertySlot(ExecState*, const Identifier& propertyName, PropertySlot&);
-        virtual bool getOwnPropertySlot(ExecState*, unsigned propertyName, PropertySlot&);
+        static bool getOwnPropertySlot(JSCell*, ExecState*, const Identifier& propertyName, PropertySlot&);
+        JS_EXPORT_PRIVATE static bool getOwnPropertySlotByIndex(JSCell*, ExecState*, unsigned propertyName, PropertySlot&);
+        JS_EXPORT_PRIVATE static bool getOwnPropertyDescriptor(JSObject*, ExecState*, const Identifier&, PropertyDescriptor&);
 
-        virtual void put(ExecState*, const Identifier& propertyName, JSValue value, PutPropertySlot&);
-        virtual void put(ExecState*, unsigned propertyName, JSValue value);
+        bool allowsAccessFrom(ExecState*);
 
-        virtual void putWithAttributes(ExecState*, const Identifier& propertyName, JSValue value, unsigned attributes, bool checkReadOnly, PutPropertySlot& slot);
-        virtual void putWithAttributes(ExecState*, const Identifier& propertyName, JSValue value, unsigned attributes);
-        virtual void putWithAttributes(ExecState*, unsigned propertyName, JSValue value, unsigned attributes);
+        JS_EXPORT_PRIVATE static void put(JSCell*, ExecState*, const Identifier& propertyName, JSValue, PutPropertySlot&);
+        JS_EXPORT_PRIVATE static void putByIndex(JSCell*, ExecState*, unsigned propertyName, JSValue, bool shouldThrow);
+
+        // putDirect is effectively an unchecked vesion of 'defineOwnProperty':
+        //  - the prototype chain is not consulted
+        //  - accessors are not called.
+        //  - attributes will be respected (after the call the property will exist with the given attributes)
+        JS_EXPORT_PRIVATE static void putDirectVirtual(JSObject*, ExecState*, const Identifier& propertyName, JSValue, unsigned attributes);
+        void putDirect(JSGlobalData&, const Identifier& propertyName, JSValue, unsigned attributes = 0);
+        void putDirect(JSGlobalData&, const Identifier& propertyName, JSValue, PutPropertySlot&);
+        void putDirectWithoutTransition(JSGlobalData&, const Identifier& propertyName, JSValue, unsigned attributes = 0);
+        void putDirectAccessor(JSGlobalData&, const Identifier& propertyName, JSValue, unsigned attributes);
 
         bool propertyIsEnumerable(ExecState*, const Identifier& propertyName) const;
 
-        bool hasProperty(ExecState*, const Identifier& propertyName) const;
-        bool hasProperty(ExecState*, unsigned propertyName) const;
+        JS_EXPORT_PRIVATE bool hasProperty(ExecState*, const Identifier& propertyName) const;
+        JS_EXPORT_PRIVATE bool hasProperty(ExecState*, unsigned propertyName) const;
         bool hasOwnProperty(ExecState*, const Identifier& propertyName) const;
 
-        virtual bool deleteProperty(ExecState*, const Identifier& propertyName);
-        virtual bool deleteProperty(ExecState*, unsigned propertyName);
+        JS_EXPORT_PRIVATE static bool deleteProperty(JSCell*, ExecState*, const Identifier& propertyName);
+        JS_EXPORT_PRIVATE static bool deletePropertyByIndex(JSCell*, ExecState*, unsigned propertyName);
 
-        virtual JSValue defaultValue(ExecState*, PreferredPrimitiveType) const;
+        JS_EXPORT_PRIVATE static JSValue defaultValue(const JSObject*, ExecState*, PreferredPrimitiveType);
 
-        virtual bool hasInstance(ExecState*, JSValue, JSValue prototypeProperty);
+        JS_EXPORT_PRIVATE static bool hasInstance(JSObject*, ExecState*, JSValue, JSValue prototypeProperty);
 
-        virtual void getPropertyNames(ExecState*, PropertyNameArray&);
+        JS_EXPORT_PRIVATE static void getOwnPropertyNames(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode);
+        JS_EXPORT_PRIVATE static void getPropertyNames(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode);
 
-        virtual JSValue toPrimitive(ExecState*, PreferredPrimitiveType = NoPreference) const;
-        virtual bool getPrimitiveNumber(ExecState*, double& number, JSValue& value);
-        virtual bool toBoolean(ExecState*) const;
-        virtual double toNumber(ExecState*) const;
-        virtual UString toString(ExecState*) const;
-        virtual JSObject* toObject(ExecState*) const;
+        JSValue toPrimitive(ExecState*, PreferredPrimitiveType = NoPreference) const;
+        JS_EXPORT_PRIVATE bool toBoolean(ExecState*) const;
+        bool getPrimitiveNumber(ExecState*, double& number, JSValue&) const;
+        JS_EXPORT_PRIVATE double toNumber(ExecState*) const;
+        JS_EXPORT_PRIVATE JSString* toString(ExecState*) const;
 
-        virtual JSObject* toThisObject(ExecState*) const;
-        virtual JSObject* unwrappedObject();
+        // NOTE: JSObject and its subclasses must be able to gracefully handle ExecState* = 0,
+        // because this call may come from inside the compiler.
+        JS_EXPORT_PRIVATE static JSObject* toThisObject(JSCell*, ExecState*);
+        JSObject* unwrappedObject();
 
-        virtual bool getPropertyAttributes(ExecState*, const Identifier& propertyName, unsigned& attributes) const;
         bool getPropertySpecificValue(ExecState* exec, const Identifier& propertyName, JSCell*& specificFunction) const;
 
         // This get function only looks at the property map.
-        JSValue getDirect(const Identifier& propertyName) const
+        JSValue getDirect(JSGlobalData& globalData, const Identifier& propertyName) const
         {
-            size_t offset = m_structure->get(propertyName);
+            size_t offset = structure()->get(globalData, propertyName);
             return offset != WTF::notFound ? getDirectOffset(offset) : JSValue();
         }
 
-        JSValue* getDirectLocation(const Identifier& propertyName)
+        WriteBarrierBase<Unknown>* getDirectLocation(JSGlobalData& globalData, const Identifier& propertyName)
         {
-            size_t offset = m_structure->get(propertyName);
+            size_t offset = structure()->get(globalData, propertyName);
             return offset != WTF::notFound ? locationForOffset(offset) : 0;
         }
 
-        JSValue* getDirectLocation(const Identifier& propertyName, unsigned& attributes)
+        WriteBarrierBase<Unknown>* getDirectLocation(JSGlobalData& globalData, const Identifier& propertyName, unsigned& attributes)
         {
             JSCell* specificFunction;
-            size_t offset = m_structure->get(propertyName, attributes, specificFunction);
+            size_t offset = structure()->get(globalData, propertyName, attributes, specificFunction);
             return offset != WTF::notFound ? locationForOffset(offset) : 0;
         }
 
-        size_t offsetForLocation(JSValue* location) const
+        size_t offsetForLocation(WriteBarrierBase<Unknown>* location) const
         {
-            return location - reinterpret_cast<const JSValue*>(propertyStorage());
+            return location - propertyStorage();
         }
 
-        void transitionTo(Structure*);
-
-        void removeDirect(const Identifier& propertyName);
-        bool hasCustomProperties() { return !m_structure->isEmpty(); }
-        bool hasGetterSetterProperties() { return m_structure->hasGetterSetterProperties(); }
-
-        void putDirect(const Identifier& propertyName, JSValue value, unsigned attr, bool checkReadOnly, PutPropertySlot& slot);
-        void putDirect(const Identifier& propertyName, JSValue value, unsigned attr = 0);
+        void transitionTo(JSGlobalData&, Structure*);
 
-        void putDirectFunction(const Identifier& propertyName, JSCell* value, unsigned attr = 0);
-        void putDirectFunction(const Identifier& propertyName, JSCell* value, unsigned attr, bool checkReadOnly, PutPropertySlot& slot);
-        void putDirectFunction(ExecState* exec, InternalFunction* function, unsigned attr = 0);
+        void removeDirect(JSGlobalData&, const Identifier& propertyName);
+        bool hasCustomProperties() { return structure()->didTransition(); }
+        bool hasGetterSetterProperties() { return structure()->hasGetterSetterProperties(); }
 
-        void putDirectWithoutTransition(const Identifier& propertyName, JSValue value, unsigned attr = 0);
-        void putDirectFunctionWithoutTransition(const Identifier& propertyName, JSCell* value, unsigned attr = 0);
-        void putDirectFunctionWithoutTransition(ExecState* exec, InternalFunction* function, unsigned attr = 0);
+        // putOwnDataProperty has 'put' like semantics, however this method:
+        //  - assumes the object contains no own getter/setter properties.
+        //  - provides no special handling for __proto__
+        //  - does not walk the prototype chain (to check for accessors or non-writable properties).
+        // This is used by JSActivation.
+        bool putOwnDataProperty(JSGlobalData&, const Identifier& propertyName, JSValue, PutPropertySlot&);
 
         // Fast access to known property offsets.
-        JSValue getDirectOffset(size_t offset) const { return JSValue::decode(propertyStorage()[offset]); }
-        void putDirectOffset(size_t offset, JSValue value) { propertyStorage()[offset] = JSValue::encode(value); }
+        JSValue getDirectOffset(size_t offset) const { return propertyStorage()[offset].get(); }
+        void putDirectOffset(JSGlobalData& globalData, size_t offset, JSValue value) { propertyStorage()[offset].set(globalData, this, value); }
+        void putUndefinedAtDirectOffset(size_t offset) { propertyStorage()[offset].setUndefined(); }
+
+        JS_EXPORT_PRIVATE static bool defineOwnProperty(JSObject*, ExecState*, const Identifier& propertyName, PropertyDescriptor&, bool shouldThrow);
+
+        bool isGlobalObject() const;
+        bool isVariableObject() const;
+        bool isStaticScopeObject() const;
+        bool isActivationObject() const;
+        bool isErrorInstance() const;
+        bool isGlobalThis() const;
+
+        void seal(JSGlobalData&);
+        void freeze(JSGlobalData&);
+        JS_EXPORT_PRIVATE void preventExtensions(JSGlobalData&);
+        bool isSealed(JSGlobalData& globalData) { return structure()->isSealed(globalData); }
+        bool isFrozen(JSGlobalData& globalData) { return structure()->isFrozen(globalData); }
+        bool isExtensible() { return structure()->isExtensible(); }
+
+        bool staticFunctionsReified() { return structure()->staticFunctionsReified(); }
+        void reifyStaticFunctionsForDelete(ExecState* exec);
+
+        JS_EXPORT_PRIVATE PropertyStorage growPropertyStorage(JSGlobalData&, size_t oldSize, size_t newSize);
+        bool isUsingInlineStorage() const { return static_cast<const void*>(m_propertyStorage.get()) == static_cast<const void*>(this + 1); }
+        void setPropertyStorage(JSGlobalData&, PropertyStorage, Structure*);
+
+        void* addressOfPropertyStorage()
+        {
+            return &m_propertyStorage;
+        }
 
-        void fillGetterPropertySlot(PropertySlot&, JSValue* location);
+        static const unsigned baseExternalStorageCapacity = 16;
 
-        virtual void defineGetter(ExecState*, const Identifier& propertyName, JSObject* getterFunction);
-        virtual void defineSetter(ExecState*, const Identifier& propertyName, JSObject* setterFunction);
-        virtual JSValue lookupGetter(ExecState*, const Identifier& propertyName);
-        virtual JSValue lookupSetter(ExecState*, const Identifier& propertyName);
+        void flattenDictionaryObject(JSGlobalData& globalData)
+        {
+            structure()->flattenDictionaryStructure(globalData, this);
+        }
 
-        virtual bool isGlobalObject() const { return false; }
-        virtual bool isVariableObject() const { return false; }
-        virtual bool isActivationObject() const { return false; }
-        virtual bool isWatchdogException() const { return false; }
-        virtual bool isNotAnObjectErrorStub() const { return false; }
+        JSGlobalObject* globalObject() const
+        {
+            ASSERT(structure()->globalObject());
+            ASSERT(!isGlobalObject() || ((JSObject*)structure()->globalObject()) == this);
+            return structure()->globalObject();
+        }
+        
+        static size_t offsetOfInlineStorage();
+        static size_t offsetOfPropertyStorage();
+        static size_t offsetOfInheritorID();
 
-        void allocatePropertyStorage(size_t oldSize, size_t newSize);
-        void allocatePropertyStorageInline(size_t oldSize, size_t newSize);
-        bool isUsingInlineStorage() const { return m_structure->isUsingInlineStorage(); }
+        static JS_EXPORTDATA const ClassInfo s_info;
 
-        static const size_t inlineStorageCapacity = sizeof(EncodedJSValue) == 2 * sizeof(void*) ? 4 : 3;
-        static const size_t nonInlineBaseStorageCapacity = 16;
+    protected:
+        void finishCreation(JSGlobalData& globalData, PropertyStorage inlineStorage)
+        {
+            Base::finishCreation(globalData);
+            ASSERT(inherits(&s_info));
+            ASSERT(structure()->propertyStorageCapacity() < baseExternalStorageCapacity);
+            ASSERT(structure()->isEmpty());
+            ASSERT(prototype().isNull() || Heap::heap(this) == Heap::heap(prototype()));
+            ASSERT_UNUSED(inlineStorage, static_cast<void*>(inlineStorage) == static_cast<void*>(this + 1));
+            ASSERT(structure()->isObject());
+            ASSERT(classInfo());
+        }
 
-        static PassRefPtr<Structure> createStructure(JSValue prototype)
+        static Structure* createStructure(JSGlobalData& globalData, JSGlobalObject* globalObject, JSValue prototype)
         {
-            return Structure::create(prototype, TypeInfo(ObjectType, HasStandardGetOwnPropertySlot));
+            return Structure::create(globalData, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), &s_info);
         }
 
-        void flattenDictionaryObject()
+        static const unsigned StructureFlags = 0;
+
+        // To instantiate objects you likely want JSFinalObject, below.
+        // To create derived types you likely want JSNonFinalObject, below.
+        JSObject(JSGlobalData&, Structure*, PropertyStorage inlineStorage);
+        
+        void resetInheritorID()
         {
-            m_structure->flattenDictionaryStructure(this);
+            m_inheritorID.clear();
         }
 
     private:
-        ConstPropertyStorage propertyStorage() const { return (isUsingInlineStorage() ? m_inlineStorage : m_externalStorage); }
-        PropertyStorage propertyStorage() { return (isUsingInlineStorage() ? m_inlineStorage : m_externalStorage); }
+        friend class LLIntOffsetsExtractor;
+        
+        // Nobody should ever ask any of these questions on something already known to be a JSObject.
+        using JSCell::isAPIValueWrapper;
+        using JSCell::isGetterSetter;
+        void getObject();
+        void getString(ExecState* exec);
+        void isObject();
+        void isString();
+        
+        ConstPropertyStorage propertyStorage() const { return m_propertyStorage.get(); }
+        PropertyStorage propertyStorage() { return m_propertyStorage.get(); }
 
-        const JSValue* locationForOffset(size_t offset) const
+        const WriteBarrierBase<Unknown>* locationForOffset(size_t offset) const
         {
-            return reinterpret_cast<const JSValue*>(&propertyStorage()[offset]);
+            return &propertyStorage()[offset];
         }
 
-        JSValue* locationForOffset(size_t offset)
+        WriteBarrierBase<Unknown>* locationForOffset(size_t offset)
         {
-            return reinterpret_cast<JSValue*>(&propertyStorage()[offset]);
+            return &propertyStorage()[offset];
         }
 
-        void putDirectInternal(const Identifier& propertyName, JSValue value, unsigned attr, bool checkReadOnly, PutPropertySlot& slot, JSCell*);
-        void putDirectInternal(JSGlobalData&, const Identifier& propertyName, JSValue value, unsigned attr, bool checkReadOnly, PutPropertySlot& slot);
-        void putDirectInternal(JSGlobalData&, const Identifier& propertyName, JSValue value, unsigned attr = 0);
+        template<PutMode>
+        bool putDirectInternal(JSGlobalData&, const Identifier& propertyName, JSValue, unsigned attr, PutPropertySlot&, JSCell*);
 
         bool inlineGetOwnPropertySlot(ExecState*, const Identifier& propertyName, PropertySlot&);
+        JS_EXPORT_PRIVATE void fillGetterPropertySlot(PropertySlot&, WriteBarrierBase<Unknown>* location);
 
         const HashEntry* findPropertyHashEntry(ExecState*, const Identifier& propertyName) const;
-        Structure* createInheritorID();
+        Structure* createInheritorID(JSGlobalData&);
 
-        union {
-            PropertyStorage m_externalStorage;
-            EncodedJSValue m_inlineStorage[inlineStorageCapacity];
-        };
+        StorageBarrier m_propertyStorage;
+        WriteBarrier<Structure> m_inheritorID;
+    };
+
+
+#if USE(JSVALUE32_64)
+#define JSNonFinalObject_inlineStorageCapacity 4
+#define JSFinalObject_inlineStorageCapacity 6
+#else
+#define JSNonFinalObject_inlineStorageCapacity 2
+#define JSFinalObject_inlineStorageCapacity 4
+#endif
+
+COMPILE_ASSERT((JSFinalObject_inlineStorageCapacity >= JSNonFinalObject_inlineStorageCapacity), final_storage_is_at_least_as_large_as_non_final);
 
-        RefPtr<Structure> m_inheritorID;
+    // JSNonFinalObject is a type of JSObject that has some internal storage,
+    // but also preserves some space in the collector cell for additional
+    // data members in derived types.
+    class JSNonFinalObject : public JSObject {
+        friend class JSObject;
+
+    public:
+        typedef JSObject Base;
+
+        static Structure* createStructure(JSGlobalData& globalData, JSGlobalObject* globalObject, JSValue prototype)
+        {
+            return Structure::create(globalData, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), &s_info);
+        }
+
+    protected:
+        explicit JSNonFinalObject(JSGlobalData& globalData, Structure* structure)
+            : JSObject(globalData, structure, m_inlineStorage)
+        {
+        }
+
+        void finishCreation(JSGlobalData& globalData)
+        {
+            Base::finishCreation(globalData, m_inlineStorage);
+            ASSERT(!(OBJECT_OFFSETOF(JSNonFinalObject, m_inlineStorage) % sizeof(double)));
+            ASSERT(this->structure()->propertyStorageCapacity() == JSNonFinalObject_inlineStorageCapacity);
+            ASSERT(classInfo());
+        }
+
+    private:
+        WriteBarrier<Unknown> m_inlineStorage[JSNonFinalObject_inlineStorageCapacity];
     };
-    
-JSObject* constructEmptyObject(ExecState*);
 
-inline JSObject* asObject(JSValue value)
+    class JSFinalObject;
+
+    // JSFinalObject is a type of JSObject that contains sufficent internal
+    // storage to fully make use of the colloctor cell containing it.
+    class JSFinalObject : public JSObject {
+        friend class JSObject;
+
+    public:
+        typedef JSObject Base;
+
+        static JSFinalObject* create(ExecState*, Structure*);
+        static Structure* createStructure(JSGlobalData& globalData, JSGlobalObject* globalObject, JSValue prototype)
+        {
+            return Structure::create(globalData, globalObject, prototype, TypeInfo(FinalObjectType, StructureFlags), &s_info);
+        }
+
+        static JS_EXPORTDATA const ClassInfo s_info;
+
+    protected:
+        void finishCreation(JSGlobalData& globalData)
+        {
+            Base::finishCreation(globalData, m_inlineStorage);
+            ASSERT(!(OBJECT_OFFSETOF(JSFinalObject, m_inlineStorage) % sizeof(double)));
+            ASSERT(this->structure()->propertyStorageCapacity() == JSFinalObject_inlineStorageCapacity);
+            ASSERT(classInfo());
+        }
+
+    private:
+        friend class LLIntOffsetsExtractor;
+        
+        explicit JSFinalObject(JSGlobalData& globalData, Structure* structure)
+            : JSObject(globalData, structure, m_inlineStorage)
+        {
+        }
+
+        static const unsigned StructureFlags = JSObject::StructureFlags;
+
+        WriteBarrierBase<Unknown> m_inlineStorage[JSFinalObject_inlineStorageCapacity];
+    };
+
+inline JSFinalObject* JSFinalObject::create(ExecState* exec, Structure* structure)
 {
-    ASSERT(asCell(value)->isObject());
-    return static_cast<JSObject*>(asCell(value));
+    JSFinalObject* finalObject = new (NotNull, allocateCell<JSFinalObject>(*exec->heap())) JSFinalObject(exec->globalData(), structure);
+    finalObject->finishCreation(exec->globalData());
+    return finalObject;
 }
 
-inline JSObject::JSObject(PassRefPtr<Structure> structure)
-    : JSCell(structure.releaseRef()) // ~JSObject balances this ref()
+inline bool isJSFinalObject(JSCell* cell)
 {
-    ASSERT(m_structure);
-    ASSERT(m_structure->propertyStorageCapacity() == inlineStorageCapacity);
-    ASSERT(m_structure->isEmpty());
-    ASSERT(prototype().isNull() || Heap::heap(this) == Heap::heap(prototype()));
-#if USE(JSVALUE64) || USE(JSVALUE32_64)
-    ASSERT(OBJECT_OFFSETOF(JSObject, m_inlineStorage) % sizeof(double) == 0);
-#endif
+    return cell->classInfo() == &JSFinalObject::s_info;
 }
 
-inline JSObject::~JSObject()
+inline bool isJSFinalObject(JSValue value)
 {
-    ASSERT(m_structure);
-    if (!isUsingInlineStorage())
-        delete [] m_externalStorage;
-    m_structure->deref();
+    return value.isCell() && isJSFinalObject(value.asCell());
 }
 
-inline JSValue JSObject::prototype() const
+inline size_t JSObject::offsetOfInlineStorage()
 {
-    return m_structure->storedPrototype();
+    ASSERT(OBJECT_OFFSETOF(JSFinalObject, m_inlineStorage) == OBJECT_OFFSETOF(JSNonFinalObject, m_inlineStorage));
+    return OBJECT_OFFSETOF(JSFinalObject, m_inlineStorage);
 }
 
-inline void JSObject::setPrototype(JSValue prototype)
+inline size_t JSObject::offsetOfPropertyStorage()
 {
-    ASSERT(prototype);
-    RefPtr<Structure> newStructure = Structure::changePrototypeTransition(m_structure, prototype);
-    setStructure(newStructure.release());
+    return OBJECT_OFFSETOF(JSObject, m_propertyStorage);
+}
+
+inline size_t JSObject::offsetOfInheritorID()
+{
+    return OBJECT_OFFSETOF(JSObject, m_inheritorID);
+}
+
+inline bool JSObject::isGlobalObject() const
+{
+    return structure()->typeInfo().type() == GlobalObjectType;
+}
+
+inline bool JSObject::isVariableObject() const
+{
+    return structure()->typeInfo().type() >= VariableObjectType;
+}
+
+inline bool JSObject::isStaticScopeObject() const
+{
+    return structure()->typeInfo().type() == StaticScopeObjectType;
+}
+
+inline bool JSObject::isActivationObject() const
+{
+    return structure()->typeInfo().type() == ActivationObjectType;
+}
+
+inline bool JSObject::isErrorInstance() const
+{
+    return structure()->typeInfo().type() == ErrorInstanceType;
+}
+
+inline bool JSObject::isGlobalThis() const
+{
+    return structure()->typeInfo().type() == GlobalThisType;
 }
 
-inline void JSObject::setStructure(PassRefPtr<Structure> structure)
+inline void JSObject::setPropertyStorage(JSGlobalData& globalData, PropertyStorage storage, Structure* structure)
 {
-    m_structure->deref();
-    m_structure = structure.releaseRef(); // ~JSObject balances this ref()
+    ASSERT(storage);
+    ASSERT(structure);
+    setStructure(globalData, structure);
+    m_propertyStorage.set(globalData, this, storage);
 }
 
-inline Structure* JSObject::inheritorID()
+inline JSObject* constructEmptyObject(ExecState* exec, Structure* structure)
 {
-    if (m_inheritorID)
+    return JSFinalObject::create(exec, structure);
+}
+
+inline CallType getCallData(JSValue value, CallData& callData)
+{
+    CallType result = value.isCell() ? value.asCell()->methodTable()->getCallData(value.asCell(), callData) : CallTypeNone;
+    ASSERT(result == CallTypeNone || value.isValidCallee());
+    return result;
+}
+
+inline ConstructType getConstructData(JSValue value, ConstructData& constructData)
+{
+    ConstructType result = value.isCell() ? value.asCell()->methodTable()->getConstructData(value.asCell(), constructData) : ConstructTypeNone;
+    ASSERT(result == ConstructTypeNone || value.isValidCallee());
+    return result;
+}
+
+inline Structure* createEmptyObjectStructure(JSGlobalData& globalData, JSGlobalObject* globalObject, JSValue prototype)
+{
+    return JSFinalObject::createStructure(globalData, globalObject, prototype);
+}
+
+inline JSObject* asObject(JSCell* cell)
+{
+    ASSERT(cell->isObject());
+    return jsCast<JSObject*>(cell);
+}
+
+inline JSObject* asObject(JSValue value)
+{
+    return asObject(value.asCell());
+}
+
+inline JSObject::JSObject(JSGlobalData& globalData, Structure* structure, PropertyStorage inlineStorage)
+    : JSCell(globalData, structure)
+    , m_propertyStorage(globalData, this, inlineStorage)
+{
+}
+
+inline JSValue JSObject::prototype() const
+{
+    return structure()->storedPrototype();
+}
+
+inline void JSObject::setPrototype(JSGlobalData& globalData, JSValue prototype)
+{
+    ASSERT(prototype);
+    setStructure(globalData, Structure::changePrototypeTransition(globalData, structure(), prototype));
+}
+
+inline Structure* JSObject::inheritorID(JSGlobalData& globalData)
+{
+    if (m_inheritorID) {
+        ASSERT(m_inheritorID->isEmpty());
         return m_inheritorID.get();
-    return createInheritorID();
+    }
+    return createInheritorID(globalData);
 }
 
 inline bool Structure::isUsingInlineStorage() const
 {
-    return (propertyStorageCapacity() == JSObject::inlineStorageCapacity);
+    return propertyStorageCapacity() < JSObject::baseExternalStorageCapacity;
 }
 
-inline bool JSCell::isObject(const ClassInfo* info) const
+inline bool JSCell::inherits(const ClassInfo* info) const
 {
-    for (const ClassInfo* ci = classInfo(); ci; ci = ci->parentClass) {
-        if (ci == info)
-            return true;
-    }
-    return false;
+    return classInfo()->isSubClassOf(info);
+}
+
+inline const MethodTable* JSCell::methodTable() const
+{
+    return &classInfo()->methodTable;
+}
+
+// this method is here to be after the inline declaration of JSCell::inherits
+inline bool JSValue::inherits(const ClassInfo* classInfo) const
+{
+    return isCell() && asCell()->inherits(classInfo);
 }
 
-// this method is here to be after the inline declaration of JSCell::isObject
-inline bool JSValue::isObject(const ClassInfo* classInfo) const
+inline JSObject* JSValue::toThisObject(ExecState* exec) const
 {
-    return isCell() && asCell()->isObject(classInfo);
+    return isCell() ? asCell()->methodTable()->toThisObject(asCell(), exec) : toThisObjectSlowCase(exec);
 }
 
 ALWAYS_INLINE bool JSObject::inlineGetOwnPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot)
 {
-    if (JSValue* location = getDirectLocation(propertyName)) {
-        if (m_structure->hasGetterSetterProperties() && location[0].isGetterSetter())
+    if (WriteBarrierBase<Unknown>* location = getDirectLocation(exec->globalData(), propertyName)) {
+        if (structure()->hasGetterSetterProperties() && location->isGetterSetter())
             fillGetterPropertySlot(slot, location);
         else
-            slot.setValueSlot(this, location, offsetForLocation(location));
-        return true;
-    }
-
-    // non-standard Netscape extension
-    if (propertyName == exec->propertyNames().underscoreProto) {
-        slot.setValue(prototype());
+            slot.setValue(this, location->get(), offsetForLocation(location));
         return true;
     }
 
@@ -335,21 +564,37 @@ ALWAYS_INLINE bool JSObject::inlineGetOwnPropertySlot(ExecState* exec, const Ide
 // It may seem crazy to inline a function this large, especially a virtual function,
 // but it makes a big difference to property lookup that derived classes can inline their
 // base class call to this.
-ALWAYS_INLINE bool JSObject::getOwnPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot)
+ALWAYS_INLINE bool JSObject::getOwnPropertySlot(JSCell* cell, ExecState* exec, const Identifier& propertyName, PropertySlot& slot)
 {
-    return inlineGetOwnPropertySlot(exec, propertyName, slot);
+    return jsCast<JSObject*>(cell)->inlineGetOwnPropertySlot(exec, propertyName, slot);
 }
 
 ALWAYS_INLINE bool JSCell::fastGetOwnPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot)
 {
-    if (structure()->typeInfo().hasStandardGetOwnPropertySlot())
+    if (!structure()->typeInfo().overridesGetOwnPropertySlot())
         return asObject(this)->inlineGetOwnPropertySlot(exec, propertyName, slot);
-    return getOwnPropertySlot(exec, propertyName, slot);
+    return methodTable()->getOwnPropertySlot(this, exec, propertyName, slot);
+}
+
+// Fast call to get a property where we may not yet have converted the string to an
+// identifier. The first time we perform a property access with a given string, try
+// performing the property map lookup without forming an identifier. We detect this
+// case by checking whether the hash has yet been set for this string.
+ALWAYS_INLINE JSValue JSCell::fastGetOwnProperty(ExecState* exec, const UString& name)
+{
+    if (!structure()->typeInfo().overridesGetOwnPropertySlot() && !structure()->hasGetterSetterProperties()) {
+        size_t offset = name.impl()->hasHash()
+            ? structure()->get(exec->globalData(), Identifier(exec, name))
+            : structure()->get(exec->globalData(), name);
+        if (offset != WTF::notFound)
+            return asObject(this)->locationForOffset(offset)->get();
+    }
+    return JSValue();
 }
 
 // It may seem crazy to inline a function this large but it makes a big difference
 // since this is function very hot in variable lookup
-inline bool JSObject::getPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot)
+ALWAYS_INLINE bool JSObject::getPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot)
 {
     JSObject* object = this;
     while (true) {
@@ -362,11 +607,11 @@ inline bool JSObject::getPropertySlot(ExecState* exec, const Identifier& propert
     }
 }
 
-inline bool JSObject::getPropertySlot(ExecState* exec, unsigned propertyName, PropertySlot& slot)
+ALWAYS_INLINE bool JSObject::getPropertySlot(ExecState* exec, unsigned propertyName, PropertySlot& slot)
 {
     JSObject* object = this;
     while (true) {
-        if (object->getOwnPropertySlot(exec, propertyName, slot))
+        if (object->methodTable()->getOwnPropertySlotByIndex(object, exec, propertyName, slot))
             return true;
         JSValue prototype = object->prototype();
         if (!prototype.isObject())
@@ -393,162 +638,166 @@ inline JSValue JSObject::get(ExecState* exec, unsigned propertyName) const
     return jsUndefined();
 }
 
-inline void JSObject::putDirectInternal(const Identifier& propertyName, JSValue value, unsigned attributes, bool checkReadOnly, PutPropertySlot& slot, JSCell* specificFunction)
+template<JSObject::PutMode mode>
+inline bool JSObject::putDirectInternal(JSGlobalData& globalData, const Identifier& propertyName, JSValue value, unsigned attributes, PutPropertySlot& slot, JSCell* specificFunction)
 {
     ASSERT(value);
+    ASSERT(value.isGetterSetter() == !!(attributes & Accessor));
     ASSERT(!Heap::heap(value) || Heap::heap(value) == Heap::heap(this));
 
-    if (m_structure->isDictionary()) {
+    if (structure()->isDictionary()) {
         unsigned currentAttributes;
         JSCell* currentSpecificFunction;
-        size_t offset = m_structure->get(propertyName, currentAttributes, currentSpecificFunction);
+        size_t offset = structure()->get(globalData, propertyName, currentAttributes, currentSpecificFunction);
         if (offset != WTF::notFound) {
+            // If there is currently a specific function, and there now either isn't,
+            // or the new value is different, then despecify.
             if (currentSpecificFunction && (specificFunction != currentSpecificFunction))
-                m_structure->despecifyDictionaryFunction(propertyName);
-            if (checkReadOnly && currentAttributes & ReadOnly)
-                return;
-            putDirectOffset(offset, value);
-            if (!specificFunction && !currentSpecificFunction)
+                structure()->despecifyDictionaryFunction(globalData, propertyName);
+            if ((mode == PutModePut) && currentAttributes & ReadOnly)
+                return false;
+
+            putDirectOffset(globalData, offset, value);
+            // At this point, the objects structure only has a specific value set if previously there
+            // had been one set, and if the new value being specified is the same (otherwise we would
+            // have despecified, above).  So, if currentSpecificFunction is not set, or if the new
+            // value is different (or there is no new value), then the slot now has no value - and
+            // as such it is cachable.
+            // If there was previously a value, and the new value is the same, then we cannot cache.
+            if (!currentSpecificFunction || (specificFunction != currentSpecificFunction))
                 slot.setExistingProperty(this, offset);
-            return;
+            return true;
         }
 
-        size_t currentCapacity = m_structure->propertyStorageCapacity();
-        offset = m_structure->addPropertyWithoutTransition(propertyName, attributes, specificFunction);
-        if (currentCapacity != m_structure->propertyStorageCapacity())
-            allocatePropertyStorage(currentCapacity, m_structure->propertyStorageCapacity());
+        if ((mode == PutModePut) && !isExtensible())
+            return false;
 
-        ASSERT(offset < m_structure->propertyStorageCapacity());
-        putDirectOffset(offset, value);
+        PropertyStorage newStorage = propertyStorage();
+        if (structure()->shouldGrowPropertyStorage())
+            newStorage = growPropertyStorage(globalData, structure()->propertyStorageCapacity(), structure()->suggestedNewPropertyStorageSize());
+        offset = structure()->addPropertyWithoutTransition(globalData, propertyName, attributes, specificFunction);
+        setPropertyStorage(globalData, newStorage, structure());
+
+        ASSERT(offset < structure()->propertyStorageCapacity());
+        putDirectOffset(globalData, offset, value);
         // See comment on setNewProperty call below.
         if (!specificFunction)
             slot.setNewProperty(this, offset);
-        return;
+        return true;
     }
 
     size_t offset;
-    size_t currentCapacity = m_structure->propertyStorageCapacity();
-    if (RefPtr<Structure> structure = Structure::addPropertyTransitionToExistingStructure(m_structure, propertyName, attributes, specificFunction, offset)) {    
+    size_t currentCapacity = structure()->propertyStorageCapacity();
+    if (Structure* structure = Structure::addPropertyTransitionToExistingStructure(this->structure(), propertyName, attributes, specificFunction, offset)) {
+        PropertyStorage newStorage = propertyStorage(); 
         if (currentCapacity != structure->propertyStorageCapacity())
-            allocatePropertyStorage(currentCapacity, structure->propertyStorageCapacity());
+            newStorage = growPropertyStorage(globalData, currentCapacity, structure->propertyStorageCapacity());
 
         ASSERT(offset < structure->propertyStorageCapacity());
-        setStructure(structure.release());
-        putDirectOffset(offset, value);
-        // See comment on setNewProperty call below.
+        setPropertyStorage(globalData, newStorage, structure);
+        putDirectOffset(globalData, offset, value);
+        // This is a new property; transitions with specific values are not currently cachable,
+        // so leave the slot in an uncachable state.
         if (!specificFunction)
             slot.setNewProperty(this, offset);
-        return;
+        return true;
     }
 
     unsigned currentAttributes;
     JSCell* currentSpecificFunction;
-    offset = m_structure->get(propertyName, currentAttributes, currentSpecificFunction);
+    offset = structure()->get(globalData, propertyName, currentAttributes, currentSpecificFunction);
     if (offset != WTF::notFound) {
-        if (checkReadOnly && currentAttributes & ReadOnly)
-            return;
-
-        if (currentSpecificFunction && (specificFunction != currentSpecificFunction)) {
-            setStructure(Structure::despecifyFunctionTransition(m_structure, propertyName));
-            putDirectOffset(offset, value);
-            // Function transitions are not currently cachable, so leave the slot in an uncachable state.
-            return;
+        if ((mode == PutModePut) && currentAttributes & ReadOnly)
+            return false;
+
+        // There are three possibilities here:
+        //  (1) There is an existing specific value set, and we're overwriting with *the same value*.
+        //       * Do nothing - no need to despecify, but that means we can't cache (a cached
+        //         put could write a different value). Leave the slot in an uncachable state.
+        //  (2) There is a specific value currently set, but we're writing a different value.
+        //       * First, we have to despecify.  Having done so, this is now a regular slot
+        //         with no specific value, so go ahead & cache like normal.
+        //  (3) Normal case, there is no specific value set.
+        //       * Go ahead & cache like normal.
+        if (currentSpecificFunction) {
+            // case (1) Do the put, then return leaving the slot uncachable.
+            if (specificFunction == currentSpecificFunction) {
+                putDirectOffset(globalData, offset, value);
+                return true;
+            }
+            // case (2) Despecify, fall through to (3).
+            setStructure(globalData, Structure::despecifyFunctionTransition(globalData, structure(), propertyName));
         }
-        putDirectOffset(offset, value);
+
+        // case (3) set the slot, do the put, return.
         slot.setExistingProperty(this, offset);
-        return;
+        putDirectOffset(globalData, offset, value);
+        return true;
     }
 
-    // If we have a specific function, we may have got to this point if there is
-    // already a transition with the correct property name and attributes, but
-    // specialized to a different function.  In this case we just want to give up
-    // and despecialize the transition.
-    // In this case we clear the value of specificFunction which will result
-    // in us adding a non-specific transition, and any subsequent lookup in
-    // Structure::addPropertyTransitionToExistingStructure will just use that.
-    if (specificFunction && m_structure->hasTransition(propertyName, attributes))
-        specificFunction = 0;
+    if ((mode == PutModePut) && !isExtensible())
+        return false;
 
-    RefPtr<Structure> structure = Structure::addPropertyTransition(m_structure, propertyName, attributes, specificFunction, offset);
+    PropertyStorage newStorage = propertyStorage();
+    if (structure()->shouldGrowPropertyStorage())
+        newStorage = growPropertyStorage(globalData, structure()->propertyStorageCapacity(), structure()->suggestedNewPropertyStorageSize());
 
-    if (currentCapacity != structure->propertyStorageCapacity())
-        allocatePropertyStorage(currentCapacity, structure->propertyStorageCapacity());
+    Structure* structure = Structure::addPropertyTransition(globalData, this->structure(), propertyName, attributes, specificFunction, offset);
 
     ASSERT(offset < structure->propertyStorageCapacity());
-    setStructure(structure.release());
-    putDirectOffset(offset, value);
-    // Function transitions are not currently cachable, so leave the slot in an uncachable state.
+    setPropertyStorage(globalData, newStorage, structure);
+    putDirectOffset(globalData, offset, value);
+    // This is a new property; transitions with specific values are not currently cachable,
+    // so leave the slot in an uncachable state.
     if (!specificFunction)
         slot.setNewProperty(this, offset);
+    return true;
 }
 
-inline void JSObject::putDirectInternal(JSGlobalData& globalData, const Identifier& propertyName, JSValue value, unsigned attributes, bool checkReadOnly, PutPropertySlot& slot)
-{
-    ASSERT(value);
-    ASSERT(!Heap::heap(value) || Heap::heap(value) == Heap::heap(this));
-
-    putDirectInternal(propertyName, value, attributes, checkReadOnly, slot, getJSFunction(globalData, value));
-}
-
-inline void JSObject::putDirectInternal(JSGlobalData& globalData, const Identifier& propertyName, JSValue value, unsigned attributes)
-{
-    PutPropertySlot slot;
-    putDirectInternal(propertyName, value, attributes, false, slot, getJSFunction(globalData, value));
-}
-
-inline void JSObject::putDirect(const Identifier& propertyName, JSValue value, unsigned attributes, bool checkReadOnly, PutPropertySlot& slot)
+inline bool JSObject::putOwnDataProperty(JSGlobalData& globalData, const Identifier& propertyName, JSValue value, PutPropertySlot& slot)
 {
     ASSERT(value);
     ASSERT(!Heap::heap(value) || Heap::heap(value) == Heap::heap(this));
+    ASSERT(!structure()->hasGetterSetterProperties());
 
-    putDirectInternal(propertyName, value, attributes, checkReadOnly, slot, 0);
+    return putDirectInternal<PutModePut>(globalData, propertyName, value, 0, slot, getJSFunction(value));
 }
 
-inline void JSObject::putDirect(const Identifier& propertyName, JSValue value, unsigned attributes)
+inline void JSObject::putDirect(JSGlobalData& globalData, const Identifier& propertyName, JSValue value, unsigned attributes)
 {
+    ASSERT(!value.isGetterSetter() && !(attributes & Accessor));
     PutPropertySlot slot;
-    putDirectInternal(propertyName, value, attributes, false, slot, 0);
+    putDirectInternal<PutModeDefineOwnProperty>(globalData, propertyName, value, attributes, slot, getJSFunction(value));
 }
 
-inline void JSObject::putDirectFunction(const Identifier& propertyName, JSCell* value, unsigned attributes, bool checkReadOnly, PutPropertySlot& slot)
+inline void JSObject::putDirect(JSGlobalData& globalData, const Identifier& propertyName, JSValue value, PutPropertySlot& slot)
 {
-    putDirectInternal(propertyName, value, attributes, checkReadOnly, slot, value);
+    ASSERT(!value.isGetterSetter());
+    putDirectInternal<PutModeDefineOwnProperty>(globalData, propertyName, value, 0, slot, getJSFunction(value));
 }
 
-inline void JSObject::putDirectFunction(const Identifier& propertyName, JSCell* value, unsigned attr)
+inline void JSObject::putDirectWithoutTransition(JSGlobalData& globalData, const Identifier& propertyName, JSValue value, unsigned attributes)
 {
-    PutPropertySlot slot;
-    putDirectInternal(propertyName, value, attr, false, slot, value);
+    ASSERT(!value.isGetterSetter() && !(attributes & Accessor));
+    PropertyStorage newStorage = propertyStorage();
+    if (structure()->shouldGrowPropertyStorage())
+        newStorage = growPropertyStorage(globalData, structure()->propertyStorageCapacity(), structure()->suggestedNewPropertyStorageSize());
+    size_t offset = structure()->addPropertyWithoutTransition(globalData, propertyName, attributes, getJSFunction(value));
+    setPropertyStorage(globalData, newStorage, structure());
+    putDirectOffset(globalData, offset, value);
 }
 
-inline void JSObject::putDirectWithoutTransition(const Identifier& propertyName, JSValue value, unsigned attributes)
+inline void JSObject::transitionTo(JSGlobalData& globalData, Structure* newStructure)
 {
-    size_t currentCapacity = m_structure->propertyStorageCapacity();
-    size_t offset = m_structure->addPropertyWithoutTransition(propertyName, attributes, 0);
-    if (currentCapacity != m_structure->propertyStorageCapacity())
-        allocatePropertyStorage(currentCapacity, m_structure->propertyStorageCapacity());
-    putDirectOffset(offset, value);
-}
-
-inline void JSObject::putDirectFunctionWithoutTransition(const Identifier& propertyName, JSCell* value, unsigned attributes)
-{
-    size_t currentCapacity = m_structure->propertyStorageCapacity();
-    size_t offset = m_structure->addPropertyWithoutTransition(propertyName, attributes, value);
-    if (currentCapacity != m_structure->propertyStorageCapacity())
-        allocatePropertyStorage(currentCapacity, m_structure->propertyStorageCapacity());
-    putDirectOffset(offset, value);
-}
-
-inline void JSObject::transitionTo(Structure* newStructure)
-{
-    if (m_structure->propertyStorageCapacity() != newStructure->propertyStorageCapacity())
-        allocatePropertyStorage(m_structure->propertyStorageCapacity(), newStructure->propertyStorageCapacity());
-    setStructure(newStructure);
+    PropertyStorage newStorage = propertyStorage();
+    if (structure()->propertyStorageCapacity() != newStructure->propertyStorageCapacity())
+        newStorage = growPropertyStorage(globalData, structure()->propertyStorageCapacity(), newStructure->propertyStorageCapacity());
+    setPropertyStorage(globalData, newStorage, newStructure);
 }
 
 inline JSValue JSObject::toPrimitive(ExecState* exec, PreferredPrimitiveType preferredType) const
 {
-    return defaultValue(exec, preferredType);
+    return methodTable()->defaultValue(this, exec, preferredType);
 }
 
 inline JSValue JSValue::get(ExecState* exec, const Identifier& propertyName) const
@@ -561,8 +810,6 @@ inline JSValue JSValue::get(ExecState* exec, const Identifier& propertyName, Pro
 {
     if (UNLIKELY(!isCell())) {
         JSObject* prototype = synthesizePrototype(exec);
-        if (propertyName == exec->propertyNames().underscoreProto)
-            return prototype;
         if (!prototype->getPropertySlot(exec, propertyName, slot))
             return jsUndefined();
         return slot.getValue(exec, propertyName);
@@ -571,8 +818,7 @@ inline JSValue JSValue::get(ExecState* exec, const Identifier& propertyName, Pro
     while (true) {
         if (cell->fastGetOwnPropertySlot(exec, propertyName, slot))
             return slot.getValue(exec, propertyName);
-        ASSERT(cell->isObject());
-        JSValue prototype = static_cast<JSObject*>(cell)->prototype();
+        JSValue prototype = asObject(cell)->prototype();
         if (!prototype.isObject())
             return jsUndefined();
         cell = asObject(prototype);
@@ -595,10 +841,9 @@ inline JSValue JSValue::get(ExecState* exec, unsigned propertyName, PropertySlot
     }
     JSCell* cell = const_cast<JSCell*>(asCell());
     while (true) {
-        if (cell->getOwnPropertySlot(exec, propertyName, slot))
+        if (cell->methodTable()->getOwnPropertySlotByIndex(cell, exec, propertyName, slot))
             return slot.getValue(exec, propertyName);
-        ASSERT(cell->isObject());
-        JSValue prototype = static_cast<JSObject*>(cell)->prototype();
+        JSValue prototype = asObject(cell)->prototype();
         if (!prototype.isObject())
             return jsUndefined();
         cell = prototype.asCell();
@@ -608,39 +853,36 @@ inline JSValue JSValue::get(ExecState* exec, unsigned propertyName, PropertySlot
 inline void JSValue::put(ExecState* exec, const Identifier& propertyName, JSValue value, PutPropertySlot& slot)
 {
     if (UNLIKELY(!isCell())) {
-        synthesizeObject(exec)->put(exec, propertyName, value, slot);
+        putToPrimitive(exec, propertyName, value, slot);
         return;
     }
-    asCell()->put(exec, propertyName, value, slot);
+    asCell()->methodTable()->put(asCell(), exec, propertyName, value, slot);
 }
 
-inline void JSValue::put(ExecState* exec, unsigned propertyName, JSValue value)
+inline void JSValue::putByIndex(ExecState* exec, unsigned propertyName, JSValue value, bool shouldThrow)
 {
     if (UNLIKELY(!isCell())) {
-        synthesizeObject(exec)->put(exec, propertyName, value);
+        PutPropertySlot slot(shouldThrow);
+        putToPrimitive(exec, Identifier::from(exec, propertyName), value, slot);
         return;
     }
-    asCell()->put(exec, propertyName, value);
+    asCell()->methodTable()->putByIndex(asCell(), exec, propertyName, value, shouldThrow);
 }
 
-ALWAYS_INLINE void JSObject::allocatePropertyStorageInline(size_t oldSize, size_t newSize)
-{
-    ASSERT(newSize > oldSize);
-
-    // It's important that this function not rely on m_structure, since
-    // we might be in the middle of a transition.
-    bool wasInline = (oldSize == JSObject::inlineStorageCapacity);
-
-    PropertyStorage oldPropertyStorage = (wasInline ? m_inlineStorage : m_externalStorage);
-    PropertyStorage newPropertyStorage = new EncodedJSValue[newSize];
+// --- JSValue inlines ----------------------------
 
-    for (unsigned i = 0; i < oldSize; ++i)
-       newPropertyStorage[i] = oldPropertyStorage[i];
-
-    if (!wasInline)
-        delete [] oldPropertyStorage;
+ALWAYS_INLINE JSObject* Register::function() const
+{
+    if (!jsValue())
+        return 0;
+    return asObject(jsValue());
+}
 
-    m_externalStorage = newPropertyStorage;
+ALWAYS_INLINE Register Register::withCallee(JSObject* callee)
+{
+    Register r;
+    r = JSValue(callee);
+    return r;
 }
 
 } // namespace JSC