diff options
Diffstat (limited to 'Source/JavaScriptCore/runtime/JSObject.cpp')
-rw-r--r-- | Source/JavaScriptCore/runtime/JSObject.cpp | 473 |
1 files changed, 84 insertions, 389 deletions
diff --git a/Source/JavaScriptCore/runtime/JSObject.cpp b/Source/JavaScriptCore/runtime/JSObject.cpp index 6a3fb84e4..bf38f6876 100644 --- a/Source/JavaScriptCore/runtime/JSObject.cpp +++ b/Source/JavaScriptCore/runtime/JSObject.cpp @@ -26,14 +26,13 @@ #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" @@ -64,6 +63,10 @@ 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); @@ -92,7 +95,7 @@ static inline void getClassPropertyNames(ExecState* exec, const ClassInfo* class } } -ALWAYS_INLINE void JSObject::copyButterfly(CopyVisitor& visitor, Butterfly* butterfly, size_t storageSize) +ALWAYS_INLINE void JSObject::visitButterfly(SlotVisitor& visitor, Butterfly* butterfly, size_t storageSize) { ASSERT(butterfly); @@ -109,93 +112,61 @@ ALWAYS_INLINE void JSObject::copyButterfly(CopyVisitor& visitor, Butterfly* butt preCapacity = 0; indexingPayloadSizeInBytes = 0; } - size_t capacityInBytes = Butterfly::totalSize(preCapacity, propertyCapacity, hasIndexingHeader, indexingPayloadSizeInBytes); - if (visitor.checkIfShouldCopy(butterfly->base(preCapacity, propertyCapacity), capacityInBytes)) { + size_t capacityInBytes = Butterfly::totalSize( + preCapacity, propertyCapacity, hasIndexingHeader, indexingPayloadSizeInBytes); + if (visitor.checkIfShouldCopyAndPinOtherwise( + butterfly->base(preCapacity, propertyCapacity), capacityInBytes)) { Butterfly* newButterfly = Butterfly::createUninitializedDuringCollection(visitor, preCapacity, propertyCapacity, hasIndexingHeader, indexingPayloadSizeInBytes); - // Copy the properties. + // Mark and copy the properties. PropertyStorage currentTarget = newButterfly->propertyStorage(); PropertyStorage currentSource = butterfly->propertyStorage(); - for (size_t count = storageSize; count--;) - (--currentTarget)->setWithoutWriteBarrier((--currentSource)->get()); + for (size_t count = storageSize; count--;) { + JSValue value = (--currentSource)->get(); + ASSERT(value); + visitor.appendUnbarrieredValue(&value); + (--currentTarget)->setWithoutWriteBarrier(value); + } if (UNLIKELY(hasIndexingHeader)) { *newButterfly->indexingHeader() = *butterfly->indexingHeader(); - // Copy the array if appropriate. - - WriteBarrier<Unknown>* currentTarget; - WriteBarrier<Unknown>* currentSource; - size_t count; - + // Mark and copy the array if appropriate. 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()); - currentTarget = newButterfly->arrayStorage()->m_vector; - currentSource = butterfly->arrayStorage()->m_vector; - count = newButterfly->arrayStorage()->vectorLength(); + 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); 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 { - 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; + // 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; + } } } @@ -212,23 +183,13 @@ void JSObject::visitChildren(JSCell* cell, SlotVisitor& visitor) Butterfly* butterfly = thisObject->butterfly(); if (butterfly) - thisObject->visitButterfly(visitor, butterfly, thisObject->structure()->outOfLineSize()); + thisObject->visitButterfly(visitor, butterfly, thisObject->structure()->outOfLineSizeForKnownNonFinalObject()); #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); @@ -242,9 +203,9 @@ void JSFinalObject::visitChildren(JSCell* cell, SlotVisitor& visitor) Butterfly* butterfly = thisObject->butterfly(); if (butterfly) - thisObject->visitButterfly(visitor, butterfly, thisObject->structure()->outOfLineSize()); + thisObject->visitButterfly(visitor, butterfly, thisObject->structure()->outOfLineSizeForKnownFinalObject()); - size_t storageSize = thisObject->structure()->inlineSize(); + size_t storageSize = thisObject->structure()->inlineSizeForKnownFinalObject(); visitor.appendValues(thisObject->inlineStorage(), storageSize); #if !ASSERT_DISABLED @@ -274,20 +235,6 @@ 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()) @@ -302,7 +249,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->value.get(slot); + it->second.get(slot); return true; } } @@ -405,16 +352,6 @@ 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(); @@ -489,7 +426,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->value.set(globalData, this, value); + map->add(this, i).iterator->second.set(globalData, this, value); } Butterfly* newButterfly = storage->butterfly()->resizeArray(globalData, structure(), 0, ArrayStorage::sizeFor(0)); @@ -507,11 +444,6 @@ 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; @@ -534,24 +466,6 @@ 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(); @@ -567,7 +481,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()->suggestedArrayStorageTransition()); + Structure* newStructure = Structure::nonPropertyTransition(globalData, structure(), structure()->suggestedIndexingTransition()); setButterfly(globalData, newButterfly, newStructure); return result; } @@ -577,107 +491,9 @@ 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()); @@ -697,11 +513,6 @@ 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); @@ -745,7 +556,8 @@ void JSObject::setPrototype(JSGlobalData& globalData, JSValue prototype) if (shouldUseSlowPut(structure()->indexingType())) return; - switchToSlowPutArrayStorage(globalData); + newStructure = Structure::nonPropertyTransition(globalData, newStructure, SwitchToSlowPutArrayStorage); + setStructure(globalData, newStructure); } bool JSObject::setPrototypeWithCycleCheck(JSGlobalData& globalData, JSValue prototype) @@ -879,14 +691,6 @@ 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(); @@ -899,7 +703,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->value.attributes & DontDelete) + if (it->second.attributes & DontDelete) return false; map->remove(it); } @@ -1060,17 +864,6 @@ 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(); @@ -1086,8 +879,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->value.attributes & DontEnum)) - keys.append(static_cast<unsigned>(it->key)); + if (mode == IncludeDontEnumProperties || !(it->second.attributes & DontEnum)) + keys.append(static_cast<unsigned>(it->first)); } std::sort(keys.begin(), keys.end()); @@ -1296,6 +1089,9 @@ 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 @@ -1305,19 +1101,16 @@ 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->value; + SparseArrayEntry* entryInMap = &result.iterator->second; // 2. Let extensible be the value of the [[Extensible]] internal property of O. // 3. If current is undefined and extensible is false, then Reject. @@ -1437,8 +1230,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->value.attributes & (Accessor | ReadOnly))) { - iter->value.put(exec, thisValue, storage->m_sparseMap.get(), value, shouldThrow); + if (iter != storage->m_sparseMap->notFound() && (iter->second.attributes & (Accessor | ReadOnly))) { + iter->second.put(exec, thisValue, storage->m_sparseMap.get(), value, shouldThrow); return true; } } @@ -1460,35 +1253,6 @@ 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(); @@ -1551,7 +1315,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->key].set(globalData, this, it->value.getNonSparseMode()); + vector[it->first].set(globalData, this, it->second.getNonSparseMode()); deallocateSparseIndexMap(); // Store the new property into the vector. @@ -1571,29 +1335,17 @@ 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)); - break; - } - if (i >= MIN_SPARSE_ARRAY_INDEX) { - putByIndexBeyondVectorLengthWithArrayStorage( - exec, i, value, shouldThrow, createArrayStorage(globalData, 0, 0)); + putByIndexBeyondVectorLengthWithArrayStorage(exec, i, value, shouldThrow, ensureArrayStorageExistsAndEnterDictionaryIndexingMode(globalData)); break; } - 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++; + if (!isDenseEnoughForVector(i, 0) || i >= MAX_STORAGE_VECTOR_LENGTH) { + putByIndexBeyondVectorLengthWithArrayStorage(exec, i, value, shouldThrow, createArrayStorage(globalData, 0, 0)); break; } - - createInitialContiguous(globalData, i + 1)[i].set(globalData, this, value); - break; - } - case ALL_CONTIGUOUS_INDEXING_TYPES: { - putByIndexBeyondVectorLengthContiguousWithoutAttributes(exec, i, value); + ArrayStorage* storage = createArrayStorage(globalData, i + 1, getNewVectorLength(0, 0, i + 1)); + storage->m_vector[i].set(globalData, this, value); + storage->m_numValuesInVector = 1; break; } @@ -1619,10 +1371,8 @@ 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); @@ -1681,7 +1431,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->key].set(globalData, this, it->value.getNonSparseMode()); + vector[it->first].set(globalData, this, it->second.getNonSparseMode()); deallocateSparseIndexMap(); // Store the new property into the vector. @@ -1704,32 +1454,14 @@ 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 (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; - } + 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)); - 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); + ArrayStorage* storage = createArrayStorage(globalData, i + 1, getNewVectorLength(0, 0, i + 1)); + storage->m_vector[i].set(globalData, this, value); + storage->m_numValuesInVector = 1; return true; } @@ -1754,7 +1486,12 @@ ALWAYS_INLINE unsigned JSObject::getNewVectorLength(unsigned currentVectorLength else if (!currentVectorLength) increasedLength = std::max(desiredLength, lastArraySize); else { - increasedLength = timesThreePlusOneDividedByTwo(desiredLength); + // 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); } ASSERT(increasedLength >= desiredLength); @@ -1774,10 +1511,9 @@ 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->vectorLength(); - length = m_butterfly->publicLength(); + vectorLength = m_butterfly->arrayStorage()->vectorLength(); + length = m_butterfly->arrayStorage()->length(); break; default: CRASH(); @@ -1786,16 +1522,6 @@ 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 @@ -1804,10 +1530,6 @@ 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(); @@ -1839,22 +1561,6 @@ 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); @@ -1883,17 +1589,6 @@ 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()) @@ -1909,7 +1604,7 @@ bool JSObject::getOwnPropertyDescriptor(JSObject* object, ExecState* exec, Prope SparseArrayValueMap::iterator it = map->find(i); if (it == map->notFound()) return false; - it->value.get(descriptor); + it->second.get(descriptor); return true; } return false; |