Bug 55736 - Implement seal/freeze/preventExtensions for normal object types.
[WebKit-https.git] / Source / JavaScriptCore / runtime / JSObject.h
index 803abfd..2b4db43 100644 (file)
@@ -70,8 +70,8 @@ namespace JSC {
         Setter       = 1 << 6   // property is a setter
     };
 
-    typedef EncodedJSValue* PropertyStorage;
-    typedef const EncodedJSValue* ConstPropertyStorage;
+    typedef WriteBarrierBase<Unknown>* PropertyStorage;
+    typedef const WriteBarrierBase<Unknown>* ConstPropertyStorage;
 
     class JSObject : public JSCell {
         friend class BatchedTransitionOptimizer;
@@ -80,8 +80,6 @@ namespace JSC {
         friend void setUpStaticFunctionSlot(ExecState* exec, const HashEntry* entry, JSObject* thisObj, const Identifier& propertyName, PropertySlot& slot);
 
     public:
-        explicit JSObject(NonNullPassRefPtr<Structure>);
-
         virtual void markChildren(MarkStack&);
         ALWAYS_INLINE void markChildrenDirect(MarkStack& markStack);
 
@@ -155,22 +153,22 @@ namespace JSC {
             return offset != WTF::notFound ? getDirectOffset(offset) : JSValue();
         }
 
-        JSValue* getDirectLocation(const Identifier& propertyName)
+        WriteBarrierBase<Unknown>* getDirectLocation(const Identifier& propertyName)
         {
             size_t offset = m_structure->get(propertyName);
             return offset != WTF::notFound ? locationForOffset(offset) : 0;
         }
 
-        JSValue* getDirectLocation(const Identifier& propertyName, unsigned& attributes)
+        WriteBarrierBase<Unknown>* getDirectLocation(const Identifier& propertyName, unsigned& attributes)
         {
             JSCell* specificFunction;
             size_t offset = m_structure->get(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*);
@@ -179,25 +177,26 @@ namespace JSC {
         bool hasCustomProperties() { return !m_structure->isEmpty(); }
         bool hasGetterSetterProperties() { return m_structure->hasGetterSetterProperties(); }
 
-        bool putDirect(const Identifier& propertyName, JSValue value, unsigned attr, bool checkReadOnly, PutPropertySlot& slot);
-        void putDirect(const Identifier& propertyName, JSValue value, unsigned attr = 0);
-        bool putDirect(const Identifier& propertyName, JSValue value, PutPropertySlot&);
+        bool putDirect(JSGlobalData&, const Identifier& propertyName, JSValue, unsigned attr, bool checkReadOnly, PutPropertySlot&);
+        void putDirect(JSGlobalData&, const Identifier& propertyName, JSValue, unsigned attr = 0);
+        bool putDirect(JSGlobalData&, const Identifier& propertyName, JSValue, PutPropertySlot&);
 
-        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(JSGlobalData&, const Identifier& propertyName, JSCell*, unsigned attr = 0);
+        void putDirectFunction(JSGlobalData&, const Identifier& propertyName, JSCell*, unsigned attr, bool checkReadOnly, PutPropertySlot&);
         void putDirectFunction(ExecState* exec, InternalFunction* function, unsigned attr = 0);
         void putDirectFunction(ExecState* exec, JSFunction* function, unsigned attr = 0);
 
-        void putDirectWithoutTransition(const Identifier& propertyName, JSValue value, unsigned attr = 0);
-        void putDirectFunctionWithoutTransition(const Identifier& propertyName, JSCell* value, unsigned attr = 0);
+        void putDirectWithoutTransition(JSGlobalData&, const Identifier& propertyName, JSValue, unsigned attr = 0);
+        void putDirectFunctionWithoutTransition(JSGlobalData&, const Identifier& propertyName, JSCell* value, unsigned attr = 0);
         void putDirectFunctionWithoutTransition(ExecState* exec, InternalFunction* function, unsigned attr = 0);
         void putDirectFunctionWithoutTransition(ExecState* exec, JSFunction* function, unsigned attr = 0);
 
         // 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(); }
 
-        void fillGetterPropertySlot(PropertySlot&, JSValue* location);
+        void fillGetterPropertySlot(PropertySlot&, WriteBarrierBase<Unknown>* location);
 
         virtual void defineGetter(ExecState*, const Identifier& propertyName, JSObject* getterFunction, unsigned attributes = 0);
         virtual void defineSetter(ExecState*, const Identifier& propertyName, JSObject* setterFunction, unsigned attributes = 0);
@@ -211,39 +210,62 @@ namespace JSC {
         virtual bool isStrictModeFunction() const { return false; }
         virtual bool isErrorInstance() const { return false; }
 
+        void seal();
+        void freeze();
+        void preventExtensions();
+        bool isSealed() { return m_structure->isSealed(); }
+        bool isFrozen() { return m_structure->isFrozen(); }
+        bool isExtensible() { return m_structure->isExtensible(); }
+
         virtual ComplType exceptionType() const { return Throw; }
 
         void allocatePropertyStorage(size_t oldSize, size_t newSize);
-        void allocatePropertyStorageInline(size_t oldSize, size_t newSize);
         bool isUsingInlineStorage() const { return m_structure->isUsingInlineStorage(); }
 
-        static const unsigned inlineStorageCapacity = sizeof(EncodedJSValue) == 2 * sizeof(void*) ? 4 : 3;
-        static const unsigned nonInlineBaseStorageCapacity = 16;
+        static const unsigned baseExternalStorageCapacity = 16;
 
-        static PassRefPtr<Structure> createStructure(JSValue prototype)
+        void flattenDictionaryObject(JSGlobalData& globalData)
         {
-            return Structure::create(prototype, TypeInfo(ObjectType, StructureFlags), AnonymousSlotCount);
+            m_structure->flattenDictionaryStructure(globalData, this);
         }
 
-        void flattenDictionaryObject()
+        void putAnonymousValue(JSGlobalData& globalData, unsigned index, JSValue value)
         {
-            m_structure->flattenDictionaryStructure(this);
+            ASSERT(index < m_structure->anonymousSlotCount());
+            locationForOffset(index)->set(globalData, this, value);
         }
-
-        void putAnonymousValue(unsigned index, JSValue value)
+        void clearAnonymousValue(unsigned index)
         {
             ASSERT(index < m_structure->anonymousSlotCount());
-            *locationForOffset(index) = value;
+            locationForOffset(index)->clear();
         }
         JSValue getAnonymousValue(unsigned index) const
         {
             ASSERT(index < m_structure->anonymousSlotCount());
-            return *locationForOffset(index);
+            return locationForOffset(index)->get();
         }
+
+        static size_t offsetOfInlineStorage();
         
+        static JS_EXPORTDATA const ClassInfo s_info;
+
     protected:
+        static PassRefPtr<Structure> createStructure(JSValue prototype)
+        {
+            return Structure::create(prototype, TypeInfo(ObjectType, StructureFlags), AnonymousSlotCount, &s_info);
+        }
+
         static const unsigned StructureFlags = 0;
-        
+
+        void putThisToAnonymousValue(unsigned index)
+        {
+            locationForOffset(index)->setWithoutWriteBarrier(this);
+        }
+
+        // To instantiate objects you likely want JSFinalObject, below.
+        // To create derived types you likely want JSNonFinalObject, below.
+        JSObject(NonNullPassRefPtr<Structure>, PropertyStorage inlineStorage);
+
     private:
         // Nobody should ever ask any of these questions on something already known to be a JSObject.
         using JSCell::isAPIValueWrapper;
@@ -253,22 +275,22 @@ namespace JSC {
         void getString(ExecState* exec);
         void isObject();
         void isString();
+        
+        ConstPropertyStorage propertyStorage() const { return m_propertyStorage; }
+        PropertyStorage propertyStorage() { return m_propertyStorage; }
 
-        ConstPropertyStorage propertyStorage() const { return (isUsingInlineStorage() ? m_inlineStorage : m_externalStorage); }
-        PropertyStorage propertyStorage() { return (isUsingInlineStorage() ? m_inlineStorage : m_externalStorage); }
-
-        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];
         }
 
-        bool putDirectInternal(const Identifier& propertyName, JSValue value, unsigned attr, bool checkReadOnly, PutPropertySlot& slot, JSCell*);
-        bool putDirectInternal(JSGlobalData&, const Identifier& propertyName, JSValue value, unsigned attr, bool checkReadOnly, PutPropertySlot& slot);
+        bool putDirectInternal(JSGlobalData&, const Identifier& propertyName, JSValue, unsigned attr, bool checkReadOnly, PutPropertySlot&, JSCell*);
+        bool putDirectInternal(JSGlobalData&, const Identifier& propertyName, JSValue, unsigned attr, bool checkReadOnly, PutPropertySlot&);
         void putDirectInternal(JSGlobalData&, const Identifier& propertyName, JSValue value, unsigned attr = 0);
 
         bool inlineGetOwnPropertySlot(ExecState*, const Identifier& propertyName, PropertySlot&);
@@ -276,14 +298,90 @@ namespace JSC {
         const HashEntry* findPropertyHashEntry(ExecState*, const Identifier& propertyName) const;
         Structure* createInheritorID();
 
-        union {
-            PropertyStorage m_externalStorage;
-            EncodedJSValue m_inlineStorage[inlineStorageCapacity];
-        };
-
+        PropertyStorage m_propertyStorage;
         RefPtr<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);
+
+    // 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:
+        static PassRefPtr<Structure> createStructure(JSValue prototype)
+        {
+            return Structure::create(prototype, TypeInfo(ObjectType, StructureFlags), AnonymousSlotCount, &s_info);
+        }
+
+    protected:
+        explicit JSNonFinalObject(NonNullPassRefPtr<Structure> structure)
+            : JSObject(structure, m_inlineStorage)
+        {
+            ASSERT(!(OBJECT_OFFSETOF(JSNonFinalObject, m_inlineStorage) % sizeof(double)));
+            ASSERT(this->structure()->propertyStorageCapacity() == JSNonFinalObject_inlineStorageCapacity);
+        }
+
+    private:
+        WriteBarrierBase<Unknown> m_inlineStorage[JSNonFinalObject_inlineStorageCapacity];
+    };
+
+    // 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:
+        static JSFinalObject* create(ExecState* exec, NonNullPassRefPtr<Structure> structure)
+        {
+            return new (exec) JSFinalObject(structure);
+        }
+
+        static PassRefPtr<Structure> createStructure(JSValue prototype)
+        {
+            return Structure::create(prototype, TypeInfo(ObjectType, StructureFlags), AnonymousSlotCount, &s_info);
+        }
+
+    private:
+        explicit JSFinalObject(NonNullPassRefPtr<Structure> structure)
+            : JSObject(structure, m_inlineStorage)
+        {
+            ASSERT(OBJECT_OFFSETOF(JSFinalObject, m_inlineStorage) % sizeof(double) == 0);
+            ASSERT(this->structure()->propertyStorageCapacity() == JSFinalObject_inlineStorageCapacity);
+        }
+
+        static const unsigned StructureFlags = JSObject::StructureFlags | IsJSFinalObject;
+
+        WriteBarrierBase<Unknown> m_inlineStorage[JSFinalObject_inlineStorageCapacity];
+    };
+
+inline size_t JSObject::offsetOfInlineStorage()
+{
+    ASSERT(OBJECT_OFFSETOF(JSFinalObject, m_inlineStorage) == OBJECT_OFFSETOF(JSNonFinalObject, m_inlineStorage));
+    return OBJECT_OFFSETOF(JSFinalObject, m_inlineStorage);
+}
+
+inline JSObject* constructEmptyObject(ExecState* exec, NonNullPassRefPtr<Structure> structure)
+{
+    return JSFinalObject::create(exec, structure);
+}
+
+inline PassRefPtr<Structure> createEmptyObjectStructure(JSValue prototype)
+{
+    return JSFinalObject::createStructure(prototype);
+}
+
 inline JSObject* asObject(JSCell* cell)
 {
     ASSERT(cell->isObject());
@@ -295,20 +393,21 @@ inline JSObject* asObject(JSValue value)
     return asObject(value.asCell());
 }
 
-inline JSObject::JSObject(NonNullPassRefPtr<Structure> structure)
+inline JSObject::JSObject(NonNullPassRefPtr<Structure> structure, PropertyStorage inlineStorage)
     : JSCell(structure.releaseRef()) // ~JSObject balances this ref()
+    , m_propertyStorage(inlineStorage)
 {
-    ASSERT(m_structure->propertyStorageCapacity() == inlineStorageCapacity);
+    ASSERT(inherits(&s_info));
+    ASSERT(m_structure->propertyStorageCapacity() < baseExternalStorageCapacity);
     ASSERT(m_structure->isEmpty());
     ASSERT(prototype().isNull() || Heap::heap(this) == Heap::heap(prototype()));
-    ASSERT(OBJECT_OFFSETOF(JSObject, m_inlineStorage) % sizeof(double) == 0);
 }
 
 inline JSObject::~JSObject()
 {
     ASSERT(m_structure);
     if (!isUsingInlineStorage())
-        delete [] m_externalStorage;
+        delete [] m_propertyStorage;
     m_structure->deref();
 }
 
@@ -352,7 +451,7 @@ inline Structure* JSObject::inheritorID()
 
 inline bool Structure::isUsingInlineStorage() const
 {
-    return (propertyStorageCapacity() == JSObject::inlineStorageCapacity);
+    return propertyStorageCapacity() < JSObject::baseExternalStorageCapacity;
 }
 
 inline bool JSCell::inherits(const ClassInfo* info) const
@@ -372,11 +471,11 @@ inline bool JSValue::inherits(const ClassInfo* classInfo) const
 
 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(propertyName)) {
+        if (m_structure->hasGetterSetterProperties() && location->isGetterSetter())
             fillGetterPropertySlot(slot, location);
         else
-            slot.setValueSlot(this, location, offsetForLocation(location));
+            slot.setValue(this, location->get(), offsetForLocation(location));
         return true;
     }
 
@@ -450,7 +549,7 @@ inline JSValue JSObject::get(ExecState* exec, unsigned propertyName) const
     return jsUndefined();
 }
 
