summaryrefslogtreecommitdiff
path: root/Source/JavaScriptCore/runtime/JSObject.h
diff options
context:
space:
mode:
Diffstat (limited to 'Source/JavaScriptCore/runtime/JSObject.h')
-rw-r--r--Source/JavaScriptCore/runtime/JSObject.h398
1 files changed, 341 insertions, 57 deletions
diff --git a/Source/JavaScriptCore/runtime/JSObject.h b/Source/JavaScriptCore/runtime/JSObject.h
index 5e2c12f2f..8df521b75 100644
--- a/Source/JavaScriptCore/runtime/JSObject.h
+++ b/Source/JavaScriptCore/runtime/JSObject.h
@@ -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, 2009 Apple Inc. All rights reserved.
+ * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2012 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
@@ -24,17 +24,22 @@
#define JSObject_h
#include "ArgList.h"
+#include "ArrayConventions.h"
+#include "ArrayStorage.h"
+#include "Butterfly.h"
#include "ClassInfo.h"
#include "CommonIdentifiers.h"
#include "CallFrame.h"
#include "JSCell.h"
#include "PropertySlot.h"
+#include "PropertyStorage.h"
+#include "PutDirectIndexMode.h"
#include "PutPropertySlot.h"
-#include "StorageBarrier.h"
#include "Structure.h"
#include "JSGlobalData.h"
#include "JSString.h"
+#include "SparseArrayValueMap.h"
#include <wtf/StdLibExtras.h>
namespace JSC {
@@ -79,6 +84,13 @@ namespace JSC {
Accessor = 1 << 5, // property is a getter/setter
};
+ COMPILE_ASSERT(None < FirstInternalAttribute, None_is_below_FirstInternalAttribute);
+ COMPILE_ASSERT(ReadOnly < FirstInternalAttribute, ReadOnly_is_below_FirstInternalAttribute);
+ COMPILE_ASSERT(DontEnum < FirstInternalAttribute, DontEnum_is_below_FirstInternalAttribute);
+ COMPILE_ASSERT(DontDelete < FirstInternalAttribute, DontDelete_is_below_FirstInternalAttribute);
+ COMPILE_ASSERT(Function < FirstInternalAttribute, Function_is_below_FirstInternalAttribute);
+ COMPILE_ASSERT(Accessor < FirstInternalAttribute, Accessor_is_below_FirstInternalAttribute);
+
class JSFinalObject;
class JSObject : public JSCell {
@@ -96,7 +108,7 @@ namespace JSC {
public:
typedef JSCell Base;
-
+
JS_EXPORT_PRIVATE static void visitChildren(JSCell*, SlotVisitor&);
JS_EXPORT_PRIVATE static String className(const JSObject*);
@@ -120,18 +132,196 @@ namespace JSC {
bool allowsAccessFrom(ExecState*);
+ unsigned getArrayLength() const
+ {
+ switch (structure()->indexingType()) {
+ case NonArray:
+ case ArrayClass:
+ return 0;
+ case NonArrayWithArrayStorage:
+ case ArrayWithArrayStorage:
+ return m_butterfly->arrayStorage()->length();
+ default:
+ ASSERT_NOT_REACHED();
+ return 0;
+ }
+ }
+
+ unsigned getVectorLength()
+ {
+ switch (structure()->indexingType()) {
+ case NonArray:
+ case ArrayClass:
+ return 0;
+ case NonArrayWithArrayStorage:
+ case ArrayWithArrayStorage:
+ return m_butterfly->arrayStorage()->vectorLength();
+ default:
+ ASSERT_NOT_REACHED();
+ return 0;
+ }
+ }
+
JS_EXPORT_PRIVATE static void put(JSCell*, ExecState*, PropertyName, JSValue, PutPropertySlot&);
JS_EXPORT_PRIVATE static void putByIndex(JSCell*, ExecState*, unsigned propertyName, JSValue, bool shouldThrow);
+
+ // This is similar to the putDirect* methods:
+ // - the prototype chain is not consulted
+ // - accessors are not called.
+ // - it will ignore extensibility and read-only properties if PutDirectIndexLikePutDirect is passed as the mode (the default).
+ // This method creates a property with attributes writable, enumerable and configurable all set to true.
+ bool putDirectIndex(ExecState* exec, unsigned propertyName, JSValue value, unsigned attributes, PutDirectIndexMode mode)
+ {
+ if (!attributes && canSetIndexQuickly(propertyName)) {
+ setIndexQuickly(exec->globalData(), propertyName, value);
+ return true;
+ }
+ return putDirectIndexBeyondVectorLength(exec, propertyName, value, attributes, mode);
+ }
+ bool putDirectIndex(ExecState* exec, unsigned propertyName, JSValue value)
+ {
+ return putDirectIndex(exec, propertyName, value, 0, PutDirectIndexLikePutDirect);
+ }
+
+ // A non-throwing version of putDirect and putDirectIndex.
+ void putDirectMayBeIndex(ExecState*, PropertyName, JSValue);
+
+ bool canGetIndexQuickly(unsigned i)
+ {
+ switch (structure()->indexingType()) {
+ case NonArray:
+ case ArrayClass:
+ return false;
+ case NonArrayWithArrayStorage:
+ case ArrayWithArrayStorage:
+ return i < m_butterfly->arrayStorage()->vectorLength() && m_butterfly->arrayStorage()->m_vector[i];
+ default:
+ ASSERT_NOT_REACHED();
+ return false;
+ }
+ }
+
+ JSValue getIndexQuickly(unsigned i)
+ {
+ switch (structure()->indexingType()) {
+ case NonArrayWithArrayStorage:
+ case ArrayWithArrayStorage:
+ return m_butterfly->arrayStorage()->m_vector[i].get();
+ default:
+ ASSERT_NOT_REACHED();
+ return JSValue();
+ }
+ }
+
+ bool canSetIndexQuickly(unsigned i)
+ {
+ switch (structure()->indexingType()) {
+ case NonArray:
+ case ArrayClass:
+ return false;
+ case NonArrayWithArrayStorage:
+ case ArrayWithArrayStorage:
+ return i < m_butterfly->arrayStorage()->vectorLength();
+ default:
+ ASSERT_NOT_REACHED();
+ return false;
+ }
+ }
+
+ void setIndexQuickly(JSGlobalData& globalData, unsigned i, JSValue v)
+ {
+ switch (structure()->indexingType()) {
+ case NonArrayWithArrayStorage:
+ case ArrayWithArrayStorage: {
+ WriteBarrier<Unknown>& x = m_butterfly->arrayStorage()->m_vector[i];
+ if (!x) {
+ ArrayStorage* storage = m_butterfly->arrayStorage();
+ ++storage->m_numValuesInVector;
+ if (i >= storage->length())
+ storage->setLength(i + 1);
+ }
+ x.set(globalData, this, v);
+ break;
+ }
+ default:
+ ASSERT_NOT_REACHED();
+ }
+ }
+
+ void initializeIndex(JSGlobalData& globalData, unsigned i, JSValue v)
+ {
+ switch (structure()->indexingType()) {
+ case NonArrayWithArrayStorage:
+ case ArrayWithArrayStorage: {
+ ArrayStorage* storage = m_butterfly->arrayStorage();
+#if CHECK_ARRAY_CONSISTENCY
+ ASSERT(storage->m_inCompactInitialization);
+ // Check that we are initializing the next index in sequence.
+ ASSERT(i == storage->m_initializationIndex);
+ // tryCreateUninitialized set m_numValuesInVector to the initialLength,
+ // check we do not try to initialize more than this number of properties.
+ ASSERT(storage->m_initializationIndex < storage->m_numValuesInVector);
+ storage->m_initializationIndex++;
+#endif
+ ASSERT(i < storage->length());
+ ASSERT(i < storage->m_numValuesInVector);
+ storage->m_vector[i].set(globalData, this, v);
+ break;
+ }
+ default:
+ ASSERT_NOT_REACHED();
+ }
+ }
+
+ void completeInitialization(unsigned newLength)
+ {
+ switch (structure()->indexingType()) {
+ case NonArrayWithArrayStorage:
+ case ArrayWithArrayStorage: {
+ ArrayStorage* storage = m_butterfly->arrayStorage();
+ // Check that we have initialized as meny properties as we think we have.
+ UNUSED_PARAM(storage);
+ ASSERT_UNUSED(newLength, newLength == storage->length());
+#if CHECK_ARRAY_CONSISTENCY
+ // Check that the number of propreties initialized matches the initialLength.
+ ASSERT(storage->m_initializationIndex == m_storage->m_numValuesInVector);
+ ASSERT(storage->m_inCompactInitialization);
+ storage->m_inCompactInitialization = false;
+#endif
+ break;
+ }
+ default:
+ ASSERT_NOT_REACHED();
+ }
+ }
+
+ bool inSparseIndexingMode()
+ {
+ switch (structure()->indexingType()) {
+ case NonArray:
+ case ArrayClass:
+ return false;
+ case NonArrayWithArrayStorage:
+ case ArrayWithArrayStorage:
+ return m_butterfly->arrayStorage()->inSparseMode();
+ default:
+ ASSERT_NOT_REACHED();
+ return false;
+ }
+ }
+
+ void enterDictionaryIndexingMode(JSGlobalData&);
// 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)
+ // - the property name is assumed to not be an index.
JS_EXPORT_PRIVATE static void putDirectVirtual(JSObject*, ExecState*, PropertyName, JSValue, unsigned attributes);
void putDirect(JSGlobalData&, PropertyName, JSValue, unsigned attributes = 0);
void putDirect(JSGlobalData&, PropertyName, JSValue, PutPropertySlot&);
void putDirectWithoutTransition(JSGlobalData&, PropertyName, JSValue, unsigned attributes = 0);
- void putDirectAccessor(JSGlobalData&, PropertyName, JSValue, unsigned attributes);
+ void putDirectAccessor(ExecState*, PropertyName, JSValue, unsigned attributes);
bool propertyIsEnumerable(ExecState*, const Identifier& propertyName) const;
@@ -147,6 +337,7 @@ namespace JSC {
JS_EXPORT_PRIVATE static bool hasInstance(JSObject*, ExecState*, JSValue, JSValue prototypeProperty);
JS_EXPORT_PRIVATE static void getOwnPropertyNames(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode);
+ JS_EXPORT_PRIVATE static void getOwnNonIndexPropertyNames(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode);
JS_EXPORT_PRIVATE static void getPropertyNames(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode);
JSValue toPrimitive(ExecState*, PreferredPrimitiveType = NoPreference) const;
@@ -203,8 +394,11 @@ namespace JSC {
return inlineStorageUnsafe();
}
- ConstPropertyStorage outOfLineStorage() const { return m_outOfLineStorage.get(); }
- PropertyStorage outOfLineStorage() { return m_outOfLineStorage.get(); }
+ const Butterfly* butterfly() const { return m_butterfly; }
+ Butterfly* butterfly() { return m_butterfly; }
+
+ ConstPropertyStorage outOfLineStorage() const { return m_butterfly->propertyStorage(); }
+ PropertyStorage outOfLineStorage() { return m_butterfly->propertyStorage(); }
const WriteBarrierBase<Unknown>* locationForOffset(PropertyOffset offset) const
{
@@ -227,7 +421,7 @@ namespace JSC {
if (offsetInInlineStorage < static_cast<size_t>(inlineStorageCapacity))
result = offsetInInlineStorage;
else
- result = outOfLineStorage() - location + (inlineStorageCapacity - 2);
+ result = outOfLineStorage() - location + (inlineStorageCapacity - 1);
validateOffset(result, structure()->typeInfo().type());
return result;
}
@@ -265,21 +459,22 @@ namespace JSC {
bool isSealed(JSGlobalData& globalData) { return structure()->isSealed(globalData); }
bool isFrozen(JSGlobalData& globalData) { return structure()->isFrozen(globalData); }
bool isExtensible() { return structure()->isExtensible(); }
+ bool indexingShouldBeSparse()
+ {
+ return !isExtensible()
+ || structure()->typeInfo().interceptsGetOwnPropertySlotByIndexEvenWhenLengthIsNotZero();
+ }
bool staticFunctionsReified() { return structure()->staticFunctionsReified(); }
void reifyStaticFunctionsForDelete(ExecState* exec);
- JS_EXPORT_PRIVATE PropertyStorage growOutOfLineStorage(JSGlobalData&, size_t oldSize, size_t newSize);
- void setOutOfLineStorage(JSGlobalData&, PropertyStorage, Structure*);
+ JS_EXPORT_PRIVATE Butterfly* growOutOfLineStorage(JSGlobalData&, size_t oldSize, size_t newSize);
+ void setButterfly(JSGlobalData&, Butterfly*, Structure*);
+ void setButterflyWithoutChangingStructure(Butterfly*); // You probably don't want to call this.
void setStructureAndReallocateStorageIfNecessary(JSGlobalData&, unsigned oldCapacity, Structure*);
void setStructureAndReallocateStorageIfNecessary(JSGlobalData&, Structure*);
- void* addressOfOutOfLineStorage()
- {
- return &m_outOfLineStorage;
- }
-
void flattenDictionaryObject(JSGlobalData& globalData)
{
structure()->flattenDictionaryStructure(globalData, this);
@@ -293,7 +488,16 @@ namespace JSC {
}
static size_t offsetOfInlineStorage();
- static size_t offsetOfOutOfLineStorage();
+
+ static ptrdiff_t butterflyOffset()
+ {
+ return OBJECT_OFFSETOF(JSObject, m_butterfly);
+ }
+
+ void* butterflyAddress()
+ {
+ return &m_butterfly;
+ }
static JS_EXPORTDATA const ClassInfo s_info;
@@ -316,14 +520,78 @@ namespace JSC {
// To instantiate objects you likely want JSFinalObject, below.
// To create derived types you likely want JSNonFinalObject, below.
- JSObject(JSGlobalData&, Structure*);
+ JSObject(JSGlobalData&, Structure*, Butterfly* = 0);
void resetInheritorID(JSGlobalData& globalData)
{
removeDirect(globalData, globalData.m_inheritorIDKey);
}
- void visitOutOfLineStorage(SlotVisitor&, PropertyStorage, size_t storageSize);
+ void visitButterfly(SlotVisitor&, Butterfly*, size_t storageSize);
+
+ // Call this if you know that the object is in a mode where it has array
+ // storage. This will assert otherwise.
+ ArrayStorage* arrayStorage()
+ {
+ ASSERT(structure()->indexingType() | HasArrayStorage);
+ return m_butterfly->arrayStorage();
+ }
+
+ // Call this if you want to predicate some actions on whether or not the
+ // object is in a mode where it has array storage.
+ ArrayStorage* arrayStorageOrNull()
+ {
+ switch (structure()->indexingType()) {
+ case ArrayWithArrayStorage:
+ case NonArrayWithArrayStorage:
+ return m_butterfly->arrayStorage();
+
+ default:
+ return 0;
+ }
+ }
+
+ // Ensure that the object is in a mode where it has array storage. Use
+ // this if you're about to perform actions that would have required the
+ // object to be converted to have array storage, if it didn't have it
+ // already.
+ ArrayStorage* ensureArrayStorage(JSGlobalData& globalData)
+ {
+ switch (structure()->indexingType()) {
+ case ArrayWithArrayStorage:
+ case NonArrayWithArrayStorage:
+ return m_butterfly->arrayStorage();
+
+ case NonArray:
+ case ArrayClass:
+ return createInitialArrayStorage(globalData);
+
+ default:
+ ASSERT_NOT_REACHED();
+ return 0;
+ }
+ }
+
+ ArrayStorage* createArrayStorage(JSGlobalData&, unsigned length, unsigned vectorLength);
+ ArrayStorage* createInitialArrayStorage(JSGlobalData&);
+
+ ArrayStorage* ensureArrayStorageExistsAndEnterDictionaryIndexingMode(JSGlobalData&);
+
+ bool defineOwnNonIndexProperty(ExecState*, PropertyName, PropertyDescriptor&, bool throwException);
+
+ enum ConsistencyCheckType { NormalConsistencyCheck, DestructorConsistencyCheck, SortConsistencyCheck };
+#if !CHECK_ARRAY_CONSISTENCY
+ void checkIndexingConsistency(ConsistencyCheckType = NormalConsistencyCheck) { }
+#else
+ void checkIndexingConsistency(ConsistencyCheckType = NormalConsistencyCheck);
+#endif
+
+ void putByIndexBeyondVectorLengthWithArrayStorage(ExecState*, unsigned propertyName, JSValue, bool shouldThrow, ArrayStorage*);
+
+ bool increaseVectorLength(JSGlobalData&, unsigned newLength);
+ void deallocateSparseIndexMap();
+ bool defineOwnIndexedProperty(ExecState*, unsigned, PropertyDescriptor&, bool throwException);
+ SparseArrayValueMap* allocateSparseIndexMap(JSGlobalData&);
private:
friend class LLIntOffsetsExtractor;
@@ -336,16 +604,30 @@ namespace JSC {
void isObject();
void isString();
+ ArrayStorage* enterDictionaryIndexingModeWhenArrayStorageAlreadyExists(JSGlobalData&, ArrayStorage*);
+
template<PutMode>
bool putDirectInternal(JSGlobalData&, PropertyName, JSValue, unsigned attr, PutPropertySlot&, JSCell*);
bool inlineGetOwnPropertySlot(ExecState*, PropertyName, PropertySlot&);
- JS_EXPORT_PRIVATE void fillGetterPropertySlot(PropertySlot&, WriteBarrierBase<Unknown>* location);
+ JS_EXPORT_PRIVATE void fillGetterPropertySlot(PropertySlot&, PropertyOffset);
const HashEntry* findPropertyHashEntry(ExecState*, PropertyName) const;
Structure* createInheritorID(JSGlobalData&);
+
+ void putIndexedDescriptor(ExecState*, SparseArrayEntry*, PropertyDescriptor&, PropertyDescriptor& old);
+
+ void putByIndexBeyondVectorLength(ExecState*, unsigned propertyName, JSValue, bool shouldThrow);
+ bool putDirectIndexBeyondVectorLengthWithArrayStorage(ExecState*, unsigned propertyName, JSValue, unsigned attributes, PutDirectIndexMode, ArrayStorage*);
+ JS_EXPORT_PRIVATE bool putDirectIndexBeyondVectorLength(ExecState*, unsigned propertyName, JSValue, unsigned attributes, PutDirectIndexMode);
+
+ unsigned getNewVectorLength(unsigned currentVectorLength, unsigned currentLength, unsigned desiredLength);
+ unsigned getNewVectorLength(unsigned desiredLength);
- StorageBarrier m_outOfLineStorage;
+ JS_EXPORT_PRIVATE bool getOwnPropertySlotSlow(ExecState*, PropertyName, PropertySlot&);
+
+ protected:
+ Butterfly* m_butterfly;
};
@@ -369,8 +651,8 @@ namespace JSC {
}
protected:
- explicit JSNonFinalObject(JSGlobalData& globalData, Structure* structure)
- : JSObject(globalData, structure)
+ explicit JSNonFinalObject(JSGlobalData& globalData, Structure* structure, Butterfly* butterfly = 0)
+ : JSObject(globalData, structure, butterfly)
{
}
@@ -453,11 +735,6 @@ inline size_t JSObject::offsetOfInlineStorage()
return OBJECT_OFFSETOF(JSFinalObject, m_inlineStorage);
}
-inline size_t JSObject::offsetOfOutOfLineStorage()
-{
- return OBJECT_OFFSETOF(JSObject, m_outOfLineStorage);
-}
-
inline bool JSObject::isGlobalObject() const
{
return structure()->typeInfo().type() == GlobalObjectType;
@@ -488,18 +765,17 @@ inline bool JSObject::isGlobalThis() const
return structure()->typeInfo().type() == GlobalThisType;
}
-inline void JSObject::setOutOfLineStorage(JSGlobalData& globalData, PropertyStorage storage, Structure* structure)
+inline void JSObject::setButterfly(JSGlobalData& globalData, Butterfly* butterfly, Structure* structure)
{
ASSERT(structure);
- if (!storage) {
- ASSERT(!structure->outOfLineCapacity());
- ASSERT(!structure->outOfLineSize());
- } else {
- ASSERT(structure->outOfLineCapacity());
- ASSERT(structure->outOfLineSize());
- }
+ ASSERT(!butterfly == (!structure->outOfLineCapacity() && !hasIndexingHeader(structure->indexingType())));
setStructure(globalData, structure);
- m_outOfLineStorage.set(globalData, this, storage);
+ m_butterfly = butterfly;
+}
+
+inline void JSObject::setButterflyWithoutChangingStructure(Butterfly* butterfly)
+{
+ m_butterfly = butterfly;
}
inline JSObject* constructEmptyObject(ExecState* exec, Structure* structure)
@@ -537,9 +813,9 @@ inline JSObject* asObject(JSValue value)
return asObject(value.asCell());
}
-inline JSObject::JSObject(JSGlobalData& globalData, Structure* structure)
+inline JSObject::JSObject(JSGlobalData& globalData, Structure* structure, Butterfly* butterfly)
: JSCell(globalData, structure)
- , m_outOfLineStorage(globalData, this, 0)
+ , m_butterfly(butterfly)
{
}
@@ -587,15 +863,17 @@ inline JSObject* JSValue::toThisObject(ExecState* exec) const
ALWAYS_INLINE bool JSObject::inlineGetOwnPropertySlot(ExecState* exec, PropertyName propertyName, PropertySlot& slot)
{
- if (WriteBarrierBase<Unknown>* location = getDirectLocation(exec->globalData(), propertyName)) {
- if (structure()->hasGetterSetterProperties() && location->isGetterSetter())
- fillGetterPropertySlot(slot, location);
+ PropertyOffset offset = structure()->get(exec->globalData(), propertyName);
+ if (LIKELY(isValidOffset(offset))) {
+ JSValue value = getDirectOffset(offset);
+ if (structure()->hasGetterSetterProperties() && value.isGetterSetter())
+ fillGetterPropertySlot(slot, offset);
else
- slot.setValue(this, location->get(), offsetForLocation(location));
+ slot.setValue(this, value, offset);
return true;
}
- return false;
+ return getOwnPropertySlotSlow(exec, propertyName, slot);
}
// It may seem crazy to inline a function this large, especially a virtual function,
@@ -681,6 +959,7 @@ inline bool JSObject::putDirectInternal(JSGlobalData& globalData, PropertyName p
ASSERT(value);
ASSERT(value.isGetterSetter() == !!(attributes & Accessor));
ASSERT(!Heap::heap(value) || Heap::heap(value) == Heap::heap(this));
+ ASSERT(propertyName.asIndex() == PropertyName::NotAnIndex);
if (structure()->isDictionary()) {
unsigned currentAttributes;
@@ -709,11 +988,11 @@ inline bool JSObject::putDirectInternal(JSGlobalData& globalData, PropertyName p
if ((mode == PutModePut) && !isExtensible())
return false;
- PropertyStorage newStorage = outOfLineStorage();
+ Butterfly* newButterfly = m_butterfly;
if (structure()->putWillGrowOutOfLineStorage())
- newStorage = growOutOfLineStorage(globalData, structure()->outOfLineCapacity(), structure()->suggestedNewOutOfLineStorageCapacity());
+ newButterfly = growOutOfLineStorage(globalData, structure()->outOfLineCapacity(), structure()->suggestedNewOutOfLineStorageCapacity());
offset = structure()->addPropertyWithoutTransition(globalData, propertyName, attributes, specificFunction);
- setOutOfLineStorage(globalData, newStorage, structure());
+ setButterfly(globalData, newButterfly, structure());
validateOffset(offset);
ASSERT(structure()->isValidOffset(offset));
@@ -727,13 +1006,13 @@ inline bool JSObject::putDirectInternal(JSGlobalData& globalData, PropertyName p
PropertyOffset offset;
size_t currentCapacity = structure()->outOfLineCapacity();
if (Structure* structure = Structure::addPropertyTransitionToExistingStructure(this->structure(), propertyName, attributes, specificFunction, offset)) {
- PropertyStorage newStorage = outOfLineStorage();
+ Butterfly* newButterfly = m_butterfly;
if (currentCapacity != structure->outOfLineCapacity())
- newStorage = growOutOfLineStorage(globalData, currentCapacity, structure->outOfLineCapacity());
+ newButterfly = growOutOfLineStorage(globalData, currentCapacity, structure->outOfLineCapacity());
validateOffset(offset);
ASSERT(structure->isValidOffset(offset));
- setOutOfLineStorage(globalData, newStorage, structure);
+ setButterfly(globalData, newButterfly, 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.
@@ -800,9 +1079,9 @@ inline void JSObject::setStructureAndReallocateStorageIfNecessary(JSGlobalData&
return;
}
- PropertyStorage newStorage = growOutOfLineStorage(
+ Butterfly* newButterfly = growOutOfLineStorage(
globalData, oldCapacity, newStructure->outOfLineCapacity());
- setOutOfLineStorage(globalData, newStorage, newStructure);
+ setButterfly(globalData, newButterfly, newStructure);
}
inline void JSObject::setStructureAndReallocateStorageIfNecessary(JSGlobalData& globalData, Structure* newStructure)
@@ -836,11 +1115,11 @@ inline void JSObject::putDirect(JSGlobalData& globalData, PropertyName propertyN
inline void JSObject::putDirectWithoutTransition(JSGlobalData& globalData, PropertyName propertyName, JSValue value, unsigned attributes)
{
ASSERT(!value.isGetterSetter() && !(attributes & Accessor));
- PropertyStorage newStorage = outOfLineStorage();
+ Butterfly* newButterfly = m_butterfly;
if (structure()->putWillGrowOutOfLineStorage())
- newStorage = growOutOfLineStorage(globalData, structure()->outOfLineCapacity(), structure()->suggestedNewOutOfLineStorageCapacity());
+ newButterfly = growOutOfLineStorage(globalData, structure()->outOfLineCapacity(), structure()->suggestedNewOutOfLineStorageCapacity());
PropertyOffset offset = structure()->addPropertyWithoutTransition(globalData, propertyName, attributes, getCallableObject(value));
- setOutOfLineStorage(globalData, newStorage, structure());
+ setButterfly(globalData, newButterfly, structure());
putDirectOffset(globalData, offset, value);
}
@@ -932,6 +1211,11 @@ ALWAYS_INLINE Register Register::withCallee(JSObject* callee)
return r;
}
+inline size_t offsetInButterfly(PropertyOffset offset)
+{
+ return offsetInOutOfLineStorage(offset) + Butterfly::indexOfPropertyStorage();
+}
+
// This is a helper for patching code where you want to emit a load or store and
// the base is:
// For inline offsets: a pointer to the out-of-line storage pointer.
@@ -939,14 +1223,14 @@ ALWAYS_INLINE Register Register::withCallee(JSObject* callee)
inline size_t offsetRelativeToPatchedStorage(PropertyOffset offset)
{
if (isOutOfLineOffset(offset))
- return sizeof(EncodedJSValue) * offsetInOutOfLineStorage(offset);
- return JSObject::offsetOfInlineStorage() - JSObject::offsetOfOutOfLineStorage() + sizeof(EncodedJSValue) * offsetInInlineStorage(offset);
+ return sizeof(EncodedJSValue) * offsetInButterfly(offset);
+ return JSObject::offsetOfInlineStorage() - JSObject::butterflyOffset() + sizeof(EncodedJSValue) * offsetInInlineStorage(offset);
}
inline int indexRelativeToBase(PropertyOffset offset)
{
if (isOutOfLineOffset(offset))
- return offsetInOutOfLineStorage(offset);
+ return offsetInOutOfLineStorage(offset) + Butterfly::indexOfPropertyStorage();
ASSERT(!(JSObject::offsetOfInlineStorage() % sizeof(EncodedJSValue)));
return JSObject::offsetOfInlineStorage() / sizeof(EncodedJSValue) + offsetInInlineStorage(offset);
}
@@ -954,7 +1238,7 @@ inline int indexRelativeToBase(PropertyOffset offset)
inline int offsetRelativeToBase(PropertyOffset offset)
{
if (isOutOfLineOffset(offset))
- return offsetInOutOfLineStorage(offset) * sizeof(EncodedJSValue);
+ return offsetInOutOfLineStorage(offset) * sizeof(EncodedJSValue) + Butterfly::offsetOfPropertyStorage();
return JSObject::offsetOfInlineStorage() + offsetInInlineStorage(offset) * sizeof(EncodedJSValue);
}