JSC should have property butterflies
authorfpizlo@apple.com <fpizlo@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 13 Sep 2012 04:18:52 +0000 (04:18 +0000)
committerfpizlo@apple.com <fpizlo@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 13 Sep 2012 04:18:52 +0000 (04:18 +0000)
https://bugs.webkit.org/show_bug.cgi?id=91933

Reviewed by Geoffrey Garen.

Source/JavaScriptCore:

This changes the JSC object model. Previously, all objects had fast lookup for
named properties. Integer indexed properties were only fast if you used a
JSArray. With this change, all objects have fast indexed properties. This is
accomplished without any space overhead by using a bidirectional object layout,
aka butterflies. Each JSObject has a m_butterfly pointer where previously it
had a m_outOfLineStorage pointer. To the left of the location pointed to by
m_butterfly, we place all named out-of-line properties. To the right, we place
all indexed properties along with indexing meta-data. Though, some indexing
meta-data is placed in the 8-byte word immediately left of the pointed-to
location; this is in anticipation of the indexing meta-data being small enough
in the common case that m_butterfly always points to the first indexed
property.

This is performance neutral, except on tests that use indexed properties on
plain objects, where the speed-up is in excess of an order of magnitude.

One notable aspect of what this change brings is that it allows indexing
storage to morph over time. Currently this is only used to allow all non-array
objects to start out without any indexed storage. But it could be used for
some kinds of array type inference in the future.

* API/JSCallbackObject.h:
(JSCallbackObject):
* API/JSCallbackObjectFunctions.h:
(JSC::::getOwnPropertySlotByIndex):
(JSC):
(JSC::::getOwnNonIndexPropertyNames):
* API/JSObjectRef.cpp:
* CMakeLists.txt:
* GNUmakefile.list.am:
* JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.def:
* JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.vcproj:
* JavaScriptCore.xcodeproj/project.pbxproj:
* Target.pri:
* bytecode/ArrayProfile.h:
(JSC):
(JSC::arrayModeFromStructure):
* bytecompiler/BytecodeGenerator.cpp:
(JSC::BytecodeGenerator::emitDirectPutById):
* dfg/DFGAbstractState.cpp:
(JSC::DFG::AbstractState::execute):
* dfg/DFGAdjacencyList.h:
(JSC::DFG::AdjacencyList::AdjacencyList):
(AdjacencyList):
* dfg/DFGArrayMode.cpp:
(JSC::DFG::fromObserved):
(JSC::DFG::modeAlreadyChecked):
(JSC::DFG::modeToString):
* dfg/DFGArrayMode.h:
(DFG):
(JSC::DFG::modeUsesButterfly):
(JSC::DFG::modeIsJSArray):
(JSC::DFG::isInBoundsAccess):
(JSC::DFG::modeSupportsLength):
* dfg/DFGByteCodeParser.cpp:
(JSC::DFG::ByteCodeParser::handleGetByOffset):
(JSC::DFG::ByteCodeParser::parseBlock):
* dfg/DFGCSEPhase.cpp:
(JSC::DFG::CSEPhase::getPropertyStorageLoadElimination):
(JSC::DFG::CSEPhase::performNodeCSE):
* dfg/DFGFixupPhase.cpp:
(JSC::DFG::FixupPhase::fixupNode):
(JSC::DFG::FixupPhase::addNode):
(FixupPhase):
(JSC::DFG::FixupPhase::checkArray):
* dfg/DFGGraph.h:
(JSC::DFG::Graph::byValIsPure):
* dfg/DFGNode.h:
(JSC::DFG::Node::Node):
(Node):
* dfg/DFGNodeType.h:
(DFG):
* dfg/DFGOperations.cpp:
(JSC::DFG::putByVal):
* dfg/DFGOperations.h:
* dfg/DFGPredictionPropagationPhase.cpp:
(JSC::DFG::PredictionPropagationPhase::propagate):
* dfg/DFGRepatch.cpp:
(JSC::DFG::generateProtoChainAccessStub):
(JSC::DFG::tryCacheGetByID):
(JSC::DFG::tryBuildGetByIDList):
(JSC::DFG::emitPutReplaceStub):
(JSC::DFG::emitPutTransitionStub):
(JSC::DFG::tryBuildPutByIdList):
* dfg/DFGSpeculativeJIT.cpp:
(JSC::DFG::SpeculativeJIT::checkArray):
(JSC::DFG::SpeculativeJIT::compileGetIndexedPropertyStorage):
(JSC::DFG::SpeculativeJIT::compileGetArrayLength):
(JSC::DFG::SpeculativeJIT::compileAllocatePropertyStorage):
(JSC::DFG::SpeculativeJIT::compileReallocatePropertyStorage):
* dfg/DFGSpeculativeJIT.h:
(JSC::DFG::SpeculativeJIT::callOperation):
(JSC::DFG::SpeculativeJIT::emitAllocateBasicJSObject):
* dfg/DFGSpeculativeJIT32_64.cpp:
(JSC::DFG::SpeculativeJIT::cachedGetById):
(JSC::DFG::SpeculativeJIT::cachedPutById):
(JSC::DFG::SpeculativeJIT::compile):
* dfg/DFGSpeculativeJIT64.cpp:
(JSC::DFG::SpeculativeJIT::cachedGetById):
(JSC::DFG::SpeculativeJIT::cachedPutById):
(JSC::DFG::SpeculativeJIT::compile):
* dfg/DFGStructureCheckHoistingPhase.cpp:
(JSC::DFG::StructureCheckHoistingPhase::run):
* heap/CopiedSpace.h:
(CopiedSpace):
* jit/JIT.h:
* jit/JITInlineMethods.h:
(JSC::JIT::emitAllocateBasicJSObject):
(JSC::JIT::emitAllocateBasicStorage):
(JSC::JIT::emitAllocateJSArray):
* jit/JITOpcodes.cpp:
(JSC::JIT::emit_op_new_array):
(JSC::JIT::emitSlow_op_new_array):
* jit/JITPropertyAccess.cpp:
(JSC::JIT::emit_op_get_by_val):
(JSC::JIT::compileGetDirectOffset):
(JSC::JIT::emit_op_put_by_val):
(JSC::JIT::compileGetByIdHotPath):
(JSC::JIT::emit_op_put_by_id):
(JSC::JIT::compilePutDirectOffset):
(JSC::JIT::privateCompilePatchGetArrayLength):
* jit/JITPropertyAccess32_64.cpp:
(JSC::JIT::emit_op_get_by_val):
(JSC::JIT::emit_op_put_by_val):
(JSC::JIT::compileGetByIdHotPath):
(JSC::JIT::emit_op_put_by_id):
(JSC::JIT::compilePutDirectOffset):
(JSC::JIT::compileGetDirectOffset):
(JSC::JIT::privateCompilePatchGetArrayLength):
* jit/JITStubs.cpp:
(JSC::DEFINE_STUB_FUNCTION):
* jsc.cpp:
* llint/LLIntSlowPaths.cpp:
(JSC::LLInt::LLINT_SLOW_PATH_DECL):
* llint/LowLevelInterpreter.asm:
* llint/LowLevelInterpreter32_64.asm:
* llint/LowLevelInterpreter64.asm:
* runtime/Arguments.cpp:
(JSC::Arguments::deletePropertyByIndex):
(JSC::Arguments::defineOwnProperty):
* runtime/ArrayConstructor.cpp:
* runtime/ArrayConventions.h: Added.
(JSC):
(JSC::isDenseEnoughForVector):
(JSC::indexingHeaderForArray):
(JSC::baseIndexingHeaderForArray):
* runtime/ArrayPrototype.cpp:
(JSC::ArrayPrototype::create):
(JSC):
(JSC::ArrayPrototype::ArrayPrototype):
(JSC::arrayProtoFuncToString):
(JSC::arrayProtoFuncJoin):
(JSC::arrayProtoFuncSort):
(JSC::arrayProtoFuncFilter):
(JSC::arrayProtoFuncMap):
(JSC::arrayProtoFuncEvery):
(JSC::arrayProtoFuncForEach):
(JSC::arrayProtoFuncSome):
(JSC::arrayProtoFuncReduce):
(JSC::arrayProtoFuncReduceRight):
* runtime/ArrayPrototype.h:
(ArrayPrototype):
(JSC::ArrayPrototype::createStructure):
* runtime/ArrayStorage.h: Added.
(JSC):
(ArrayStorage):
(JSC::ArrayStorage::ArrayStorage):
(JSC::ArrayStorage::from):
(JSC::ArrayStorage::butterfly):
(JSC::ArrayStorage::indexingHeader):
(JSC::ArrayStorage::length):
(JSC::ArrayStorage::setLength):
(JSC::ArrayStorage::vectorLength):
(JSC::ArrayStorage::setVectorLength):
(JSC::ArrayStorage::copyHeaderFromDuringGC):
(JSC::ArrayStorage::inSparseMode):
(JSC::ArrayStorage::lengthOffset):
(JSC::ArrayStorage::vectorLengthOffset):
(JSC::ArrayStorage::numValuesInVectorOffset):
(JSC::ArrayStorage::vectorOffset):
(JSC::ArrayStorage::indexBiasOffset):
(JSC::ArrayStorage::sparseMapOffset):
(JSC::ArrayStorage::sizeFor):
* runtime/Butterfly.h: Added.
(JSC):
(Butterfly):
(JSC::Butterfly::Butterfly):
(JSC::Butterfly::totalSize):
(JSC::Butterfly::fromBase):
(JSC::Butterfly::offsetOfIndexingHeader):
(JSC::Butterfly::offsetOfPublicLength):
(JSC::Butterfly::offsetOfVectorLength):
(JSC::Butterfly::indexingHeader):
(JSC::Butterfly::propertyStorage):
(JSC::Butterfly::indexingPayload):
(JSC::Butterfly::arrayStorage):
(JSC::Butterfly::offsetOfPropertyStorage):
(JSC::Butterfly::indexOfPropertyStorage):
(JSC::Butterfly::base):
* runtime/ButterflyInlineMethods.h: Added.
(JSC):
(JSC::Butterfly::createUninitialized):
(JSC::Butterfly::create):
(JSC::Butterfly::createUninitializedDuringCollection):
(JSC::Butterfly::base):
(JSC::Butterfly::growPropertyStorage):
(JSC::Butterfly::growArrayRight):
(JSC::Butterfly::resizeArray):
(JSC::Butterfly::unshift):
(JSC::Butterfly::shift):
* runtime/ClassInfo.h:
(MethodTable):
(JSC):
* runtime/IndexingHeader.h: Added.
(JSC):
(IndexingHeader):
(JSC::IndexingHeader::offsetOfIndexingHeader):
(JSC::IndexingHeader::offsetOfPublicLength):
(JSC::IndexingHeader::offsetOfVectorLength):
(JSC::IndexingHeader::IndexingHeader):
(JSC::IndexingHeader::vectorLength):
(JSC::IndexingHeader::setVectorLength):
(JSC::IndexingHeader::publicLength):
(JSC::IndexingHeader::setPublicLength):
(JSC::IndexingHeader::from):
(JSC::IndexingHeader::fromEndOf):
(JSC::IndexingHeader::propertyStorage):
(JSC::IndexingHeader::arrayStorage):
(JSC::IndexingHeader::butterfly):
* runtime/IndexingHeaderInlineMethods.h: Added.
(JSC):
(JSC::IndexingHeader::preCapacity):
(JSC::IndexingHeader::indexingPayloadSizeInBytes):
* runtime/IndexingType.h: Added.
(JSC):
(JSC::hasIndexingHeader):
* runtime/JSActivation.cpp:
(JSC::JSActivation::JSActivation):
(JSC::JSActivation::visitChildren):
(JSC::JSActivation::getOwnNonIndexPropertyNames):
* runtime/JSActivation.h:
(JSActivation):
(JSC::JSActivation::tearOff):
* runtime/JSArray.cpp:
(JSC):
(JSC::createArrayButterflyInDictionaryIndexingMode):
(JSC::JSArray::setLengthWritable):
(JSC::JSArray::defineOwnProperty):
(JSC::JSArray::getOwnPropertySlot):
(JSC::JSArray::getOwnPropertyDescriptor):
(JSC::JSArray::put):
(JSC::JSArray::deleteProperty):
(JSC::JSArray::getOwnNonIndexPropertyNames):
(JSC::JSArray::unshiftCountSlowCase):
(JSC::JSArray::setLength):
(JSC::JSArray::pop):
(JSC::JSArray::push):
(JSC::JSArray::shiftCount):
(JSC::JSArray::unshiftCount):
(JSC::JSArray::sortNumeric):
(JSC::JSArray::sort):
(JSC::JSArray::fillArgList):
(JSC::JSArray::copyToArguments):
(JSC::JSArray::compactForSorting):
* runtime/JSArray.h:
(JSC):
(JSArray):
(JSC::JSArray::JSArray):
(JSC::JSArray::length):
(JSC::JSArray::createStructure):
(JSC::JSArray::isLengthWritable):
(JSC::createArrayButterfly):
(JSC::JSArray::create):
(JSC::JSArray::tryCreateUninitialized):
* runtime/JSBoundFunction.cpp:
(JSC::boundFunctionCall):
(JSC::boundFunctionConstruct):
(JSC::JSBoundFunction::finishCreation):
* runtime/JSCell.cpp:
(JSC::JSCell::getOwnNonIndexPropertyNames):
(JSC):
* runtime/JSCell.h:
(JSCell):
* runtime/JSFunction.cpp:
(JSC::JSFunction::getOwnPropertySlot):
(JSC::JSFunction::getOwnPropertyDescriptor):
(JSC::JSFunction::getOwnNonIndexPropertyNames):
(JSC::JSFunction::defineOwnProperty):
* runtime/JSFunction.h:
(JSFunction):
* runtime/JSGlobalData.cpp:
(JSC::JSGlobalData::JSGlobalData):
* runtime/JSGlobalData.h:
(JSGlobalData):
* runtime/JSGlobalObject.cpp:
(JSC::JSGlobalObject::reset):
* runtime/JSONObject.cpp:
(JSC::Stringifier::Holder::appendNextProperty):
(JSC::Walker::walk):
* runtime/JSObject.cpp:
(JSC):
(JSC::JSObject::visitButterfly):
(JSC::JSObject::visitChildren):
(JSC::JSFinalObject::visitChildren):
(JSC::JSObject::getOwnPropertySlotByIndex):
(JSC::JSObject::put):
(JSC::JSObject::putByIndex):
(JSC::JSObject::enterDictionaryIndexingModeWhenArrayStorageAlreadyExists):
(JSC::JSObject::enterDictionaryIndexingMode):
(JSC::JSObject::createArrayStorage):
(JSC::JSObject::createInitialArrayStorage):
(JSC::JSObject::ensureArrayStorageExistsAndEnterDictionaryIndexingMode):
(JSC::JSObject::putDirectAccessor):
(JSC::JSObject::deleteProperty):
(JSC::JSObject::deletePropertyByIndex):
(JSC::JSObject::getOwnPropertyNames):
(JSC::JSObject::getOwnNonIndexPropertyNames):
(JSC::JSObject::preventExtensions):
(JSC::JSObject::fillGetterPropertySlot):
(JSC::JSObject::putIndexedDescriptor):
(JSC::JSObject::defineOwnIndexedProperty):
(JSC::JSObject::allocateSparseIndexMap):
(JSC::JSObject::deallocateSparseIndexMap):
(JSC::JSObject::putByIndexBeyondVectorLengthWithArrayStorage):
(JSC::JSObject::putByIndexBeyondVectorLength):
(JSC::JSObject::putDirectIndexBeyondVectorLengthWithArrayStorage):
(JSC::JSObject::putDirectIndexBeyondVectorLength):
(JSC::JSObject::getNewVectorLength):
(JSC::JSObject::increaseVectorLength):
(JSC::JSObject::checkIndexingConsistency):
(JSC::JSObject::growOutOfLineStorage):
(JSC::JSObject::getOwnPropertyDescriptor):
(JSC::putDescriptor):
(JSC::JSObject::putDirectMayBeIndex):
(JSC::JSObject::defineOwnNonIndexProperty):
(JSC::JSObject::defineOwnProperty):
(JSC::JSObject::getOwnPropertySlotSlow):
* runtime/JSObject.h:
(JSC::JSObject::getArrayLength):
(JSObject):
(JSC::JSObject::getVectorLength):
(JSC::JSObject::putDirectIndex):
(JSC::JSObject::canGetIndexQuickly):
(JSC::JSObject::getIndexQuickly):
(JSC::JSObject::canSetIndexQuickly):
(JSC::JSObject::setIndexQuickly):
(JSC::JSObject::initializeIndex):
(JSC::JSObject::completeInitialization):
(JSC::JSObject::inSparseIndexingMode):
(JSC::JSObject::butterfly):
(JSC::JSObject::outOfLineStorage):
(JSC::JSObject::offsetForLocation):
(JSC::JSObject::indexingShouldBeSparse):
(JSC::JSObject::butterflyOffset):
(JSC::JSObject::butterflyAddress):
(JSC::JSObject::arrayStorage):
(JSC::JSObject::arrayStorageOrZero):
(JSC::JSObject::ensureArrayStorage):
(JSC::JSObject::checkIndexingConsistency):
(JSC::JSNonFinalObject::JSNonFinalObject):
(JSC):
(JSC::JSObject::setButterfly):
(JSC::JSObject::setButterflyWithoutChangingStructure):
(JSC::JSObject::JSObject):
(JSC::JSObject::inlineGetOwnPropertySlot):
(JSC::JSObject::putDirectInternal):
(JSC::JSObject::setStructureAndReallocateStorageIfNecessary):
(JSC::JSObject::putDirectWithoutTransition):
(JSC::offsetInButterfly):
(JSC::offsetRelativeToPatchedStorage):
(JSC::indexRelativeToBase):
(JSC::offsetRelativeToBase):
* runtime/JSPropertyNameIterator.cpp:
(JSC::JSPropertyNameIterator::create):
* runtime/JSSymbolTableObject.cpp:
(JSC::JSSymbolTableObject::getOwnNonIndexPropertyNames):
* runtime/JSSymbolTableObject.h:
(JSSymbolTableObject):
* runtime/JSTypeInfo.h:
(JSC):
(JSC::TypeInfo::interceptsGetOwnPropertySlotByIndexEvenWhenLengthIsNotZero):
(JSC::TypeInfo::overridesGetPropertyNames):
* runtime/LiteralParser.cpp:
(JSC::::parse):
* runtime/ObjectConstructor.cpp:
* runtime/ObjectPrototype.cpp:
(JSC::ObjectPrototype::ObjectPrototype):
(JSC):
* runtime/ObjectPrototype.h:
(ObjectPrototype):
* runtime/PropertyOffset.h:
(JSC::offsetInOutOfLineStorage):
* runtime/PropertyStorage.h: Added.
(JSC):
* runtime/PutDirectIndexMode.h: Added.
(JSC):
* runtime/RegExpMatchesArray.cpp:
(JSC::RegExpMatchesArray::RegExpMatchesArray):
(JSC):
(JSC::RegExpMatchesArray::create):
(JSC::RegExpMatchesArray::finishCreation):
* runtime/RegExpMatchesArray.h:
(RegExpMatchesArray):
(JSC::RegExpMatchesArray::createStructure):
* runtime/RegExpObject.cpp:
(JSC::RegExpObject::getOwnNonIndexPropertyNames):
* runtime/RegExpObject.h:
(RegExpObject):
* runtime/Reject.h: Added.
(JSC):
(JSC::reject):
* runtime/SparseArrayValueMap.cpp: Added.
(JSC):
* runtime/SparseArrayValueMap.h: Added.
(JSC):
(SparseArrayEntry):
(JSC::SparseArrayEntry::SparseArrayEntry):
(SparseArrayValueMap):
(JSC::SparseArrayValueMap::sparseMode):
(JSC::SparseArrayValueMap::setSparseMode):
(JSC::SparseArrayValueMap::lengthIsReadOnly):
(JSC::SparseArrayValueMap::setLengthIsReadOnly):
(JSC::SparseArrayValueMap::find):
(JSC::SparseArrayValueMap::remove):
(JSC::SparseArrayValueMap::notFound):
(JSC::SparseArrayValueMap::isEmpty):
(JSC::SparseArrayValueMap::contains):
(JSC::SparseArrayValueMap::size):
(JSC::SparseArrayValueMap::begin):
(JSC::SparseArrayValueMap::end):
* runtime/SparseArrayValueMapInlineMethods.h: Added.
(JSC):
(JSC::SparseArrayValueMap::SparseArrayValueMap):
(JSC::SparseArrayValueMap::~SparseArrayValueMap):
(JSC::SparseArrayValueMap::finishCreation):
(JSC::SparseArrayValueMap::create):
(JSC::SparseArrayValueMap::destroy):
(JSC::SparseArrayValueMap::createStructure):
(JSC::SparseArrayValueMap::add):
(JSC::SparseArrayValueMap::putEntry):
(JSC::SparseArrayValueMap::putDirect):
(JSC::SparseArrayEntry::get):
(JSC::SparseArrayEntry::getNonSparseMode):
(JSC::SparseArrayValueMap::visitChildren):
* runtime/StorageBarrier.h: Removed.
* runtime/StringObject.cpp:
(JSC::StringObject::putByIndex):
(JSC):
(JSC::StringObject::deletePropertyByIndex):
* runtime/StringObject.h:
(StringObject):
* runtime/StringPrototype.cpp:
* runtime/Structure.cpp:
(JSC::Structure::Structure):
(JSC::Structure::materializePropertyMap):
(JSC::Structure::nonPropertyTransition):
(JSC):
* runtime/Structure.h:
(Structure):
(JSC::Structure::indexingType):
(JSC::Structure::indexingTypeIncludingHistory):
(JSC::Structure::indexingTypeOffset):
(JSC::Structure::create):
* runtime/StructureTransitionTable.h:
(JSC):
(JSC::toAttributes):
(JSC::newIndexingType):
(JSC::StructureTransitionTable::Hash::hash):
* tests/mozilla/js1_6/Array/regress-304828.js:

Source/WebCore:

Teach the DOM that to intercept get/put on indexed properties, you now have
to override getOwnPropertySlotByIndex and putByIndex.

No new tests because no new behavior. One test was rebased because indexed
property iteration order now matches other engines (indexed properties always
come first).

* bindings/js/ArrayValue.cpp:
(WebCore::ArrayValue::get):
* bindings/js/JSBlobCustom.cpp:
(WebCore::JSBlobConstructor::constructJSBlob):
* bindings/js/JSCanvasRenderingContext2DCustom.cpp:
(WebCore::JSCanvasRenderingContext2D::setWebkitLineDash):
* bindings/js/JSDOMStringListCustom.cpp:
(WebCore::toDOMStringList):
* bindings/js/JSDOMStringMapCustom.cpp:
(WebCore::JSDOMStringMap::deletePropertyByIndex):
(WebCore):
* bindings/js/JSDOMWindowCustom.cpp:
(WebCore::JSDOMWindow::getOwnPropertySlot):
(WebCore::JSDOMWindow::getOwnPropertySlotByIndex):
(WebCore):
(WebCore::JSDOMWindow::putByIndex):
(WebCore::JSDOMWindow::deletePropertyByIndex):
* bindings/js/JSDOMWindowShell.cpp:
(WebCore::JSDOMWindowShell::getOwnPropertySlotByIndex):
(WebCore):
(WebCore::JSDOMWindowShell::putByIndex):
(WebCore::JSDOMWindowShell::deletePropertyByIndex):
* bindings/js/JSDOMWindowShell.h:
(JSDOMWindowShell):
* bindings/js/JSHistoryCustom.cpp:
(WebCore::JSHistory::deletePropertyByIndex):
(WebCore):
* bindings/js/JSInspectorFrontendHostCustom.cpp:
(WebCore::populateContextMenuItems):
* bindings/js/JSLocationCustom.cpp:
(WebCore::JSLocation::deletePropertyByIndex):
(WebCore):
* bindings/js/JSStorageCustom.cpp:
(WebCore::JSStorage::deletePropertyByIndex):
(WebCore):
* bindings/js/JSWebSocketCustom.cpp:
(WebCore::JSWebSocketConstructor::constructJSWebSocket):
* bindings/js/ScriptValue.cpp:
(WebCore::jsToInspectorValue):
* bindings/js/SerializedScriptValue.cpp:
(WebCore::CloneSerializer::serialize):
* bindings/scripts/CodeGeneratorJS.pm:
(GenerateHeader):
(GenerateImplementation):
* bridge/runtime_array.cpp:
(JSC::RuntimeArray::RuntimeArray):
* bridge/runtime_array.h:
(JSC::RuntimeArray::createStructure):
(RuntimeArray):

LayoutTests:

Modify the JSON test to indicate that iterating over properties now returns
indexed properties first. This is a behavior change that makes us more
compliant with other implementations.

Also check in new expected file for the edge cases of indexed property access
with prototype accessors. This changeset introduces a known regression in that
department, which is tracked here: https://bugs.webkit.org/show_bug.cgi?id=96596

* fast/js/resources/JSON-stringify.js:
* platform/mac/fast/js/primitive-property-access-edge-cases-expected.txt: Added.

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@128400 268f45cc-cd09-0410-ab3c-d52691b4dbfc

118 files changed:
LayoutTests/ChangeLog
LayoutTests/fast/js/resources/JSON-stringify.js
LayoutTests/platform/mac/fast/js/primitive-property-access-edge-cases-expected.txt [new file with mode: 0644]
Source/JavaScriptCore/API/JSCallbackObject.h
Source/JavaScriptCore/API/JSCallbackObjectFunctions.h
Source/JavaScriptCore/API/JSObjectRef.cpp
Source/JavaScriptCore/CMakeLists.txt
Source/JavaScriptCore/ChangeLog
Source/JavaScriptCore/GNUmakefile.list.am
Source/JavaScriptCore/JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.def
Source/JavaScriptCore/JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.vcproj
Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj
Source/JavaScriptCore/Target.pri
Source/JavaScriptCore/bytecode/ArrayProfile.h
Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp
Source/JavaScriptCore/dfg/DFGAbstractState.cpp
Source/JavaScriptCore/dfg/DFGAdjacencyList.h
Source/JavaScriptCore/dfg/DFGArrayMode.cpp
Source/JavaScriptCore/dfg/DFGArrayMode.h
Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp
Source/JavaScriptCore/dfg/DFGCSEPhase.cpp
Source/JavaScriptCore/dfg/DFGFixupPhase.cpp
Source/JavaScriptCore/dfg/DFGGraph.h
Source/JavaScriptCore/dfg/DFGNode.h
Source/JavaScriptCore/dfg/DFGNodeType.h
Source/JavaScriptCore/dfg/DFGOperations.cpp
Source/JavaScriptCore/dfg/DFGOperations.h
Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp
Source/JavaScriptCore/dfg/DFGRepatch.cpp
Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp
Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h
Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp
Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp
Source/JavaScriptCore/dfg/DFGStructureCheckHoistingPhase.cpp
Source/JavaScriptCore/heap/CopiedSpace.h
Source/JavaScriptCore/jit/JIT.h
Source/JavaScriptCore/jit/JITInlineMethods.h
Source/JavaScriptCore/jit/JITOpcodes.cpp
Source/JavaScriptCore/jit/JITPropertyAccess.cpp
Source/JavaScriptCore/jit/JITPropertyAccess32_64.cpp
Source/JavaScriptCore/jit/JITStubs.cpp
Source/JavaScriptCore/jsc.cpp
Source/JavaScriptCore/llint/LLIntSlowPaths.cpp
Source/JavaScriptCore/llint/LowLevelInterpreter.asm
Source/JavaScriptCore/llint/LowLevelInterpreter32_64.asm
Source/JavaScriptCore/llint/LowLevelInterpreter64.asm
Source/JavaScriptCore/runtime/Arguments.cpp
Source/JavaScriptCore/runtime/ArrayConstructor.cpp
Source/JavaScriptCore/runtime/ArrayConventions.h [new file with mode: 0644]
Source/JavaScriptCore/runtime/ArrayPrototype.cpp
Source/JavaScriptCore/runtime/ArrayPrototype.h
Source/JavaScriptCore/runtime/ArrayStorage.h [new file with mode: 0644]
Source/JavaScriptCore/runtime/Butterfly.h [new file with mode: 0644]
Source/JavaScriptCore/runtime/ButterflyInlineMethods.h [new file with mode: 0644]
Source/JavaScriptCore/runtime/ClassInfo.h
Source/JavaScriptCore/runtime/IndexingHeader.h [new file with mode: 0644]
Source/JavaScriptCore/runtime/IndexingHeaderInlineMethods.h [new file with mode: 0644]
Source/JavaScriptCore/runtime/IndexingType.h [new file with mode: 0644]
Source/JavaScriptCore/runtime/JSActivation.cpp
Source/JavaScriptCore/runtime/JSActivation.h
Source/JavaScriptCore/runtime/JSArray.cpp
Source/JavaScriptCore/runtime/JSArray.h
Source/JavaScriptCore/runtime/JSBoundFunction.cpp
Source/JavaScriptCore/runtime/JSCell.cpp
Source/JavaScriptCore/runtime/JSCell.h
Source/JavaScriptCore/runtime/JSFunction.cpp
Source/JavaScriptCore/runtime/JSFunction.h
Source/JavaScriptCore/runtime/JSGlobalData.cpp
Source/JavaScriptCore/runtime/JSGlobalData.h
Source/JavaScriptCore/runtime/JSGlobalObject.cpp
Source/JavaScriptCore/runtime/JSONObject.cpp
Source/JavaScriptCore/runtime/JSObject.cpp
Source/JavaScriptCore/runtime/JSObject.h
Source/JavaScriptCore/runtime/JSPropertyNameIterator.cpp
Source/JavaScriptCore/runtime/JSSymbolTableObject.cpp
Source/JavaScriptCore/runtime/JSSymbolTableObject.h
Source/JavaScriptCore/runtime/JSTypeInfo.h
Source/JavaScriptCore/runtime/LiteralParser.cpp
Source/JavaScriptCore/runtime/ObjectConstructor.cpp
Source/JavaScriptCore/runtime/ObjectPrototype.cpp
Source/JavaScriptCore/runtime/ObjectPrototype.h
Source/JavaScriptCore/runtime/PropertyOffset.h
Source/JavaScriptCore/runtime/PropertyStorage.h [moved from Source/JavaScriptCore/runtime/StorageBarrier.h with 52% similarity]
Source/JavaScriptCore/runtime/PutDirectIndexMode.h [new file with mode: 0644]
Source/JavaScriptCore/runtime/RegExpMatchesArray.cpp
Source/JavaScriptCore/runtime/RegExpMatchesArray.h
Source/JavaScriptCore/runtime/RegExpObject.cpp
Source/JavaScriptCore/runtime/RegExpObject.h
Source/JavaScriptCore/runtime/Reject.h [new file with mode: 0644]
Source/JavaScriptCore/runtime/SparseArrayValueMap.cpp [new file with mode: 0644]
Source/JavaScriptCore/runtime/SparseArrayValueMap.h [new file with mode: 0644]
Source/JavaScriptCore/runtime/SparseArrayValueMapInlineMethods.h [new file with mode: 0644]
Source/JavaScriptCore/runtime/StringObject.cpp
Source/JavaScriptCore/runtime/StringObject.h
Source/JavaScriptCore/runtime/StringPrototype.cpp
Source/JavaScriptCore/runtime/Structure.cpp
Source/JavaScriptCore/runtime/Structure.h
Source/JavaScriptCore/runtime/StructureTransitionTable.h
Source/JavaScriptCore/tests/mozilla/js1_6/Array/regress-304828.js
Source/WebCore/ChangeLog
Source/WebCore/bindings/js/ArrayValue.cpp
Source/WebCore/bindings/js/JSBlobCustom.cpp
Source/WebCore/bindings/js/JSCanvasRenderingContext2DCustom.cpp
Source/WebCore/bindings/js/JSDOMStringListCustom.cpp
Source/WebCore/bindings/js/JSDOMStringMapCustom.cpp
Source/WebCore/bindings/js/JSDOMWindowCustom.cpp
Source/WebCore/bindings/js/JSDOMWindowShell.cpp
Source/WebCore/bindings/js/JSDOMWindowShell.h
Source/WebCore/bindings/js/JSHistoryCustom.cpp
Source/WebCore/bindings/js/JSInspectorFrontendHostCustom.cpp
Source/WebCore/bindings/js/JSLocationCustom.cpp
Source/WebCore/bindings/js/JSStorageCustom.cpp
Source/WebCore/bindings/js/JSWebSocketCustom.cpp
Source/WebCore/bindings/js/ScriptValue.cpp
Source/WebCore/bindings/js/SerializedScriptValue.cpp
Source/WebCore/bindings/scripts/CodeGeneratorJS.pm
Source/WebCore/bridge/runtime_array.cpp
Source/WebCore/bridge/runtime_array.h

index e4e25e9..e5c53cc 100644 (file)
@@ -1,3 +1,21 @@
+2012-09-12  Filip Pizlo  <fpizlo@apple.com>
+
+        JSC should have property butterflies
+        https://bugs.webkit.org/show_bug.cgi?id=91933
+
+        Reviewed by Geoffrey Garen.
+
+        Modify the JSON test to indicate that iterating over properties now returns
+        indexed properties first. This is a behavior change that makes us more
+        compliant with other implementations.
+        
+        Also check in new expected file for the edge cases of indexed property access
+        with prototype accessors. This changeset introduces a known regression in that
+        department, which is tracked here: https://bugs.webkit.org/show_bug.cgi?id=96596
+
+        * fast/js/resources/JSON-stringify.js:
+        * platform/mac/fast/js/primitive-property-access-edge-cases-expected.txt: Added.
+
 2012-09-12  Kent Tamura  <tkent@chromium.org>
 
         [Chromium] Test expectation update
index 622d023..22ff8ce 100644 (file)
@@ -334,7 +334,7 @@ function createTests() {
         jsonObject.stringify({a:"a", b:"b", c:"c", 3: "d", 2: "e", 1: "f"}, replaceFunc);
         return replaceTracker;
     });
-    result[result.length - 1].expected = '(string){"a":"a","b":"b","c":"c","3":"d","2":"e","1":"f"};a(string)"a";b(string)"b";c(string)"c";3(string)"d";2(string)"e";1(string)"f";';
+    result[result.length - 1].expected = '(string){"1":"f","2":"e","3":"d","a":"a","b":"b","c":"c"};1(string)"f";2(string)"e";3(string)"d";a(string)"a";b(string)"b";c(string)"c";';
     result.push(function(jsonObject){
         var count = 0;
         var array = [{toString:function(){count++; array[0]='a'; array[1]='c'; array[2]='b'; return 'a'}}];
diff --git a/LayoutTests/platform/mac/fast/js/primitive-property-access-edge-cases-expected.txt b/LayoutTests/platform/mac/fast/js/primitive-property-access-edge-cases-expected.txt
new file mode 100644 (file)
index 0000000..827fbbf
--- /dev/null
@@ -0,0 +1,58 @@
+This page tests for assertion failures in edge cases of property lookup on primitive values.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS checkGet(1, Number) is true
+PASS checkGet('hello', String) is true
+PASS checkGet(true, Boolean) is true
+PASS checkSet(1, Number) is true
+PASS checkSet('hello', String) is true
+PASS checkSet(true, Boolean) is true
+PASS checkGetStrict(1, Number) is true
+PASS checkGetStrict('hello', String) is true
+PASS checkGetStrict(true, Boolean) is true
+PASS checkSetStrict(1, Number) is true
+PASS checkSetStrict('hello', String) is true
+PASS checkSetStrict(true, Boolean) is true
+PASS checkRead(1, Number) is true
+PASS checkRead('hello', String) is true
+PASS checkRead(true, Boolean) is true
+PASS checkWrite(1, Number) is true
+PASS checkWrite('hello', String) is true
+PASS checkWrite(true, Boolean) is true
+PASS checkReadStrict(1, Number) is true
+PASS checkReadStrict('hello', String) is true
+PASS checkReadStrict(true, Boolean) is true
+PASS checkWriteStrict(1, Number) threw exception TypeError: Attempted to assign to readonly property..
+PASS checkWriteStrict('hello', String) threw exception TypeError: Attempted to assign to readonly property..
+PASS checkWriteStrict(true, Boolean) threw exception TypeError: Attempted to assign to readonly property..
+PASS checkNumericGet(1, Number) is true
+PASS checkNumericGet('hello', String) is true
+PASS checkNumericGet(true, Boolean) is true
+FAIL checkNumericSet(1, Number) should be true. Was false.
+FAIL checkNumericSet('hello', String) should be true. Was false.
+FAIL checkNumericSet(true, Boolean) should be true. Was false.
+PASS checkNumericGetStrict(1, Number) is true
+PASS checkNumericGetStrict('hello', String) is true
+PASS checkNumericGetStrict(true, Boolean) is true
+FAIL checkNumericSetStrict(1, Number) should be true. Was false.
+FAIL checkNumericSetStrict('hello', String) should be true. Was false.
+FAIL checkNumericSetStrict(true, Boolean) should be true. Was false.
+PASS checkNumericRead(1, Number) is true
+PASS checkNumericRead('hello', String) is true
+PASS checkNumericRead(true, Boolean) is true
+PASS checkNumericWrite(1, Number) is true
+PASS checkNumericWrite('hello', String) is true
+PASS checkNumericWrite(true, Boolean) is true
+PASS checkNumericReadStrict(1, Number) is true
+PASS checkNumericReadStrict('hello', String) is true
+PASS checkNumericReadStrict(true, Boolean) is true
+PASS checkNumericWriteStrict(1, Number) threw exception TypeError: Attempted to assign to readonly property..
+PASS checkNumericWriteStrict('hello', String) threw exception TypeError: Attempted to assign to readonly property..
+PASS checkNumericWriteStrict(true, Boolean) threw exception TypeError: Attempted to assign to readonly property..
+PASS didNotCrash is true
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
index 36d7fa9..8d7aedd 100644 (file)
@@ -168,7 +168,7 @@ public:
     using Parent::methodTable;
 
 protected:
-    static const unsigned StructureFlags = ProhibitsPropertyCaching | OverridesGetOwnPropertySlot | ImplementsHasInstance | OverridesHasInstance | OverridesVisitChildren | OverridesGetPropertyNames | Parent::StructureFlags;
+    static const unsigned StructureFlags = ProhibitsPropertyCaching | OverridesGetOwnPropertySlot | InterceptsGetOwnPropertySlotByIndexEvenWhenLengthIsNotZero | ImplementsHasInstance | OverridesHasInstance | OverridesVisitChildren | OverridesGetPropertyNames | Parent::StructureFlags;
 
 private:
     static String className(const JSObject*);
@@ -178,6 +178,7 @@ private:
     static JSValue defaultValue(const JSObject*, ExecState*, PreferredPrimitiveType);
 
     static bool getOwnPropertySlot(JSCell*, ExecState*, PropertyName, PropertySlot&);
+    static bool getOwnPropertySlotByIndex(JSCell*, ExecState*, unsigned propertyName, PropertySlot&);
     static bool getOwnPropertyDescriptor(JSObject*, ExecState*, PropertyName, PropertyDescriptor&);
     
     static void put(JSCell*, ExecState*, PropertyName, JSValue, PutPropertySlot&);
@@ -187,7 +188,7 @@ private:
 
     static bool hasInstance(JSObject*, ExecState*, JSValue, JSValue proto);
 
-    static void getOwnPropertyNames(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode);
+    static void getOwnNonIndexPropertyNames(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode);
 
     static ConstructType getConstructData(JSCell*, ConstructData&);
     static CallType getCallData(JSCell*, CallData&);
index 0691daf..39d0782 100644 (file)
@@ -183,6 +183,12 @@ bool JSCallbackObject<Parent>::getOwnPropertySlot(JSCell* cell, ExecState* exec,
 }
 
 template <class Parent>
+bool JSCallbackObject<Parent>::getOwnPropertySlotByIndex(JSCell* cell, ExecState* exec, unsigned propertyName, PropertySlot& slot)
+{
+    return cell->methodTable()->getOwnPropertySlot(cell, exec, Identifier::from(exec, propertyName), slot);
+}
+
+template <class Parent>
 JSValue JSCallbackObject<Parent>::defaultValue(const JSObject* object, ExecState* exec, PreferredPrimitiveType hint)
 {
     const JSCallbackObject* thisObject = jsCast<const JSCallbackObject*>(object);
@@ -449,7 +455,7 @@ EncodedJSValue JSCallbackObject<Parent>::call(ExecState* exec)
 }
 
 template <class Parent>
-void JSCallbackObject<Parent>::getOwnPropertyNames(JSObject* object, ExecState* exec, PropertyNameArray& propertyNames, EnumerationMode mode)
+void JSCallbackObject<Parent>::getOwnNonIndexPropertyNames(JSObject* object, ExecState* exec, PropertyNameArray& propertyNames, EnumerationMode mode)
 {
     JSCallbackObject* thisObject = jsCast<JSCallbackObject*>(object);
     JSContextRef execRef = toRef(exec);
@@ -484,7 +490,7 @@ void JSCallbackObject<Parent>::getOwnPropertyNames(JSObject* object, ExecState*
         }
     }
     
-    Parent::getOwnPropertyNames(thisObject, exec, propertyNames, mode);
+    Parent::getOwnNonIndexPropertyNames(thisObject, exec, propertyNames, mode);
 }
 
 template <class Parent>
index e206cb1..7a8956e 100644 (file)
@@ -29,7 +29,9 @@
 #include "JSObjectRefPrivate.h"
 
 #include "APICast.h"
+#include "ButterflyInlineMethods.h"
 #include "CodeBlock.h"
+#include "CopiedSpaceInlineMethods.h"
 #include "DateConstructor.h"
 #include "ErrorConstructor.h"
 #include "FunctionConstructor.h"
index 2065c5b..9a2e7b5 100644 (file)
@@ -246,6 +246,7 @@ SET(JavaScriptCore_SOURCES
     runtime/RegExpObject.cpp
     runtime/RegExpPrototype.cpp
     runtime/SmallStrings.cpp
+    runtime/SparseArrayValueMap.cpp
     runtime/StrictEvalActivation.cpp
     runtime/StringConstructor.cpp
     runtime/StringObject.cpp
index ee88d91..cb6ab8e 100644 (file)
@@ -1,3 +1,480 @@
+2012-09-09  Filip Pizlo  <fpizlo@apple.com>
+
+        JSC should have property butterflies
+        https://bugs.webkit.org/show_bug.cgi?id=91933
+
+        Reviewed by Geoffrey Garen.
+
+        This changes the JSC object model. Previously, all objects had fast lookup for
+        named properties. Integer indexed properties were only fast if you used a
+        JSArray. With this change, all objects have fast indexed properties. This is
+        accomplished without any space overhead by using a bidirectional object layout,
+        aka butterflies. Each JSObject has a m_butterfly pointer where previously it
+        had a m_outOfLineStorage pointer. To the left of the location pointed to by
+        m_butterfly, we place all named out-of-line properties. To the right, we place
+        all indexed properties along with indexing meta-data. Though, some indexing
+        meta-data is placed in the 8-byte word immediately left of the pointed-to
+        location; this is in anticipation of the indexing meta-data being small enough
+        in the common case that m_butterfly always points to the first indexed
+        property.
+        
+        This is performance neutral, except on tests that use indexed properties on
+        plain objects, where the speed-up is in excess of an order of magnitude.
+        
+        One notable aspect of what this change brings is that it allows indexing
+        storage to morph over time. Currently this is only used to allow all non-array
+        objects to start out without any indexed storage. But it could be used for
+        some kinds of array type inference in the future.
+
+        * API/JSCallbackObject.h:
+        (JSCallbackObject):
+        * API/JSCallbackObjectFunctions.h:
+        (JSC::::getOwnPropertySlotByIndex):
+        (JSC):
+        (JSC::::getOwnNonIndexPropertyNames):
+        * API/JSObjectRef.cpp:
+        * CMakeLists.txt:
+        * GNUmakefile.list.am:
+        * JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.def:
+        * JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.vcproj:
+        * JavaScriptCore.xcodeproj/project.pbxproj:
+        * Target.pri:
+        * bytecode/ArrayProfile.h:
+        (JSC):
+        (JSC::arrayModeFromStructure):
+        * bytecompiler/BytecodeGenerator.cpp:
+        (JSC::BytecodeGenerator::emitDirectPutById):
+        * dfg/DFGAbstractState.cpp:
+        (JSC::DFG::AbstractState::execute):
+        * dfg/DFGAdjacencyList.h:
+        (JSC::DFG::AdjacencyList::AdjacencyList):
+        (AdjacencyList):
+        * dfg/DFGArrayMode.cpp:
+        (JSC::DFG::fromObserved):
+        (JSC::DFG::modeAlreadyChecked):
+        (JSC::DFG::modeToString):
+        * dfg/DFGArrayMode.h:
+        (DFG):
+        (JSC::DFG::modeUsesButterfly):
+        (JSC::DFG::modeIsJSArray):
+        (JSC::DFG::isInBoundsAccess):
+        (JSC::DFG::modeSupportsLength):
+        * dfg/DFGByteCodeParser.cpp:
+        (JSC::DFG::ByteCodeParser::handleGetByOffset):
+        (JSC::DFG::ByteCodeParser::parseBlock):
+        * dfg/DFGCSEPhase.cpp:
+        (JSC::DFG::CSEPhase::getPropertyStorageLoadElimination):
+        (JSC::DFG::CSEPhase::performNodeCSE):
+        * dfg/DFGFixupPhase.cpp:
+        (JSC::DFG::FixupPhase::fixupNode):
+        (JSC::DFG::FixupPhase::addNode):
+        (FixupPhase):
+        (JSC::DFG::FixupPhase::checkArray):
+        * dfg/DFGGraph.h:
+        (JSC::DFG::Graph::byValIsPure):
+        * dfg/DFGNode.h:
+        (JSC::DFG::Node::Node):
+        (Node):
+        * dfg/DFGNodeType.h:
+        (DFG):
+        * dfg/DFGOperations.cpp:
+        (JSC::DFG::putByVal):
+        * dfg/DFGOperations.h:
+        * dfg/DFGPredictionPropagationPhase.cpp:
+        (JSC::DFG::PredictionPropagationPhase::propagate):
+        * dfg/DFGRepatch.cpp:
+        (JSC::DFG::generateProtoChainAccessStub):
+        (JSC::DFG::tryCacheGetByID):
+        (JSC::DFG::tryBuildGetByIDList):
+        (JSC::DFG::emitPutReplaceStub):
+        (JSC::DFG::emitPutTransitionStub):
+        (JSC::DFG::tryBuildPutByIdList):
+        * dfg/DFGSpeculativeJIT.cpp:
+        (JSC::DFG::SpeculativeJIT::checkArray):
+        (JSC::DFG::SpeculativeJIT::compileGetIndexedPropertyStorage):
+        (JSC::DFG::SpeculativeJIT::compileGetArrayLength):
+        (JSC::DFG::SpeculativeJIT::compileAllocatePropertyStorage):
+        (JSC::DFG::SpeculativeJIT::compileReallocatePropertyStorage):
+        * dfg/DFGSpeculativeJIT.h:
+        (JSC::DFG::SpeculativeJIT::callOperation):
+        (JSC::DFG::SpeculativeJIT::emitAllocateBasicJSObject):
+        * dfg/DFGSpeculativeJIT32_64.cpp:
+        (JSC::DFG::SpeculativeJIT::cachedGetById):
+        (JSC::DFG::SpeculativeJIT::cachedPutById):
+        (JSC::DFG::SpeculativeJIT::compile):
+        * dfg/DFGSpeculativeJIT64.cpp:
+        (JSC::DFG::SpeculativeJIT::cachedGetById):
+        (JSC::DFG::SpeculativeJIT::cachedPutById):
+        (JSC::DFG::SpeculativeJIT::compile):
+        * dfg/DFGStructureCheckHoistingPhase.cpp:
+        (JSC::DFG::StructureCheckHoistingPhase::run):
+        * heap/CopiedSpace.h:
+        (CopiedSpace):
+        * jit/JIT.h:
+        * jit/JITInlineMethods.h:
+        (JSC::JIT::emitAllocateBasicJSObject):
+        (JSC::JIT::emitAllocateBasicStorage):
+        (JSC::JIT::emitAllocateJSArray):
+        * jit/JITOpcodes.cpp:
+        (JSC::JIT::emit_op_new_array):
+        (JSC::JIT::emitSlow_op_new_array):
+        * jit/JITPropertyAccess.cpp:
+        (JSC::JIT::emit_op_get_by_val):
+        (JSC::JIT::compileGetDirectOffset):
+        (JSC::JIT::emit_op_put_by_val):
+        (JSC::JIT::compileGetByIdHotPath):
+        (JSC::JIT::emit_op_put_by_id):
+        (JSC::JIT::compilePutDirectOffset):
+        (JSC::JIT::privateCompilePatchGetArrayLength):
+        * jit/JITPropertyAccess32_64.cpp:
+        (JSC::JIT::emit_op_get_by_val):
+        (JSC::JIT::emit_op_put_by_val):
+        (JSC::JIT::compileGetByIdHotPath):
+        (JSC::JIT::emit_op_put_by_id):
+        (JSC::JIT::compilePutDirectOffset):
+        (JSC::JIT::compileGetDirectOffset):
+        (JSC::JIT::privateCompilePatchGetArrayLength):
+        * jit/JITStubs.cpp:
+        (JSC::DEFINE_STUB_FUNCTION):
+        * jsc.cpp:
+        * llint/LLIntSlowPaths.cpp:
+        (JSC::LLInt::LLINT_SLOW_PATH_DECL):
+        * llint/LowLevelInterpreter.asm:
+        * llint/LowLevelInterpreter32_64.asm:
+        * llint/LowLevelInterpreter64.asm:
+        * runtime/Arguments.cpp:
+        (JSC::Arguments::deletePropertyByIndex):
+        (JSC::Arguments::defineOwnProperty):
+        * runtime/ArrayConstructor.cpp:
+        * runtime/ArrayConventions.h: Added.
+        (JSC):
+        (JSC::isDenseEnoughForVector):
+        (JSC::indexingHeaderForArray):
+        (JSC::baseIndexingHeaderForArray):
+        * runtime/ArrayPrototype.cpp:
+        (JSC::ArrayPrototype::create):
+        (JSC):
+        (JSC::ArrayPrototype::ArrayPrototype):
+        (JSC::arrayProtoFuncToString):
+        (JSC::arrayProtoFuncJoin):
+        (JSC::arrayProtoFuncSort):
+        (JSC::arrayProtoFuncFilter):
+        (JSC::arrayProtoFuncMap):
+        (JSC::arrayProtoFuncEvery):
+        (JSC::arrayProtoFuncForEach):
+        (JSC::arrayProtoFuncSome):
+        (JSC::arrayProtoFuncReduce):
+        (JSC::arrayProtoFuncReduceRight):
+        * runtime/ArrayPrototype.h:
+        (ArrayPrototype):
+        (JSC::ArrayPrototype::createStructure):
+        * runtime/ArrayStorage.h: Added.
+        (JSC):
+        (ArrayStorage):
+        (JSC::ArrayStorage::ArrayStorage):
+        (JSC::ArrayStorage::from):
+        (JSC::ArrayStorage::butterfly):
+        (JSC::ArrayStorage::indexingHeader):
+        (JSC::ArrayStorage::length):
+        (JSC::ArrayStorage::setLength):
+        (JSC::ArrayStorage::vectorLength):
+        (JSC::ArrayStorage::setVectorLength):
+        (JSC::ArrayStorage::copyHeaderFromDuringGC):
+        (JSC::ArrayStorage::inSparseMode):
+        (JSC::ArrayStorage::lengthOffset):
+        (JSC::ArrayStorage::vectorLengthOffset):
+        (JSC::ArrayStorage::numValuesInVectorOffset):
+        (JSC::ArrayStorage::vectorOffset):
+        (JSC::ArrayStorage::indexBiasOffset):
+        (JSC::ArrayStorage::sparseMapOffset):
+        (JSC::ArrayStorage::sizeFor):
+        * runtime/Butterfly.h: Added.
+        (JSC):
+        (Butterfly):
+        (JSC::Butterfly::Butterfly):
+        (JSC::Butterfly::totalSize):
+        (JSC::Butterfly::fromBase):
+        (JSC::Butterfly::offsetOfIndexingHeader):
+        (JSC::Butterfly::offsetOfPublicLength):
+        (JSC::Butterfly::offsetOfVectorLength):
+        (JSC::Butterfly::indexingHeader):
+        (JSC::Butterfly::propertyStorage):
+        (JSC::Butterfly::indexingPayload):
+        (JSC::Butterfly::arrayStorage):
+        (JSC::Butterfly::offsetOfPropertyStorage):
+        (JSC::Butterfly::indexOfPropertyStorage):
+        (JSC::Butterfly::base):
+        * runtime/ButterflyInlineMethods.h: Added.
+        (JSC):
+        (JSC::Butterfly::createUninitialized):
+        (JSC::Butterfly::create):
+        (JSC::Butterfly::createUninitializedDuringCollection):
+        (JSC::Butterfly::base):
+        (JSC::Butterfly::growPropertyStorage):
+        (JSC::Butterfly::growArrayRight):
+        (JSC::Butterfly::resizeArray):
+        (JSC::Butterfly::unshift):
+        (JSC::Butterfly::shift):
+        * runtime/ClassInfo.h:
+        (MethodTable):
+        (JSC):
+        * runtime/IndexingHeader.h: Added.
+        (JSC):
+        (IndexingHeader):
+        (JSC::IndexingHeader::offsetOfIndexingHeader):
+        (JSC::IndexingHeader::offsetOfPublicLength):
+        (JSC::IndexingHeader::offsetOfVectorLength):
+        (JSC::IndexingHeader::IndexingHeader):
+        (JSC::IndexingHeader::vectorLength):
+        (JSC::IndexingHeader::setVectorLength):
+        (JSC::IndexingHeader::publicLength):
+        (JSC::IndexingHeader::setPublicLength):
+        (JSC::IndexingHeader::from):
+        (JSC::IndexingHeader::fromEndOf):
+        (JSC::IndexingHeader::propertyStorage):
+        (JSC::IndexingHeader::arrayStorage):
+        (JSC::IndexingHeader::butterfly):
+        * runtime/IndexingHeaderInlineMethods.h: Added.
+        (JSC):
+        (JSC::IndexingHeader::preCapacity):
+        (JSC::IndexingHeader::indexingPayloadSizeInBytes):
+        * runtime/IndexingType.h: Added.
+        (JSC):
+        (JSC::hasIndexingHeader):
+        * runtime/JSActivation.cpp:
+        (JSC::JSActivation::JSActivation):
+        (JSC::JSActivation::visitChildren):
+        (JSC::JSActivation::getOwnNonIndexPropertyNames):
+        * runtime/JSActivation.h:
+        (JSActivation):
+        (JSC::JSActivation::tearOff):
+        * runtime/JSArray.cpp:
+        (JSC):
+        (JSC::createArrayButterflyInDictionaryIndexingMode):
+        (JSC::JSArray::setLengthWritable):
+        (JSC::JSArray::defineOwnProperty):
+        (JSC::JSArray::getOwnPropertySlot):
+        (JSC::JSArray::getOwnPropertyDescriptor):
+        (JSC::JSArray::put):
+        (JSC::JSArray::deleteProperty):
+        (JSC::JSArray::getOwnNonIndexPropertyNames):
+        (JSC::JSArray::unshiftCountSlowCase):
+        (JSC::JSArray::setLength):
+        (JSC::JSArray::pop):
+        (JSC::JSArray::push):
+        (JSC::JSArray::shiftCount):
+        (JSC::JSArray::unshiftCount):
+        (JSC::JSArray::sortNumeric):
+        (JSC::JSArray::sort):
+        (JSC::JSArray::fillArgList):
+        (JSC::JSArray::copyToArguments):
+        (JSC::JSArray::compactForSorting):
+        * runtime/JSArray.h:
+        (JSC):
+        (JSArray):
+        (JSC::JSArray::JSArray):
+        (JSC::JSArray::length):
+        (JSC::JSArray::createStructure):
+        (JSC::JSArray::isLengthWritable):
+        (JSC::createArrayButterfly):
+        (JSC::JSArray::create):
+        (JSC::JSArray::tryCreateUninitialized):
+        * runtime/JSBoundFunction.cpp:
+        (JSC::boundFunctionCall):
+        (JSC::boundFunctionConstruct):
+        (JSC::JSBoundFunction::finishCreation):
+        * runtime/JSCell.cpp:
+        (JSC::JSCell::getOwnNonIndexPropertyNames):
+        (JSC):
+        * runtime/JSCell.h:
+        (JSCell):
+        * runtime/JSFunction.cpp:
+        (JSC::JSFunction::getOwnPropertySlot):
+        (JSC::JSFunction::getOwnPropertyDescriptor):
+        (JSC::JSFunction::getOwnNonIndexPropertyNames):
+        (JSC::JSFunction::defineOwnProperty):
+        * runtime/JSFunction.h:
+        (JSFunction):
+        * runtime/JSGlobalData.cpp:
+        (JSC::JSGlobalData::JSGlobalData):
+        * runtime/JSGlobalData.h:
+        (JSGlobalData):
+        * runtime/JSGlobalObject.cpp:
+        (JSC::JSGlobalObject::reset):
+        * runtime/JSONObject.cpp:
+        (JSC::Stringifier::Holder::appendNextProperty):
+        (JSC::Walker::walk):
+        * runtime/JSObject.cpp:
+        (JSC):
+        (JSC::JSObject::visitButterfly):
+        (JSC::JSObject::visitChildren):
+        (JSC::JSFinalObject::visitChildren):
+        (JSC::JSObject::getOwnPropertySlotByIndex):
+        (JSC::JSObject::put):
+        (JSC::JSObject::putByIndex):
+        (JSC::JSObject::enterDictionaryIndexingModeWhenArrayStorageAlreadyExists):
+        (JSC::JSObject::enterDictionaryIndexingMode):
+        (JSC::JSObject::createArrayStorage):
+        (JSC::JSObject::createInitialArrayStorage):
+        (JSC::JSObject::ensureArrayStorageExistsAndEnterDictionaryIndexingMode):
+        (JSC::JSObject::putDirectAccessor):
+        (JSC::JSObject::deleteProperty):
+        (JSC::JSObject::deletePropertyByIndex):
+        (JSC::JSObject::getOwnPropertyNames):
+        (JSC::JSObject::getOwnNonIndexPropertyNames):
+        (JSC::JSObject::preventExtensions):
+        (JSC::JSObject::fillGetterPropertySlot):
+        (JSC::JSObject::putIndexedDescriptor):
+        (JSC::JSObject::defineOwnIndexedProperty):
+        (JSC::JSObject::allocateSparseIndexMap):
+        (JSC::JSObject::deallocateSparseIndexMap):
+        (JSC::JSObject::putByIndexBeyondVectorLengthWithArrayStorage):
+        (JSC::JSObject::putByIndexBeyondVectorLength):
+        (JSC::JSObject::putDirectIndexBeyondVectorLengthWithArrayStorage):
+        (JSC::JSObject::putDirectIndexBeyondVectorLength):
+        (JSC::JSObject::getNewVectorLength):
+        (JSC::JSObject::increaseVectorLength):
+        (JSC::JSObject::checkIndexingConsistency):
+        (JSC::JSObject::growOutOfLineStorage):
+        (JSC::JSObject::getOwnPropertyDescriptor):
+        (JSC::putDescriptor):
+        (JSC::JSObject::putDirectMayBeIndex):
+        (JSC::JSObject::defineOwnNonIndexProperty):
+        (JSC::JSObject::defineOwnProperty):
+        (JSC::JSObject::getOwnPropertySlotSlow):
+        * runtime/JSObject.h:
+        (JSC::JSObject::getArrayLength):
+        (JSObject):
+        (JSC::JSObject::getVectorLength):
+        (JSC::JSObject::putDirectIndex):
+        (JSC::JSObject::canGetIndexQuickly):
+        (JSC::JSObject::getIndexQuickly):
+        (JSC::JSObject::canSetIndexQuickly):
+        (JSC::JSObject::setIndexQuickly):
+        (JSC::JSObject::initializeIndex):
+        (JSC::JSObject::completeInitialization):
+        (JSC::JSObject::inSparseIndexingMode):
+        (JSC::JSObject::butterfly):
+        (JSC::JSObject::outOfLineStorage):
+        (JSC::JSObject::offsetForLocation):
+        (JSC::JSObject::indexingShouldBeSparse):
+        (JSC::JSObject::butterflyOffset):
+        (JSC::JSObject::butterflyAddress):
+        (JSC::JSObject::arrayStorage):
+        (JSC::JSObject::arrayStorageOrZero):
+        (JSC::JSObject::ensureArrayStorage):
+        (JSC::JSObject::checkIndexingConsistency):
+        (JSC::JSNonFinalObject::JSNonFinalObject):
+        (JSC):
+        (JSC::JSObject::setButterfly):
+        (JSC::JSObject::setButterflyWithoutChangingStructure):
+        (JSC::JSObject::JSObject):
+        (JSC::JSObject::inlineGetOwnPropertySlot):
+        (JSC::JSObject::putDirectInternal):
+        (JSC::JSObject::setStructureAndReallocateStorageIfNecessary):
+        (JSC::JSObject::putDirectWithoutTransition):
+        (JSC::offsetInButterfly):
+        (JSC::offsetRelativeToPatchedStorage):
+        (JSC::indexRelativeToBase):
+        (JSC::offsetRelativeToBase):
+        * runtime/JSPropertyNameIterator.cpp:
+        (JSC::JSPropertyNameIterator::create):
+        * runtime/JSSymbolTableObject.cpp:
+        (JSC::JSSymbolTableObject::getOwnNonIndexPropertyNames):
+        * runtime/JSSymbolTableObject.h:
+        (JSSymbolTableObject):
+        * runtime/JSTypeInfo.h:
+        (JSC):
+        (JSC::TypeInfo::interceptsGetOwnPropertySlotByIndexEvenWhenLengthIsNotZero):
+        (JSC::TypeInfo::overridesGetPropertyNames):
+        * runtime/LiteralParser.cpp:
+        (JSC::::parse):
+        * runtime/ObjectConstructor.cpp:
+        * runtime/ObjectPrototype.cpp:
+        (JSC::ObjectPrototype::ObjectPrototype):
+        (JSC):
+        * runtime/ObjectPrototype.h:
+        (ObjectPrototype):
+        * runtime/PropertyOffset.h:
+        (JSC::offsetInOutOfLineStorage):
+        * runtime/PropertyStorage.h: Added.
+        (JSC):
+        * runtime/PutDirectIndexMode.h: Added.
+        (JSC):
+        * runtime/RegExpMatchesArray.cpp:
+        (JSC::RegExpMatchesArray::RegExpMatchesArray):
+        (JSC):
+        (JSC::RegExpMatchesArray::create):
+        (JSC::RegExpMatchesArray::finishCreation):
+        * runtime/RegExpMatchesArray.h:
+        (RegExpMatchesArray):
+        (JSC::RegExpMatchesArray::createStructure):
+        * runtime/RegExpObject.cpp:
+        (JSC::RegExpObject::getOwnNonIndexPropertyNames):
+        * runtime/RegExpObject.h:
+        (RegExpObject):
+        * runtime/Reject.h: Added.
+        (JSC):
+        (JSC::reject):
+        * runtime/SparseArrayValueMap.cpp: Added.
+        (JSC):
+        * runtime/SparseArrayValueMap.h: Added.
+        (JSC):
+        (SparseArrayEntry):
+        (JSC::SparseArrayEntry::SparseArrayEntry):
+        (SparseArrayValueMap):
+        (JSC::SparseArrayValueMap::sparseMode):
+        (JSC::SparseArrayValueMap::setSparseMode):
+        (JSC::SparseArrayValueMap::lengthIsReadOnly):
+        (JSC::SparseArrayValueMap::setLengthIsReadOnly):
+        (JSC::SparseArrayValueMap::find):
+        (JSC::SparseArrayValueMap::remove):
+        (JSC::SparseArrayValueMap::notFound):
+        (JSC::SparseArrayValueMap::isEmpty):
+        (JSC::SparseArrayValueMap::contains):
+        (JSC::SparseArrayValueMap::size):
+        (JSC::SparseArrayValueMap::begin):
+        (JSC::SparseArrayValueMap::end):
+        * runtime/SparseArrayValueMapInlineMethods.h: Added.
+        (JSC):
+        (JSC::SparseArrayValueMap::SparseArrayValueMap):
+        (JSC::SparseArrayValueMap::~SparseArrayValueMap):
+        (JSC::SparseArrayValueMap::finishCreation):
+        (JSC::SparseArrayValueMap::create):
+        (JSC::SparseArrayValueMap::destroy):
+        (JSC::SparseArrayValueMap::createStructure):
+        (JSC::SparseArrayValueMap::add):
+        (JSC::SparseArrayValueMap::putEntry):
+        (JSC::SparseArrayValueMap::putDirect):
+        (JSC::SparseArrayEntry::get):
+        (JSC::SparseArrayEntry::getNonSparseMode):
+        (JSC::SparseArrayValueMap::visitChildren):
+        * runtime/StorageBarrier.h: Removed.
+        * runtime/StringObject.cpp:
+        (JSC::StringObject::putByIndex):
+        (JSC):
+        (JSC::StringObject::deletePropertyByIndex):
+        * runtime/StringObject.h:
+        (StringObject):
+        * runtime/StringPrototype.cpp:
+        * runtime/Structure.cpp:
+        (JSC::Structure::Structure):
+        (JSC::Structure::materializePropertyMap):
+        (JSC::Structure::nonPropertyTransition):
+        (JSC):
+        * runtime/Structure.h:
+        (Structure):
+        (JSC::Structure::indexingType):
+        (JSC::Structure::indexingTypeIncludingHistory):
+        (JSC::Structure::indexingTypeOffset):
+        (JSC::Structure::create):
+        * runtime/StructureTransitionTable.h:
+        (JSC):
+        (JSC::toAttributes):
+        (JSC::newIndexingType):
+        (JSC::StructureTransitionTable::Hash::hash):
+        * tests/mozilla/js1_6/Array/regress-304828.js:
+
 2012-09-12  Mark Lam  <mark.lam@apple.com>
 
         Refactor Opcodes to distinguish between core and extension opcodes.
index 9d8161f..b171524 100644 (file)
@@ -457,8 +457,10 @@ javascriptcore_sources += \
        Source/JavaScriptCore/runtime/Arguments.h \
        Source/JavaScriptCore/runtime/ArrayConstructor.cpp \
        Source/JavaScriptCore/runtime/ArrayConstructor.h \
+       Source/JavaScriptCore/runtime/ArrayConventions.h \
        Source/JavaScriptCore/runtime/ArrayPrototype.cpp \
        Source/JavaScriptCore/runtime/ArrayPrototype.h \
+       Source/JavaScriptCore/runtime/ArrayStorage.h \
        Source/JavaScriptCore/runtime/BatchedTransitionOptimizer.h \
        Source/JavaScriptCore/runtime/BigInteger.h \
        Source/JavaScriptCore/runtime/BooleanConstructor.cpp \
@@ -467,6 +469,8 @@ javascriptcore_sources += \
        Source/JavaScriptCore/runtime/BooleanObject.h \
        Source/JavaScriptCore/runtime/BooleanPrototype.cpp \
        Source/JavaScriptCore/runtime/BooleanPrototype.h \
+       Source/JavaScriptCore/runtime/ButterflyInlineMethods.h \
+       Source/JavaScriptCore/runtime/Butterfly.h \
        Source/JavaScriptCore/runtime/CachedTranscendentalFunction.h \
        Source/JavaScriptCore/runtime/CallData.cpp \
        Source/JavaScriptCore/runtime/CallData.h \
@@ -511,6 +515,9 @@ javascriptcore_sources += \
        Source/JavaScriptCore/runtime/GetterSetter.h \
        Source/JavaScriptCore/runtime/Identifier.cpp \
        Source/JavaScriptCore/runtime/Identifier.h \
+       Source/JavaScriptCore/runtime/IndexingHeaderInlineMethods.h \
+       Source/JavaScriptCore/runtime/IndexingHeader.h \
+       Source/JavaScriptCore/runtime/IndexingType.h \
        Source/JavaScriptCore/runtime/InitializeThreading.cpp \
        Source/JavaScriptCore/runtime/InitializeThreading.h \
        Source/JavaScriptCore/runtime/InternalFunction.cpp \
@@ -616,7 +623,9 @@ javascriptcore_sources += \
        Source/JavaScriptCore/runtime/PropertyOffset.h \
        Source/JavaScriptCore/runtime/PropertySlot.cpp \
        Source/JavaScriptCore/runtime/PropertySlot.h \
+       Source/JavaScriptCore/runtime/PropertyStorage.h \
        Source/JavaScriptCore/runtime/Protect.h \
+       Source/JavaScriptCore/runtime/PutDirectIndexMode.h \
        Source/JavaScriptCore/runtime/PutPropertySlot.h \
        Source/JavaScriptCore/runtime/RegExpCache.cpp \
        Source/JavaScriptCore/runtime/RegExpCache.h \
@@ -633,11 +642,14 @@ javascriptcore_sources += \
        Source/JavaScriptCore/runtime/RegExpObject.h \
        Source/JavaScriptCore/runtime/RegExpPrototype.cpp \
        Source/JavaScriptCore/runtime/RegExpPrototype.h \
+       Source/JavaScriptCore/runtime/Reject.h \
        Source/JavaScriptCore/runtime/SamplingCounter.cpp \
        Source/JavaScriptCore/runtime/SamplingCounter.h \
        Source/JavaScriptCore/runtime/SmallStrings.cpp \
        Source/JavaScriptCore/runtime/SmallStrings.h \
-       Source/JavaScriptCore/runtime/StorageBarrier.h \
+       Source/JavaScriptCore/runtime/SparseArrayValueMapInlineMethods.h \
+       Source/JavaScriptCore/runtime/SparseArrayValueMap.cpp \
+       Source/JavaScriptCore/runtime/SparseArrayValueMap.h \
        Source/JavaScriptCore/runtime/StrictEvalActivation.cpp \
        Source/JavaScriptCore/runtime/StrictEvalActivation.h \
        Source/JavaScriptCore/runtime/StringConstructor.cpp \
index b072cee..4d54364 100755 (executable)
@@ -22,7 +22,7 @@ EXPORTS
     ??0RegExpObject@JSC@@IAE@PAVJSGlobalObject@1@PAVStructure@1@PAVRegExp@1@@Z
     ??0SHA1@WTF@@QAE@XZ
     ??0StringObject@JSC@@IAE@AAVJSGlobalData@1@PAVStructure@1@@Z
-    ??0Structure@JSC@@AAE@AAVJSGlobalData@1@PAVJSGlobalObject@1@VJSValue@1@ABVTypeInfo@1@PBUClassInfo@1@@Z
+    ??0Structure@JSC@@AAE@AAVJSGlobalData@1@PAVJSGlobalObject@1@VJSValue@1@ABVTypeInfo@1@PBUClassInfo@1@E@Z
     ??0ThreadCondition@WTF@@QAE@XZ
     ??0WTFThreadData@WTF@@QAE@XZ
     ??0YarrPattern@Yarr@JSC@@QAE@ABVString@WTF@@_N1PAPBD@Z
@@ -185,13 +185,12 @@ EXPORTS
     ?fastRealloc@WTF@@YAPAXPAXI@Z
     ?fastStrDup@WTF@@YAPADPBD@Z
     ?fastZeroedMalloc@WTF@@YAPAXI@Z
-    ?fillGetterPropertySlot@JSObject@JSC@@AAEXAAVPropertySlot@2@PAV?$WriteBarrierBase@W4Unknown@JSC@@@2@@Z
+    ?fillGetterPropertySlot@JSObject@JSC@@AAEXAAVPropertySlot@2@H@Z
     ?finalize@WeakHandleOwner@JSC@@UAEXV?$Handle@W4Unknown@JSC@@@2@PAX@Z
     ?findAllocator@WeakSet@JSC@@AAEPAUFreeCell@WeakBlock@2@XZ
     ?finishCreation@BooleanObject@JSC@@IAEXAAVJSGlobalData@2@@Z
     ?finishCreation@DateInstance@JSC@@IAEXAAVJSGlobalData@2@N@Z
     ?finishCreation@InternalFunction@JSC@@IAEXAAVJSGlobalData@2@ABVString@WTF@@@Z
-    ?finishCreation@JSArray@JSC@@IAEXAAVJSGlobalData@2@I@Z
     ?finishCreation@RegExpObject@JSC@@IAEXPAVJSGlobalObject@2@@Z
     ?finishCreation@StringObject@JSC@@IAEXAAVJSGlobalData@2@PAVJSString@2@@Z
     ?focus@Profile@JSC@@QAEXPBVProfileNode@2@@Z
@@ -204,13 +203,14 @@ EXPORTS
     ?getCallableObjectSlow@JSC@@YAPAVJSCell@1@PAV21@@Z
     ?getConstructData@JSCell@JSC@@SA?AW4ConstructType@2@PAV12@AATConstructData@2@@Z
     ?getObject@JSCell@JSC@@QAEPAVJSObject@2@XZ
+    ?getOwnNonIndexPropertyNames@JSObject@JSC@@SAXPAV12@PAVExecState@2@AAVPropertyNameArray@2@W4EnumerationMode@2@@Z
+    ?getOwnNonIndexPropertyNames@JSSymbolTableObject@JSC@@SAXPAVJSObject@2@PAVExecState@2@AAVPropertyNameArray@2@W4EnumerationMode@2@@Z
     ?getOwnPropertyDescriptor@JSGlobalObject@JSC@@SA_NPAVJSObject@2@PAVExecState@2@VPropertyName@2@AAVPropertyDescriptor@2@@Z
     ?getOwnPropertyDescriptor@JSObject@JSC@@SA_NPAV12@PAVExecState@2@VPropertyName@2@AAVPropertyDescriptor@2@@Z
     ?getOwnPropertyNames@JSObject@JSC@@SAXPAV12@PAVExecState@2@AAVPropertyNameArray@2@W4EnumerationMode@2@@Z
-    ?getOwnPropertyNames@JSSymbolTableObject@JSC@@SAXPAVJSObject@2@PAVExecState@2@AAVPropertyNameArray@2@W4EnumerationMode@2@@Z
     ?getOwnPropertySlot@JSGlobalObject@JSC@@SA_NPAVJSCell@2@PAVExecState@2@VPropertyName@2@AAVPropertySlot@2@@Z
-    ?getOwnPropertySlotByIndex@JSArray@JSC@@SA_NPAVJSCell@2@PAVExecState@2@IAAVPropertySlot@2@@Z
     ?getOwnPropertySlotByIndex@JSObject@JSC@@SA_NPAVJSCell@2@PAVExecState@2@IAAVPropertySlot@2@@Z
+    ?getOwnPropertySlotSlow@JSObject@JSC@@AAE_NPAVExecState@2@VPropertyName@2@AAVPropertySlot@2@@Z
     ?getPropertyNames@JSObject@JSC@@SAXPAV12@PAVExecState@2@AAVPropertyNameArray@2@W4EnumerationMode@2@@Z
     ?getSlice@ArgList@JSC@@QBEXHAAV12@@Z
     ?getStackTrace@Interpreter@JSC@@SAXPAVJSGlobalData@2@AAV?$Vector@UStackFrame@JSC@@$0A@@WTF@@@Z
@@ -220,8 +220,8 @@ EXPORTS
     ?getter@PropertyDescriptor@JSC@@QBE?AVJSValue@2@XZ
     ?globalExec@JSGlobalObject@JSC@@QAEPAVExecState@2@XZ
     ?globalObjectCount@Heap@JSC@@QAEIXZ
-    ?growOutOfLineStorage@JSObject@JSC@@QAEPAV?$WriteBarrierBase@W4Unknown@JSC@@@2@AAVJSGlobalData@2@II@Z
     ?grow@HandleSet@JSC@@AAEXXZ
+    ?growOutOfLineStorage@JSObject@JSC@@QAEPAVButterfly@2@AAVJSGlobalData@2@II@Z
     ?hasInstance@JSObject@JSC@@SA_NPAV12@PAVExecState@2@VJSValue@2@2@Z
     ?hasProperty@JSObject@JSC@@QBE_NPAVExecState@2@I@Z
     ?hasProperty@JSObject@JSC@@QBE_NPAVExecState@2@VPropertyName@2@@Z
@@ -276,7 +276,7 @@ EXPORTS
     ?put@JSGlobalObject@JSC@@SAXPAVJSCell@2@PAVExecState@2@VPropertyName@2@VJSValue@2@AAVPutPropertySlot@2@@Z
     ?put@JSObject@JSC@@SAXPAVJSCell@2@PAVExecState@2@VPropertyName@2@VJSValue@2@AAVPutPropertySlot@2@@Z
     ?putByIndex@JSObject@JSC@@SAXPAVJSCell@2@PAVExecState@2@IVJSValue@2@_N@Z
-    ?putDirectIndexBeyondVectorLength@JSArray@JSC@@AAE_NPAVExecState@2@IVJSValue@2@W4PutDirectIndexMode@2@@Z
+    ?putDirectIndexBeyondVectorLength@JSObject@JSC@@AAE_NPAVExecState@2@IVJSValue@2@IW4PutDirectIndexMode@2@@Z
     ?putDirectVirtual@JSGlobalObject@JSC@@SAXPAVJSObject@2@PAVExecState@2@VPropertyName@2@VJSValue@2@I@Z
     ?putDirectVirtual@JSObject@JSC@@SAXPAV12@PAVExecState@2@VPropertyName@2@VJSValue@2@I@Z
     ?randomNumber@WTF@@YANXZ
@@ -355,10 +355,10 @@ EXPORTS
     ?toThisObjectSlowCase@JSValue@JSC@@ABEPAVJSObject@2@PAVExecState@2@@Z
     ?toWTFStringSlowCase@JSValue@JSC@@ABE?AVString@WTF@@PAVExecState@2@@Z
     ?transfer@ArrayBuffer@WTF@@QAE_NAAVArrayBufferContents@2@AAV?$Vector@V?$RefPtr@VArrayBufferView@WTF@@@WTF@@$0A@@2@@Z
+    ?tryAllocateSlowCase@CopiedSpace@JSC@@AAE?AVCheckedBoolean@@IPAPAX@Z
     ?tryFastCalloc@WTF@@YA?AUTryMallocReturnValue@1@II@Z
     ?tryFastMalloc@WTF@@YA?AUTryMallocReturnValue@1@I@Z
     ?tryFastRealloc@WTF@@YA?AUTryMallocReturnValue@1@PAXI@Z
-    ?tryFinishCreationUninitialized@JSArray@JSC@@IAEPAV12@AAVJSGlobalData@2@I@Z
     ?tryLock@Mutex@WTF@@QAE_NXZ
     ?type@DebuggerCallFrame@JSC@@QBE?AW4Type@12@XZ
     ?unlock@JSLock@JSC@@QAEXXZ
index 32661a3..10da9ab 100644 (file)
                        Name="runtime"
                        >
                        <File
+                               RelativePath="..\..\runtime\Reject.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\runtime\SparseArrayValueMapInlineMethods.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\runtime\ArrayStorage.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\runtime\IndexingType.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\runtime\PropertyStorage.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\runtime\PutDirectIndexMode.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\runtime\ButterflyInlineMethods.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\runtime\Butterfly.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\runtime\IndexingHeaderInlineMethods.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\runtime\SparseArrayValueMap.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\runtime\ArrayConventions.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\runtime\IndexingHeader.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\runtime\SparseArrayValueMap.cpp"
+                               >
+                       </File>
+                       <File
                                RelativePath="..\..\runtime\ArgList.cpp"
                                >
                        </File>
index 7d180eb..db75c07 100644 (file)
@@ -73,6 +73,8 @@
                0F0B83B514BCF86200885B4F /* MethodCallLinkInfo.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F0B83B314BCF85E00885B4F /* MethodCallLinkInfo.h */; settings = {ATTRIBUTES = (Private, ); }; };
                0F0B83B714BCF8E100885B4F /* GlobalResolveInfo.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F0B83B614BCF8DF00885B4F /* GlobalResolveInfo.h */; settings = {ATTRIBUTES = (Private, ); }; };
                0F0B83B914BCF95F00885B4F /* CallReturnOffsetToBytecodeOffset.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F0B83B814BCF95B00885B4F /* CallReturnOffsetToBytecodeOffset.h */; settings = {ATTRIBUTES = (Private, ); }; };
+               0F0CD4C215F1A6070032F1C0 /* PutDirectIndexMode.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F0CD4C015F1A6040032F1C0 /* PutDirectIndexMode.h */; settings = {ATTRIBUTES = (Private, ); }; };
+               0F0CD4C415F6B6BB0032F1C0 /* SparseArrayValueMap.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F0CD4C315F6B6B50032F1C0 /* SparseArrayValueMap.cpp */; };
                0F0FC45A14BD15F500B81154 /* LLIntCallLinkInfo.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F0FC45814BD15F100B81154 /* LLIntCallLinkInfo.h */; settings = {ATTRIBUTES = (Private, ); }; };
                0F15F15F14B7A73E005DE37D /* CommonSlowPaths.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F15F15D14B7A73A005DE37D /* CommonSlowPaths.h */; settings = {ATTRIBUTES = (Private, ); }; };
                0F16015D156198C900C2587C /* DFGArgumentsSimplificationPhase.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F16015A156198BF00C2587C /* DFGArgumentsSimplificationPhase.cpp */; };
                0FB5467914F5C46B002C2989 /* LazyOperandValueProfile.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0FB5467814F5C468002C2989 /* LazyOperandValueProfile.cpp */; };
                0FB5467B14F5C7E1002C2989 /* MethodOfGettingAValueProfile.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FB5467A14F5C7D4002C2989 /* MethodOfGettingAValueProfile.h */; settings = {ATTRIBUTES = (Private, ); }; };
                0FB5467D14F5CFD6002C2989 /* MethodOfGettingAValueProfile.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0FB5467C14F5CFD3002C2989 /* MethodOfGettingAValueProfile.cpp */; };
+               0FB7F39515ED8E4600F167B2 /* ArrayConventions.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FB7F38915ED8E3800F167B2 /* ArrayConventions.h */; settings = {ATTRIBUTES = (Private, ); }; };
+               0FB7F39615ED8E4600F167B2 /* ArrayStorage.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FB7F38A15ED8E3800F167B2 /* ArrayStorage.h */; settings = {ATTRIBUTES = (Private, ); }; };
+               0FB7F39715ED8E4600F167B2 /* Butterfly.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FB7F38B15ED8E3800F167B2 /* Butterfly.h */; settings = {ATTRIBUTES = (Private, ); }; };
+               0FB7F39815ED8E4600F167B2 /* ButterflyInlineMethods.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FB7F38C15ED8E3800F167B2 /* ButterflyInlineMethods.h */; settings = {ATTRIBUTES = (Private, ); }; };
+               0FB7F39915ED8E4600F167B2 /* IndexingHeader.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FB7F38D15ED8E3800F167B2 /* IndexingHeader.h */; settings = {ATTRIBUTES = (Private, ); }; };
+               0FB7F39A15ED8E4600F167B2 /* IndexingHeaderInlineMethods.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FB7F38E15ED8E3800F167B2 /* IndexingHeaderInlineMethods.h */; settings = {ATTRIBUTES = (Private, ); }; };
+               0FB7F39B15ED8E4600F167B2 /* IndexingType.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FB7F38F15ED8E3800F167B2 /* IndexingType.h */; settings = {ATTRIBUTES = (Private, ); }; };
+               0FB7F39C15ED8E4600F167B2 /* PropertyStorage.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FB7F39015ED8E3800F167B2 /* PropertyStorage.h */; settings = {ATTRIBUTES = (Private, ); }; };
+               0FB7F39D15ED8E4600F167B2 /* Reject.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FB7F39115ED8E3800F167B2 /* Reject.h */; settings = {ATTRIBUTES = (Private, ); }; };
+               0FB7F39E15ED8E4600F167B2 /* SparseArrayValueMap.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FB7F39215ED8E3800F167B2 /* SparseArrayValueMap.h */; settings = {ATTRIBUTES = (Private, ); }; };
+               0FB7F39F15ED8E4600F167B2 /* SparseArrayValueMapInlineMethods.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FB7F39315ED8E3800F167B2 /* SparseArrayValueMapInlineMethods.h */; settings = {ATTRIBUTES = (Private, ); }; };
                0FBC0AE71496C7C400D4FBDD /* DFGExitProfile.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0FBC0AE41496C7C100D4FBDD /* DFGExitProfile.cpp */; };
                0FBC0AE81496C7C700D4FBDD /* DFGExitProfile.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FBC0AE51496C7C100D4FBDD /* DFGExitProfile.h */; settings = {ATTRIBUTES = (Private, ); }; };
                0FBD7E691447999600481315 /* CodeOrigin.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FBD7E671447998F00481315 /* CodeOrigin.h */; settings = {ATTRIBUTES = (Private, ); }; };
                A766B44F0EE8DCD1009518CA /* ExecutableAllocator.h in Headers */ = {isa = PBXBuildFile; fileRef = A7B48DB50EE74CFC00DCBDB6 /* ExecutableAllocator.h */; settings = {ATTRIBUTES = (Private, ); }; };
                A76C51761182748D00715B05 /* JSInterfaceJIT.h in Headers */ = {isa = PBXBuildFile; fileRef = A76C51741182748D00715B05 /* JSInterfaceJIT.h */; settings = {ATTRIBUTES = (Private, ); }; };
                A76F54A313B28AAB00EF2BCE /* JITWriteBarrier.h in Headers */ = {isa = PBXBuildFile; fileRef = A76F54A213B28AAB00EF2BCE /* JITWriteBarrier.h */; };
-               A781E359141970C700094D90 /* StorageBarrier.h in Headers */ = {isa = PBXBuildFile; fileRef = A781E358141970C700094D90 /* StorageBarrier.h */; settings = {ATTRIBUTES = (Private, ); }; };
                A784A26111D16622005776AC /* ASTBuilder.h in Headers */ = {isa = PBXBuildFile; fileRef = A7A7EE7411B98B8D0065A14F /* ASTBuilder.h */; };
                A784A26411D16622005776AC /* SyntaxChecker.h in Headers */ = {isa = PBXBuildFile; fileRef = A7A7EE7711B98B8D0065A14F /* SyntaxChecker.h */; };
                A7B48F490EE8936F00DCBDB6 /* ExecutableAllocator.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A7B48DB60EE74CFC00DCBDB6 /* ExecutableAllocator.cpp */; };
                0F0B83B314BCF85E00885B4F /* MethodCallLinkInfo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MethodCallLinkInfo.h; sourceTree = "<group>"; };
                0F0B83B614BCF8DF00885B4F /* GlobalResolveInfo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GlobalResolveInfo.h; sourceTree = "<group>"; };
                0F0B83B814BCF95B00885B4F /* CallReturnOffsetToBytecodeOffset.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CallReturnOffsetToBytecodeOffset.h; sourceTree = "<group>"; };
+               0F0CD4C015F1A6040032F1C0 /* PutDirectIndexMode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PutDirectIndexMode.h; sourceTree = "<group>"; };
+               0F0CD4C315F6B6B50032F1C0 /* SparseArrayValueMap.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SparseArrayValueMap.cpp; sourceTree = "<group>"; };
                0F0FC45814BD15F100B81154 /* LLIntCallLinkInfo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LLIntCallLinkInfo.h; sourceTree = "<group>"; };
                0F15F15D14B7A73A005DE37D /* CommonSlowPaths.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CommonSlowPaths.h; sourceTree = "<group>"; };
                0F16015A156198BF00C2587C /* DFGArgumentsSimplificationPhase.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DFGArgumentsSimplificationPhase.cpp; path = dfg/DFGArgumentsSimplificationPhase.cpp; sourceTree = "<group>"; };
                0FB5467814F5C468002C2989 /* LazyOperandValueProfile.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = LazyOperandValueProfile.cpp; sourceTree = "<group>"; };
                0FB5467A14F5C7D4002C2989 /* MethodOfGettingAValueProfile.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MethodOfGettingAValueProfile.h; sourceTree = "<group>"; };
                0FB5467C14F5CFD3002C2989 /* MethodOfGettingAValueProfile.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = MethodOfGettingAValueProfile.cpp; sourceTree = "<group>"; };
+               0FB7F38915ED8E3800F167B2 /* ArrayConventions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ArrayConventions.h; sourceTree = "<group>"; };
+               0FB7F38A15ED8E3800F167B2 /* ArrayStorage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ArrayStorage.h; sourceTree = "<group>"; };
+               0FB7F38B15ED8E3800F167B2 /* Butterfly.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Butterfly.h; sourceTree = "<group>"; };
+               0FB7F38C15ED8E3800F167B2 /* ButterflyInlineMethods.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ButterflyInlineMethods.h; sourceTree = "<group>"; };
+               0FB7F38D15ED8E3800F167B2 /* IndexingHeader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IndexingHeader.h; sourceTree = "<group>"; };
+               0FB7F38E15ED8E3800F167B2 /* IndexingHeaderInlineMethods.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IndexingHeaderInlineMethods.h; sourceTree = "<group>"; };
+               0FB7F38F15ED8E3800F167B2 /* IndexingType.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IndexingType.h; sourceTree = "<group>"; };
+               0FB7F39015ED8E3800F167B2 /* PropertyStorage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PropertyStorage.h; sourceTree = "<group>"; };
+               0FB7F39115ED8E3800F167B2 /* Reject.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Reject.h; sourceTree = "<group>"; };
+               0FB7F39215ED8E3800F167B2 /* SparseArrayValueMap.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SparseArrayValueMap.h; sourceTree = "<group>"; };
+               0FB7F39315ED8E3800F167B2 /* SparseArrayValueMapInlineMethods.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SparseArrayValueMapInlineMethods.h; sourceTree = "<group>"; };
                0FBC0AE41496C7C100D4FBDD /* DFGExitProfile.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DFGExitProfile.cpp; sourceTree = "<group>"; };
                0FBC0AE51496C7C100D4FBDD /* DFGExitProfile.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DFGExitProfile.h; sourceTree = "<group>"; };
                0FBD7E671447998F00481315 /* CodeOrigin.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CodeOrigin.h; sourceTree = "<group>"; };
                A767FF9F14F4502900789059 /* JSCTypedArrayStubs.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSCTypedArrayStubs.h; sourceTree = "<group>"; };
                A76C51741182748D00715B05 /* JSInterfaceJIT.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSInterfaceJIT.h; sourceTree = "<group>"; };
                A76F54A213B28AAB00EF2BCE /* JITWriteBarrier.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JITWriteBarrier.h; sourceTree = "<group>"; };
-               A781E358141970C700094D90 /* StorageBarrier.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = StorageBarrier.h; sourceTree = "<group>"; };
                A79EDB0811531CD60019E912 /* JSObjectRefPrivate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSObjectRefPrivate.h; sourceTree = "<group>"; };
                A7A7EE7411B98B8D0065A14F /* ASTBuilder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASTBuilder.h; sourceTree = "<group>"; };
                A7A7EE7711B98B8D0065A14F /* SyntaxChecker.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SyntaxChecker.h; sourceTree = "<group>"; };
                7EF6E0BB0EB7A1EC0079AFAF /* runtime */ = {
                        isa = PBXGroup;
                        children = (
+                               0F0CD4C315F6B6B50032F1C0 /* SparseArrayValueMap.cpp */,
+                               0F0CD4C015F1A6040032F1C0 /* PutDirectIndexMode.h */,
+                               0FB7F38915ED8E3800F167B2 /* ArrayConventions.h */,
+                               0FB7F38A15ED8E3800F167B2 /* ArrayStorage.h */,
+                               0FB7F38B15ED8E3800F167B2 /* Butterfly.h */,
+                               0FB7F38C15ED8E3800F167B2 /* ButterflyInlineMethods.h */,
+                               0FB7F38D15ED8E3800F167B2 /* IndexingHeader.h */,
+                               0FB7F38E15ED8E3800F167B2 /* IndexingHeaderInlineMethods.h */,
+                               0FB7F38F15ED8E3800F167B2 /* IndexingType.h */,
+                               0FB7F39015ED8E3800F167B2 /* PropertyStorage.h */,
+                               0FB7F39115ED8E3800F167B2 /* Reject.h */,
+                               0FB7F39215ED8E3800F167B2 /* SparseArrayValueMap.h */,
+                               0FB7F39315ED8E3800F167B2 /* SparseArrayValueMapInlineMethods.h */,
+                               C2D58C3315912FEE0021A844 /* GCActivityCallback.cpp */,
                                BCF605110E203EF800B9A64D /* ArgList.cpp */,
                                BCF605120E203EF800B9A64D /* ArgList.h */,
                                BC257DE50E1F51C50016B6C9 /* Arguments.cpp */,
                                0F77008E1402FDD60078EB39 /* SamplingCounter.h */,
                                93303FE80E6A72B500786E6A /* SmallStrings.cpp */,
                                93303FEA0E6A72C000786E6A /* SmallStrings.h */,
-                               A781E358141970C700094D90 /* StorageBarrier.h */,
                                A730B6111250068F009D25B1 /* StrictEvalActivation.cpp */,
                                A730B6101250068F009D25B1 /* StrictEvalActivation.h */,
                                BC18C3C00E16EE3300B34460 /* StringConstructor.cpp */,
                                E49DC16C12EF294E00184A1F /* SourceProviderCache.h in Headers */,
                                E49DC16D12EF295300184A1F /* SourceProviderCacheItem.h in Headers */,
                                A7386554118697B400540279 /* SpecializedThunkJIT.h in Headers */,
-                               A781E359141970C700094D90 /* StorageBarrier.h in Headers */,
                                A730B6121250068F009D25B1 /* StrictEvalActivation.h in Headers */,
                                BC18C4660E16F5CD00B34460 /* StringConstructor.h in Headers */,
                                BC18C4680E16F5CD00B34460 /* StringObject.h in Headers */,
                                14874AE615EBDE4A002E3587 /* JSScope.h in Headers */,
                                FED287B215EC9A5700DA8161 /* LLIntOpcode.h in Headers */,
                                1442566215EDE98D0066A49B /* JSWithScope.h in Headers */,
+                               0FB7F39515ED8E4600F167B2 /* ArrayConventions.h in Headers */,
+                               0FB7F39615ED8E4600F167B2 /* ArrayStorage.h in Headers */,
+                               0FB7F39715ED8E4600F167B2 /* Butterfly.h in Headers */,
+                               0FB7F39815ED8E4600F167B2 /* ButterflyInlineMethods.h in Headers */,
+                               0FB7F39915ED8E4600F167B2 /* IndexingHeader.h in Headers */,
+                               0FB7F39A15ED8E4600F167B2 /* IndexingHeaderInlineMethods.h in Headers */,
+                               0FB7F39B15ED8E4600F167B2 /* IndexingType.h in Headers */,
+                               0FB7F39C15ED8E4600F167B2 /* PropertyStorage.h in Headers */,
+                               0FB7F39D15ED8E4600F167B2 /* Reject.h in Headers */,
+                               0FB7F39E15ED8E4600F167B2 /* SparseArrayValueMap.h in Headers */,
+                               0FB7F39F15ED8E4600F167B2 /* SparseArrayValueMapInlineMethods.h in Headers */,
+                               0F0CD4C215F1A6070032F1C0 /* PutDirectIndexMode.h in Headers */,
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
                                14874AE315EBDE4A002E3587 /* JSNameScope.cpp in Sources */,
                                14874AE515EBDE4A002E3587 /* JSScope.cpp in Sources */,
                                1442566115EDE98D0066A49B /* JSWithScope.cpp in Sources */,
+                               0F0CD4C415F6B6BB0032F1C0 /* SparseArrayValueMap.cpp in Sources */,
                                FE20CE9D15F04A9500DF3430 /* LLIntCLoop.cpp in Sources */,
                                C225494315F7DBAA0065E898 /* SlotVisitor.cpp in Sources */,
                        );
index 336d800..6f063fa 100644 (file)
@@ -246,6 +246,7 @@ SOURCES += \
     runtime/RegExpCache.cpp \
     runtime/SamplingCounter.cpp \
     runtime/SmallStrings.cpp \
+    runtime/SparseArrayValueMap.cpp \
     runtime/StrictEvalActivation.cpp \
     runtime/StringConstructor.cpp \
     runtime/StringObject.cpp \
index 5a656e2..312473f 100644 (file)
@@ -35,16 +35,16 @@ namespace JSC {
 
 class LLIntOffsetsExtractor;
 
+// This is a bitfield where each bit represents an IndexingType that we have seen.
+// There are 17 indexing types (0 to 16, inclusive), so 32 bits is more than enough.
 typedef unsigned ArrayModes;
 
-static const unsigned IsNotArray = 1;
-static const unsigned IsJSArray  = 2;
+#define asArrayModes(type) \
+    (1 << static_cast<unsigned>(type))
 
 inline ArrayModes arrayModeFromStructure(Structure* structure)
 {
-    if (structure->classInfo() == &JSArray::s_info)
-        return IsJSArray;
-    return IsNotArray;
+    return asArrayModes(structure->indexingTypeIncludingHistory());
 }
 
 class ArrayProfile {
index d8cb1d4..47eb698 100644 (file)
@@ -1758,7 +1758,9 @@ RegisterID* BytecodeGenerator::emitDirectPutById(RegisterID* base, const Identif
     instructions().append(0);
     instructions().append(0);
     instructions().append(0);
-    instructions().append(property != m_globalData->propertyNames->underscoreProto);
+    instructions().append(
+        property != m_globalData->propertyNames->underscoreProto
+        && PropertyName(property).asIndex() == PropertyName::NotAnIndex);
     return value;
 }
 
index 5f79f66..f6145c1 100644 (file)
@@ -852,11 +852,11 @@ bool AbstractState::execute(unsigned indexInBlock)
             forNode(node.child2()).filter(SpecInt32);
             forNode(nodeIndex).makeTop();
             break;
-        case Array::JSArray:
+        case IN_BOUNDS_ARRAY_STORAGE_MODES:
             forNode(node.child2()).filter(SpecInt32);
             forNode(nodeIndex).makeTop();
             break;
-        case Array::JSArrayOutOfBounds:
+        case OUT_OF_BOUNDS_ARRAY_STORAGE_MODES:
             forNode(node.child2()).filter(SpecInt32);
             clobberWorld(node.codeOrigin, indexInBlock);
             forNode(nodeIndex).makeTop();
@@ -916,10 +916,10 @@ bool AbstractState::execute(unsigned indexInBlock)
         case Array::Generic:
             clobberWorld(node.codeOrigin, indexInBlock);
             break;
-        case Array::JSArray:
+        case IN_BOUNDS_ARRAY_STORAGE_MODES:
             forNode(child2).filter(SpecInt32);
             break;
-        case Array::JSArrayOutOfBounds:
+        case OUT_OF_BOUNDS_ARRAY_STORAGE_MODES:
             forNode(child2).filter(SpecInt32);
             clobberWorld(node.codeOrigin, indexInBlock);
             break;
@@ -1341,7 +1341,7 @@ bool AbstractState::execute(unsigned indexInBlock)
         forNode(node.child1()).set(node.structureTransitionData().newStructure);
         m_haveStructures = true;
         break;
-    case GetPropertyStorage:
+    case GetButterfly:
     case AllocatePropertyStorage:
     case ReallocatePropertyStorage:
         node.setCanExit(false);
@@ -1359,8 +1359,7 @@ bool AbstractState::execute(unsigned indexInBlock)
         case Array::String:
             forNode(node.child1()).filter(SpecString);
             break;
-        case Array::JSArray:
-        case Array::JSArrayOutOfBounds:
+        case ALL_ARRAY_STORAGE_MODES:
             // This doesn't filter anything meaningful right now. We may want to add
             // CFA tracking of array mode speculations, but we don't have that, yet.
             forNode(node.child1()).filter(SpecCell);
index a59223b..921a67a 100644 (file)
@@ -44,6 +44,8 @@ public:
     
     enum { Size = 3 };
     
+    AdjacencyList() { }
+    
     AdjacencyList(Kind kind)
 #if !ASSERT_DISABLED
         : m_kind(kind)
index cd3944f..eda5782 100644 (file)
@@ -40,8 +40,12 @@ Array::Mode fromObserved(ArrayModes modes, bool makeSafe)
     switch (modes) {
     case 0:
         return Array::Undecided;
-    case IsJSArray:
-        return makeSafe ? Array::JSArrayOutOfBounds : Array::JSArray;
+    case asArrayModes(NonArrayWithArrayStorage):
+        return makeSafe ? Array::ArrayStorageOutOfBounds : Array::ArrayStorage;
+    case asArrayModes(ArrayWithArrayStorage):
+        return makeSafe ? Array::ArrayWithArrayStorageOutOfBounds : Array::ArrayWithArrayStorage;
+    case asArrayModes(NonArrayWithArrayStorage) | asArrayModes(ArrayWithArrayStorage):
+        return makeSafe ? Array::PossiblyArrayWithArrayStorageOutOfBounds : Array::PossiblyArrayWithArrayStorage;
     default:
         // We know that this is possibly a kind of array for which, though there is no
         // useful data in the array profile, we may be able to extract useful data from
@@ -120,10 +124,14 @@ bool modeAlreadyChecked(AbstractValue& value, Array::Mode arrayMode)
     case Array::String:
         return isStringSpeculation(value.m_type);
         
-    case Array::JSArray:
-    case Array::JSArrayOutOfBounds:
+    case NON_ARRAY_ARRAY_STORAGE_MODES:
         return value.m_currentKnownStructure.hasSingleton()
-            && value.m_currentKnownStructure.singleton()->classInfo() == &JSArray::s_info;
+            && (value.m_currentKnownStructure.singleton()->indexingType() & HasArrayStorage);
+
+    case ARRAY_WITH_ARRAY_STORAGE_MODES:
+        return value.m_currentKnownStructure.hasSingleton()
+            && (value.m_currentKnownStructure.singleton()->indexingType() & HasArrayStorage)
+            && (value.m_currentKnownStructure.singleton()->indexingType() & IsArray);
         
     case Array::Arguments:
         return isArgumentsSpeculation(value.m_type);
@@ -174,10 +182,18 @@ const char* modeToString(Array::Mode mode)
         return "ForceExit";
     case Array::String:
         return "String";
-    case Array::JSArray:
-        return "JSArray";
-    case Array::JSArrayOutOfBounds:
-        return "JSArrayOutOfBounds";
+    case Array::ArrayStorage:
+        return "ArrayStorage";
+    case Array::ArrayStorageOutOfBounds:
+        return "ArrayStorageOutOfBounds";
+    case Array::ArrayWithArrayStorage:
+        return "ArrayWithArrayStorage";
+    case Array::ArrayWithArrayStorageOutOfBounds:
+        return "ArrayWithArrayStorageOutOfBounds";
+    case Array::PossiblyArrayWithArrayStorage:
+        return "PossiblyArrayWithArrayStorage";
+    case Array::PossiblyArrayWithArrayStorageOutOfBounds:
+        return "PossiblyArrayWithArrayStorageOutOfBounds";
     case Array::Arguments:
         return "Arguments";
     case Array::Int8Array:
index 36a8637..2eb009b 100644 (file)
@@ -46,8 +46,12 @@ enum Mode {
     ForceExit, // Implies that we have no idea how to execute this operation, so we should just give up.
     Generic,
     String,
-    JSArray,
-    JSArrayOutOfBounds,
+    ArrayStorage,
+    ArrayStorageOutOfBounds,
+    ArrayWithArrayStorage,
+    ArrayWithArrayStorageOutOfBounds,
+    PossiblyArrayWithArrayStorage,
+    PossiblyArrayWithArrayStorageOutOfBounds,
     Arguments,
     Int8Array,
     Int16Array,
@@ -61,6 +65,29 @@ enum Mode {
 };
 } // namespace Array
 
+// Helpers for 'case' statements. For example, saying "case AllArrayStorageModes:"
+// is the same as having multiple case statements listing off all of the modes that
+// have the word "ArrayStorage" in them.
+#define NON_ARRAY_ARRAY_STORAGE_MODES                      \
+    Array::ArrayStorage:                                   \
+    case Array::ArrayStorageOutOfBounds:                   \
+    case Array::PossiblyArrayWithArrayStorage:             \
+    case Array::PossiblyArrayWithArrayStorageOutOfBounds
+#define ARRAY_WITH_ARRAY_STORAGE_MODES                     \
+    Array::ArrayWithArrayStorage:                          \
+    case Array::ArrayWithArrayStorageOutOfBounds
+#define ALL_ARRAY_STORAGE_MODES                            \
+    NON_ARRAY_ARRAY_STORAGE_MODES:                         \
+    case ARRAY_WITH_ARRAY_STORAGE_MODES
+#define IN_BOUNDS_ARRAY_STORAGE_MODES                      \
+    Array::ArrayStorage:                                   \
+    case Array::ArrayWithArrayStorage:                     \
+    case Array::PossiblyArrayWithArrayStorage
+#define OUT_OF_BOUNDS_ARRAY_STORAGE_MODES                  \
+    Array::ArrayStorageOutOfBounds:                        \
+    case Array::ArrayWithArrayStorageOutOfBounds:          \
+    case Array::PossiblyArrayWithArrayStorageOutOfBounds
+
 Array::Mode fromObserved(ArrayModes modes, bool makeSafe);
 
 Array::Mode fromStructure(Structure*, bool makeSafe);
@@ -71,11 +98,30 @@ bool modeAlreadyChecked(AbstractValue&, Array::Mode);
 
 const char* modeToString(Array::Mode);
 
+inline bool modeUsesButterfly(Array::Mode arrayMode)
+{
+    switch (arrayMode) {
+    case ALL_ARRAY_STORAGE_MODES:
+        return true;
+    default:
+        return false;
+    }
+}
+
 inline bool modeIsJSArray(Array::Mode arrayMode)
 {
     switch (arrayMode) {
-    case Array::JSArray:
-    case Array::JSArrayOutOfBounds:
+    case ARRAY_WITH_ARRAY_STORAGE_MODES:
+        return true;
+    default:
+        return false;
+    }
+}
+
+inline bool isInBoundsAccess(Array::Mode arrayMode)
+{
+    switch (arrayMode) {
+    case IN_BOUNDS_ARRAY_STORAGE_MODES:
         return true;
     default:
         return false;
@@ -114,25 +160,6 @@ inline Array::Mode modeForPut(Array::Mode arrayMode)
     }
 }
 
-inline bool modesCompatibleForStorageLoad(Array::Mode left, Array::Mode right)
-{
-    if (left == right)
-        return true;
-    
-    bool leftIsJSArray =
-        left == Array::JSArray
-        || left == Array::JSArrayOutOfBounds;
-    
-    bool rightIsJSArray =
-        right == Array::JSArray
-        || right == Array::JSArrayOutOfBounds;
-    
-    if (leftIsJSArray && rightIsJSArray)
-        return true;
-    
-    return false;
-}
-
 inline bool modeIsSpecific(Array::Mode mode)
 {
     switch (mode) {
@@ -147,7 +174,15 @@ inline bool modeIsSpecific(Array::Mode mode)
 
 inline bool modeSupportsLength(Array::Mode mode)
 {
-    return modeIsSpecific(mode);
+    switch (mode) {
+    case Array::Undecided:
+    case Array::ForceExit:
+    case Array::Generic:
+    case NON_ARRAY_ARRAY_STORAGE_MODES:
+        return false;
+    default:
+        return true;
+    }
 }
 
 } } // namespace JSC::DFG
index eea6906..39ee0e7 100644 (file)
@@ -1685,7 +1685,7 @@ void ByteCodeParser::handleGetByOffset(
     if (isInlineOffset(offset))
         propertyStorage = base;
     else
-        propertyStorage = addToGraph(GetPropertyStorage, base);
+        propertyStorage = addToGraph(GetButterfly, base);
     set(destinationOperand,
         addToGraph(
             GetByOffset, OpInfo(m_graph.m_storageAccessData.size()), OpInfo(prediction),
@@ -2318,7 +2318,7 @@ bool ByteCodeParser::parseBlock(unsigned limit)
                 if (isInlineOffset(putByIdStatus.offset()))
                     propertyStorage = base;
                 else
-                    propertyStorage = addToGraph(GetPropertyStorage, base);
+                    propertyStorage = addToGraph(GetButterfly, base);
                 addToGraph(PutByOffset, OpInfo(m_graph.m_storageAccessData.size()), propertyStorage, base, value);
                 
                 StorageAccessData storageAccessData;
@@ -2369,13 +2369,13 @@ bool ByteCodeParser::parseBlock(unsigned limit)
                     } else {
                         propertyStorage = addToGraph(
                             ReallocatePropertyStorage, OpInfo(transitionData),
-                            base, addToGraph(GetPropertyStorage, base));
+                            base, addToGraph(GetButterfly, base));
                     }
                 } else {
                     if (isInlineOffset(putByIdStatus.offset()))
                         propertyStorage = base;
                     else
-                        propertyStorage = addToGraph(GetPropertyStorage, base);
+                        propertyStorage = addToGraph(GetButterfly, base);
                 }
                 
                 addToGraph(PutStructure, OpInfo(transitionData), base);
index b368197..f58ee39 100644 (file)
@@ -583,7 +583,7 @@ private:
 
             Node& node = m_graph[index];
             switch (node.op()) {
-            case GetPropertyStorage:
+            case GetButterfly:
                 if (node.child1() == child1)
                     return index;
                 break;
@@ -1160,7 +1160,7 @@ private:
             break;
         }
 
-        case GetPropertyStorage:
+        case GetButterfly:
             setReplacement(getPropertyStorageLoadElimination(node.child1().index()));
             break;
 
index 4053d4a..2f92e56 100644 (file)
@@ -112,7 +112,7 @@ private:
                 break;
             nodePtr->setOp(GetArrayLength);
             ASSERT(nodePtr->flags() & NodeMustGenerate);
-            nodePtr->clearFlags(NodeMustGenerate);
+            nodePtr->clearFlags(NodeMustGenerate | NodeClobbersWorld);
             m_graph.deref(m_compileIndex);
             nodePtr->setArrayMode(arrayMode);
             
@@ -365,6 +365,16 @@ private:
 #endif
     }
     
+    NodeIndex addNode(const Node& node, bool shouldGenerate)
+    {
+        NodeIndex nodeIndex = m_graph.size();
+        m_graph.append(node);
+        m_insertionSet.append(m_indexInBlock, nodeIndex);
+        if (shouldGenerate)
+            m_graph[nodeIndex].ref();
+        return nodeIndex;
+    }
+    
     NodeIndex checkArray(Array::Mode arrayMode, CodeOrigin codeOrigin, NodeIndex array, bool (*storageCheck)(Array::Mode) = canCSEStorage, bool shouldGenerate = true)
     {
         ASSERT(modeIsSpecific(arrayMode));
@@ -381,15 +391,11 @@ private:
         
         if (shouldGenerate)
             m_graph.ref(array);
-        Node getIndexedPropertyStorage(
-            GetIndexedPropertyStorage, codeOrigin, OpInfo(arrayMode), array);
-        if (shouldGenerate)
-            getIndexedPropertyStorage.ref();
-        NodeIndex getIndexedPropertyStorageIndex = m_graph.size();
-        m_graph.append(getIndexedPropertyStorage);
-        m_insertionSet.append(m_indexInBlock, getIndexedPropertyStorageIndex);
         
-        return getIndexedPropertyStorageIndex;
+        if (modeUsesButterfly(arrayMode))
+            return addNode(Node(GetButterfly, codeOrigin, array), shouldGenerate);
+        
+        return addNode(Node(GetIndexedPropertyStorage, codeOrigin, OpInfo(arrayMode), array), shouldGenerate);
     }
     
     void blessArrayOperation(Edge base, unsigned storageChildIdx)
index 70cbbaf..4166f72 100644 (file)
@@ -473,7 +473,7 @@ public:
     {
         switch (node.arrayMode()) {
         case Array::Generic:
-        case Array::JSArrayOutOfBounds:
+        case OUT_OF_BOUNDS_ARRAY_STORAGE_MODES:
             return false;
         case Array::String:
             return node.op() == GetByVal;
index 0a51b71..a435879 100644 (file)
@@ -78,6 +78,8 @@ struct OpInfo {
 struct Node {
     enum VarArgTag { VarArg };
     
+    Node() { }
+    
     // Construct a node with up to 3 children, no immediate value.
     Node(NodeType op, CodeOrigin codeOrigin, NodeIndex child1 = NoNode, NodeIndex child2 = NoNode, NodeIndex child3 = NoNode)
         : codeOrigin(codeOrigin)
index d86b9b3..4c2a85c 100644 (file)
@@ -137,7 +137,7 @@ namespace JSC { namespace DFG {
     macro(PhantomPutStructure, NodeMustGenerate | NodeDoesNotExit) \
     macro(AllocatePropertyStorage, NodeMustGenerate | NodeDoesNotExit | NodeResultStorage) \
     macro(ReallocatePropertyStorage, NodeMustGenerate | NodeDoesNotExit | NodeResultStorage) \
-    macro(GetPropertyStorage, NodeResultStorage) \
+    macro(GetButterfly, NodeResultStorage) \
     macro(CheckArray, NodeMustGenerate) \
     macro(GetIndexedPropertyStorage, NodeResultStorage) \
     macro(GetByOffset, NodeResultJS) \
index b5bfd23..19a3892 100644 (file)
@@ -27,6 +27,7 @@
 #include "DFGOperations.h"
 
 #include "Arguments.h"
+#include "ButterflyInlineMethods.h"
 #include "CodeBlock.h"
 #include "CopiedSpaceInlineMethods.h"
 #include "DFGOSRExit.h"
@@ -226,14 +227,14 @@ static inline void putByVal(ExecState* exec, JSValue baseValue, uint32_t index,
     JSGlobalData& globalData = exec->globalData();
     NativeCallFrameTracer tracer(&globalData, exec);
     
-    if (isJSArray(baseValue)) {
-        JSArray* array = asArray(baseValue);
-        if (array->canSetIndex(index)) {
-            array->setIndex(globalData, index, value);
+    if (baseValue.isObject()) {
+        JSObject* object = asObject(baseValue);
+        if (object->canSetIndexQuickly(index)) {
+            object->setIndexQuickly(globalData, index, value);
             return;
         }
 
-        JSArray::putByIndex(array, exec, index, value, strict);
+        object->methodTable()->putByIndex(object, exec, index, value, strict);
         return;
     }
 
@@ -341,11 +342,12 @@ static inline EncodedJSValue getByVal(ExecState* exec, JSCell* base, uint32_t in
     JSGlobalData& globalData = exec->globalData();
     NativeCallFrameTracer tracer(&globalData, exec);
     
-    // FIXME: the JIT used to handle these in compiled code!
-    if (isJSArray(base) && asArray(base)->canGetIndex(index))
-        return JSValue::encode(asArray(base)->getIndex(index));
+    if (base->isObject()) {
+        JSObject* object = asObject(base);
+        if (object->canGetIndexQuickly(index))
+            return JSValue::encode(object->getIndexQuickly(index));
+    }
 
-    // FIXME: the JITstub used to relink this to an optimized form!
     if (isJSString(base) && asString(base)->canGetIndex(index))
         return JSValue::encode(asString(base)->getIndex(exec, index));
 
@@ -548,15 +550,15 @@ void DFG_OPERATION operationPutByValCellNonStrict(ExecState* exec, JSCell* cell,
     operationPutByValInternal<false>(exec, JSValue::encode(cell), encodedProperty, encodedValue);
 }
 
-void DFG_OPERATION operationPutByValBeyondArrayBoundsStrict(ExecState* exec, JSArray* array, int32_t index, EncodedJSValue encodedValue)
+void DFG_OPERATION operationPutByValBeyondArrayBoundsStrict(ExecState* exec, JSObject* array, int32_t index, EncodedJSValue encodedValue)
 {
     JSGlobalData* globalData = &exec->globalData();
     NativeCallFrameTracer tracer(globalData, exec);
     
     if (index >= 0) {
         // We should only get here if index is outside the existing vector.
-        ASSERT(!array->canSetIndex(index));
-        JSArray::putByIndex(array, exec, index, JSValue::decode(encodedValue), true);
+        ASSERT(!array->canSetIndexQuickly(index));
+        array->methodTable()->putByIndex(array, exec, index, JSValue::decode(encodedValue), true);
         return;
     }
     
@@ -565,15 +567,15 @@ void DFG_OPERATION operationPutByValBeyondArrayBoundsStrict(ExecState* exec, JSA
         array, exec, Identifier::from(exec, index), JSValue::decode(encodedValue), slot);
 }
 
-void DFG_OPERATION operationPutByValBeyondArrayBoundsNonStrict(ExecState* exec, JSArray* array, int32_t index, EncodedJSValue encodedValue)
+void DFG_OPERATION operationPutByValBeyondArrayBoundsNonStrict(ExecState* exec, JSObject* array, int32_t index, EncodedJSValue encodedValue)
 {
     JSGlobalData* globalData = &exec->globalData();
     NativeCallFrameTracer tracer(globalData, exec);
     
     if (index >= 0) {
         // We should only get here if index is outside the existing vector.
-        ASSERT(!array->canSetIndex(index));
-        JSArray::putByIndex(array, exec, index, JSValue::decode(encodedValue), false);
+        ASSERT(!array->canSetIndexQuickly(index));
+        array->methodTable()->putByIndex(array, exec, index, JSValue::decode(encodedValue), false);
         return;
     }
     
@@ -1263,20 +1265,29 @@ void DFG_OPERATION operationReallocateStorageAndFinishPut(ExecState* exec, JSObj
 
 char* DFG_OPERATION operationAllocatePropertyStorageWithInitialCapacity(ExecState* exec)
 {
-    JSGlobalData& globalData = exec->globalData();
-    void* result;
-    if (!globalData.heap.tryAllocateStorage(initialOutOfLineCapacity * sizeof(JSValue), &result))
-        CRASH();
-    return reinterpret_cast<char*>(reinterpret_cast<JSValue*>(result) + initialOutOfLineCapacity + 1);
+    return reinterpret_cast<char*>(
+        Butterfly::createUninitialized(exec->globalData(), 0, initialOutOfLineCapacity, false, 0));
 }
 
 char* DFG_OPERATION operationAllocatePropertyStorage(ExecState* exec, size_t newSize)
 {
-    JSGlobalData& globalData = exec->globalData();
-    void* result;
-    if (!globalData.heap.tryAllocateStorage(newSize, &result))
-        CRASH();
-    return reinterpret_cast<char*>(reinterpret_cast<JSValue*>(result) + 1) + newSize;
+    return reinterpret_cast<char*>(
+        Butterfly::createUninitialized(exec->globalData(), 0, newSize, false, 0));
+}
+
+char* DFG_OPERATION operationReallocateButterflyToHavePropertyStorageWithInitialCapacity(ExecState* exec, JSObject* object)
+{
+    ASSERT(!object->structure()->outOfLineCapacity());
+    Butterfly* result = object->growOutOfLineStorage(exec->globalData(), 0, initialOutOfLineCapacity);
+    object->setButterflyWithoutChangingStructure(result);
+    return reinterpret_cast<char*>(result);
+}
+
+char* DFG_OPERATION operationReallocateButterflyToGrowPropertyStorage(ExecState* exec, JSObject* object, size_t newSize)
+{
+    Butterfly* result = object->growOutOfLineStorage(exec->globalData(), object->structure()->outOfLineCapacity(), newSize);
+    object->setButterflyWithoutChangingStructure(result);
+    return reinterpret_cast<char*>(result);
 }
 
 double DFG_OPERATION operationFModOnInts(int32_t a, int32_t b)
index aa52703..02c6b3a 100644 (file)
@@ -95,7 +95,7 @@ typedef size_t DFG_OPERATION (*S_DFGOperation_ECC)(ExecState*, JSCell*, JSCell*)
 typedef size_t DFG_OPERATION (*S_DFGOperation_EJ)(ExecState*, EncodedJSValue);
 typedef size_t DFG_OPERATION (*S_DFGOperation_EJJ)(ExecState*, EncodedJSValue, EncodedJSValue);
 typedef size_t DFG_OPERATION (*S_DFGOperation_J)(EncodedJSValue);
-typedef void DFG_OPERATION (*V_DFGOperation_EAZJ)(ExecState*, JSArray*, int32_t, EncodedJSValue);
+typedef void DFG_OPERATION (*V_DFGOperation_EOZJ)(ExecState*, JSObject*, int32_t, EncodedJSValue);
 typedef void DFG_OPERATION (*V_DFGOperation_EC)(ExecState*, JSCell*);
 typedef void DFG_OPERATION (*V_DFGOperation_ECIcf)(ExecState*, JSCell*, InlineCallFrame*);
 typedef void DFG_OPERATION (*V_DFGOperation_ECCIcf)(ExecState*, JSCell*, JSCell*, InlineCallFrame*);
@@ -108,8 +108,10 @@ typedef void DFG_OPERATION (*V_DFGOperation_EJPP)(ExecState*, EncodedJSValue, En
 typedef void DFG_OPERATION (*V_DFGOperation_EPZJ)(ExecState*, void*, int32_t, EncodedJSValue);
 typedef void DFG_OPERATION (*V_DFGOperation_W)(WatchpointSet*);
 typedef char* DFG_OPERATION (*P_DFGOperation_E)(ExecState*);
-typedef char* DFG_OPERATION (*P_DFGOperation_ES)(ExecState*, size_t);
+typedef char* DFG_OPERATION (*P_DFGOperation_EO)(ExecState*, JSObject*);
+typedef char* DFG_OPERATION (*P_DFGOperation_EOS)(ExecState*, JSObject*, size_t);
 typedef char* DFG_OPERATION (*P_DFGOperation_EPS)(ExecState*, void*, size_t);
+typedef char* DFG_OPERATION (*P_DFGOperation_ES)(ExecState*, size_t);
 
 // These routines are provide callbacks out to C++ implementations of operations too complex to JIT.
 JSCell* DFG_OPERATION operationNewObject(ExecState*) WTF_INTERNAL;
@@ -142,8 +144,8 @@ void DFG_OPERATION operationPutByValStrict(ExecState*, EncodedJSValue encodedBas
 void DFG_OPERATION operationPutByValNonStrict(ExecState*, EncodedJSValue encodedBase, EncodedJSValue encodedProperty, EncodedJSValue encodedValue) WTF_INTERNAL;
 void DFG_OPERATION operationPutByValCellStrict(ExecState*, JSCell*, EncodedJSValue encodedProperty, EncodedJSValue encodedValue) WTF_INTERNAL;
 void DFG_OPERATION operationPutByValCellNonStrict(ExecState*, JSCell*, EncodedJSValue encodedProperty, EncodedJSValue encodedValue) WTF_INTERNAL;
-void DFG_OPERATION operationPutByValBeyondArrayBoundsStrict(ExecState*, JSArray*, int32_t index, EncodedJSValue encodedValue) WTF_INTERNAL;
-void DFG_OPERATION operationPutByValBeyondArrayBoundsNonStrict(ExecState*, JSArray*, int32_t index, EncodedJSValue encodedValue) WTF_INTERNAL;
+void DFG_OPERATION operationPutByValBeyondArrayBoundsStrict(ExecState*, JSObject*, int32_t index, EncodedJSValue encodedValue) WTF_INTERNAL;
+void DFG_OPERATION operationPutByValBeyondArrayBoundsNonStrict(ExecState*, JSObject*, int32_t index, EncodedJSValue encodedValue) WTF_INTERNAL;
 EncodedJSValue DFG_OPERATION operationArrayPush(ExecState*, EncodedJSValue encodedValue, JSArray*) WTF_INTERNAL;
 EncodedJSValue DFG_OPERATION operationArrayPop(ExecState*, JSArray*) WTF_INTERNAL;
 EncodedJSValue DFG_OPERATION operationRegExpExec(ExecState*, JSCell*, JSCell*) WTF_INTERNAL;
@@ -189,6 +191,8 @@ size_t DFG_OPERATION operationIsFunction(EncodedJSValue) WTF_INTERNAL;
 void DFG_OPERATION operationReallocateStorageAndFinishPut(ExecState*, JSObject*, Structure*, PropertyOffset, EncodedJSValue) WTF_INTERNAL;
 char* DFG_OPERATION operationAllocatePropertyStorageWithInitialCapacity(ExecState*) WTF_INTERNAL;
 char* DFG_OPERATION operationAllocatePropertyStorage(ExecState*, size_t newSize) WTF_INTERNAL;
+char* DFG_OPERATION operationReallocateButterflyToHavePropertyStorageWithInitialCapacity(ExecState*, JSObject*) WTF_INTERNAL;
+char* DFG_OPERATION operationReallocateButterflyToGrowPropertyStorage(ExecState*, JSObject*, size_t newSize) WTF_INTERNAL;
 
 // This method is used to lookup an exception hander, keyed by faultLocation, which is
 // the return location from one of the calls out to one of the helper operations above.
index af57ab8..5b23650 100644 (file)
@@ -448,7 +448,7 @@ private:
             break;
         }
             
-        case GetPropertyStorage
+        case GetButterfly
         case GetIndexedPropertyStorage:
         case AllocatePropertyStorage:
         case ReallocatePropertyStorage: {
index 1af4999..6fbbe73 100644 (file)
@@ -199,12 +199,12 @@ static void generateProtoChainAccessStub(ExecState* exec, StructureStubInfo& stu
         stubJit.load32(MacroAssembler::Address(resultGPR, OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.payload)), resultGPR);
 #endif
     } else {
-        stubJit.loadPtr(protoObject->addressOfOutOfLineStorage(), resultGPR);
+        stubJit.loadPtr(protoObject->butterflyAddress(), resultGPR);
 #if USE(JSVALUE64)
-        stubJit.loadPtr(MacroAssembler::Address(resultGPR, offsetInOutOfLineStorage(offset) * sizeof(WriteBarrier<Unknown>)), resultGPR);
+        stubJit.loadPtr(MacroAssembler::Address(resultGPR, offsetInButterfly(offset) * sizeof(WriteBarrier<Unknown>)), resultGPR);
 #elif USE(JSVALUE32_64)
-        stubJit.load32(MacroAssembler::Address(resultGPR, offsetInOutOfLineStorage(offset) * sizeof(WriteBarrier<Unknown>) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.tag)), resultTagGPR);
-        stubJit.load32(MacroAssembler::Address(resultGPR, offsetInOutOfLineStorage(offset) * sizeof(WriteBarrier<Unknown>) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.payload)), resultGPR);
+        stubJit.load32(MacroAssembler::Address(resultGPR, offsetInButterfly(offset) * sizeof(WriteBarrier<Unknown>) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.tag)), resultTagGPR);
+        stubJit.load32(MacroAssembler::Address(resultGPR, offsetInButterfly(offset) * sizeof(WriteBarrier<Unknown>) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.payload)), resultGPR);
 #endif
     }
 
@@ -254,13 +254,10 @@ static bool tryCacheGetByID(ExecState* exec, JSValue baseValue, const Identifier
         MacroAssembler::JumpList failureCases;
        
         stubJit.loadPtr(MacroAssembler::Address(baseGPR, JSCell::structureOffset()), scratchGPR); 
-        failureCases.append(stubJit.branchPtr(
-            MacroAssembler::NotEqual, 
-            MacroAssembler::Address(scratchGPR, Structure::classInfoOffset()), 
-            MacroAssembler::TrustedImmPtr(&JSArray::s_info)));
+        failureCases.append(stubJit.branch8(MacroAssembler::NotEqual, MacroAssembler::Address(baseGPR, Structure::indexingTypeOffset()), MacroAssembler::TrustedImm32(ArrayWithArrayStorage)));
         
-        stubJit.loadPtr(MacroAssembler::Address(baseGPR, JSArray::storageOffset()), scratchGPR);
-        stubJit.load32(MacroAssembler::Address(scratchGPR, OBJECT_OFFSETOF(ArrayStorage, m_length)), scratchGPR);
+        stubJit.loadPtr(MacroAssembler::Address(baseGPR, JSObject::butterflyOffset()), scratchGPR);
+        stubJit.load32(MacroAssembler::Address(scratchGPR, ArrayStorage::lengthOffset()), scratchGPR);
         failureCases.append(stubJit.branch32(MacroAssembler::LessThan, scratchGPR, MacroAssembler::TrustedImm32(0)));
 
 #if USE(JSVALUE64)
@@ -427,7 +424,7 @@ static bool tryBuildGetByIDList(ExecState* exec, JSValue baseValue, const Identi
                     stubJit.load32(MacroAssembler::Address(baseGPR, offsetRelativeToBase(slot.cachedOffset())), scratchGPR);
 #endif
                 } else {
-                    stubJit.loadPtr(MacroAssembler::Address(baseGPR, JSObject::offsetOfOutOfLineStorage()), scratchGPR);
+                    stubJit.loadPtr(MacroAssembler::Address(baseGPR, JSObject::butterflyOffset()), scratchGPR);
 #if USE(JSVALUE64)
                     stubJit.loadPtr(MacroAssembler::Address(scratchGPR, offsetRelativeToBase(slot.cachedOffset())), scratchGPR);
 #else
@@ -477,7 +474,7 @@ static bool tryBuildGetByIDList(ExecState* exec, JSValue baseValue, const Identi
                 }
 #endif
             } else {
-                stubJit.loadPtr(MacroAssembler::Address(baseGPR, JSObject::offsetOfOutOfLineStorage()), resultGPR);
+                stubJit.loadPtr(MacroAssembler::Address(baseGPR, JSObject::butterflyOffset()), resultGPR);
 #if USE(JSVALUE64)
                 stubJit.loadPtr(MacroAssembler::Address(resultGPR, offsetRelativeToBase(slot.cachedOffset())), resultGPR);
 #else
@@ -685,17 +682,17 @@ static void emitPutReplaceStub(
     if (isInlineOffset(slot.cachedOffset()))
         stubJit.storePtr(valueGPR, MacroAssembler::Address(baseGPR, JSObject::offsetOfInlineStorage() + offsetInInlineStorage(slot.cachedOffset()) * sizeof(JSValue)));
     else {
-        stubJit.loadPtr(MacroAssembler::Address(baseGPR, JSObject::offsetOfOutOfLineStorage()), scratchGPR);
-        stubJit.storePtr(valueGPR, MacroAssembler::Address(scratchGPR, offsetInOutOfLineStorage(slot.cachedOffset()) * sizeof(JSValue)));
+        stubJit.loadPtr(MacroAssembler::Address(baseGPR, JSObject::butterflyOffset()), scratchGPR);
+        stubJit.storePtr(valueGPR, MacroAssembler::Address(scratchGPR, offsetInButterfly(slot.cachedOffset()) * sizeof(JSValue)));
     }
 #elif USE(JSVALUE32_64)
     if (isInlineOffset(slot.cachedOffset())) {
         stubJit.store32(valueGPR, MacroAssembler::Address(baseGPR, JSObject::offsetOfInlineStorage() + offsetInInlineStorage(slot.cachedOffset()) * sizeof(JSValue) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.payload)));
         stubJit.store32(valueTagGPR, MacroAssembler::Address(baseGPR, JSObject::offsetOfInlineStorage() + offsetInInlineStorage(slot.cachedOffset()) * sizeof(JSValue) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.tag)));
     } else {
-        stubJit.loadPtr(MacroAssembler::Address(baseGPR, JSObject::offsetOfOutOfLineStorage()), scratchGPR);
-        stubJit.store32(valueGPR, MacroAssembler::Address(scratchGPR, offsetInOutOfLineStorage(slot.cachedOffset()) * sizeof(JSValue) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.payload)));
-        stubJit.store32(valueTagGPR, MacroAssembler::Address(scratchGPR, offsetInOutOfLineStorage(slot.cachedOffset()) * sizeof(JSValue) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.tag)));
+        stubJit.loadPtr(MacroAssembler::Address(baseGPR, JSObject::butterflyOffset()), scratchGPR);
+        stubJit.store32(valueGPR, MacroAssembler::Address(scratchGPR, offsetInButterfly(slot.cachedOffset()) * sizeof(JSValue) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.payload)));
+        stubJit.store32(valueTagGPR, MacroAssembler::Address(scratchGPR, offsetInButterfly(slot.cachedOffset()) * sizeof(JSValue) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.tag)));
     }
 #endif
     
@@ -834,7 +831,7 @@ static void emitPutTransitionStub(
             size_t oldSize = oldStructure->outOfLineCapacity() * sizeof(JSValue);
             ASSERT(newSize > oldSize);
             
-            stubJit.loadPtr(MacroAssembler::Address(baseGPR, JSObject::offsetOfOutOfLineStorage()), scratchGPR3);
+            stubJit.loadPtr(MacroAssembler::Address(baseGPR, JSObject::butterflyOffset()), scratchGPR3);
             stubJit.loadPtr(&copiedAllocator->m_currentRemaining, scratchGPR1);
             slowPath.append(stubJit.branchSubPtr(MacroAssembler::Signed, MacroAssembler::TrustedImm32(newSize), scratchGPR1));
             stubJit.storePtr(scratchGPR1, &copiedAllocator->m_currentRemaining);
@@ -848,7 +845,7 @@ static void emitPutTransitionStub(
             }
         }
         
-        stubJit.storePtr(scratchGPR1, MacroAssembler::Address(baseGPR, JSObject::offsetOfOutOfLineStorage()));
+        stubJit.storePtr(scratchGPR1, MacroAssembler::Address(baseGPR, JSObject::butterflyOffset()));
         scratchGPR1HasStorage = true;
     }
 
@@ -858,8 +855,8 @@ static void emitPutTransitionStub(
         stubJit.storePtr(valueGPR, MacroAssembler::Address(baseGPR, JSObject::offsetOfInlineStorage() + offsetInInlineStorage(slot.cachedOffset()) * sizeof(JSValue)));
     else {
         if (!scratchGPR1HasStorage)
-            stubJit.loadPtr(MacroAssembler::Address(baseGPR, JSObject::offsetOfOutOfLineStorage()), scratchGPR1);
-        stubJit.storePtr(valueGPR, MacroAssembler::Address(scratchGPR1, offsetInOutOfLineStorage(slot.cachedOffset()) * sizeof(JSValue)));
+            stubJit.loadPtr(MacroAssembler::Address(baseGPR, JSObject::butterflyOffset()), scratchGPR1);
+        stubJit.storePtr(valueGPR, MacroAssembler::Address(scratchGPR1, offsetInButterfly(slot.cachedOffset()) * sizeof(JSValue)));
     }
 #elif USE(JSVALUE32_64)
     if (isInlineOffset(slot.cachedOffset())) {
@@ -867,9 +864,9 @@ static void emitPutTransitionStub(
         stubJit.store32(valueTagGPR, MacroAssembler::Address(baseGPR, JSObject::offsetOfInlineStorage() + offsetInInlineStorage(slot.cachedOffset()) * sizeof(JSValue) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.tag)));
     } else {
         if (!scratchGPR1HasStorage)
-            stubJit.loadPtr(MacroAssembler::Address(baseGPR, JSObject::offsetOfOutOfLineStorage()), scratchGPR1);
-        stubJit.store32(valueGPR, MacroAssembler::Address(scratchGPR1, offsetInOutOfLineStorage(slot.cachedOffset()) * sizeof(JSValue) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.payload)));
-        stubJit.store32(valueTagGPR, MacroAssembler::Address(scratchGPR1, offsetInOutOfLineStorage(slot.cachedOffset()) * sizeof(JSValue) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.tag)));
+            stubJit.loadPtr(MacroAssembler::Address(baseGPR, JSObject::butterflyOffset()), scratchGPR1);
+        stubJit.store32(valueGPR, MacroAssembler::Address(scratchGPR1, offsetInButterfly(slot.cachedOffset()) * sizeof(JSValue) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.payload)));
+        stubJit.store32(valueTagGPR, MacroAssembler::Address(scratchGPR1, offsetInButterfly(slot.cachedOffset()) * sizeof(JSValue) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.tag)));
     }
 #endif
             
@@ -1024,6 +1021,11 @@ static bool tryBuildPutByIdList(ExecState* exec, JSValue baseValue, const Identi
                 && oldStructure->outOfLineCapacity())
                 return false;
             
+            // Skip optimizing the case where we need realloc, and the structure has
+            // indexing storage.
+            if (hasIndexingHeader(oldStructure->indexingType()))
+                return false;
+            
             normalizePrototypeChain(exec, baseCell);
             
             StructureChain* prototypeChain = structure->prototypeChain(exec);
index c9c07da..54b1649 100644 (file)
@@ -315,19 +315,30 @@ void SpeculativeJIT::checkArray(Node& node)
     case Array::String:
         expectedClassInfo = &JSString::s_info;
         break;
-    case Array::JSArray:
-    case Array::JSArrayOutOfBounds: {
-        // This code duplicates the code below in anticipation of this code being
-        // substantially changed in the future.
+    case NON_ARRAY_ARRAY_STORAGE_MODES: {
         GPRTemporary temp(this);
         m_jit.loadPtr(
             MacroAssembler::Address(baseReg, JSCell::structureOffset()), temp.gpr());
         speculationCheck(
             Uncountable, JSValueRegs(), NoNode,
-            m_jit.branchPtr(
+            m_jit.branchTest8(
+                MacroAssembler::Zero,
+                MacroAssembler::Address(temp.gpr(), Structure::indexingTypeOffset()),
+                MacroAssembler::TrustedImm32(HasArrayStorage)));
+        
+        noResult(m_compileIndex);
+        return;
+    }
+    case ARRAY_WITH_ARRAY_STORAGE_MODES: {
+        GPRTemporary temp(this);
+        m_jit.loadPtr(
+            MacroAssembler::Address(baseReg, JSCell::structureOffset()), temp.gpr());
+        speculationCheck(
+            Uncountable, JSValueRegs(), NoNode,
+            m_jit.branch8(
                 MacroAssembler::NotEqual,
-                MacroAssembler::Address(temp.gpr(), Structure::classInfoOffset()),
-                MacroAssembler::TrustedImmPtr(&JSArray::s_info)));
+                MacroAssembler::Address(temp.gpr(), Structure::indexingTypeOffset()),
+                MacroAssembler::TrustedImm32(ArrayWithArrayStorage)));
         
         noResult(m_compileIndex);
         return;
@@ -3006,11 +3017,6 @@ void SpeculativeJIT::compileGetIndexedPropertyStorage(Node& node)
         m_jit.loadPtr(MacroAssembler::Address(storageReg, StringImpl::dataOffset()), storageReg);
         break;
         
-    case Array::JSArray:
-    case Array::JSArrayOutOfBounds:
-        m_jit.loadPtr(MacroAssembler::Address(baseReg, JSArray::storageOffset()), storageReg);
-        break;
-        
     default:
         ASSERT(descriptor);
         m_jit.loadPtr(MacroAssembler::Address(baseReg, descriptor->m_storageOffset), storageReg);
@@ -3125,13 +3131,12 @@ void SpeculativeJIT::compileGetArrayLength(Node& node)
     const TypedArrayDescriptor* descriptor = typedArrayDescriptor(node.arrayMode());
 
     switch (node.arrayMode()) {
-    case Array::JSArray:
-    case Array::JSArrayOutOfBounds: {
+    case ARRAY_WITH_ARRAY_STORAGE_MODES: {
         StorageOperand storage(this, node.child2());
         GPRTemporary result(this, storage);
         GPRReg storageReg = storage.gpr();
         GPRReg resultReg = result.gpr();
-        m_jit.load32(MacroAssembler::Address(storageReg, OBJECT_OFFSETOF(ArrayStorage, m_length)), resultReg);
+        m_jit.load32(MacroAssembler::Address(storageReg, ArrayStorage::lengthOffset()), resultReg);
             
         speculationCheck(Uncountable, JSValueRegs(), NoNode, m_jit.branch32(MacroAssembler::LessThan, resultReg, MacroAssembler::TrustedImm32(0)));
             
@@ -3227,6 +3232,20 @@ bool SpeculativeJIT::compileRegExpExec(Node& node)
 
 void SpeculativeJIT::compileAllocatePropertyStorage(Node& node)
 {
+    if (hasIndexingHeader(node.structureTransitionData().previousStructure->indexingType())) {
+        SpeculateCellOperand base(this, node.child1());
+        
+        GPRReg baseGPR = base.gpr();
+        
+        flushRegisters();
+
+        GPRResult result(this);
+        callOperation(operationReallocateButterflyToHavePropertyStorageWithInitialCapacity, result.gpr(), baseGPR);
+        
+        storageResult(result.gpr(), m_compileIndex);
+        return;
+    }
+    
     SpeculateCellOperand base(this, node.child1());
     GPRTemporary scratch(this);
         
@@ -3248,13 +3267,31 @@ void SpeculativeJIT::compileAllocatePropertyStorage(Node& node)
     addSlowPathGenerator(
         slowPathCall(slowPath, this, operationAllocatePropertyStorageWithInitialCapacity, scratchGPR));
         
-    m_jit.storePtr(scratchGPR, JITCompiler::Address(baseGPR, JSObject::offsetOfOutOfLineStorage()));
+    m_jit.storePtr(scratchGPR, JITCompiler::Address(baseGPR, JSObject::butterflyOffset()));
         
     storageResult(scratchGPR, m_compileIndex);
 }
 
 void SpeculativeJIT::compileReallocatePropertyStorage(Node& node)
 {
+    size_t oldSize = node.structureTransitionData().previousStructure->outOfLineCapacity() * sizeof(JSValue);
+    size_t newSize = oldSize * outOfLineGrowthFactor;
+    ASSERT(newSize == node.structureTransitionData().newStructure->outOfLineCapacity() * sizeof(JSValue));
+
+    if (hasIndexingHeader(node.structureTransitionData().previousStructure->indexingType())) {
+        SpeculateCellOperand base(this, node.child1());
+        
+        GPRReg baseGPR = base.gpr();
+        
+        flushRegisters();
+
+        GPRResult result(this);
+        callOperation(operationReallocateButterflyToGrowPropertyStorage, result.gpr(), baseGPR, newSize / sizeof(JSValue));
+        
+        storageResult(result.gpr(), m_compileIndex);
+        return;
+    }
+    
     SpeculateCellOperand base(this, node.child1());
     StorageOperand oldStorage(this, node.child2());
     GPRTemporary scratch1(this);
@@ -3267,9 +3304,6 @@ void SpeculativeJIT::compileReallocatePropertyStorage(Node& node)
         
     JITCompiler::Jump slowPath;
         
-    size_t oldSize = node.structureTransitionData().previousStructure->outOfLineCapacity() * sizeof(JSValue);
-    size_t newSize = oldSize * outOfLineGrowthFactor;
-    ASSERT(newSize == node.structureTransitionData().newStructure->outOfLineCapacity() * sizeof(JSValue));
     CopiedAllocator* copiedAllocator = &m_jit.globalData()->heap.storageAllocator();
         
     m_jit.loadPtr(&copiedAllocator->m_currentRemaining, scratchGPR2);
@@ -3280,13 +3314,13 @@ void SpeculativeJIT::compileReallocatePropertyStorage(Node& node)
     m_jit.addPtr(JITCompiler::TrustedImm32(sizeof(JSValue)), scratchGPR2);
         
     addSlowPathGenerator(
-        slowPathCall(slowPath, this, operationAllocatePropertyStorage, scratchGPR2, newSize));
+        slowPathCall(slowPath, this, operationAllocatePropertyStorage, scratchGPR2, newSize / sizeof(JSValue)));
     // We have scratchGPR2 = new storage, scratchGPR1 = scratch
     for (ptrdiff_t offset = 0; offset < static_cast<ptrdiff_t>(oldSize); offset += sizeof(void*)) {
         m_jit.loadPtr(JITCompiler::Address(oldStorageGPR, -(offset + sizeof(JSValue) + sizeof(void*))), scratchGPR1);
         m_jit.storePtr(scratchGPR1, JITCompiler::Address(scratchGPR2, -(offset + sizeof(JSValue) + sizeof(void*))));
     }
-    m_jit.storePtr(scratchGPR2, JITCompiler::Address(baseGPR, JSObject::offsetOfOutOfLineStorage()));
+    m_jit.storePtr(scratchGPR2, JITCompiler::Address(baseGPR, JSObject::butterflyOffset()));
     
     storageResult(scratchGPR2, m_compileIndex);
 }
index 06a8d9e..286b72c 100644 (file)
@@ -1156,9 +1156,14 @@ public:
         m_jit.setupArgumentsExecState();
         return appendCallWithExceptionCheckSetResult(operation, result);
     }
-    JITCompiler::Call callOperation(P_DFGOperation_ES operation, GPRReg result, size_t size)
+    JITCompiler::Call callOperation(P_DFGOperation_EO operation, GPRReg result, GPRReg object)
     {
-        m_jit.setupArgumentsWithExecState(TrustedImmPtr(size));
+        m_jit.setupArgumentsWithExecState(object);
+        return appendCallWithExceptionCheckSetResult(operation, result);
+    }
+    JITCompiler::Call callOperation(P_DFGOperation_EOS operation, GPRReg result, GPRReg object, size_t size)
+    {
+        m_jit.setupArgumentsWithExecState(object, TrustedImmPtr(size));
         return appendCallWithExceptionCheckSetResult(operation, result);
     }
     JITCompiler::Call callOperation(P_DFGOperation_EPS operation, GPRReg result, GPRReg old, size_t size)
@@ -1166,6 +1171,11 @@ public:
         m_jit.setupArgumentsWithExecState(old, TrustedImmPtr(size));
         return appendCallWithExceptionCheckSetResult(operation, result);
     }
+    JITCompiler::Call callOperation(P_DFGOperation_ES operation, GPRReg result, size_t size)
+    {
+        m_jit.setupArgumentsWithExecState(TrustedImmPtr(size));
+        return appendCallWithExceptionCheckSetResult(operation, result);
+    }
     JITCompiler::Call callOperation(J_DFGOperation_E operation, GPRReg result)
     {
         m_jit.setupArgumentsExecState();
@@ -1378,7 +1388,7 @@ public:
         m_jit.setupArgumentsWithExecState(arg1, arg2, arg3);
         return appendCallWithExceptionCheck(operation);
     }
-    JITCompiler::Call callOperation(V_DFGOperation_EAZJ operation, GPRReg arg1, GPRReg arg2, GPRReg arg3)
+    JITCompiler::Call callOperation(V_DFGOperation_EOZJ operation, GPRReg arg1, GPRReg arg2, GPRReg arg3)
     {
         m_jit.setupArgumentsWithExecState(arg1, arg2, arg3);
         return appendCallWithExceptionCheck(operation);
@@ -1448,6 +1458,21 @@ public:
         m_jit.setupArgumentsExecState();
         return appendCallWithExceptionCheckSetResult(operation, result);
     }
+    JITCompiler::Call callOperation(P_DFGOperation_EO operation, GPRReg result, GPRReg arg1)
+    {
+        m_jit.setupArgumentsWithExecState(arg1);
+        return appendCallWithExceptionCheckSetResult(operation, result);
+    }
+    JITCompiler::Call callOperation(P_DFGOperation_EOS operation, GPRReg result, GPRReg arg1, size_t arg2)
+    {
+        m_jit.setupArgumentsWithExecState(arg1, TrustedImmPtr(arg2));
+        return appendCallWithExceptionCheckSetResult(operation, result);
+    }
+    JITCompiler::Call callOperation(P_DFGOperation_EPS operation, GPRReg result, GPRReg old, size_t size)
+    {
+        m_jit.setupArgumentsWithExecState(old, TrustedImmPtr(size));
+        return appendCallWithExceptionCheckSetResult(operation, result);
+    }
     JITCompiler::Call callOperation(P_DFGOperation_ES operation, GPRReg result, size_t size)
     {
         m_jit.setupArgumentsWithExecState(TrustedImmPtr(size));
@@ -1696,7 +1721,7 @@ public:
         m_jit.setupArgumentsWithExecState(arg1, arg2, EABI_32BIT_DUMMY_ARG arg3Payload, arg3Tag);
         return appendCallWithExceptionCheck(operation);
     }
-    JITCompiler::Call callOperation(V_DFGOperation_EAZJ operation, GPRReg arg1, GPRReg arg2, GPRReg arg3Tag, GPRReg arg3Payload)
+    JITCompiler::Call callOperation(V_DFGOperation_EOZJ operation, GPRReg arg1, GPRReg arg2, GPRReg arg3Tag, GPRReg arg3Payload)
     {
         m_jit.setupArgumentsWithExecState(arg1, arg2, EABI_32BIT_DUMMY_ARG arg3Payload, arg3Tag);
         return appendCallWithExceptionCheck(operation);
@@ -2185,7 +2210,7 @@ public:
         m_jit.storePtr(structure, MacroAssembler::Address(resultGPR, JSCell::structureOffset()));
         
         // Initialize the object's property storage pointer.
-        m_jit.storePtr(MacroAssembler::TrustedImmPtr(0), MacroAssembler::Address(resultGPR, ClassType::offsetOfOutOfLineStorage()));
+        m_jit.storePtr(MacroAssembler::TrustedImmPtr(0), MacroAssembler::Address(resultGPR, JSObject::butterflyOffset()));
     }
 
     template<typename T>
index 38889fd..f40db37 100644 (file)
@@ -508,7 +508,7 @@ void SpeculativeJIT::cachedGetById(CodeOrigin codeOrigin, GPRReg baseTagGPROrNon
     JITCompiler::DataLabelPtr structureToCompare;
     JITCompiler::PatchableJump structureCheck = m_jit.patchableBranchPtrWithPatch(JITCompiler::NotEqual, JITCompiler::Address(basePayloadGPR, JSCell::structureOffset()), structureToCompare, JITCompiler::TrustedImmPtr(reinterpret_cast<void*>(-1)));
     
-    JITCompiler::ConvertibleLoadLabel propertyStorageLoad = m_jit.convertibleLoadPtr(JITCompiler::Address(basePayloadGPR, JSObject::offsetOfOutOfLineStorage()), resultPayloadGPR);
+    JITCompiler::ConvertibleLoadLabel propertyStorageLoad = m_jit.convertibleLoadPtr(JITCompiler::Address(basePayloadGPR, JSObject::butterflyOffset()), resultPayloadGPR);
     JITCompiler::DataLabelCompact tagLoadWithPatch = m_jit.load32WithCompactAddressOffsetPatch(JITCompiler::Address(resultPayloadGPR, OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.tag)), resultTagGPR);
     JITCompiler::DataLabelCompact payloadLoadWithPatch = m_jit.load32WithCompactAddressOffsetPatch(JITCompiler::Address(resultPayloadGPR, OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.payload)), resultPayloadGPR);
     
@@ -565,7 +565,7 @@ void SpeculativeJIT::cachedPutById(CodeOrigin codeOrigin, GPRReg basePayloadGPR,
 
     writeBarrier(basePayloadGPR, valueTagGPR, valueUse, WriteBarrierForPropertyAccess, scratchGPR);
 
-    JITCompiler::ConvertibleLoadLabel propertyStorageLoad = m_jit.convertibleLoadPtr(JITCompiler::Address(basePayloadGPR, JSObject::offsetOfOutOfLineStorage()), scratchGPR);
+    JITCompiler::ConvertibleLoadLabel propertyStorageLoad = m_jit.convertibleLoadPtr(JITCompiler::Address(basePayloadGPR, JSObject::butterflyOffset()), scratchGPR);
     JITCompiler::DataLabel32 tagStoreWithPatch = m_jit.store32WithAddressOffsetPatch(valueTagGPR, JITCompiler::Address(scratchGPR, OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.tag)));
     JITCompiler::DataLabel32 payloadStoreWithPatch = m_jit.store32WithAddressOffsetPatch(valuePayloadGPR, JITCompiler::Address(scratchGPR, OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.payload)));
 
@@ -2554,7 +2554,7 @@ void SpeculativeJIT::compile(Node& node)
             jsValueResult(resultTag.gpr(), resultPayload.gpr(), m_compileIndex);
             break;
         }
-        case Array::JSArray: {
+        case IN_BOUNDS_ARRAY_STORAGE_MODES: {
             SpeculateStrictInt32Operand property(this, node.child2());
             StorageOperand storage(this, node.child3());
             GPRReg propertyReg = property.gpr();
@@ -2563,14 +2563,7 @@ void SpeculativeJIT::compile(Node& node)
             if (!m_compileOkay)
                 return;
 
-            // Check that base is an array, and that property is contained within m_vector (< m_vectorLength).
-            // If we have predicted the base to be type array, we can skip the check.
-            {
-                SpeculateCellOperand base(this, node.child1());
-                GPRReg baseReg = base.gpr();
-                // We've already speculated that it's some kind of array, at this point.
-                speculationCheck(OutOfBounds, JSValueRegs(), NoNode, m_jit.branch32(MacroAssembler::AboveOrEqual, propertyReg, MacroAssembler::Address(baseReg, JSArray::vectorLengthOffset())));
-            }
+            speculationCheck(OutOfBounds, JSValueRegs(), NoNode, m_jit.branch32(MacroAssembler::AboveOrEqual, propertyReg, MacroAssembler::Address(storageReg, ArrayStorage::vectorLengthOffset())));
 
             GPRTemporary resultTag(this);
             GPRTemporary resultPayload(this);
@@ -2582,12 +2575,13 @@ void SpeculativeJIT::compile(Node& node)
             jsValueResult(resultTag.gpr(), resultPayload.gpr(), m_compileIndex);
             break;
         }
-        case Array::JSArrayOutOfBounds: {
+        case OUT_OF_BOUNDS_ARRAY_STORAGE_MODES: {
             SpeculateCellOperand base(this, node.child1());
             SpeculateStrictInt32Operand property(this, node.child2());
             StorageOperand storage(this, node.child3());
             GPRReg propertyReg = property.gpr();
             GPRReg storageReg = storage.gpr();
+            GPRReg baseReg = base.gpr();
 
             if (!m_compileOkay)
                 return;
@@ -2597,13 +2591,9 @@ void SpeculativeJIT::compile(Node& node)
             GPRReg resultTagReg = resultTag.gpr();
             GPRReg resultPayloadReg = resultPayload.gpr();
 
-            // Check that base is an array, and that property is contained within m_vector (< m_vectorLength).
-            // If we have predicted the base to be type array, we can skip the check.
-            GPRReg baseReg = base.gpr();
-            // We've already speculated that it's some kind of array, at this point.
             JITCompiler::Jump outOfBounds = m_jit.branch32(
                 MacroAssembler::AboveOrEqual, propertyReg,
-                MacroAssembler::Address(baseReg, JSArray::vectorLengthOffset()));
+                MacroAssembler::Address(storageReg, ArrayStorage::vectorLengthOffset()));
 
             m_jit.load32(MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesEight, OBJECT_OFFSETOF(ArrayStorage, m_vector[0]) + OBJECT_OFFSETOF(JSValue, u.asBits.tag)), resultTagReg);
             JITCompiler::Jump hole = m_jit.branch32(
@@ -2712,8 +2702,7 @@ void SpeculativeJIT::compile(Node& node)
         GPRReg propertyReg = property.gpr();
 
         switch (arrayMode) {
-        case Array::JSArray:
-        case Array::JSArrayOutOfBounds: {
+        case ALL_ARRAY_STORAGE_MODES: {
             JSValueOperand value(this, child3);
 
             GPRReg valueTagReg = value.tagGPR();
@@ -2741,8 +2730,8 @@ void SpeculativeJIT::compile(Node& node)
                 break;
             }
 
-            MacroAssembler::Jump beyondArrayBounds = m_jit.branch32(MacroAssembler::AboveOrEqual, propertyReg, MacroAssembler::Address(baseReg, JSArray::vectorLengthOffset()));
-            if (arrayMode == Array::JSArray)
+            MacroAssembler::Jump beyondArrayBounds = m_jit.branch32(MacroAssembler::AboveOrEqual, propertyReg, MacroAssembler::Address(storageReg, ArrayStorage::vectorLengthOffset()));
+            if (isInBoundsAccess(node.arrayMode()))
                 speculationCheck(OutOfBounds, JSValueRegs(), NoNode, beyondArrayBounds);
             
             base.use();
@@ -2755,9 +2744,9 @@ void SpeculativeJIT::compile(Node& node)
             m_jit.add32(TrustedImm32(1), MacroAssembler::Address(storageReg, OBJECT_OFFSETOF(ArrayStorage, m_numValuesInVector)));
 
             // If we're writing to a hole we might be growing the array; 
-            MacroAssembler::Jump lengthDoesNotNeedUpdate = m_jit.branch32(MacroAssembler::Below, propertyReg, MacroAssembler::Address(storageReg, OBJECT_OFFSETOF(ArrayStorage, m_length)));
+            MacroAssembler::Jump lengthDoesNotNeedUpdate = m_jit.branch32(MacroAssembler::Below, propertyReg, MacroAssembler::Address(storageReg, ArrayStorage::lengthOffset()));
             m_jit.add32(TrustedImm32(1), propertyReg);
-            m_jit.store32(propertyReg, MacroAssembler::Address(storageReg, OBJECT_OFFSETOF(ArrayStorage, m_length)));
+            m_jit.store32(propertyReg, MacroAssembler::Address(storageReg, ArrayStorage::lengthOffset()));
             m_jit.sub32(TrustedImm32(1), propertyReg);
 
             lengthDoesNotNeedUpdate.link(&m_jit);
@@ -2767,7 +2756,7 @@ void SpeculativeJIT::compile(Node& node)
             m_jit.store32(valueTagReg, MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesEight, OBJECT_OFFSETOF(ArrayStorage, m_vector[0]) + OBJECT_OFFSETOF(JSValue, u.asBits.tag)));
             m_jit.store32(valuePayloadReg, MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesEight, OBJECT_OFFSETOF(ArrayStorage, m_vector[0]) + OBJECT_OFFSETOF(JSValue, u.asBits.payload)));
         
-            if (arrayMode == Array::JSArrayOutOfBounds) {
+            if (!isInBoundsAccess(node.arrayMode())) {
                 addSlowPathGenerator(
                     slowPathCall(
                         beyondArrayBounds, this,
@@ -2897,18 +2886,18 @@ void SpeculativeJIT::compile(Node& node)
         StorageOperand storage(this, node.child3());
         GPRReg storageGPR = storage.gpr();
 
-        m_jit.load32(MacroAssembler::Address(storageGPR, OBJECT_OFFSETOF(ArrayStorage, m_length)), storageLengthGPR);
+        m_jit.load32(MacroAssembler::Address(storageGPR, ArrayStorage::lengthOffset()), storageLengthGPR);
         
         // Refuse to handle bizarre lengths.
         speculationCheck(Uncountable, JSValueRegs(), NoNode, m_jit.branch32(MacroAssembler::Above, storageLengthGPR, TrustedImm32(0x7ffffffe)));
         
-        MacroAssembler::Jump slowPath = m_jit.branch32(MacroAssembler::AboveOrEqual, storageLengthGPR, MacroAssembler::Address(baseGPR, JSArray::vectorLengthOffset()));
+        MacroAssembler::Jump slowPath = m_jit.branch32(MacroAssembler::AboveOrEqual, storageLengthGPR, MacroAssembler::Address(storageGPR, ArrayStorage::vectorLengthOffset()));
         
         m_jit.store32(valueTagGPR, MacroAssembler::BaseIndex(storageGPR, storageLengthGPR, MacroAssembler::TimesEight, OBJECT_OFFSETOF(ArrayStorage, m_vector[0]) + OBJECT_OFFSETOF(JSValue, u.asBits.tag)));
         m_jit.store32(valuePayloadGPR, MacroAssembler::BaseIndex(storageGPR, storageLengthGPR, MacroAssembler::TimesEight, OBJECT_OFFSETOF(ArrayStorage, m_vector[0]) + OBJECT_OFFSETOF(JSValue, u.asBits.payload)));
         
         m_jit.add32(TrustedImm32(1), storageLengthGPR);
-        m_jit.store32(storageLengthGPR, MacroAssembler::Address(storageGPR, OBJECT_OFFSETOF(ArrayStorage, m_length)));
+        m_jit.store32(storageLengthGPR, MacroAssembler::Address(storageGPR, ArrayStorage::lengthOffset()));
         m_jit.add32(TrustedImm32(1), MacroAssembler::Address(storageGPR, OBJECT_OFFSETOF(ArrayStorage, m_numValuesInVector)));
         m_jit.move(TrustedImm32(JSValue::Int32Tag), storageGPR);
         
@@ -2933,19 +2922,19 @@ void SpeculativeJIT::compile(Node& node)
         GPRReg storageGPR = storage.gpr();
         GPRReg storageLengthGPR = storageLength.gpr();
         
-        m_jit.load32(MacroAssembler::Address(storageGPR, OBJECT_OFFSETOF(ArrayStorage, m_length)), storageLengthGPR);
+        m_jit.load32(MacroAssembler::Address(storageGPR, ArrayStorage::lengthOffset()), storageLengthGPR);
         
         JITCompiler::JumpList setUndefinedCases;
         setUndefinedCases.append(m_jit.branchTest32(MacroAssembler::Zero, storageLengthGPR));
         
         m_jit.sub32(TrustedImm32(1), storageLengthGPR);
         
-        MacroAssembler::Jump slowCase = m_jit.branch32(MacroAssembler::AboveOrEqual, storageLengthGPR, MacroAssembler::Address(baseGPR, JSArray::vectorLengthOffset()));
+        MacroAssembler::Jump slowCase = m_jit.branch32(MacroAssembler::AboveOrEqual, storageLengthGPR, MacroAssembler::Address(storageGPR, ArrayStorage::vectorLengthOffset()));
         
         m_jit.load32(MacroAssembler::BaseIndex(storageGPR, storageLengthGPR, MacroAssembler::TimesEight, OBJECT_OFFSETOF(ArrayStorage, m_vector[0]) + OBJECT_OFFSETOF(JSValue, u.asBits.tag)), valueTagGPR);
         m_jit.load32(MacroAssembler::BaseIndex(storageGPR, storageLengthGPR, MacroAssembler::TimesEight, OBJECT_OFFSETOF(ArrayStorage, m_vector[0]) + OBJECT_OFFSETOF(JSValue, u.asBits.payload)), valuePayloadGPR);
         
-        m_jit.store32(storageLengthGPR, MacroAssembler::Address(storageGPR, OBJECT_OFFSETOF(ArrayStorage, m_length)));
+        m_jit.store32(storageLengthGPR, MacroAssembler::Address(storageGPR, ArrayStorage::lengthOffset()));
 
         setUndefinedCases.append(m_jit.branch32(MacroAssembler::Equal, TrustedImm32(JSValue::EmptyValueTag), valueTagGPR));
         
@@ -3589,14 +3578,14 @@ void SpeculativeJIT::compile(Node& node)
         compileReallocatePropertyStorage(node);
         break;
         
-    case GetPropertyStorage: {
+    case GetButterfly: {
         SpeculateCellOperand base(this, node.child1());
         GPRTemporary result(this, base);
         
         GPRReg baseGPR = base.gpr();
         GPRReg resultGPR = result.gpr();
         
-        m_jit.loadPtr(JITCompiler::Address(baseGPR, JSObject::offsetOfOutOfLineStorage()), resultGPR);
+        m_jit.loadPtr(JITCompiler::Address(baseGPR, JSObject::butterflyOffset()), resultGPR);
         
         storageResult(resultGPR, m_compileIndex);
         break;
@@ -3956,7 +3945,7 @@ void SpeculativeJIT::compile(Node& node)
         JITCompiler::Jump structuresNotMatch = m_jit.branchPtr(JITCompiler::NotEqual, resultPayloadGPR, JITCompiler::Address(globalObjectGPR, JSCell::structureOffset()));
 
         // Fast case
-        m_jit.loadPtr(JITCompiler::Address(globalObjectGPR, JSObject::offsetOfOutOfLineStorage()), resultPayloadGPR);
+        m_jit.loadPtr(JITCompiler::Address(globalObjectGPR, JSObject::butterflyOffset()), resultPayloadGPR);
         m_jit.load32(JITCompiler::Address(resolveInfoGPR, OBJECT_OFFSETOF(GlobalResolveInfo, offset)), resolveInfoGPR);
 #if DFG_ENABLE(JIT_ASSERT)
         JITCompiler::Jump isOutOfLine = m_jit.branch32(JITCompiler::GreaterThanOrEqual, resolveInfoGPR, TrustedImm32(inlineStorageCapacity));
index 0435df9..aa5fe67 100644 (file)
@@ -498,7 +498,7 @@ void SpeculativeJIT::cachedGetById(CodeOrigin codeOrigin, GPRReg baseGPR, GPRReg
     JITCompiler::PatchableJump structureCheck = m_jit.patchableBranchPtrWithPatch(JITCompiler::NotEqual, JITCompiler::Address(baseGPR, JSCell::structureOffset()), structureToCompare, JITCompiler::TrustedImmPtr(reinterpret_cast<void*>(-1)));
     
     JITCompiler::ConvertibleLoadLabel propertyStorageLoad =
-        m_jit.convertibleLoadPtr(JITCompiler::Address(baseGPR, JSObject::offsetOfOutOfLineStorage()), resultGPR);
+        m_jit.convertibleLoadPtr(JITCompiler::Address(baseGPR, JSObject::butterflyOffset()), resultGPR);
     JITCompiler::DataLabelCompact loadWithPatch = m_jit.loadPtrWithCompactAddressOffsetPatch(JITCompiler::Address(resultGPR, 0), resultGPR);
     
     JITCompiler::Label doneLabel = m_jit.label();
@@ -534,7 +534,7 @@ void SpeculativeJIT::cachedPutById(CodeOrigin codeOrigin, GPRReg baseGPR, GPRReg
     writeBarrier(baseGPR, valueGPR, valueUse, WriteBarrierForPropertyAccess, scratchGPR);
 
     JITCompiler::ConvertibleLoadLabel propertyStorageLoad =
-        m_jit.convertibleLoadPtr(JITCompiler::Address(baseGPR, JSObject::offsetOfOutOfLineStorage()), scratchGPR);
+        m_jit.convertibleLoadPtr(JITCompiler::Address(baseGPR, JSObject::butterflyOffset()), scratchGPR);
     JITCompiler::DataLabel32 storeWithPatch = m_jit.storePtrWithAddressOffsetPatch(valueGPR, JITCompiler::Address(scratchGPR, 0));
 
     JITCompiler::Label doneLabel = m_jit.label();
@@ -2584,8 +2584,26 @@ void SpeculativeJIT::compile(Node& node)
             jsValueResult(result.gpr(), m_compileIndex);
             break;
         }
-        case Array::JSArray:
-        case Array::JSArrayOutOfBounds: {
+        case IN_BOUNDS_ARRAY_STORAGE_MODES: {
+            SpeculateStrictInt32Operand property(this, node.child2());
+            StorageOperand storage(this, node.child3());
+            
+            GPRReg propertyReg = property.gpr();
+            GPRReg storageReg = storage.gpr();
+            
+            if (!m_compileOkay)
+                return;
+            
+            speculationCheck(OutOfBounds, JSValueRegs(), NoNode, m_jit.branch32(MacroAssembler::AboveOrEqual, propertyReg, MacroAssembler::Address(storageReg, ArrayStorage::vectorLengthOffset())));
+            
+            GPRTemporary result(this);
+            m_jit.loadPtr(MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::ScalePtr, OBJECT_OFFSETOF(ArrayStorage, m_vector[0])), result.gpr());
+            speculationCheck(OutOfBounds, JSValueRegs(), NoNode, m_jit.branchTestPtr(MacroAssembler::Zero, result.gpr()));
+            
+            jsValueResult(result.gpr(), m_compileIndex);
+            break;
+        }
+        case OUT_OF_BOUNDS_ARRAY_STORAGE_MODES: {
             SpeculateCellOperand base(this, node.child1());
             SpeculateStrictInt32Operand property(this, node.child2());
             StorageOperand storage(this, node.child3());
@@ -2597,27 +2615,19 @@ void SpeculativeJIT::compile(Node& node)
             if (!m_compileOkay)
                 return;
             
-            // We will have already speculated that the base is some kind of array,
-            // at this point.
-            
-            MacroAssembler::Jump outOfBounds = m_jit.branch32(MacroAssembler::AboveOrEqual, propertyReg, MacroAssembler::Address(baseReg, JSArray::vectorLengthOffset()));
-            if (node.arrayMode() == Array::JSArray)
-                speculationCheck(OutOfBounds, JSValueRegs(), NoNode, outOfBounds);
+            MacroAssembler::Jump outOfBounds = m_jit.branch32(MacroAssembler::AboveOrEqual, propertyReg, MacroAssembler::Address(storageReg, ArrayStorage::vectorLengthOffset()));
             
             GPRTemporary result(this);
             m_jit.loadPtr(MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::ScalePtr, OBJECT_OFFSETOF(ArrayStorage, m_vector[0])), result.gpr());
             MacroAssembler::Jump hole = m_jit.branchTestPtr(MacroAssembler::Zero, result.gpr());
-            if (node.arrayMode() == Array::JSArray)
-                speculationCheck(OutOfBounds, JSValueRegs(), NoNode, hole);
-            else {
-                MacroAssembler::JumpList slowCases;
-                slowCases.append(outOfBounds);
-                slowCases.append(hole);
-                addSlowPathGenerator(
-                    slowPathCall(
-                        slowCases, this, operationGetByValArrayInt,
-                        result.gpr(), baseReg, propertyReg));
-            }
+
+            MacroAssembler::JumpList slowCases;
+            slowCases.append(outOfBounds);
+            slowCases.append(hole);
+            addSlowPathGenerator(
+                slowPathCall(
+                    slowCases, this, operationGetByValArrayInt,
+                    result.gpr(), baseReg, propertyReg));
             
             jsValueResult(result.gpr(), m_compileIndex);
             break;
@@ -2703,6 +2713,9 @@ void SpeculativeJIT::compile(Node& node)
         if (alreadyHandled)
             break;
         
+        // FIXME: the base may not be necessary for some array access modes. But we have to
+        // keep it alive to this point, so it's likely to be in a register anyway. Likely
+        // no harm in locking it here.
         SpeculateCellOperand base(this, child1);
         SpeculateStrictInt32Operand property(this, child2);
         
@@ -2710,11 +2723,9 @@ void SpeculativeJIT::compile(Node& node)
         GPRReg propertyReg = property.gpr();
 
         switch (arrayMode) {
-        case Array::JSArray:
-        case Array::JSArrayOutOfBounds: {
+        case ALL_ARRAY_STORAGE_MODES: {
             JSValueOperand value(this, child3);
 
-            // Map base, property & value into registers, allocate a scratch register.
             GPRReg valueReg = value.gpr();
         
             if (!m_compileOkay)
@@ -2738,8 +2749,8 @@ void SpeculativeJIT::compile(Node& node)
                 break;
             }
             
-            MacroAssembler::Jump beyondArrayBounds = m_jit.branch32(MacroAssembler::AboveOrEqual, propertyReg, MacroAssembler::Address(baseReg, JSArray::vectorLengthOffset()));
-            if (arrayMode == Array::JSArray)
+            MacroAssembler::Jump beyondArrayBounds = m_jit.branch32(MacroAssembler::AboveOrEqual, propertyReg, MacroAssembler::Address(storageReg, ArrayStorage::vectorLengthOffset()));
+            if (isInBoundsAccess(arrayMode))
                 speculationCheck(OutOfBounds, JSValueRegs(), NoNode, beyondArrayBounds);
 
             base.use();
@@ -2752,9 +2763,9 @@ void SpeculativeJIT::compile(Node& node)
             m_jit.add32(TrustedImm32(1), MacroAssembler::Address(storageReg, OBJECT_OFFSETOF(ArrayStorage, m_numValuesInVector)));
 
             // If we're writing to a hole we might be growing the array; 
-            MacroAssembler::Jump lengthDoesNotNeedUpdate = m_jit.branch32(MacroAssembler::Below, propertyReg, MacroAssembler::Address(storageReg, OBJECT_OFFSETOF(ArrayStorage, m_length)));
+            MacroAssembler::Jump lengthDoesNotNeedUpdate = m_jit.branch32(MacroAssembler::Below, propertyReg, MacroAssembler::Address(storageReg, ArrayStorage::lengthOffset()));
             m_jit.add32(TrustedImm32(1), propertyReg);
-            m_jit.store32(propertyReg, MacroAssembler::Address(storageReg, OBJECT_OFFSETOF(ArrayStorage, m_length)));
+            m_jit.store32(propertyReg, MacroAssembler::Address(storageReg, ArrayStorage::lengthOffset()));
             m_jit.sub32(TrustedImm32(1), propertyReg);
 
             lengthDoesNotNeedUpdate.link(&m_jit);
@@ -2763,7 +2774,7 @@ void SpeculativeJIT::compile(Node& node)
             // Store the value to the array.
             m_jit.storePtr(valueReg, MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::ScalePtr, OBJECT_OFFSETOF(ArrayStorage, m_vector[0])));
 
-            if (arrayMode == Array::JSArrayOutOfBounds) {
+            if (!isInBoundsAccess(arrayMode)) {
                 addSlowPathGenerator(
                     slowPathCall(
                         beyondArrayBounds, this,
@@ -2932,17 +2943,17 @@ void SpeculativeJIT::compile(Node& node)
         StorageOperand storage(this, node.child3());
         GPRReg storageGPR = storage.gpr();
 
-        m_jit.load32(MacroAssembler::Address(storageGPR, OBJECT_OFFSETOF(ArrayStorage, m_length)), storageLengthGPR);
+        m_jit.load32(MacroAssembler::Address(storageGPR, ArrayStorage::lengthOffset()), storageLengthGPR);
         
         // Refuse to handle bizarre lengths.
         speculationCheck(Uncountable, JSValueRegs(), NoNode, m_jit.branch32(MacroAssembler::Above, storageLengthGPR, TrustedImm32(0x7ffffffe)));
         
-        MacroAssembler::Jump slowPath = m_jit.branch32(MacroAssembler::AboveOrEqual, storageLengthGPR, MacroAssembler::Address(baseGPR, JSArray::vectorLengthOffset()));
+        MacroAssembler::Jump slowPath = m_jit.branch32(MacroAssembler::AboveOrEqual, storageLengthGPR, MacroAssembler::Address(storageGPR, ArrayStorage::vectorLengthOffset()));
         
         m_jit.storePtr(valueGPR, MacroAssembler::BaseIndex(storageGPR, storageLengthGPR, MacroAssembler::ScalePtr, OBJECT_OFFSETOF(ArrayStorage, m_vector[0])));
         
         m_jit.add32(TrustedImm32(1), storageLengthGPR);
-        m_jit.store32(storageLengthGPR, MacroAssembler::Address(storageGPR, OBJECT_OFFSETOF(ArrayStorage, m_length)));
+        m_jit.store32(storageLengthGPR, MacroAssembler::Address(storageGPR, ArrayStorage::lengthOffset()));
         m_jit.add32(TrustedImm32(1), MacroAssembler::Address(storageGPR, OBJECT_OFFSETOF(ArrayStorage, m_numValuesInVector)));
         m_jit.orPtr(GPRInfo::tagTypeNumberRegister, storageLengthGPR);
         
@@ -2968,18 +2979,18 @@ void SpeculativeJIT::compile(Node& node)
         GPRReg valueGPR = value.gpr();
         GPRReg storageLengthGPR = storageLength.gpr();
         
-        m_jit.load32(MacroAssembler::Address(storageGPR, OBJECT_OFFSETOF(ArrayStorage, m_length)), storageLengthGPR);
+        m_jit.load32(MacroAssembler::Address(storageGPR, ArrayStorage::lengthOffset()), storageLengthGPR);
         
         JITCompiler::JumpList setUndefinedCases;
         setUndefinedCases.append(m_jit.branchTest32(MacroAssembler::Zero, storageLengthGPR));
         
         m_jit.sub32(TrustedImm32(1), storageLengthGPR);
         
-        MacroAssembler::Jump slowCase = m_jit.branch32(MacroAssembler::AboveOrEqual, storageLengthGPR, MacroAssembler::Address(baseGPR, JSArray::vectorLengthOffset()));
+        MacroAssembler::Jump slowCase = m_jit.branch32(MacroAssembler::AboveOrEqual, storageLengthGPR, MacroAssembler::Address(storageGPR, ArrayStorage::vectorLengthOffset()));
         
         m_jit.loadPtr(MacroAssembler::BaseIndex(storageGPR, storageLengthGPR, MacroAssembler::ScalePtr, OBJECT_OFFSETOF(ArrayStorage, m_vector[0])), valueGPR);
         
-        m_jit.store32(storageLengthGPR, MacroAssembler::Address(storageGPR, OBJECT_OFFSETOF(ArrayStorage, m_length)));
+        m_jit.store32(storageLengthGPR, MacroAssembler::Address(storageGPR, ArrayStorage::lengthOffset()));
 
         setUndefinedCases.append(m_jit.branchTestPtr(MacroAssembler::Zero, valueGPR));
         
@@ -3567,14 +3578,14 @@ void SpeculativeJIT::compile(Node& node)
         compileReallocatePropertyStorage(node);
         break;
         
-    case GetPropertyStorage: {
+    case GetButterfly: {
         SpeculateCellOperand base(this, node.child1());
         GPRTemporary result(this, base);
         
         GPRReg baseGPR = base.gpr();
         GPRReg resultGPR = result.gpr();
         
-        m_jit.loadPtr(JITCompiler::Address(baseGPR, JSObject::offsetOfOutOfLineStorage()), resultGPR);
+        m_jit.loadPtr(JITCompiler::Address(baseGPR, JSObject::butterflyOffset()), resultGPR);
         
         storageResult(resultGPR, m_compileIndex);
         break;
@@ -3917,7 +3928,7 @@ void SpeculativeJIT::compile(Node& node)
 #endif
         m_jit.neg32(resolveInfoGPR);
         m_jit.signExtend32ToPtr(resolveInfoGPR, resolveInfoGPR);
-        m_jit.loadPtr(JITCompiler::Address(globalObjectGPR, JSObject::offsetOfOutOfLineStorage()), resultGPR);
+        m_jit.loadPtr(JITCompiler::Address(globalObjectGPR, JSObject::butterflyOffset()), resultGPR);
         m_jit.loadPtr(JITCompiler::BaseIndex(resultGPR, resolveInfoGPR, JITCompiler::ScalePtr, (inlineStorageCapacity - 2) * static_cast<ptrdiff_t>(sizeof(JSValue))), resultGPR);
         
         addSlowPathGenerator(
index dec2e49..f6fe127 100644 (file)
@@ -94,7 +94,7 @@ public:
                 case StructureTransitionWatchpoint:
                 case AllocatePropertyStorage:
                 case ReallocatePropertyStorage:
-                case GetPropertyStorage:
+                case GetButterfly:
                 case GetByVal:
                 case PutByVal:
                 case PutByValAlias:
index ec394ca..e8a4f87 100644 (file)
@@ -81,7 +81,7 @@ private:
     static bool isOversize(size_t);
     static CopiedBlock* oversizeBlockFor(void* ptr);
 
-    CheckedBoolean tryAllocateSlowCase(size_t, void**);
+    JS_EXPORT_PRIVATE CheckedBoolean tryAllocateSlowCase(size_t, void**);
     CheckedBoolean tryAllocateOversize(size_t, void**);
     CheckedBoolean tryReallocateOversize(void**, size_t, size_t);
     
index beb4cc0..ce70b40 100644 (file)
@@ -435,7 +435,7 @@ namespace JSC {
         void emitWriteBarrier(JSCell* owner, RegisterID value, RegisterID scratch, WriteBarrierMode, WriteBarrierUseKind);
 
         template<typename ClassType, bool destructor, typename StructureType> void emitAllocateBasicJSObject(StructureType, RegisterID result, RegisterID storagePtr);
-        void emitAllocateBasicStorage(size_t, RegisterID result);
+        void emitAllocateBasicStorage(size_t, ptrdiff_t offsetFromBase, RegisterID result);
         template<typename T> void emitAllocateJSFinalObject(T structure, RegisterID result, RegisterID storagePtr);
         void emitAllocateJSArray(unsigned valuesRegister, unsigned length, RegisterID cellResult, RegisterID storageResult, RegisterID storagePtr);
         
index 3f32597..35ac44b 100644 (file)
@@ -423,7 +423,7 @@ template <typename ClassType, bool destructor, typename StructureType> inline vo
     storePtr(structure, Address(result, JSCell::structureOffset()));
 
     // initialize the object's property storage pointer
-    storePtr(TrustedImmPtr(0), Address(result, ClassType::offsetOfOutOfLineStorage()));
+    storePtr(TrustedImmPtr(0), Address(result, JSObject::butterflyOffset()));
 }
 
 template <typename T> inline void JIT::emitAllocateJSFinalObject(T structure, RegisterID result, RegisterID scratch)
@@ -431,7 +431,7 @@ template <typename T> inline void JIT::emitAllocateJSFinalObject(T structure, Re
     emitAllocateBasicJSObject<JSFinalObject, false, T>(structure, result, scratch);
 }
 
-inline void JIT::emitAllocateBasicStorage(size_t size, RegisterID result)
+inline void JIT::emitAllocateBasicStorage(size_t size, ptrdiff_t offsetFromBase, RegisterID result)
 {
     CopiedAllocator* allocator = &m_globalData->heap.storageAllocator();
 
@@ -440,37 +440,32 @@ inline void JIT::emitAllocateBasicStorage(size_t size, RegisterID result)
     storePtr(result, &allocator->m_currentRemaining);
     negPtr(result);
     addPtr(AbsoluteAddress(&allocator->m_currentPayloadEnd), result);
-    subPtr(TrustedImm32(size), result);
+    subPtr(TrustedImm32(size - offsetFromBase), result);
 }
 
 inline void JIT::emitAllocateJSArray(unsigned valuesRegister, unsigned length, RegisterID cellResult, RegisterID storageResult, RegisterID storagePtr)
 {
     unsigned initialLength = std::max(length, 4U);
-    size_t initialStorage = JSArray::storageSize(initialLength);
+    size_t initialStorage = Butterfly::totalSize(0, 0, true, ArrayStorage::sizeFor(initialLength));
 
     // We allocate the backing store first to ensure that garbage collection 
     // doesn't happen during JSArray initialization.
-    emitAllocateBasicStorage(initialStorage, storageResult);
+    emitAllocateBasicStorage(initialStorage, sizeof(IndexingHeader), storageResult);
 
     // Allocate the cell for the array.
     emitAllocateBasicJSObject<JSArray, false>(TrustedImmPtr(m_codeBlock->globalObject()->arrayStructure()), cellResult, storagePtr);
 
     // Store all the necessary info in the ArrayStorage.
-    storePtr(storageResult, Address(storageResult, ArrayStorage::allocBaseOffset()));
     store32(Imm32(length), Address(storageResult, ArrayStorage::lengthOffset()));
     store32(Imm32(length), Address(storageResult, ArrayStorage::numValuesInVectorOffset()));
+    store32(Imm32(initialLength), Address(storageResult, ArrayStorage::vectorLengthOffset()));
+    store32(TrustedImm32(0), Address(storageResult, ArrayStorage::indexBiasOffset()));
+    storePtr(TrustedImmPtr(0), Address(storageResult, ArrayStorage::sparseMapOffset()));
 
     // Store the newly allocated ArrayStorage.
-    storePtr(storageResult, Address(cellResult, JSArray::storageOffset()));
+    storePtr(storageResult, Address(cellResult, JSObject::butterflyOffset()));
 
-    // Store the vector length and index bias.
-    store32(Imm32(initialLength), Address(cellResult, JSArray::vectorLengthOffset()));
-    store32(TrustedImm32(0), Address(cellResult, JSArray::indexBiasOffset()));
-
-    // Initialize the sparse value map.
-    storePtr(TrustedImmPtr(0), Address(cellResult, JSArray::sparseValueMapOffset()));
-
-        // Store the values we have.
+    // Store the values we have.
     for (unsigned i = 0; i < length; i++) {
 #if USE(JSVALUE64)
         loadPtr(Address(callFrameRegister, (valuesRegister + i) * sizeof(Register)), storagePtr);
@@ -482,16 +477,6 @@ inline void JIT::emitAllocateJSArray(unsigned valuesRegister, unsigned length, R
         store32(storagePtr, Address(storageResult, ArrayStorage::vectorOffset() + sizeof(WriteBarrier<Unknown>) * i + sizeof(uint32_t)));
 #endif
     }
-
-    // Zero out the remaining slots.
-    for (unsigned i = length; i < initialLength; i++) {
-#if USE(JSVALUE64)
-        storePtr(TrustedImmPtr(0), Address(storageResult, ArrayStorage::vectorOffset() + sizeof(WriteBarrier<Unknown>) * i));
-#else
-        store32(TrustedImm32(static_cast<int>(JSValue::EmptyValueTag)), Address(storageResult, ArrayStorage::vectorOffset() + sizeof(WriteBarrier<Unknown>) * i + OBJECT_OFFSETOF(JSValue, u.asBits.tag)));
-        store32(TrustedImm32(0), Address(storageResult, ArrayStorage::vectorOffset() + sizeof(WriteBarrier<Unknown>) * i + OBJECT_OFFSETOF(JSValue, u.asBits.payload)));
-#endif
-    }
 }
 
 #if ENABLE(VALUE_PROFILER)
index f859f8b..486be6b 100644 (file)
@@ -1666,7 +1666,7 @@ void JIT::emit_op_new_func_exp(Instruction* currentInstruction)
 void JIT::emit_op_new_array(Instruction* currentInstruction)
 {
     int length = currentInstruction[3].u.operand;
-    if (CopiedSpace::isOversize(JSArray::storageSize(length))) {
+    if (CopiedSpace::isOversize(Butterfly::totalSize(0, 0, true, ArrayStorage::sizeFor(length)))) {
         JITStubCall stubCall(this, cti_op_new_array);
         stubCall.addArgument(TrustedImm32(currentInstruction[2].u.operand));
         stubCall.addArgument(TrustedImm32(currentInstruction[3].u.operand));
@@ -1685,7 +1685,7 @@ void JIT::emitSlow_op_new_array(Instruction* currentInstruction, Vector<SlowCase
     // If the allocation would be oversize, we will already make the proper stub call above in 
     // emit_op_new_array.
     int length = currentInstruction[3].u.operand;
-    if (CopiedSpace::isOversize(JSArray::storageSize(length)))
+    if (CopiedSpace::isOversize(Butterfly::totalSize(0, 0, true, ArrayStorage::sizeFor(length))))
         return;
     linkSlowCase(iter); // Not enough space in CopiedSpace for storage.
     linkSlowCase(iter); // Not enough space in MarkedSpace for cell.
index ada862a..fb4b07c 100644 (file)
@@ -114,10 +114,10 @@ void JIT::emit_op_get_by_val(Instruction* currentInstruction)
 #if ENABLE(VALUE_PROFILER)
     storePtr(regT2, currentInstruction[4].u.arrayProfile->addressOfLastSeenStructure());
 #endif
-    addSlowCase(branchPtr(NotEqual, Address(regT2, Structure::classInfoOffset()), TrustedImmPtr(&JSArray::s_info)));
+    addSlowCase(branchTest8(Zero, Address(regT2, Structure::indexingTypeOffset()), TrustedImm32(HasArrayStorage)));
 
-    loadPtr(Address(regT0, JSArray::storageOffset()), regT2);
-    addSlowCase(branch32(AboveOrEqual, regT1, Address(regT0, JSArray::vectorLengthOffset())));
+    loadPtr(Address(regT0, JSObject::butterflyOffset()), regT2);
+    addSlowCase(branch32(AboveOrEqual, regT1, Address(regT2, ArrayStorage::vectorLengthOffset())));
 
     loadPtr(BaseIndex(regT2, regT1, ScalePtr, OBJECT_OFFSETOF(ArrayStorage, m_vector[0])), regT0);
     addSlowCase(branchTestPtr(Zero, regT0));
@@ -162,7 +162,7 @@ void JIT::compileGetDirectOffset(RegisterID base, RegisterID result, RegisterID
     
     if (finalObjectMode == MayBeFinal) {
         Jump isInline = branch32(LessThan, offset, TrustedImm32(inlineStorageCapacity));
-        loadPtr(Address(base, JSObject::offsetOfOutOfLineStorage()), scratch);
+        loadPtr(Address(base, JSObject::butterflyOffset()), scratch);
         neg32(offset);
         Jump done = jump();
         isInline.link(this);
@@ -174,7 +174,7 @@ void JIT::compileGetDirectOffset(RegisterID base, RegisterID result, RegisterID
         breakpoint();
         isOutOfLine.link(this);
 #endif
-        loadPtr(Address(base, JSObject::offsetOfOutOfLineStorage()), scratch);
+        loadPtr(Address(base, JSObject::butterflyOffset()), scratch);
         neg32(offset);
     }
     signExtend32ToPtr(offset, offset);
@@ -239,10 +239,10 @@ void JIT::emit_op_put_by_val(Instruction* currentInstruction)
 #if ENABLE(VALUE_PROFILER)
     storePtr(regT2, currentInstruction[4].u.arrayProfile->addressOfLastSeenStructure());
 #endif
-    addSlowCase(branchPtr(NotEqual, Address(regT2, Structure::classInfoOffset()), TrustedImmPtr(&JSArray::s_info)));
-    addSlowCase(branch32(AboveOrEqual, regT1, Address(regT0, JSArray::vectorLengthOffset())));
+    addSlowCase(branchTest8(Zero, Address(regT2, Structure::indexingTypeOffset()), TrustedImm32(HasArrayStorage)));
+    loadPtr(Address(regT0, JSObject::butterflyOffset()), regT2);
+    addSlowCase(branch32(AboveOrEqual, regT1, Address(regT2, ArrayStorage::vectorLengthOffset())));
 
-    loadPtr(Address(regT0, JSArray::storageOffset()), regT2);
     Jump empty = branchTestPtr(Zero, BaseIndex(regT2, regT1, ScalePtr, OBJECT_OFFSETOF(ArrayStorage, m_vector[0])));
 
     Label storeResult(this);
@@ -252,10 +252,10 @@ void JIT::emit_op_put_by_val(Instruction* currentInstruction)
     
     empty.link(this);
     add32(TrustedImm32(1), Address(regT2, OBJECT_OFFSETOF(ArrayStorage, m_numValuesInVector)));
-    branch32(Below, regT1, Address(regT2, OBJECT_OFFSETOF(ArrayStorage, m_length))).linkTo(storeResult, this);
+    branch32(Below, regT1, Address(regT2, ArrayStorage::lengthOffset())).linkTo(storeResult, this);
 
     add32(TrustedImm32(1), regT1);
-    store32(regT1, Address(regT2, OBJECT_OFFSETOF(ArrayStorage, m_length)));
+    store32(regT1, Address(regT2, ArrayStorage::lengthOffset()));
     sub32(TrustedImm32(1), regT1);
     jump().linkTo(storeResult, this);
 
@@ -403,7 +403,7 @@ void JIT::compileGetByIdHotPath(int baseVReg, Identifier*)
     PatchableJump structureCheck = patchableBranchPtrWithPatch(NotEqual, Address(regT0, JSCell::structureOffset()), structureToCompare, TrustedImmPtr(reinterpret_cast<void*>(patchGetByIdDefaultStructure)));
     addSlowCase(structureCheck);
 
-    ConvertibleLoadLabel propertyStorageLoad = convertibleLoadPtr(Address(regT0, JSObject::offsetOfOutOfLineStorage()), regT0);
+    ConvertibleLoadLabel propertyStorageLoad = convertibleLoadPtr(Address(regT0, JSObject::butterflyOffset()), regT0);
     DataLabelCompact displacementLabel = loadPtrWithCompactAddressOffsetPatch(Address(regT0, patchGetByIdDefaultOffset), regT0);
 
     Label putResult(this);
@@ -470,7 +470,7 @@ void JIT::emit_op_put_by_id(Instruction* currentInstruction)
     DataLabelPtr structureToCompare;
     addSlowCase(branchPtrWithPatch(NotEqual, Address(regT0, JSCell::structureOffset()), structureToCompare, TrustedImmPtr(reinterpret_cast<void*>(patchGetByIdDefaultStructure))));
 
-    ConvertibleLoadLabel propertyStorageLoad = convertibleLoadPtr(Address(regT0, JSObject::offsetOfOutOfLineStorage()), regT2);
+    ConvertibleLoadLabel propertyStorageLoad = convertibleLoadPtr(Address(regT0, JSObject::butterflyOffset()), regT2);
     DataLabel32 displacementLabel = storePtrWithAddressOffsetPatch(regT1, Address(regT2, patchPutByIdDefaultOffset));
 
     END_UNINTERRUPTED_SEQUENCE(sequencePutById);
@@ -509,8 +509,8 @@ void JIT::compilePutDirectOffset(RegisterID base, RegisterID value, PropertyOffs
         return;
     }
     
-    loadPtr(Address(base, JSObject::offsetOfOutOfLineStorage()), base);
-    storePtr(value, Address(base, sizeof(JSValue) * offsetInOutOfLineStorage(cachedOffset)));
+    loadPtr(Address(base, JSObject::butterflyOffset()), base);
+    storePtr(value, Address(base, sizeof(JSValue) * offsetInButterfly(cachedOffset)));
 }
 
 // Compile a load from an object's property storage.  May overwrite base.
@@ -521,8 +521,8 @@ void JIT::compileGetDirectOffset(RegisterID base, RegisterID result, PropertyOff
         return;
     }
     
-    loadPtr(Address(base, JSObject::offsetOfOutOfLineStorage()), result);
-    loadPtr(Address(result, sizeof(JSValue) * offsetInOutOfLineStorage(cachedOffset)), result);
+    loadPtr(Address(base, JSObject::butterflyOffset()), result);
+    loadPtr(Address(result, sizeof(JSValue) * offsetInButterfly(cachedOffset)), result);
 }
 
 void JIT::compileGetDirectOffset(JSObject* base, RegisterID result, PropertyOffset cachedOffset)
@@ -532,8 +532,8 @@ void JIT::compileGetDirectOffset(JSObject* base, RegisterID result, PropertyOffs
         return;
     }
     
-    loadPtr(base->addressOfOutOfLineStorage(), result);
-    loadPtr(Address(result, offsetInOutOfLineStorage(cachedOffset) * sizeof(WriteBarrier<Unknown>)), result);
+    loadPtr(base->butterflyAddress(), result);
+    loadPtr(Address(result, offsetInButterfly(cachedOffset) * sizeof(WriteBarrier<Unknown>)), result);
 }
 
 void JIT::privateCompilePutByIdTransition(StructureStubInfo* stubInfo, Structure* oldStructure, Structure* newStructure, PropertyOffset cachedOffset, StructureChain* chain, ReturnAddressPtr returnAddress, bool direct)
@@ -660,11 +660,11 @@ void JIT::privateCompilePatchGetArrayLength(ReturnAddressPtr returnAddress)
 #if ENABLE(VALUE_PROFILER)
     storePtr(regT3, m_codeBlock->getOrAddArrayProfile(stubInfo->bytecodeIndex)->addressOfLastSeenStructure());
 #endif
-    Jump failureCases1 = branchPtr(NotEqual, Address(regT3, Structure::classInfoOffset()), TrustedImmPtr(&JSArray::s_info));
+    Jump failureCases1 = branch8(NotEqual, Address(regT3, Structure::indexingTypeOffset()), TrustedImm32(ArrayWithArrayStorage));
 
     // Checks out okay! - get the length from the storage
-    loadPtr(Address(regT0, JSArray::storageOffset()), regT3);
-    load32(Address(regT3, OBJECT_OFFSETOF(ArrayStorage, m_length)), regT2);
+    loadPtr(Address(regT0, JSObject::butterflyOffset()), regT3);
+    load32(Address(regT3, ArrayStorage::lengthOffset()), regT2);
     Jump failureCases2 = branch32(LessThan, regT2, TrustedImm32(0));
 
     emitFastArithIntToImmNoCheck(regT2, regT0);
index f3c79a9..8332b4b 100644 (file)
@@ -213,10 +213,10 @@ void JIT::emit_op_get_by_val(Instruction* currentInstruction)
 #if ENABLE(VALUE_PROFILER)
     storePtr(regT1, currentInstruction[4].u.arrayProfile->addressOfLastSeenStructure());
 #endif
-    addSlowCase(branchPtr(NotEqual, Address(regT1, Structure::classInfoOffset()), TrustedImmPtr(&JSArray::s_info)));
+    addSlowCase(branchTest8(Zero, Address(regT1, Structure::indexingTypeOffset()), TrustedImm32(HasArrayStorage)));
     
-    loadPtr(Address(regT0, JSArray::storageOffset()), regT3);
-    addSlowCase(branch32(AboveOrEqual, regT2, Address(regT0, JSArray::vectorLengthOffset())));
+    loadPtr(Address(regT0, JSObject::butterflyOffset()), regT3);
+    addSlowCase(branch32(AboveOrEqual, regT2, Address(regT3, ArrayStorage::vectorLengthOffset())));
     
     load32(BaseIndex(regT3, regT2, TimesEight, OBJECT_OFFSETOF(ArrayStorage, m_vector[0]) + OBJECT_OFFSETOF(JSValue, u.asBits.tag)), regT1); // tag
     load32(BaseIndex(regT3, regT2, TimesEight, OBJECT_OFFSETOF(ArrayStorage, m_vector[0]) + OBJECT_OFFSETOF(JSValue, u.asBits.payload)), regT0); // payload
@@ -272,11 +272,11 @@ void JIT::emit_op_put_by_val(Instruction* currentInstruction)
 #if ENABLE(VALUE_PROFILER)
     storePtr(regT1, currentInstruction[4].u.arrayProfile->addressOfLastSeenStructure());
 #endif
-    addSlowCase(branchPtr(NotEqual, Address(regT1, Structure::classInfoOffset()), TrustedImmPtr(&JSArray::s_info)));
-    addSlowCase(branch32(AboveOrEqual, regT2, Address(regT0, JSArray::vectorLengthOffset())));
+    addSlowCase(branchTest8(Zero, Address(regT1, Structure::indexingTypeOffset()), TrustedImm32(HasArrayStorage)));
+    loadPtr(Address(regT0, JSObject::butterflyOffset()), regT3);
+    addSlowCase(branch32(AboveOrEqual, regT2, Address(regT3, ArrayStorage::vectorLengthOffset())));
 
     emitWriteBarrier(regT0, regT1, regT1, regT3, UnconditionalWriteBarrier, WriteBarrierForPropertyAccess);
-    loadPtr(Address(regT0, JSArray::storageOffset()), regT3);
     
     Jump empty = branch32(Equal, BaseIndex(regT3, regT2, TimesEight, OBJECT_OFFSETOF(ArrayStorage, m_vector[0]) + OBJECT_OFFSETOF(JSValue, u.asBits.tag)), TrustedImm32(JSValue::EmptyValueTag));
     
@@ -288,10 +288,10 @@ void JIT::emit_op_put_by_val(Instruction* currentInstruction)
     
     empty.link(this);
     add32(TrustedImm32(1), Address(regT3, OBJECT_OFFSETOF(ArrayStorage, m_numValuesInVector)));
-    branch32(Below, regT2, Address(regT3, OBJECT_OFFSETOF(ArrayStorage, m_length))).linkTo(storeResult, this);
+    branch32(Below, regT2, Address(regT3, ArrayStorage::lengthOffset())).linkTo(storeResult, this);
     
     add32(TrustedImm32(1), regT2, regT0);
-    store32(regT0, Address(regT3, OBJECT_OFFSETOF(ArrayStorage, m_length)));
+    store32(regT0, Address(regT3, ArrayStorage::lengthOffset()));
     jump().linkTo(storeResult, this);
     
     end.link(this);
@@ -343,7 +343,7 @@ void JIT::compileGetByIdHotPath()
     PatchableJump structureCheck = patchableBranchPtrWithPatch(NotEqual, Address(regT0, JSCell::structureOffset()), structureToCompare, TrustedImmPtr(reinterpret_cast<void*>(patchGetByIdDefaultStructure)));
     addSlowCase(structureCheck);
     
-    ConvertibleLoadLabel propertyStorageLoad = convertibleLoadPtr(Address(regT0, JSObject::offsetOfOutOfLineStorage()), regT2);
+    ConvertibleLoadLabel propertyStorageLoad = convertibleLoadPtr(Address(regT0, JSObject::butterflyOffset()), regT2);
     DataLabelCompact displacementLabel1 = loadPtrWithCompactAddressOffsetPatch(Address(regT2, patchGetByIdDefaultOffset), regT0); // payload
     DataLabelCompact displacementLabel2 = loadPtrWithCompactAddressOffsetPatch(Address(regT2, patchGetByIdDefaultOffset), regT1); // tag
     
@@ -409,7 +409,7 @@ void JIT::emit_op_put_by_id(Instruction* currentInstruction)
     DataLabelPtr structureToCompare;
     addSlowCase(branchPtrWithPatch(NotEqual, Address(regT0, JSCell::structureOffset()), structureToCompare, TrustedImmPtr(reinterpret_cast<void*>(patchGetByIdDefaultStructure))));
     
-    ConvertibleLoadLabel propertyStorageLoad = convertibleLoadPtr(Address(regT0, JSObject::offsetOfOutOfLineStorage()), regT1);
+    ConvertibleLoadLabel propertyStorageLoad = convertibleLoadPtr(Address(regT0, JSObject::butterflyOffset()), regT1);
     DataLabel32 displacementLabel1 = storePtrWithAddressOffsetPatch(regT2, Address(regT1, patchPutByIdDefaultOffset)); // payload
     DataLabel32 displacementLabel2 = storePtrWithAddressOffsetPatch(regT3, Address(regT1, patchPutByIdDefaultOffset)); // tag
     
@@ -443,7 +443,7 @@ void JIT::emitSlow_op_put_by_id(Instruction* currentInstruction, Vector<SlowCase
 void JIT::compilePutDirectOffset(RegisterID base, RegisterID valueTag, RegisterID valuePayload, PropertyOffset cachedOffset)
 {
     if (isOutOfLineOffset(cachedOffset))
-        loadPtr(Address(base, JSObject::offsetOfOutOfLineStorage()), base);
+        loadPtr(Address(base, JSObject::butterflyOffset()), base);
     emitStore(indexRelativeToBase(cachedOffset), valueTag, valuePayload, base);
 }
 
@@ -456,7 +456,7 @@ void JIT::compileGetDirectOffset(RegisterID base, RegisterID resultTag, Register
     }
     
     RegisterID temp = resultPayload;
-    loadPtr(Address(base, JSObject::offsetOfOutOfLineStorage()), temp);
+    loadPtr(Address(base, JSObject::butterflyOffset()), temp);
     emitLoad(indexRelativeToBase(cachedOffset), resultTag, resultPayload, temp);
 }
 
@@ -469,9 +469,9 @@ void JIT::compileGetDirectOffset(JSObject* base, RegisterID resultTag, RegisterI
         return;
     }
     
-    loadPtr(base->addressOfOutOfLineStorage(), resultTag);
-    load32(Address(resultTag, offsetInOutOfLineStorage(cachedOffset) * sizeof(WriteBarrier<Unknown>) + OBJECT_OFFSETOF(JSValue, u.asBits.payload)), resultPayload);
-    load32(Address(resultTag, offsetInOutOfLineStorage(cachedOffset) * sizeof(WriteBarrier<Unknown>) + OBJECT_OFFSETOF(JSValue, u.asBits.tag)), resultTag);
+    loadPtr(base->butterflyAddress(), resultTag);
+    load32(Address(resultTag, offsetInButterfly(cachedOffset) * sizeof(WriteBarrier<Unknown>) + OBJECT_OFFSETOF(JSValue, u.asBits.payload)), resultPayload);
+    load32(Address(resultTag, offsetInButterfly(cachedOffset) * sizeof(WriteBarrier<Unknown>) + OBJECT_OFFSETOF(JSValue, u.asBits.tag)), resultTag);
 }
 
 void JIT::privateCompilePutByIdTransition(StructureStubInfo* stubInfo, Structure* oldStructure, Structure* newStructure, PropertyOffset cachedOffset, StructureChain* chain, ReturnAddressPtr returnAddress, bool direct)
@@ -620,11 +620,11 @@ void JIT::privateCompilePatchGetArrayLength(ReturnAddressPtr returnAddress)
 #if ENABLE(VALUE_PROFILER)
     storePtr(regT2, m_codeBlock->getOrAddArrayProfile(stubInfo->bytecodeIndex)->addressOfLastSeenStructure());
 #endif
-    Jump failureCases1 = branchPtr(NotEqual, Address(regT2, Structure::classInfoOffset()), TrustedImmPtr(&JSArray::s_info));
+    Jump failureCases1 = branch8(NotEqual, Address(regT2, Structure::indexingTypeOffset()), TrustedImm32(ArrayWithArrayStorage));
     
     // Checks out okay! - get the length from the storage
-    loadPtr(Address(regT0, JSArray::storageOffset()), regT2);
-    load32(Address(regT2, OBJECT_OFFSETOF(ArrayStorage, m_length)), regT2);
+    loadPtr(Address(regT0, JSArray::butterflyOffset()), regT2);
+    load32(Address(regT2, ArrayStorage::lengthOffset()), regT2);
     
     Jump failureCases2 = branch32(Above, regT2, TrustedImm32(INT_MAX));
     move(regT2, regT0);
@@ -1029,7 +1029,7 @@ void JIT::compileGetDirectOffset(RegisterID base, RegisterID resultTag, Register
     
     if (finalObjectMode == MayBeFinal) {
         Jump isInline = branch32(LessThan, offset, TrustedImm32(inlineStorageCapacity));
-        loadPtr(Address(base, JSObject::offsetOfOutOfLineStorage()), base);
+        loadPtr(Address(base, JSObject::butterflyOffset()), base);
         neg32(offset);
         Jump done = jump();
         isInline.link(this);
@@ -1041,7 +1041,7 @@ void JIT::compileGetDirectOffset(RegisterID base, RegisterID resultTag, Register
         breakpoint();
         isOutOfLine.link(this);
 #endif
-        loadPtr(Address(base, JSObject::offsetOfOutOfLineStorage()), base);
+        loadPtr(Address(base, JSObject::butterflyOffset()), base);
         neg32(offset);
     }
     load32(BaseIndex(base, offset, TimesEight, OBJECT_OFFSETOF(JSValue, u.asBits.payload) + (inlineStorageCapacity - 2) * sizeof(EncodedJSValue)), resultPayload);
index 5fad9c8..40d653b 100644 (file)
@@ -1504,8 +1504,8 @@ DEFINE_STUB_FUNCTION(JSObject*, op_put_by_id_transition_realloc)
     ASSERT(baseValue.isObject());
     JSObject* base = asObject(baseValue);
     JSGlobalData& globalData = *stackFrame.globalData;
-    PropertyStorage newStorage = base->growOutOfLineStorage(globalData, oldSize, newSize);
-    base->setOutOfLineStorage(globalData, newStorage, newStructure);
+    Butterfly* butterfly = base->growOutOfLineStorage(globalData, oldSize, newSize);
+    base->setButterfly(globalData, butterfly, newStructure);
 
     return base;
 }
@@ -2415,7 +2415,7 @@ DEFINE_STUB_FUNCTION(EncodedJSValue, op_get_by_val)
 
     JSValue baseValue = stackFrame.args[0].jsValue();
     JSValue subscript = stackFrame.args[1].jsValue();
-
+    
     if (LIKELY(baseValue.isCell() && subscript.isString())) {
         if (JSValue result = baseValue.asCell()->fastGetOwnProperty(callFrame, asString(subscript)->value(callFrame))) {
             CHECK_FOR_EXCEPTION();
@@ -2508,12 +2508,12 @@ DEFINE_STUB_FUNCTION(void, op_put_by_val)
 
     if (LIKELY(subscript.isUInt32())) {
         uint32_t i = subscript.asUInt32();
-        if (isJSArray(baseValue)) {
-            JSArray* jsArray = asArray(baseValue);
-            if (jsArray->canSetIndex(i))
-                jsArray->setIndex(*globalData, i, value);
+        if (baseValue.isObject()) {
+            JSObject* object = asObject(baseValue);
+            if (object->canSetIndexQuickly(i))
+                object->setIndexQuickly(*globalData, i, value);
             else
-                JSArray::putByIndex(jsArray, callFrame, i, value, callFrame->codeBlock()->isStrictMode());
+                object->methodTable()->putByIndex(object, callFrame, i, value, callFrame->codeBlock()->isStrictMode());
         } else
             baseValue.putByIndex(callFrame, i, value, callFrame->codeBlock()->isStrictMode());
     } else if (isName(subscript)) {
@@ -3368,7 +3368,7 @@ DEFINE_STUB_FUNCTION(void, op_put_getter_setter)
         accessor->setGetter(callFrame->globalData(), asObject(getter));
     if (!setter.isUndefined())
         accessor->setSetter(callFrame->globalData(), asObject(setter));
-    baseObj->putDirectAccessor(callFrame->globalData(), stackFrame.args[1].identifier(), accessor, Accessor);
+    baseObj->putDirectAccessor(callFrame, stackFrame.args[1].identifier(), accessor, Accessor);
 }
 
 DEFINE_STUB_FUNCTION(void, op_throw_reference_error)
index b044d57..e5e891e 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *  Copyright (C) 1999-2000 Harri Porten (porten@kde.org)
- *  Copyright (C) 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved.
+ *  Copyright (C) 2004, 2005, 2006, 2007, 2008, 2012 Apple Inc. All rights reserved.
  *  Copyright (C) 2006 Bjoern Graf (bjoern.graf@gmail.com)
  *
  *  This library is free software; you can redistribute it and/or
 
 #include "config.h"
 
+#include "ButterflyInlineMethods.h"
 #include "BytecodeGenerator.h"
 #include "Completion.h"
+#include "CopiedSpaceInlineMethods.h"
 #include "ExceptionHelpers.h"
 #include "InitializeThreading.h"
 #include "Interpreter.h"
index 0bae5a1..b0441e8 100644 (file)
@@ -877,7 +877,7 @@ LLINT_SLOW_PATH_DECL(slow_path_get_by_id)
                 pc[5].u.operand = offsetInInlineStorage(slot.cachedOffset()) * sizeof(JSValue) + JSObject::offsetOfInlineStorage();
             } else {
                 pc[0].u.opcode = LLInt::getOpcode(llint_op_get_by_id_out_of_line);
-                pc[5].u.operand = offsetInOutOfLineStorage(slot.cachedOffset()) * sizeof(JSValue);
+                pc[5].u.operand = offsetInButterfly(slot.cachedOffset()) * sizeof(JSValue);
             }
         }
     }
@@ -950,7 +950,7 @@ LLINT_SLOW_PATH_DECL(slow_path_put_by_id)
                     if (isInlineOffset(slot.cachedOffset()))
                         pc[5].u.operand = offsetInInlineStorage(slot.cachedOffset()) * sizeof(JSValue) + JSObject::offsetOfInlineStorage();
                     else
-                        pc[5].u.operand = offsetInOutOfLineStorage(slot.cachedOffset()) * sizeof(JSValue);
+                        pc[5].u.operand = offsetInButterfly(slot.cachedOffset()) * sizeof(JSValue);
                     pc[6].u.structure.set(
                         globalData, codeBlock->ownerExecutable(), structure);
                     StructureChain* chain = structure->prototypeChain(exec);
@@ -978,7 +978,7 @@ LLINT_SLOW_PATH_DECL(slow_path_put_by_id)
                     pc[5].u.operand = offsetInInlineStorage(slot.cachedOffset()) * sizeof(JSValue) + JSObject::offsetOfInlineStorage();
                 } else {
                     pc[0].u.opcode = LLInt::getOpcode(llint_op_put_by_id_out_of_line);
-                    pc[5].u.operand = offsetInOutOfLineStorage(slot.cachedOffset()) * sizeof(JSValue);
+                    pc[5].u.operand = offsetInButterfly(slot.cachedOffset()) * sizeof(JSValue);
                 }
             }
         }
@@ -1057,12 +1057,12 @@ LLINT_SLOW_PATH_DECL(slow_path_put_by_val)
     
     if (LIKELY(subscript.isUInt32())) {
         uint32_t i = subscript.asUInt32();
-        if (isJSArray(baseValue)) {
-            JSArray* jsArray = asArray(baseValue);
-            if (jsArray->canSetIndex(i))
-                jsArray->setIndex(globalData, i, value);
+        if (baseValue.isObject()) {
+            JSObject* object = asObject(baseValue);
+            if (object->canSetIndexQuickly(i))
+                object->setIndexQuickly(globalData, i, value);
             else
-                JSArray::putByIndex(jsArray, exec, i, value, exec->codeBlock()->isStrictMode());
+                object->methodTable()->putByIndex(object, exec, i, value, exec->codeBlock()->isStrictMode());
             LLINT_END();
         }
         baseValue.putByIndex(exec, i, value, exec->codeBlock()->isStrictMode());
@@ -1139,7 +1139,7 @@ LLINT_SLOW_PATH_DECL(slow_path_put_getter_setter)
     if (!setter.isUndefined())
         accessor->setSetter(globalData, asObject(setter));
     baseObj->putDirectAccessor(
-        globalData,
+        exec,
         exec->codeBlock()->identifier(pc[2].u.operand),
         accessor, Accessor);
     LLINT_END();
index cbc1bfb..6f5460a 100644 (file)
@@ -61,6 +61,11 @@ else
     const PayloadOffset = 0
 end
 
+# Constant for reasoning about butterflies.
+const IsArray = 1
+const HasArrayStorage = 8
+const AllArrayTypes = 15
+
 # Type constants.
 const StringType = 5
 const ObjectType = 13
@@ -339,7 +344,7 @@ macro allocateBasicJSObject(sizeClassIndex, structure, result, scratch1, scratch
     
         # Initialize the object.
         storep structure, JSCell::m_structure[result]
-        storep 0, JSObject::m_outOfLineStorage[result]
+        storep 0, JSObject::m_butterfly[result]
     end
 end
 
@@ -514,7 +519,7 @@ macro withInlineStorage(object, propertyStorage, continuation)
 end
 
 macro withOutOfLineStorage(object, propertyStorage, continuation)
-    loadp JSObject::m_outOfLineStorage[object], propertyStorage
+    loadp JSObject::m_butterfly[object], propertyStorage
     # Indicate that the propertyStorage register now points to the
     # property storage, and that the object register may be reused
     # if the object pointer is not needed anymore.
index a8dab1f..02d272e 100644 (file)
@@ -947,21 +947,21 @@ _llint_op_is_string:
 macro loadPropertyAtVariableOffsetKnownNotFinal(propertyOffset, objectAndStorage, tag, payload)
     assert(macro (ok) bigteq propertyOffset, InlineStorageCapacity, ok end)
     negi propertyOffset
-    loadp JSObject::m_outOfLineStorage[objectAndStorage], objectAndStorage
-    loadi TagOffset + (InlineStorageCapacity - 2) * 8[objectAndStorage, propertyOffset, 8], tag
-    loadi PayloadOffset + (InlineStorageCapacity - 2) * 8[objectAndStorage, propertyOffset, 8], payload
+    loadp JSObject::m_butterfly[objectAndStorage], objectAndStorage
+    loadi TagOffset + (InlineStorageCapacity - 1) * 8 - sizeof IndexingHeader[objectAndStorage, propertyOffset, 8], tag
+    loadi PayloadOffset + (InlineStorageCapacity - 1) * 8 - sizeof IndexingHeader[objectAndStorage, propertyOffset, 8], payload
 end
 
 macro loadPropertyAtVariableOffset(propertyOffset, objectAndStorage, tag, payload)
     bilt propertyOffset, InlineStorageCapacity, .isInline
-    loadp JSObject::m_outOfLineStorage[objectAndStorage], objectAndStorage
+    loadp JSObject::m_butterfly[objectAndStorage], objectAndStorage
     negi propertyOffset
     jmp .ready
 .isInline:
-    addp JSFinalObject::m_inlineStorage - (InlineStorageCapacity - 2) * 8, objectAndStorage
+    addp JSFinalObject::m_inlineStorage - (InlineStorageCapacity - 1) * 8 + sizeof IndexingHeader, objectAndStorage
 .ready:
-    loadi TagOffset + (InlineStorageCapacity - 2) * 8[objectAndStorage, propertyOffset, 8], tag
-    loadi PayloadOffset + (InlineStorageCapacity - 2) * 8[objectAndStorage, propertyOffset, 8], payload
+    loadi TagOffset + (InlineStorageCapacity - 1) * 8 - sizeof IndexingHeader[objectAndStorage, propertyOffset, 8], tag
+    loadi PayloadOffset + (InlineStorageCapacity - 1) * 8 - sizeof IndexingHeader[objectAndStorage, propertyOffset, 8], payload
 end
 
 macro resolveGlobal(size, slow)
@@ -1177,14 +1177,11 @@ _llint_op_get_array_length:
     if VALUE_PROFILER
         storep t2, ArrayProfile::m_lastSeenStructure[t1]
     end
-    loadp CodeBlock[cfr], t1
-    loadp CodeBlock::m_globalData[t1], t1
-    loadp JSGlobalData::jsArrayClassInfo[t1], t1
-    bpneq Structure::m_classInfo[t2], t1, .opGetArrayLengthSlow
+    bbneq Structure::m_indexingType[t2], IsArray | HasArrayStorage, .opGetArrayLengthSlow
     loadi 4[PC], t1
     loadp 32[PC], t2
-    loadp JSArray::m_storage[t3], t0
-    loadi ArrayStorage::m_length[t0], t0
+    loadp JSObject::m_butterfly[t3], t0
+    loadi -sizeof IndexingHeader + IndexingHeader::m_publicLength[t0], t0
     bilt t0, 0, .opGetArrayLengthSlow
     valueProfile(Int32Tag, t0, t2)
     storep t0, PayloadOffset[cfr, t1, 8]
@@ -1315,12 +1312,9 @@ _llint_op_get_by_val:
     if VALUE_PROFILER
         storep t3, ArrayProfile::m_lastSeenStructure[t2]
     end
-    loadp CodeBlock[cfr], t2
-    loadp CodeBlock::m_globalData[t2], t2
-    loadp JSGlobalData::jsArrayClassInfo[t2], t2
-    bpneq Structure::m_classInfo[t3], t2, .opGetByValSlow
-    loadp JSArray::m_storage[t0], t3
-    biaeq t1, JSArray::m_vectorLength[t0], .opGetByValSlow
+    btpz Structure::m_indexingType[t3], HasArrayStorage, .opGetByValSlow
+    loadp JSObject::m_butterfly[t0], t3
+    biaeq t1, -sizeof IndexingHeader + IndexingHeader::m_vectorLength[t0], .opGetByValSlow
     loadi 4[PC], t0
     loadi ArrayStorage::m_vector + TagOffset[t3, t1, 8], t2
     loadi ArrayStorage::m_vector + PayloadOffset[t3, t1, 8], t1
@@ -1401,12 +1395,9 @@ _llint_op_put_by_val:
     if VALUE_PROFILER
         storep t3, ArrayProfile::m_lastSeenStructure[t0]
     end
-    loadp CodeBlock[cfr], t0
-    loadp CodeBlock::m_globalData[t0], t0
-    loadp JSGlobalData::jsArrayClassInfo[t0], t0
-    bpneq Structure::m_classInfo[t3], t0, .opPutByValSlow
-    biaeq t2, JSArray::m_vectorLength[t1], .opPutByValSlow
-    loadp JSArray::m_storage[t1], t0
+    btpz Structure::m_indexingType[t3], HasArrayStorage, .opPutByValSlow
+    loadp JSObject::m_butterfly[t1], t0
+    biaeq t2, -sizeof IndexingHeader + IndexingHeader::m_vectorLength[t0], .opPutByValSlow
     bieq ArrayStorage::m_vector + TagOffset[t0, t2, 8], EmptyValueTag, .opPutByValEmpty
 .opPutByValStoreResult:
     loadi 12[PC], t3
@@ -1418,9 +1409,9 @@ _llint_op_put_by_val:
 
 .opPutByValEmpty:
     addi 1, ArrayStorage::m_numValuesInVector[t0]
-    bib t2, ArrayStorage::m_length[t0], .opPutByValStoreResult
+    bib t2, -sizeof IndexingHeader + IndexingHeader::m_publicLength[t0], .opPutByValStoreResult
     addi 1, t2, t1
-    storei t1, ArrayStorage::m_length[t0]
+    storei t1, -sizeof IndexingHeader + IndexingHeader::m_publicLength[t0]
     jmp .opPutByValStoreResult
 
 .opPutByValSlow:
index c8231cd..30bac71 100644 (file)
@@ -806,20 +806,20 @@ _llint_op_is_string:
 macro loadPropertyAtVariableOffsetKnownNotFinal(propertyOffsetAsPointer, objectAndStorage, value)
     assert(macro (ok) bigteq propertyOffsetAsPointer, InlineStorageCapacity, ok end)
     negp propertyOffsetAsPointer
-    loadp JSObject::m_outOfLineStorage[objectAndStorage], objectAndStorage
-    loadp (InlineStorageCapacity - 2) * 8[objectAndStorage, propertyOffsetAsPointer, 8], value
+    loadp JSObject::m_butterfly[objectAndStorage], objectAndStorage
+    loadp (InlineStorageCapacity - 1) * 8 - sizeof IndexingHeader[objectAndStorage, propertyOffsetAsPointer, 8], value
 end
 
 macro loadPropertyAtVariableOffset(propertyOffsetAsInt, objectAndStorage, value)
     bilt propertyOffsetAsInt, InlineStorageCapacity, .isInline
-    loadp JSObject::m_outOfLineStorage[objectAndStorage], objectAndStorage
+    loadp JSObject::m_butterfly[objectAndStorage], objectAndStorage
     negi propertyOffsetAsInt
     sxi2p propertyOffsetAsInt, propertyOffsetAsInt
     jmp .ready
 .isInline:
-    addp JSFinalObject::m_inlineStorage - (InlineStorageCapacity - 2) * 8, objectAndStorage
+    addp JSFinalObject::m_inlineStorage - (InlineStorageCapacity - 1) * 8 + sizeof IndexingHeader, objectAndStorage
 .ready:
-    loadp (InlineStorageCapacity - 2) * 8[objectAndStorage, propertyOffsetAsInt, 8], value
+    loadp (InlineStorageCapacity - 1) * 8 - sizeof IndexingHeader[objectAndStorage, propertyOffsetAsInt, 8], value
 end
 
 macro resolveGlobal(size, slow)
@@ -1024,14 +1024,11 @@ _llint_op_get_array_length:
     if VALUE_PROFILER
         storep t2, ArrayProfile::m_lastSeenStructure[t1]
     end
-    loadp CodeBlock[cfr], t1
-    loadp CodeBlock::m_globalData[t1], t1
-    loadp JSGlobalData::jsArrayClassInfo[t1], t1
-    bpneq Structure::m_classInfo[t2], t1, .opGetArrayLengthSlow
+    bbneq Structure::m_indexingType[t2], IsArray | HasArrayStorage, .opGetArrayLengthSlow
     loadis 8[PB, PC, 8], t1
     loadp 64[PB, PC, 8], t2
-    loadp JSArray::m_storage[t3], t0
-    loadi ArrayStorage::m_length[t0], t0
+    loadp JSObject::m_butterfly[t3], t0
+    loadi -sizeof IndexingHeader + IndexingHeader::m_publicLength[t0], t0
     bilt t0, 0, .opGetArrayLengthSlow
     orp tagTypeNumber, t0
     valueProfile(t0, t2)
@@ -1160,12 +1157,9 @@ _llint_op_get_by_val:
     if VALUE_PROFILER
         storep t3, ArrayProfile::m_lastSeenStructure[t2]
     end
-    loadp CodeBlock[cfr], t2
-    loadp CodeBlock::m_globalData[t2], t2
-    loadp JSGlobalData::jsArrayClassInfo[t2], t2
-    bpneq Structure::m_classInfo[t3], t2, .opGetByValSlow
-    loadp JSArray::m_storage[t0], t3
-    biaeq t1, JSArray::m_vectorLength[t0], .opGetByValSlow
+    btbz Structure::m_indexingType[t3], HasArrayStorage, .opGetByValSlow
+    loadp JSObject::m_butterfly[t0], t3
+    biaeq t1, -sizeof IndexingHeader + IndexingHeader::m_vectorLength[t3], .opGetByValSlow
     loadis 8[PB, PC, 8], t0
     loadp ArrayStorage::m_vector[t3, t1, 8], t2
     btpz t2, .opGetByValSlow
@@ -1245,12 +1239,9 @@ _llint_op_put_by_val:
     if VALUE_PROFILER
         storep t3, ArrayProfile::m_lastSeenStructure[t0]
     end
-    loadp CodeBlock[cfr], t0
-    loadp CodeBlock::m_globalData[t0], t0
-    loadp JSGlobalData::jsArrayClassInfo[t0], t0
-    bpneq Structure::m_classInfo[t3], t0, .opPutByValSlow
-    biaeq t2, JSArray::m_vectorLength[t1], .opPutByValSlow
-    loadp JSArray::m_storage[t1], t0
+    btbz Structure::m_indexingType[t3], HasArrayStorage, .opPutByValSlow
+    loadp JSObject::m_butterfly[t1], t0
+    biaeq t2, -sizeof IndexingHeader + IndexingHeader::m_vectorLength[t0], .opPutByValSlow
     btpz ArrayStorage::m_vector[t0, t2, 8], .opPutByValEmpty
 .opPutByValStoreResult:
     loadis 24[PB, PC, 8], t3
@@ -1261,9 +1252,9 @@ _llint_op_put_by_val:
 
 .opPutByValEmpty:
     addi 1, ArrayStorage::m_numValuesInVector[t0]
-    bib t2, ArrayStorage::m_length[t0], .opPutByValStoreResult
+    bib t2, -sizeof IndexingHeader + IndexingHeader::m_publicLength[t0], .opPutByValStoreResult
     addi 1, t2, t1
-    storei t1, ArrayStorage::m_length[t0]
+    storei t1, -sizeof IndexingHeader + IndexingHeader::m_publicLength[t0]
     jmp .opPutByValStoreResult
 
 .opPutByValSlow:
index fe79f74..47795ed 100644 (file)
@@ -255,7 +255,7 @@ bool Arguments::deletePropertyByIndex(JSCell* cell, ExecState* exec, unsigned i)
         }
     }
 
-    return JSObject::deleteProperty(thisObject, exec, Identifier(exec, String::number(i)));
+    return JSObject::deletePropertyByIndex(thisObject, exec, i);
 }
 
 bool Arguments::deleteProperty(JSCell* cell, ExecState* exec, PropertyName propertyName) 
@@ -308,7 +308,7 @@ bool Arguments::defineOwnProperty(JSObject* object, ExecState* exec, PropertyNam
         // If the property is not yet present on the object, and is not yet marked as deleted, then add it now.
         PropertySlot slot;
         if ((!thisObject->d->deletedArguments || !thisObject->d->deletedArguments[i]) && !JSObject::getOwnPropertySlot(thisObject, exec, propertyName, slot))
-            object->putDirect(exec->globalData(), propertyName, thisObject->argument(i).get(), 0);
+            object->putDirectMayBeIndex(exec, propertyName, thisObject->argument(i).get());
         if (!Base::defineOwnProperty(object, exec, propertyName, descriptor, shouldThrow))
             return false;
 
index c9a6dc6..eda35e1 100644 (file)
@@ -25,6 +25,8 @@
 #include "ArrayConstructor.h"
 
 #include "ArrayPrototype.h"
+#include "ButterflyInlineMethods.h"
+#include "CopiedSpaceInlineMethods.h"
 #include "Error.h"
 #include "ExceptionHelpers.h"
 #include "JSArray.h"
diff --git a/Source/JavaScriptCore/runtime/ArrayConventions.h b/Source/JavaScriptCore/runtime/ArrayConventions.h
new file mode 100644 (file)
index 0000000..af98e15
--- /dev/null
@@ -0,0 +1,103 @@
+/*
+ *  Copyright (C) 1999-2000 Harri Porten (porten@kde.org)
+ *  Copyright (C) 2003, 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 Lesser General Public
+ *  License as published by the Free Software Foundation; either
+ *  version 2 of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifndef ArrayConventions_h
+#define ArrayConventions_h
+
+#include "IndexingHeader.h"
+#include "WriteBarrier.h"
+
+namespace JSC {
+
+#define CHECK_ARRAY_CONSISTENCY 0
+
+// Overview of JSArray
+//
+// Properties of JSArray objects may be stored in one of three locations:
+//   * The regular JSObject property map.
+//   * A storage vector.
+//   * A sparse map of array entries.
+//
+// Properties with non-numeric identifiers, with identifiers that are not representable
+// as an unsigned integer, or where the value is greater than  MAX_ARRAY_INDEX
+// (specifically, this is only one property - the value 0xFFFFFFFFU as an unsigned 32-bit
+// integer) are not considered array indices and will be stored in the JSObject property map.
+//
+// All properties with a numeric identifer, representable as an unsigned integer i,
+// where (i <= MAX_ARRAY_INDEX), are an array index and will be stored in either the
+// storage vector or the sparse map. An array index i will be handled in the following
+// fashion:
+//
+//   * Where (i < MIN_SPARSE_ARRAY_INDEX) the value will be stored in the storage vector,
+//     unless the array is in SparseMode in which case all properties go into the map.
+//   * Where (MIN_SPARSE_ARRAY_INDEX <= i <= MAX_STORAGE_VECTOR_INDEX) the value will either
+//     be stored in the storage vector or in the sparse array, depending on the density of
+//     data that would be stored in the vector (a vector being used where at least
+//     (1 / minDensityMultiplier) of the entries would be populated).
+//   * Where (MAX_STORAGE_VECTOR_INDEX < i <= MAX_ARRAY_INDEX) the value will always be stored
+//     in the sparse array.
+
+// Define the maximum storage vector length to be 2^32 / sizeof(JSValue) / 2 to ensure that
+// there is no risk of overflow.
+#define MAX_STORAGE_VECTOR_LENGTH (static_cast<unsigned>(IndexingHeader::maximumLength))
+
+// These values have to be macros to be used in max() and min() without introducing
+// a PIC branch in Mach-O binaries, see <rdar://problem/5971391>.
+#define MIN_SPARSE_ARRAY_INDEX 10000U
+#define MAX_STORAGE_VECTOR_INDEX (MAX_STORAGE_VECTOR_LENGTH - 1)
+// 0xFFFFFFFF is a bit weird -- is not an array index even though it's an integer.
+#define MAX_ARRAY_INDEX 0xFFFFFFFEU
+
+// The value BASE_VECTOR_LEN is the maximum number of vector elements we'll allocate
+// for an array that was created with a sepcified length (e.g. a = new Array(123))
+#define BASE_VECTOR_LEN 4U
+    
+// The upper bound to the size we'll grow a zero length array when the first element
+// is added.
+#define FIRST_VECTOR_GROW 4U
+
+// Our policy for when to use a vector and when to use a sparse map.
+// For all array indices under MIN_SPARSE_ARRAY_INDEX, we always use a vector.
+// When indices greater than MIN_SPARSE_ARRAY_INDEX are involved, we use a vector
+// as long as it is 1/8 full. If more sparse than that, we use a map.
+static const unsigned minDensityMultiplier = 8;
+
+inline bool isDenseEnoughForVector(unsigned length, unsigned numValues)
+{
+    return length <= MIN_SPARSE_ARRAY_INDEX || length / minDensityMultiplier <= numValues;
+}
+
+inline IndexingHeader indexingHeaderForArray(unsigned length, unsigned vectorLength)
+{
+    IndexingHeader result;
+    result.setPublicLength(length);
+    result.setVectorLength(vectorLength);
+    return result;
+}
+
+inline IndexingHeader baseIndexingHeaderForArray(unsigned length)
+{
+    return indexingHeaderForArray(length, BASE_VECTOR_LEN);
+}
+
+} // namespace JSC
+
+#endif // ArrayConventions_h
+
index 4b13f99..503aecd 100644 (file)
 #include "config.h"
 #include "ArrayPrototype.h"
 
+#include "ButterflyInlineMethods.h"
 #include "CachedCall.h"
 #include "CodeBlock.h"
+#include "CopiedSpaceInlineMethods.h"
 #include "Interpreter.h"
 #include "JIT.h"
 #include "JSStringBuilder.h"
@@ -114,9 +116,17 @@ const ClassInfo ArrayPrototype::s_info = {"Array", &JSArray::s_info, 0, ExecStat
 @end
 */
 
+ArrayPrototype* ArrayPrototype::create(ExecState* exec, JSGlobalObject* globalObject, Structure* structure)
+{
+    Butterfly* butterfly = createArrayButterfly(exec->globalData(), 0);
+    ArrayPrototype* prototype = new (NotNull, allocateCell<ArrayPrototype>(*exec->heap())) ArrayPrototype(globalObject, structure, butterfly);
+    prototype->finishCreation(globalObject);
+    return prototype;
+}
+
 // ECMA 15.4.4
-ArrayPrototype::ArrayPrototype(JSGlobalObject* globalObject, Structure* structure)
-    : JSArray(globalObject->globalData(), structure)
+ArrayPrototype::ArrayPrototype(JSGlobalObject* globalObject, Structure* structure, Butterfly* butterfly)
+    : JSArray(globalObject->globalData(), structure, butterfly)
 {
 }
 
@@ -292,8 +302,8 @@ EncodedJSValue JSC_HOST_CALL arrayProtoFuncToString(ExecState* exec)
 
     for (unsigned k = 0; k < length; k++) {
         JSValue element;
-        if (thisObj->canGetIndex(k))
-            element = thisObj->getIndex(k);
+        if (thisObj->canGetIndexQuickly(k))
+            element = thisObj->getIndexQuickly(k);
         else
             element = thisObj->get(exec, k);
         
@@ -413,10 +423,10 @@ EncodedJSValue JSC_HOST_CALL arrayProtoFuncJoin(ExecState* exec)
         JSArray* array = asArray(thisObj);
 
         for (; k < length; k++) {
-            if (!array->canGetIndex(k))
+            if (!array->canGetIndexQuickly(k))
                 break;
 
-            JSValue element = array->getIndex(k);
+            JSValue element = array->getIndexQuickly(k);
             if (!element.isUndefinedOrNull())
                 stringJoiner.append(element.toWTFStringInline(exec));
             else
@@ -628,7 +638,7 @@ EncodedJSValue JSC_HOST_CALL arrayProtoFuncSort(ExecState* exec)
     CallData callData;
     CallType callType = getCallData(function, callData);
 
-    if (thisObj->classInfo() == &JSArray::s_info && !asArray(thisObj)->inSparseMode()) {
+    if (thisObj->classInfo() == &JSArray::s_info && !asArray(thisObj)->inSparseIndexingMode()) {
         if (isNumericCompareFunction(exec, callType, callData))
             asArray(thisObj)->sortNumeric(exec, function, callType, callData);
         else if (callType != CallTypeNone)
@@ -788,9 +798,9 @@ EncodedJSValue JSC_HOST_CALL arrayProtoFuncFilter(ExecState* exec)
         JSArray* array = asArray(thisObj);
         CachedCall cachedCall(exec, f, 3);
         for (; k < length && !exec->hadException(); ++k) {
-            if (!array->canGetIndex(k))
+            if (!array->canGetIndexQuickly(k))
                 break;
-            JSValue v = array->getIndex(k);
+            JSValue v = array->getIndexQuickly(k);
             cachedCall.setThis(applyThis);
             cachedCall.setArgument(0, v);
             cachedCall.setArgument(1, jsNumber(k));
@@ -846,11 +856,11 @@ EncodedJSValue JSC_HOST_CALL arrayProtoFuncMap(ExecState* exec)
         JSArray* array = asArray(thisObj);
         CachedCall cachedCall(exec, f, 3);
         for (; k < length && !exec->hadException(); ++k) {
-            if (UNLIKELY(!array->canGetIndex(k)))
+            if (UNLIKELY(!array->canGetIndexQuickly(k)))
                 break;
 
             cachedCall.setThis(applyThis);
-            cachedCall.setArgument(0, array->getIndex(k));
+            cachedCall.setArgument(0, array->getIndexQuickly(k));
             cachedCall.setArgument(1, jsNumber(k));
             cachedCall.setArgument(2, thisObj);
 
@@ -909,11 +919,11 @@ EncodedJSValue JSC_HOST_CALL arrayProtoFuncEvery(ExecState* exec)
         JSArray* array = asArray(thisObj);
         CachedCall cachedCall(exec, f, 3);
         for (; k < length && !exec->hadException(); ++k) {
-            if (UNLIKELY(!array->canGetIndex(k)))
+            if (UNLIKELY(!array->canGetIndexQuickly(k)))
                 break;
             
             cachedCall.setThis(applyThis);
-            cachedCall.setArgument(0, array->getIndex(k));
+            cachedCall.setArgument(0, array->getIndexQuickly(k));
             cachedCall.setArgument(1, jsNumber(k));
             cachedCall.setArgument(2, thisObj);
             JSValue result = cachedCall.call();
@@ -965,11 +975,11 @@ EncodedJSValue JSC_HOST_CALL arrayProtoFuncForEach(ExecState* exec)
         JSArray* array = asArray(thisObj);
         CachedCall cachedCall(exec, f, 3);
         for (; k < length && !exec->hadException(); ++k) {
-            if (UNLIKELY(!array->canGetIndex(k)))
+            if (UNLIKELY(!array->canGetIndexQuickly(k)))
                 break;
 
             cachedCall.setThis(applyThis);
-            cachedCall.setArgument(0, array->getIndex(k));
+            cachedCall.setArgument(0, array->getIndexQuickly(k));
             cachedCall.setArgument(1, jsNumber(k));
             cachedCall.setArgument(2, thisObj);
 
@@ -1017,11 +1027,11 @@ EncodedJSValue JSC_HOST_CALL arrayProtoFuncSome(ExecState* exec)
         JSArray* array = asArray(thisObj);
         CachedCall cachedCall(exec, f, 3);
         for (; k < length && !exec->hadException(); ++k) {
-            if (UNLIKELY(!array->canGetIndex(k)))
+            if (UNLIKELY(!array->canGetIndexQuickly(k)))
                 break;
             
             cachedCall.setThis(applyThis);
-            cachedCall.setArgument(0, array->getIndex(k));
+            cachedCall.setArgument(0, array->getIndexQuickly(k));
             cachedCall.setArgument(1, jsNumber(k));
             cachedCall.setArgument(2, thisObj);
             JSValue result = cachedCall.call();
@@ -1075,8 +1085,8 @@ EncodedJSValue JSC_HOST_CALL arrayProtoFuncReduce(ExecState* exec)
 
     if (exec->argumentCount() >= 2)
         rv = exec->argument(1);
-    else if (array && array->canGetIndex(0)){
-        rv = array->getIndex(0);
+    else if (array && array->canGetIndexQuickly(0)) {
+        rv = array->getIndexQuickly(0);
         i = 1;
     } else {
         for (i = 0; i < length; i++) {
@@ -1097,8 +1107,8 @@ EncodedJSValue JSC_HOST_CALL arrayProtoFuncReduce(ExecState* exec)
             cachedCall.setThis(jsUndefined());
             cachedCall.setArgument(0, rv);
             JSValue v;
-            if (LIKELY(array->canGetIndex(i)))
-                v = array->getIndex(i);
+            if (LIKELY(array->canGetIndexQuickly(i)))
+                v = array->getIndexQuickly(i);
             else
                 break; // length has been made unsafe while we enumerate fallback to slow path
             cachedCall.setArgument(1, v);
@@ -1152,8 +1162,8 @@ EncodedJSValue JSC_HOST_CALL arrayProtoFuncReduceRight(ExecState* exec)
     
     if (exec->argumentCount() >= 2)
         rv = exec->argument(1);
-    else if (array && array->canGetIndex(length - 1)){
-        rv = array->getIndex(length - 1);
+    else if (array && array->canGetIndexQuickly(length - 1)) {
+        rv = array->getIndexQuickly(length - 1);
         i = 1;
     } else {
         for (i = 0; i < length; i++) {
@@ -1174,9 +1184,9 @@ EncodedJSValue JSC_HOST_CALL arrayProtoFuncReduceRight(ExecState* exec)
             unsigned idx = length - i - 1;
             cachedCall.setThis(jsUndefined());
             cachedCall.setArgument(0, rv);
-            if (UNLIKELY(!array->canGetIndex(idx)))
+            if (UNLIKELY(!array->canGetIndexQuickly(idx)))
                 break; // length has been made unsafe while we enumerate fallback to slow path
-            cachedCall.setArgument(1, array->getIndex(idx));
+            cachedCall.setArgument(1, array->getIndexQuickly(idx));
             cachedCall.setArgument(2, jsNumber(idx));
             cachedCall.setArgument(3, array);
             rv = cachedCall.call();
index 4f52fb6..b330211 100644 (file)
@@ -28,17 +28,12 @@ namespace JSC {
 
     class ArrayPrototype : public JSArray {
     private:
-        ArrayPrototype(JSGlobalObject*, Structure*);
+        ArrayPrototype(JSGlobalObject*, Structure*, Butterfly*);
 
     public:
         typedef JSArray Base;
 
-        static ArrayPrototype* create(ExecState* exec, JSGlobalObject* globalObject, Structure* structure)
-        {
-            ArrayPrototype* prototype = new (NotNull, allocateCell<ArrayPrototype>(*exec->heap())) ArrayPrototype(globalObject, structure);
-            prototype->finishCreation(globalObject);
-            return prototype;
-        }
+        static ArrayPrototype* create(ExecState*, JSGlobalObject*, Structure*);
         
         static bool getOwnPropertySlot(JSCell*, ExecState*, PropertyName, PropertySlot&);
         static bool getOwnPropertyDescriptor(JSObject*, ExecState*, PropertyName, PropertyDescriptor&);
@@ -47,7 +42,7 @@ namespace JSC {
 
         static Structure* createStructure(JSGlobalData& globalData, JSGlobalObject* globalObject, JSValue prototype)
         {
-            return Structure::create(globalData, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), &s_info);
+            return Structure::create(globalData, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), &s_info, ArrayWithArrayStorage);
         }
 
     protected:
diff --git a/Source/JavaScriptCore/runtime/ArrayStorage.h b/Source/JavaScriptCore/runtime/ArrayStorage.h
new file mode 100644 (file)
index 0000000..d967d0b
--- /dev/null
@@ -0,0 +1,106 @@
+/*
+ * Copyright (C) 2012 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
+ */
+
+#ifndef ArrayStorage_h
+#define ArrayStorage_h
+
+#include "ArrayConventions.h"
+#include "Butterfly.h"
+#include "IndexingHeader.h"
+#include "SparseArrayValueMap.h"
+#include "WriteBarrier.h"
+#include <wtf/Noncopyable.h>
+#include <wtf/Platform.h>
+
+namespace JSC {
+
+// This struct holds the actual data values of an array. A JSArray object points to its contained ArrayStorage
+// struct by pointing to m_vector. To access the contained ArrayStorage struct, use the getStorage() and 
+// setStorage() methods. It is important to note that there may be space before the ArrayStorage that 
+// is used to quick unshift / shift operation. The actual allocated pointer is available by using:
+//     getStorage() - m_indexBias * sizeof(JSValue)
+struct ArrayStorage {
+    WTF_MAKE_NONCOPYABLE(ArrayStorage);
+private:
+    ArrayStorage() { } // Not directly instantiable. Can only be created as part of a Butterfly.
+public:
+    
+    static ArrayStorage* from(Butterfly* butterfly) { return reinterpret_cast<ArrayStorage*>(butterfly); }
+    static ArrayStorage* from(IndexingHeader* indexingHeader) { return indexingHeader->arrayStorage(); }
+    
+    Butterfly* butterfly() { return reinterpret_cast<Butterfly*>(this); }
+    IndexingHeader* indexingHeader() { return IndexingHeader::from(this); }
+    
+    // We steal two fields from the indexing header: vectorLength and length.
+    unsigned length() { return indexingHeader()->publicLength(); }
+    void setLength(unsigned length) { indexingHeader()->setPublicLength(length); }
+    unsigned vectorLength() { return indexingHeader()->vectorLength(); }
+    void setVectorLength(unsigned length) { indexingHeader()->setVectorLength(length); }
+    
+    ALWAYS_INLINE void copyHeaderFromDuringGC(const ArrayStorage& other)
+    {
+        m_sparseMap.copyFrom(other.m_sparseMap);
+        m_indexBias = other.m_indexBias;
+        m_numValuesInVector = other.m_numValuesInVector;
+#if CHECK_ARRAY_CONSISTENCY
+        m_initializationIndex = other.m_initializationIndex;
+        m_inCompactInitialization = other.m_inCompactInitialization;
+#endif
+    }
+    
+    bool inSparseMode()
+    {
+        return m_sparseMap && m_sparseMap->sparseMode();
+    }
+    
+    WriteBarrier<SparseArrayValueMap> m_sparseMap;
+    unsigned m_indexBias;
+    unsigned m_numValuesInVector;
+#if CHECK_ARRAY_CONSISTENCY
+    // Needs to be a uintptr_t for alignment purposes.
+    uintptr_t m_initializationIndex;
+    uintptr_t m_inCompactInitialization;
+#elif USE(JSVALUE32_64)
+    uintptr_t m_padding;
+#endif
+    WriteBarrier<Unknown> m_vector[1];
+    
+    static ptrdiff_t lengthOffset() { return Butterfly::offsetOfPublicLength(); }
+    static ptrdiff_t vectorLengthOffset() { return Butterfly::offsetOfVectorLength(); }
+    static ptrdiff_t numValuesInVectorOffset() { return OBJECT_OFFSETOF(ArrayStorage, m_numValuesInVector); }
+    static ptrdiff_t vectorOffset() { return OBJECT_OFFSETOF(ArrayStorage, m_vector); }
+    static ptrdiff_t indexBiasOffset() { return OBJECT_OFFSETOF(ArrayStorage, m_indexBias); }
+    static ptrdiff_t sparseMapOffset() { return OBJECT_OFFSETOF(ArrayStorage, m_sparseMap); }
+    
+    static size_t sizeFor(unsigned vectorLength)
+    {
+        return ArrayStorage::vectorOffset() + vectorLength * sizeof(WriteBarrier<Unknown>);
+    }
+};
+
+} // namespace JSC
+
+#endif // ArrayStorage_h
+
diff --git a/Source/JavaScriptCore/runtime/Butterfly.h b/Source/JavaScriptCore/runtime/Butterfly.h
new file mode 100644 (file)
index 0000000..1926169
--- /dev/null
@@ -0,0 +1,106 @@
+/*
+ * Copyright (C) 2012 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
+ */
+
+#ifndef Butterfly_h
+#define Butterfly_h
+
+#include "IndexingHeader.h"
+#include "PropertyOffset.h"
+#include "PropertyStorage.h"
+#include <wtf/Noncopyable.h>
+#include <wtf/Platform.h>
+
+namespace JSC {
+
+class JSGlobalData;
+class SlotVisitor;
+struct ArrayStorage;
+
+class Butterfly {
+    WTF_MAKE_NONCOPYABLE(Butterfly);
+private:
+    Butterfly() { } // Not instantiable.
+public:
+    
+    static size_t totalSize(size_t preCapacity, size_t propertyCapacity, bool hasIndexingHeader, size_t indexingPayloadSizeInBytes)
+    {
+        ASSERT(indexingPayloadSizeInBytes ? hasIndexingHeader : true);
+        ASSERT(sizeof(EncodedJSValue) == sizeof(IndexingHeader));
+        return (preCapacity + propertyCapacity) * sizeof(EncodedJSValue) + (hasIndexingHeader ? sizeof(IndexingHeader) : 0) + indexingPayloadSizeInBytes;
+    }
+
+    static Butterfly* fromBase(void* base, size_t preCapacity, size_t propertyCapacity)
+    {
+        return reinterpret_cast<Butterfly*>(static_cast<EncodedJSValue*>(base) + preCapacity + propertyCapacity + 1);
+    }
+    
+    static ptrdiff_t offsetOfIndexingHeader() { return IndexingHeader::offsetOfIndexingHeader(); }
+    static ptrdiff_t offsetOfPublicLength() { return offsetOfIndexingHeader() + IndexingHeader::offsetOfPublicLength(); }
+    static ptrdiff_t offsetOfVectorLength() { return offsetOfIndexingHeader() + IndexingHeader::offsetOfVectorLength(); }
+    
+    static Butterfly* createUninitialized(JSGlobalData&, size_t preCapacity, size_t propertyCapacity, bool hasIndexingHeader, size_t indexingPayloadSizeInBytes);
+
+    static Butterfly* create(JSGlobalData&, size_t preCapacity, size_t propertyCapacity, bool hasIndexingHeader, const IndexingHeader&, size_t indexingPayloadSizeInBytes);
+    static Butterfly* create(JSGlobalData&, Structure*);
+    static Butterfly* createUninitializedDuringCollection(SlotVisitor&, size_t preCapacity, size_t propertyCapacity, bool hasIndexingHeader, size_t indexingPayloadSizeInBytes);
+    
+    IndexingHeader* indexingHeader() { return IndexingHeader::from(this); }
+    const IndexingHeader* indexingHeader() const { return IndexingHeader::from(this); }
+    PropertyStorage propertyStorage() { return indexingHeader()->propertyStorage(); }
+    ConstPropertyStorage propertyStorage() const { return indexingHeader()->propertyStorage(); }
+    template<typename T>
+    T* indexingPayload() { return reinterpret_cast<T*>(this); }
+    ArrayStorage* arrayStorage() { return indexingPayload<ArrayStorage>(); }
+    
+    static ptrdiff_t offsetOfPropertyStorage() { return -static_cast<ptrdiff_t>(sizeof(IndexingHeader)); }
+    static int indexOfPropertyStorage()
+    {
+        ASSERT(sizeof(IndexingHeader) == sizeof(EncodedJSValue));
+        return -1;
+    }
+
+    void* base(size_t preCapacity, size_t propertyCapacity) { return propertyStorage() - propertyCapacity - preCapacity; }
+    void* base(Structure*);
+    
+    // The butterfly reallocation methods perform the reallocation itself but do not change any
+    // of the meta-data to reflect that the reallocation occurred. Note that this set of
+    // methods is not exhaustive and is not intended to encapsulate all possible allocation
+    // modes of butterflies - there are code paths that allocate butterflies by calling
+    // directly into Heap::tryAllocateStorage.
+    Butterfly* growPropertyStorage(JSGlobalData&, size_t preCapacity, size_t oldPropertyCapacity, bool hasIndexingHeader, size_t indexingPayloadSizeInBytes, size_t newPropertyCapacity);
+    Butterfly* growPropertyStorage(JSGlobalData&, Structure* oldStructure, size_t oldPropertyCapacity, size_t newPropertyCapacity);
+    Butterfly* growPropertyStorage(JSGlobalData&, Structure* oldStructure, size_t newPropertyCapacity);
+    Butterfly* growArrayRight(JSGlobalData&, Structure* oldStructure, size_t propertyCapacity, bool hadIndexingHeader, size_t oldIndexingPayloadSizeInBytes, size_t newIndexingPayloadSizeInBytes); // Assumes that preCapacity is zero, and asserts as much.
+    Butterfly* growArrayRight(JSGlobalData&, Structure*, size_t newIndexingPayloadSizeInBytes);
+    Butterfly* resizeArray(JSGlobalData&, size_t propertyCapacity, bool oldHasIndexingHeader, size_t oldIndexingPayloadSizeInBytes, size_t newPreCapacity, bool newHasIndexingHeader, size_t newIndexingPayloadSizeInBytes);
+    Butterfly* resizeArray(JSGlobalData&, Structure*, size_t newPreCapacity, size_t newIndexingPayloadSizeInBytes); // Assumes that you're not changing whether or not the object has an indexing header.
+    Butterfly* unshift(Structure*, size_t numberOfSlots);
+    Butterfly* shift(Structure*, size_t numberOfSlots);
+};
+
+} // namespace JSC
+
+#endif // Butterfly_h
+
diff --git a/Source/JavaScriptCore/runtime/ButterflyInlineMethods.h b/Source/JavaScriptCore/runtime/ButterflyInlineMethods.h
new file mode 100644 (file)
index 0000000..0493503
--- /dev/null
@@ -0,0 +1,179 @@
+/*
+ * Copyright (C) 2012 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
+ */
+
+#ifndef ButterflyInlineMethods_h
+#define ButterflyInlineMethods_h
+
+#include "ArrayStorage.h"
+#include "Butterfly.h"
+#include "CopiedSpaceInlineMethods.h"
+#include "JSGlobalData.h"
+#include "SlotVisitor.h"
+#include "Structure.h"
+
+namespace JSC {
+
+inline Butterfly* Butterfly::createUninitialized(JSGlobalData& globalData, size_t preCapacity, size_t propertyCapacity, bool hasIndexingHeader, size_t indexingPayloadSizeInBytes)
+{
+    void* temp;
+    size_t size = totalSize(preCapacity, propertyCapacity, hasIndexingHeader, indexingPayloadSizeInBytes);
+    if (!globalData.heap.tryAllocateStorage(size, &temp))
+        CRASH();
+    Butterfly* result = fromBase(temp, preCapacity, propertyCapacity);
+    return result;
+}
+
+inline Butterfly* Butterfly::create(JSGlobalData& globalData, size_t preCapacity, size_t propertyCapacity, bool hasIndexingHeader, const IndexingHeader& indexingHeader, size_t indexingPayloadSizeInBytes)
+{
+    Butterfly* result = createUninitialized(
+        globalData, preCapacity, propertyCapacity, hasIndexingHeader, indexingPayloadSizeInBytes);
+    if (hasIndexingHeader)
+        *result->indexingHeader() = indexingHeader;
+    return result;
+}
+
+inline Butterfly* Butterfly::create(JSGlobalData& globalData, Structure* structure)
+{
+    return create(globalData, 0, structure->outOfLineCapacity(), hasIndexingHeader(structure->indexingType()), IndexingHeader(), 0);
+}
+
+inline Butterfly* Butterfly::createUninitializedDuringCollection(SlotVisitor& visitor, size_t preCapacity, size_t propertyCapacity, bool hasIndexingHeader, size_t indexingPayloadSizeInBytes)
+{
+    Butterfly* result = fromBase(
+        visitor.allocateNewSpace(totalSize(preCapacity, propertyCapacity, hasIndexingHeader, indexingPayloadSizeInBytes)),
+        preCapacity, propertyCapacity);
+    return result;
+}
+
+inline void* Butterfly::base(Structure* structure)
+{
+    return base(indexingHeader()->preCapacity(structure), structure->outOfLineCapacity());
+}
+
+inline Butterfly* Butterfly::growPropertyStorage(JSGlobalData& globalData, size_t preCapacity, size_t oldPropertyCapacity, bool hasIndexingHeader, size_t indexingPayloadSizeInBytes, size_t newPropertyCapacity)
+{
+    ASSERT(newPropertyCapacity > oldPropertyCapacity);
+    Butterfly* result = createUninitialized(
+        globalData, preCapacity, newPropertyCapacity, hasIndexingHeader, indexingPayloadSizeInBytes);
+    memcpy(
+        result->propertyStorage() - oldPropertyCapacity,
+        propertyStorage() - oldPropertyCapacity,
+        totalSize(0, oldPropertyCapacity, hasIndexingHeader, indexingPayloadSizeInBytes));
+    return result;
+}
+
+inline Butterfly* Butterfly::growPropertyStorage(JSGlobalData& globalData, Structure* structure, size_t oldPropertyCapacity, size_t newPropertyCapacity)
+{
+    return growPropertyStorage(
+        globalData, indexingHeader()->preCapacity(structure), oldPropertyCapacity,
+        hasIndexingHeader(structure->indexingType()),
+        indexingHeader()->indexingPayloadSizeInBytes(structure), newPropertyCapacity);
+}
+
+inline Butterfly* Butterfly::growPropertyStorage(JSGlobalData& globalData, Structure* oldStructure, size_t newPropertyCapacity)
+{
+    return growPropertyStorage(
+        globalData, oldStructure, oldStructure->outOfLineCapacity(), newPropertyCapacity);
+}
+
+inline Butterfly* Butterfly::growArrayRight(JSGlobalData& globalData, Structure* oldStructure, size_t propertyCapacity, bool hadIndexingHeader, size_t oldIndexingPayloadSizeInBytes, size_t newIndexingPayloadSizeInBytes)
+{
+    ASSERT_UNUSED(oldStructure, !indexingHeader()->preCapacity(oldStructure));
+    ASSERT_UNUSED(oldStructure, hadIndexingHeader == hasIndexingHeader(oldStructure->indexingType()));
+    void* theBase = base(0, propertyCapacity);
+    size_t oldSize = totalSize(0, propertyCapacity, hadIndexingHeader, oldIndexingPayloadSizeInBytes);
+    size_t newSize = totalSize(0, propertyCapacity, true, newIndexingPayloadSizeInBytes);
+    if (!globalData.heap.tryReallocateStorage(&theBase, oldSize, newSize))
+        return 0;
+    return fromBase(theBase, 0, propertyCapacity);
+}
+
+inline Butterfly* Butterfly::growArrayRight(JSGlobalData& globalData, Structure* oldStructure, size_t newIndexingPayloadSizeInBytes)
+{
+    return growArrayRight(
+        globalData, oldStructure, oldStructure->outOfLineCapacity(),
+        hasIndexingHeader(oldStructure->indexingType()),
+        indexingHeader()->indexingPayloadSizeInBytes(oldStructure), newIndexingPayloadSizeInBytes);
+}
+
+inline Butterfly* Butterfly::resizeArray(JSGlobalData& globalData, size_t propertyCapacity, bool oldHasIndexingHeader, size_t oldIndexingPayloadSizeInBytes, size_t newPreCapacity, bool newHasIndexingHeader, size_t newIndexingPayloadSizeInBytes)
+{
+    Butterfly* result = createUninitialized(
+        globalData, newPreCapacity, propertyCapacity, newHasIndexingHeader, newIndexingPayloadSizeInBytes);
+    // FIXME: This could be made much more efficient if we used the property size,
+    // not the capacity.
+    void* to = result->propertyStorage() - propertyCapacity;
+    void* from = propertyStorage() - propertyCapacity;
+    size_t size = std::min(
+        totalSize(0, propertyCapacity, oldHasIndexingHeader, oldIndexingPayloadSizeInBytes),
+        totalSize(0, propertyCapacity, newHasIndexingHeader, newIndexingPayloadSizeInBytes));
+    memcpy(to, from, size);
+    return result;
+}
+
+inline Butterfly* Butterfly::resizeArray(JSGlobalData& globalData, Structure* structure, size_t newPreCapacity, size_t newIndexingPayloadSizeInBytes)
+{
+    bool hasIndexingHeader = JSC::hasIndexingHeader(structure->indexingType());
+    return resizeArray(
+        globalData, structure->outOfLineCapacity(), hasIndexingHeader,
+        indexingHeader()->indexingPayloadSizeInBytes(structure), newPreCapacity,
+        hasIndexingHeader, newIndexingPayloadSizeInBytes);
+}
+
+inline Butterfly* Butterfly::unshift(Structure* structure, size_t numberOfSlots)
+{
+    ASSERT(hasIndexingHeader(structure->indexingType()));
+    ASSERT(numberOfSlots <= indexingHeader()->preCapacity(structure));
+    unsigned propertyCapacity = structure->outOfLineCapacity();
+    // FIXME: It would probably be wise to rewrite this as a loop since (1) we know in which
+    // direction we're moving memory so we don't need the extra check of memmove and (2) we're
+    // moving a small amount of memory in the common case so the throughput of memmove won't
+    // amortize the overhead of calling it. And no, we cannot rely on the C++ compiler to
+    // inline memmove (particularly since the size argument is likely to be variable), nor can
+    // we rely on the compiler to recognize the ordering of the pointer arguments (since
+    // propertyCapacity is variable and could cause wrap-around as far as the compiler knows).
+    memmove(
+        propertyStorage() - numberOfSlots - propertyCapacity,
+        propertyStorage() - propertyCapacity,
+        sizeof(EncodedJSValue) * propertyCapacity + sizeof(IndexingHeader) + ArrayStorage::sizeFor(0));
+    return IndexingHeader::fromEndOf(propertyStorage() - numberOfSlots)->butterfly();
+}
+
+inline Butterfly* Butterfly::shift(Structure* structure, size_t numberOfSlots)
+{
+    ASSERT(hasIndexingHeader(structure->indexingType()));
+    unsigned propertyCapacity = structure->outOfLineCapacity();
+    // FIXME: See comment in unshift(), above.
+    memmove(
+        propertyStorage() - propertyCapacity + numberOfSlots,
+        propertyStorage() - propertyCapacity,
+        sizeof(EncodedJSValue) * propertyCapacity + sizeof(IndexingHeader) + ArrayStorage::sizeFor(0));
+    return IndexingHeader::fromEndOf(propertyStorage() + numberOfSlots)->butterfly();
+}
+
+} // namespace JSC
+
+#endif // ButterflyInlineMethods_h
+
index 4c72f3e..0e1747b 100644 (file)
@@ -72,6 +72,9 @@ namespace JSC {
         typedef void (*GetOwnPropertyNamesFunctionPtr)(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode);
         GetOwnPropertyNamesFunctionPtr getOwnPropertyNames;
 
+        typedef void (*GetOwnNonIndexPropertyNamesFunctionPtr)(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode);
+        GetOwnNonIndexPropertyNamesFunctionPtr getOwnNonIndexPropertyNames;
+
         typedef void (*GetPropertyNamesFunctionPtr)(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode);
         GetPropertyNamesFunctionPtr getPropertyNames;
 
@@ -124,6 +127,7 @@ struct MemberCheck##member { \
         &ClassName::toThisObject, \
         &ClassName::defaultValue, \
         &ClassName::getOwnPropertyNames, \
+        &ClassName::getOwnNonIndexPropertyNames, \
         &ClassName::getPropertyNames, \
         &ClassName::className, \
         &ClassName::hasInstance, \
diff --git a/Source/JavaScriptCore/runtime/IndexingHeader.h b/Source/JavaScriptCore/runtime/IndexingHeader.h
new file mode 100644 (file)
index 0000000..caa1818
--- /dev/null
@@ -0,0 +1,122 @@
+/*
+ * Copyright (C) 2012 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
+ */
+
+#ifndef IndexingHeader_h
+#define IndexingHeader_h
+
+#include "PropertyStorage.h"
+#include <wtf/Platform.h>
+
+namespace JSC {
+
+class Butterfly;
+class LLIntOffsetsExtractor;
+class Structure;
+struct ArrayStorage;
+
+class IndexingHeader {
+public:
+    // Define the maximum storage vector length to be 2^32 / sizeof(JSValue) / 2 to ensure that
+    // there is no risk of overflow.
+    enum { maximumLength = 0x10000000 };
+    
+    static ptrdiff_t offsetOfIndexingHeader() { return -static_cast<ptrdiff_t>(sizeof(IndexingHeader)); }
+    
+    static ptrdiff_t offsetOfPublicLength() { return OBJECT_OFFSETOF(IndexingHeader, m_publicLength); }
+    static ptrdiff_t offsetOfVectorLength() { return OBJECT_OFFSETOF(IndexingHeader, m_vectorLength); }
+    
+    IndexingHeader()
+        : m_publicLength(0)
+        , m_vectorLength(0)
+    {
+    }
+    
+    uint32_t vectorLength() const { return m_vectorLength; }
+    
+    void setVectorLength(uint32_t length)
+    {
+        ASSERT(length <= maximumLength);
+        m_vectorLength = length;
+    }
+    
+    uint32_t publicLength() { return m_publicLength; }
+    void setPublicLength(uint32_t auxWord) { m_publicLength = auxWord; }
+    
+    static IndexingHeader* from(Butterfly* butterfly)
+    {
+        return reinterpret_cast<IndexingHeader*>(butterfly) - 1;
+    }
+    
+    static const IndexingHeader* from(const Butterfly* butterfly)
+    {
+        return reinterpret_cast<const IndexingHeader*>(butterfly) - 1;
+    }
+    
+    static IndexingHeader* from(ArrayStorage* arrayStorage)
+    {
+        return reinterpret_cast<IndexingHeader*>(arrayStorage) - 1;
+    }
+    
+    static IndexingHeader* fromEndOf(PropertyStorage propertyStorage)
+    {
+        return reinterpret_cast<IndexingHeader*>(propertyStorage);
+    }
+    
+    PropertyStorage propertyStorage()
+    {
+        return reinterpret_cast<PropertyStorage>(this);
+    }
+    
+    ConstPropertyStorage propertyStorage() const
+    {
+        return reinterpret_cast<ConstPropertyStorage>(this);
+    }
+    
+    ArrayStorage* arrayStorage()
+    {
+        return reinterpret_cast<ArrayStorage*>(this + 1);
+    }
+    
+    Butterfly* butterfly()
+    {
+        return reinterpret_cast<Butterfly*>(this + 1);
+    }
+    
+    // These methods are not standalone in the sense that they cannot be
+    // used on a copy of the IndexingHeader.
+    size_t preCapacity(Structure*);
+    size_t indexingPayloadSizeInBytes(Structure*);
+    
+private:
+    friend class LLIntOffsetsExtractor;
+    
+    uint32_t m_publicLength; // The meaning of this field depends on the array type, but for all JSArrays we rely on this being the publicly visible length (array.length).
+    uint32_t m_vectorLength; // The length of the indexed property storage. The actual size of the storage depends on this, and the type.
+};
+
+} // namespace JSC
+
+#endif // IndexingHeader_h
+
diff --git a/Source/JavaScriptCore/runtime/IndexingHeaderInlineMethods.h b/Source/JavaScriptCore/runtime/IndexingHeaderInlineMethods.h
new file mode 100644 (file)
index 0000000..8d6e082
--- /dev/null
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2012 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
+ */
+
+#ifndef IndexingHeaderInlineMethods_h
+#define IndexingHeaderInlineMethods_h
+
+#include "ArrayStorage.h"
+#include "IndexingHeader.h"
+#include "Structure.h"
+
+namespace JSC {
+
+inline size_t IndexingHeader::preCapacity(Structure* structure)
+{
+    if (LIKELY(!(structure->indexingType() & HasArrayStorage)))
+        return 0;
+    
+    return arrayStorage()->m_indexBias;
+}
+
+inline size_t IndexingHeader::indexingPayloadSizeInBytes(Structure* structure)
+{
+    if (LIKELY(!(structure->indexingType() & HasArrayStorage)))
+        return 0;
+    
+    return ArrayStorage::sizeFor(arrayStorage()->vectorLength());
+}
+
+} // namespace JSC
+
+#endif // IndexingHeaderInlineMethods_h
+
diff --git a/Source/JavaScriptCore/runtime/IndexingType.h b/Source/JavaScriptCore/runtime/IndexingType.h
new file mode 100644 (file)
index 0000000..8671895
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2012 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
+ */
+
+#ifndef IndexingType_h
+#define IndexingType_h
+
+namespace JSC {
+
+typedef uint8_t IndexingType;
+
+// Flags for testing the presence of capabilities.
+static const IndexingType IsArray                  = 1;
+static const IndexingType HasArrayStorage          = 8;
+
+// Additional flags for tracking the history of the type. These are usually
+// masked off unless you ask for them directly.
+static const IndexingType HadArrayStorage          = 16; // Means that this object did have array storage in the past.
+
+// List of acceptable array types.
+static const IndexingType NonArray                 = 0;
+static const IndexingType NonArrayWithArrayStorage = HasArrayStorage;
+static const IndexingType Array                    = IsArray;
+static const IndexingType ArrayWithArrayStorage    = IsArray | HasArrayStorage;
+
+// Mask of all possible types.
+static const IndexingType AllArrayTypes            = 15;
+
+// Mask of all possible types including the history.
+static const IndexingType AllArrayTypesAndHistory  = 31;
+
+inline bool hasIndexingHeader(IndexingType type)
+{
+    return !!(type & HasArrayStorage);
+}
+
+} // namespace JSC
+
+#endif // IndexingType_h
+
index 585d2af..dc061bc 100644 (file)
@@ -107,7 +107,7 @@ inline bool JSActivation::symbolTablePut(ExecState* exec, PropertyName propertyN
     return true;
 }
 
-void JSActivation::getOwnPropertyNames(JSObject* object, ExecState* exec, PropertyNameArray& propertyNames, EnumerationMode mode)
+void JSActivation::getOwnNonIndexPropertyNames(JSObject* object, ExecState* exec, PropertyNameArray& propertyNames, EnumerationMode mode)
 {
     JSActivation* thisObject = jsCast<JSActivation*>(object);
 
@@ -122,8 +122,8 @@ void JSActivation::getOwnPropertyNames(JSObject* object, ExecState* exec, Proper
             continue;
         propertyNames.add(Identifier(exec, it->first.get()));
     }
-    // Skip the JSVariableObject implementation of getOwnPropertyNames
-    JSObject::getOwnPropertyNames(thisObject, exec, propertyNames, mode);
+    // Skip the JSVariableObject implementation of getOwnNonIndexPropertyNames
+    JSObject::getOwnNonIndexPropertyNames(thisObject, exec, propertyNames, mode);
 }
 
 inline bool JSActivation::symbolTablePutWithAttributes(JSGlobalData& globalData, PropertyName propertyName, JSValue value, unsigned attributes)
index 8eb8fb0..df59c3d 100644 (file)
@@ -65,7 +65,7 @@ namespace JSC {
         bool isDynamicScope(bool& requiresDynamicChecks) const;
 
         static bool getOwnPropertySlot(JSCell*, ExecState*, PropertyName, PropertySlot&);
-        static void getOwnPropertyNames(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode);
+        static void getOwnNonIndexPropertyNames(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode);
         JS_EXPORT_PRIVATE static bool getOwnPropertyDescriptor(JSObject*, ExecState*, PropertyName, PropertyDescriptor&);
 
         static void put(JSCell*, ExecState*, PropertyName, JSValue, PutPropertySlot&);
index 8e1606f..a30cbaa 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *  Copyright (C) 1999-2000 Harri Porten (porten@kde.org)
- *  Copyright (C) 2003, 2007, 2008, 2009 Apple Inc. All rights reserved.
+ *  Copyright (C) 2003, 2007, 2008, 2009, 2012 Apple Inc. All rights reserved.
  *  Copyright (C) 2003 Peter Kelly (pmk@post.com)
  *  Copyright (C) 2006 Alexey Proskuryakov (ap@nypop.com)
  *
 #include "JSArray.h"
 
 #include "ArrayPrototype.h"
+#include "ButterflyInlineMethods.h"
 #include "CopiedSpace.h"
 #include "CopiedSpaceInlineMethods.h"
 #include "CachedCall.h"
 #include "Error.h"
 #include "Executable.h"
 #include "GetterSetter.h"
+#include "IndexingHeaderInlineMethods.h"
 #include "PropertyNameArray.h"
+#include "Reject.h"
+#include "SparseArrayValueMapInlineMethods.h"
 #include <wtf/AVLTree.h>
 #include <wtf/Assertions.h>
 #include <wtf/OwnPtr.h>
@@ -45,480 +49,23 @@ namespace JSC {
 ASSERT_CLASS_FITS_IN_CELL(JSArray);
 ASSERT_HAS_TRIVIAL_DESTRUCTOR(JSArray);
 
-// Overview of JSArray
-//
-// Properties of JSArray objects may be stored in one of three locations:
-//   * The regular JSObject property map.
-//   * A storage vector.
-//   * A sparse map of array entries.
-//
-// Properties with non-numeric identifiers, with identifiers that are not representable
-// as an unsigned integer, or where the value is greater than  MAX_ARRAY_INDEX
-// (specifically, this is only one property - the value 0xFFFFFFFFU as an unsigned 32-bit
-// integer) are not considered array indices and will be stored in the JSObject property map.
-//
-// All properties with a numeric identifer, representable as an unsigned integer i,
-// where (i <= MAX_ARRAY_INDEX), are an array index and will be stored in either the
-// storage vector or the sparse map.  An array index i will be handled in the following
-// fashion:
-//
-//   * Where (i < MIN_SPARSE_ARRAY_INDEX) the value will be stored in the storage vector,
-//     unless the array is in SparseMode in which case all properties go into the map.
-//   * Where (MIN_SPARSE_ARRAY_INDEX <= i <= MAX_STORAGE_VECTOR_INDEX) the value will either
-//     be stored in the storage vector or in the sparse array, depending on the density of
-//     data that would be stored in the vector (a vector being used where at least
-//     (1 / minDensityMultiplier) of the entries would be populated).
-//   * Where (MAX_STORAGE_VECTOR_INDEX < i <= MAX_ARRAY_INDEX) the value will always be stored
-//     in the sparse array.
-
-// The definition of MAX_STORAGE_VECTOR_LENGTH is dependant on the definition storageSize
-// function below - the MAX_STORAGE_VECTOR_LENGTH limit is defined such that the storage
-// size calculation cannot overflow.  (sizeof(ArrayStorage) - sizeof(WriteBarrier<Unknown>)) +
-// (vectorLength * sizeof(WriteBarrier<Unknown>)) must be <= 0xFFFFFFFFU (which is maximum value of size_t).
-#define MAX_STORAGE_VECTOR_LENGTH static_cast<unsigned>((0xFFFFFFFFU - (sizeof(ArrayStorage) - sizeof(WriteBarrier<Unknown>))) / sizeof(WriteBarrier<Unknown>))
-
-// These values have to be macros to be used in max() and min() without introducing
-// a PIC branch in Mach-O binaries, see <rdar://problem/5971391>.
-#define MIN_SPARSE_ARRAY_INDEX 10000U
-#define MAX_STORAGE_VECTOR_INDEX (MAX_STORAGE_VECTOR_LENGTH - 1)
-// 0xFFFFFFFF is a bit weird -- is not an array index even though it's an integer.
-#define MAX_ARRAY_INDEX 0xFFFFFFFEU
-
-// The value BASE_VECTOR_LEN is the maximum number of vector elements we'll allocate
-// for an array that was created with a sepcified length (e.g. a = new Array(123))
-#define BASE_VECTOR_LEN 4U
-    
-// The upper bound to the size we'll grow a zero length array when the first element
-// is added.
-#define FIRST_VECTOR_GROW 4U
-
-// Our policy for when to use a vector and when to use a sparse map.
-// For all array indices under MIN_SPARSE_ARRAY_INDEX, we always use a vector.
-// When indices greater than MIN_SPARSE_ARRAY_INDEX are involved, we use a vector
-// as long as it is 1/8 full. If more sparse than that, we use a map.
-static const unsigned minDensityMultiplier = 8;
-
 const ClassInfo JSArray::s_info = {"Array", &JSNonFinalObject::s_info, 0, 0, CREATE_METHOD_TABLE(JSArray)};
 
-// We keep track of the size of the last array after it was grown.  We use this
-// as a simple heuristic for as the value to grow the next array from size 0.
-// This value is capped by the constant FIRST_VECTOR_GROW defined above.
-static unsigned lastArraySize = 0;
-
-static inline bool isDenseEnoughForVector(unsigned length, unsigned numValues)
-{
-    return length <= MIN_SPARSE_ARRAY_INDEX || length / minDensityMultiplier <= numValues;
-}
-
-static bool reject(ExecState* exec, bool throwException, const char* message)
-{
-    if (throwException)
-        throwTypeError(exec, ASCIILiteral(message));
-    return false;
-}
-
-#if !CHECK_ARRAY_CONSISTENCY
-
-inline void JSArray::checkConsistency(ConsistencyCheckType)
-{
-}
-
-#endif
-
-void JSArray::finishCreation(JSGlobalData& globalData, unsigned initialLength)
-{
-    Base::finishCreation(globalData);
-    ASSERT(inherits(&s_info));
-
-    unsigned initialVectorLength = BASE_VECTOR_LEN;
-    unsigned initialStorageSize = storageSize(initialVectorLength);
-
-    void* newStorage = 0;
-    if (!globalData.heap.tryAllocateStorage(initialStorageSize, &newStorage))
-        CRASH();
-    
-    m_storage = static_cast<ArrayStorage*>(newStorage);
-    m_storage->m_allocBase = m_storage;
-    m_storage->m_length = initialLength;
-    m_vectorLength = initialVectorLength;
-    m_storage->m_numValuesInVector = 0;
-#if CHECK_ARRAY_CONSISTENCY
-    m_storage->m_inCompactInitialization = false;
-#endif
-
-    checkConsistency();
-}
-
-JSArray* JSArray::tryFinishCreationUninitialized(JSGlobalData& globalData, unsigned initialLength)
+Butterfly* createArrayButterflyInDictionaryIndexingMode(JSGlobalData& globalData, unsigned initialLength)
 {
-    Base::finishCreation(globalData);
-    ASSERT(inherits(&s_info));
-
-    // Check for lengths larger than we can handle with a vector.
-    if (initialLength > MAX_STORAGE_VECTOR_LENGTH)
-        return 0;
-
-    unsigned initialVectorLength = max(initialLength, BASE_VECTOR_LEN);
-    unsigned initialStorageSize = storageSize(initialVectorLength);
-
-    void* newStorage = 0;
-    if (!globalData.heap.tryAllocateStorage(initialStorageSize, &newStorage))
-        CRASH();
-    
-    m_storage = static_cast<ArrayStorage*>(newStorage);
-    m_storage->m_allocBase = m_storage;
-    m_storage->m_length = initialLength;
-    m_vectorLength = initialVectorLength;
-    m_storage->m_numValuesInVector = initialLength;
-
+    Butterfly* butterfly = Butterfly::create(
+        globalData, 0, 0, true, IndexingHeader(), ArrayStorage::sizeFor(0));
+    ArrayStorage* storage = butterfly->arrayStorage();
+    storage->setLength(initialLength);
+    storage->setVectorLength(0);
+    storage->m_indexBias = 0;
+    storage->m_sparseMap.clear();
+    storage->m_numValuesInVector = 0;
 #if CHECK_ARRAY_CONSISTENCY
-    m_storage->m_initializationIndex = 0;
-    m_storage->m_inCompactInitialization = true;
+    storage->m_initializationIndex = 0;
+    storage->m_inCompactInitialization = 0;
 #endif
-
-    return this;
-}
-
-// This function can be called multiple times on the same object.
-void JSArray::finalize(JSCell* cell)
-{
-    JSArray* thisObject = jsCast<JSArray*>(cell);
-    thisObject->checkConsistency(DestructorConsistencyCheck);
-    thisObject->deallocateSparseMap();
-}
-
-inline SparseArrayValueMap::AddResult SparseArrayValueMap::add(JSArray* array, unsigned i)
-{
-    SparseArrayEntry entry;
-    entry.setWithoutWriteBarrier(jsUndefined());
-
-    AddResult result = m_map.add(i, entry);
-    size_t capacity = m_map.capacity();
-    if (capacity != m_reportedCapacity) {
-        Heap::heap(array)->reportExtraMemoryCost((capacity - m_reportedCapacity) * (sizeof(unsigned) + sizeof(WriteBarrier<Unknown>)));
-        m_reportedCapacity = capacity;
-    }
-    return result;
-}
-
-inline void SparseArrayValueMap::put(ExecState* exec, JSArray* array, unsigned i, JSValue value, bool shouldThrow)
-{
-    AddResult result = add(array, i);
-    SparseArrayEntry& entry = result.iterator->second;
-
-    // To save a separate find & add, we first always add to the sparse map.
-    // In the uncommon case that this is a new property, and the array is not
-    // extensible, this is not the right thing to have done - so remove again.
-    if (result.isNewEntry && !array->isExtensible()) {
-        remove(result.iterator);
-        if (shouldThrow)
-            throwTypeError(exec, ASCIILiteral(StrictModeReadonlyPropertyWriteError));
-        return;
-    }
-
-    if (!(entry.attributes & Accessor)) {
-        if (entry.attributes & ReadOnly) {
-            if (shouldThrow)
-                throwTypeError(exec, ASCIILiteral(StrictModeReadonlyPropertyWriteError));
-            return;
-        }
-
-        entry.set(exec->globalData(), array, value);
-        return;
-    }
-
-    JSValue accessor = entry.Base::get();
-    ASSERT(accessor.isGetterSetter());
-    JSObject* setter = asGetterSetter(accessor)->setter();
-    
-    if (!setter) {
-        if (shouldThrow)
-            throwTypeError(exec, ASCIILiteral(StrictModeReadonlyPropertyWriteError));
-        return;
-    }
-
-    CallData callData;
-    CallType callType = setter->methodTable()->getCallData(setter, callData);
-    MarkedArgumentBuffer args;
-    args.append(value);
-    call(exec, setter, callType, callData, array, args);
-}
-
-inline bool SparseArrayValueMap::putDirect(ExecState* exec, JSArray* array, unsigned i, JSValue value, PutDirectIndexMode mode)
-{
-    AddResult result = add(array, i);
-    SparseArrayEntry& entry = result.iterator->second;
-
-    // To save a separate find & add, we first always add to the sparse map.
-    // In the uncommon case that this is a new property, and the array is not
-    // extensible, this is not the right thing to have done - so remove again.
-    if (mode != PutDirectIndexLikePutDirect && result.isNewEntry && !array->isExtensible()) {
-        remove(result.iterator);
-        return reject(exec, mode == PutDirectIndexShouldThrow, "Attempting to define property on object that is not extensible.");
-    }
-
-    entry.attributes = 0;
-    entry.set(exec->globalData(), array, value);
-    return true;
-}
-
-inline void SparseArrayEntry::get(PropertySlot& slot) const
-{
-    JSValue value = Base::get();
-    ASSERT(value);
-
-    if (LIKELY(!value.isGetterSetter())) {
-        slot.setValue(value);
-        return;
-    }
-
-    JSObject* getter = asGetterSetter(value)->getter();
-    if (!getter) {
-        slot.setUndefined();
-        return;
-    }
-
-    slot.setGetterSlot(getter);
-}
-
-inline void SparseArrayEntry::get(PropertyDescriptor& descriptor) const
-{
-    descriptor.setDescriptor(Base::get(), attributes);
-}
-
-inline JSValue SparseArrayEntry::get(ExecState* exec, JSArray* array) const
-{
-    JSValue result = Base::get();
-    ASSERT(result);
-
-    if (LIKELY(!result.isGetterSetter()))
-        return result;
-
-    JSObject* getter = asGetterSetter(result)->getter();
-    if (!getter)
-        return jsUndefined();
-
-    CallData callData;
-    CallType callType = getter->methodTable()->getCallData(getter, callData);
-    return call(exec, getter, callType, callData, array, exec->emptyList());
-}
-
-inline JSValue SparseArrayEntry::getNonSparseMode() const
-{
-    ASSERT(!attributes);
-    return Base::get();
-}
-
-inline void SparseArrayValueMap::visitChildren(SlotVisitor& visitor)
-{
-    iterator end = m_map.end();
-    for (iterator it = m_map.begin(); it != end; ++it)
-        visitor.append(&it->second);
-}
-
-void JSArray::allocateSparseMap(JSGlobalData& globalData)
-{
-    m_sparseValueMap = new SparseArrayValueMap;
-    globalData.heap.addFinalizer(this, finalize);
-}
-
-void JSArray::deallocateSparseMap()
-{
-    delete m_sparseValueMap;
-    m_sparseValueMap = 0;
-}
-
-void JSArray::enterDictionaryMode(JSGlobalData& globalData)
-{
-    ArrayStorage* storage = m_storage;
-    SparseArrayValueMap* map = m_sparseValueMap;
-
-    if (!map) {
-        allocateSparseMap(globalData);
-        map = m_sparseValueMap;
-    }
-
-    if (map->sparseMode())
-        return;
-
-    map->setSparseMode();
-
-    unsigned usedVectorLength = min(storage->m_length, m_vectorLength);
-    for (unsigned i = 0; i < usedVectorLength; ++i) {
-        JSValue value = storage->m_vector[i].get();
-        // 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);
-    }
-
-    void* newRawStorage = 0;
-    if (!globalData.heap.tryAllocateStorage(storageSize(0), &newRawStorage))
-        CRASH();
-    
-    ArrayStorage* newStorage = static_cast<ArrayStorage*>(newRawStorage);
-    memcpy(newStorage, m_storage, storageSize(0));
-    newStorage->m_allocBase = newStorage;
-    m_storage = newStorage;
-    m_indexBias = 0;
-    m_vectorLength = 0;
-}
-
-void JSArray::putDescriptor(ExecState* exec, SparseArrayEntry* entryInMap, PropertyDescriptor& descriptor, PropertyDescriptor& oldDescriptor)
-{
-    if (descriptor.isDataDescriptor()) {
-        if (descriptor.value())
-            entryInMap->set(exec->globalData(), this, descriptor.value());
-        else if (oldDescriptor.isAccessorDescriptor())
-            entryInMap->set(exec->globalData(), this, jsUndefined());
-        entryInMap->attributes = descriptor.attributesOverridingCurrent(oldDescriptor) & ~Accessor;
-        return;
-    }
-
-    if (descriptor.isAccessorDescriptor()) {
-        JSObject* getter = 0;
-        if (descriptor.getterPresent())
-            getter = descriptor.getterObject();
-        else if (oldDescriptor.isAccessorDescriptor())
-            getter = oldDescriptor.getterObject();
-        JSObject* setter = 0;
-        if (descriptor.setterPresent())
-            setter = descriptor.setterObject();
-        else if (oldDescriptor.isAccessorDescriptor())
-            setter = oldDescriptor.setterObject();
-
-        GetterSetter* accessor = GetterSetter::create(exec);
-        if (getter)
-            accessor->setGetter(exec->globalData(), getter);
-        if (setter)
-            accessor->setSetter(exec->globalData(), setter);
-
-        entryInMap->set(exec->globalData(), this, accessor);
-        entryInMap->attributes = descriptor.attributesOverridingCurrent(oldDescriptor) & ~ReadOnly;
-        return;
-    }
-
-    ASSERT(descriptor.isGenericDescriptor());
-    entryInMap->attributes = descriptor.attributesOverridingCurrent(oldDescriptor);
-}
-
-// Defined in ES5.1 8.12.9
-bool JSArray::defineOwnNumericProperty(ExecState* exec, unsigned index, PropertyDescriptor& descriptor, bool throwException)
-{
-    ASSERT(index != 0xFFFFFFFF);
-
-    if (!inSparseMode()) {
-        // 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
-        // – however if the property currently exists missing attributes will override from their current 'true'
-        // state (i.e. defineOwnProperty could be used to set a value without needing to entering 'SparseMode').
-        if (!descriptor.attributes()) {
-            ASSERT(!descriptor.isAccessorDescriptor());
-            return putDirectIndex(exec, index, descriptor.value(), throwException ? PutDirectIndexShouldThrow : PutDirectIndexShouldNotThrow);
-        }
-
-        enterDictionaryMode(exec->globalData());
-    }
-
-    SparseArrayValueMap* map = m_sparseValueMap;
-    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;
-
-    // 2. Let extensible be the value of the [[Extensible]] internal property of O.
-    // 3. If current is undefined and extensible is false, then Reject.
-    // 4. If current is undefined and extensible is true, then
-    if (result.isNewEntry) {
-        if (!isExtensible()) {
-            map->remove(result.iterator);
-            return reject(exec, throwException, "Attempting to define property on object that is not extensible.");
-        }
-
-        // 4.a. If IsGenericDescriptor(Desc) or IsDataDescriptor(Desc) is true, then create an own data property
-        // named P of object O whose [[Value]], [[Writable]], [[Enumerable]] and [[Configurable]] attribute values
-        // are described by Desc. If the value of an attribute field of Desc is absent, the attribute of the newly
-        // created property is set to its default value.
-        // 4.b. Else, Desc must be an accessor Property Descriptor so, create an own accessor property named P of
-        // object O whose [[Get]], [[Set]], [[Enumerable]] and [[Configurable]] attribute values are described by
-        // Desc. If the value of an attribute field of Desc is absent, the attribute of the newly created property
-        // is set to its default value.
-        // 4.c. Return true.
-
-        PropertyDescriptor defaults;
-        entryInMap->setWithoutWriteBarrier(jsUndefined());
-        entryInMap->attributes = DontDelete | DontEnum | ReadOnly;
-        entryInMap->get(defaults);
-
-        putDescriptor(exec, entryInMap, descriptor, defaults);
-        if (index >= m_storage->m_length)
-            m_storage->m_length = index + 1;
-        return true;
-    }
-
-    // 5. Return true, if every field in Desc is absent.
-    // 6. Return true, if every field in Desc also occurs in current and the value of every field in Desc is the same value as the corresponding field in current when compared using the SameValue algorithm (9.12).
-    PropertyDescriptor current;
-    entryInMap->get(current);
-    if (descriptor.isEmpty() || descriptor.equalTo(exec, current))
-        return true;
-
-    // 7. If the [[Configurable]] field of current is false then
-    if (!current.configurable()) {
-        // 7.a. Reject, if the [[Configurable]] field of Desc is true.
-        if (descriptor.configurablePresent() && descriptor.configurable())
-            return reject(exec, throwException, "Attempting to change configurable attribute of unconfigurable property.");
-        // 7.b. Reject, if the [[Enumerable]] field of Desc is present and the [[Enumerable]] fields of current and Desc are the Boolean negation of each other.
-        if (descriptor.enumerablePresent() && current.enumerable() != descriptor.enumerable())
-            return reject(exec, throwException, "Attempting to change enumerable attribute of unconfigurable property.");
-    }
-
-    // 8. If IsGenericDescriptor(Desc) is true, then no further validation is required.
-    if (!descriptor.isGenericDescriptor()) {
-        // 9. Else, if IsDataDescriptor(current) and IsDataDescriptor(Desc) have different results, then
-        if (current.isDataDescriptor() != descriptor.isDataDescriptor()) {
-            // 9.a. Reject, if the [[Configurable]] field of current is false.
-            if (!current.configurable())
-                return reject(exec, throwException, "Attempting to change access mechanism for an unconfigurable property.");
-            // 9.b. If IsDataDescriptor(current) is true, then convert the property named P of object O from a
-            // data property to an accessor property. Preserve the existing values of the converted property‘s
-            // [[Configurable]] and [[Enumerable]] attributes and set the rest of the property‘s attributes to
-            // their default values.
-            // 9.c. Else, convert the property named P of object O from an accessor property to a data property.
-            // Preserve the existing values of the converted property‘s [[Configurable]] and [[Enumerable]]
-            // attributes and set the rest of the property‘s attributes to their default values.
-        } else if (current.isDataDescriptor() && descriptor.isDataDescriptor()) {
-            // 10. Else, if IsDataDescriptor(current) and IsDataDescriptor(Desc) are both true, then
-            // 10.a. If the [[Configurable]] field of current is false, then
-            if (!current.configurable() && !current.writable()) {
-                // 10.a.i. Reject, if the [[Writable]] field of current is false and the [[Writable]] field of Desc is true.
-                if (descriptor.writable())
-                    return reject(exec, throwException, "Attempting to change writable attribute of unconfigurable property.");
-                // 10.a.ii. If the [[Writable]] field of current is false, then
-                // 10.a.ii.1. Reject, if the [[Value]] field of Desc is present and SameValue(Desc.[[Value]], current.[[Value]]) is false.
-                if (descriptor.value() && !sameValue(exec, descriptor.value(), current.value()))
-                    return reject(exec, throwException, "Attempting to change value of a readonly property.");
-            }
-            // 10.b. else, the [[Configurable]] field of current is true, so any change is acceptable.
-        } else {
-            ASSERT(current.isAccessorDescriptor() && current.getterPresent() && current.setterPresent());
-            // 11. Else, IsAccessorDescriptor(current) and IsAccessorDescriptor(Desc) are both true so, if the [[Configurable]] field of current is false, then
-            if (!current.configurable()) {
-                // 11.i. Reject, if the [[Set]] field of Desc is present and SameValue(Desc.[[Set]], current.[[Set]]) is false.
-                if (descriptor.setterPresent() && descriptor.setter() != current.setter())
-                    return reject(exec, throwException, "Attempting to change the setter of an unconfigurable property.");
-                // 11.ii. Reject, if the [[Get]] field of Desc is present and SameValue(Desc.[[Get]], current.[[Get]]) is false.
-                if (descriptor.getterPresent() && descriptor.getter() != current.getter())
-                    return reject(exec, throwException, "Attempting to change the getter of an unconfigurable property.");
-            }
-        }
-    }
-
-    // 12. For each attribute field of Desc that is present, set the correspondingly named attribute of the property named P of object O to the value of the field.
-    putDescriptor(exec, entryInMap, descriptor, current);
-    // 13. Return true.
-    return true;
+    return butterfly;
 }
 
 void JSArray::setLengthWritable(ExecState* exec, bool writable)
@@ -527,9 +74,9 @@ void JSArray::setLengthWritable(ExecState* exec, bool writable)
     if (!isLengthWritable() || writable)
         return;
 
-    enterDictionaryMode(exec->globalData());
+    enterDictionaryIndexingMode(exec->globalData());
 
-    SparseArrayValueMap* map = m_sparseValueMap;
+    SparseArrayValueMap* map = arrayStorage()->m_sparseMap.get();
     ASSERT(map);
     map->setLengthIsReadOnly();
 }
@@ -630,38 +177,10 @@ bool JSArray::defineOwnProperty(JSObject* object, ExecState* exec, PropertyName
         // e.i. Set oldLenDesc.[[Value]] to index + 1.
         // e.ii. Call the default [[DefineOwnProperty]] internal method (8.12.9) on A passing "length", oldLenDesc, and false as arguments. This call will always return true.
         // f. Return true.
-        return array->defineOwnNumericProperty(exec, index, descriptor, throwException);
-    }
-
-    return JSObject::defineOwnProperty(object, exec, propertyName, descriptor, throwException);
-}
-
-bool JSArray::getOwnPropertySlotByIndex(JSCell* cell, ExecState* exec, unsigned i, PropertySlot& slot)
-{
-    JSArray* thisObject = jsCast<JSArray*>(cell);
-    ArrayStorage* storage = thisObject->m_storage;
-
-    if (i >= storage->m_length) {
-        if (i > MAX_ARRAY_INDEX)
-            return thisObject->methodTable()->getOwnPropertySlot(thisObject, exec, Identifier::from(exec, i), slot);
-        return false;
+        return array->defineOwnIndexedProperty(exec, index, descriptor, throwException);
     }
 
-    if (i < thisObject->m_vectorLength) {
-        JSValue value = storage->m_vector[i].get();
-        if (value) {
-            slot.setValue(value);
-            return true;
-        }
-    } else if (SparseArrayValueMap* map = thisObject->m_sparseValueMap) {
-        SparseArrayValueMap::iterator it = map->find(i);
-        if (it != map->notFound()) {
-            it->second.get(slot);
-            return true;
-        }
-    }
-
-    return JSObject::getOwnPropertySlot(thisObject, exec, Identifier::from(exec, i), slot);
+    return array->JSObject::defineOwnNonIndexProperty(exec, propertyName, descriptor, throwException);
 }
 
 bool JSArray::getOwnPropertySlot(JSCell* cell, ExecState* exec, PropertyName propertyName, PropertySlot& slot)
@@ -672,10 +191,6 @@ bool JSArray::getOwnPropertySlot(JSCell* cell, ExecState* exec, PropertyName pro
         return true;
     }
 
-    unsigned i = propertyName.asIndex();
-    if (i != PropertyName::NotAnIndex)
-        return JSArray::getOwnPropertySlotByIndex(thisObject, exec, i, slot);
-
     return JSObject::getOwnPropertySlot(thisObject, exec, propertyName, slot);
 }
 
@@ -687,26 +202,6 @@ bool JSArray::getOwnPropertyDescriptor(JSObject* object, ExecState* exec, Proper
         return true;
     }
 
-    ArrayStorage* storage = thisObject->m_storage;
-    
-    unsigned i = propertyName.asIndex();
-    if (i != PropertyName::NotAnIndex) {
-        if (i >= storage->m_length)
-            return false;
-        if (i < thisObject->m_vectorLength) {
-            WriteBarrier<Unknown>& value = storage->m_vector[i];
-            if (value) {
-                descriptor.setDescriptor(value.get(), 0);
-                return true;
-            }
-        } else if (SparseArrayValueMap* map = thisObject->m_sparseValueMap) {
-            SparseArrayValueMap::iterator it = map->find(i);
-            if (it != map->notFound()) {
-                it->second.get(descriptor);
-                return true;
-            }
-        }
-    }
     return JSObject::getOwnPropertyDescriptor(thisObject, exec, propertyName, descriptor);
 }
 
@@ -714,11 +209,6 @@ bool JSArray::getOwnPropertyDescriptor(JSObject* object, ExecState* exec, Proper
 void JSArray::put(JSCell* cell, ExecState* exec, PropertyName propertyName, JSValue value, PutPropertySlot& slot)
 {
     JSArray* thisObject = jsCast<JSArray*>(cell);
-    unsigned i = propertyName.asIndex();
-    if (i != PropertyName::NotAnIndex) {
-        putByIndex(thisObject, exec, i, value, slot.isStrictMode());
-        return;
-    }
 
     if (propertyName == exec->propertyNames().length) {
         unsigned newLength = value.toUInt32(exec);
@@ -733,196 +223,9 @@ void JSArray::put(JSCell* cell, ExecState* exec, PropertyName propertyName, JSVa
     JSObject::put(thisObject, exec, propertyName, value, slot);
 }
 
-void JSArray::putByIndex(JSCell* cell, ExecState* exec, unsigned i, JSValue value, bool shouldThrow)
-{
-    JSArray* thisObject = jsCast<JSArray*>(cell);
-    thisObject->checkConsistency();
-
-    ArrayStorage* storage = thisObject->m_storage;
-
-    // Fast case - store to the vector.
-    if (i < thisObject->m_vectorLength) {
-        WriteBarrier<Unknown>& valueSlot = storage->m_vector[i];
-        unsigned length = storage->m_length;
-
-        // Update m_length & m_numValuesInVector as necessary.
-        if (i >= length) {
-            length = i + 1;
-            storage->m_length = length;
-            ++storage->m_numValuesInVector;
-        } else if (!valueSlot)
-            ++storage->m_numValuesInVector;
-
-        valueSlot.set(exec->globalData(), thisObject, value);
-        thisObject->checkConsistency();
-        return;
-    }
-
-    // Handle 2^32-1 - this is not an array index (see ES5.1 15.4), and is treated as a regular property.
-    if (UNLIKELY(i > MAX_ARRAY_INDEX)) {
-        PutPropertySlot slot(shouldThrow);
-        thisObject->methodTable()->put(thisObject, exec, Identifier::from(exec, i), value, slot);
-        return;
-    }
-
-    // For all other cases, call putByIndexBeyondVectorLength.
-    thisObject->putByIndexBeyondVectorLength(exec, i, value, shouldThrow);
-    thisObject->checkConsistency();
-}
-
-void JSArray::putByIndexBeyondVectorLength(ExecState* exec, unsigned i, JSValue value, bool shouldThrow)
-{
-    JSGlobalData& globalData = exec->globalData();
-
-    // i should be a valid array index that is outside of the current vector.
-    ASSERT(i >= m_vectorLength);
-    ASSERT(i <= MAX_ARRAY_INDEX);
-
-    ArrayStorage* storage = m_storage;
-    SparseArrayValueMap* map = m_sparseValueMap;
-
-    // First, handle cases where we don't currently have a sparse map.
-    if (LIKELY(!map)) {
-        // If the array is not extensible, we should have entered dictionary mode, and created the spare map.
-        ASSERT(isExtensible());
-    
-        // Update m_length if necessary.
-        if (i >= storage->m_length)
-            storage->m_length = i + 1;
-
-        // Check that it is sensible to still be using a vector, and then try to grow the vector.
-        if (LIKELY((isDenseEnoughForVector(i, storage->m_numValuesInVector)) && increaseVectorLength(globalData, i + 1))) {
-            // success! - reread m_storage since it has likely been reallocated, and store to the vector.
-            storage = m_storage;
-            storage->m_vector[i].set(globalData, this, value);
-            ++storage->m_numValuesInVector;
-            return;
-        }
-        // We don't want to, or can't use a vector to hold this property - allocate a sparse map & add the value.
-        allocateSparseMap(exec->globalData());
-        map = m_sparseValueMap;
-        map->put(exec, this, i, value, shouldThrow);
-        return;
-    }
-
-    // Update m_length if necessary.
-    unsigned length = storage->m_length;
-    if (i >= length) {
-        // Prohibit growing the array if length is not writable.
-        if (map->lengthIsReadOnly() || !isExtensible()) {
-            if (shouldThrow)
-                throwTypeError(exec, ASCIILiteral(StrictModeReadonlyPropertyWriteError));
-            return;
-        }
-        length = i + 1;
-        storage->m_length = length;
-    }
-
-    // We are currently using a map - check whether we still want to be doing so.
-    // We will continue  to use a sparse map if SparseMode is set, a vector would be too sparse, or if allocation fails.
-    unsigned numValuesInArray = storage->m_numValuesInVector + map->size();
-    if (map->sparseMode() || !isDenseEnoughForVector(length, numValuesInArray) || !increaseVectorLength(exec->globalData(), length)) {
-        map->put(exec, this, i, value, shouldThrow);
-        return;
-    }
-
-    // Reread m_storage afterincreaseVectorLength, update m_numValuesInVector.
-    storage = m_storage;
-    storage->m_numValuesInVector = numValuesInArray;
-
-    // Copy all values from the map into the vector, and delete the map.
-    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());
-    deallocateSparseMap();
-
-    // Store the new property into the vector.
-    WriteBarrier<Unknown>& valueSlot = vector[i];
-    if (!valueSlot)
-        ++storage->m_numValuesInVector;
-    valueSlot.set(globalData, this, value);
-}
-
-bool JSArray::putDirectIndexBeyondVectorLength(ExecState* exec, unsigned i, JSValue value, PutDirectIndexMode mode)
-{
-    JSGlobalData& globalData = exec->globalData();
-
-    // i should be a valid array index that is outside of the current vector.
-    ASSERT(i >= m_vectorLength);
-    ASSERT(i <= MAX_ARRAY_INDEX);
-
-    ArrayStorage* storage = m_storage;
-    SparseArrayValueMap* map = m_sparseValueMap;
-
-    // First, handle cases where we don't currently have a sparse map.
-    if (LIKELY(!map)) {
-        // If the array is not extensible, we should have entered dictionary mode, and created the spare map.
-        ASSERT(isExtensible());
-    
-        // Update m_length if necessary.
-        if (i >= storage->m_length)
-            storage->m_length = i + 1;
-
-        // Check that it is sensible to still be using a vector, and then try to grow the vector.
-        if (LIKELY((isDenseEnoughForVector(i, storage->m_numValuesInVector)) && increaseVectorLength(globalData, i + 1))) {
-            // success! - reread m_storage since it has likely been reallocated, and store to the vector.
-            storage = m_storage;
-            storage->m_vector[i].set(globalData, this, value);
-            ++storage->m_numValuesInVector;
-            return true;
-        }
-        // We don't want to, or can't use a vector to hold this property - allocate a sparse map & add the value.
-        allocateSparseMap(exec->globalData());
-        map = m_sparseValueMap;
-        return map->putDirect(exec, this, i, value, mode);
-    }
-
-    // Update m_length if necessary.
-    unsigned length = storage->m_length;
-    if (i >= length) {
-        // Prohibit growing the array if length is not writable.
-        if (mode != PutDirectIndexLikePutDirect) {
-            if (map->lengthIsReadOnly())
-                return reject(exec, mode == PutDirectIndexShouldThrow, StrictModeReadonlyPropertyWriteError);
-            if (!isExtensible())
-                return reject(exec, mode == PutDirectIndexShouldThrow, "Attempting to define property on object that is not extensible.");
-        }
-        length = i + 1;
-        storage->m_length = length;
-    }
-
-    // We are currently using a map - check whether we still want to be doing so.
-    // We will continue  to use a sparse map if SparseMode is set, a vector would be too sparse, or if allocation fails.
-    unsigned numValuesInArray = storage->m_numValuesInVector + map->size();
-    if (map->sparseMode() || !isDenseEnoughForVector(length, numValuesInArray) || !increaseVectorLength(exec->globalData(), length))
-        return map->putDirect(exec, this, i, value, mode);
-
-    // Reread m_storage afterincreaseVectorLength, update m_numValuesInVector.
-    storage = m_storage;
-    storage->m_numValuesInVector = numValuesInArray;
-
-    // Copy all values from the map into the vector, and delete the map.
-    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());
-    deallocateSparseMap();
-
-    // Store the new property into the vector.
-    WriteBarrier<Unknown>& valueSlot = vector[i];
-    if (!valueSlot)
-        ++storage->m_numValuesInVector;
-    valueSlot.set(globalData, this, value);
-    return true;
-}
-
 bool JSArray::deleteProperty(JSCell* cell, ExecState* exec, PropertyName propertyName)
 {
     JSArray* thisObject = jsCast<JSArray*>(cell);
-    unsigned i = propertyName.asIndex();
-    if (i != PropertyName::NotAnIndex)
-        return thisObject->methodTable()->deletePropertyByIndex(thisObject, exec, i);
 
     if (propertyName == exec->propertyNames().length)
         return false;
@@ -930,35 +233,6 @@ bool JSArray::deleteProperty(JSCell* cell, ExecState* exec, PropertyName propert
     return JSObject::deleteProperty(thisObject, exec, propertyName);
 }
 
-bool JSArray::deletePropertyByIndex(JSCell* cell, ExecState* exec, unsigned i)
-{
-    JSArray* thisObject = jsCast<JSArray*>(cell);
-    thisObject->checkConsistency();
-
-    if (i > MAX_ARRAY_INDEX)
-        return thisObject->methodTable()->deleteProperty(thisObject, exec, Identifier::from(exec, i));
-
-    ArrayStorage* storage = thisObject->m_storage;
-    
-    if (i < thisObject->m_vectorLength) {
-        WriteBarrier<Unknown>& valueSlot = storage->m_vector[i];
-        if (valueSlot) {
-            valueSlot.clear();
-            --storage->m_numValuesInVector;
-        }
-    } else if (SparseArrayValueMap* map = thisObject->m_sparseValueMap) {
-        SparseArrayValueMap::iterator it = map->find(i);
-        if (it != map->notFound()) {
-            if (it->second.attributes & DontDelete)
-                return false;
-            map->remove(it);
-        }
-    }
-
-    thisObject->checkConsistency();
-    return true;
-}
-
 static int compareKeysForQSort(const void* a, const void* b)
 {
     unsigned da = *static_cast<const unsigned*>(a);
@@ -966,127 +240,26 @@ static int compareKeysForQSort(const void* a, const void* b)
     return (da > db) - (da < db);
 }
 
-void JSArray::getOwnPropertyNames(JSObject* object, ExecState* exec, PropertyNameArray& propertyNames, EnumerationMode mode)
+void JSArray::getOwnNonIndexPropertyNames(JSObject* object, ExecState* exec, PropertyNameArray& propertyNames, EnumerationMode mode)
 {
     JSArray* thisObject = jsCast<JSArray*>(object);
-    // FIXME: Filling PropertyNameArray with an identifier for every integer
-    // is incredibly inefficient for large arrays. We need a different approach,
-    // which almost certainly means a different structure for PropertyNameArray.
-
-    ArrayStorage* storage = thisObject->m_storage;
-    
-    unsigned usedVectorLength = min(storage->m_length, thisObject->m_vectorLength);
-    for (unsigned i = 0; i < usedVectorLength; ++i) {
-        if (storage->m_vector[i])
-            propertyNames.add(Identifier::from(exec, i));
-    }
-
-    if (SparseArrayValueMap* map = thisObject->m_sparseValueMap) {
-        Vector<unsigned> keys;
-        keys.reserveCapacity(map->size());
-        
-        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));
-        }
-
-        qsort(keys.begin(), keys.size(), sizeof(unsigned), compareKeysForQSort);
-        for (unsigned i = 0; i < keys.size(); ++i)
-            propertyNames.add(Identifier::from(exec, keys[i]));
-    }
 
     if (mode == IncludeDontEnumProperties)
         propertyNames.add(exec->propertyNames().length);
 
-    JSObject::getOwnPropertyNames(thisObject, exec, propertyNames, mode);
-}
-
-ALWAYS_INLINE unsigned JSArray::getNewVectorLength(unsigned desiredLength)
-{
-    ASSERT(desiredLength <= MAX_STORAGE_VECTOR_LENGTH);
-
-    unsigned increasedLength;
-    unsigned maxInitLength = min(m_storage->m_length, 100000U);
-
-    if (desiredLength < maxInitLength)
-        increasedLength = maxInitLength;
-    else if (!m_vectorLength)
-        increasedLength = 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);
-    }
-
-    ASSERT(increasedLength >= desiredLength);
-
-    lastArraySize = min(increasedLength, FIRST_VECTOR_GROW);
-
-    return min(increasedLength, MAX_STORAGE_VECTOR_LENGTH);
-}
-
-bool JSArray::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
-    // to the vector. Callers have to account for that, because they can do it more efficiently.
-    if (newLength > MAX_STORAGE_VECTOR_LENGTH)
-        return false;
-
-    ArrayStorage* storage = m_storage;
-
-    unsigned vectorLength = m_vectorLength;
-    ASSERT(newLength > vectorLength);
-    unsigned newVectorLength = getNewVectorLength(newLength);
-
-    // Fast case - there is no precapacity. In these cases a realloc makes sense.
-    if (LIKELY(!m_indexBias)) {
-        void* newStorage = storage->m_allocBase;
-        if (!globalData.heap.tryReallocateStorage(&newStorage, storageSize(vectorLength), storageSize(newVectorLength)))
-            return false;
-
-        storage = m_storage = reinterpret_cast_ptr<ArrayStorage*>(static_cast<char*>(newStorage));
-        m_storage->m_allocBase = newStorage;
-        ASSERT(m_storage->m_allocBase);
-
-        m_vectorLength = newVectorLength;
-        
-        return true;
-    }
-
-    // Remove some, but not all of the precapacity. Atomic decay, & capped to not overflow array length.
-    unsigned newIndexBias = min(m_indexBias >> 1, MAX_STORAGE_VECTOR_LENGTH - newVectorLength);
-    // Calculate new stoarge capcity, allowing room for the pre-capacity.
-    unsigned newStorageCapacity = newVectorLength + newIndexBias;
-    void* newAllocBase = 0;
-    if (!globalData.heap.tryAllocateStorage(storageSize(newStorageCapacity), &newAllocBase))    
-        return false;
-    // The sum of m_vectorLength and m_indexBias will never exceed MAX_STORAGE_VECTOR_LENGTH.
-    ASSERT(m_vectorLength <= MAX_STORAGE_VECTOR_LENGTH && (MAX_STORAGE_VECTOR_LENGTH - m_vectorLength) >= m_indexBias);
-
-    m_vectorLength = newVectorLength;
-    m_indexBias = newIndexBias;
-    m_storage = reinterpret_cast_ptr<ArrayStorage*>(reinterpret_cast<WriteBarrier<Unknown>*>(newAllocBase) + m_indexBias);
-
-    // Copy the ArrayStorage header & current contents of the vector.
-    memmove(m_storage, storage, storageSize(vectorLength));
-
-    // Free the old allocation, update m_allocBase.
-    m_storage->m_allocBase = newAllocBase;
-
-    return true;
+    JSObject::getOwnNonIndexPropertyNames(thisObject, exec, propertyNames, mode);
 }
 
 // This method makes room in the vector, but leaves the new space uncleared.
 bool JSArray::unshiftCountSlowCase(JSGlobalData& globalData, unsigned count)
 {
-    // If not, we should have handled this on the fast path.
-    ASSERT(count > m_indexBias);
+    ArrayStorage* storage = ensureArrayStorage(globalData);
+    Butterfly* butterfly = storage->butterfly();
+    unsigned propertyCapacity = structure()->outOfLineCapacity();
+    unsigned propertySize = structure()->outOfLineSize();
 
-    ArrayStorage* storage = m_storage;
+    // If not, we should have handled this on the fast path.
+    ASSERT(count > storage->m_indexBias);
 
     // Step 1:
     // Gather 4 key metrics:
@@ -1095,8 +268,8 @@ bool JSArray::unshiftCountSlowCase(JSGlobalData& globalData, unsigned count)
     //  * currentCapacity - what is the current size of the vector, including any pre-capacity.
     //  * desiredCapacity - how large should we like to grow the vector to - based on 2x requiredVectorLength.
 
-    unsigned length = storage->m_length;
-    unsigned usedVectorLength = min(m_vectorLength, length);
+    unsigned length = storage->length();
+    unsigned usedVectorLength = min(storage->vectorLength(), length);
     ASSERT(usedVectorLength <= MAX_STORAGE_VECTOR_LENGTH);
     // Check that required vector length is possible, in an overflow-safe fashion.
     if (count > MAX_STORAGE_VECTOR_LENGTH - usedVectorLength)
@@ -1104,8 +277,8 @@ bool JSArray::unshiftCountSlowCase(JSGlobalData& globalData, unsigned count)
     unsigned requiredVectorLength = usedVectorLength + count;
     ASSERT(requiredVectorLength <= MAX_STORAGE_VECTOR_LENGTH);
     // The sum of m_vectorLength and m_indexBias will never exceed MAX_STORAGE_VECTOR_LENGTH.
-    ASSERT(m_vectorLength <= MAX_STORAGE_VECTOR_LENGTH && (MAX_STORAGE_VECTOR_LENGTH - m_vectorLength) >= m_indexBias);
-    unsigned currentCapacity = m_vectorLength + m_indexBias;
+    ASSERT(storage->vectorLength() <= MAX_STORAGE_VECTOR_LENGTH && (MAX_STORAGE_VECTOR_LENGTH - storage->vectorLength()) >= storage->m_indexBias);
+    unsigned currentCapacity = storage->vectorLength() + storage->m_indexBias;
     // The calculation of desiredCapacity won't overflow, due to the range of MAX_STORAGE_VECTOR_LENGTH.
     unsigned desiredCapacity = min(MAX_STORAGE_VECTOR_LENGTH, max(BASE_VECTOR_LEN, requiredVectorLength) << 1);
 
@@ -1116,10 +289,11 @@ bool JSArray::unshiftCountSlowCase(JSGlobalData& globalData, unsigned count)
     unsigned newStorageCapacity;
     // If the current storage array is sufficiently large (but not too large!) then just keep using it.
     if (currentCapacity > desiredCapacity && isDenseEnoughForVector(currentCapacity, requiredVectorLength)) {
-        newAllocBase = storage->m_allocBase;
+        newAllocBase = butterfly->base(structure());
         newStorageCapacity = currentCapacity;
     } else {
-        if (!globalData.heap.tryAllocateStorage(storageSize(desiredCapacity), &newAllocBase))
+        size_t newSize = Butterfly::totalSize(0, propertyCapacity, true, ArrayStorage::sizeFor(desiredCapacity));
+        if (!globalData.heap.tryAllocateStorage(newSize, &newAllocBase))
             return false;
         newStorageCapacity = desiredCapacity;
     }
@@ -1132,45 +306,40 @@ bool JSArray::unshiftCountSlowCase(JSGlobalData& globalData, unsigned count)
     // If it did, we calculate the amount that will remain based on an atomic decay - leave the
     // vector with half the post-capacity it had previously.
     unsigned postCapacity = 0;
-    if (length < m_vectorLength) {
+    if (length < storage->vectorLength()) {
         // Atomic decay, + the post-capacity cannot be greater than what is available.
-        postCapacity = min((m_vectorLength - length) >> 1, newStorageCapacity - requiredVectorLength);
-        // If we're moving contents within the same allocation, the post-capacity is being reduced.
-        ASSERT(newAllocBase != storage->m_allocBase || postCapacity < m_vectorLength - length);
-    }
-
-    m_vectorLength = requiredVectorLength + postCapacity;
-    m_indexBias = newStorageCapacity - m_vectorLength;
-    m_storage = reinterpret_cast_ptr<ArrayStorage*>(reinterpret_cast<WriteBarrier<Unknown>*>(newAllocBase) + m_indexBias);
-
-    // Step 4:
-    // Copy array data / header into their new locations, clear post-capacity & free any old allocation.
-
-    // If this is being moved within the existing buffer of memory, we are always shifting data
-    // to the right (since count > m_indexBias). As such this memmove cannot trample the header.
-    memmove(m_storage->m_vector + count, storage->m_vector, sizeof(WriteBarrier<Unknown>) * usedVectorLength);
-    memmove(m_storage, storage, storageSize(0));
-
-    // Are we copying into a new allocation?
-    if (newAllocBase != m_storage->m_allocBase) {
-        // Free the old allocation, update m_allocBase.
-        m_storage->m_allocBase = newAllocBase;
+        postCapacity = min((storage->vectorLength() - length) >> 1, newStorageCapacity - requiredVectorLength);
+        // If we're moving contents within the same allocation, the post-capacity is being reduced.
+        ASSERT(newAllocBase != butterfly->base(structure()) || postCapacity < storage->vectorLength() - length);
     }
+    
+    unsigned newVectorLength = requiredVectorLength + postCapacity;
+    unsigned newIndexBias = newStorageCapacity - newVectorLength;
+
+    Butterfly* newButterfly = Butterfly::fromBase(newAllocBase, newIndexBias, propertyCapacity);
+    
+    memmove(newButterfly->arrayStorage()->m_vector + count, storage->m_vector, sizeof(JSValue) * usedVectorLength);
+    memmove(newButterfly->propertyStorage() - propertySize, butterfly->propertyStorage() - propertySize, sizeof(JSValue) * propertySize + sizeof(IndexingHeader) + ArrayStorage::sizeFor(0));
+    
+    newButterfly->arrayStorage()->setVectorLength(newVectorLength);
+    newButterfly->arrayStorage()->m_indexBias = newIndexBias;
+    
+    m_butterfly = newButterfly;
 
     return true;
 }
 
 bool JSArray::setLength(ExecState* exec, unsigned newLength, bool throwException)
 {
-    checkConsistency();
+    checkIndexingConsistency();
 
-    ArrayStorage* storage = m_storage;
-    unsigned length = storage->m_length;
+    ArrayStorage* storage = ensureArrayStorage(exec->globalData());
+    unsigned length = storage->length();
 
     // If the length is read only then we enter sparse mode, so should enter the following 'if'.
-    ASSERT(isLengthWritable() || m_sparseValueMap);
+    ASSERT(isLengthWritable() || storage->m_sparseMap);
 
-    if (SparseArrayValueMap* map = m_sparseValueMap) {
+    if (SparseArrayValueMap* map = storage->m_sparseMap.get()) {
         // Fail if the length is not writable.
         if (map->lengthIsReadOnly())
             return reject(exec, throwException, StrictModeReadonlyPropertyWriteError);
@@ -1197,7 +366,7 @@ bool JSArray::setLength(ExecState* exec, unsigned newLength, bool throwException
                     SparseArrayValueMap::iterator it = map->find(index);
                     ASSERT(it != map->notFound());
                     if (it->second.attributes & DontDelete) {
-                        storage->m_length = index + 1;
+                        storage->setLength(index + 1);
                         return reject(exec, throwException, "Unable to delete property.");
                     }
                     map->remove(it);
@@ -1206,14 +375,14 @@ bool JSArray::setLength(ExecState* exec, unsigned newLength, bool throwException
                 for (unsigned i = 0; i < keys.size(); ++i)
                     map->remove(keys[i]);
                 if (map->isEmpty())
-                    deallocateSparseMap();
+                    deallocateSparseIndexMap();
             }
         }
     }
 
     if (newLength < length) {
         // Delete properties from the vector.
-        unsigned usedVectorLength = min(length, m_vectorLength);
+        unsigned usedVectorLength = min(length, storage->vectorLength());
         for (unsigned i = newLength; i < usedVectorLength; ++i) {
             WriteBarrier<Unknown>& valueSlot = storage->m_vector[i];
             bool hadValue = valueSlot;
@@ -1222,53 +391,65 @@ bool JSArray::setLength(ExecState* exec, unsigned newLength, bool throwException
         }
     }
 
-    storage->m_length = newLength;
+    storage->setLength(newLength);
 
-    checkConsistency();
+    checkIndexingConsistency();
     return true;
 }
 
 JSValue JSArray::pop(ExecState* exec)
 {
-    checkConsistency();
-    ArrayStorage* storage = m_storage;
+    checkIndexingConsistency();
     
-    unsigned length = storage->m_length;
-    if (!length) {
-        if (!isLengthWritable())
-            throwTypeError(exec, ASCIILiteral(StrictModeReadonlyPropertyWriteError));
+    switch (structure()->indexingType()) {
+    case Array:
         return jsUndefined();
-    }
+        
+    case ArrayWithArrayStorage: {
+        ArrayStorage* storage = m_butterfly->arrayStorage();
+    
+        unsigned length = storage->length();
+        if (!length) {
+            if (!isLengthWritable())
+                throwTypeError(exec, StrictModeReadonlyPropertyWriteError);
+            return jsUndefined();
+        }
 
-    unsigned index = length - 1;
-    if (index < m_vectorLength) {
-        WriteBarrier<Unknown>& valueSlot = storage->m_vector[index];
-        if (valueSlot) {
-            --storage->m_numValuesInVector;
-            JSValue element = valueSlot.get();
-            valueSlot.clear();
+        unsigned index = length - 1;
+        if (index < storage->vectorLength()) {
+            WriteBarrier<Unknown>& valueSlot = storage->m_vector[index];
+            if (valueSlot) {
+                --storage->m_numValuesInVector;
+                JSValue element = valueSlot.get();
+                valueSlot.clear();
             
-            ASSERT(isLengthWritable());
-            storage->m_length = index;
-            checkConsistency();
-            return element;
+                ASSERT(isLengthWritable());
+                storage->setLength(index);
+                checkIndexingConsistency();
+                return element;
+            }
         }
-    }
 
-    // Let element be the result of calling the [[Get]] internal method of O with argument indx.
-    JSValue element = get(exec, index);
-    if (exec->hadException())
-        return jsUndefined();
-    // Call the [[Delete]] internal method of O with arguments indx and true.
-    if (!deletePropertyByIndex(this, exec, index)) {
-        throwTypeError(exec, ASCIILiteral("Unable to delete property."));
-        return jsUndefined();
+        // Let element be the result of calling the [[Get]] internal method of O with argument indx.
+        JSValue element = get(exec, index);
+        if (exec->hadException())
+            return jsUndefined();
+        // Call the [[Delete]] internal method of O with arguments indx and true.
+        if (!deletePropertyByIndex(this, exec, index)) {
+            throwTypeError(exec, "Unable to delete property.");
+            return jsUndefined();
+        }
+        // Call the [[Put]] internal method of O with arguments "length", indx, and true.
+        setLength(exec, index, true);
+        // Return element.
+        checkIndexingConsistency();
+        return element;
+    }
+        
+    default:
+        ASSERT_NOT_REACHED();
+        return JSValue();
     }
-    // Call the [[Put]] internal method of O with arguments "length", indx, and true.
-    setLength(exec, index, true);
-    // Return element.
-    checkConsistency();
-    return element;
 }
 
 // Push & putIndex are almost identical, with two small differences.
@@ -1276,63 +457,77 @@ JSValue JSArray::pop(ExecState* exec)
 //  - pushing to an array of length 2^32-1 stores the property, but throws a range error.
 void JSArray::push(ExecState* exec, JSValue value)
 {
-    checkConsistency();
-    ArrayStorage* storage = m_storage;
-
-    // Fast case - push within vector, always update m_length & m_numValuesInVector.
-    unsigned length = storage->m_length;
-    if (length < m_vectorLength) {
-        storage->m_vector[length].set(exec->globalData(), this, value);
-        storage->m_length = length + 1;
-        ++storage->m_numValuesInVector;
-        checkConsistency();
-        return;
+    checkIndexingConsistency();
+    
+    switch (structure()->indexingType()) {
+    case Array: {
+        putByIndexBeyondVectorLengthWithArrayStorage(exec, 0, value, true, createInitialArrayStorage(exec->globalData()));
+        break;
     }
+        
+    case ArrayWithArrayStorage: {
+        ArrayStorage* storage = m_butterfly->arrayStorage();
+
+        // Fast case - push within vector, always update m_length & m_numValuesInVector.
+        unsigned length = storage->length();
+        if (length < storage->vectorLength()) {
+            storage->m_vector[length].set(exec->globalData(), this, value);
+            storage->setLength(length + 1);
+            ++storage->m_numValuesInVector;
+            checkIndexingConsistency();
+            return;
+        }
 
-    // Pushing to an array of length 2^32-1 stores the property, but throws a range error.
-    if (UNLIKELY(storage->m_length == 0xFFFFFFFFu)) {
-        methodTable()->putByIndex(this, exec, storage->m_length, value, true);
-        // Per ES5.1 15.4.4.7 step 6 & 15.4.5.1 step 3.d.
-        if (!exec->hadException())
-            throwError(exec, createRangeError(exec, ASCIILiteral("Invalid array length")));
-        return;
-    }
+        // Pushing to an array of length 2^32-1 stores the property, but throws a range error.
+        if (UNLIKELY(storage->length() == 0xFFFFFFFFu)) {
+            methodTable()->putByIndex(this, exec, storage->length(), value, true);
+            // Per ES5.1 15.4.4.7 step 6 & 15.4.5.1 step 3.d.
+            if (!exec->hadException())
+                throwError(exec, createRangeError(exec, "Invalid array length"));
+            return;
+        }
 
-    // Handled the same as putIndex.
-    putByIndexBeyondVectorLength(exec, storage->m_length, value, true);
-    checkConsistency();
+        // Handled the same as putIndex.
+        putByIndexBeyondVectorLengthWithArrayStorage(exec, storage->length(), value, true, storage);
+        checkIndexingConsistency();
+        break;
+    }
+        
+    default:
+        ASSERT_NOT_REACHED();
+    }
 }
 
-bool JSArray::shiftCount(ExecState*, unsigned count)
+bool JSArray::shiftCount(ExecState* exec, unsigned count)
 {
     ASSERT(count > 0);
     
-    ArrayStorage* storage = m_storage;
+    ArrayStorage* storage = ensureArrayStorage(exec->globalData());
     
-    unsigned oldLength = storage->m_length;
+    unsigned oldLength = storage->length();
     
     // If the array contains holes or is otherwise in an abnormal state,
     // use the generic algorithm in ArrayPrototype.
-    if (oldLength != storage->m_numValuesInVector || inSparseMode())
+    if (oldLength != storage->m_numValuesInVector || inSparseIndexingMode())
         return false;
 
     if (!oldLength)
         return true;
     
     storage->m_numValuesInVector -= count;
-    storage->m_length -= count;
+    storage->setLength(oldLength - count);
     
-    if (m_vectorLength) {
-        count = min(m_vectorLength, (unsigned)count);
+    unsigned vectorLength = storage->vectorLength();
+    if (vectorLength) {
+        count = min(vectorLength, (unsigned)count);
         
-        m_vectorLength -= count;
+        vectorLength -= count;
+        storage->setVectorLength(vectorLength);
         
-        if (m_vectorLength) {
-            char* newBaseStorage = reinterpret_cast<char*>(storage) + count * sizeof(WriteBarrier<Unknown>);
-            memmove(newBaseStorage, storage, storageSize(0));
-            m_storage = reinterpret_cast_ptr<ArrayStorage*>(newBaseStorage);
-
-            m_indexBias += count;
+        if (vectorLength) {
+            m_butterfly = m_butterfly->shift(structure(), count);
+            storage = m_butterfly->arrayStorage();
+            storage->m_indexBias += count;
         }
     }
     return true;
@@ -1341,59 +536,30 @@ bool JSArray::shiftCount(ExecState*, unsigned count)
 // Returns true if the unshift can be handled, false to fallback.    
 bool JSArray::unshiftCount(ExecState* exec, unsigned count)
 {
-    ArrayStorage* storage = m_storage;
-    unsigned length = storage->m_length;
+    ArrayStorage* storage = ensureArrayStorage(exec->globalData());
+    unsigned length = storage->length();
 
     // If the array contains holes or is otherwise in an abnormal state,
     // use the generic algorithm in ArrayPrototype.
-    if (length != storage->m_numValuesInVector || inSparseMode())
+    if (length != storage->m_numValuesInVector || storage->inSparseMode())
         return false;
 
-    if (m_indexBias >= count) {
-        m_indexBias -= count;
-        char* newBaseStorage = reinterpret_cast<char*>(storage) - count * sizeof(WriteBarrier<Unknown>);
-        memmove(newBaseStorage, storage, storageSize(0));
-        m_storage = reinterpret_cast_ptr<ArrayStorage*>(newBaseStorage);
-        m_vectorLength += count;
+    if (storage->m_indexBias >= count) {
+        m_butterfly = storage->butterfly()->unshift(structure(), count);
+        storage = m_butterfly->arrayStorage();
+        storage->m_indexBias -= count;
+        storage->setVectorLength(storage->vectorLength() + count);
     } else if (!unshiftCountSlowCase(exec->globalData(), count)) {
         throwOutOfMemoryError(exec);
         return true;
     }
 
-    WriteBarrier<Unknown>* vector = m_storage->m_vector;
+    WriteBarrier<Unknown>* vector = storage->m_vector;
     for (unsigned i = 0; i < count; i++)
         vector[i].clear();
     return true;
 }
 
-void JSArray::visitChildren(JSCell* cell, SlotVisitor& visitor)
-{
-    JSArray* thisObject = jsCast<JSArray*>(cell);
-    ASSERT_GC_OBJECT_INHERITS(thisObject, &s_info);
-    COMPILE_ASSERT(StructureFlags & OverridesVisitChildren, OverridesVisitChildrenWithoutSettingFlag);
-    ASSERT(thisObject->structure()->typeInfo().overridesVisitChildren());
-
-    JSNonFinalObject::visitChildren(thisObject, visitor);
-
-    if (thisObject->m_storage) {
-        MARK_LOG_MESSAGE1("[%u]: ", thisObject->length());
-
-        ArrayStorage* storage = thisObject->m_storage;
-        void* baseStorage = storage->m_allocBase;
-
-        visitor.copyAndAppend(reinterpret_cast<void**>(&baseStorage), storageSize(thisObject->m_vectorLength + thisObject->m_indexBias), storage->m_vector->slot(), thisObject->m_vectorLength);
-
-        if (baseStorage != thisObject->m_storage->m_allocBase) {
-            thisObject->m_storage = reinterpret_cast_ptr<ArrayStorage*>(static_cast<char*>(baseStorage) + sizeof(JSValue) * thisObject->m_indexBias);
-            thisObject->m_storage->m_allocBase = baseStorage;
-            ASSERT(thisObject->m_storage->m_allocBase);
-        }
-    }
-
-    if (SparseArrayValueMap* map = thisObject->m_sparseValueMap)
-        map->visitChildren(visitor);
-}
-
 static int compareNumbersForQSort(const void* a, const void* b)
 {
     double da = static_cast<const JSValue*>(a)->asNumber();
@@ -1410,112 +576,137 @@ static int compareByStringPairForQSort(const void* a, const void* b)
 
 void JSArray::sortNumeric(ExecState* exec, JSValue compareFunction, CallType callType, const CallData& callData)
 {
-    ASSERT(!inSparseMode());
-
-    ArrayStorage* storage = m_storage;
-
-    unsigned lengthNotIncludingUndefined = compactForSorting(exec->globalData());
-    if (m_sparseValueMap) {
-        throwOutOfMemoryError(exec);
-        return;
-    }
+    ASSERT(!inSparseIndexingMode());
 
-    if (!lengthNotIncludingUndefined)
+    switch (structure()->indexingType()) {
+    case Array:
         return;
         
-    bool allValuesAreNumbers = true;
-    size_t size = storage->m_numValuesInVector;
-    for (size_t i = 0; i < size; ++i) {
-        if (!storage->m_vector[i].isNumber()) {
-            allValuesAreNumbers = false;
-            break;
+    case ArrayWithArrayStorage: {
+        unsigned lengthNotIncludingUndefined = compactForSorting(exec->globalData());
+        ArrayStorage* storage = m_butterfly->arrayStorage();
+        
+        if (storage->m_sparseMap.get()) {
+            throwOutOfMemoryError(exec);
+            return;
+        }
+        
+        if (!lengthNotIncludingUndefined)
+            return;
+        
+        bool allValuesAreNumbers = true;
+        size_t size = storage->m_numValuesInVector;
+        for (size_t i = 0; i < size; ++i) {
+            if (!storage->m_vector[i].isNumber()) {
+                allValuesAreNumbers = false;
+                break;
+            }
         }
+        
+        if (!allValuesAreNumbers)
+            return sort(exec, compareFunction, callType, callData);
+        
+        // For numeric comparison, which is fast, qsort is faster than mergesort. We
+        // also don't require mergesort's stability, since there's no user visible
+        // side-effect from swapping the order of equal primitive values.
+        qsort(storage->m_vector, size, sizeof(WriteBarrier<Unknown>), compareNumbersForQSort);
+        
+        checkIndexingConsistency(SortConsistencyCheck);
+        return;
+    }
+        
+    default:
+        ASSERT_NOT_REACHED();
     }
-
-    if (!allValuesAreNumbers)
-        return sort(exec, compareFunction, callType, callData);
-
-    // For numeric comparison, which is fast, qsort is faster than mergesort. We
-    // also don't require mergesort's stability, since there's no user visible
-    // side-effect from swapping the order of equal primitive values.
-    qsort(storage->m_vector, size, sizeof(WriteBarrier<Unknown>), compareNumbersForQSort);
-
-    checkConsistency(SortConsistencyCheck);
 }
 
 void JSArray::sort(ExecState* exec)
 {
-    ASSERT(!inSparseMode());
-
-    unsigned lengthNotIncludingUndefined = compactForSorting(exec->globalData());
-    if (m_sparseValueMap) {
-        throwOutOfMemoryError(exec);
-        return;
-    }
-
-    if (!lengthNotIncludingUndefined)
-        return;
-
-    // Converting JavaScript values to strings can be expensive, so we do it once up front and sort based on that.
-    // This is a considerable improvement over doing it twice per comparison, though it requires a large temporary
-    // buffer. Besides, this protects us from crashing if some objects have custom toString methods that return
-    // random or otherwise changing results, effectively making compare function inconsistent.
-
-    Vector<ValueStringPair> values(lengthNotIncludingUndefined);
-    if (!values.begin()) {
-        throwOutOfMemoryError(exec);
-        return;
-    }
+    ASSERT(!inSparseIndexingMode());
     
-    Heap::heap(this)->pushTempSortVector(&values);
-
-    bool isSortingPrimitiveValues = true;
-    for (size_t i = 0; i < lengthNotIncludingUndefined; i++) {
-        JSValue value = m_storage->m_vector[i].get();
-        ASSERT(!value.isUndefined());
-        values[i].first = value;
-        isSortingPrimitiveValues = isSortingPrimitiveValues && value.isPrimitive();
-    }
-
-    // FIXME: The following loop continues to call toString on subsequent values even after
-    // a toString call raises an exception.
-
-    for (size_t i = 0; i < lengthNotIncludingUndefined; i++)
-        values[i].second = values[i].first.toWTFStringInline(exec);
-
-    if (exec->hadException()) {
-        Heap::heap(this)->popTempSortVector(&values);
+    switch (structure()->indexingType()) {
+    case Array:
         return;
-    }
-
-    // FIXME: Since we sort by string value, a fast algorithm might be to use a radix sort. That would be O(N) rather
-    // than O(N log N).
-
+        
+    case ArrayWithArrayStorage: {
+        unsigned lengthNotIncludingUndefined = compactForSorting(exec->globalData());
+        ArrayStorage* storage = m_butterfly->arrayStorage();
+        if (storage->m_sparseMap.get()) {
+            throwOutOfMemoryError(exec);
+            return;
+        }
+        
+        if (!lengthNotIncludingUndefined)
+            return;
+        
+        // Converting JavaScript values to strings can be expensive, so we do it once up front and sort based on that.
+        // This is a considerable improvement over doing it twice per comparison, though it requires a large temporary
+        // buffer. Besides, this protects us from crashing if some objects have custom toString methods that return
+        // random or otherwise changing results, effectively making compare function inconsistent.
+        
+        Vector<ValueStringPair> values(lengthNotIncludingUndefined);
+        if (!values.begin()) {
+            throwOutOfMemoryError(exec);
+            return;
+        }
+        
+        Heap::heap(this)->pushTempSortVector(&values);
+        
+        bool isSortingPrimitiveValues = true;
+        for (size_t i = 0; i < lengthNotIncludingUndefined; i++) {
+            JSValue value = storage->m_vector[i].get();
+            ASSERT(!value.isUndefined());
+            values[i].first = value;
+            isSortingPrimitiveValues = isSortingPrimitiveValues && value.isPrimitive();
+        }
+        
+        // FIXME: The following loop continues to call toString on subsequent values even after
+        // a toString call raises an exception.
+        
+        for (size_t i = 0; i < lengthNotIncludingUndefined; i++)
+            values[i].second = values[i].first.toWTFStringInline(exec);
+        
+        if (exec->hadException()) {
+            Heap::heap(this)->popTempSortVector(&values);
+            return;
+        }
+        
+        // FIXME: Since we sort by string value, a fast algorithm might be to use a radix sort. That would be O(N) rather
+        // than O(N log N).
+        
 #if HAVE(MERGESORT)
-    if (isSortingPrimitiveValues)
-        qsort(values.begin(), values.size(), sizeof(ValueStringPair), compareByStringPairForQSort);
-    else
-        mergesort(values.begin(), values.size(), sizeof(ValueStringPair), compareByStringPairForQSort);
+        if (isSortingPrimitiveValues)
+            qsort(values.begin(), values.size(), sizeof(ValueStringPair), compareByStringPairForQSort);
+        else
+            mergesort(values.begin(), values.size(), sizeof(ValueStringPair), compareByStringPairForQSort);
 #else
-    // FIXME: The qsort library function is likely to not be a stable sort.
-    // ECMAScript-262 does not specify a stable sort, but in practice, browsers perform a stable sort.
-    qsort(values.begin(), values.size(), sizeof(ValueStringPair), compareByStringPairForQSort);
+        // FIXME: The qsort library function is likely to not be a stable sort.
+        // ECMAScript-262 does not specify a stable sort, but in practice, browsers perform a stable sort.
+        qsort(values.begin(), values.size(), sizeof(ValueStringPair), compareByStringPairForQSort);
 #endif
-
-    // If the toString function changed the length of the array or vector storage,
-    // increase the length to handle the orignal number of actual values.
-    if (m_vectorLength < lengthNotIncludingUndefined)
-        increaseVectorLength(exec->globalData(), lengthNotIncludingUndefined);
-    if (m_storage->m_length < lengthNotIncludingUndefined)
-        m_storage->m_length = lengthNotIncludingUndefined;
-
-    JSGlobalData& globalData = exec->globalData();
-    for (size_t i = 0; i < lengthNotIncludingUndefined; i++)
-        m_storage->m_vector[i].set(globalData, this, values[i].first);
-
-    Heap::heap(this)->popTempSortVector(&values);
-    
-    checkConsistency(SortConsistencyCheck);
+        
+        // If the toString function changed the length of the array or vector storage,
+        // increase the length to handle the orignal number of actual values.
+        if (storage->vectorLength() < lengthNotIncludingUndefined) {
+            increaseVectorLength(exec->globalData(), lengthNotIncludingUndefined);
+            storage = m_butterfly->arrayStorage();
+        }
+        if (storage->length() < lengthNotIncludingUndefined)
+            storage->setLength(lengthNotIncludingUndefined);
+        
+        JSGlobalData& globalData = exec->globalData();
+        for (size_t i = 0; i < lengthNotIncludingUndefined; i++)
+            storage->m_vector[i].set(globalData, this, values[i].first);
+        
+        Heap::heap(this)->popTempSortVector(&values);
+        
+        checkIndexingConsistency(SortConsistencyCheck);
+        return;
+    }
+        
+    default:
+        ASSERT_NOT_REACHED();
+    }
 }
 
 struct AVLTreeNodeForArrayCompare {
@@ -1597,253 +788,257 @@ struct AVLTreeAbstractorForArrayCompare {
 
 void JSArray::sort(ExecState* exec, JSValue compareFunction, CallType callType, const CallData& callData)
 {
-    ASSERT(!inSparseMode());
-
-    checkConsistency();
-
-    // FIXME: This ignores exceptions raised in the compare function or in toNumber.
-
-    // The maximum tree depth is compiled in - but the caller is clearly up to no good
-    // if a larger array is passed.
-    ASSERT(m_storage->m_length <= static_cast<unsigned>(std::numeric_limits<int>::max()));
-    if (m_storage->m_length > static_cast<unsigned>(std::numeric_limits<int>::max()))
-        return;
-
-    unsigned usedVectorLength = min(m_storage->m_length, m_vectorLength);
-    unsigned nodeCount = usedVectorLength + (m_sparseValueMap ? m_sparseValueMap->size() : 0);
-
-    if (!nodeCount)
-        return;
-
-    AVLTree<AVLTreeAbstractorForArrayCompare, 44> tree; // Depth 44 is enough for 2^31 items
-    tree.abstractor().m_exec = exec;
-    tree.abstractor().m_compareFunction = compareFunction;
-    tree.abstractor().m_compareCallType = callType;
-    tree.abstractor().m_compareCallData = &callData;
-    tree.abstractor().m_nodes.grow(nodeCount);
-
-    if (callType == CallTypeJS)
-        tree.abstractor().m_cachedCall = adoptPtr(new CachedCall(exec, jsCast<JSFunction*>(compareFunction), 2));
-
-    if (!tree.abstractor().m_nodes.begin()) {
-        throwOutOfMemoryError(exec);
+    ASSERT(!inSparseIndexingMode());
+    
+    switch (structure()->indexingType()) {
+    case Array:
         return;
-    }
-
-    // FIXME: If the compare function modifies the array, the vector, map, etc. could be modified
-    // right out from under us while we're building the tree here.
-
-    unsigned numDefined = 0;
-    unsigned numUndefined = 0;
-
-    // Iterate over the array, ignoring missing values, counting undefined ones, and inserting all other ones into the tree.
-    for (; numDefined < usedVectorLength; ++numDefined) {
-        JSValue v = m_storage->m_vector[numDefined].get();
-        if (!v || v.isUndefined())
-            break;
-        tree.abstractor().m_nodes[numDefined].value = v;
-        tree.insert(numDefined);
-    }
-    for (unsigned i = numDefined; i < usedVectorLength; ++i) {
-        JSValue v = m_storage->m_vector[i].get();
-        if (v) {
-            if (v.isUndefined())
-                ++numUndefined;
-            else {
-                tree.abstractor().m_nodes[numDefined].value = v;
-                tree.insert(numDefined);
-                ++numDefined;
+        
+    case ArrayWithArrayStorage: {
+        ArrayStorage* storage = m_butterfly->arrayStorage();
+        checkIndexingConsistency();
+        
+        // FIXME: This ignores exceptions raised in the compare function or in toNumber.
+        
+        // The maximum tree depth is compiled in - but the caller is clearly up to no good
+        // if a larger array is passed.
+        ASSERT(storage->length() <= static_cast<unsigned>(std::numeric_limits<int>::max()));
+        if (storage->length() > static_cast<unsigned>(std::numeric_limits<int>::max()))
+            return;
+        
+        unsigned usedVectorLength = min(storage->length(), storage->vectorLength());
+        unsigned nodeCount = usedVectorLength + (storage->m_sparseMap ? storage->m_sparseMap->size() : 0);
+        
+        if (!nodeCount)
+            return;
+        
+        AVLTree<AVLTreeAbstractorForArrayCompare, 44> tree; // Depth 44 is enough for 2^31 items
+        tree.abstractor().m_exec = exec;
+        tree.abstractor().m_compareFunction = compareFunction;
+        tree.abstractor().m_compareCallType = callType;
+        tree.abstractor().m_compareCallData = &callData;
+        tree.abstractor().m_nodes.grow(nodeCount);
+        
+        if (callType == CallTypeJS)
+            tree.abstractor().m_cachedCall = adoptPtr(new CachedCall(exec, jsCast<JSFunction*>(compareFunction), 2));
+        
+        if (!tree.abstractor().m_nodes.begin()) {
+            throwOutOfMemoryError(exec);
+            return;
+        }
+        
+        // FIXME: If the compare function modifies the array, the vector, map, etc. could be modified
+        // right out from under us while we're building the tree here.
+        
+        unsigned numDefined = 0;
+        unsigned numUndefined = 0;
+        
+        // Iterate over the array, ignoring missing values, counting undefined ones, and inserting all other ones into the tree.
+        for (; numDefined < usedVectorLength; ++numDefined) {
+            JSValue v = storage->m_vector[numDefined].get();
+            if (!v || v.isUndefined())
+                break;
+            tree.abstractor().m_nodes[numDefined].value = v;
+            tree.insert(numDefined);
+        }
+        for (unsigned i = numDefined; i < usedVectorLength; ++i) {
+            JSValue v = storage->m_vector[i].get();
+            if (v) {
+                if (v.isUndefined())
+                    ++numUndefined;
+                else {
+                    tree.abstractor().m_nodes[numDefined].value = v;
+                    tree.insert(numDefined);
+                    ++numDefined;
+                }
             }
         }
-    }
-
-    unsigned newUsedVectorLength = numDefined + numUndefined;
-
-    if (SparseArrayValueMap* map = m_sparseValueMap) {
-        newUsedVectorLength += map->size();
-        if (newUsedVectorLength > m_vectorLength) {
-            // Check that it is possible to allocate an array large enough to hold all the entries.
-            if ((newUsedVectorLength > MAX_STORAGE_VECTOR_LENGTH) || !increaseVectorLength(exec->globalData(), newUsedVectorLength)) {
-                throwOutOfMemoryError(exec);
-                return;
+        
+        unsigned newUsedVectorLength = numDefined + numUndefined;
+        
+        if (SparseArrayValueMap* map = storage->m_sparseMap.get()) {
+            newUsedVectorLength += map->size();
+            if (newUsedVectorLength > storage->vectorLength()) {
+                // Check that it is possible to allocate an array large enough to hold all the entries.
+                if ((newUsedVectorLength > MAX_STORAGE_VECTOR_LENGTH) || !increaseVectorLength(exec->globalData(), newUsedVectorLength)) {
+                    throwOutOfMemoryError(exec);
+                    return;
+                }
+                storage = m_butterfly->arrayStorage();
+            }
+            
+            SparseArrayValueMap::const_iterator end = map->end();
+            for (SparseArrayValueMap::const_iterator it = map->begin(); it != end; ++it) {
+                tree.abstractor().m_nodes[numDefined].value = it->second.getNonSparseMode();
+                tree.insert(numDefined);
+                ++numDefined;
             }
+            
+            deallocateSparseIndexMap();
         }
-
-        SparseArrayValueMap::const_iterator end = map->end();
-        for (SparseArrayValueMap::const_iterator it = map->begin(); it != end; ++it) {
-            tree.abstractor().m_nodes[numDefined].value = it->second.getNonSparseMode();
-            tree.insert(numDefined);
-            ++numDefined;
+        
+        ASSERT(tree.abstractor().m_nodes.size() >= numDefined);
+        
+        // FIXME: If the compare function changed the length of the array, the following might be
+        // modifying the vector incorrectly.
+        
+        // Copy the values back into m_storage.
+        AVLTree<AVLTreeAbstractorForArrayCompare, 44>::Iterator iter;
+        iter.start_iter_least(tree);
+        JSGlobalData& globalData = exec->globalData();
+        for (unsigned i = 0; i < numDefined; ++i) {
+            storage->m_vector[i].set(globalData, this, tree.abstractor().m_nodes[*iter].value);
+            ++iter;
         }
-
-        deallocateSparseMap();
+        
+        // Put undefined values back in.
+        for (unsigned i = numDefined; i < newUsedVectorLength; ++i)
+            storage->m_vector[i].setUndefined();
+        
+        // Ensure that unused values in the vector are zeroed out.
+        for (unsigned i = newUsedVectorLength; i < usedVectorLength; ++i)
+            storage->m_vector[i].clear();
+        
+        storage->m_numValuesInVector = newUsedVectorLength;
+        
+        checkIndexingConsistency(SortConsistencyCheck);
+        return;
     }
-
-    ASSERT(tree.abstractor().m_nodes.size() >= numDefined);
-
-    // FIXME: If the compare function changed the length of the array, the following might be
-    // modifying the vector incorrectly.
-
-    // Copy the values back into m_storage.
-    AVLTree<AVLTreeAbstractorForArrayCompare, 44>::Iterator iter;
-    iter.start_iter_least(tree);
-    JSGlobalData& globalData = exec->globalData();
-    for (unsigned i = 0; i < numDefined; ++i) {
-        m_storage->m_vector[i].set(globalData, this, tree.abstractor().m_nodes[*iter].value);
-        ++iter;
+        
+    default:
+        ASSERT_NOT_REACHED();
     }
-
-    // Put undefined values back in.
-    for (unsigned i = numDefined; i < newUsedVectorLength; ++i)
-        m_storage->m_vector[i].setUndefined();
-
-    // Ensure that unused values in the vector are zeroed out.
-    for (unsigned i = newUsedVectorLength; i < usedVectorLength; ++i)
-        m_storage->m_vector[i].clear();
-
-    m_storage->m_numValuesInVector = newUsedVectorLength;
-
-    checkConsistency(SortConsistencyCheck);
 }
 
 void JSArray::fillArgList(ExecState* exec, MarkedArgumentBuffer& args)
 {
-    ArrayStorage* storage = m_storage;
-
-    WriteBarrier<Unknown>* vector = storage->m_vector;
-    unsigned vectorEnd = min(storage->m_length, m_vectorLength);
-    unsigned i = 0;
-    for (; i < vectorEnd; ++i) {
-        WriteBarrier<Unknown>& v = vector[i];
-        if (!v)
-            break;
-        args.append(v.get());
+    switch (structure()->indexingType()) {
+    case Array:
+        return;
+    
+    case ArrayWithArrayStorage: {
+        ArrayStorage* storage = m_butterfly->arrayStorage();
+        
+        WriteBarrier<Unknown>* vector = storage->m_vector;
+        unsigned vectorEnd = min(storage->length(), storage->vectorLength());
+        unsigned i = 0;
+        for (; i < vectorEnd; ++i) {
+            WriteBarrier<Unknown>& v = vector[i];
+            if (!v)
+                break;
+            args.append(v.get());
+        }
+        
+        for (; i < storage->length(); ++i)
+            args.append(get(exec, i));
+        return;
+    }
+        
+    default:
+        ASSERT_NOT_REACHED();
     }
-
-    for (; i < storage->m_length; ++i)
-        args.append(get(exec, i));
 }
 
 void JSArray::copyToArguments(ExecState* exec, CallFrame* callFrame, uint32_t length)
 {
     ASSERT(length == this->length());
-    UNUSED_PARAM(length);
-    unsigned i = 0;
-    WriteBarrier<Unknown>* vector = m_storage->m_vector;
-    unsigned vectorEnd = min(length, m_vectorLength);
-    for (; i < vectorEnd; ++i) {
-        WriteBarrier<Unknown>& v = vector[i];
-        if (!v)
-            break;
-        callFrame->setArgument(i, v.get());
+    switch (structure()->indexingType()) {
+    case Array:
+        return;
+        
+    case ArrayWithArrayStorage: {
+        ArrayStorage* storage = m_butterfly->arrayStorage();
+        unsigned i = 0;
+        WriteBarrier<Unknown>* vector = storage->m_vector;
+        unsigned vectorEnd = min(length, storage->vectorLength());
+        for (; i < vectorEnd; ++i) {
<