-inline bool JSObject::putDirectInternal(const Identifier& propertyName, JSValue value, unsigned attributes, bool checkReadOnly, PutPropertySlot& slot, JSCell* specificFunction)
+inline bool JSObject::putDirectInternal(JSGlobalData& globalData, const Identifier& propertyName, JSValue value, unsigned attributes, bool checkReadOnly, PutPropertySlot& slot, JSCell* specificFunction)
 {
     ASSERT(value);
     ASSERT(!Heap::heap(value) || Heap::heap(value) == Heap::heap(this));
@@ -467,7 +566,7 @@ inline bool JSObject::putDirectInternal(const Identifier& propertyName, JSValue
             if (checkReadOnly && currentAttributes & ReadOnly)
                 return false;
 
-            putDirectOffset(offset, value);
+            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
@@ -479,13 +578,16 @@ inline bool JSObject::putDirectInternal(const Identifier& propertyName, JSValue
             return true;
         }
 
+        if (!isExtensible())
+            return false;
+
         size_t currentCapacity = m_structure->propertyStorageCapacity();
         offset = m_structure->addPropertyWithoutTransition(propertyName, attributes, specificFunction);
         if (currentCapacity != m_structure->propertyStorageCapacity())
             allocatePropertyStorage(currentCapacity, m_structure->propertyStorageCapacity());
 
         ASSERT(offset < m_structure->propertyStorageCapacity());
-        putDirectOffset(offset, value);
+        putDirectOffset(globalData, offset, value);
         // See comment on setNewProperty call below.
         if (!specificFunction)
             slot.setNewProperty(this, offset);
@@ -500,7 +602,7 @@ inline bool JSObject::putDirectInternal(const Identifier& propertyName, JSValue
 
         ASSERT(offset < structure->propertyStorageCapacity());
         setStructure(structure.release());
-        putDirectOffset(offset, value);
+        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)
@@ -527,7 +629,7 @@ inline bool JSObject::putDirectInternal(const Identifier& propertyName, JSValue
         if (currentSpecificFunction) {
             // case (1) Do the put, then return leaving the slot uncachable.
             if (specificFunction == currentSpecificFunction) {
-                putDirectOffset(offset, value);
+                putDirectOffset(globalData, offset, value);
                 return true;
             }
             // case (2) Despecify, fall through to (3).
@@ -536,19 +638,12 @@ inline bool JSObject::putDirectInternal(const Identifier& propertyName, JSValue
 
         // case (3) set the slot, do the put, return.
         slot.setExistingProperty(this, offset);
-        putDirectOffset(offset, value);
+        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 (!isExtensible())
+        return false;
 
     RefPtr<Structure> structure = Structure::addPropertyTransition(m_structure, propertyName, attributes, specificFunction, offset);
 
@@ -557,7 +652,7 @@ inline bool JSObject::putDirectInternal(const Identifier& propertyName, JSValue
 
     ASSERT(offset < structure->propertyStorageCapacity());
     setStructure(structure.release());
-    putDirectOffset(offset, value);
+    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)
@@ -570,61 +665,61 @@ inline bool JSObject::putDirectInternal(JSGlobalData& globalData, const Identifi
     ASSERT(value);
     ASSERT(!Heap::heap(value) || Heap::heap(value) == Heap::heap(this));
 
-    return putDirectInternal(propertyName, value, attributes, checkReadOnly, slot, getJSFunction(globalData, value));
+    return putDirectInternal(globalData, 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));
+    putDirectInternal(globalData, propertyName, value, attributes, false, slot, getJSFunction(globalData, value));
 }
 
-inline bool JSObject::putDirect(const Identifier& propertyName, JSValue value, unsigned attributes, bool checkReadOnly, PutPropertySlot& slot)
+inline bool JSObject::putDirect(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));
 
-    return putDirectInternal(propertyName, value, attributes, checkReadOnly, slot, 0);
+    return putDirectInternal(globalData, propertyName, value, attributes, checkReadOnly, slot, 0);
 }
 
-inline void JSObject::putDirect(const Identifier& propertyName, JSValue value, unsigned attributes)
+inline void JSObject::putDirect(JSGlobalData& globalData, const Identifier& propertyName, JSValue value, unsigned attributes)
 {
     PutPropertySlot slot;
-    putDirectInternal(propertyName, value, attributes, false, slot, 0);
+    putDirectInternal(globalData, propertyName, value, attributes, false, slot, 0);
 }
 
-inline bool JSObject::putDirect(const Identifier& propertyName, JSValue value, PutPropertySlot& slot)
+inline bool JSObject::putDirect(JSGlobalData& globalData, const Identifier& propertyName, JSValue value, PutPropertySlot& slot)
 {
-    return putDirectInternal(propertyName, value, 0, false, slot, 0);
+    return putDirectInternal(globalData, propertyName, value, 0, false, slot, 0);
 }
 
-inline void JSObject::putDirectFunction(const Identifier& propertyName, JSCell* value, unsigned attributes, bool checkReadOnly, PutPropertySlot& slot)
+inline void JSObject::putDirectFunction(JSGlobalData& globalData, const Identifier& propertyName, JSCell* value, unsigned attributes, bool checkReadOnly, PutPropertySlot& slot)
 {
-    putDirectInternal(propertyName, value, attributes, checkReadOnly, slot, value);
+    putDirectInternal(globalData, propertyName, value, attributes, checkReadOnly, slot, value);
 }
 
-inline void JSObject::putDirectFunction(const Identifier& propertyName, JSCell* value, unsigned attr)
+inline void JSObject::putDirectFunction(JSGlobalData& globalData, const Identifier& propertyName, JSCell* value, unsigned attr)
 {
     PutPropertySlot slot;
-    putDirectInternal(propertyName, value, attr, false, slot, value);
+    putDirectInternal(globalData, propertyName, value, attr, false, slot, value);
 }
 
-inline void JSObject::putDirectWithoutTransition(const Identifier& propertyName, JSValue value, unsigned attributes)
+inline void JSObject::putDirectWithoutTransition(JSGlobalData& globalData, const Identifier& propertyName, JSValue value, unsigned attributes)
 {
     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);
+    putDirectOffset(globalData, offset, value);
 }
 
-inline void JSObject::putDirectFunctionWithoutTransition(const Identifier& propertyName, JSCell* value, unsigned attributes)
+inline void JSObject::putDirectFunctionWithoutTransition(JSGlobalData& globalData, 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);
+    putDirectOffset(globalData, offset, value);
 }
 
 inline void JSObject::transitionTo(Structure* newStructure)
