summaryrefslogtreecommitdiff
path: root/Source/JavaScriptCore/runtime/JSObject.cpp
diff options
context:
space:
mode:
authorSimon Hausmann <simon.hausmann@digia.com>2012-10-15 16:08:57 +0200
committerSimon Hausmann <simon.hausmann@digia.com>2012-10-15 16:08:57 +0200
commit5466563f4b5b6b86523e3f89bb7f77e5b5270c78 (patch)
tree8caccf7cd03a15207cde3ba282c88bf132482a91 /Source/JavaScriptCore/runtime/JSObject.cpp
parent33b26980cb24288b5a9f2590ccf32a949281bb79 (diff)
downloadqtwebkit-5466563f4b5b6b86523e3f89bb7f77e5b5270c78.tar.gz
Imported WebKit commit 0dc6cd75e1d4836eaffbb520be96fac4847cc9d2 (http://svn.webkit.org/repository/webkit/trunk@131300)
WebKit update which introduces the QtWebKitWidgets module that contains the WK1 widgets based API. (In fact it renames QtWebKit to QtWebKitWidgets while we're working on completing the entire split as part of https://bugs.webkit.org/show_bug.cgi?id=99314
Diffstat (limited to 'Source/JavaScriptCore/runtime/JSObject.cpp')
-rw-r--r--Source/JavaScriptCore/runtime/JSObject.cpp473
1 files changed, 389 insertions, 84 deletions
diff --git a/Source/JavaScriptCore/runtime/JSObject.cpp b/Source/JavaScriptCore/runtime/JSObject.cpp
index bf38f6876..6a3fb84e4 100644
--- a/Source/JavaScriptCore/runtime/JSObject.cpp
+++ b/Source/JavaScriptCore/runtime/JSObject.cpp
@@ -26,13 +26,14 @@
#include "ButterflyInlineMethods.h"
#include "CopiedSpaceInlineMethods.h"
+#include "CopyVisitor.h"
+#include "CopyVisitorInlineMethods.h"
#include "DatePrototype.h"
#include "ErrorConstructor.h"
#include "GetterSetter.h"
#include "IndexingHeaderInlineMethods.h"
#include "JSFunction.h"
#include "JSGlobalObject.h"
-#include "JSGlobalThis.h"
#include "Lookup.h"
#include "NativeErrorConstructor.h"
#include "Nodes.h"
@@ -63,10 +64,6 @@ JSCell* getCallableObjectSlow(JSCell* cell)
return 0;
}
-ASSERT_CLASS_FITS_IN_CELL(JSObject);
-ASSERT_CLASS_FITS_IN_CELL(JSNonFinalObject);
-ASSERT_CLASS_FITS_IN_CELL(JSFinalObject);
-
ASSERT_HAS_TRIVIAL_DESTRUCTOR(JSObject);
ASSERT_HAS_TRIVIAL_DESTRUCTOR(JSFinalObject);
@@ -95,7 +92,7 @@ static inline void getClassPropertyNames(ExecState* exec, const ClassInfo* class
}
}
-ALWAYS_INLINE void JSObject::visitButterfly(SlotVisitor& visitor, Butterfly* butterfly, size_t storageSize)
+ALWAYS_INLINE void JSObject::copyButterfly(CopyVisitor& visitor, Butterfly* butterfly, size_t storageSize)
{
ASSERT(butterfly);
@@ -112,61 +109,93 @@ ALWAYS_INLINE void JSObject::visitButterfly(SlotVisitor& visitor, Butterfly* but
preCapacity = 0;
indexingPayloadSizeInBytes = 0;
}
- size_t capacityInBytes = Butterfly::totalSize(
- preCapacity, propertyCapacity, hasIndexingHeader, indexingPayloadSizeInBytes);
- if (visitor.checkIfShouldCopyAndPinOtherwise(
- butterfly->base(preCapacity, propertyCapacity), capacityInBytes)) {
+ size_t capacityInBytes = Butterfly::totalSize(preCapacity, propertyCapacity, hasIndexingHeader, indexingPayloadSizeInBytes);
+ if (visitor.checkIfShouldCopy(butterfly->base(preCapacity, propertyCapacity), capacityInBytes)) {
Butterfly* newButterfly = Butterfly::createUninitializedDuringCollection(visitor, preCapacity, propertyCapacity, hasIndexingHeader, indexingPayloadSizeInBytes);
- // Mark and copy the properties.
+ // Copy the properties.
PropertyStorage currentTarget = newButterfly->propertyStorage();
PropertyStorage currentSource = butterfly->propertyStorage();
- for (size_t count = storageSize; count--;) {
- JSValue value = (--currentSource)->get();
- ASSERT(value);
- visitor.appendUnbarrieredValue(&value);
- (--currentTarget)->setWithoutWriteBarrier(value);
- }
+ for (size_t count = storageSize; count--;)
+ (--currentTarget)->setWithoutWriteBarrier((--currentSource)->get());
if (UNLIKELY(hasIndexingHeader)) {
*newButterfly->indexingHeader() = *butterfly->indexingHeader();
- // Mark and copy the array if appropriate.
+ // Copy the array if appropriate.
+
+ WriteBarrier<Unknown>* currentTarget;
+ WriteBarrier<Unknown>* currentSource;
+ size_t count;
+
switch (structure->indexingType()) {
+ case ALL_CONTIGUOUS_INDEXING_TYPES: {
+ currentTarget = newButterfly->contiguous();
+ currentSource = butterfly->contiguous();
+ ASSERT(newButterfly->publicLength() <= newButterfly->vectorLength());
+ count = newButterfly->vectorLength();
+ break;
+ }
+
case ALL_ARRAY_STORAGE_INDEXING_TYPES: {
newButterfly->arrayStorage()->copyHeaderFromDuringGC(*butterfly->arrayStorage());
- WriteBarrier<Unknown>* currentTarget = newButterfly->arrayStorage()->m_vector;
- WriteBarrier<Unknown>* currentSource = butterfly->arrayStorage()->m_vector;
- for (size_t count = newButterfly->arrayStorage()->vectorLength(); count--;) {
- JSValue value = (currentSource++)->get();
- if (value)
- visitor.appendUnbarrieredValue(&value);
- (currentTarget++)->setWithoutWriteBarrier(value);
- }
- if (newButterfly->arrayStorage()->m_sparseMap)
- visitor.append(&newButterfly->arrayStorage()->m_sparseMap);
+ currentTarget = newButterfly->arrayStorage()->m_vector;
+ currentSource = butterfly->arrayStorage()->m_vector;
+ count = newButterfly->arrayStorage()->vectorLength();
break;
}
default:
+ CRASH();
+ currentTarget = 0;
+ currentSource = 0;
+ count = 0;
break;
}
+
+ while (count--)
+ (currentTarget++)->setWithoutWriteBarrier((currentSource++)->get());
}
m_butterfly = newButterfly;
+ visitor.didCopy(butterfly->base(preCapacity, propertyCapacity), capacityInBytes);
+ }
+}
+
+ALWAYS_INLINE void JSObject::visitButterfly(SlotVisitor& visitor, Butterfly* butterfly, size_t storageSize)
+{
+ ASSERT(butterfly);
+
+ Structure* structure = this->structure();
+
+ size_t propertyCapacity = structure->outOfLineCapacity();
+ size_t preCapacity;
+ size_t indexingPayloadSizeInBytes;
+ bool hasIndexingHeader = JSC::hasIndexingHeader(structure->indexingType());
+ if (UNLIKELY(hasIndexingHeader)) {
+ preCapacity = butterfly->indexingHeader()->preCapacity(structure);
+ indexingPayloadSizeInBytes = butterfly->indexingHeader()->indexingPayloadSizeInBytes(structure);
} else {
- // Mark the properties.
- visitor.appendValues(butterfly->propertyStorage() - storageSize, storageSize);
-
- // Mark the array if appropriate.
- switch (structure->indexingType()) {
- case ALL_ARRAY_STORAGE_INDEXING_TYPES:
- visitor.appendValues(butterfly->arrayStorage()->m_vector, butterfly->arrayStorage()->vectorLength());
- if (butterfly->arrayStorage()->m_sparseMap)
- visitor.append(&butterfly->arrayStorage()->m_sparseMap);
- break;
- default:
- break;
- }
+ preCapacity = 0;
+ indexingPayloadSizeInBytes = 0;
+ }
+ size_t capacityInBytes = Butterfly::totalSize(preCapacity, propertyCapacity, hasIndexingHeader, indexingPayloadSizeInBytes);
+
+ // Mark the properties.
+ visitor.appendValues(butterfly->propertyStorage() - storageSize, storageSize);
+ visitor.copyLater(butterfly->base(preCapacity, propertyCapacity), capacityInBytes);
+
+ // Mark the array if appropriate.
+ switch (structure->indexingType()) {
+ case ALL_CONTIGUOUS_INDEXING_TYPES:
+ visitor.appendValues(butterfly->contiguous(), butterfly->publicLength());
+ break;
+ case ALL_ARRAY_STORAGE_INDEXING_TYPES:
+ visitor.appendValues(butterfly->arrayStorage()->m_vector, butterfly->arrayStorage()->vectorLength());
+ if (butterfly->arrayStorage()->m_sparseMap)
+ visitor.append(&butterfly->arrayStorage()->m_sparseMap);
+ break;
+ default:
+ break;
}
}
@@ -183,13 +212,23 @@ void JSObject::visitChildren(JSCell* cell, SlotVisitor& visitor)
Butterfly* butterfly = thisObject->butterfly();
if (butterfly)
- thisObject->visitButterfly(visitor, butterfly, thisObject->structure()->outOfLineSizeForKnownNonFinalObject());
+ thisObject->visitButterfly(visitor, butterfly, thisObject->structure()->outOfLineSize());
#if !ASSERT_DISABLED
visitor.m_isCheckingForDefaultMarkViolation = wasCheckingForDefaultMarkViolation;
#endif
}
+void JSObject::copyBackingStore(JSCell* cell, CopyVisitor& visitor)
+{
+ JSObject* thisObject = jsCast<JSObject*>(cell);
+ ASSERT_GC_OBJECT_INHERITS(thisObject, &s_info);
+
+ Butterfly* butterfly = thisObject->butterfly();
+ if (butterfly)
+ thisObject->copyButterfly(visitor, butterfly, thisObject->structure()->outOfLineSize());
+}
+
void JSFinalObject::visitChildren(JSCell* cell, SlotVisitor& visitor)
{
JSFinalObject* thisObject = jsCast<JSFinalObject*>(cell);
@@ -203,9 +242,9 @@ void JSFinalObject::visitChildren(JSCell* cell, SlotVisitor& visitor)
Butterfly* butterfly = thisObject->butterfly();
if (butterfly)
- thisObject->visitButterfly(visitor, butterfly, thisObject->structure()->outOfLineSizeForKnownFinalObject());
+ thisObject->visitButterfly(visitor, butterfly, thisObject->structure()->outOfLineSize());
- size_t storageSize = thisObject->structure()->inlineSizeForKnownFinalObject();
+ size_t storageSize = thisObject->structure()->inlineSize();
visitor.appendValues(thisObject->inlineStorage(), storageSize);
#if !ASSERT_DISABLED
@@ -235,6 +274,20 @@ bool JSObject::getOwnPropertySlotByIndex(JSCell* cell, ExecState* exec, unsigned
case ALL_BLANK_INDEXING_TYPES:
break;
+ case ALL_CONTIGUOUS_INDEXING_TYPES: {
+ Butterfly* butterfly = thisObject->m_butterfly;
+ if (i >= butterfly->vectorLength())
+ return false;
+
+ JSValue value = butterfly->contiguous()[i].get();
+ if (value) {
+ slot.setValue(value);
+ return true;
+ }
+
+ return false;
+ }
+
case ALL_ARRAY_STORAGE_INDEXING_TYPES: {
ArrayStorage* storage = thisObject->m_butterfly->arrayStorage();
if (i >= storage->length())
@@ -249,7 +302,7 @@ bool JSObject::getOwnPropertySlotByIndex(JSCell* cell, ExecState* exec, unsigned
} else if (SparseArrayValueMap* map = storage->m_sparseMap.get()) {
SparseArrayValueMap::iterator it = map->find(i);
if (it != map->notFound()) {
- it->second.get(slot);
+ it->value.get(slot);
return true;
}
}
@@ -352,6 +405,16 @@ void JSObject::putByIndex(JSCell* cell, ExecState* exec, unsigned propertyName,
case ALL_BLANK_INDEXING_TYPES:
break;
+ case ALL_CONTIGUOUS_INDEXING_TYPES: {
+ Butterfly* butterfly = thisObject->m_butterfly;
+ if (propertyName >= butterfly->vectorLength())
+ break;
+ butterfly->contiguous()[propertyName].set(exec->globalData(), thisObject, value);
+ if (propertyName >= butterfly->publicLength())
+ butterfly->setPublicLength(propertyName + 1);
+ return;
+ }
+
case NonArrayWithArrayStorage:
case ArrayWithArrayStorage: {
ArrayStorage* storage = thisObject->m_butterfly->arrayStorage();
@@ -426,7 +489,7 @@ ArrayStorage* JSObject::enterDictionaryIndexingModeWhenArrayStorageAlreadyExists
// This will always be a new entry in the map, so no need to check we can write,
// and attributes are default so no need to set them.
if (value)
- map->add(this, i).iterator->second.set(globalData, this, value);
+ map->add(this, i).iterator->value.set(globalData, this, value);
}
Butterfly* newButterfly = storage->butterfly()->resizeArray(globalData, structure(), 0, ArrayStorage::sizeFor(0));
@@ -444,6 +507,11 @@ ArrayStorage* JSObject::enterDictionaryIndexingModeWhenArrayStorageAlreadyExists
void JSObject::enterDictionaryIndexingMode(JSGlobalData& globalData)
{
switch (structure()->indexingType()) {
+ case ALL_CONTIGUOUS_INDEXING_TYPES:
+ // NOTE: this is horribly inefficient, as it will perform two conversions. We could optimize
+ // this case if we ever cared.
+ enterDictionaryIndexingModeWhenArrayStorageAlreadyExists(globalData, convertContiguousToArrayStorage(globalData));
+ break;
case ALL_ARRAY_STORAGE_INDEXING_TYPES:
enterDictionaryIndexingModeWhenArrayStorageAlreadyExists(globalData, m_butterfly->arrayStorage());
break;
@@ -466,6 +534,24 @@ void JSObject::notifyPresenceOfIndexedAccessors(JSGlobalData& globalData)
globalObject()->haveABadTime(globalData);
}
+WriteBarrier<Unknown>* JSObject::createInitialContiguous(JSGlobalData& globalData, unsigned length)
+{
+ ASSERT(length < MAX_ARRAY_INDEX);
+ IndexingType oldType = structure()->indexingType();
+ ASSERT_UNUSED(oldType, !hasIndexedProperties(oldType));
+ ASSERT(!structure()->needsSlowPutIndexing());
+ ASSERT(!indexingShouldBeSparse());
+ unsigned vectorLength = std::max(length, BASE_VECTOR_LEN);
+ Butterfly* newButterfly = m_butterfly->growArrayRight(
+ globalData, structure(), structure()->outOfLineCapacity(), false, 0,
+ sizeof(EncodedJSValue) * vectorLength);
+ newButterfly->setPublicLength(length);
+ newButterfly->setVectorLength(vectorLength);
+ Structure* newStructure = Structure::nonPropertyTransition(globalData, structure(), AllocateContiguous);
+ setButterfly(globalData, newButterfly, newStructure);
+ return newButterfly->contiguous();
+}
+
ArrayStorage* JSObject::createArrayStorage(JSGlobalData& globalData, unsigned length, unsigned vectorLength)
{
IndexingType oldType = structure()->indexingType();
@@ -481,7 +567,7 @@ ArrayStorage* JSObject::createArrayStorage(JSGlobalData& globalData, unsigned le
result->m_sparseMap.clear();
result->m_numValuesInVector = 0;
result->m_indexBias = 0;
- Structure* newStructure = Structure::nonPropertyTransition(globalData, structure(), structure()->suggestedIndexingTransition());
+ Structure* newStructure = Structure::nonPropertyTransition(globalData, structure(), structure()->suggestedArrayStorageTransition());
setButterfly(globalData, newButterfly, newStructure);
return result;
}
@@ -491,9 +577,107 @@ ArrayStorage* JSObject::createInitialArrayStorage(JSGlobalData& globalData)
return createArrayStorage(globalData, 0, BASE_VECTOR_LEN);
}
+ArrayStorage* JSObject::convertContiguousToArrayStorage(JSGlobalData& globalData, NonPropertyTransition transition, unsigned neededLength)
+{
+ ASSERT(hasContiguous(structure()->indexingType()));
+
+ unsigned publicLength = m_butterfly->publicLength();
+ unsigned propertyCapacity = structure()->outOfLineCapacity();
+ unsigned propertySize = structure()->outOfLineSize();
+
+ Butterfly* newButterfly = Butterfly::createUninitialized(
+ globalData, 0, propertyCapacity, true, ArrayStorage::sizeFor(neededLength));
+
+ memcpy(
+ newButterfly->propertyStorage() - propertySize,
+ m_butterfly->propertyStorage() - propertySize,
+ propertySize * sizeof(EncodedJSValue));
+
+ ArrayStorage* newStorage = newButterfly->arrayStorage();
+ newStorage->setVectorLength(neededLength);
+ newStorage->setLength(publicLength);
+ newStorage->m_sparseMap.clear();
+ newStorage->m_indexBias = 0;
+ newStorage->m_numValuesInVector = 0;
+ for (unsigned i = publicLength; i--;) {
+ JSValue v = m_butterfly->contiguous()[i].get();
+ if (!v)
+ continue;
+ newStorage->m_vector[i].setWithoutWriteBarrier(v);
+ newStorage->m_numValuesInVector++;
+ }
+
+ Structure* newStructure = Structure::nonPropertyTransition(globalData, structure(), transition);
+ setButterfly(globalData, newButterfly, newStructure);
+ return newStorage;
+}
+
+ArrayStorage* JSObject::convertContiguousToArrayStorage(JSGlobalData& globalData, NonPropertyTransition transition)
+{
+ return convertContiguousToArrayStorage(globalData, transition, m_butterfly->vectorLength());
+}
+
+ArrayStorage* JSObject::convertContiguousToArrayStorage(JSGlobalData& globalData)
+{
+ return convertContiguousToArrayStorage(globalData, structure()->suggestedArrayStorageTransition());
+}
+
+WriteBarrier<Unknown>* JSObject::ensureContiguousSlow(JSGlobalData& globalData)
+{
+ switch (structure()->indexingType()) {
+ case ALL_BLANK_INDEXING_TYPES:
+ if (UNLIKELY(indexingShouldBeSparse() || structure()->needsSlowPutIndexing()))
+ return 0;
+ return createInitialContiguous(globalData, 0);
+
+ default:
+ ASSERT_NOT_REACHED();
+ return 0;
+ }
+}
+
+ArrayStorage* JSObject::ensureArrayStorageSlow(JSGlobalData& globalData)
+{
+ switch (structure()->indexingType()) {
+ case ALL_CONTIGUOUS_INDEXING_TYPES:
+ ASSERT(!indexingShouldBeSparse());
+ ASSERT(!structure()->needsSlowPutIndexing());
+ return convertContiguousToArrayStorage(globalData);
+
+ case ALL_BLANK_INDEXING_TYPES:
+ if (UNLIKELY(indexingShouldBeSparse()))
+ return ensureArrayStorageExistsAndEnterDictionaryIndexingMode(globalData);
+ return createInitialArrayStorage(globalData);
+
+ default:
+ ASSERT_NOT_REACHED();
+ return 0;
+ }
+}
+
+Butterfly* JSObject::ensureIndexedStorageSlow(JSGlobalData& globalData)
+{
+ switch (structure()->indexingType()) {
+ case ALL_BLANK_INDEXING_TYPES:
+ if (UNLIKELY(structure()->needsSlowPutIndexing()))
+ return createInitialArrayStorage(globalData)->butterfly();
+ if (UNLIKELY(indexingShouldBeSparse()))
+ return ensureArrayStorageExistsAndEnterDictionaryIndexingMode(globalData)->butterfly();
+ return Butterfly::fromContiguous(createInitialContiguous(globalData, 0));
+
+ default:
+ ASSERT_NOT_REACHED();
+ return 0;
+ }
+}
+
ArrayStorage* JSObject::ensureArrayStorageExistsAndEnterDictionaryIndexingMode(JSGlobalData& globalData)
{
switch (structure()->indexingType()) {
+ case ALL_CONTIGUOUS_INDEXING_TYPES:
+ // FIXME: This could be made way more efficient, if we cared.
+ return enterDictionaryIndexingModeWhenArrayStorageAlreadyExists(globalData, convertContiguousToArrayStorage(globalData));
+
case ALL_ARRAY_STORAGE_INDEXING_TYPES:
return enterDictionaryIndexingModeWhenArrayStorageAlreadyExists(globalData, m_butterfly->arrayStorage());
@@ -513,6 +697,11 @@ ArrayStorage* JSObject::ensureArrayStorageExistsAndEnterDictionaryIndexingMode(J
void JSObject::switchToSlowPutArrayStorage(JSGlobalData& globalData)
{
switch (structure()->indexingType()) {
+ case ALL_CONTIGUOUS_INDEXING_TYPES: {
+ convertContiguousToArrayStorage(globalData, AllocateSlowPutArrayStorage);
+ break;
+ }
+
case NonArrayWithArrayStorage:
case ArrayWithArrayStorage: {
Structure* newStructure = Structure::nonPropertyTransition(globalData, structure(), SwitchToSlowPutArrayStorage);
@@ -556,8 +745,7 @@ void JSObject::setPrototype(JSGlobalData& globalData, JSValue prototype)
if (shouldUseSlowPut(structure()->indexingType()))
return;
- newStructure = Structure::nonPropertyTransition(globalData, newStructure, SwitchToSlowPutArrayStorage);
- setStructure(globalData, newStructure);
+ switchToSlowPutArrayStorage(globalData);
}
bool JSObject::setPrototypeWithCycleCheck(JSGlobalData& globalData, JSValue prototype)
@@ -691,6 +879,14 @@ bool JSObject::deletePropertyByIndex(JSCell* cell, ExecState* exec, unsigned i)
case ALL_BLANK_INDEXING_TYPES:
return true;
+ case ALL_CONTIGUOUS_INDEXING_TYPES: {
+ Butterfly* butterfly = thisObject->m_butterfly;
+ if (i >= butterfly->vectorLength())
+ return true;
+ butterfly->contiguous()[i].clear();
+ return true;
+ }
+
case ALL_ARRAY_STORAGE_INDEXING_TYPES: {
ArrayStorage* storage = thisObject->m_butterfly->arrayStorage();
@@ -703,7 +899,7 @@ bool JSObject::deletePropertyByIndex(JSCell* cell, ExecState* exec, unsigned i)
} else if (SparseArrayValueMap* map = storage->m_sparseMap.get()) {
SparseArrayValueMap::iterator it = map->find(i);
if (it != map->notFound()) {
- if (it->second.attributes & DontDelete)
+ if (it->value.attributes & DontDelete)
return false;
map->remove(it);
}
@@ -864,6 +1060,17 @@ void JSObject::getOwnPropertyNames(JSObject* object, ExecState* exec, PropertyNa
case ALL_BLANK_INDEXING_TYPES:
break;
+ case ALL_CONTIGUOUS_INDEXING_TYPES: {
+ Butterfly* butterfly = object->m_butterfly;
+ unsigned usedLength = butterfly->publicLength();
+ for (unsigned i = 0; i < usedLength; ++i) {
+ if (!butterfly->contiguous()[i])
+ continue;
+ propertyNames.add(Identifier::from(exec, i));
+ }
+ break;
+ }
+
case ALL_ARRAY_STORAGE_INDEXING_TYPES: {
ArrayStorage* storage = object->m_butterfly->arrayStorage();
@@ -879,8 +1086,8 @@ void JSObject::getOwnPropertyNames(JSObject* object, ExecState* exec, PropertyNa
SparseArrayValueMap::const_iterator end = map->end();
for (SparseArrayValueMap::const_iterator it = map->begin(); it != end; ++it) {
- if (mode == IncludeDontEnumProperties || !(it->second.attributes & DontEnum))
- keys.append(static_cast<unsigned>(it->first));
+ if (mode == IncludeDontEnumProperties || !(it->value.attributes & DontEnum))
+ keys.append(static_cast<unsigned>(it->key));
}
std::sort(keys.begin(), keys.end());
@@ -1089,9 +1296,6 @@ bool JSObject::defineOwnIndexedProperty(ExecState* exec, unsigned index, Propert
{
ASSERT(index <= MAX_ARRAY_INDEX);
- if (descriptor.attributes() & (ReadOnly | Accessor))
- notifyPresenceOfIndexedAccessors(exec->globalData());
-
if (!inSparseIndexingMode()) {
// Fast case: we're putting a regular property to a regular array
// FIXME: this will pessimistically assume that if attributes are missing then they'll default to false
@@ -1101,16 +1305,19 @@ bool JSObject::defineOwnIndexedProperty(ExecState* exec, unsigned index, Propert
ASSERT(!descriptor.isAccessorDescriptor());
return putDirectIndex(exec, index, descriptor.value(), 0, throwException ? PutDirectIndexShouldThrow : PutDirectIndexShouldNotThrow);
}
-
+
ensureArrayStorageExistsAndEnterDictionaryIndexingMode(exec->globalData());
}
+ if (descriptor.attributes() & (ReadOnly | Accessor))
+ notifyPresenceOfIndexedAccessors(exec->globalData());
+
SparseArrayValueMap* map = m_butterfly->arrayStorage()->m_sparseMap.get();
ASSERT(map);
// 1. Let current be the result of calling the [[GetOwnProperty]] internal method of O with property name P.
SparseArrayValueMap::AddResult result = map->add(this, index);
- SparseArrayEntry* entryInMap = &result.iterator->second;
+ SparseArrayEntry* entryInMap = &result.iterator->value;
// 2. Let extensible be the value of the [[Extensible]] internal property of O.
// 3. If current is undefined and extensible is false, then Reject.
@@ -1230,8 +1437,8 @@ bool JSObject::attemptToInterceptPutByIndexOnHoleForPrototype(ExecState* exec, J
ArrayStorage* storage = current->arrayStorageOrNull();
if (storage && storage->m_sparseMap) {
SparseArrayValueMap::iterator iter = storage->m_sparseMap->find(i);
- if (iter != storage->m_sparseMap->notFound() && (iter->second.attributes & (Accessor | ReadOnly))) {
- iter->second.put(exec, thisValue, storage->m_sparseMap.get(), value, shouldThrow);
+ if (iter != storage->m_sparseMap->notFound() && (iter->value.attributes & (Accessor | ReadOnly))) {
+ iter->value.put(exec, thisValue, storage->m_sparseMap.get(), value, shouldThrow);
return true;
}
}
@@ -1253,6 +1460,35 @@ bool JSObject::attemptToInterceptPutByIndexOnHole(ExecState* exec, unsigned i, J
return asObject(prototypeValue)->attemptToInterceptPutByIndexOnHoleForPrototype(exec, this, i, value, shouldThrow);
}
+void JSObject::putByIndexBeyondVectorLengthContiguousWithoutAttributes(ExecState* exec, unsigned i, JSValue value)
+{
+ ASSERT(hasContiguous(structure()->indexingType()));
+ ASSERT(!indexingShouldBeSparse());
+
+ // For us to get here, the index is either greater than the public length, or greater than
+ // or equal to the vector length.
+ ASSERT(i >= m_butterfly->vectorLength());
+
+ JSGlobalData& globalData = exec->globalData();
+
+ if (i >= MAX_ARRAY_INDEX - 1
+ || (i >= MIN_SPARSE_ARRAY_INDEX
+ && !isDenseEnoughForVector(i, countElementsInContiguous(m_butterfly)))) {
+ ASSERT(i <= MAX_ARRAY_INDEX);
+ convertContiguousToArrayStorage(globalData, AllocateArrayStorage);
+ SparseArrayValueMap* map = allocateSparseIndexMap(globalData);
+ map->putEntry(exec, this, i, value, false);
+ ASSERT(i >= arrayStorage()->length());
+ arrayStorage()->setLength(i + 1);
+ return;
+ }
+
+ ensureContiguousLength(globalData, i + 1);
+
+ ASSERT(i < m_butterfly->vectorLength());
+ m_butterfly->contiguous()[i].set(globalData, this, value);
+}
+
void JSObject::putByIndexBeyondVectorLengthWithArrayStorage(ExecState* exec, unsigned i, JSValue value, bool shouldThrow, ArrayStorage* storage)
{
JSGlobalData& globalData = exec->globalData();
@@ -1315,7 +1551,7 @@ void JSObject::putByIndexBeyondVectorLengthWithArrayStorage(ExecState* exec, uns
WriteBarrier<Unknown>* vector = storage->m_vector;
SparseArrayValueMap::const_iterator end = map->end();
for (SparseArrayValueMap::const_iterator it = map->begin(); it != end; ++it)
- vector[it->first].set(globalData, this, it->second.getNonSparseMode());
+ vector[it->key].set(globalData, this, it->value.getNonSparseMode());
deallocateSparseIndexMap();
// Store the new property into the vector.
@@ -1335,17 +1571,29 @@ void JSObject::putByIndexBeyondVectorLength(ExecState* exec, unsigned i, JSValue
switch (structure()->indexingType()) {
case ALL_BLANK_INDEXING_TYPES: {
if (indexingShouldBeSparse()) {
- putByIndexBeyondVectorLengthWithArrayStorage(exec, i, value, shouldThrow, ensureArrayStorageExistsAndEnterDictionaryIndexingMode(globalData));
+ putByIndexBeyondVectorLengthWithArrayStorage(
+ exec, i, value, shouldThrow,
+ ensureArrayStorageExistsAndEnterDictionaryIndexingMode(globalData));
+ break;
+ }
+ if (i >= MIN_SPARSE_ARRAY_INDEX) {
+ putByIndexBeyondVectorLengthWithArrayStorage(
+ exec, i, value, shouldThrow, createArrayStorage(globalData, 0, 0));
break;
}
- if (!isDenseEnoughForVector(i, 0) || i >= MAX_STORAGE_VECTOR_LENGTH) {
- putByIndexBeyondVectorLengthWithArrayStorage(exec, i, value, shouldThrow, createArrayStorage(globalData, 0, 0));
+ if (structure()->needsSlowPutIndexing()) {
+ ArrayStorage* storage = createArrayStorage(globalData, i + 1, getNewVectorLength(0, 0, i + 1));
+ storage->m_vector[i].set(globalData, this, value);
+ storage->m_numValuesInVector++;
break;
}
+
+ createInitialContiguous(globalData, i + 1)[i].set(globalData, this, value);
+ break;
+ }
- ArrayStorage* storage = createArrayStorage(globalData, i + 1, getNewVectorLength(0, 0, i + 1));
- storage->m_vector[i].set(globalData, this, value);
- storage->m_numValuesInVector = 1;
+ case ALL_CONTIGUOUS_INDEXING_TYPES: {
+ putByIndexBeyondVectorLengthContiguousWithoutAttributes(exec, i, value);
break;
}
@@ -1371,8 +1619,10 @@ void JSObject::putByIndexBeyondVectorLength(ExecState* exec, unsigned i, JSValue
bool JSObject::putDirectIndexBeyondVectorLengthWithArrayStorage(ExecState* exec, unsigned i, JSValue value, unsigned attributes, PutDirectIndexMode mode, ArrayStorage* storage)
{
JSGlobalData& globalData = exec->globalData();
-
+
// i should be a valid array index that is outside of the current vector.
+ ASSERT(hasArrayStorage(structure()->indexingType()));
+ ASSERT(arrayStorage() == storage);
ASSERT(i >= storage->vectorLength() || attributes);
ASSERT(i <= MAX_ARRAY_INDEX);
@@ -1431,7 +1681,7 @@ bool JSObject::putDirectIndexBeyondVectorLengthWithArrayStorage(ExecState* exec,
WriteBarrier<Unknown>* vector = storage->m_vector;
SparseArrayValueMap::const_iterator end = map->end();
for (SparseArrayValueMap::const_iterator it = map->begin(); it != end; ++it)
- vector[it->first].set(globalData, this, it->second.getNonSparseMode());
+ vector[it->key].set(globalData, this, it->value.getNonSparseMode());
deallocateSparseIndexMap();
// Store the new property into the vector.
@@ -1454,14 +1704,32 @@ bool JSObject::putDirectIndexBeyondVectorLength(ExecState* exec, unsigned i, JSV
switch (structure()->indexingType()) {
case ALL_BLANK_INDEXING_TYPES: {
- if (indexingShouldBeSparse() || attributes)
- return putDirectIndexBeyondVectorLengthWithArrayStorage(exec, i, value, attributes, mode, ensureArrayStorageExistsAndEnterDictionaryIndexingMode(globalData));
- if (!isDenseEnoughForVector(i, 0) || i >= MAX_STORAGE_VECTOR_LENGTH)
- return putDirectIndexBeyondVectorLengthWithArrayStorage(exec, i, value, attributes, mode, createArrayStorage(globalData, 0, 0));
+ if (indexingShouldBeSparse() || attributes) {
+ return putDirectIndexBeyondVectorLengthWithArrayStorage(
+ exec, i, value, attributes, mode,
+ ensureArrayStorageExistsAndEnterDictionaryIndexingMode(globalData));
+ }
+ if (i >= MIN_SPARSE_ARRAY_INDEX) {
+ return putDirectIndexBeyondVectorLengthWithArrayStorage(
+ exec, i, value, attributes, mode, createArrayStorage(globalData, 0, 0));
+ }
+ if (structure()->needsSlowPutIndexing()) {
+ ArrayStorage* storage = createArrayStorage(globalData, i + 1, getNewVectorLength(0, 0, i + 1));
+ storage->m_vector[i].set(globalData, this, value);
+ storage->m_numValuesInVector++;
+ return true;
+ }
- ArrayStorage* storage = createArrayStorage(globalData, i + 1, getNewVectorLength(0, 0, i + 1));
- storage->m_vector[i].set(globalData, this, value);
- storage->m_numValuesInVector = 1;
+ createInitialContiguous(globalData, i + 1)[i].set(globalData, this, value);
+ return true;
+ }
+
+ case ALL_CONTIGUOUS_INDEXING_TYPES: {
+ if (attributes & (ReadOnly | Accessor)) {
+ return putDirectIndexBeyondVectorLengthWithArrayStorage(
+ exec, i, value, attributes, mode, convertContiguousToArrayStorage(globalData));
+ }
+ putByIndexBeyondVectorLengthContiguousWithoutAttributes(exec, i, value);
return true;
}
@@ -1486,12 +1754,7 @@ ALWAYS_INLINE unsigned JSObject::getNewVectorLength(unsigned currentVectorLength
else if (!currentVectorLength)
increasedLength = std::max(desiredLength, lastArraySize);
else {
- // Mathematically equivalent to:
- // increasedLength = (newLength * 3 + 1) / 2;
- // or:
- // increasedLength = (unsigned)ceil(newLength * 1.5));
- // This form is not prone to internal overflow.
- increasedLength = desiredLength + (desiredLength >> 1) + (desiredLength & 1);
+ increasedLength = timesThreePlusOneDividedByTwo(desiredLength);
}
ASSERT(increasedLength >= desiredLength);
@@ -1511,9 +1774,10 @@ ALWAYS_INLINE unsigned JSObject::getNewVectorLength(unsigned desiredLength)
vectorLength = 0;
length = 0;
break;
+ case ALL_CONTIGUOUS_INDEXING_TYPES:
case ALL_ARRAY_STORAGE_INDEXING_TYPES:
- vectorLength = m_butterfly->arrayStorage()->vectorLength();
- length = m_butterfly->arrayStorage()->length();
+ vectorLength = m_butterfly->vectorLength();
+ length = m_butterfly->publicLength();
break;
default:
CRASH();
@@ -1522,6 +1786,16 @@ ALWAYS_INLINE unsigned JSObject::getNewVectorLength(unsigned desiredLength)
return getNewVectorLength(vectorLength, length, desiredLength);
}
+unsigned JSObject::countElementsInContiguous(Butterfly* butterfly)
+{
+ unsigned numValues = 0;
+ for (unsigned i = butterfly->publicLength(); i--;) {
+ if (butterfly->contiguous()[i])
+ numValues++;
+ }
+ return numValues;
+}
+
bool JSObject::increaseVectorLength(JSGlobalData& globalData, unsigned newLength)
{
// This function leaves the array in an internally inconsistent state, because it does not move any values from sparse value map
@@ -1530,6 +1804,10 @@ bool JSObject::increaseVectorLength(JSGlobalData& globalData, unsigned newLength
return false;
ArrayStorage* storage = arrayStorage();
+
+ if (newLength >= MIN_SPARSE_ARRAY_INDEX
+ && !isDenseEnoughForVector(newLength, storage->m_numValuesInVector))
+ return false;
unsigned indexBias = storage->m_indexBias;
unsigned vectorLength = storage->vectorLength();
@@ -1561,6 +1839,22 @@ bool JSObject::increaseVectorLength(JSGlobalData& globalData, unsigned newLength
return true;
}
+void JSObject::ensureContiguousLengthSlow(JSGlobalData& globalData, unsigned length)
+{
+ ASSERT(length < MAX_ARRAY_INDEX);
+ ASSERT(hasContiguous(structure()->indexingType()));
+ ASSERT(length > m_butterfly->vectorLength());
+
+ unsigned newVectorLength = std::min(
+ length << 1,
+ MAX_STORAGE_VECTOR_LENGTH);
+ m_butterfly = m_butterfly->growArrayRight(
+ globalData, structure(), structure()->outOfLineCapacity(), true,
+ m_butterfly->vectorLength() * sizeof(EncodedJSValue),
+ newVectorLength * sizeof(EncodedJSValue));
+ m_butterfly->setVectorLength(newVectorLength);
+}
+
Butterfly* JSObject::growOutOfLineStorage(JSGlobalData& globalData, size_t oldSize, size_t newSize)
{
ASSERT(newSize > oldSize);
@@ -1589,6 +1883,17 @@ bool JSObject::getOwnPropertyDescriptor(JSObject* object, ExecState* exec, Prope
case ALL_BLANK_INDEXING_TYPES:
return false;
+ case ALL_CONTIGUOUS_INDEXING_TYPES: {
+ Butterfly* butterfly = object->m_butterfly;
+ if (i >= butterfly->vectorLength())
+ return false;
+ JSValue value = butterfly->contiguous()[i].get();
+ if (!value)
+ return false;
+ descriptor.setDescriptor(value, 0);
+ return true;
+ }
+
case ALL_ARRAY_STORAGE_INDEXING_TYPES: {
ArrayStorage* storage = object->m_butterfly->arrayStorage();
if (i >= storage->length())
@@ -1604,7 +1909,7 @@ bool JSObject::getOwnPropertyDescriptor(JSObject* object, ExecState* exec, Prope
SparseArrayValueMap::iterator it = map->find(i);
if (it == map->notFound())
return false;
- it->second.get(descriptor);
+ it->value.get(descriptor);
return true;
}
return false;