@@ -703,7 +798,7 @@ inline void JSValue::put(ExecState* exec, const Identifier& propertyName, JSValu
 inline void JSValue::putDirect(ExecState* exec, const Identifier& propertyName, JSValue value, PutPropertySlot& slot)
 {
     ASSERT(isCell() && isObject());
-    if (!asObject(asCell())->putDirect(propertyName, value, slot) && slot.isStrictMode())
+    if (!asObject(asCell())->putDirect(exec->globalData(), propertyName, value, slot) && slot.isStrictMode())
         throwTypeError(exec, StrictModeReadonlyPropertyWriteError);
 }
 
@@ -716,35 +811,14 @@ inline void JSValue::put(ExecState* exec, unsigned propertyName, JSValue value)
     asCell()->put(exec, propertyName, value);
 }
 
-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];
-
-    for (unsigned i = 0; i < oldSize; ++i)
-       newPropertyStorage[i] = oldPropertyStorage[i];
-
-    if (!wasInline)
-        delete [] oldPropertyStorage;
-
-    m_externalStorage = newPropertyStorage;
-}
-
 ALWAYS_INLINE void JSObject::markChildrenDirect(MarkStack& markStack)
 {
     JSCell::markChildren(markStack);
 
-    markStack.append(prototype());
-    
+    markStack.append(m_structure->storedPrototypeSlot());
     PropertyStorage storage = propertyStorage();
     size_t storageSize = m_structure->propertyStorageSize();
-    markStack.appendValues(reinterpret_cast<JSValue*>(storage), storageSize);
+    markStack.appendValues(storage, storageSize);
 }
 
 // --- JSValue inlines ----------------------------