JSC should infer when indexed storage contains only integers or doubles
authorfpizlo@apple.com <fpizlo@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 8 Nov 2012 22:28:25 +0000 (22:28 +0000)
committerfpizlo@apple.com <fpizlo@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 8 Nov 2012 22:28:25 +0000 (22:28 +0000)
https://bugs.webkit.org/show_bug.cgi?id=98606

Reviewed by Oliver Hunt.

Source/JavaScriptCore:

This adds two new indexing types: int32 and double. It also adds array allocation profiling,
which allows array allocations to converge to allocating arrays using those types to which
those arrays would have been converted.

20% speed-up on navier-stokes. 40% speed-up on various Kraken DSP tests. Some slow-downs too,
but a performance win overall on all benchmarks we track.

* API/JSObjectRef.cpp:
(JSObjectMakeArray):
* CMakeLists.txt:
* GNUmakefile.list.am:
* JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.def:
* JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.vcproj:
* JavaScriptCore.xcodeproj/project.pbxproj:
* Target.pri:
* assembler/AbstractMacroAssembler.h:
(JumpList):
(JSC::AbstractMacroAssembler::JumpList::JumpList):
* assembler/MacroAssemblerX86Common.h:
(JSC::MacroAssemblerX86Common::branchDouble):
* assembler/X86Assembler.h:
(JSC::X86Assembler::jnp):
(X86Assembler):
(JSC::X86Assembler::X86InstructionFormatter::emitRex):
* bytecode/ArrayAllocationProfile.cpp: Added.
(JSC):
(JSC::ArrayAllocationProfile::updateIndexingType):
* bytecode/ArrayAllocationProfile.h: Added.
(JSC):
(ArrayAllocationProfile):
(JSC::ArrayAllocationProfile::ArrayAllocationProfile):
(JSC::ArrayAllocationProfile::selectIndexingType):
(JSC::ArrayAllocationProfile::updateLastAllocation):
(JSC::ArrayAllocationProfile::selectIndexingTypeFor):
(JSC::ArrayAllocationProfile::updateLastAllocationFor):
* bytecode/ArrayProfile.cpp:
(JSC::ArrayProfile::updatedObservedArrayModes):
(JSC):
* bytecode/ArrayProfile.h:
(JSC):
(JSC::arrayModesInclude):
(JSC::shouldUseSlowPutArrayStorage):
(JSC::shouldUseFastArrayStorage):
(JSC::shouldUseContiguous):
(JSC::shouldUseDouble):
(JSC::shouldUseInt32):
(ArrayProfile):
* bytecode/ByValInfo.h:
(JSC::isOptimizableIndexingType):
(JSC::jitArrayModeForIndexingType):
* bytecode/CodeBlock.cpp:
(JSC::CodeBlock::dump):
(JSC::CodeBlock::CodeBlock):
(JSC::CodeBlock::updateAllPredictionsAndCountLiveness):
(JSC):
(JSC::CodeBlock::updateAllValueProfilePredictions):
(JSC::CodeBlock::updateAllArrayPredictions):
(JSC::CodeBlock::updateAllPredictions):
(JSC::CodeBlock::shouldOptimizeNow):
* bytecode/CodeBlock.h:
(CodeBlock):
(JSC::CodeBlock::numberOfArrayAllocationProfiles):
(JSC::CodeBlock::addArrayAllocationProfile):
(JSC::CodeBlock::updateAllValueProfilePredictions):
(JSC::CodeBlock::updateAllArrayPredictions):
* bytecode/DFGExitProfile.h:
(JSC::DFG::exitKindToString):
* bytecode/Instruction.h:
(JSC):
(JSC::Instruction::Instruction):
* bytecode/Opcode.h:
(JSC):
(JSC::padOpcodeName):
* bytecode/SpeculatedType.h:
(JSC):
(JSC::isRealNumberSpeculation):
* bytecode/UnlinkedCodeBlock.cpp:
(JSC::UnlinkedCodeBlock::UnlinkedCodeBlock):
* bytecode/UnlinkedCodeBlock.h:
(JSC):
(JSC::UnlinkedCodeBlock::addArrayAllocationProfile):
(JSC::UnlinkedCodeBlock::numberOfArrayAllocationProfiles):
(UnlinkedCodeBlock):
* bytecompiler/BytecodeGenerator.cpp:
(JSC::BytecodeGenerator::newArrayAllocationProfile):
(JSC):
(JSC::BytecodeGenerator::emitNewArray):
(JSC::BytecodeGenerator::emitExpectedFunctionSnippet):
* bytecompiler/BytecodeGenerator.h:
(BytecodeGenerator):
* dfg/DFGAbstractState.cpp:
(JSC::DFG::AbstractState::execute):
* dfg/DFGArrayMode.cpp:
(JSC::DFG::ArrayMode::fromObserved):
(JSC::DFG::ArrayMode::refine):
(DFG):
(JSC::DFG::ArrayMode::alreadyChecked):
(JSC::DFG::arrayTypeToString):
* dfg/DFGArrayMode.h:
(JSC::DFG::ArrayMode::withType):
(ArrayMode):
(JSC::DFG::ArrayMode::withTypeAndConversion):
(JSC::DFG::ArrayMode::usesButterfly):
(JSC::DFG::ArrayMode::isSpecific):
(JSC::DFG::ArrayMode::supportsLength):
(JSC::DFG::ArrayMode::arrayModesThatPassFiltering):
* dfg/DFGByteCodeParser.cpp:
(JSC::DFG::ByteCodeParser::getArrayMode):
(ByteCodeParser):
(JSC::DFG::ByteCodeParser::handleIntrinsic):
(JSC::DFG::ByteCodeParser::handleConstantInternalFunction):
(JSC::DFG::ByteCodeParser::parseBlock):
* dfg/DFGCCallHelpers.h:
(JSC::DFG::CCallHelpers::setupArgumentsWithExecState):
(CCallHelpers):
* dfg/DFGCallArrayAllocatorSlowPathGenerator.h:
(JSC::DFG::CallArrayAllocatorSlowPathGenerator::generateInternal):
(JSC::DFG::CallArrayAllocatorWithVariableSizeSlowPathGenerator::generateInternal):
* dfg/DFGFixupPhase.cpp:
(JSC::DFG::FixupPhase::fixupNode):
(JSC::DFG::FixupPhase::checkArray):
* dfg/DFGGraph.cpp:
(JSC::DFG::Graph::dump):
* dfg/DFGGraph.h:
(JSC::DFG::Graph::byValIsPure):
* dfg/DFGNode.h:
(NewArrayBufferData):
(JSC::DFG::Node::hasIndexingType):
(Node):
(JSC::DFG::Node::indexingType):
(JSC::DFG::Node::setIndexingType):
* dfg/DFGOperations.cpp:
* dfg/DFGOperations.h:
* dfg/DFGPredictionPropagationPhase.cpp:
(JSC::DFG::PredictionPropagationPhase::doRoundOfDoubleVoting):
* dfg/DFGSpeculativeJIT.cpp:
(JSC::DFG::SpeculativeJIT::emitAllocateJSArray):
(JSC::DFG::SpeculativeJIT::jumpSlowForUnwantedArrayMode):
(DFG):
(JSC::DFG::SpeculativeJIT::checkArray):
(JSC::DFG::SpeculativeJIT::arrayify):
(JSC::DFG::SpeculativeJIT::compileDoublePutByVal):
(JSC::DFG::SpeculativeJIT::compileGetArrayLength):
* dfg/DFGSpeculativeJIT.h:
(JSC::DFG::SpeculativeJIT::callOperation):
(SpeculativeJIT):
(SpeculateIntegerOperand):
(JSC::DFG::SpeculateIntegerOperand::use):
(SpeculateDoubleOperand):
(JSC::DFG::SpeculateDoubleOperand::use):
* dfg/DFGSpeculativeJIT32_64.cpp:
(DFG):
(JSC::DFG::SpeculativeJIT::compileContiguousPutByVal):
(JSC::DFG::SpeculativeJIT::compile):
* dfg/DFGSpeculativeJIT64.cpp:
(JSC::DFG::SpeculativeJIT::compile):
* jit/JIT.h:
(JSC::JIT::emitInt32GetByVal):
(JIT):
(JSC::JIT::emitInt32PutByVal):
(JSC::JIT::emitDoublePutByVal):
(JSC::JIT::emitContiguousPutByVal):
* jit/JITExceptions.cpp:
(JSC::genericThrow):
* jit/JITInlineMethods.h:
(JSC::arrayProfileSaw):
(JSC::JIT::chooseArrayMode):
* jit/JITOpcodes.cpp:
(JSC::JIT::emit_op_new_array):
(JSC::JIT::emit_op_new_array_with_size):
(JSC::JIT::emit_op_new_array_buffer):
* jit/JITPropertyAccess.cpp:
(JSC::JIT::emit_op_get_by_val):
(JSC::JIT::emitDoubleGetByVal):
(JSC):
(JSC::JIT::emitContiguousGetByVal):
(JSC::JIT::emit_op_put_by_val):
(JSC::JIT::emitGenericContiguousPutByVal):
(JSC::JIT::emitSlow_op_put_by_val):
(JSC::JIT::privateCompileGetByVal):
(JSC::JIT::privateCompilePutByVal):
* jit/JITPropertyAccess32_64.cpp:
(JSC::JIT::emit_op_get_by_val):
(JSC::JIT::emitContiguousGetByVal):
(JSC::JIT::emitDoubleGetByVal):
(JSC):
(JSC::JIT::emit_op_put_by_val):
(JSC::JIT::emitGenericContiguousPutByVal):
(JSC::JIT::emitSlow_op_put_by_val):
* jit/JITStubs.cpp:
(JSC::DEFINE_STUB_FUNCTION):
* jit/JITStubs.h:
(JSC):
* jsc.cpp:
(GlobalObject::finishCreation):
* llint/LLIntSlowPaths.cpp:
(JSC::LLInt::jitCompileAndSetHeuristics):
(JSC::LLInt::LLINT_SLOW_PATH_DECL):
* llint/LowLevelInterpreter.asm:
* llint/LowLevelInterpreter32_64.asm:
* llint/LowLevelInterpreter64.asm:
* offlineasm/x86.rb:
* runtime/ArrayConstructor.cpp:
(JSC::constructArrayWithSizeQuirk):
* runtime/ArrayConstructor.h:
(JSC):
* runtime/ArrayPrototype.cpp:
(JSC::arrayProtoFuncConcat):
(JSC::arrayProtoFuncSlice):
(JSC::arrayProtoFuncSplice):
(JSC::arrayProtoFuncFilter):
(JSC::arrayProtoFuncMap):
* runtime/Butterfly.h:
(JSC::Butterfly::contiguousInt32):
(JSC::Butterfly::contiguousDouble):
(JSC::Butterfly::fromContiguous):
* runtime/ButterflyInlineMethods.h:
(JSC::Butterfly::createUninitializedDuringCollection):
* runtime/FunctionPrototype.cpp:
(JSC::functionProtoFuncBind):
* runtime/IndexingHeaderInlineMethods.h:
(JSC::IndexingHeader::indexingPayloadSizeInBytes):
* runtime/IndexingType.cpp:
(JSC::leastUpperBoundOfIndexingTypes):
(JSC):
(JSC::leastUpperBoundOfIndexingTypeAndType):
(JSC::leastUpperBoundOfIndexingTypeAndValue):
(JSC::indexingTypeToString):
* runtime/IndexingType.h:
(JSC):
(JSC::hasUndecided):
(JSC::hasInt32):
(JSC::hasDouble):
* runtime/JSArray.cpp:
(JSC::JSArray::setLength):
(JSC::JSArray::pop):
(JSC::JSArray::push):
(JSC::JSArray::shiftCountWithAnyIndexingType):
(JSC::JSArray::unshiftCountWithAnyIndexingType):
(JSC::compareNumbersForQSortWithInt32):
(JSC):
(JSC::compareNumbersForQSortWithDouble):
(JSC::JSArray::sortNumericVector):
(JSC::JSArray::sortNumeric):
(JSC::JSArray::sortCompactedVector):
(JSC::JSArray::sort):
(JSC::JSArray::sortVector):
(JSC::JSArray::fillArgList):
(JSC::JSArray::copyToArguments):
(JSC::JSArray::compactForSorting):
* runtime/JSArray.h:
(JSArray):
(JSC::createContiguousArrayButterfly):
(JSC::JSArray::create):
(JSC::JSArray::tryCreateUninitialized):
* runtime/JSGlobalObject.cpp:
(JSC::JSGlobalObject::reset):
(JSC):
(JSC::JSGlobalObject::haveABadTime):
(JSC::JSGlobalObject::visitChildren):
* runtime/JSGlobalObject.h:
(JSGlobalObject):
(JSC::JSGlobalObject::originalArrayStructureForIndexingType):
(JSC::JSGlobalObject::arrayStructureForIndexingTypeDuringAllocation):
(JSC::JSGlobalObject::arrayStructureForProfileDuringAllocation):
(JSC::JSGlobalObject::isOriginalArrayStructure):
(JSC::constructEmptyArray):
(JSC::constructArray):
* runtime/JSObject.cpp:
(JSC::JSObject::copyButterfly):
(JSC::JSObject::getOwnPropertySlotByIndex):
(JSC::JSObject::putByIndex):
(JSC::JSObject::enterDictionaryIndexingMode):
(JSC::JSObject::createInitialIndexedStorage):
(JSC):
(JSC::JSObject::createInitialUndecided):
(JSC::JSObject::createInitialInt32):
(JSC::JSObject::createInitialDouble):
(JSC::JSObject::createInitialContiguous):
(JSC::JSObject::convertUndecidedToInt32):
(JSC::JSObject::convertUndecidedToDouble):
(JSC::JSObject::convertUndecidedToContiguous):
(JSC::JSObject::constructConvertedArrayStorageWithoutCopyingElements):
(JSC::JSObject::convertUndecidedToArrayStorage):
(JSC::JSObject::convertInt32ToDouble):
(JSC::JSObject::convertInt32ToContiguous):
(JSC::JSObject::convertInt32ToArrayStorage):
(JSC::JSObject::convertDoubleToContiguous):
(JSC::JSObject::convertDoubleToArrayStorage):
(JSC::JSObject::convertContiguousToArrayStorage):
(JSC::JSObject::convertUndecidedForValue):
(JSC::JSObject::convertInt32ForValue):
(JSC::JSObject::setIndexQuicklyToUndecided):
(JSC::JSObject::convertInt32ToDoubleOrContiguousWhilePerformingSetIndex):
(JSC::JSObject::convertDoubleToContiguousWhilePerformingSetIndex):
(JSC::JSObject::ensureInt32Slow):
(JSC::JSObject::ensureDoubleSlow):
(JSC::JSObject::ensureContiguousSlow):
(JSC::JSObject::ensureArrayStorageSlow):
(JSC::JSObject::ensureArrayStorageExistsAndEnterDictionaryIndexingMode):
(JSC::JSObject::switchToSlowPutArrayStorage):
(JSC::JSObject::deletePropertyByIndex):
(JSC::JSObject::getOwnPropertyNames):
(JSC::JSObject::putByIndexBeyondVectorLengthWithoutAttributes):
(JSC::JSObject::putByIndexBeyondVectorLength):
(JSC::JSObject::putDirectIndexBeyondVectorLength):
(JSC::JSObject::getNewVectorLength):
(JSC::JSObject::countElements):
(JSC::JSObject::ensureLengthSlow):
(JSC::JSObject::getOwnPropertyDescriptor):
* runtime/JSObject.h:
(JSC::JSObject::getArrayLength):
(JSC::JSObject::getVectorLength):
(JSC::JSObject::canGetIndexQuickly):
(JSC::JSObject::getIndexQuickly):
(JSC::JSObject::tryGetIndexQuickly):
(JSC::JSObject::canSetIndexQuickly):
(JSC::JSObject::canSetIndexQuicklyForPutDirect):
(JSC::JSObject::setIndexQuickly):
(JSC::JSObject::initializeIndex):
(JSC::JSObject::hasSparseMap):
(JSC::JSObject::inSparseIndexingMode):
(JSObject):
(JSC::JSObject::ensureInt32):
(JSC::JSObject::ensureDouble):
(JSC::JSObject::ensureLength):
(JSC::JSObject::indexingData):
(JSC::JSObject::currentIndexingData):
(JSC::JSObject::getHolyIndexQuickly):
(JSC::JSObject::relevantLength):
(JSC::JSObject::currentRelevantLength):
* runtime/JSValue.cpp:
(JSC::JSValue::description):
* runtime/LiteralParser.cpp:
(JSC::::parse):
* runtime/ObjectConstructor.cpp:
(JSC::objectConstructorGetOwnPropertyNames):
(JSC::objectConstructorKeys):
* runtime/StringPrototype.cpp:
(JSC::stringProtoFuncMatch):
(JSC::stringProtoFuncSplit):
* runtime/Structure.cpp:
(JSC::Structure::nonPropertyTransition):
* runtime/StructureTransitionTable.h:
(JSC::newIndexingType):

Source/WebCore:

Just refactoring WebCore to pass 0 for the ArrayAllocationProfile*.

* bindings/js/JSCanvasRenderingContext2DCustom.cpp:
(WebCore::JSCanvasRenderingContext2D::webkitLineDash):
* bindings/js/JSClipboardCustom.cpp:
(WebCore::JSClipboard::types):
* bindings/js/JSDOMBinding.cpp:
(WebCore::jsArray):
* bindings/js/JSDOMBinding.h:
(WebCore::jsArray):
* bindings/js/JSInjectedScriptHostCustom.cpp:
(WebCore::getJSListenerFunctions):
* bindings/js/JSJavaScriptCallFrameCustom.cpp:
(WebCore::JSJavaScriptCallFrame::scopeChain):
* bindings/js/JSMessageEventCustom.cpp:
(WebCore::JSMessageEvent::ports):
* bindings/js/JSMutationCallbackCustom.cpp:
(WebCore::JSMutationCallback::handleEvent):
* bindings/js/JSWebGLRenderingContextCustom.cpp:
(WebCore::toJS):
(WebCore::JSWebGLRenderingContext::getAttachedShaders):
(WebCore::JSWebGLRenderingContext::getSupportedExtensions):
* bindings/js/SerializedScriptValue.cpp:
(WebCore::CloneDeserializer::deserialize):

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

89 files changed:
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/assembler/AbstractMacroAssembler.h
Source/JavaScriptCore/assembler/MacroAssemblerX86Common.h
Source/JavaScriptCore/assembler/X86Assembler.h
Source/JavaScriptCore/bytecode/ArrayAllocationProfile.cpp [new file with mode: 0644]
Source/JavaScriptCore/bytecode/ArrayAllocationProfile.h [new file with mode: 0644]
Source/JavaScriptCore/bytecode/ArrayProfile.cpp
Source/JavaScriptCore/bytecode/ArrayProfile.h
Source/JavaScriptCore/bytecode/ByValInfo.h
Source/JavaScriptCore/bytecode/CodeBlock.cpp
Source/JavaScriptCore/bytecode/CodeBlock.h
Source/JavaScriptCore/bytecode/DFGExitProfile.h
Source/JavaScriptCore/bytecode/Instruction.h
Source/JavaScriptCore/bytecode/Opcode.h
Source/JavaScriptCore/bytecode/SpeculatedType.h
Source/JavaScriptCore/bytecode/UnlinkedCodeBlock.cpp
Source/JavaScriptCore/bytecode/UnlinkedCodeBlock.h
Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp
Source/JavaScriptCore/bytecompiler/BytecodeGenerator.h
Source/JavaScriptCore/dfg/DFGAbstractState.cpp
Source/JavaScriptCore/dfg/DFGArrayMode.cpp
Source/JavaScriptCore/dfg/DFGArrayMode.h
Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp
Source/JavaScriptCore/dfg/DFGCCallHelpers.h
Source/JavaScriptCore/dfg/DFGCallArrayAllocatorSlowPathGenerator.h
Source/JavaScriptCore/dfg/DFGFixupPhase.cpp
Source/JavaScriptCore/dfg/DFGGraph.cpp
Source/JavaScriptCore/dfg/DFGGraph.h
Source/JavaScriptCore/dfg/DFGNode.h
Source/JavaScriptCore/dfg/DFGOperations.cpp
Source/JavaScriptCore/dfg/DFGOperations.h
Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp
Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp
Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h
Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp
Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp
Source/JavaScriptCore/jit/JIT.h
Source/JavaScriptCore/jit/JITExceptions.cpp
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/jit/JITStubs.h
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/offlineasm/x86.rb
Source/JavaScriptCore/runtime/ArrayConstructor.cpp
Source/JavaScriptCore/runtime/ArrayConstructor.h
Source/JavaScriptCore/runtime/ArrayPrototype.cpp
Source/JavaScriptCore/runtime/Butterfly.h
Source/JavaScriptCore/runtime/ButterflyInlineMethods.h
Source/JavaScriptCore/runtime/FunctionPrototype.cpp
Source/JavaScriptCore/runtime/IndexingHeaderInlineMethods.h
Source/JavaScriptCore/runtime/IndexingType.cpp
Source/JavaScriptCore/runtime/IndexingType.h
Source/JavaScriptCore/runtime/JSArray.cpp
Source/JavaScriptCore/runtime/JSArray.h
Source/JavaScriptCore/runtime/JSGlobalObject.cpp
Source/JavaScriptCore/runtime/JSGlobalObject.h
Source/JavaScriptCore/runtime/JSObject.cpp
Source/JavaScriptCore/runtime/JSObject.h
Source/JavaScriptCore/runtime/JSValue.cpp
Source/JavaScriptCore/runtime/LiteralParser.cpp
Source/JavaScriptCore/runtime/ObjectConstructor.cpp
Source/JavaScriptCore/runtime/StringPrototype.cpp
Source/JavaScriptCore/runtime/Structure.cpp
Source/JavaScriptCore/runtime/StructureTransitionTable.h
Source/WebCore/ChangeLog
Source/WebCore/bindings/js/JSCanvasRenderingContext2DCustom.cpp
Source/WebCore/bindings/js/JSClipboardCustom.cpp
Source/WebCore/bindings/js/JSDOMBinding.cpp
Source/WebCore/bindings/js/JSDOMBinding.h
Source/WebCore/bindings/js/JSInjectedScriptHostCustom.cpp
Source/WebCore/bindings/js/JSJavaScriptCallFrameCustom.cpp
Source/WebCore/bindings/js/JSMessageEventCustom.cpp
Source/WebCore/bindings/js/JSMutationCallbackCustom.cpp
Source/WebCore/bindings/js/JSWebGLRenderingContextCustom.cpp
Source/WebCore/bindings/js/SerializedScriptValue.cpp

index 491fa98..4ed17e2 100644 (file)
@@ -144,9 +144,9 @@ JSObjectRef JSObjectMakeArray(JSContextRef ctx, size_t argumentCount, const JSVa
         for (size_t i = 0; i < argumentCount; ++i)
             argList.append(toJS(exec, arguments[i]));
 
-        result = constructArray(exec, argList);
+        result = constructArray(exec, static_cast<ArrayAllocationProfile*>(0), argList);
     } else
-        result = constructEmptyArray(exec);
+        result = constructEmptyArray(exec, 0);
 
     if (exec->hadException()) {
         if (exception)
index 393db67..bfaca56 100644 (file)
@@ -40,6 +40,7 @@ SET(JavaScriptCore_SOURCES
     assembler/MacroAssembler.cpp
     assembler/LinkBuffer.cpp
 
+    bytecode/ArrayAllocationProfile.cpp
     bytecode/ArrayProfile.cpp
     bytecode/CallLinkInfo.cpp
     bytecode/CallLinkStatus.cpp
index 320b1cf..f58aa40 100644 (file)
@@ -1,3 +1,356 @@
+2012-11-06  Filip Pizlo  <fpizlo@apple.com>
+
+        JSC should infer when indexed storage contains only integers or doubles
+        https://bugs.webkit.org/show_bug.cgi?id=98606
+
+        Reviewed by Oliver Hunt.
+
+        This adds two new indexing types: int32 and double. It also adds array allocation profiling,
+        which allows array allocations to converge to allocating arrays using those types to which
+        those arrays would have been converted.
+        
+        20% speed-up on navier-stokes. 40% speed-up on various Kraken DSP tests. Some slow-downs too,
+        but a performance win overall on all benchmarks we track.
+
+        * API/JSObjectRef.cpp:
+        (JSObjectMakeArray):
+        * CMakeLists.txt:
+        * GNUmakefile.list.am:
+        * JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.def:
+        * JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.vcproj:
+        * JavaScriptCore.xcodeproj/project.pbxproj:
+        * Target.pri:
+        * assembler/AbstractMacroAssembler.h:
+        (JumpList):
+        (JSC::AbstractMacroAssembler::JumpList::JumpList):
+        * assembler/MacroAssemblerX86Common.h:
+        (JSC::MacroAssemblerX86Common::branchDouble):
+        * assembler/X86Assembler.h:
+        (JSC::X86Assembler::jnp):
+        (X86Assembler):
+        (JSC::X86Assembler::X86InstructionFormatter::emitRex):
+        * bytecode/ArrayAllocationProfile.cpp: Added.
+        (JSC):
+        (JSC::ArrayAllocationProfile::updateIndexingType):
+        * bytecode/ArrayAllocationProfile.h: Added.
+        (JSC):
+        (ArrayAllocationProfile):
+        (JSC::ArrayAllocationProfile::ArrayAllocationProfile):
+        (JSC::ArrayAllocationProfile::selectIndexingType):
+        (JSC::ArrayAllocationProfile::updateLastAllocation):
+        (JSC::ArrayAllocationProfile::selectIndexingTypeFor):
+        (JSC::ArrayAllocationProfile::updateLastAllocationFor):
+        * bytecode/ArrayProfile.cpp:
+        (JSC::ArrayProfile::updatedObservedArrayModes):
+        (JSC):
+        * bytecode/ArrayProfile.h:
+        (JSC):
+        (JSC::arrayModesInclude):
+        (JSC::shouldUseSlowPutArrayStorage):
+        (JSC::shouldUseFastArrayStorage):
+        (JSC::shouldUseContiguous):
+        (JSC::shouldUseDouble):
+        (JSC::shouldUseInt32):
+        (ArrayProfile):
+        * bytecode/ByValInfo.h:
+        (JSC::isOptimizableIndexingType):
+        (JSC::jitArrayModeForIndexingType):
+        * bytecode/CodeBlock.cpp:
+        (JSC::CodeBlock::dump):
+        (JSC::CodeBlock::CodeBlock):
+        (JSC::CodeBlock::updateAllPredictionsAndCountLiveness):
+        (JSC):
+        (JSC::CodeBlock::updateAllValueProfilePredictions):
+        (JSC::CodeBlock::updateAllArrayPredictions):
+        (JSC::CodeBlock::updateAllPredictions):
+        (JSC::CodeBlock::shouldOptimizeNow):
+        * bytecode/CodeBlock.h:
+        (CodeBlock):
+        (JSC::CodeBlock::numberOfArrayAllocationProfiles):
+        (JSC::CodeBlock::addArrayAllocationProfile):
+        (JSC::CodeBlock::updateAllValueProfilePredictions):
+        (JSC::CodeBlock::updateAllArrayPredictions):
+        * bytecode/DFGExitProfile.h:
+        (JSC::DFG::exitKindToString):
+        * bytecode/Instruction.h:
+        (JSC):
+        (JSC::Instruction::Instruction):
+        * bytecode/Opcode.h:
+        (JSC):
+        (JSC::padOpcodeName):
+        * bytecode/SpeculatedType.h:
+        (JSC):
+        (JSC::isRealNumberSpeculation):
+        * bytecode/UnlinkedCodeBlock.cpp:
+        (JSC::UnlinkedCodeBlock::UnlinkedCodeBlock):
+        * bytecode/UnlinkedCodeBlock.h:
+        (JSC):
+        (JSC::UnlinkedCodeBlock::addArrayAllocationProfile):
+        (JSC::UnlinkedCodeBlock::numberOfArrayAllocationProfiles):
+        (UnlinkedCodeBlock):
+        * bytecompiler/BytecodeGenerator.cpp:
+        (JSC::BytecodeGenerator::newArrayAllocationProfile):
+        (JSC):
+        (JSC::BytecodeGenerator::emitNewArray):
+        (JSC::BytecodeGenerator::emitExpectedFunctionSnippet):
+        * bytecompiler/BytecodeGenerator.h:
+        (BytecodeGenerator):
+        * dfg/DFGAbstractState.cpp:
+        (JSC::DFG::AbstractState::execute):
+        * dfg/DFGArrayMode.cpp:
+        (JSC::DFG::ArrayMode::fromObserved):
+        (JSC::DFG::ArrayMode::refine):
+        (DFG):
+        (JSC::DFG::ArrayMode::alreadyChecked):
+        (JSC::DFG::arrayTypeToString):
+        * dfg/DFGArrayMode.h:
+        (JSC::DFG::ArrayMode::withType):
+        (ArrayMode):
+        (JSC::DFG::ArrayMode::withTypeAndConversion):
+        (JSC::DFG::ArrayMode::usesButterfly):
+        (JSC::DFG::ArrayMode::isSpecific):
+        (JSC::DFG::ArrayMode::supportsLength):
+        (JSC::DFG::ArrayMode::arrayModesThatPassFiltering):
+        * dfg/DFGByteCodeParser.cpp:
+        (JSC::DFG::ByteCodeParser::getArrayMode):
+        (ByteCodeParser):
+        (JSC::DFG::ByteCodeParser::handleIntrinsic):
+        (JSC::DFG::ByteCodeParser::handleConstantInternalFunction):
+        (JSC::DFG::ByteCodeParser::parseBlock):
+        * dfg/DFGCCallHelpers.h:
+        (JSC::DFG::CCallHelpers::setupArgumentsWithExecState):
+        (CCallHelpers):
+        * dfg/DFGCallArrayAllocatorSlowPathGenerator.h:
+        (JSC::DFG::CallArrayAllocatorSlowPathGenerator::generateInternal):
+        (JSC::DFG::CallArrayAllocatorWithVariableSizeSlowPathGenerator::generateInternal):
+        * dfg/DFGFixupPhase.cpp:
+        (JSC::DFG::FixupPhase::fixupNode):
+        (JSC::DFG::FixupPhase::checkArray):
+        * dfg/DFGGraph.cpp:
+        (JSC::DFG::Graph::dump):
+        * dfg/DFGGraph.h:
+        (JSC::DFG::Graph::byValIsPure):
+        * dfg/DFGNode.h:
+        (NewArrayBufferData):
+        (JSC::DFG::Node::hasIndexingType):
+        (Node):
+        (JSC::DFG::Node::indexingType):
+        (JSC::DFG::Node::setIndexingType):
+        * dfg/DFGOperations.cpp:
+        * dfg/DFGOperations.h:
+        * dfg/DFGPredictionPropagationPhase.cpp:
+        (JSC::DFG::PredictionPropagationPhase::doRoundOfDoubleVoting):
+        * dfg/DFGSpeculativeJIT.cpp:
+        (JSC::DFG::SpeculativeJIT::emitAllocateJSArray):
+        (JSC::DFG::SpeculativeJIT::jumpSlowForUnwantedArrayMode):
+        (DFG):
+        (JSC::DFG::SpeculativeJIT::checkArray):
+        (JSC::DFG::SpeculativeJIT::arrayify):
+        (JSC::DFG::SpeculativeJIT::compileDoublePutByVal):
+        (JSC::DFG::SpeculativeJIT::compileGetArrayLength):
+        * dfg/DFGSpeculativeJIT.h:
+        (JSC::DFG::SpeculativeJIT::callOperation):
+        (SpeculativeJIT):
+        (SpeculateIntegerOperand):
+        (JSC::DFG::SpeculateIntegerOperand::use):
+        (SpeculateDoubleOperand):
+        (JSC::DFG::SpeculateDoubleOperand::use):
+        * dfg/DFGSpeculativeJIT32_64.cpp:
+        (DFG):
+        (JSC::DFG::SpeculativeJIT::compileContiguousPutByVal):
+        (JSC::DFG::SpeculativeJIT::compile):
+        * dfg/DFGSpeculativeJIT64.cpp:
+        (JSC::DFG::SpeculativeJIT::compile):
+        * jit/JIT.h:
+        (JSC::JIT::emitInt32GetByVal):
+        (JIT):
+        (JSC::JIT::emitInt32PutByVal):
+        (JSC::JIT::emitDoublePutByVal):
+        (JSC::JIT::emitContiguousPutByVal):
+        * jit/JITExceptions.cpp:
+        (JSC::genericThrow):
+        * jit/JITInlineMethods.h:
+        (JSC::arrayProfileSaw):
+        (JSC::JIT::chooseArrayMode):
+        * jit/JITOpcodes.cpp:
+        (JSC::JIT::emit_op_new_array):
+        (JSC::JIT::emit_op_new_array_with_size):
+        (JSC::JIT::emit_op_new_array_buffer):
+        * jit/JITPropertyAccess.cpp:
+        (JSC::JIT::emit_op_get_by_val):
+        (JSC::JIT::emitDoubleGetByVal):
+        (JSC):
+        (JSC::JIT::emitContiguousGetByVal):
+        (JSC::JIT::emit_op_put_by_val):
+        (JSC::JIT::emitGenericContiguousPutByVal):
+        (JSC::JIT::emitSlow_op_put_by_val):
+        (JSC::JIT::privateCompileGetByVal):
+        (JSC::JIT::privateCompilePutByVal):
+        * jit/JITPropertyAccess32_64.cpp:
+        (JSC::JIT::emit_op_get_by_val):
+        (JSC::JIT::emitContiguousGetByVal):
+        (JSC::JIT::emitDoubleGetByVal):
+        (JSC):
+        (JSC::JIT::emit_op_put_by_val):
+        (JSC::JIT::emitGenericContiguousPutByVal):
+        (JSC::JIT::emitSlow_op_put_by_val):
+        * jit/JITStubs.cpp:
+        (JSC::DEFINE_STUB_FUNCTION):
+        * jit/JITStubs.h:
+        (JSC):
+        * jsc.cpp:
+        (GlobalObject::finishCreation):
+        * llint/LLIntSlowPaths.cpp:
+        (JSC::LLInt::jitCompileAndSetHeuristics):
+        (JSC::LLInt::LLINT_SLOW_PATH_DECL):
+        * llint/LowLevelInterpreter.asm:
+        * llint/LowLevelInterpreter32_64.asm:
+        * llint/LowLevelInterpreter64.asm:
+        * offlineasm/x86.rb:
+        * runtime/ArrayConstructor.cpp:
+        (JSC::constructArrayWithSizeQuirk):
+        * runtime/ArrayConstructor.h:
+        (JSC):
+        * runtime/ArrayPrototype.cpp:
+        (JSC::arrayProtoFuncConcat):
+        (JSC::arrayProtoFuncSlice):
+        (JSC::arrayProtoFuncSplice):
+        (JSC::arrayProtoFuncFilter):
+        (JSC::arrayProtoFuncMap):
+        * runtime/Butterfly.h:
+        (JSC::Butterfly::contiguousInt32):
+        (JSC::Butterfly::contiguousDouble):
+        (JSC::Butterfly::fromContiguous):
+        * runtime/ButterflyInlineMethods.h:
+        (JSC::Butterfly::createUninitializedDuringCollection):
+        * runtime/FunctionPrototype.cpp:
+        (JSC::functionProtoFuncBind):
+        * runtime/IndexingHeaderInlineMethods.h:
+        (JSC::IndexingHeader::indexingPayloadSizeInBytes):
+        * runtime/IndexingType.cpp:
+        (JSC::leastUpperBoundOfIndexingTypes):
+        (JSC):
+        (JSC::leastUpperBoundOfIndexingTypeAndType):
+        (JSC::leastUpperBoundOfIndexingTypeAndValue):
+        (JSC::indexingTypeToString):
+        * runtime/IndexingType.h:
+        (JSC):
+        (JSC::hasUndecided):
+        (JSC::hasInt32):
+        (JSC::hasDouble):
+        * runtime/JSArray.cpp:
+        (JSC::JSArray::setLength):
+        (JSC::JSArray::pop):
+        (JSC::JSArray::push):
+        (JSC::JSArray::shiftCountWithAnyIndexingType):
+        (JSC::JSArray::unshiftCountWithAnyIndexingType):
+        (JSC::compareNumbersForQSortWithInt32):
+        (JSC):
+        (JSC::compareNumbersForQSortWithDouble):
+        (JSC::JSArray::sortNumericVector):
+        (JSC::JSArray::sortNumeric):
+        (JSC::JSArray::sortCompactedVector):
+        (JSC::JSArray::sort):
+        (JSC::JSArray::sortVector):
+        (JSC::JSArray::fillArgList):
+        (JSC::JSArray::copyToArguments):
+        (JSC::JSArray::compactForSorting):
+        * runtime/JSArray.h:
+        (JSArray):
+        (JSC::createContiguousArrayButterfly):
+        (JSC::JSArray::create):
+        (JSC::JSArray::tryCreateUninitialized):
+        * runtime/JSGlobalObject.cpp:
+        (JSC::JSGlobalObject::reset):
+        (JSC):
+        (JSC::JSGlobalObject::haveABadTime):
+        (JSC::JSGlobalObject::visitChildren):
+        * runtime/JSGlobalObject.h:
+        (JSGlobalObject):
+        (JSC::JSGlobalObject::originalArrayStructureForIndexingType):
+        (JSC::JSGlobalObject::arrayStructureForIndexingTypeDuringAllocation):
+        (JSC::JSGlobalObject::arrayStructureForProfileDuringAllocation):
+        (JSC::JSGlobalObject::isOriginalArrayStructure):
+        (JSC::constructEmptyArray):
+        (JSC::constructArray):
+        * runtime/JSObject.cpp:
+        (JSC::JSObject::copyButterfly):
+        (JSC::JSObject::getOwnPropertySlotByIndex):
+        (JSC::JSObject::putByIndex):
+        (JSC::JSObject::enterDictionaryIndexingMode):
+        (JSC::JSObject::createInitialIndexedStorage):
+        (JSC):
+        (JSC::JSObject::createInitialUndecided):
+        (JSC::JSObject::createInitialInt32):
+        (JSC::JSObject::createInitialDouble):
+        (JSC::JSObject::createInitialContiguous):
+        (JSC::JSObject::convertUndecidedToInt32):
+        (JSC::JSObject::convertUndecidedToDouble):
+        (JSC::JSObject::convertUndecidedToContiguous):
+        (JSC::JSObject::constructConvertedArrayStorageWithoutCopyingElements):
+        (JSC::JSObject::convertUndecidedToArrayStorage):
+        (JSC::JSObject::convertInt32ToDouble):
+        (JSC::JSObject::convertInt32ToContiguous):
+        (JSC::JSObject::convertInt32ToArrayStorage):
+        (JSC::JSObject::convertDoubleToContiguous):
+        (JSC::JSObject::convertDoubleToArrayStorage):
+        (JSC::JSObject::convertContiguousToArrayStorage):
+        (JSC::JSObject::convertUndecidedForValue):
+        (JSC::JSObject::convertInt32ForValue):
+        (JSC::JSObject::setIndexQuicklyToUndecided):
+        (JSC::JSObject::convertInt32ToDoubleOrContiguousWhilePerformingSetIndex):
+        (JSC::JSObject::convertDoubleToContiguousWhilePerformingSetIndex):
+        (JSC::JSObject::ensureInt32Slow):
+        (JSC::JSObject::ensureDoubleSlow):
+        (JSC::JSObject::ensureContiguousSlow):
+        (JSC::JSObject::ensureArrayStorageSlow):
+        (JSC::JSObject::ensureArrayStorageExistsAndEnterDictionaryIndexingMode):
+        (JSC::JSObject::switchToSlowPutArrayStorage):
+        (JSC::JSObject::deletePropertyByIndex):
+        (JSC::JSObject::getOwnPropertyNames):
+        (JSC::JSObject::putByIndexBeyondVectorLengthWithoutAttributes):
+        (JSC::JSObject::putByIndexBeyondVectorLength):
+        (JSC::JSObject::putDirectIndexBeyondVectorLength):
+        (JSC::JSObject::getNewVectorLength):
+        (JSC::JSObject::countElements):
+        (JSC::JSObject::ensureLengthSlow):
+        (JSC::JSObject::getOwnPropertyDescriptor):
+        * runtime/JSObject.h:
+        (JSC::JSObject::getArrayLength):
+        (JSC::JSObject::getVectorLength):
+        (JSC::JSObject::canGetIndexQuickly):
+        (JSC::JSObject::getIndexQuickly):
+        (JSC::JSObject::tryGetIndexQuickly):
+        (JSC::JSObject::canSetIndexQuickly):
+        (JSC::JSObject::canSetIndexQuicklyForPutDirect):
+        (JSC::JSObject::setIndexQuickly):
+        (JSC::JSObject::initializeIndex):
+        (JSC::JSObject::hasSparseMap):
+        (JSC::JSObject::inSparseIndexingMode):
+        (JSObject):
+        (JSC::JSObject::ensureInt32):
+        (JSC::JSObject::ensureDouble):
+        (JSC::JSObject::ensureLength):
+        (JSC::JSObject::indexingData):
+        (JSC::JSObject::currentIndexingData):
+        (JSC::JSObject::getHolyIndexQuickly):
+        (JSC::JSObject::relevantLength):
+        (JSC::JSObject::currentRelevantLength):
+        * runtime/JSValue.cpp:
+        (JSC::JSValue::description):
+        * runtime/LiteralParser.cpp:
+        (JSC::::parse):
+        * runtime/ObjectConstructor.cpp:
+        (JSC::objectConstructorGetOwnPropertyNames):
+        (JSC::objectConstructorKeys):
+        * runtime/StringPrototype.cpp:
+        (JSC::stringProtoFuncMatch):
+        (JSC::stringProtoFuncSplit):
+        * runtime/Structure.cpp:
+        (JSC::Structure::nonPropertyTransition):
+        * runtime/StructureTransitionTable.h:
+        (JSC::newIndexingType):
+
 2012-11-08  Balazs Kilvady  <kilvadyb@homejinni.com>
 
         ASSERT problem on MIPS
index d68a22b..951138b 100644 (file)
@@ -83,6 +83,8 @@ javascriptcore_sources += \
        Source/JavaScriptCore/assembler/RepatchBuffer.h \
        Source/JavaScriptCore/assembler/SH4Assembler.h \
        Source/JavaScriptCore/assembler/X86Assembler.h \
+       Source/JavaScriptCore/bytecode/ArrayAllocationProfile.cpp \
+       Source/JavaScriptCore/bytecode/ArrayAllocationProfile.h \
        Source/JavaScriptCore/bytecode/ArrayProfile.cpp \
        Source/JavaScriptCore/bytecode/ArrayProfile.h \
        Source/JavaScriptCore/bytecode/ByValInfo.h \
index b231005..3ec6dd2 100755 (executable)
@@ -110,11 +110,12 @@ EXPORTS
     ?computeHash@SHA1@WTF@@QAEXAAV?$Vector@E$0BE@@2@@Z
     ?configurable@PropertyDescriptor@JSC@@QBE_NXZ
     ?construct@JSC@@YAPAVJSObject@1@PAVExecState@1@VJSValue@1@W4ConstructType@1@ABTConstructData@1@ABVArgList@1@@Z
-    ?constructArray@JSC@@YAPAVJSArray@1@PAVExecState@1@ABVArgList@1@@Z
     ?constructEmptyObject@JSC@@YAPAVJSObject@1@PAVExecState@1@@Z
     ?constructFunctionSkippingEvalEnabledCheck@JSC@@YAPAVJSObject@1@PAVExecState@1@PAVJSGlobalObject@1@ABVArgList@1@ABVIdentifier@1@ABVString@WTF@@ABVTextPosition@8@@Z
     ?constructNumber@JSC@@YAPAVNumberObject@1@PAVExecState@1@PAVJSGlobalObject@1@VJSValue@1@@Z
     ?constructString@JSC@@YAPAVStringObject@1@PAVExecState@1@PAVJSGlobalObject@1@VJSValue@1@@Z
+    ?convertDoubleToContiguousWhilePerformingSetIndex@JSObject@JSC@@AAEXAAVJSGlobalData@2@IVJSValue@2@@Z
+    ?convertInt32ToDoubleOrContiguousWhilePerformingSetIndex@JSObject@JSC@@AAEXAAVJSGlobalData@2@IVJSValue@2@@Z
     ?convertLatin1ToUTF8@Unicode@WTF@@YA?AW4ConversionResult@12@PAPBEPBEPAPADPAD@Z
     ?convertUTF16ToUTF8@Unicode@WTF@@YA?AW4ConversionResult@12@PAPB_WPB_WPAPADPAD_N@Z
     ?convertUTF8ToUTF16@Unicode@WTF@@YA?AW4ConversionResult@12@PAPBDPBDPAPA_WPA_WPA_N_N@Z
@@ -333,6 +334,7 @@ EXPORTS
     ?setGarbageCollectionTimerEnabled@Heap@JSC@@QAEX_N@Z
     ?setGetter@PropertyDescriptor@JSC@@QAEXVJSValue@2@@Z
     ?setGlobalThis@JSGlobalObject@JSC@@IAEXAAVJSGlobalData@2@PAVJSObject@2@@Z
+    ?setIndexQuicklyToUndecided@JSObject@JSC@@AAEXAAVJSGlobalData@2@IVJSValue@2@@Z
     ?setLoc@StatementNode@JSC@@QAEXHH@Z
     ?setMainThreadCallbacksPaused@WTF@@YAX_N@Z
     ?setOption@Options@JSC@@SA_NPBD@Z
@@ -402,6 +404,7 @@ EXPORTS
     ?unlock@Mutex@WTF@@QAEXXZ
     ?unlockAtomicallyInitializedStaticMutex@WTF@@YAXXZ
     ?unprotect@Heap@JSC@@QAE_NVJSValue@2@@Z
+    ?updateIndexingType@ArrayAllocationProfile@JSC@@QAEXXZ
     ?validate@SlotVisitor@JSC@@CAXPAVJSCell@2@@Z
     ?visitChildren@JSGlobalObject@JSC@@SAXPAVJSCell@2@AAVSlotVisitor@2@@Z
     ?visitChildren@JSObject@JSC@@SAXPAVJSCell@2@AAVSlotVisitor@2@@Z
index c63231c..55f30ee 100644 (file)
                        Name="bytecode"
                        >
                        <File
+                               RelativePath="..\..\bytecode\ArrayAllocationProfile.cpp"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\bytecode\ArrayAllocationProfile.h"
+                               >
+                       </File>
+                       <File
                                RelativePath="..\..\bytecode\ArrayProfile.cpp"
                                >
                        </File>
index 3cada1c..15a536e 100644 (file)
                0F7B294C14C3CD43007C3DB1 /* DFGByteCodeCache.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F5F08CC146BE602000472A9 /* DFGByteCodeCache.h */; settings = {ATTRIBUTES = (Private, ); }; };
                0F7B294D14C3CD4C007C3DB1 /* DFGCommon.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FC0977E1469EBC400CF2442 /* DFGCommon.h */; settings = {ATTRIBUTES = (Private, ); }; };
                0F8023EA1613832B00A0BA45 /* ByValInfo.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F8023E91613832300A0BA45 /* ByValInfo.h */; settings = {ATTRIBUTES = (Private, ); }; };
+               0F8335B71639C1E6001443B5 /* ArrayAllocationProfile.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F8335B41639C1E3001443B5 /* ArrayAllocationProfile.cpp */; };
+               0F8335B81639C1EA001443B5 /* ArrayAllocationProfile.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F8335B51639C1E3001443B5 /* ArrayAllocationProfile.h */; settings = {ATTRIBUTES = (Private, ); }; };
                0F919D0C157EE09F004A4E7D /* JSSymbolTableObject.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F919D09157EE09D004A4E7D /* JSSymbolTableObject.cpp */; };
                0F919D0D157EE0A2004A4E7D /* JSSymbolTableObject.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F919D0A157EE09D004A4E7D /* JSSymbolTableObject.h */; settings = {ATTRIBUTES = (Private, ); }; };
                0F919D10157F3329004A4E7D /* JSSegmentedVariableObject.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F919D0E157F3327004A4E7D /* JSSegmentedVariableObject.cpp */; };
                0F7700911402FF280078EB39 /* SamplingCounter.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SamplingCounter.cpp; sourceTree = "<group>"; };
                0F7B294814C3CD23007C3DB1 /* DFGCCallHelpers.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGCCallHelpers.h; path = dfg/DFGCCallHelpers.h; sourceTree = "<group>"; };
                0F8023E91613832300A0BA45 /* ByValInfo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ByValInfo.h; sourceTree = "<group>"; };
+               0F8335B41639C1E3001443B5 /* ArrayAllocationProfile.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ArrayAllocationProfile.cpp; sourceTree = "<group>"; };
+               0F8335B51639C1E3001443B5 /* ArrayAllocationProfile.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ArrayAllocationProfile.h; sourceTree = "<group>"; };
                0F919D09157EE09D004A4E7D /* JSSymbolTableObject.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSSymbolTableObject.cpp; sourceTree = "<group>"; };
                0F919D0A157EE09D004A4E7D /* JSSymbolTableObject.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSSymbolTableObject.h; sourceTree = "<group>"; };
                0F919D0E157F3327004A4E7D /* JSSegmentedVariableObject.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSSegmentedVariableObject.cpp; sourceTree = "<group>"; };
                969A078F0ED1D3AE00F1F681 /* bytecode */ = {
                        isa = PBXGroup;
                        children = (
+                               0F8335B41639C1E3001443B5 /* ArrayAllocationProfile.cpp */,
+                               0F8335B51639C1E3001443B5 /* ArrayAllocationProfile.h */,
                                0F63945115D07051006A597C /* ArrayProfile.cpp */,
                                0F63945215D07051006A597C /* ArrayProfile.h */,
                                0F21C27E14BEAA8000ADC64B /* BytecodeConventions.h */,
                                0FEB3ECD16237F4D00AB67AD /* TypedArrayDescriptor.h in Headers */,
                                0F256C361627B0AD007F2783 /* DFGCallArrayAllocatorSlowPathGenerator.h in Headers */,
                                C2239D1B16262BDD005AC5FD /* GCThread.h in Headers */,
+                               0F8335B81639C1EA001443B5 /* ArrayAllocationProfile.h in Headers */,
                                A7B601821639FD2A00372BA3 /* UnlinkedCodeBlock.h in Headers */,
                                A77F1822164088B200640A47 /* CodeCache.h in Headers */,
                                A77F1825164192C700640A47 /* ParserModes.h in Headers */,
                                C24D31E2161CD695002AA4DB /* HeapStatistics.cpp in Sources */,
                                C2239D1716262BDD005AC5FD /* CopyVisitor.cpp in Sources */,
                                C2239D1A16262BDD005AC5FD /* GCThread.cpp in Sources */,
+                               0F8335B71639C1E6001443B5 /* ArrayAllocationProfile.cpp in Sources */,
                                A76F279415F13C9600517D67 /* UnlinkedCodeBlock.cpp in Sources */,
                                A77F1821164088B200640A47 /* CodeCache.cpp in Sources */,
                        );
index b0fcc16..f978fb4 100644 (file)
@@ -50,6 +50,7 @@ SOURCES += \
     assembler/MacroAssembler.cpp \
     assembler/MacroAssemblerARM.cpp \
     assembler/MacroAssemblerSH4.cpp \
+    bytecode/ArrayAllocationProfile.cpp \
     bytecode/ArrayProfile.cpp \
     bytecode/CallLinkInfo.cpp \
     bytecode/CallLinkStatus.cpp \
index c75adb7..673031b 100644 (file)
@@ -586,6 +586,13 @@ public:
 
     public:
         typedef Vector<Jump, 16> JumpVector;
+        
+        JumpList() { }
+        
+        JumpList(Jump jump)
+        {
+            append(jump);
+        }
 
         void link(AbstractMacroAssembler<AssemblerType>* masm)
         {
index 66db26a..53cb80c 100644 (file)
@@ -826,11 +826,15 @@ public:
             m_assembler.ucomisd_rr(right, left);
 
         if (cond == DoubleEqual) {
+            if (left == right)
+                return Jump(m_assembler.jnp());
             Jump isUnordered(m_assembler.jp());
             Jump result = Jump(m_assembler.je());
             isUnordered.link(this);
             return result;
         } else if (cond == DoubleNotEqualOrUnordered) {
+            if (left == right)
+                return Jump(m_assembler.jp());
             Jump isUnordered(m_assembler.jp());
             Jump isEqual(m_assembler.je());
             isUnordered.link(this);
index ecb178e..4d08b70 100644 (file)
@@ -1475,6 +1475,12 @@ public:
         return m_formatter.immediateRel32();
     }
 
+    AssemblerLabel jnp()
+    {
+        m_formatter.twoByteOp(jccRel32(ConditionNP));
+        return m_formatter.immediateRel32();
+    }
+
     AssemblerLabel jp()
     {
         m_formatter.twoByteOp(jccRel32(ConditionP));
@@ -2314,6 +2320,9 @@ private:
         // Format a REX prefix byte.
         inline void emitRex(bool w, int r, int x, int b)
         {
+            ASSERT(r >= 0);
+            ASSERT(x >= 0);
+            ASSERT(b >= 0);
             m_buffer.putByteUnchecked(PRE_REX | ((int)w << 3) | ((r>>3)<<2) | ((x>>3)<<1) | (b>>3));
         }
 
diff --git a/Source/JavaScriptCore/bytecode/ArrayAllocationProfile.cpp b/Source/JavaScriptCore/bytecode/ArrayAllocationProfile.cpp
new file mode 100644 (file)
index 0000000..aa682da
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+ * 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. 
+ */
+
+#include "config.h"
+#include "ArrayAllocationProfile.h"
+
+namespace JSC {
+
+void ArrayAllocationProfile::updateIndexingType()
+{
+    if (!m_lastArray)
+        return;
+    m_currentIndexingType = leastUpperBoundOfIndexingTypes(m_currentIndexingType, m_lastArray->structure()->indexingType());
+    m_lastArray = 0;
+}
+
+} // namespace JSC
+
diff --git a/Source/JavaScriptCore/bytecode/ArrayAllocationProfile.h b/Source/JavaScriptCore/bytecode/ArrayAllocationProfile.h
new file mode 100644 (file)
index 0000000..a1647fa
--- /dev/null
@@ -0,0 +1,80 @@
+/*
+ * 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 ArrayAllocationProfile_h
+#define ArrayAllocationProfile_h
+
+#include "IndexingType.h"
+#include "JSArray.h"
+
+namespace JSC {
+
+class ArrayAllocationProfile {
+public:
+    ArrayAllocationProfile()
+        : m_currentIndexingType(ArrayWithUndecided)
+        , m_lastArray(0)
+    {
+    }
+    
+    IndexingType selectIndexingType()
+    {
+        if (m_lastArray && UNLIKELY(m_lastArray->structure()->indexingType() != m_currentIndexingType))
+            updateIndexingType();
+        return m_currentIndexingType;
+    }
+    
+    JSArray* updateLastAllocation(JSArray* lastArray)
+    {
+        m_lastArray = lastArray;
+        return lastArray;
+    }
+    
+    JS_EXPORT_PRIVATE void updateIndexingType();
+    
+    static IndexingType selectIndexingTypeFor(ArrayAllocationProfile* profile)
+    {
+        if (!profile)
+            return ArrayWithUndecided;
+        return profile->selectIndexingType();
+    }
+    
+    static JSArray* updateLastAllocationFor(ArrayAllocationProfile* profile, JSArray* lastArray)
+    {
+        if (profile)
+            profile->updateLastAllocation(lastArray);
+        return lastArray;
+    }
+
+private:
+    
+    IndexingType m_currentIndexingType;
+    JSArray* m_lastArray;
+};
+
+} // namespace JSC
+
+#endif // ArrayAllocationProfile_h
+
index 5a87380..51baf33 100644 (file)
@@ -65,6 +65,13 @@ const char* arrayModesToString(ArrayModes arrayModes)
     return result;
 }
 
+ArrayModes ArrayProfile::updatedObservedArrayModes() const
+{
+    if (m_lastSeenStructure)
+        return m_observedArrayModes | arrayModeFromStructure(m_lastSeenStructure);
+    return m_observedArrayModes;
+}
+
 void ArrayProfile::computeUpdatedPrediction(CodeBlock* codeBlock, OperationInProgress operation)
 {
     if (m_lastSeenStructure) {
index 376684f..5116cd3 100644 (file)
@@ -45,15 +45,20 @@ typedef unsigned ArrayModes;
 
 #define ALL_NON_ARRAY_ARRAY_MODES                       \
     (asArrayModes(NonArray)                             \
-     | asArrayModes(NonArrayWithContiguous)             \
-     | asArrayModes(NonArrayWithArrayStorage)           \
-     | asArrayModes(NonArrayWithSlowPutArrayStorage))
+    | asArrayModes(NonArrayWithInt32)                   \
+    | asArrayModes(NonArrayWithDouble)                  \
+    | asArrayModes(NonArrayWithContiguous)              \
+    | asArrayModes(NonArrayWithArrayStorage)            \
+    | asArrayModes(NonArrayWithSlowPutArrayStorage))
 
 #define ALL_ARRAY_ARRAY_MODES                           \
     (asArrayModes(ArrayClass)                           \
-     | asArrayModes(ArrayWithContiguous)                \
-     | asArrayModes(ArrayWithArrayStorage)              \
-     | asArrayModes(ArrayWithSlowPutArrayStorage))
+    | asArrayModes(ArrayWithUndecided)                  \
+    | asArrayModes(ArrayWithInt32)                      \
+    | asArrayModes(ArrayWithDouble)                     \
+    | asArrayModes(ArrayWithContiguous)                 \
+    | asArrayModes(ArrayWithArrayStorage)               \
+    | asArrayModes(ArrayWithSlowPutArrayStorage))
 
 #define ALL_ARRAY_MODES (ALL_NON_ARRAY_ARRAY_MODES | ALL_ARRAY_ARRAY_MODES)
 
@@ -79,6 +84,36 @@ inline bool arrayModesAlreadyChecked(ArrayModes proven, ArrayModes expected)
     return (expected | proven) == expected;
 }
 
+inline bool arrayModesInclude(ArrayModes arrayModes, IndexingType shape)
+{
+    return !!(arrayModes & (asArrayModes(NonArray | shape) | asArrayModes(ArrayClass | shape)));
+}
+
+inline bool shouldUseSlowPutArrayStorage(ArrayModes arrayModes)
+{
+    return arrayModesInclude(arrayModes, SlowPutArrayStorageShape);
+}
+
+inline bool shouldUseFastArrayStorage(ArrayModes arrayModes)
+{
+    return arrayModesInclude(arrayModes, ArrayStorageShape);
+}
+
+inline bool shouldUseContiguous(ArrayModes arrayModes)
+{
+    return arrayModesInclude(arrayModes, ContiguousShape);
+}
+
+inline bool shouldUseDouble(ArrayModes arrayModes)
+{
+    return arrayModesInclude(arrayModes, DoubleShape);
+}
+
+inline bool shouldUseInt32(ArrayModes arrayModes)
+{
+    return arrayModesInclude(arrayModes, Int32Shape);
+}
+
 class ArrayProfile {
 public:
     ArrayProfile()
@@ -128,6 +163,7 @@ public:
         return !structureIsPolymorphic() && m_expectedStructure;
     }
     ArrayModes observedArrayModes() const { return m_observedArrayModes; }
+    ArrayModes updatedObservedArrayModes() const; // Computes the observed array modes without updating the profile.
     bool mayInterceptIndexedAccesses() const { return m_mayInterceptIndexedAccesses; }
     
     bool mayStoreToHole() const { return m_mayStoreToHole; }
index 8cba446..3f79967 100644 (file)
@@ -39,6 +39,8 @@
 namespace JSC {
 
 enum JITArrayMode {
+    JITInt32,
+    JITDouble,
     JITContiguous,
     JITArrayStorage,
     JITInt8Array,
@@ -55,6 +57,8 @@ enum JITArrayMode {
 inline bool isOptimizableIndexingType(IndexingType indexingType)
 {
     switch (indexingType) {
+    case ALL_INT32_INDEXING_TYPES:
+    case ALL_DOUBLE_INDEXING_TYPES:
     case ALL_CONTIGUOUS_INDEXING_TYPES:
     case ARRAY_WITH_ARRAY_STORAGE_INDEXING_TYPES:
         return true;
@@ -77,6 +81,10 @@ inline bool hasOptimizableIndexing(Structure* structure)
 inline JITArrayMode jitArrayModeForIndexingType(IndexingType indexingType)
 {
     switch (indexingType) {
+    case ALL_INT32_INDEXING_TYPES:
+        return JITInt32;
+    case ALL_DOUBLE_INDEXING_TYPES:
+        return JITDouble;
     case ALL_CONTIGUOUS_INDEXING_TYPES:
         return JITContiguous;
     case ARRAY_WITH_ARRAY_STORAGE_INDEXING_TYPES:
index 5686d5d..69d7c20 100644 (file)
@@ -654,6 +654,7 @@ void CodeBlock::dump(ExecState* exec, const Vector<Instruction>::const_iterator&
             int argc = (++it)->u.operand;
             dataLog("[%4d] new_array\t %s, %s, %d", location, registerName(exec, dst).data(), registerName(exec, argv).data(), argc);
             dumpBytecodeCommentAndNewLine(location);
+            ++it; // Skip array allocation profile.
             break;
         }
         case op_new_array_with_size: {
@@ -661,6 +662,7 @@ void CodeBlock::dump(ExecState* exec, const Vector<Instruction>::const_iterator&
             int length = (++it)->u.operand;
             dataLog("[%4d] new_array_with_size\t %s, %s", location, registerName(exec, dst).data(), registerName(exec, length).data());
             dumpBytecodeCommentAndNewLine(location);
+            ++it; // Skip array allocation profile.
             break;
         }
         case op_new_array_buffer: {
@@ -669,6 +671,7 @@ void CodeBlock::dump(ExecState* exec, const Vector<Instruction>::const_iterator&
             int argc = (++it)->u.operand;
             dataLog("[%4d] new_array_buffer\t %s, %d, %d", location, registerName(exec, dst).data(), argv, argc);
             dumpBytecodeCommentAndNewLine(location);
+            ++it; // Skip array allocation profile.
             break;
         }
         case op_new_regexp: {
@@ -1746,6 +1749,8 @@ CodeBlock::CodeBlock(ScriptExecutable* ownerExecutable, UnlinkedCodeBlock* unlin
 #if ENABLE(DFG_JIT)
     if (size_t size = unlinkedCodeBlock->numberOfArrayProfiles())
         m_arrayProfiles.grow(size);
+    if (size_t size = unlinkedCodeBlock->numberOfArrayAllocationProfiles())
+        m_arrayAllocationProfiles.grow(size);
     if (size_t size = unlinkedCodeBlock->numberOfValueProfiles())
         m_valueProfiles.grow(size);
 #endif
@@ -1800,6 +1805,14 @@ CodeBlock::CodeBlock(ScriptExecutable* ownerExecutable, UnlinkedCodeBlock* unlin
             break;
         }
 
+        case op_new_array:
+        case op_new_array_buffer:
+        case op_new_array_with_size: {
+            int arrayAllocationProfileIndex = pc[i + opLength - 1].u.operand;
+            instructions[i + opLength - 1] = &m_arrayAllocationProfiles[arrayAllocationProfileIndex];
+            break;
+        }
+
         case op_call:
         case op_call_eval: {
             int arrayProfileIndex = pc[i + opLength - 1].u.operand;
@@ -2790,18 +2803,28 @@ void CodeBlock::updateAllPredictionsAndCountLiveness(
 #if ENABLE(DFG_JIT)
     m_lazyOperandValueProfiles.computeUpdatedPredictions(operation);
 #endif
-    
-    // Don't count the array profiles towards statistics, since each array profile
-    // site also has a value profile site - so we already know whether or not it's
-    // live.
+}
+
+void CodeBlock::updateAllValueProfilePredictions(OperationInProgress operation)
+{
+    unsigned ignoredValue1, ignoredValue2;
+    updateAllPredictionsAndCountLiveness(operation, ignoredValue1, ignoredValue2);
+}
+
+void CodeBlock::updateAllArrayPredictions(OperationInProgress operation)
+{
     for (unsigned i = m_arrayProfiles.size(); i--;)
         m_arrayProfiles[i].computeUpdatedPrediction(this, operation);
+    
+    // Don't count these either, for similar reasons.
+    for (unsigned i = m_arrayAllocationProfiles.size(); i--;)
+        m_arrayAllocationProfiles[i].updateIndexingType();
 }
 
 void CodeBlock::updateAllPredictions(OperationInProgress operation)
 {
-    unsigned ignoredValue1, ignoredValue2;
-    updateAllPredictionsAndCountLiveness(operation, ignoredValue1, ignoredValue2);
+    updateAllValueProfilePredictions(operation);
+    updateAllArrayPredictions(operation);
 }
 
 bool CodeBlock::shouldOptimizeNow()
@@ -2817,12 +2840,14 @@ bool CodeBlock::shouldOptimizeNow()
     if (m_optimizationDelayCounter >= Options::maximumOptimizationDelay())
         return true;
     
+    updateAllArrayPredictions();
+    
     unsigned numberOfLiveNonArgumentValueProfiles;
     unsigned numberOfSamplesInProfiles;
     updateAllPredictionsAndCountLiveness(NoOperation, numberOfLiveNonArgumentValueProfiles, numberOfSamplesInProfiles);
 
 #if ENABLE(JIT_VERBOSE_OSR)
-    dataLog("Profile hotness: %lf, %lf\n", (double)numberOfLiveNonArgumentValueProfiles / numberOfValueProfiles(), (double)numberOfSamplesInProfiles / ValueProfile::numberOfBuckets / numberOfValueProfiles());
+    dataLog("Profile hotness: %lf (%u / %u), %lf (%u / %u)\n", (double)numberOfLiveNonArgumentValueProfiles / numberOfValueProfiles(), numberOfLiveNonArgumentValueProfiles, numberOfValueProfiles(), (double)numberOfSamplesInProfiles / ValueProfile::numberOfBuckets / numberOfValueProfiles(), numberOfSamplesInProfiles, ValueProfile::numberOfBuckets * numberOfValueProfiles());
 #endif
 
     if ((!numberOfValueProfiles() || (double)numberOfLiveNonArgumentValueProfiles / numberOfValueProfiles() >= Options::desiredProfileLivenessRate())
index a280649..0199935 100644 (file)
@@ -755,6 +755,13 @@ namespace JSC {
         }
         ArrayProfile* getArrayProfile(unsigned bytecodeOffset);
         ArrayProfile* getOrAddArrayProfile(unsigned bytecodeOffset);
+        
+        unsigned numberOfArrayAllocationProfiles() const { return m_arrayAllocationProfiles.size(); }
+        ArrayAllocationProfile* addArrayAllocationProfile()
+        {
+            m_arrayAllocationProfiles.append(ArrayAllocationProfile());
+            return &m_arrayAllocationProfiles.last();
+        }
 #endif
 
         // Exception handling support
@@ -1145,9 +1152,13 @@ namespace JSC {
 
 #if ENABLE(VALUE_PROFILER)
         bool shouldOptimizeNow();
+        void updateAllValueProfilePredictions(OperationInProgress = NoOperation);
+        void updateAllArrayPredictions(OperationInProgress = NoOperation);
         void updateAllPredictions(OperationInProgress = NoOperation);
 #else
         bool shouldOptimizeNow() { return false; }
+        void updateAllValueProfilePredictions(OperationInProgress = NoOperation) { }
+        void updateAllArrayPredictions(OperationInProgress = NoOperation) { }
         void updateAllPredictions(OperationInProgress = NoOperation) { }
 #endif
         
@@ -1330,6 +1341,7 @@ namespace JSC {
         SegmentedVector<ValueProfile, 8> m_valueProfiles;
         SegmentedVector<RareCaseProfile, 8> m_rareCaseProfiles;
         SegmentedVector<RareCaseProfile, 8> m_specialFastCaseProfiles;
+        SegmentedVector<ArrayAllocationProfile, 8> m_arrayAllocationProfiles;
         ArrayProfileVector m_arrayProfiles;
         unsigned m_executionEntryCount;
 #endif
index 60d313a..7132adf 100644 (file)
@@ -58,6 +58,8 @@ inline const char* exitKindToString(ExitKind kind)
         return "BadCache";
     case BadWeakConstantCache:
         return "BadWeakConstantCache";
+    case BadIndexingType:
+        return "BadIndexingType";
     case Overflow:
         return "Overflow";
     case NegativeZero:
index 9fcf509..50b80e0 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2008 Apple Inc. All rights reserved.
+ * Copyright (C) 2008, 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
@@ -47,6 +47,7 @@ namespace JSC {
     // curently actually use PolymorphicAccessStructureLists, which we should).  Anyway, this seems like the best
     // solution for now - will need to something smarter if/when we actually want mixed-mode operation.
 
+    class ArrayAllocationProfile;
     class ArrayProfile;
     class JSCell;
     class Structure;
@@ -193,6 +194,7 @@ namespace JSC {
         
         Instruction(ValueProfile* profile) { u.profile = profile; }
         Instruction(ArrayProfile* profile) { u.arrayProfile = profile; }
+        Instruction(ArrayAllocationProfile* profile) { u.arrayAllocationProfile = profile; }
         
         Instruction(WriteBarrier<Unknown>* registerPointer) { u.registerPointer = registerPointer; }
         
@@ -212,6 +214,7 @@ namespace JSC {
             LLIntCallLinkInfo* callLinkInfo;
             ValueProfile* profile;
             ArrayProfile* arrayProfile;
+            ArrayAllocationProfile* arrayAllocationProfile;
             void* pointer;
             bool* predicatePointer;
         } u;
index 8979d0b..38d314d 100644 (file)
@@ -48,9 +48,9 @@ namespace JSC {
         macro(op_convert_this, 3) \
         \
         macro(op_new_object, 2) \
-        macro(op_new_array, 4) \
-        macro(op_new_array_with_size, 3) \
-        macro(op_new_array_buffer, 4) \
+        macro(op_new_array, 5) \
+        macro(op_new_array_with_size, 4) \
+        macro(op_new_array_buffer, 5) \
         macro(op_new_regexp, 3) \
         macro(op_mov, 3) \
         \
index 09ba9fd..2832aef 100644 (file)
@@ -61,6 +61,7 @@ static const SpeculatedType SpecInt32             = 0x00800000; // It's definite
 static const SpeculatedType SpecDoubleReal        = 0x01000000; // It's definitely a non-NaN double.
 static const SpeculatedType SpecDoubleNaN         = 0x02000000; // It's definitely a NaN.
 static const SpeculatedType SpecDouble            = 0x03000000; // It's either a non-NaN or a NaN double.
+static const SpeculatedType SpecRealNumber        = 0x01800000; // It's either an Int32 or a DoubleReal.
 static const SpeculatedType SpecNumber            = 0x03800000; // It's either an Int32 or a Double.
 static const SpeculatedType SpecBoolean           = 0x04000000; // It's definitely a Boolean.
 static const SpeculatedType SpecOther             = 0x08000000; // It's definitely none of the above.
@@ -238,6 +239,11 @@ inline bool isDoubleSpeculation(SpeculatedType value)
     return !!value && (value & SpecDouble) == value;
 }
 
+inline bool isRealNumberSpeculation(SpeculatedType value)
+{
+    return !!(value & SpecRealNumber) && !(value & ~SpecRealNumber);
+}
+
 inline bool isNumberSpeculation(SpeculatedType value)
 {
     return !!(value & SpecNumber) && !(value & ~SpecNumber);
index 8aa4840..3076eba 100644 (file)
@@ -171,6 +171,7 @@ UnlinkedCodeBlock::UnlinkedCodeBlock(JSGlobalData* globalData, Structure* struct
     , m_resolveOperationCount(0)
     , m_putToBaseOperationCount(1)
     , m_arrayProfileCount(0)
+    , m_arrayAllocationProfileCount(0)
     , m_valueProfileCount(0)
     , m_llintCallLinkInfoCount(0)
 #if ENABLE(BYTECODE_COMMENTS)
index bf3f5fd..cfe32db 100644 (file)
@@ -56,6 +56,7 @@ class UnlinkedFunctionCodeBlock;
 
 typedef unsigned UnlinkedValueProfile;
 typedef unsigned UnlinkedArrayProfile;
+typedef unsigned UnlinkedArrayAllocationProfile;
 typedef unsigned UnlinkedLLIntCallLinkInfo;
 
 struct ExecutableInfo {
@@ -392,6 +393,8 @@ public:
 
     UnlinkedArrayProfile addArrayProfile() { return m_arrayProfileCount++; }
     unsigned numberOfArrayProfiles() { return m_arrayProfileCount; }
+    UnlinkedArrayAllocationProfile addArrayAllocationProfile() { return m_arrayAllocationProfileCount++; }
+    unsigned numberOfArrayAllocationProfiles() { return m_arrayAllocationProfileCount; }
     UnlinkedValueProfile addValueProfile() { return m_valueProfileCount++; }
     unsigned numberOfValueProfiles() { return m_valueProfileCount; }
 
@@ -518,6 +521,7 @@ private:
     unsigned m_resolveOperationCount;
     unsigned m_putToBaseOperationCount;
     unsigned m_arrayProfileCount;
+    unsigned m_arrayAllocationProfileCount;
     unsigned m_valueProfileCount;
     unsigned m_llintCallLinkInfoCount;
 
index b118725..b1b9de6 100644 (file)
@@ -716,6 +716,15 @@ UnlinkedArrayProfile BytecodeGenerator::newArrayProfile()
 #endif
 }
 
+UnlinkedArrayAllocationProfile BytecodeGenerator::newArrayAllocationProfile()
+{
+#if ENABLE(VALUE_PROFILER)
+    return m_codeBlock->addArrayAllocationProfile();
+#else
+    return 0;
+#endif
+}
+
 UnlinkedValueProfile BytecodeGenerator::emitProfiledOpcode(OpcodeID opcodeID)
 {
 #if ENABLE(VALUE_PROFILER)
@@ -1605,6 +1614,7 @@ RegisterID* BytecodeGenerator::emitNewArray(RegisterID* dst, ElementNode* elemen
             instructions().append(dst->index());
             instructions().append(constantBufferIndex);
             instructions().append(length);
+            instructions().append(newArrayAllocationProfile());
             return dst;
         }
     }
@@ -1622,6 +1632,7 @@ RegisterID* BytecodeGenerator::emitNewArray(RegisterID* dst, ElementNode* elemen
     instructions().append(dst->index());
     instructions().append(argv.size() ? argv[0]->index() : 0); // argv
     instructions().append(argv.size()); // argc
+    instructions().append(newArrayAllocationProfile());
     return dst;
 }
 
@@ -1757,12 +1768,14 @@ ExpectedFunction BytecodeGenerator::emitExpectedFunctionSnippet(RegisterID* dst,
                 emitOpcode(op_new_array_with_size);
                 instructions().append(dst->index());
                 instructions().append(callArguments.argumentRegister(0)->index());
+                instructions().append(newArrayAllocationProfile());
             } else {
                 ASSERT(callArguments.argumentCountIncludingThis() == 1);
                 emitOpcode(op_new_array);
                 instructions().append(dst->index());
                 instructions().append(0);
                 instructions().append(0);
+                instructions().append(newArrayAllocationProfile());
             }
         }
         break;
index 828726d..2e7aa20 100644 (file)
@@ -523,6 +523,7 @@ namespace JSC {
 #endif
 
         void emitOpcode(OpcodeID);
+        UnlinkedArrayAllocationProfile newArrayAllocationProfile();
         UnlinkedArrayProfile newArrayProfile();
         UnlinkedValueProfile emitProfiledOpcode(OpcodeID);
         void retrieveLastBinaryOp(int& dstIndex, int& src1Index, int& src2Index);
index e518c24..a0c3f75 100644 (file)
@@ -424,7 +424,10 @@ bool AbstractState::execute(unsigned indexInBlock)
             break;
         }
         speculateNumberUnary(node);
-        forNode(nodeIndex).set(SpecDouble);
+        if (isInt32Speculation(forNode(node.child1()).m_type))
+            forNode(nodeIndex).set(SpecDoubleReal);
+        else
+            forNode(nodeIndex).set(SpecDouble);
         break;
     }
         
@@ -450,7 +453,11 @@ bool AbstractState::execute(unsigned indexInBlock)
         }
         if (Node::shouldSpeculateNumber(m_graph[node.child1()], m_graph[node.child2()])) {
             speculateNumberBinary(node);
-            forNode(nodeIndex).set(SpecDouble);
+            if (isRealNumberSpeculation(forNode(node.child1()).m_type)
+                && isRealNumberSpeculation(forNode(node.child2()).m_type))
+                forNode(nodeIndex).set(SpecDoubleReal);
+            else
+                forNode(nodeIndex).set(SpecDouble);
             break;
         }
         if (node.op() == ValueAdd) {
@@ -522,7 +529,11 @@ bool AbstractState::execute(unsigned indexInBlock)
             break;
         }
         speculateNumberBinary(node);
-        forNode(nodeIndex).set(SpecDouble);
+        if (isRealNumberSpeculation(forNode(node.child1()).m_type)
+            || isRealNumberSpeculation(forNode(node.child2()).m_type))
+            forNode(nodeIndex).set(SpecDoubleReal);
+        else
+            forNode(nodeIndex).set(SpecDouble);
         break;
     }
         
@@ -842,6 +853,7 @@ bool AbstractState::execute(unsigned indexInBlock)
         switch (node.arrayMode().type()) {
         case Array::SelectUsingPredictions:
         case Array::Unprofiled:
+        case Array::Undecided:
             ASSERT_NOT_REACHED();
             break;
         case Array::ForceExit:
@@ -859,6 +871,22 @@ bool AbstractState::execute(unsigned indexInBlock)
             forNode(node.child2()).filter(SpecInt32);
             forNode(nodeIndex).makeTop();
             break;
+        case Array::Int32:
+            forNode(node.child2()).filter(SpecInt32);
+            if (node.arrayMode().isOutOfBounds()) {
+                clobberWorld(node.codeOrigin, indexInBlock);
+                forNode(nodeIndex).makeTop();
+            } else
+                forNode(nodeIndex).set(SpecInt32);
+            break;
+        case Array::Double:
+            forNode(node.child2()).filter(SpecInt32);
+            if (node.arrayMode().isOutOfBounds()) {
+                clobberWorld(node.codeOrigin, indexInBlock);
+                forNode(nodeIndex).makeTop();
+            } else
+                forNode(nodeIndex).set(SpecDoubleReal);
+            break;
         case Array::Contiguous:
         case Array::ArrayStorage:
         case Array::SlowPutArrayStorage:
@@ -926,6 +954,20 @@ bool AbstractState::execute(unsigned indexInBlock)
         case Array::Generic:
             clobberWorld(node.codeOrigin, indexInBlock);
             break;
+        case Array::Int32:
+            forNode(child1).filter(SpecCell);
+            forNode(child2).filter(SpecInt32);
+            forNode(child3).filter(SpecInt32);
+            if (node.arrayMode().isOutOfBounds())
+                clobberWorld(node.codeOrigin, indexInBlock);
+            break;
+        case Array::Double:
+            forNode(child1).filter(SpecCell);
+            forNode(child2).filter(SpecInt32);
+            forNode(child3).filter(SpecRealNumber);
+            if (node.arrayMode().isOutOfBounds())
+                clobberWorld(node.codeOrigin, indexInBlock);
+            break;
         case Array::Contiguous:
         case Array::ArrayStorage:
             forNode(child1).filter(SpecCell);
@@ -1018,6 +1060,16 @@ bool AbstractState::execute(unsigned indexInBlock)
             
     case ArrayPush:
         node.setCanExit(true);
+        switch (node.arrayMode().type()) {
+        case Array::Int32:
+            forNode(node.child2()).filter(SpecInt32);
+            break;
+        case Array::Double:
+            forNode(node.child2()).filter(SpecRealNumber);
+            break;
+        default:
+            break;
+        }
         clobberWorld(node.codeOrigin, indexInBlock);
         forNode(nodeIndex).set(SpecNumber);
         break;
@@ -1122,13 +1174,13 @@ bool AbstractState::execute(unsigned indexInBlock)
             
     case NewArray:
         node.setCanExit(true);
-        forNode(nodeIndex).set(m_graph.globalObjectFor(node.codeOrigin)->arrayStructure());
+        forNode(nodeIndex).set(m_graph.globalObjectFor(node.codeOrigin)->arrayStructureForIndexingTypeDuringAllocation(node.indexingType()));
         m_haveStructures = true;
         break;
         
     case NewArrayBuffer:
         node.setCanExit(true);
-        forNode(nodeIndex).set(m_graph.globalObjectFor(node.codeOrigin)->arrayStructure());
+        forNode(nodeIndex).set(m_graph.globalObjectFor(node.codeOrigin)->arrayStructureForIndexingTypeDuringAllocation(node.indexingType()));
         m_haveStructures = true;
         break;
 
@@ -1384,11 +1436,11 @@ bool AbstractState::execute(unsigned indexInBlock)
         case Array::String:
             forNode(node.child1()).filter(SpecString);
             break;
+        case Array::Int32:
+        case Array::Double:
         case Array::Contiguous:
         case Array::ArrayStorage:
         case Array::SlowPutArrayStorage:
-            // 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);
             break;
         case Array::Arguments:
index 699902a..0d15b9a 100644 (file)
@@ -34,19 +34,46 @@ namespace JSC { namespace DFG {
 
 ArrayMode ArrayMode::fromObserved(ArrayProfile* profile, Array::Action action, bool makeSafe)
 {
-    switch (profile->observedArrayModes()) {
+    ArrayModes observed = profile->observedArrayModes();
+    switch (observed) {
     case 0:
         return ArrayMode(Array::Unprofiled);
     case asArrayModes(NonArray):
         if (action == Array::Write && !profile->mayInterceptIndexedAccesses())
-            return ArrayMode(Array::Contiguous, Array::NonArray, Array::OutOfBounds, Array::Convert); // FIXME: we don't know whether to go to contiguous or array storage. We're making a static guess here. In future we should use exit profiling for this.
+            return ArrayMode(Array::Undecided, Array::NonArray, Array::OutOfBounds, Array::Convert);
         return ArrayMode(Array::SelectUsingPredictions);
+
+    case asArrayModes(ArrayWithUndecided):
+        if (action == Array::Write)
+            return ArrayMode(Array::Undecided, Array::Array, Array::OutOfBounds, Array::Convert);
+        return ArrayMode(Array::Generic);
+        
+    case asArrayModes(NonArray) | asArrayModes(ArrayWithUndecided):
+        if (action == Array::Write && !profile->mayInterceptIndexedAccesses())
+            return ArrayMode(Array::Undecided, Array::PossiblyArray, Array::OutOfBounds, Array::Convert);
+        return ArrayMode(Array::SelectUsingPredictions);
+
+    case asArrayModes(NonArrayWithInt32):
+        return ArrayMode(Array::Int32, Array::NonArray, Array::AsIs).withProfile(profile, makeSafe);
+    case asArrayModes(ArrayWithInt32):
+        return ArrayMode(Array::Int32, Array::Array, Array::AsIs).withProfile(profile, makeSafe);
+    case asArrayModes(NonArrayWithInt32) | asArrayModes(ArrayWithInt32):
+        return ArrayMode(Array::Int32, Array::PossiblyArray, Array::AsIs).withProfile(profile, makeSafe);
+
+    case asArrayModes(NonArrayWithDouble):
+        return ArrayMode(Array::Double, Array::NonArray, Array::AsIs).withProfile(profile, makeSafe);
+    case asArrayModes(ArrayWithDouble):
+        return ArrayMode(Array::Double, Array::Array, Array::AsIs).withProfile(profile, makeSafe);
+    case asArrayModes(NonArrayWithDouble) | asArrayModes(ArrayWithDouble):
+        return ArrayMode(Array::Double, Array::PossiblyArray, Array::AsIs).withProfile(profile, makeSafe);
+
     case asArrayModes(NonArrayWithContiguous):
         return ArrayMode(Array::Contiguous, Array::NonArray, Array::AsIs).withProfile(profile, makeSafe);
     case asArrayModes(ArrayWithContiguous):
         return ArrayMode(Array::Contiguous, Array::Array, Array::AsIs).withProfile(profile, makeSafe);
     case asArrayModes(NonArrayWithContiguous) | asArrayModes(ArrayWithContiguous):
         return ArrayMode(Array::Contiguous, Array::PossiblyArray, Array::AsIs).withProfile(profile, makeSafe);
+
     case asArrayModes(NonArrayWithArrayStorage):
         return ArrayMode(Array::ArrayStorage, Array::NonArray, Array::AsIs).withProfile(profile, makeSafe);
     case asArrayModes(NonArrayWithSlowPutArrayStorage):
@@ -62,36 +89,39 @@ ArrayMode ArrayMode::fromObserved(ArrayProfile* profile, Array::Action action, b
     case asArrayModes(NonArrayWithSlowPutArrayStorage) | asArrayModes(ArrayWithSlowPutArrayStorage):
     case asArrayModes(NonArrayWithArrayStorage) | asArrayModes(ArrayWithArrayStorage) | asArrayModes(NonArrayWithSlowPutArrayStorage) | asArrayModes(ArrayWithSlowPutArrayStorage):
         return ArrayMode(Array::SlowPutArrayStorage, Array::PossiblyArray, Array::AsIs).withProfile(profile, makeSafe);
-    case asArrayModes(NonArrayWithContiguous) | asArrayModes(NonArrayWithArrayStorage):
-        return ArrayMode(Array::ArrayStorage, Array::NonArray, Array::Convert).withProfile(profile, makeSafe);
-    case asArrayModes(ArrayWithContiguous) | asArrayModes(ArrayWithArrayStorage):
-        return ArrayMode(Array::ArrayStorage, Array::Array, Array::Convert).withProfile(profile, makeSafe);
-    case asArrayModes(NonArrayWithContiguous) | asArrayModes(NonArrayWithArrayStorage) | asArrayModes(ArrayWithContiguous) | asArrayModes(ArrayWithArrayStorage):
-        return ArrayMode(Array::ArrayStorage, Array::PossiblyArray, Array::Convert).withProfile(profile, makeSafe);
-    case asArrayModes(NonArray) | asArrayModes(NonArrayWithContiguous):
-        if (action == Array::Write && !profile->mayInterceptIndexedAccesses())
-            return ArrayMode(Array::Contiguous, Array::NonArray, Array::OutOfBounds, Array::Convert);
-        return ArrayMode(Array::SelectUsingPredictions);
-    case asArrayModes(NonArray) | asArrayModes(NonArrayWithContiguous) | asArrayModes(NonArrayWithArrayStorage):
-    case asArrayModes(NonArray) | asArrayModes(NonArrayWithArrayStorage):
-        if (action == Array::Write && !profile->mayInterceptIndexedAccesses())
-            return ArrayMode(Array::ArrayStorage, Array::NonArray, Array::OutOfBounds, Array::Convert);
-        return ArrayMode(Array::SelectUsingPredictions);
-    case asArrayModes(NonArray) | asArrayModes(NonArrayWithSlowPutArrayStorage):
-    case asArrayModes(NonArray) | asArrayModes(NonArrayWithArrayStorage) | asArrayModes(NonArrayWithSlowPutArrayStorage):
-        if (action == Array::Write && !profile->mayInterceptIndexedAccesses())
-            return ArrayMode(Array::SlowPutArrayStorage, Array::NonArray, Array::OutOfBounds, Array::Convert);
-        return ArrayMode(Array::SelectUsingPredictions);
+
     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
-        // the value profiles of the inputs. Hence, we leave it as undecided, and let
-        // the predictions propagator decide later.
-        return ArrayMode(Array::SelectUsingPredictions);
+        if ((observed & asArrayModes(NonArray)) && profile->mayInterceptIndexedAccesses())
+            return ArrayMode(Array::SelectUsingPredictions);
+        
+        Array::Type type;
+        Array::Class arrayClass;
+        
+        if (shouldUseSlowPutArrayStorage(observed))
+            type = Array::SlowPutArrayStorage;
+        else if (shouldUseFastArrayStorage(observed))
+            type = Array::ArrayStorage;
+        else if (shouldUseContiguous(observed))
+            type = Array::Contiguous;
+        else if (shouldUseDouble(observed))
+            type = Array::Double;
+        else if (shouldUseInt32(observed))
+            type = Array::Int32;
+        else
+            type = Array::Undecided;
+        
+        if (observed & (asArrayModes(ArrayWithUndecided) | asArrayModes(ArrayWithInt32) | asArrayModes(ArrayWithDouble) | asArrayModes(ArrayWithContiguous) | asArrayModes(ArrayWithArrayStorage) | asArrayModes(ArrayWithSlowPutArrayStorage)))
+            arrayClass = Array::Array;
+        else if (observed & (asArrayModes(NonArray) | asArrayModes(NonArrayWithInt32) | asArrayModes(NonArrayWithDouble) | asArrayModes(NonArrayWithContiguous) | asArrayModes(NonArrayWithArrayStorage) | asArrayModes(NonArrayWithSlowPutArrayStorage)))
+            arrayClass = Array::NonArray;
+        else
+            arrayClass = Array::PossiblyArray;
+        
+        return ArrayMode(type, arrayClass, Array::Convert).withProfile(profile, makeSafe);
     }
 }
 
-ArrayMode ArrayMode::refine(SpeculatedType base, SpeculatedType index) const
+ArrayMode ArrayMode::refine(SpeculatedType base, SpeculatedType index, SpeculatedType value) const
 {
     if (!base || !index) {
         // It can be that we had a legitimate arrayMode but no incoming predictions. That'll
@@ -104,49 +134,85 @@ ArrayMode ArrayMode::refine(SpeculatedType base, SpeculatedType index) const
     if (!isInt32Speculation(index) || !isCellSpeculation(base))
         return ArrayMode(Array::Generic);
     
-    if (type() == Array::Unprofiled) {
-        // If the indexing type wasn't recorded in the array profile but the values are
-        // base=cell property=int, then we know that this access didn't execute.
+    switch (type()) {
+    case Array::Unprofiled:
         return ArrayMode(Array::ForceExit);
-    }
-    
-    if (type() != Array::SelectUsingPredictions)
+        
+    case Array::Undecided:
+        if (!value)
+            return withType(Array::ForceExit);
+        if (isInt32Speculation(value))
+            return withTypeAndConversion(Array::Int32, Array::Convert);
+        if (isNumberSpeculation(value))
+            return withTypeAndConversion(Array::Double, Array::Convert);
+        return withTypeAndConversion(Array::Contiguous, Array::Convert);
+        
+    case Array::Int32:
+        if (!value || isInt32Speculation(value))
+            return *this;
+        if (isNumberSpeculation(value))
+            return withTypeAndConversion(Array::Double, Array::Convert);
+        return withTypeAndConversion(Array::Contiguous, Array::Convert);
+        
+    case Array::Double:
+        if (!value || isNumberSpeculation(value))
+            return *this;
+        return withTypeAndConversion(Array::Contiguous, Array::Convert);
+        
+    case Array::SelectUsingPredictions:
+        if (isStringSpeculation(base))
+            return ArrayMode(Array::String);
+        
+        if (isArgumentsSpeculation(base))
+            return ArrayMode(Array::Arguments);
+        
+        if (isInt8ArraySpeculation(base))
+            return ArrayMode(Array::Int8Array);
+        
+        if (isInt16ArraySpeculation(base))
+            return ArrayMode(Array::Int16Array);
+        
+        if (isInt32ArraySpeculation(base))
+            return ArrayMode(Array::Int32Array);
+        
+        if (isUint8ArraySpeculation(base))
+            return ArrayMode(Array::Uint8Array);
+        
+        if (isUint8ClampedArraySpeculation(base))
+            return ArrayMode(Array::Uint8ClampedArray);
+        
+        if (isUint16ArraySpeculation(base))
+            return ArrayMode(Array::Uint16Array);
+        
+        if (isUint32ArraySpeculation(base))
+            return ArrayMode(Array::Uint32Array);
+        
+        if (isFloat32ArraySpeculation(base))
+            return ArrayMode(Array::Float32Array);
+        
+        if (isFloat64ArraySpeculation(base))
+            return ArrayMode(Array::Float64Array);
+
+        return ArrayMode(Array::Generic);
+
+    default:
         return *this;
-    
-    if (isStringSpeculation(base))
-        return ArrayMode(Array::String);
-    
-    if (isArgumentsSpeculation(base))
-        return ArrayMode(Array::Arguments);
-    
-    if (isInt8ArraySpeculation(base))
-        return ArrayMode(Array::Int8Array);
-    
-    if (isInt16ArraySpeculation(base))
-        return ArrayMode(Array::Int16Array);
-    
-    if (isInt32ArraySpeculation(base))
-        return ArrayMode(Array::Int32Array);
-    
-    if (isUint8ArraySpeculation(base))
-        return ArrayMode(Array::Uint8Array);
-    
-    if (isUint8ClampedArraySpeculation(base))
-        return ArrayMode(Array::Uint8ClampedArray);
-    
-    if (isUint16ArraySpeculation(base))
-        return ArrayMode(Array::Uint16Array);
-    
-    if (isUint32ArraySpeculation(base))
-        return ArrayMode(Array::Uint32Array);
-    
-    if (isFloat32ArraySpeculation(base))
-        return ArrayMode(Array::Float32Array);
-    
-    if (isFloat64ArraySpeculation(base))
-        return ArrayMode(Array::Float64Array);
-    
-    return ArrayMode(Array::Generic);
+    }
+}
+
+bool ArrayMode::alreadyChecked(AbstractValue& value, IndexingType shape) const
+{
+    if (isJSArray()) {
+        if (arrayModesAlreadyChecked(value.m_arrayModes, asArrayModes(shape | IsArray)))
+            return true;
+        return value.m_currentKnownStructure.hasSingleton()
+            && (value.m_currentKnownStructure.singleton()->indexingType() & IndexingShapeMask) == shape
+            && (value.m_currentKnownStructure.singleton()->indexingType() & IsArray);
+    }
+    if (arrayModesAlreadyChecked(value.m_arrayModes, asArrayModes(shape) | asArrayModes(shape | IsArray)))
+        return true;
+    return value.m_currentKnownStructure.hasSingleton()
+        && (value.m_currentKnownStructure.singleton()->indexingType() & IndexingShapeMask) == shape;
 }
 
 bool ArrayMode::alreadyChecked(AbstractValue& value) const
@@ -161,31 +227,17 @@ bool ArrayMode::alreadyChecked(AbstractValue& value) const
     case Array::String:
         return speculationChecked(value.m_type, SpecString);
         
+    case Array::Int32:
+        return alreadyChecked(value, Int32Shape);
+        
+    case Array::Double:
+        return alreadyChecked(value, DoubleShape);
+        
     case Array::Contiguous:
-        if (isJSArray()) {
-            if (arrayModesAlreadyChecked(value.m_arrayModes, asArrayModes(ArrayWithContiguous)))
-                return true;
-            return value.m_currentKnownStructure.hasSingleton()
-                && hasContiguous(value.m_currentKnownStructure.singleton()->indexingType())
-                && (value.m_currentKnownStructure.singleton()->indexingType() & IsArray);
-        }
-        if (arrayModesAlreadyChecked(value.m_arrayModes, asArrayModes(NonArrayWithContiguous) | asArrayModes(ArrayWithContiguous)))
-            return true;
-        return value.m_currentKnownStructure.hasSingleton()
-            && hasContiguous(value.m_currentKnownStructure.singleton()->indexingType());
+        return alreadyChecked(value, ContiguousShape);
         
     case Array::ArrayStorage:
-        if (isJSArray()) {
-            if (arrayModesAlreadyChecked(value.m_arrayModes, asArrayModes(ArrayWithArrayStorage)))
-                return true;
-            return value.m_currentKnownStructure.hasSingleton()
-                && hasFastArrayStorage(value.m_currentKnownStructure.singleton()->indexingType())
-                && (value.m_currentKnownStructure.singleton()->indexingType() & IsArray);
-        }
-        if (arrayModesAlreadyChecked(value.m_arrayModes, asArrayModes(NonArrayWithArrayStorage) | asArrayModes(ArrayWithArrayStorage)))
-            return true;
-        return value.m_currentKnownStructure.hasSingleton()
-            && hasFastArrayStorage(value.m_currentKnownStructure.singleton()->indexingType());
+        return alreadyChecked(value, ArrayStorageShape);
         
     case Array::SlowPutArrayStorage:
         if (isJSArray()) {
@@ -232,6 +284,7 @@ bool ArrayMode::alreadyChecked(AbstractValue& value) const
         
     case Array::SelectUsingPredictions:
     case Array::Unprofiled:
+    case Array::Undecided:
         break;
     }
     
@@ -252,6 +305,12 @@ const char* arrayTypeToString(Array::Type type)
         return "ForceExit";
     case Array::String:
         return "String";
+    case Array::Undecided:
+        return "Undecided";
+    case Array::Int32:
+        return "Int32";
+    case Array::Double:
+        return "Double";
     case Array::Contiguous:
         return "Contiguous";
     case Array::ArrayStorage:
index 615965c..206d689 100644 (file)
@@ -52,7 +52,10 @@ enum Type {
     ForceExit, // Implies that we have no idea how to execute this operation, so we should just give up.
     Generic,
     String,
-    
+
+    Undecided,
+    Int32,
+    Double,
     Contiguous,
     ArrayStorage,
     SlowPutArrayStorage,
@@ -81,7 +84,6 @@ enum Speculation {
     ToHole,
     OutOfBounds
 };
-
 enum Conversion {
     AsIs,
     Convert
@@ -169,7 +171,17 @@ public:
         return ArrayMode(type(), myArrayClass, mySpeculation, conversion());
     }
     
-    ArrayMode refine(SpeculatedType base, SpeculatedType index) const;
+    ArrayMode withType(Array::Type type) const
+    {
+        return ArrayMode(type, arrayClass(), speculation(), conversion());
+    }
+    
+    ArrayMode withTypeAndConversion(Array::Type type, Array::Conversion conversion) const
+    {
+        return ArrayMode(type, arrayClass(), speculation(), conversion);
+    }
+    
+    ArrayMode refine(SpeculatedType base, SpeculatedType index, SpeculatedType value = SpecNone) const;
     
     bool alreadyChecked(AbstractValue&) const;
     
@@ -178,6 +190,8 @@ public:
     bool usesButterfly() const
     {
         switch (type()) {
+        case Array::Int32:
+        case Array::Double:
         case Array::Contiguous:
         case Array::ArrayStorage:
         case Array::SlowPutArrayStorage:
@@ -263,6 +277,7 @@ public:
         case Array::Unprofiled:
         case Array::ForceExit:
         case Array::Generic:
+        case Array::Undecided:
             return false;
         default:
             return true;
@@ -277,6 +292,8 @@ public:
         case Array::ForceExit:
         case Array::Generic:
             return false;
+        case Array::Int32:
+        case Array::Double:
         case Array::Contiguous:
         case Array::ArrayStorage:
         case Array::SlowPutArrayStorage:
@@ -309,6 +326,10 @@ public:
         switch (type()) {
         case Array::Generic:
             return ALL_ARRAY_MODES;
+        case Array::Int32:
+            return arrayModesWithIndexingShape(Int32Shape);
+        case Array::Double:
+            return arrayModesWithIndexingShape(DoubleShape);
         case Array::Contiguous:
             return arrayModesWithIndexingShape(ContiguousShape);
         case Array::ArrayStorage:
@@ -354,6 +375,8 @@ private:
         }
     }
     
+    bool alreadyChecked(AbstractValue&, IndexingType shape) const;
+    
     union {
         struct {
             uint8_t type;
index 70aa2b6..142b8ab 100644 (file)
@@ -905,10 +905,15 @@ private:
         return getPrediction(m_graph.size(), m_currentProfilingIndex);
     }
     
-    ArrayMode getArrayMode(ArrayProfile* profile)
+    ArrayMode getArrayMode(ArrayProfile* profile, Array::Action action)
     {
         profile->computeUpdatedPrediction(m_inlineStackTop->m_codeBlock);
-        return ArrayMode::fromObserved(profile, Array::Read, false);
+        return ArrayMode::fromObserved(profile, action, false);
+    }
+    
+    ArrayMode getArrayMode(ArrayProfile* profile)
+    {
+        return getArrayMode(profile, Array::Read);
     }
     
     ArrayMode getArrayModeAndEmitChecks(ArrayProfile* profile, Array::Action action, NodeIndex base)
@@ -1649,7 +1654,12 @@ bool ByteCodeParser::handleIntrinsic(bool usesResult, int resultOperand, Intrins
             return false;
         
         ArrayMode arrayMode = getArrayMode(m_currentInstruction[5].u.arrayProfile);
+        if (!arrayMode.isJSArray())
+            return false;
         switch (arrayMode.type()) {
+        case Array::Undecided:
+        case Array::Int32:
+        case Array::Double:
         case Array::Contiguous:
         case Array::ArrayStorage: {
             NodeIndex arrayPush = addToGraph(ArrayPush, OpInfo(arrayMode.asWord()), OpInfo(prediction), get(registerOffset + argumentToOperand(0)), get(registerOffset + argumentToOperand(1)));
@@ -1669,7 +1679,11 @@ bool ByteCodeParser::handleIntrinsic(bool usesResult, int resultOperand, Intrins
             return false;
         
         ArrayMode arrayMode = getArrayMode(m_currentInstruction[5].u.arrayProfile);
+        if (!arrayMode.isJSArray())
+            return false;
         switch (arrayMode.type()) {
+        case Array::Int32:
+        case Array::Double:
         case Array::Contiguous:
         case Array::ArrayStorage: {
             NodeIndex arrayPop = addToGraph(ArrayPop, OpInfo(arrayMode.asWord()), OpInfo(prediction), get(registerOffset + argumentToOperand(0)));
@@ -1754,7 +1768,7 @@ bool ByteCodeParser::handleConstantInternalFunction(
         if (argumentCountIncludingThis == 2) {
             setIntrinsicResult(
                 usesResult, resultOperand,
-                addToGraph(NewArrayWithSize, get(registerOffset + argumentToOperand(1))));
+                addToGraph(NewArrayWithSize, OpInfo(ArrayWithUndecided), get(registerOffset + argumentToOperand(1))));
             return true;
         }
         
@@ -1762,7 +1776,7 @@ bool ByteCodeParser::handleConstantInternalFunction(
             addVarArgChild(get(registerOffset + argumentToOperand(i)));
         setIntrinsicResult(
             usesResult, resultOperand,
-            addToGraph(Node::VarArg, NewArray, OpInfo(0), OpInfo(0)));
+            addToGraph(Node::VarArg, NewArray, OpInfo(ArrayWithUndecided), OpInfo(0)));
         return true;
     }
     
@@ -2122,24 +2136,37 @@ bool ByteCodeParser::parseBlock(unsigned limit)
         case op_new_array: {
             int startOperand = currentInstruction[2].u.operand;
             int numOperands = currentInstruction[3].u.operand;
+            ArrayAllocationProfile* profile = currentInstruction[4].u.arrayAllocationProfile;
             for (int operandIdx = startOperand; operandIdx < startOperand + numOperands; ++operandIdx)
                 addVarArgChild(get(operandIdx));
-            set(currentInstruction[1].u.operand, addToGraph(Node::VarArg, NewArray, OpInfo(0), OpInfo(0)));
+            set(currentInstruction[1].u.operand, addToGraph(Node::VarArg, NewArray, OpInfo(profile->selectIndexingType()), OpInfo(0)));
             NEXT_OPCODE(op_new_array);
         }
             
         case op_new_array_with_size: {
             int lengthOperand = currentInstruction[2].u.operand;
-            set(currentInstruction[1].u.operand, addToGraph(NewArrayWithSize, get(lengthOperand)));
+            ArrayAllocationProfile* profile = currentInstruction[3].u.arrayAllocationProfile;
+            set(currentInstruction[1].u.operand, addToGraph(NewArrayWithSize, OpInfo(profile->selectIndexingType()), get(lengthOperand)));
             NEXT_OPCODE(op_new_array_with_size);
         }
             
         case op_new_array_buffer: {
             int startConstant = currentInstruction[2].u.operand;
             int numConstants = currentInstruction[3].u.operand;
+            ArrayAllocationProfile* profile = currentInstruction[4].u.arrayAllocationProfile;
             NewArrayBufferData data;
             data.startConstant = m_inlineStackTop->m_constantBufferRemap[startConstant];
             data.numConstants = numConstants;
+            data.indexingType = profile->selectIndexingType();
+
+            // If this statement has never executed, we'll have the wrong indexing type in the profile.
+            for (int i = 0; i < numConstants; ++i) {
+                data.indexingType =
+                    leastUpperBoundOfIndexingTypeAndValue(
+                        data.indexingType,
+                        m_codeBlock->constantBuffer(data.startConstant)[i]);
+            }
+            
             m_graph.m_newArrayBufferData.append(data);
             set(currentInstruction[1].u.operand, addToGraph(NewArrayBuffer, OpInfo(&m_graph.m_newArrayBufferData.last())));
             NEXT_OPCODE(op_new_array_buffer);
index a2570b7..308dde5 100644 (file)
@@ -210,6 +210,15 @@ public:
         addCallArgument(arg3);
     }
 
+    ALWAYS_INLINE void setupArgumentsWithExecState(GPRReg arg1, TrustedImm32 arg2, GPRReg arg3)
+    {
+        resetCallArguments();
+        addCallArgument(GPRInfo::callFrameRegister);
+        addCallArgument(arg1);
+        addCallArgument(arg2);
+        addCallArgument(arg3);
+    }
+
     ALWAYS_INLINE void setupArgumentsWithExecState(GPRReg arg1, TrustedImm32 arg2, TrustedImmPtr arg3)
     {
         resetCallArguments();
@@ -268,6 +277,16 @@ public:
         addCallArgument(arg4);
     }
 
+    ALWAYS_INLINE void setupArgumentsWithExecState(GPRReg arg1, GPRReg arg2, GPRReg arg3, TrustedImm32 arg4)
+    {
+        resetCallArguments();
+        addCallArgument(GPRInfo::callFrameRegister);
+        addCallArgument(arg1);
+        addCallArgument(arg2);
+        addCallArgument(arg3);
+        addCallArgument(arg4);
+    }
+
     ALWAYS_INLINE void setupArgumentsWithExecState(TrustedImm32 arg1, TrustedImmPtr arg2, GPRReg arg3)
     {
         resetCallArguments();
@@ -317,6 +336,23 @@ public:
         addCallArgument(arg4);
         addCallArgument(arg5);
     }
+
+    ALWAYS_INLINE void setupArgumentsWithExecState(FPRReg arg1, GPRReg arg2)
+    {
+        resetCallArguments();
+        addCallArgument(GPRInfo::callFrameRegister);
+        addCallArgument(arg1);
+        addCallArgument(arg2);
+    }
+
+    ALWAYS_INLINE void setupArgumentsWithExecState(GPRReg arg1, GPRReg arg2, FPRReg arg3)
+    {
+        resetCallArguments();
+        addCallArgument(GPRInfo::callFrameRegister);
+        addCallArgument(arg1);
+        addCallArgument(arg2);
+        addCallArgument(arg3);
+    }
 #endif // !NUMBER_OF_ARGUMENT_REGISTERS
     // These methods are suitable for any calling convention that provides for
     // at least 4 argument registers, e.g. X86_64, ARMv7.
@@ -463,6 +499,20 @@ public:
     {
         setupTwoStubArgs<FPRInfo::argumentFPR0, FPRInfo::argumentFPR1>(arg1, arg2);
     }
+    
+    ALWAYS_INLINE void setupArgumentsWithExecState(FPRReg arg1, GPRReg arg2)
+    {
+        moveDouble(arg1, FPRInfo::argumentFPR0);
+        move(arg2, GPRInfo::argumentGPR1);
+        move(GPRInfo::callFrameRegister, GPRInfo::argumentGPR0);
+    }
+
+    ALWAYS_INLINE void setupArgumentsWithExecState(GPRReg arg1, GPRReg arg2, FPRReg arg3)
+    {
+        moveDouble(arg3, FPRInfo::argumentFPR0);
+        setupStubArguments(arg1, arg2);
+        move(GPRInfo::callFrameRegister, GPRInfo::argumentGPR0);
+    }
 #elif CPU(ARM)
 #if CPU(ARM_HARDFP)
     ALWAYS_INLINE void setupArguments(FPRReg arg1)
@@ -496,6 +546,21 @@ public:
         assembler().vmov(GPRInfo::argumentGPR0, GPRInfo::argumentGPR1, arg1);
         assembler().vmov(GPRInfo::argumentGPR2, GPRInfo::argumentGPR3, arg2);
     }
+
+    ALWAYS_INLINE void setupArgumentsWithExecState(FPRReg arg1, GPRReg arg2)
+    {
+        move(arg2, GPRInfo::argumentGPR3);
+        assembler().vmov(GPRInfo::argumentGPR1, GPRInfo::argumentGPR2, arg1);
+        move(GPRInfo::callFrameRegister, GPRInfo::argumentGPR0);
+    }
+
+    ALWAYS_INLINE void setupArgumentsWithExecState(GPRReg arg1, GPRReg arg2, FPRReg arg3)
+    {
+        setupStubArguments(arg1, arg2);
+        move(GPRInfo::callFrameRegister, GPRInfo::argumentGPR0);
+        assembler().vmov(GPRInfo::argumentGPR3, GPRInfo::nonArgGPR0, arg3);
+        poke(GPRInfo::nonArgGPR0);
+    }
 #endif // CPU(ARM_HARDFP)
 #else
 #error "DFG JIT not supported on this platform."
@@ -635,6 +700,13 @@ public:
         move(GPRInfo::callFrameRegister, GPRInfo::argumentGPR0);
     }
 
+    ALWAYS_INLINE void setupArgumentsWithExecState(GPRReg arg1, TrustedImm32 arg2, GPRReg arg3)
+    {
+        setupTwoStubArgs<GPRInfo::argumentGPR1, GPRInfo::argumentGPR3>(arg1, arg3);
+        move(arg2, GPRInfo::argumentGPR2);
+        move(GPRInfo::callFrameRegister, GPRInfo::argumentGPR0);
+    }
+
     ALWAYS_INLINE void setupArgumentsWithExecState(GPRReg arg1, TrustedImm32 arg2, TrustedImmPtr arg3)
     {
         move(arg1, GPRInfo::argumentGPR1);
@@ -723,6 +795,12 @@ public:
         setupArgumentsWithExecState(arg1, arg2, arg3);
     }
 
+    ALWAYS_INLINE void setupArgumentsWithExecState(GPRReg arg1, GPRReg arg2, GPRReg arg3, TrustedImm32 arg4)
+    {
+        poke(arg4);
+        setupArgumentsWithExecState(arg1, arg2, arg3);
+    }
+
     ALWAYS_INLINE void setupArgumentsWithExecState(GPRReg arg1, TrustedImmPtr arg2, TrustedImm32 arg3, GPRReg arg4)
     {
         poke(arg4);
index 46d5f44..03713b6 100644 (file)
@@ -61,7 +61,7 @@ protected:
             jit->silentSpill(m_plans[i]);
         jit->callOperation(m_function, m_resultGPR, m_structure, m_size);
         GPRReg canTrample = SpeculativeJIT::pickCanTrample(m_resultGPR);
-        for (unsigned i = 0; i < m_plans.size(); ++i)
+        for (unsigned i = m_plans.size(); i--;)
             jit->silentFill(m_plans[i], canTrample);
         jit->m_jit.loadPtr(MacroAssembler::Address(m_resultGPR, JSObject::butterflyOffset()), m_storageGPR);
         jumpTo(jit);
@@ -106,7 +106,7 @@ protected:
         done.link(&jit->m_jit);
         jit->callOperation(m_function, m_resultGPR, scratchGPR, m_sizeGPR);
         GPRReg canTrample = SpeculativeJIT::pickCanTrample(m_resultGPR);
-        for (unsigned i = 0; i < m_plans.size(); ++i)
+        for (unsigned i = m_plans.size(); i--;)
             jit->silentFill(m_plans[i], canTrample);
         jumpTo(jit);
     }
index 5a76aa8..8be8f2c 100644 (file)
@@ -145,7 +145,30 @@ private:
         }
             
         case ArrayPush: {
+            // May need to refine the array mode in case the value prediction contravenes
+            // the array prediction. For example, we may have evidence showing that the
+            // array is in Int32 mode, but the value we're storing is likely to be a double.
+            // Then we should turn this into a conversion to Double array followed by the
+            // push. On the other hand, we absolutely don't want to refine based on the
+            // base prediction. If it has non-cell garbage in it, then we want that to be
+            // ignored. That's because ArrayPush can't handle any array modes that aren't
+            // array-related - so if refine() turned this into a "Generic" ArrayPush then
+            // that would break things.
+            node.setArrayMode(
+                node.arrayMode().refine(
+                    m_graph[node.child1()].prediction() & SpecCell,
+                    SpecInt32,
+                    m_graph[node.child2()].prediction()));
             blessArrayOperation(node.child1(), node.child2(), 2);
+            
+            Node* nodePtr = &m_graph[m_compileIndex];
+            switch (nodePtr->arrayMode().type()) {
+            case Array::Double:
+                fixDoubleEdge(1);
+                break;
+            default:
+                break;
+            }
             break;
         }
             
@@ -328,13 +351,17 @@ private:
             node.setArrayMode(
                 node.arrayMode().refine(
                     m_graph[child1].prediction(),
-                    m_graph[child2].prediction()));
+                    m_graph[child2].prediction(),
+                    m_graph[child3].prediction()));
             
             blessArrayOperation(child1, child2, 3);
             
             Node* nodePtr = &m_graph[m_compileIndex];
             
             switch (nodePtr->arrayMode().modeForPut().type()) {
+            case Array::Double:
+                fixDoubleEdge(2);
+                break;
             case Array::Int8Array:
             case Array::Int16Array:
             case Array::Int32Array:
@@ -355,6 +382,19 @@ private:
             break;
         }
             
+        case NewArray: {
+            for (unsigned i = m_graph.varArgNumChildren(node); i--;) {
+                node.setIndexingType(
+                    leastUpperBoundOfIndexingTypeAndType(
+                        node.indexingType(), m_graph[m_graph.varArgChild(node, i)].prediction()));
+            }
+            if (node.indexingType() == ArrayWithDouble) {
+                for (unsigned i = m_graph.varArgNumChildren(node); i--;)
+                    fixDoubleEdge(i);
+            }
+            break;
+        }
+            
         default:
             break;
         }
@@ -392,15 +432,17 @@ private:
             if (arrayMode.isJSArrayWithOriginalStructure()) {
                 JSGlobalObject* globalObject = m_graph.baselineCodeBlockFor(codeOrigin)->globalObject();
                 switch (arrayMode.type()) {
+                case Array::Int32:
+                    structure = globalObject->originalArrayStructureForIndexingType(ArrayWithInt32);
+                    break;
+                case Array::Double:
+                    structure = globalObject->originalArrayStructureForIndexingType(ArrayWithDouble);
+                    break;
                 case Array::Contiguous:
-                    structure = globalObject->arrayStructure();
-                    if (structure->indexingType() != ArrayWithContiguous)
-                        structure = 0;
+                    structure = globalObject->originalArrayStructureForIndexingType(ArrayWithContiguous);
                     break;
                 case Array::ArrayStorage:
-                    structure = globalObject->arrayStructureWithArrayStorage();
-                    if (structure->indexingType() != ArrayWithArrayStorage)
-                        structure = 0;
+                    structure = globalObject->originalArrayStructureForIndexingType(ArrayWithArrayStorage);
                     break;
                 default:
                     break;
index 8e8817f..38079f0 100644 (file)
@@ -287,6 +287,11 @@ void Graph::dump(const char* prefix, NodeIndex nodeIndex)
         dataLog("]");
         hasPrinted = true;
     }
+    if (node.hasIndexingType()) {
+        if (hasPrinted)
+            dataLog(", ");
+        dataLog("%s", indexingTypeToString(node.indexingType()));
+    }
     if (op == JSConstant) {
         dataLog("%s$%u", hasPrinted ? ", " : "", node.constantNumber());
         JSValue value = valueOfJSConstant(nodeIndex);
index 9fbb2df..252eb18 100644 (file)
@@ -493,6 +493,8 @@ public:
         switch (node.arrayMode().type()) {
         case Array::Generic:
             return false;
+        case Array::Int32:
+        case Array::Double:
         case Array::Contiguous:
         case Array::ArrayStorage:
             return !node.arrayMode().isOutOfBounds();
index e66629e..f077de2 100644 (file)
@@ -62,6 +62,7 @@ struct StructureTransitionData {
 struct NewArrayBufferData {
     unsigned startConstant;
     unsigned numConstants;
+    IndexingType indexingType;
 };
 
 // This type used in passing an immediate argument to Node constructor;
@@ -433,6 +434,32 @@ struct Node {
         return newArrayBufferData()->numConstants;
     }
     
+    bool hasIndexingType()
+    {
+        switch (op()) {
+        case NewArray:
+        case NewArrayWithSize:
+        case NewArrayBuffer:
+            return true;
+        default:
+            return false;
+        }
+    }
+    
+    IndexingType indexingType()
+    {
+        ASSERT(hasIndexingType());
+        if (op() == NewArrayBuffer)
+            return newArrayBufferData()->indexingType;
+        return m_opInfo;
+    }
+    
+    void setIndexingType(IndexingType indexingType)
+    {
+        ASSERT(hasIndexingType());
+        m_opInfo = indexingType;
+    }
+    
     bool hasRegexpIndex()
     {
         return op() == NewRegexp;
index 0e45e23..c9c49a0 100644 (file)
@@ -580,6 +580,40 @@ void DFG_OPERATION operationPutByValBeyondArrayBoundsNonStrict(ExecState* exec,
         array, exec, Identifier::from(exec, index), JSValue::decode(encodedValue), slot);
 }
 
+void DFG_OPERATION operationPutDoubleByValBeyondArrayBoundsStrict(ExecState* exec, JSObject* array, int32_t index, double value)
+{
+    JSGlobalData* globalData = &exec->globalData();
+    NativeCallFrameTracer tracer(globalData, exec);
+    
+    JSValue jsValue = JSValue(JSValue::EncodeAsDouble, value);
+    
+    if (index >= 0) {
+        array->putByIndexInline(exec, index, jsValue, true);
+        return;
+    }
+    
+    PutPropertySlot slot(true);
+    array->methodTable()->put(
+        array, exec, Identifier::from(exec, index), jsValue, slot);
+}
+
+void DFG_OPERATION operationPutDoubleByValBeyondArrayBoundsNonStrict(ExecState* exec, JSObject* array, int32_t index, double value)
+{
+    JSGlobalData* globalData = &exec->globalData();
+    NativeCallFrameTracer tracer(globalData, exec);
+    
+    JSValue jsValue = JSValue(JSValue::EncodeAsDouble, value);
+    
+    if (index >= 0) {
+        array->putByIndexInline(exec, index, jsValue, false);
+        return;
+    }
+    
+    PutPropertySlot slot(false);
+    array->methodTable()->put(
+        array, exec, Identifier::from(exec, index), jsValue, slot);
+}
+
 EncodedJSValue DFG_OPERATION operationArrayPush(ExecState* exec, EncodedJSValue encodedValue, JSArray* array)
 {
     JSGlobalData* globalData = &exec->globalData();
@@ -589,6 +623,15 @@ EncodedJSValue DFG_OPERATION operationArrayPush(ExecState* exec, EncodedJSValue
     return JSValue::encode(jsNumber(array->length()));
 }
 
+EncodedJSValue DFG_OPERATION operationArrayPushDouble(ExecState* exec, double value, JSArray* array)
+{
+    JSGlobalData* globalData = &exec->globalData();
+    NativeCallFrameTracer tracer(globalData, exec);
+    
+    array->push(exec, JSValue(JSValue::EncodeAsDouble, value));
+    return JSValue::encode(jsNumber(array->length()));
+}
+
 EncodedJSValue DFG_OPERATION operationArrayPop(ExecState* exec, JSArray* array)
 {
     JSGlobalData* globalData = &exec->globalData();
@@ -1327,30 +1370,36 @@ char* DFG_OPERATION operationReallocateButterflyToGrowPropertyStorage(ExecState*
     return reinterpret_cast<char*>(result);
 }
 
-char* DFG_OPERATION operationEnsureContiguous(ExecState* exec, JSObject* object)
+char* DFG_OPERATION operationEnsureInt32(ExecState* exec, JSObject* object)
 {
     JSGlobalData& globalData = exec->globalData();
     NativeCallFrameTracer tracer(&globalData, exec);
     
-    return reinterpret_cast<char*>(object->ensureContiguous(globalData));
+    return reinterpret_cast<char*>(object->ensureInt32(globalData));
 }
 
-char* DFG_OPERATION operationEnsureArrayStorage(ExecState* exec, JSObject* object)
+char* DFG_OPERATION operationEnsureDouble(ExecState* exec, JSObject* object)
 {
     JSGlobalData& globalData = exec->globalData();
     NativeCallFrameTracer tracer(&globalData, exec);
+    
+    return reinterpret_cast<char*>(object->ensureDouble(globalData));
+}
 
-    return reinterpret_cast<char*>(object->ensureArrayStorage(globalData));
+char* DFG_OPERATION operationEnsureContiguous(ExecState* exec, JSObject* object)
+{
+    JSGlobalData& globalData = exec->globalData();
+    NativeCallFrameTracer tracer(&globalData, exec);
+    
+    return reinterpret_cast<char*>(object->ensureContiguous(globalData));
 }
 
-char* DFG_OPERATION operationEnsureContiguousOrArrayStorage(ExecState* exec, JSObject* object, int32_t index)
+char* DFG_OPERATION operationEnsureArrayStorage(ExecState* exec, JSObject* object)
 {
     JSGlobalData& globalData = exec->globalData();
     NativeCallFrameTracer tracer(&globalData, exec);
 
-    if (static_cast<unsigned>(index) >= MIN_SPARSE_ARRAY_INDEX)
-        return reinterpret_cast<char*>(object->ensureArrayStorage(globalData));
-    return reinterpret_cast<char*>(object->ensureIndexedStorage(globalData));
+    return reinterpret_cast<char*>(object->ensureArrayStorage(globalData));
 }
 
 double DFG_OPERATION operationFModOnInts(int32_t a, int32_t b)
index 8d2beac..b99c214 100644 (file)
@@ -64,6 +64,7 @@ typedef EncodedJSValue DFG_OPERATION (*J_DFGOperation_EAZ)(ExecState*, JSArray*,
 typedef EncodedJSValue DFG_OPERATION (*J_DFGOperation_ECC)(ExecState*, JSCell*, JSCell*);
 typedef EncodedJSValue DFG_OPERATION (*J_DFGOperation_ECI)(ExecState*, JSCell*, Identifier*);
 typedef EncodedJSValue DFG_OPERATION (*J_DFGOperation_ECJ)(ExecState*, JSCell*, EncodedJSValue);
+typedef EncodedJSValue DFG_OPERATION (*J_DFGOperation_EDA)(ExecState*, double, JSArray*);
 typedef EncodedJSValue DFG_OPERATION (*J_DFGOperation_EGriJsgI)(ExecState*, ResolveOperation*, JSGlobalObject*, Identifier*);
 typedef EncodedJSValue DFG_OPERATION (*J_DFGOperation_EI)(ExecState*, Identifier*);
 typedef EncodedJSValue DFG_OPERATION (*J_DFGOperation_EIRo)(ExecState*, Identifier*, ResolveOperations*);
@@ -92,6 +93,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_EOZD)(ExecState*, JSObject*, int32_t, double);
 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*);
@@ -148,7 +150,10 @@ void DFG_OPERATION operationPutByValCellStrict(ExecState*, JSCell*, EncodedJSVal
 void DFG_OPERATION operationPutByValCellNonStrict(ExecState*, JSCell*, EncodedJSValue encodedProperty, 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;
+void DFG_OPERATION operationPutDoubleByValBeyondArrayBoundsStrict(ExecState*, JSObject*, int32_t index, double value) WTF_INTERNAL;
+void DFG_OPERATION operationPutDoubleByValBeyondArrayBoundsNonStrict(ExecState*, JSObject*, int32_t index, double value) WTF_INTERNAL;
 EncodedJSValue DFG_OPERATION operationArrayPush(ExecState*, EncodedJSValue encodedValue, JSArray*) WTF_INTERNAL;
+EncodedJSValue DFG_OPERATION operationArrayPushDouble(ExecState*, double value, JSArray*) WTF_INTERNAL;
 EncodedJSValue DFG_OPERATION operationArrayPop(ExecState*, JSArray*) WTF_INTERNAL;
 EncodedJSValue DFG_OPERATION operationArrayPopAndRecoverLength(ExecState*, JSArray*) WTF_INTERNAL;
 EncodedJSValue DFG_OPERATION operationRegExpExec(ExecState*, JSCell*, JSCell*) WTF_INTERNAL;
@@ -195,9 +200,10 @@ char* DFG_OPERATION operationAllocatePropertyStorageWithInitialCapacity(ExecStat
 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;
+char* DFG_OPERATION operationEnsureInt32(ExecState*, JSObject*);
+char* DFG_OPERATION operationEnsureDouble(ExecState*, JSObject*);
 char* DFG_OPERATION operationEnsureContiguous(ExecState*, JSObject*);
 char* DFG_OPERATION operationEnsureArrayStorage(ExecState*, JSObject*);
-char* DFG_OPERATION operationEnsureContiguousOrArrayStorage(ExecState*, JSObject*, int32_t);
 
 // 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 3e8ead5..7ed0c26 100644 (file)
@@ -849,6 +849,24 @@ private:
                 break;
             }
                 
+            case PutByVal:
+            case PutByValAlias: {
+                Edge child1 = m_graph.varArgChild(node, 0);
+                Edge child2 = m_graph.varArgChild(node, 1);
+                Edge child3 = m_graph.varArgChild(node, 2);
+                m_graph.vote(child1, VoteValue);
+                m_graph.vote(child2, VoteValue);
+                switch (node.arrayMode().type()) {
+                case Array::Double:
+                    m_graph.vote(child3, VoteDouble);
+                    break;
+                default:
+                    m_graph.vote(child3, VoteValue);
+                    break;
+                }
+                break;
+            }
+                
             default:
                 m_graph.vote(node, VoteValue);
                 break;
index 6bedd6d..6a5056f 100644 (file)
@@ -59,7 +59,7 @@ SpeculativeJIT::~SpeculativeJIT()
 
 void SpeculativeJIT::emitAllocateJSArray(Structure* structure, GPRReg resultGPR, GPRReg storageGPR, unsigned numElements)
 {
-    ASSERT(hasContiguous(structure->indexingType()));
+    ASSERT(hasUndecided(structure->indexingType()) || hasInt32(structure->indexingType()) || hasDouble(structure->indexingType()) || hasContiguous(structure->indexingType()));
     
     GPRTemporary scratch(this);
     GPRReg scratchGPR = scratch.gpr();
@@ -67,6 +67,7 @@ void SpeculativeJIT::emitAllocateJSArray(Structure* structure, GPRReg resultGPR,
     unsigned vectorLength = std::max(BASE_VECTOR_LEN, numElements);
     
     JITCompiler::JumpList slowCases;
+    
     slowCases.append(
         emitAllocateBasicStorage(TrustedImm32(vectorLength * sizeof(JSValue) + sizeof(IndexingHeader)), storageGPR));
     m_jit.subPtr(TrustedImm32(vectorLength * sizeof(JSValue)), storageGPR);
@@ -79,6 +80,21 @@ void SpeculativeJIT::emitAllocateJSArray(Structure* structure, GPRReg resultGPR,
     m_jit.store32(TrustedImm32(numElements), MacroAssembler::Address(storageGPR, Butterfly::offsetOfPublicLength()));
     m_jit.store32(TrustedImm32(vectorLength), MacroAssembler::Address(storageGPR, Butterfly::offsetOfVectorLength()));
     
+    if (hasDouble(structure->indexingType()) && numElements < vectorLength) {
+#if USE(JSVALUE64)
+        m_jit.move(TrustedImm64(bitwise_cast<int64_t>(QNaN)), scratchGPR);
+        for (unsigned i = numElements; i < vectorLength; ++i)
+            m_jit.store64(scratchGPR, MacroAssembler::Address(storageGPR, sizeof(double) * i));
+#else
+        EncodedValueDescriptor value;
+        value.asInt64 = JSValue::encode(JSValue(JSValue::EncodeAsDouble, QNaN));
+        for (unsigned i = numElements; i < vectorLength; ++i) {
+            m_jit.store32(TrustedImm32(value.asBits.tag), MacroAssembler::Address(storageGPR, sizeof(double) * i + OBJECT_OFFSETOF(JSValue, u.asBits.tag)));
+            m_jit.store32(TrustedImm32(value.asBits.payload), MacroAssembler::Address(storageGPR, sizeof(double) * i + OBJECT_OFFSETOF(JSValue, u.asBits.payload)));
+        }
+#endif
+    }
+    
     // I want a slow path that also loads out the storage pointer, and that's
     // what this custom CallArrayAllocatorSlowPathGenerator gives me. It's a lot
     // of work for a very small piece of functionality. :-/
@@ -343,24 +359,31 @@ const TypedArrayDescriptor* SpeculativeJIT::typedArrayDescriptor(ArrayMode array
     }
 }
 
+JITCompiler::Jump SpeculativeJIT::jumpSlowForUnwantedArrayMode(GPRReg tempGPR, ArrayMode arrayMode, IndexingType shape, bool invert)
+{
+    if (arrayMode.isJSArray()) {
+        m_jit.and32(TrustedImm32(IsArray | IndexingShapeMask), tempGPR);
+        return m_jit.branch32(
+            invert ? MacroAssembler::Equal : MacroAssembler::NotEqual, tempGPR, TrustedImm32(IsArray | shape));
+    }
+    m_jit.and32(TrustedImm32(IndexingShapeMask), tempGPR);
+    return m_jit.branch32(invert ? MacroAssembler::Equal : MacroAssembler::NotEqual, tempGPR, TrustedImm32(shape));
+}
+
 JITCompiler::JumpList SpeculativeJIT::jumpSlowForUnwantedArrayMode(GPRReg tempGPR, ArrayMode arrayMode, bool invert)
 {
     JITCompiler::JumpList result;
     
     switch (arrayMode.type()) {
-    case Array::Contiguous: {
-        if (arrayMode.isJSArray()) {
-            m_jit.and32(TrustedImm32(IsArray | IndexingShapeMask), tempGPR);
-            result.append(
-                m_jit.branch32(
-                    invert ? MacroAssembler::Equal : MacroAssembler::NotEqual, tempGPR, TrustedImm32(IsArray | ContiguousShape)));
-            break;
-        }
-        m_jit.and32(TrustedImm32(IndexingShapeMask), tempGPR);
-        result.append(
-            m_jit.branch32(invert ? MacroAssembler::Equal : MacroAssembler::NotEqual, tempGPR, TrustedImm32(ContiguousShape)));
-        break;
-    }
+    case Array::Int32:
+        return jumpSlowForUnwantedArrayMode(tempGPR, arrayMode, Int32Shape, invert);
+
+    case Array::Double:
+        return jumpSlowForUnwantedArrayMode(tempGPR, arrayMode, DoubleShape, invert);
+
+    case Array::Contiguous:
+        return jumpSlowForUnwantedArrayMode(tempGPR, arrayMode, ContiguousShape, invert);
+
     case Array::ArrayStorage:
     case Array::SlowPutArrayStorage: {
         if (arrayMode.isJSArray()) {
@@ -437,6 +460,8 @@ void SpeculativeJIT::checkArray(Node& node)
     case Array::String:
         expectedClassInfo = &JSString::s_info;
         break;
+    case Array::Int32:
+    case Array::Double:
     case Array::Contiguous:
     case Array::ArrayStorage:
     case Array::SlowPutArrayStorage: {
@@ -528,16 +553,30 @@ void SpeculativeJIT::arrayify(Node& node, GPRReg baseReg, GPRReg propertyReg)
         
     // If we're allegedly creating contiguous storage and the index is bogus, then
     // just don't.
-    if (node.arrayMode().type() == Array::Contiguous && propertyReg != InvalidGPRReg) {
-        speculationCheck(
-            Uncountable, JSValueRegs(), NoNode,
-            m_jit.branch32(
-                MacroAssembler::AboveOrEqual, propertyReg, TrustedImm32(MIN_SPARSE_ARRAY_INDEX)));
+    if (propertyReg != InvalidGPRReg) {
+        switch (node.arrayMode().type()) {
+        case Array::Int32:
+        case Array::Double:
+        case Array::Contiguous:
+            speculationCheck(
+                Uncountable, JSValueRegs(), NoNode,
+                m_jit.branch32(
+                    MacroAssembler::AboveOrEqual, propertyReg, TrustedImm32(MIN_SPARSE_ARRAY_INDEX)));
+            break;
+        default:
+            break;
+        }
     }
     
     // Now call out to create the array storage.
     silentSpillAllRegisters(tempGPR);
     switch (node.arrayMode().type()) {
+    case Array::Int32:
+        callOperation(operationEnsureInt32, tempGPR, baseReg);
+        break;
+    case Array::Double:
+        callOperation(operationEnsureDouble, tempGPR, baseReg);
+        break;
     case Array::Contiguous:
         callOperation(operationEnsureContiguous, tempGPR, baseReg);
         break;
@@ -1797,6 +1836,85 @@ ValueRecovery SpeculativeJIT::computeValueRecoveryFor(const ValueSource& valueSo
     return ValueRecovery();
 }
 
+void SpeculativeJIT::compileDoublePutByVal(Node& node, SpeculateCellOperand& base, SpeculateStrictInt32Operand& property)
+{
+    Edge child3 = m_jit.graph().varArgChild(node, 2);
+    Edge child4 = m_jit.graph().varArgChild(node, 3);
+
+    ArrayMode arrayMode = node.arrayMode();
+    
+    GPRReg baseReg = base.gpr();
+    GPRReg propertyReg = property.gpr();
+    
+    SpeculateDoubleOperand value(this, child3);
+
+    FPRReg valueReg = value.fpr();
+    
+    if (!isRealNumberSpeculation(m_state.forNode(child3).m_type)) {
+        // FIXME: We need a way of profiling these, and we need to hoist them into
+        // SpeculateDoubleOperand.
+        speculationCheck(
+            BadType, JSValueRegs(), NoNode,
+            m_jit.branchDouble(MacroAssembler::DoubleNotEqualOrUnordered, valueReg, valueReg));
+    }
+    
+    if (!m_compileOkay)
+        return;
+    
+    StorageOperand storage(this, child4);
+    GPRReg storageReg = storage.gpr();
+
+    if (node.op() == PutByValAlias) {
+        // Store the value to the array.
+        GPRReg propertyReg = property.gpr();
+        FPRReg valueReg = value.fpr();
+        m_jit.storeDouble(valueReg, MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesEight));
+        
+        noResult(m_compileIndex);
+        return;
+    }
+    
+    GPRTemporary temporary;
+    GPRReg temporaryReg = temporaryRegisterForPutByVal(temporary, node);
+
+    MacroAssembler::JumpList slowCases;
+    
+    if (arrayMode.isInBounds()) {
+        speculationCheck(
+            Uncountable, JSValueRegs(), NoNode,
+            m_jit.branch32(MacroAssembler::AboveOrEqual, propertyReg, MacroAssembler::Address(storageReg, Butterfly::offsetOfPublicLength())));
+    } else {
+        MacroAssembler::Jump inBounds = m_jit.branch32(MacroAssembler::Below, propertyReg, MacroAssembler::Address(storageReg, Butterfly::offsetOfPublicLength()));
+        
+        slowCases.append(m_jit.branch32(MacroAssembler::AboveOrEqual, propertyReg, MacroAssembler::Address(storageReg, Butterfly::offsetOfVectorLength())));
+        
+        if (!arrayMode.isOutOfBounds())
+            speculationCheck(Uncountable, JSValueRegs(), NoNode, slowCases);
+        
+        m_jit.add32(TrustedImm32(1), propertyReg, temporaryReg);
+        m_jit.store32(temporaryReg, MacroAssembler::Address(storageReg, Butterfly::offsetOfPublicLength()));
+        
+        inBounds.link(&m_jit);
+    }
+    
+    m_jit.storeDouble(valueReg, MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesEight));
+
+    base.use();
+    property.use();
+    value.use();
+    storage.use();
+    
+    if (arrayMode.isOutOfBounds()) {
+        addSlowPathGenerator(
+            slowPathCall(
+                slowCases, this,
+                m_jit.codeBlock()->isStrictMode() ? operationPutDoubleByValBeyondArrayBoundsStrict : operationPutDoubleByValBeyondArrayBoundsNonStrict,
+                NoResult, baseReg, propertyReg, valueReg));
+    }
+
+    noResult(m_compileIndex, UseChildrenCalledExplicitly);
+}
+
 void SpeculativeJIT::compileGetCharCodeAt(Node& node)
 {
     SpeculateCellOperand string(this, node.child1());
@@ -3336,6 +3454,8 @@ void SpeculativeJIT::compileGetArrayLength(Node& node)
     const TypedArrayDescriptor* descriptor = typedArrayDescriptor(node.arrayMode());
 
     switch (node.arrayMode().type()) {
+    case Array::Int32:
+    case Array::Double:
     case Array::Contiguous: {
         StorageOperand storage(this, node.child2());
         GPRTemporary result(this, storage);
index 446ea7d..059d3a6 100644 (file)
@@ -1308,6 +1308,11 @@ public:
         m_jit.setupArgumentsWithExecState(arg1, TrustedImmPtr(identifier));
         return appendCallWithExceptionCheckSetResult(operation, result);
     }
+    JITCompiler::Call callOperation(J_DFGOperation_EDA operation, GPRReg result, FPRReg arg1, GPRReg arg2)
+    {
+        m_jit.setupArgumentsWithExecState(arg1, arg2);
+        return appendCallWithExceptionCheckSetResult(operation, result);
+    }
     JITCompiler::Call callOperation(J_DFGOperation_EJA operation, GPRReg result, GPRReg arg1, GPRReg arg2)
     {
         m_jit.setupArgumentsWithExecState(arg1, arg2);
@@ -1453,6 +1458,11 @@ public:
         m_jit.setupArgumentsWithExecState(arg1, arg2, arg3);
         return appendCallWithExceptionCheck(operation);
     }
+    JITCompiler::Call callOperation(V_DFGOperation_EOZD operation, GPRReg arg1, GPRReg arg2, FPRReg arg3)
+    {
+        m_jit.setupArgumentsWithExecState(arg1, arg2, arg3);
+        return appendCallWithExceptionCheck(operation);
+    }
     JITCompiler::Call callOperation(V_DFGOperation_EOZJ operation, GPRReg arg1, GPRReg arg2, GPRReg arg3)
     {
         m_jit.setupArgumentsWithExecState(arg1, arg2, arg3);
@@ -1661,11 +1671,21 @@ public:
         m_jit.setupArgumentsWithExecState(EABI_32BIT_DUMMY_ARG arg1Payload, TrustedImm32(arg1Tag), TrustedImmPtr(identifier));
         return appendCallWithExceptionCheckSetResult(operation, resultPayload, resultTag);
     }
+    JITCompiler::Call callOperation(J_DFGOperation_EDA operation, GPRReg resultTag, GPRReg resultPayload, FPRReg arg1, GPRReg arg2)
+    {
+        m_jit.setupArgumentsWithExecState(arg1, arg2);
+        return appendCallWithExceptionCheckSetResult(operation, resultPayload, resultTag);
+    }
     JITCompiler::Call callOperation(J_DFGOperation_EJA operation, GPRReg resultTag, GPRReg resultPayload, GPRReg arg1Tag, GPRReg arg1Payload, GPRReg arg2)
     {
         m_jit.setupArgumentsWithExecState(EABI_32BIT_DUMMY_ARG arg1Payload, arg1Tag, arg2);
         return appendCallWithExceptionCheckSetResult(operation, resultPayload, resultTag);
     }
+    JITCompiler::Call callOperation(J_DFGOperation_EJA operation, GPRReg resultTag, GPRReg resultPayload, TrustedImm32 arg1Tag, GPRReg arg1Payload, GPRReg arg2)
+    {
+        m_jit.setupArgumentsWithExecState(EABI_32BIT_DUMMY_ARG arg1Payload, arg1Tag, arg2);
+        return appendCallWithExceptionCheckSetResult(operation, resultPayload, resultTag);
+    }
     JITCompiler::Call callOperation(J_DFGOperation_EJ operation, GPRReg resultTag, GPRReg resultPayload, GPRReg arg1Tag, GPRReg arg1Payload)
     {
         m_jit.setupArgumentsWithExecState(EABI_32BIT_DUMMY_ARG arg1Payload, arg1Tag);
@@ -1819,11 +1839,21 @@ public:
         m_jit.setupArgumentsWithExecState(arg1, arg2, EABI_32BIT_DUMMY_ARG arg3Payload, arg3Tag);
         return appendCallWithExceptionCheck(operation);
     }
+    JITCompiler::Call callOperation(V_DFGOperation_EOZD operation, GPRReg arg1, GPRReg arg2, FPRReg arg3)
+    {
+        m_jit.setupArgumentsWithExecState(arg1, arg2, arg3);
+        return appendCallWithExceptionCheck(operation);
+    }
     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);
     }
+    JITCompiler::Call callOperation(V_DFGOperation_EOZJ operation, GPRReg arg1, GPRReg arg2, TrustedImm32 arg3Tag, GPRReg arg3Payload)
+    {
+        m_jit.setupArgumentsWithExecState(arg1, arg2, EABI_32BIT_DUMMY_ARG arg3Payload, arg3Tag);
+        return appendCallWithExceptionCheck(operation);
+    }
     JITCompiler::Call callOperation(V_DFGOperation_W operation, WatchpointSet* watchpointSet)
     {
         m_jit.setupArguments(TrustedImmPtr(watchpointSet));
@@ -2270,6 +2300,11 @@ public:
     void compileAllocatePropertyStorage(Node&);
     void compileReallocatePropertyStorage(Node&);
     
+#if USE(JSVALUE32_64)
+    template<typename BaseOperandType, typename PropertyOperandType, typename ValueOperandType, typename TagType>
+    void compileContiguousPutByVal(Node&, BaseOperandType&, PropertyOperandType&, ValueOperandType&, GPRReg valuePayloadReg, TagType valueTag);
+#endif
+    void compileDoublePutByVal(Node&, SpeculateCellOperand& base, SpeculateStrictInt32Operand& property);
     bool putByValWillNeedExtraRegister(ArrayMode arrayMode)
     {
         return arrayMode.mayStoreToHole();
@@ -2415,6 +2450,7 @@ public:
     
     const TypedArrayDescriptor* typedArrayDescriptor(ArrayMode);
     
+    JITCompiler::Jump jumpSlowForUnwantedArrayMode(GPRReg tempWithIndexingTypeReg, ArrayMode, IndexingType, bool invert);
     JITCompiler::JumpList jumpSlowForUnwantedArrayMode(GPRReg tempWithIndexingTypeReg, ArrayMode, bool invert = false);
     void checkArray(Node&);
     void arrayify(Node&, GPRReg baseReg, GPRReg propertyReg);
@@ -2955,6 +2991,11 @@ public:
             m_gprOrInvalid = m_jit->fillSpeculateInt(index(), m_format);
         return m_gprOrInvalid;
     }
+    
+    void use()
+    {
+        m_jit->use(m_index);
+    }
 
 private:
     SpeculativeJIT* m_jit;
@@ -3035,6 +3076,11 @@ public:
             m_fprOrInvalid = m_jit->fillSpeculateDouble(index());
         return m_fprOrInvalid;
     }
+    
+    void use()
+    {
+        m_jit->use(m_index);
+    }
 
 private:
     SpeculativeJIT* m_jit;
index 65fdf55..4c09ad0 100644 (file)
@@ -2046,6 +2046,69 @@ void SpeculativeJIT::emitBranch(Node& node)
     }
 }
 
+template<typename BaseOperandType, typename PropertyOperandType, typename ValueOperandType, typename TagType>
+void SpeculativeJIT::compileContiguousPutByVal(Node& node, BaseOperandType& base, PropertyOperandType& property, ValueOperandType& value, GPRReg valuePayloadReg, TagType valueTag)
+{
+    Edge child4 = m_jit.graph().varArgChild(node, 3);
+
+    ArrayMode arrayMode = node.arrayMode();
+    
+    GPRReg baseReg = base.gpr();
+    GPRReg propertyReg = property.gpr();
+    
+    StorageOperand storage(this, child4);
+    GPRReg storageReg = storage.gpr();
+
+    if (node.op() == PutByValAlias) {
+        // Store the value to the array.
+        GPRReg propertyReg = property.gpr();
+        m_jit.store32(valueTag, MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesEight, OBJECT_OFFSETOF(JSValue, u.asBits.tag)));
+        m_jit.store32(valuePayloadReg, MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesEight, OBJECT_OFFSETOF(JSValue, u.asBits.payload)));
+        
+        noResult(m_compileIndex);
+        return;
+    }
+    
+    MacroAssembler::JumpList slowCases;
+
+    if (arrayMode.isInBounds()) {
+        speculationCheck(
+            Uncountable, JSValueRegs(), NoNode,
+            m_jit.branch32(MacroAssembler::AboveOrEqual, propertyReg, MacroAssembler::Address(storageReg, Butterfly::offsetOfPublicLength())));
+    } else {
+        MacroAssembler::Jump inBounds = m_jit.branch32(MacroAssembler::Below, propertyReg, MacroAssembler::Address(storageReg, Butterfly::offsetOfPublicLength()));
+        
+        slowCases.append(m_jit.branch32(MacroAssembler::AboveOrEqual, propertyReg, MacroAssembler::Address(storageReg, Butterfly::offsetOfVectorLength())));
+        
+        if (!arrayMode.isOutOfBounds())
+            speculationCheck(Uncountable, JSValueRegs(), NoNode, slowCases);
+        
+        m_jit.add32(TrustedImm32(1), propertyReg);
+        m_jit.store32(propertyReg, MacroAssembler::Address(storageReg, Butterfly::offsetOfPublicLength()));
+        m_jit.sub32(TrustedImm32(1), propertyReg);
+        
+        inBounds.link(&m_jit);
+    }
+    
+    m_jit.store32(valueTag, MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesEight, OBJECT_OFFSETOF(JSValue, u.asBits.tag)));
+    m_jit.store32(valuePayloadReg, MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesEight, OBJECT_OFFSETOF(JSValue, u.asBits.payload)));
+    
+    base.use();
+    property.use();
+    value.use();
+    storage.use();
+    
+    if (arrayMode.isOutOfBounds()) {
+        addSlowPathGenerator(
+            slowPathCall(
+                slowCases, this,
+                m_jit.codeBlock()->isStrictMode() ? operationPutByValBeyondArrayBoundsStrict : operationPutByValBeyondArrayBoundsNonStrict,
+                NoResult, baseReg, propertyReg, valueTag, valuePayloadReg));
+    }
+
+    noResult(m_compileIndex, UseChildrenCalledExplicitly);    
+}
+
 void SpeculativeJIT::compile(Node& node)
 {
     NodeType op = node.op();
@@ -2567,6 +2630,7 @@ void SpeculativeJIT::compile(Node& node)
             jsValueResult(resultTag.gpr(), resultPayload.gpr(), m_compileIndex);
             break;
         }
+        case Array::Int32:
         case Array::Contiguous: {
             if (node.arrayMode().isInBounds()) {
                 SpeculateStrictInt32Operand property(this, node.child2());
@@ -2580,8 +2644,20 @@ void SpeculativeJIT::compile(Node& node)
             
                 speculationCheck(OutOfBounds, JSValueRegs(), NoNode, m_jit.branch32(MacroAssembler::AboveOrEqual, propertyReg, MacroAssembler::Address(storageReg, Butterfly::offsetOfPublicLength())));
             
-                GPRTemporary resultTag(this);
                 GPRTemporary resultPayload(this);
+                if (node.arrayMode().type() == Array::Int32) {
+                    speculationCheck(
+                        OutOfBounds, JSValueRegs(), NoNode,
+                        m_jit.branch32(
+                            MacroAssembler::Equal,
+                            MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesEight, OBJECT_OFFSETOF(JSValue, u.asBits.tag)),
+                            TrustedImm32(JSValue::EmptyValueTag)));
+                    m_jit.load32(MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesEight, OBJECT_OFFSETOF(JSValue, u.asBits.payload)), resultPayload.gpr());
+                    integerResult(resultPayload.gpr(), m_compileIndex);
+                    break;
+                }
+                
+                GPRTemporary resultTag(this);
                 m_jit.load32(MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesEight, OBJECT_OFFSETOF(JSValue, u.asBits.tag)), resultTag.gpr());
                 speculationCheck(OutOfBounds, JSValueRegs(), NoNode, m_jit.branch32(MacroAssembler::Equal, resultTag.gpr(), TrustedImm32(JSValue::EmptyValueTag)));
                 m_jit.load32(MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesEight, OBJECT_OFFSETOF(JSValue, u.asBits.payload)), resultPayload.gpr());
@@ -2621,6 +2697,60 @@ void SpeculativeJIT::compile(Node& node)
             jsValueResult(resultTagReg, resultPayloadReg, m_compileIndex);
             break;
         }
+        case Array::Double: {
+            if (node.arrayMode().isInBounds()) {
+                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, Butterfly::offsetOfPublicLength())));
+            
+                FPRTemporary result(this);
+                m_jit.loadDouble(MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesEight), result.fpr());
+                speculationCheck(OutOfBounds, JSValueRegs(), NoNode, m_jit.branchDouble(MacroAssembler::DoubleNotEqualOrUnordered, result.fpr(), result.fpr()));
+                doubleResult(result.fpr(), m_compileIndex);
+                break;
+            }
+
+            SpeculateCellOperand base(this, node.child1());
+            SpeculateStrictInt32Operand property(this, node.child2());
+            StorageOperand storage(this, node.child3());
+            
+            GPRReg baseReg = base.gpr();
+            GPRReg propertyReg = property.gpr();
+            GPRReg storageReg = storage.gpr();
+            
+            if (!m_compileOkay)
+                return;
+            
+            GPRTemporary resultTag(this);
+            GPRTemporary resultPayload(this);
+            FPRTemporary temp(this);
+            GPRReg resultTagReg = resultTag.gpr();
+            GPRReg resultPayloadReg = resultPayload.gpr();
+            FPRReg tempReg = temp.fpr();
+            
+            MacroAssembler::JumpList slowCases;
+            
+            slowCases.append(m_jit.branch32(MacroAssembler::AboveOrEqual, propertyReg, MacroAssembler::Address(storageReg, Butterfly::offsetOfPublicLength())));
+            
+            m_jit.loadDouble(MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesEight), tempReg);
+            slowCases.append(m_jit.branchDouble(MacroAssembler::DoubleNotEqualOrUnordered, tempReg, tempReg));
+            boxDouble(tempReg, resultTagReg, resultPayloadReg);
+
+            addSlowPathGenerator(
+                slowPathCall(
+                    slowCases, this, operationGetByValArrayInt,
+                    JSValueRegs(resultTagReg, resultPayloadReg), baseReg, propertyReg));
+            
+            jsValueResult(resultTagReg, resultPayloadReg, m_compileIndex);
+            break;
+        }
         case Array::ArrayStorage:
         case Array::SlowPutArrayStorage: {
             if (node.arrayMode().isInBounds()) {
@@ -2771,6 +2901,17 @@ void SpeculativeJIT::compile(Node& node)
         GPRReg propertyReg = property.gpr();
 
         switch (arrayMode.type()) {
+        case Array::Int32: {
+            SpeculateIntegerOperand value(this, child3);
+
+            GPRReg valuePayloadReg = value.gpr();
+        
+            if (!m_compileOkay)
+                return;
+            
+            compileContiguousPutByVal(node, base, property, value, valuePayloadReg, TrustedImm32(JSValue::Int32Tag));
+            break;
+        }
         case Array::Contiguous: {
             JSValueOperand value(this, child3);
 
@@ -2784,61 +2925,14 @@ void SpeculativeJIT::compile(Node& node)
                 GPRTemporary scratch(this);
                 writeBarrier(baseReg, valueTagReg, child3, WriteBarrierForPropertyAccess, scratch.gpr());
             }
-
-            StorageOperand storage(this, child4);
-            GPRReg storageReg = storage.gpr();
-
-            if (node.op() == PutByValAlias) {
-                // Store the value to the array.
-                GPRReg propertyReg = property.gpr();
-                m_jit.store32(valueTagReg, MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesEight, OBJECT_OFFSETOF(JSValue, u.asBits.tag)));
-                m_jit.store32(valuePayloadReg, MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesEight, OBJECT_OFFSETOF(JSValue, u.asBits.payload)));
-                
-                noResult(m_compileIndex);
-                break;
-            }
-            
-            MacroAssembler::JumpList slowCases;
-
-            if (arrayMode.isInBounds()) {
-                speculationCheck(
-                    Uncountable, JSValueRegs(), NoNode,
-                    m_jit.branch32(MacroAssembler::AboveOrEqual, propertyReg, MacroAssembler::Address(storageReg, Butterfly::offsetOfPublicLength())));
-            } else {
-                MacroAssembler::Jump inBounds = m_jit.branch32(MacroAssembler::Below, propertyReg, MacroAssembler::Address(storageReg, Butterfly::offsetOfPublicLength()));
-                
-                slowCases.append(m_jit.branch32(MacroAssembler::AboveOrEqual, propertyReg, MacroAssembler::Address(storageReg, Butterfly::offsetOfVectorLength())));
-                
-                if (!arrayMode.isOutOfBounds())
-                    speculationCheck(Uncountable, JSValueRegs(), NoNode, slowCases);
-                
-                m_jit.add32(TrustedImm32(1), propertyReg);
-                m_jit.store32(propertyReg, MacroAssembler::Address(storageReg, Butterfly::offsetOfPublicLength()));
-                m_jit.sub32(TrustedImm32(1), propertyReg);
-                
-                inBounds.link(&m_jit);
-            }
-            
-            m_jit.store32(valueTagReg, MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesEight, OBJECT_OFFSETOF(JSValue, u.asBits.tag)));
-            m_jit.store32(valuePayloadReg, MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesEight, OBJECT_OFFSETOF(JSValue, u.asBits.payload)));
-            
-            base.use();
-            property.use();
-            value.use();
-            storage.use();
             
-            if (arrayMode.isOutOfBounds()) {
-                addSlowPathGenerator(
-                    slowPathCall(
-                        slowCases, this,
-                        m_jit.codeBlock()->isStrictMode() ? operationPutByValBeyondArrayBoundsStrict : operationPutByValBeyondArrayBoundsNonStrict,
-                        NoResult, baseReg, propertyReg, valueTagReg, valuePayloadReg));
-            }
-
-            noResult(m_compileIndex, UseChildrenCalledExplicitly);
+            compileContiguousPutByVal(node, base, property, value, valuePayloadReg, valueTagReg);
+            break;
+        }
+        case Array::Double: {
+            compileDoublePutByVal(node, base, property);
             break;
         }
-            
         case Array::ArrayStorage:
         case Array::SlowPutArrayStorage: {
             JSValueOperand value(this, child3);
@@ -3028,24 +3122,47 @@ void SpeculativeJIT::compile(Node& node)
         ASSERT(node.arrayMode().isJSArray());
         
         SpeculateCellOperand base(this, node.child1());
-        JSValueOperand value(this, node.child2());
         GPRTemporary storageLength(this);
         
         GPRReg baseGPR = base.gpr();
-        GPRReg valueTagGPR = value.tagGPR();
-        GPRReg valuePayloadGPR = value.payloadGPR();
         GPRReg storageLengthGPR = storageLength.gpr();
         
-        if (Heap::isWriteBarrierEnabled()) {
-            GPRTemporary scratch(this);
-            writeBarrier(baseGPR, valueTagGPR, node.child2(), WriteBarrierForPropertyAccess, scratch.gpr(), storageLengthGPR);
-        }
-
         StorageOperand storage(this, node.child3());
         GPRReg storageGPR = storage.gpr();
         
         switch (node.arrayMode().type()) {
+        case Array::Int32: {
+            SpeculateIntegerOperand value(this, node.child2());
+            GPRReg valuePayloadGPR = value.gpr();
+            
+            m_jit.load32(MacroAssembler::Address(storageGPR, Butterfly::offsetOfPublicLength()), storageLengthGPR);
+            MacroAssembler::Jump slowPath = m_jit.branch32(MacroAssembler::AboveOrEqual, storageLengthGPR, MacroAssembler::Address(storageGPR, Butterfly::offsetOfVectorLength()));
+            m_jit.store32(TrustedImm32(JSValue::Int32Tag), MacroAssembler::BaseIndex(storageGPR, storageLengthGPR, MacroAssembler::TimesEight, OBJECT_OFFSETOF(JSValue, u.asBits.tag)));
+            m_jit.store32(valuePayloadGPR, MacroAssembler::BaseIndex(storageGPR, storageLengthGPR, MacroAssembler::TimesEight, OBJECT_OFFSETOF(JSValue, u.asBits.payload)));
+            m_jit.add32(TrustedImm32(1), storageLengthGPR);
+            m_jit.store32(storageLengthGPR, MacroAssembler::Address(storageGPR, Butterfly::offsetOfPublicLength()));
+            m_jit.move(TrustedImm32(JSValue::Int32Tag), storageGPR);
+            
+            addSlowPathGenerator(
+                slowPathCall(
+                    slowPath, this, operationArrayPush,
+                    JSValueRegs(storageGPR, storageLengthGPR),
+                    TrustedImm32(JSValue::Int32Tag), valuePayloadGPR, baseGPR));
+        
+            jsValueResult(storageGPR, storageLengthGPR, m_compileIndex);
+            break;
+        }
+            
         case Array::Contiguous: {
+            JSValueOperand value(this, node.child2());
+            GPRReg valueTagGPR = value.tagGPR();
+            GPRReg valuePayloadGPR = value.payloadGPR();
+
+            if (Heap::isWriteBarrierEnabled()) {
+                GPRTemporary scratch(this);
+                writeBarrier(baseGPR, valueTagGPR, node.child2(), WriteBarrierForPropertyAccess, scratch.gpr(), storageLengthGPR);
+            }
+
             m_jit.load32(MacroAssembler::Address(storageGPR, Butterfly::offsetOfPublicLength()), storageLengthGPR);
             MacroAssembler::Jump slowPath = m_jit.branch32(MacroAssembler::AboveOrEqual, storageLengthGPR, MacroAssembler::Address(storageGPR, Butterfly::offsetOfVectorLength()));
             m_jit.store32(valueTagGPR, MacroAssembler::BaseIndex(storageGPR, storageLengthGPR, MacroAssembler::TimesEight, OBJECT_OFFSETOF(JSValue, u.asBits.tag)));
@@ -3064,7 +3181,45 @@ void SpeculativeJIT::compile(Node& node)
             break;
         }
             
+        case Array::Double: {
+            SpeculateDoubleOperand value(this, node.child2());
+            FPRReg valueFPR = value.fpr();
+
+            if (!isRealNumberSpeculation(m_state.forNode(node.child2()).m_type)) {
+                // FIXME: We need a way of profiling these, and we need to hoist them into
+                // SpeculateDoubleOperand.
+                speculationCheck(
+                    BadType, JSValueRegs(), NoNode,
+                    m_jit.branchDouble(MacroAssembler::DoubleNotEqualOrUnordered, valueFPR, valueFPR));
+            }
+            
+            m_jit.load32(MacroAssembler::Address(storageGPR, Butterfly::offsetOfPublicLength()), storageLengthGPR);
+            MacroAssembler::Jump slowPath = m_jit.branch32(MacroAssembler::AboveOrEqual, storageLengthGPR, MacroAssembler::Address(storageGPR, Butterfly::offsetOfVectorLength()));
+            m_jit.storeDouble(valueFPR, MacroAssembler::BaseIndex(storageGPR, storageLengthGPR, MacroAssembler::TimesEight));
+            m_jit.add32(TrustedImm32(1), storageLengthGPR);
+            m_jit.store32(storageLengthGPR, MacroAssembler::Address(storageGPR, Butterfly::offsetOfPublicLength()));
+            m_jit.move(TrustedImm32(JSValue::Int32Tag), storageGPR);
+            
+            addSlowPathGenerator(
+                slowPathCall(
+                    slowPath, this, operationArrayPushDouble,
+                    JSValueRegs(storageGPR, storageLengthGPR),
+                    valueFPR, baseGPR));
+        
+            jsValueResult(storageGPR, storageLengthGPR, m_compileIndex);
+            break;
+        }
+            
         case Array::ArrayStorage: {
+            JSValueOperand value(this, node.child2());
+            GPRReg valueTagGPR = value.tagGPR();
+            GPRReg valuePayloadGPR = value.payloadGPR();
+
+            if (Heap::isWriteBarrierEnabled()) {
+                GPRTemporary scratch(this);
+                writeBarrier(baseGPR, valueTagGPR, node.child2(), WriteBarrierForPropertyAccess, scratch.gpr(), storageLengthGPR);
+            }
+
             m_jit.load32(MacroAssembler::Address(storageGPR, ArrayStorage::lengthOffset()), storageLengthGPR);
         
             // Refuse to handle bizarre lengths.
@@ -3107,6 +3262,7 @@ void SpeculativeJIT::compile(Node& node)
         GPRReg storageGPR = storage.gpr();
         
         switch (node.arrayMode().type()) {
+        case Array::Int32:
         case Array::Contiguous: {
             m_jit.load32(
                 MacroAssembler::Address(storageGPR, Butterfly::offsetOfPublicLength()), valuePayloadGPR);
@@ -3140,6 +3296,44 @@ void SpeculativeJIT::compile(Node& node)
             break;
         }
             
+        case Array::Double: {
+            FPRTemporary temp(this);
+            FPRReg tempFPR = temp.fpr();
+            
+            m_jit.load32(
+                MacroAssembler::Address(storageGPR, Butterfly::offsetOfPublicLength()), valuePayloadGPR);
+            MacroAssembler::Jump undefinedCase =
+                m_jit.branchTest32(MacroAssembler::Zero, valuePayloadGPR);
+            m_jit.sub32(TrustedImm32(1), valuePayloadGPR);
+            m_jit.store32(
+                valuePayloadGPR, MacroAssembler::Address(storageGPR, Butterfly::offsetOfPublicLength()));
+            m_jit.loadDouble(
+                MacroAssembler::BaseIndex(storageGPR, valuePayloadGPR, MacroAssembler::TimesEight),
+                tempFPR);
+            MacroAssembler::Jump slowCase = m_jit.branchDouble(MacroAssembler::DoubleNotEqualOrUnordered, tempFPR, tempFPR);
+            JSValue nan = JSValue(JSValue::EncodeAsDouble, QNaN);
+            m_jit.store32(
+                MacroAssembler::TrustedImm32(nan.u.asBits.tag),
+                MacroAssembler::BaseIndex(storageGPR, valuePayloadGPR, MacroAssembler::TimesEight, OBJECT_OFFSETOF(JSValue, u.asBits.tag)));
+            m_jit.store32(
+                MacroAssembler::TrustedImm32(nan.u.asBits.payload),
+                MacroAssembler::BaseIndex(storageGPR, valuePayloadGPR, MacroAssembler::TimesEight, OBJECT_OFFSETOF(JSValue, u.asBits.payload)));
+            boxDouble(tempFPR, valueTagGPR, valuePayloadGPR);
+
+            addSlowPathGenerator(
+                slowPathMove(
+                    undefinedCase, this,
+                    MacroAssembler::TrustedImm32(jsUndefined().tag()), valueTagGPR,
+                    MacroAssembler::TrustedImm32(jsUndefined().payload()), valuePayloadGPR));
+            addSlowPathGenerator(
+                slowPathCall(
+                    slowCase, this, operationArrayPopAndRecoverLength,
+                    JSValueRegs(valueTagGPR, valuePayloadGPR), baseGPR));
+            
+            jsValueResult(valueTagGPR, valuePayloadGPR, m_compileIndex);
+            break;
+        }
+
         case Array::ArrayStorage: {
             GPRTemporary storageLength(this);
             GPRReg storageLengthGPR = storageLength.gpr();
@@ -3358,11 +3552,17 @@ void SpeculativeJIT::compile(Node& node)
 
     case NewArray: {
         JSGlobalObject* globalObject = m_jit.graph().globalObjectFor(node.codeOrigin);
-        if (!globalObject->isHavingABadTime()) {
+        if (!globalObject->isHavingABadTime() && !hasArrayStorage(node.indexingType())) {
             globalObject->havingABadTimeWatchpoint()->add(speculationWatchpoint());
             
-            ASSERT(hasContiguous(globalObject->arrayStructure()->indexingType()));
-            
+            Structure* structure = globalObject->arrayStructureForIndexingTypeDuringAllocation(node.indexingType());
+            ASSERT(structure->indexingType() == node.indexingType());
+            ASSERT(
+                hasUndecided(structure->indexingType())
+                || hasInt32(structure->indexingType())
+                || hasDouble(structure->indexingType())
+                || hasContiguous(structure->indexingType()));
+
             unsigned numElements = node.numChildren();
             
             GPRTemporary result(this);
@@ -3371,17 +3571,52 @@ void SpeculativeJIT::compile(Node& node)
             GPRReg resultGPR = result.gpr();
             GPRReg storageGPR = storage.gpr();
 
-            emitAllocateJSArray(globalObject->arrayStructure(), resultGPR, storageGPR, numElements);
+            emitAllocateJSArray(structure, resultGPR, storageGPR, numElements);
             
             // At this point, one way or another, resultGPR and storageGPR have pointers to
             // the JSArray and the Butterfly, respectively.
             
+            ASSERT(!hasUndecided(structure->indexingType()) || !node.numChildren());
+            
             for (unsigned operandIdx = 0; operandIdx < node.numChildren(); ++operandIdx) {
-                JSValueOperand operand(this, m_jit.graph().m_varArgChildren[node.firstChild() + operandIdx]);
-                GPRReg opTagGPR = operand.tagGPR();
-                GPRReg opPayloadGPR = operand.payloadGPR();
-                m_jit.store32(opTagGPR, MacroAssembler::Address(storageGPR, sizeof(JSValue) * operandIdx + OBJECT_OFFSETOF(JSValue, u.asBits.tag)));
-                m_jit.store32(opPayloadGPR, MacroAssembler::Address(storageGPR, sizeof(JSValue) * operandIdx + OBJECT_OFFSETOF(JSValue, u.asBits.payload)));
+                Edge use = m_jit.graph().m_varArgChildren[node.firstChild() + operandIdx];
+                switch (node.indexingType()) {
+                case ALL_BLANK_INDEXING_TYPES:
+                case ALL_UNDECIDED_INDEXING_TYPES:
+                    CRASH();
+                    break;
+                case ALL_DOUBLE_INDEXING_TYPES: {
+                    SpeculateDoubleOperand operand(this, use);
+                    FPRReg opFPR = operand.fpr();
+                    if (!isRealNumberSpeculation(m_state.forNode(use).m_type)) {
+                        // FIXME: We need a way of profiling these, and we need to hoist them into
+                        // SpeculateDoubleOperand.
+                        speculationCheck(
+                            BadType, JSValueRegs(), NoNode,
+                            m_jit.branchDouble(MacroAssembler::DoubleNotEqualOrUnordered, opFPR, opFPR));
+                    }
+        
+                    m_jit.storeDouble(opFPR, MacroAssembler::Address(storageGPR, sizeof(double) * operandIdx));
+                    break;
+                }
+                case ALL_INT32_INDEXING_TYPES: {
+                    SpeculateIntegerOperand operand(this, use);
+                    m_jit.store32(TrustedImm32(JSValue::Int32Tag), MacroAssembler::Address(storageGPR, sizeof(JSValue) * operandIdx + OBJECT_OFFSETOF(JSValue, u.asBits.tag)));
+                    m_jit.store32(operand.gpr(), MacroAssembler::Address(storageGPR, sizeof(JSValue) * operandIdx + OBJECT_OFFSETOF(JSValue, u.asBits.payload)));
+                    break;
+                }
+                case ALL_CONTIGUOUS_INDEXING_TYPES: {
+                    JSValueOperand operand(this, m_jit.graph().m_varArgChildren[node.firstChild() + operandIdx]);
+                    GPRReg opTagGPR = operand.tagGPR();
+                    GPRReg opPayloadGPR = operand.payloadGPR();
+                    m_jit.store32(opTagGPR, MacroAssembler::Address(storageGPR, sizeof(JSValue) * operandIdx + OBJECT_OFFSETOF(JSValue, u.asBits.tag)));
+                    m_jit.store32(opPayloadGPR, MacroAssembler::Address(storageGPR, sizeof(JSValue) * operandIdx + OBJECT_OFFSETOF(JSValue, u.asBits.payload)));
+                    break;
+                }
+                default:
+                    CRASH();
+                    break;
+                }
             }
             
             // Yuck, we should *really* have a way of also returning the storageGPR. But
@@ -3399,7 +3634,7 @@ void SpeculativeJIT::compile(Node& node)
             flushRegisters();
             GPRResult result(this);
             callOperation(
-                operationNewEmptyArray, result.gpr(), globalObject->arrayStructure());
+                operationNewEmptyArray, result.gpr(), globalObject->arrayStructureForIndexingTypeDuringAllocation(node.indexingType()));
             cellResult(result.gpr(), m_compileIndex);
             break;
         }
@@ -3409,13 +3644,61 @@ void SpeculativeJIT::compile(Node& node)
         EncodedJSValue* buffer = scratchBuffer ? static_cast<EncodedJSValue*>(scratchBuffer->dataBuffer()) : 0;
         
         for (unsigned operandIdx = 0; operandIdx < node.numChildren(); ++operandIdx) {
-            JSValueOperand operand(this, m_jit.graph().m_varArgChildren[node.firstChild() + operandIdx]);
-            GPRReg opTagGPR = operand.tagGPR();
-            GPRReg opPayloadGPR = operand.payloadGPR();
-            operand.use();
-            
-            m_jit.store32(opTagGPR, reinterpret_cast<char*>(buffer + operandIdx) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.tag));
-            m_jit.store32(opPayloadGPR, reinterpret_cast<char*>(buffer + operandIdx) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.payload));
+            // Need to perform the speculations that this node promises to perform. If we're
+            // emitting code here and the indexing type is not array storage then there is
+            // probably something hilarious going on and we're already failing at all the
+            // things, but at least we're going to be sound.
+            Edge use = m_jit.graph().m_varArgChildren[node.firstChild() + operandIdx];
+            switch (node.indexingType()) {
+            case ALL_BLANK_INDEXING_TYPES:
+            case ALL_UNDECIDED_INDEXING_TYPES:
+                CRASH();
+                break;
+            case ALL_DOUBLE_INDEXING_TYPES: {
+                SpeculateDoubleOperand operand(this, use);
+                FPRReg opFPR = operand.fpr();
+                if (!isRealNumberSpeculation(m_state.forNode(use).m_type)) {
+                    // FIXME: We need a way of profiling these, and we need to hoist them into
+                    // SpeculateDoubleOperand.
+                    speculationCheck(
+                        BadType, JSValueRegs(), NoNode,
+                        m_jit.branchDouble(MacroAssembler::DoubleNotEqualOrUnordered, opFPR, opFPR));
+                }
+                
+                m_jit.storeDouble(opFPR, reinterpret_cast<char*>(buffer + operandIdx));
+                break;
+            }
+            case ALL_INT32_INDEXING_TYPES: {
+                SpeculateIntegerOperand operand(this, use);
+                GPRReg opGPR = operand.gpr();
+                m_jit.store32(TrustedImm32(JSValue::Int32Tag), reinterpret_cast<char*>(buffer + operandIdx) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.tag));
+                m_jit.store32(opGPR, reinterpret_cast<char*>(buffer + operandIdx) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.payload));
+                break;
+            }
+            case ALL_CONTIGUOUS_INDEXING_TYPES:
+            case ALL_ARRAY_STORAGE_INDEXING_TYPES: {
+                JSValueOperand operand(this, m_jit.graph().m_varArgChildren[node.firstChild() + operandIdx]);
+                GPRReg opTagGPR = operand.tagGPR();
+                GPRReg opPayloadGPR = operand.payloadGPR();
+                
+                m_jit.store32(opTagGPR, reinterpret_cast<char*>(buffer + operandIdx) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.tag));
+                m_jit.store32(opPayloadGPR, reinterpret_cast<char*>(buffer + operandIdx) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.payload));
+                operand.use();
+                break;
+            }
+            default:
+                CRASH();
+                break;
+            }
+        }
+        
+        switch (node.indexingType()) {
+        case ALL_DOUBLE_INDEXING_TYPES:
+        case ALL_INT32_INDEXING_TYPES:
+            useChildren(node);
+            break;
+        default:
+            break;
         }
         
         flushRegisters();
@@ -3431,8 +3714,8 @@ void SpeculativeJIT::compile(Node& node)
         GPRResult result(this);
         
         callOperation(
-            operationNewArray, result.gpr(), globalObject->arrayStructure(),
-            static_cast<void *>(buffer), node.numChildren());
+            operationNewArray, result.gpr(), globalObject->arrayStructureForIndexingTypeDuringAllocation(node.indexingType()),
+            static_cast<void*>(buffer), node.numChildren());
 
         if (scratchSize) {
             GPRTemporary scratch(this);
@@ -3471,17 +3754,30 @@ void SpeculativeJIT::compile(Node& node)
                 emitAllocateBasicStorage(resultGPR, storageGPR));
             m_jit.subPtr(scratchGPR, storageGPR);
             emitAllocateBasicJSObject<JSArray, MarkedBlock::None>(
-                TrustedImmPtr(globalObject->arrayStructure()), resultGPR, scratchGPR,
+                TrustedImmPtr(globalObject->arrayStructureForIndexingTypeDuringAllocation(node.indexingType())), resultGPR, scratchGPR,
                 storageGPR, sizeof(JSArray), slowCases);
             
             m_jit.store32(sizeGPR, MacroAssembler::Address(storageGPR, Butterfly::offsetOfPublicLength()));
             m_jit.store32(sizeGPR, MacroAssembler::Address(storageGPR, Butterfly::offsetOfVectorLength()));
             
+            if (hasDouble(node.indexingType())) {
+                JSValue nan = JSValue(JSValue::EncodeAsDouble, QNaN);
+                
+                m_jit.move(sizeGPR, scratchGPR);
+                MacroAssembler::Jump done = m_jit.branchTest32(MacroAssembler::Zero, scratchGPR);
+                MacroAssembler::Label loop = m_jit.label();
+                m_jit.sub32(TrustedImm32(1), scratchGPR);
+                m_jit.store32(TrustedImm32(nan.u.asBits.tag), MacroAssembler::BaseIndex(storageGPR, scratchGPR, MacroAssembler::TimesEight, OBJECT_OFFSETOF(JSValue, u.asBits.tag)));
+                m_jit.store32(TrustedImm32(nan.u.asBits.payload), MacroAssembler::BaseIndex(storageGPR, scratchGPR, MacroAssembler::TimesEight, OBJECT_OFFSETOF(JSValue, u.asBits.payload)));
+                m_jit.branchTest32(MacroAssembler::NonZero, scratchGPR).linkTo(loop, &m_jit);
+                done.link(&m_jit);
+            }
+            
             addSlowPathGenerator(adoptPtr(
                 new CallArrayAllocatorWithVariableSizeSlowPathGenerator(
                     slowCases, this, operationNewArrayWithSize, resultGPR,
-                    globalObject->arrayStructure(),
-                    globalObject->arrayStructureWithArrayStorage(),
+                    globalObject->arrayStructureForIndexingTypeDuringAllocation(node.indexingType()),
+                    globalObject->arrayStructureForIndexingTypeDuringAllocation(ArrayWithArrayStorage),
                     sizeGPR)));
             
             cellResult(resultGPR, m_compileIndex);
@@ -3492,15 +3788,24 @@ void SpeculativeJIT::compile(Node& node)
         GPRReg sizeGPR = size.gpr();
         flushRegisters();
         GPRResult result(this);
+        GPRReg resultGPR = result.gpr();
+        GPRReg structureGPR = selectScratchGPR(sizeGPR);
+        MacroAssembler::Jump bigLength = m_jit.branch32(MacroAssembler::AboveOrEqual, sizeGPR, TrustedImm32(MIN_SPARSE_ARRAY_INDEX));
+        m_jit.move(TrustedImmPtr(globalObject->arrayStructureForIndexingTypeDuringAllocation(node.indexingType())), structureGPR);
+        MacroAssembler::Jump done = m_jit.jump();
+        bigLength.link(&m_jit);
+        m_jit.move(TrustedImmPtr(globalObject->arrayStructureForIndexingTypeDuringAllocation(ArrayWithArrayStorage)), structureGPR);
+        done.link(&m_jit);
         callOperation(
-            operationNewArrayWithSize, result.gpr(), globalObject->arrayStructure(), sizeGPR);
-        cellResult(result.gpr(), m_compileIndex);
+            operationNewArrayWithSize, resultGPR, structureGPR, sizeGPR);
+        cellResult(resultGPR, m_compileIndex);
         break;
     }
         
     case NewArrayBuffer: {
         JSGlobalObject* globalObject = m_jit.graph().globalObjectFor(node.codeOrigin);
-        if (!globalObject->isHavingABadTime()) {
+        IndexingType indexingType = node.indexingType();
+        if (!globalObject->isHavingABadTime() && !hasArrayStorage(indexingType)) {
             globalObject->havingABadTimeWatchpoint()->add(speculationWatchpoint());
             
             unsigned numElements = node.numConstants();
@@ -3511,12 +3816,25 @@ void SpeculativeJIT::compile(Node& node)
             GPRReg resultGPR = result.gpr();
             GPRReg storageGPR = storage.gpr();
 
-            emitAllocateJSArray(globalObject->arrayStructure(), resultGPR, storageGPR, numElements);
+            emitAllocateJSArray(globalObject->arrayStructureForIndexingTypeDuringAllocation(indexingType), resultGPR, storageGPR, numElements);
             
-            int32_t* data = bitwise_cast<int32_t*>(m_jit.codeBlock()->constantBuffer(node.startConstant()));
-            for (unsigned index = 0; index < node.numConstants() * 2; ++index) {
-                m_jit.store32(
-                    Imm32(data[index]), MacroAssembler::Address(storageGPR, sizeof(int32_t) * index));
+            if (node.indexingType() == ArrayWithDouble) {
+                JSValue* data = m_jit.codeBlock()->constantBuffer(node.startConstant());
+                for (unsigned index = 0; index < node.numConstants(); ++index) {
+                    union {
+                        int32_t halves[2];
+                        double value;
+                    } u;
+                    u.value = data[index].asNumber();
+                    m_jit.store32(Imm32(u.halves[0]), MacroAssembler::Address(storageGPR, sizeof(double) * index));
+                    m_jit.store32(Imm32(u.halves[1]), MacroAssembler::Address(storageGPR, sizeof(double) * index + sizeof(int32_t)));
+                }
+            } else {
+                int32_t* data = bitwise_cast<int32_t*>(m_jit.codeBlock()->constantBuffer(node.startConstant()));
+                for (unsigned index = 0; index < node.numConstants() * 2; ++index) {
+                    m_jit.store32(
+                        Imm32(data[index]), MacroAssembler::Address(storageGPR, sizeof(int32_t) * index));
+                }
             }
             
             cellResult(resultGPR, m_compileIndex);
@@ -3526,7 +3844,7 @@ void SpeculativeJIT::compile(Node& node)
         flushRegisters();
         GPRResult result(this);
         
-        callOperation(operationNewArrayBuffer, result.gpr(), globalObject->arrayStructure(), node.startConstant(), node.numConstants());
+        callOperation(operationNewArrayBuffer, result.gpr(), globalObject->arrayStructureForIndexingTypeDuringAllocation(node.indexingType()), node.startConstant(), node.numConstants());
         
         cellResult(result.gpr(), m_compileIndex);
         break;
index 6c066c3..62f79e7 100644 (file)
@@ -2598,6 +2598,7 @@ void SpeculativeJIT::compile(Node& node)
             jsValueResult(result.gpr(), m_compileIndex);
             break;
         }
+        case Array::Int32:
         case Array::Contiguous: {
             if (node.arrayMode().isInBounds()) {
                 SpeculateStrictInt32Operand property(this, node.child2());
@@ -2614,7 +2615,7 @@ void SpeculativeJIT::compile(Node& node)
                 GPRTemporary result(this);
                 m_jit.load64(MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesEight), result.gpr());
                 speculationCheck(OutOfBounds, JSValueRegs(), NoNode, m_jit.branchTest64(MacroAssembler::Zero, result.gpr()));
-                jsValueResult(result.gpr(), m_compileIndex);
+                jsValueResult(result.gpr(), m_compileIndex, node.arrayMode().type() == Array::Int32 ? DataFormatJSInteger : DataFormatJS);
                 break;
             }
             
@@ -2647,6 +2648,60 @@ void SpeculativeJIT::compile(Node& node)
             jsValueResult(resultReg, m_compileIndex);
             break;
         }
+
+        case Array::Double: {
+            if (node.arrayMode().isInBounds()) {
+                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, Butterfly::offsetOfPublicLength())));
+            
+                FPRTemporary result(this);
+                m_jit.loadDouble(MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesEight), result.fpr());
+                speculationCheck(OutOfBounds, JSValueRegs(), NoNode, m_jit.branchDouble(MacroAssembler::DoubleNotEqualOrUnordered, result.fpr(), result.fpr()));
+                doubleResult(result.fpr(), m_compileIndex);
+                break;
+            }
+
+            SpeculateCellOperand base(this, node.child1());
+            SpeculateStrictInt32Operand property(this, node.child2());
+            StorageOperand storage(this, node.child3());
+            
+            GPRReg baseReg = base.gpr();
+            GPRReg propertyReg = property.gpr();
+            GPRReg storageReg = storage.gpr();
+            
+            if (!m_compileOkay)
+                return;
+            
+            GPRTemporary result(this);
+            FPRTemporary temp(this);
+            GPRReg resultReg = result.gpr();
+            FPRReg tempReg = temp.fpr();
+            
+            MacroAssembler::JumpList slowCases;
+            
+            slowCases.append(m_jit.branch32(MacroAssembler::AboveOrEqual, propertyReg, MacroAssembler::Address(storageReg, Butterfly::offsetOfPublicLength())));
+            
+            m_jit.loadDouble(MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesEight), tempReg);
+            slowCases.append(m_jit.branchDouble(MacroAssembler::DoubleNotEqualOrUnordered, tempReg, tempReg));
+            boxDouble(tempReg, resultReg);
+            
+            addSlowPathGenerator(
+                slowPathCall(
+                    slowCases, this, operationGetByValArrayInt,
+                    result.gpr(), baseReg, propertyReg));
+            
+            jsValueResult(resultReg, m_compileIndex);
+            break;
+        }
+
         case Array::ArrayStorage:
         case Array::SlowPutArrayStorage: {
             if (node.arrayMode().isInBounds()) {
@@ -2789,6 +2844,7 @@ void SpeculativeJIT::compile(Node& node)
         GPRReg propertyReg = property.gpr();
 
         switch (arrayMode.type()) {
+        case Array::Int32:
         case Array::Contiguous: {
             JSValueOperand value(this, child3);
 
@@ -2796,8 +2852,15 @@ void SpeculativeJIT::compile(Node& node)
         
             if (!m_compileOkay)
                 return;
+            
+            if (arrayMode.type() == Array::Int32
+                && !isInt32Speculation(m_state.forNode(child3).m_type)) {
+                speculationCheck(
+                    BadType, JSValueRegs(valueReg), child3,
+                    m_jit.branch64(MacroAssembler::Below, valueReg, GPRInfo::tagTypeNumberRegister));
+            }
         
-            if (Heap::isWriteBarrierEnabled()) {
+            if (arrayMode.type() == Array::Contiguous && Heap::isWriteBarrierEnabled()) {
                 GPRTemporary scratch(this);
                 writeBarrier(baseReg, value.gpr(), child3, WriteBarrierForPropertyAccess, scratch.gpr());
             }
@@ -2857,6 +2920,11 @@ void SpeculativeJIT::compile(Node& node)
             break;
         }
             
+        case Array::Double: {
+            compileDoublePutByVal(node, base, property);
+            break;
+        }
+            
         case Array::ArrayStorage:
         case Array::SlowPutArrayStorage: {
             JSValueOperand value(this, child3);
@@ -3081,23 +3149,31 @@ void SpeculativeJIT::compile(Node& node)
         ASSERT(node.arrayMode().isJSArray());
         
         SpeculateCellOperand base(this, node.child1());
-        JSValueOperand value(this, node.child2());
         GPRTemporary storageLength(this);
         
         GPRReg baseGPR = base.gpr();
-        GPRReg valueGPR = value.gpr();
         GPRReg storageLengthGPR = storageLength.gpr();
         
-        if (Heap::isWriteBarrierEnabled()) {
-            GPRTemporary scratch(this);
-            writeBarrier(baseGPR, valueGPR, node.child2(), WriteBarrierForPropertyAccess, scratch.gpr(), storageLengthGPR);
-        }
-
         StorageOperand storage(this, node.child3());
         GPRReg storageGPR = storage.gpr();
 
         switch (node.arrayMode().type()) {
+        case Array::Int32:
         case Array::Contiguous: {
+            JSValueOperand value(this, node.child2());
+            GPRReg valueGPR = value.gpr();
+
+            if (node.arrayMode().type() == Array::Int32 && !isInt32Speculation(m_state.forNode(node.child2()).m_type)) {
+                speculationCheck(
+                    BadType, JSValueRegs(valueGPR), node.child2(),
+                    m_jit.branch64(MacroAssembler::Below, valueGPR, GPRInfo::tagTypeNumberRegister));
+            }
+
+            if (node.arrayMode().type() != Array::Int32 && Heap::isWriteBarrierEnabled()) {
+                GPRTemporary scratch(this);
+                writeBarrier(baseGPR, valueGPR, node.child2(), WriteBarrierForPropertyAccess, scratch.gpr(), storageLengthGPR);
+            }
+            
             m_jit.load32(MacroAssembler::Address(storageGPR, Butterfly::offsetOfPublicLength()), storageLengthGPR);
             MacroAssembler::Jump slowPath = m_jit.branch32(MacroAssembler::AboveOrEqual, storageLengthGPR, MacroAssembler::Address(storageGPR, Butterfly::offsetOfVectorLength()));
             m_jit.store64(valueGPR, MacroAssembler::BaseIndex(storageGPR, storageLengthGPR, MacroAssembler::TimesEight));
@@ -3114,7 +3190,43 @@ void SpeculativeJIT::compile(Node& node)
             break;
         }
             
+        case Array::Double: {
+            SpeculateDoubleOperand value(this, node.child2());
+            FPRReg valueFPR = value.fpr();
+
+            if (!isRealNumberSpeculation(m_state.forNode(node.child2()).m_type)) {
+                // FIXME: We need a way of profiling these, and we need to hoist them into
+                // SpeculateDoubleOperand.
+                speculationCheck(
+                    BadType, JSValueRegs(), NoNode,
+                    m_jit.branchDouble(MacroAssembler::DoubleNotEqualOrUnordered, valueFPR, valueFPR));
+            }
+            
+            m_jit.load32(MacroAssembler::Address(storageGPR, Butterfly::offsetOfPublicLength()), storageLengthGPR);
+            MacroAssembler::Jump slowPath = m_jit.branch32(MacroAssembler::AboveOrEqual, storageLengthGPR, MacroAssembler::Address(storageGPR, Butterfly::offsetOfVectorLength()));
+            m_jit.storeDouble(valueFPR, MacroAssembler::BaseIndex(storageGPR, storageLengthGPR, MacroAssembler::TimesEight));
+            m_jit.add32(TrustedImm32(1), storageLengthGPR);
+            m_jit.store32(storageLengthGPR, MacroAssembler::Address(storageGPR, Butterfly::offsetOfPublicLength()));
+            m_jit.or64(GPRInfo::tagTypeNumberRegister, storageLengthGPR);
+            
+            addSlowPathGenerator(
+                slowPathCall(
+                    slowPath, this, operationArrayPushDouble, NoResult, storageLengthGPR,
+                    valueFPR, baseGPR));
+        
+            jsValueResult(storageLengthGPR, m_compileIndex);
+            break;
+        }
+            
         case Array::ArrayStorage: {
+            JSValueOperand value(this, node.child2());
+            GPRReg valueGPR = value.gpr();
+
+            if (Heap::isWriteBarrierEnabled()) {
+                GPRTemporary scratch(this);
+                writeBarrier(baseGPR, valueGPR, node.child2(), WriteBarrierForPropertyAccess, scratch.gpr(), storageLengthGPR);
+            }
+
             m_jit.load32(MacroAssembler::Address(storageGPR, ArrayStorage::lengthOffset()), storageLengthGPR);
         
             // Refuse to handle bizarre lengths.
@@ -3152,13 +3264,17 @@ void SpeculativeJIT::compile(Node& node)
         StorageOperand storage(this, node.child2());
         GPRTemporary value(this);
         GPRTemporary storageLength(this);
+        FPRTemporary temp(this); // This is kind of lame, since we don't always need it. I'm relying on the fact that we don't have FPR pressure, especially in code that uses pop().
         
         GPRReg baseGPR = base.gpr();
         GPRReg storageGPR = storage.gpr();
         GPRReg valueGPR = value.gpr();
         GPRReg storageLengthGPR = storageLength.gpr();
+        FPRReg tempFPR = temp.fpr();
         
         switch (node.arrayMode().type()) {
+        case Array::Int32:
+        case Array::Double:
         case Array::Contiguous: {
             m_jit.load32(
                 MacroAssembler::Address(storageGPR, Butterfly::offsetOfPublicLength()), storageLengthGPR);
@@ -3167,14 +3283,27 @@ void SpeculativeJIT::compile(Node& node)
             m_jit.sub32(TrustedImm32(1), storageLengthGPR);
             m_jit.store32(
                 storageLengthGPR, MacroAssembler::Address(storageGPR, Butterfly::offsetOfPublicLength()));
-            m_jit.load64(
-                MacroAssembler::BaseIndex(storageGPR, storageLengthGPR, MacroAssembler::TimesEight),
-                valueGPR);
-            // FIXME: This would not have to be here if changing the publicLength also zeroed the values between the old
-            // length and the new length.
-            m_jit.store64(
+            MacroAssembler::Jump slowCase;
+            if (node.arrayMode().type() == Array::Double) {
+                m_jit.loadDouble(
+                    MacroAssembler::BaseIndex(storageGPR, storageLengthGPR, MacroAssembler::TimesEight),
+                    tempFPR);
+                // FIXME: This would not have to be here if changing the publicLength also zeroed the values between the old
+                // length and the new length.
+                m_jit.store64(
+                MacroAssembler::TrustedImm64((int64_t)0), MacroAssembler::BaseIndex(storageGPR, storageLengthGPR, MacroAssembler::TimesEight));
+                slowCase = m_jit.branchDouble(MacroAssembler::DoubleNotEqualOrUnordered, tempFPR, tempFPR);
+                boxDouble(tempFPR, valueGPR);
+            } else {
+                m_jit.load64(
+                    MacroAssembler::BaseIndex(storageGPR, storageLengthGPR, MacroAssembler::TimesEight),
+                    valueGPR);
+                // FIXME: This would not have to be here if changing the publicLength also zeroed the values between the old
+                // length and the new length.
+                m_jit.store64(
                 MacroAssembler::TrustedImm64((int64_t)0), MacroAssembler::BaseIndex(storageGPR, storageLengthGPR, MacroAssembler::TimesEight));
-            MacroAssembler::Jump slowCase = m_jit.branchTest64(MacroAssembler::Zero, valueGPR);
+                slowCase = m_jit.branchTest64(MacroAssembler::Zero, valueGPR);
+            }
 
             addSlowPathGenerator(
                 slowPathMove(
@@ -3184,6 +3313,7 @@ void SpeculativeJIT::compile(Node& node)
                 slowPathCall(
                     slowCase, this, operationArrayPopAndRecoverLength, valueGPR, baseGPR));
             
+            // We can't know for sure that the result is an int because of the slow paths. :-/
             jsValueResult(valueGPR, m_compileIndex);
             break;
         }
@@ -3338,10 +3468,16 @@ void SpeculativeJIT::compile(Node& node)
         
     case NewArray: {
         JSGlobalObject* globalObject = m_jit.graph().globalObjectFor(node.codeOrigin);
-        if (!globalObject->isHavingABadTime()) {
+        if (!globalObject->isHavingABadTime() && !hasArrayStorage(node.indexingType())) {
             globalObject->havingABadTimeWatchpoint()->add(speculationWatchpoint());
             
-            ASSERT(hasContiguous(globalObject->arrayStructure()->indexingType()));
+            Structure* structure = globalObject->arrayStructureForIndexingTypeDuringAllocation(node.indexingType());
+            ASSERT(structure->indexingType() == node.indexingType());
+            ASSERT(
+                hasUndecided(structure->indexingType())
+                || hasInt32(structure->indexingType())
+                || hasDouble(structure->indexingType())
+                || hasContiguous(structure->indexingType()));
             
             unsigned numElements = node.numChildren();
             
@@ -3351,15 +3487,50 @@ void SpeculativeJIT::compile(Node& node)
             GPRReg resultGPR = result.gpr();
             GPRReg storageGPR = storage.gpr();
 
-            emitAllocateJSArray(globalObject->arrayStructure(), resultGPR, storageGPR, numElements);
+            emitAllocateJSArray(structure, resultGPR, storageGPR, numElements);
             
             // At this point, one way or another, resultGPR and storageGPR have pointers to
             // the JSArray and the Butterfly, respectively.
             
+            ASSERT(!hasUndecided(structure->indexingType()) || !node.numChildren());
+            
             for (unsigned operandIdx = 0; operandIdx < node.numChildren(); ++operandIdx) {
-                JSValueOperand operand(this, m_jit.graph().m_varArgChildren[node.firstChild() + operandIdx]);
-                GPRReg opGPR = operand.gpr();
-                m_jit.store64(opGPR, MacroAssembler::Address(storageGPR, sizeof(JSValue) * operandIdx));
+                Edge use = m_jit.graph().m_varArgChildren[node.firstChild() + operandIdx];
+                switch (node.indexingType()) {
+                case ALL_BLANK_INDEXING_TYPES:
+                case ALL_UNDECIDED_INDEXING_TYPES:
+                    CRASH();
+                    break;
+                case ALL_DOUBLE_INDEXING_TYPES: {
+                    SpeculateDoubleOperand operand(this, use);
+                    FPRReg opFPR = operand.fpr();
+                    if (!isRealNumberSpeculation(m_state.forNode(use).m_type)) {
+                        // FIXME: We need a way of profiling these, and we need to hoist them into
+                        // SpeculateDoubleOperand.
+                        speculationCheck(
+                            BadType, JSValueRegs(), NoNode,
+                            m_jit.branchDouble(MacroAssembler::DoubleNotEqualOrUnordered, opFPR, opFPR));
+                    }
+        
+                    m_jit.storeDouble(opFPR, MacroAssembler::Address(storageGPR, sizeof(double) * operandIdx));
+                    break;
+                }
+                case ALL_INT32_INDEXING_TYPES:
+                case ALL_CONTIGUOUS_INDEXING_TYPES: {
+                    JSValueOperand operand(this, use);
+                    GPRReg opGPR = operand.gpr();
+                    if (hasInt32(node.indexingType()) && !isInt32Speculation(m_state.forNode(use).m_type)) {
+                        speculationCheck(
+                            BadType, JSValueRegs(opGPR), use.index(),
+                            m_jit.branch64(MacroAssembler::Below, opGPR, GPRInfo::tagTypeNumberRegister));
+                    }
+                    m_jit.store64(opGPR, MacroAssembler::Address(storageGPR, sizeof(JSValue) * operandIdx));
+                    break;
+                }
+                default:
+                    CRASH();
+                    break;
+                }
             }
             
             // Yuck, we should *really* have a way of also returning the storageGPR. But
@@ -3376,7 +3547,7 @@ void SpeculativeJIT::compile(Node& node)
         if (!node.numChildren()) {
             flushRegisters();
             GPRResult result(this);
-            callOperation(operationNewEmptyArray, result.gpr(), globalObject->arrayStructure());
+            callOperation(operationNewEmptyArray, result.gpr(), globalObject->arrayStructureForIndexingTypeDuringAllocation(node.indexingType()));
             cellResult(result.gpr(), m_compileIndex);
             break;
         }
@@ -3386,11 +3557,65 @@ void SpeculativeJIT::compile(Node& node)
         EncodedJSValue* buffer = scratchBuffer ? static_cast<EncodedJSValue*>(scratchBuffer->dataBuffer()) : 0;
         
         for (unsigned operandIdx = 0; operandIdx < node.numChildren(); ++operandIdx) {
-            JSValueOperand operand(this, m_jit.graph().m_varArgChildren[node.firstChild() + operandIdx]);
-            GPRReg opGPR = operand.gpr();
-            operand.use();
-            
-            m_jit.store64(opGPR, buffer + operandIdx);
+            // Need to perform the speculations that this node promises to perform. If we're
+            // emitting code here and the indexing type is not array storage then there is
+            // probably something hilarious going on and we're already failing at all the
+            // things, but at least we're going to be sound.
+            Edge use = m_jit.graph().m_varArgChildren[node.firstChild() + operandIdx];
+            switch (node.indexingType()) {
+            case ALL_BLANK_INDEXING_TYPES:
+            case ALL_UNDECIDED_INDEXING_TYPES:
+                CRASH();
+                break;
+            case ALL_DOUBLE_INDEXING_TYPES: {
+                SpeculateDoubleOperand operand(this, use);
+                GPRTemporary scratch(this);
+                FPRReg opFPR = operand.fpr();
+                GPRReg scratchGPR = scratch.gpr();
+                if (!isRealNumberSpeculation(m_state.forNode(use).m_type)) {
+                    // FIXME: We need a way of profiling these, and we need to hoist them into
+                    // SpeculateDoubleOperand.
+                    speculationCheck(
+                        BadType, JSValueRegs(), NoNode,
+                        m_jit.branchDouble(MacroAssembler::DoubleNotEqualOrUnordered, opFPR, opFPR));
+                }
+                
+                m_jit.boxDouble(opFPR, scratchGPR);
+                m_jit.store64(scratchGPR, buffer + operandIdx);
+                break;
+            }
+            case ALL_INT32_INDEXING_TYPES: {
+                JSValueOperand operand(this, use);
+                GPRReg opGPR = operand.gpr();
+                if (hasInt32(node.indexingType()) && !isInt32Speculation(m_state.forNode(use).m_type)) {
+                    speculationCheck(
+                        BadType, JSValueRegs(opGPR), use.index(),
+                        m_jit.branch64(MacroAssembler::Below, opGPR, GPRInfo::tagTypeNumberRegister));
+                }
+                m_jit.store64(opGPR, buffer + operandIdx);
+                break;
+            }
+            case ALL_CONTIGUOUS_INDEXING_TYPES:
+            case ALL_ARRAY_STORAGE_INDEXING_TYPES: {
+                JSValueOperand operand(this, use);
+                GPRReg opGPR = operand.gpr();
+                m_jit.store64(opGPR, buffer + operandIdx);
+                operand.use();
+                break;
+            }
+            default:
+                CRASH();
+                break;
+            }
+        }
+        
+        switch (node.indexingType()) {
+        case ALL_DOUBLE_INDEXING_TYPES:
+        case ALL_INT32_INDEXING_TYPES:
+            useChildren(node);
+            break;
+        default:
+            break;
         }
         
         flushRegisters();
@@ -3406,7 +3631,7 @@ void SpeculativeJIT::compile(Node& node)
         GPRResult result(this);
         
         callOperation(
-            operationNewArray, result.gpr(), globalObject->arrayStructure(),
+            operationNewArray, result.gpr(), globalObject->arrayStructureForIndexingTypeDuringAllocation(node.indexingType()),
             static_cast<void*>(buffer), node.numChildren());
 
         if (scratchSize) {
@@ -3422,18 +3647,26 @@ void SpeculativeJIT::compile(Node& node)
         
     case NewArrayWithSize: {
         JSGlobalObject* globalObject = m_jit.graph().globalObjectFor(node.codeOrigin);
-        if (!globalObject->isHavingABadTime()) {
+        if (!globalObject->isHavingABadTime() && !hasArrayStorage(node.indexingType())) {
             globalObject->havingABadTimeWatchpoint()->add(speculationWatchpoint());
             
             SpeculateStrictInt32Operand size(this, node.child1());
             GPRTemporary result(this);
             GPRTemporary storage(this);
             GPRTemporary scratch(this);
+            GPRTemporary scratch2;
             
             GPRReg sizeGPR = size.gpr();
             GPRReg resultGPR = result.gpr();
             GPRReg storageGPR = storage.gpr();
             GPRReg scratchGPR = scratch.gpr();
+            GPRReg scratch2GPR = InvalidGPRReg;
+            
+            if (hasDouble(node.indexingType())) {
+                GPRTemporary realScratch2(this, size);
+                scratch2.adopt(realScratch2);
+                scratch2GPR = scratch2.gpr();
+            }
             
             MacroAssembler::JumpList slowCases;
             slowCases.append(m_jit.branch32(MacroAssembler::AboveOrEqual, sizeGPR, TrustedImm32(MIN_SPARSE_ARRAY_INDEX)));
@@ -3446,17 +3679,28 @@ void SpeculativeJIT::compile(Node& node)
                 emitAllocateBasicStorage(resultGPR, storageGPR));
             m_jit.subPtr(scratchGPR, storageGPR);
             emitAllocateBasicJSObject<JSArray, MarkedBlock::None>(
-                TrustedImmPtr(globalObject->arrayStructure()), resultGPR, scratchGPR,
+                TrustedImmPtr(globalObject->arrayStructureForIndexingTypeDuringAllocation(node.indexingType())), resultGPR, scratchGPR,
                 storageGPR, sizeof(JSArray), slowCases);
             
             m_jit.store32(sizeGPR, MacroAssembler::Address(storageGPR, Butterfly::offsetOfPublicLength()));
             m_jit.store32(sizeGPR, MacroAssembler::Address(storageGPR, Butterfly::offsetOfVectorLength()));
             
+            if (hasDouble(node.indexingType())) {
+                m_jit.move(TrustedImm64(bitwise_cast<int64_t>(QNaN)), scratchGPR);
+                m_jit.move(sizeGPR, scratch2GPR);
+                MacroAssembler::Jump done = m_jit.branchTest32(MacroAssembler::Zero, scratch2GPR);
+                MacroAssembler::Label loop = m_jit.label();
+                m_jit.sub32(TrustedImm32(1), scratch2GPR);
+                m_jit.store64(scratchGPR, MacroAssembler::BaseIndex(storageGPR, scratch2GPR, MacroAssembler::TimesEight));
+                m_jit.branchTest32(MacroAssembler::NonZero, scratch2GPR).linkTo(loop, &m_jit);
+                done.link(&m_jit);
+            }
+            
             addSlowPathGenerator(adoptPtr(
                 new CallArrayAllocatorWithVariableSizeSlowPathGenerator(
                     slowCases, this, operationNewArrayWithSize, resultGPR,
-                    globalObject->arrayStructure(),
-                    globalObject->arrayStructureWithArrayStorage(),
+                    globalObject->arrayStructureForIndexingTypeDuringAllocation(node.indexingType()),
+                    globalObject->arrayStructureForIndexingTypeDuringAllocation(ArrayWithArrayStorage),
                     sizeGPR)));
             
             cellResult(resultGPR, m_compileIndex);
@@ -3470,10 +3714,10 @@ void SpeculativeJIT::compile(Node& node)
         GPRReg resultGPR = result.gpr();
         GPRReg structureGPR = selectScratchGPR(sizeGPR);
         MacroAssembler::Jump bigLength = m_jit.branch32(MacroAssembler::AboveOrEqual, sizeGPR, TrustedImm32(MIN_SPARSE_ARRAY_INDEX));
-        m_jit.move(TrustedImmPtr(globalObject->arrayStructure()), structureGPR);
+        m_jit.move(TrustedImmPtr(globalObject->arrayStructureForIndexingTypeDuringAllocation(node.indexingType())), structureGPR);
         MacroAssembler::Jump done = m_jit.jump();
         bigLength.link(&m_jit);
-        m_jit.move(TrustedImmPtr(globalObject->arrayStructureWithArrayStorage()), structureGPR);
+        m_jit.move(TrustedImmPtr(globalObject->arrayStructureForIndexingTypeDuringAllocation(ArrayWithArrayStorage)), structureGPR);
         done.link(&m_jit);
         callOperation(operationNewArrayWithSize, resultGPR, structureGPR, sizeGPR);
         cellResult(resultGPR, m_compileIndex);
@@ -3520,7 +3764,8 @@ void SpeculativeJIT::compile(Node& node)
         
     case NewArrayBuffer: {
         JSGlobalObject* globalObject = m_jit.graph().globalObjectFor(node.codeOrigin);
-        if (!globalObject->isHavingABadTime()) {
+        IndexingType indexingType = node.indexingType();
+        if (!globalObject->isHavingABadTime() && !hasArrayStorage(indexingType)) {
             globalObject->havingABadTimeWatchpoint()->add(speculationWatchpoint());
             
             unsigned numElements = node.numConstants();
@@ -3531,13 +3776,23 @@ void SpeculativeJIT::compile(Node& node)
             GPRReg resultGPR = result.gpr();
             GPRReg storageGPR = storage.gpr();
 
-            emitAllocateJSArray(globalObject->arrayStructure(), resultGPR, storageGPR, numElements);
+            emitAllocateJSArray(globalObject->arrayStructureForIndexingTypeDuringAllocation(indexingType), resultGPR, storageGPR, numElements);
             
+            ASSERT(indexingType & IsArray);
             JSValue* data = m_jit.codeBlock()->constantBuffer(node.startConstant());
-            for (unsigned index = 0; index < node.numConstants(); ++index) {
-                m_jit.store64(
-                    Imm64(JSValue::encode(data[index])),
-                    MacroAssembler::Address(storageGPR, sizeof(JSValue) * index));
+            if (indexingType == ArrayWithDouble) {
+                for (unsigned index = 0; index < node.numConstants(); ++index) {
+                    double value = data[index].asNumber();
+                    m_jit.store64(
+                        Imm64(bitwise_cast<int64_t>(value)),
+                        MacroAssembler::Address(storageGPR, sizeof(double) * index));
+                }
+            } else {
+                for (unsigned index = 0; index < node.numConstants(); ++index) {
+                    m_jit.store64(
+                        Imm64(JSValue::encode(data[index])),
+                        MacroAssembler::Address(storageGPR, sizeof(JSValue) * index));
+                }
             }
             
             cellResult(resultGPR, m_compileIndex);
@@ -3547,7 +3802,7 @@ void SpeculativeJIT::compile(Node& node)
         flushRegisters();
         GPRResult result(this);
         
-        callOperation(operationNewArrayBuffer, result.gpr(), globalObject->arrayStructure(), node.startConstant(), node.numConstants());
+        callOperation(operationNewArrayBuffer, result.gpr(), globalObject->arrayStructureForIndexingTypeDuringAllocation(node.indexingType()), node.startConstant(), node.numConstants());
         
         cellResult(result.gpr(), m_compileIndex);
         break;
index dcf87d3..9b0879f 100644 (file)
@@ -474,7 +474,9 @@ namespace JSC {
         // Property is int-checked and zero extended. Base is cell checked.
         // Structure is already profiled. Returns the slow cases. Fall-through
         // case contains result in regT0, and it is not yet profiled.
-        JumpList emitContiguousGetByVal(Instruction*, PatchableJump& badType);
+        JumpList emitInt32GetByVal(Instruction* instruction, PatchableJump& badType) { return emitContiguousGetByVal(instruction, badType, Int32Shape); }
+        JumpList emitDoubleGetByVal(Instruction*, PatchableJump& badType);
+        JumpList emitContiguousGetByVal(Instruction*, PatchableJump& badType, IndexingType expectedShape = ContiguousShape);
         JumpList emitArrayStorageGetByVal(Instruction*, PatchableJump& badType);
         JumpList emitIntTypedArrayGetByVal(Instruction*, PatchableJump& badType, const TypedArrayDescriptor&, size_t elementSize, TypedArraySignedness);
         JumpList emitFloatTypedArrayGetByVal(Instruction*, PatchableJump& badType, const TypedArrayDescriptor&, size_t elementSize);
@@ -483,7 +485,20 @@ namespace JSC {
         // The value to store is not yet loaded. Property is int-checked and
         // zero-extended. Base is cell checked. Structure is already profiled.
         // returns the slow cases.
-        JumpList emitContiguousPutByVal(Instruction*, PatchableJump& badType);
+        JumpList emitInt32PutByVal(Instruction* currentInstruction, PatchableJump& badType)
+        {
+            return emitGenericContiguousPutByVal<Int32Shape>(currentInstruction, badType);
+        }
+        JumpList emitDoublePutByVal(Instruction* currentInstruction, PatchableJump& badType)
+        {
+            return emitGenericContiguousPutByVal<DoubleShape>(currentInstruction, badType);
+        }
+        JumpList emitContiguousPutByVal(Instruction* currentInstruction, PatchableJump& badType)
+        {
+            return emitGenericContiguousPutByVal<ContiguousShape>(currentInstruction, badType);
+        }
+        template<IndexingType indexingShape>
+        JumpList emitGenericContiguousPutByVal(Instruction*, PatchableJump& badType);
         JumpList emitArrayStoragePutByVal(Instruction*, PatchableJump& badType);
         JumpList emitIntTypedArrayPutByVal(Instruction*, PatchableJump& badType, const TypedArrayDescriptor&, size_t elementSize, TypedArraySignedness, TypedArrayRounding);
         JumpList emitFloatTypedArrayPutByVal(Instruction*, PatchableJump& badType, const TypedArrayDescriptor&, size_t elementSize);
index f6cec24..aeb8694 100644 (file)
@@ -39,7 +39,7 @@ namespace JSC {
 ExceptionHandler genericThrow(JSGlobalData* globalData, ExecState* callFrame, JSValue exceptionValue, unsigned vPCIndex)
 {
     ASSERT(exceptionValue);
-
+    
     globalData->exception = JSValue();
     HandlerInfo* handler = globalData->interpreter->throwException(callFrame, exceptionValue, vPCIndex); // This may update callFrame & exceptionValue!
     globalData->exception = exceptionValue;
index 410bdf7..e1aef34 100644 (file)
@@ -528,12 +528,12 @@ inline void JIT::emitArrayProfileStoreToHoleSpecialCase(ArrayProfile* arrayProfi
 #endif
 }
 
-static inline bool arrayProfileSaw(ArrayProfile* profile, IndexingType capability)
+static inline bool arrayProfileSaw(ArrayModes arrayModes, IndexingType capability)
 {
 #if ENABLE(VALUE_PROFILER)
-    return !!(profile->observedArrayModes() & (asArrayModes(NonArray | capability) | asArrayModes(ArrayClass | capability)));
+    return arrayModesInclude(arrayModes, capability);
 #else
-    UNUSED_PARAM(profile);
+    UNUSED_PARAM(arrayModes);
     UNUSED_PARAM(capability);
     return false;
 #endif
@@ -541,7 +541,13 @@ static inline bool arrayProfileSaw(ArrayProfile* profile, IndexingType capabilit
 
 inline JITArrayMode JIT::chooseArrayMode(ArrayProfile* profile)
 {
-    if (arrayProfileSaw(profile, ArrayStorageShape))
+    profile->computeUpdatedPrediction(m_codeBlock);
+    ArrayModes arrayModes = profile->observedArrayModes();
+    if (arrayProfileSaw(arrayModes, DoubleShape))
+        return JITDouble;
+    if (arrayProfileSaw(arrayModes, Int32Shape))
+        return JITInt32;
+    if (arrayProfileSaw(arrayModes, ArrayStorageShape))
         return JITArrayStorage;
     return JITContiguous;
 }
index 4fb9d8c..487f241 100644 (file)
@@ -1952,6 +1952,7 @@ void JIT::emit_op_new_array(Instruction* currentInstruction)
     JITStubCall stubCall(this, cti_op_new_array);
     stubCall.addArgument(TrustedImm32(currentInstruction[2].u.operand));
     stubCall.addArgument(TrustedImm32(currentInstruction[3].u.operand));
+    stubCall.addArgument(TrustedImmPtr(currentInstruction[4].u.arrayAllocationProfile));
     stubCall.call(currentInstruction[1].u.operand);
 }
 
@@ -1963,6 +1964,7 @@ void JIT::emit_op_new_array_with_size(Instruction* currentInstruction)
 #else
     stubCall.addArgument(currentInstruction[2].u.operand);
 #endif
+    stubCall.addArgument(TrustedImmPtr(currentInstruction[3].u.arrayAllocationProfile));
     stubCall.call(currentInstruction[1].u.operand);
 }
 
@@ -1971,6 +1973,7 @@ void JIT::emit_op_new_array_buffer(Instruction* currentInstruction)
     JITStubCall stubCall(this, cti_op_new_array_buffer);
     stubCall.addArgument(TrustedImm32(currentInstruction[2].u.operand));
     stubCall.addArgument(TrustedImm32(currentInstruction[3].u.operand));
+    stubCall.addArgument(TrustedImmPtr(currentInstruction[4].u.arrayAllocationProfile));
     stubCall.call(currentInstruction[1].u.operand);
 }
 
index 6362598..05dbf0c 100644 (file)
@@ -98,7 +98,7 @@ void JIT::emit_op_get_by_val(Instruction* currentInstruction)
     unsigned base = currentInstruction[2].u.operand;
     unsigned property = currentInstruction[3].u.operand;
     ArrayProfile* profile = currentInstruction[4].u.arrayProfile;
-
+    
     emitGetVirtualRegisters(base, regT0, property, regT1);
     emitJumpSlowCaseIfNotImmediateInteger(regT1);
 
@@ -120,6 +120,12 @@ void JIT::emit_op_get_by_val(Instruction* currentInstruction)
 
     JITArrayMode mode = chooseArrayMode(profile);
     switch (mode) {
+    case JITInt32:
+        slowCases = emitInt32GetByVal(currentInstruction, badType);
+        break;
+    case JITDouble:
+        slowCases = emitDoubleGetByVal(currentInstruction, badType);
+        break;
     case JITContiguous:
         slowCases = emitContiguousGetByVal(currentInstruction, badType);
         break;
@@ -148,11 +154,26 @@ void JIT::emit_op_get_by_val(Instruction* currentInstruction)
     m_byValCompilationInfo.append(ByValCompilationInfo(m_bytecodeOffset, badType, mode, done));
 }
 
-JIT::JumpList JIT::emitContiguousGetByVal(Instruction*, PatchableJump& badType)
+JIT::JumpList JIT::emitDoubleGetByVal(Instruction*, PatchableJump& badType)
 {
     JumpList slowCases;
     
-    badType = patchableBranch32(NotEqual, regT2, TrustedImm32(ContiguousShape));
+    badType = patchableBranch32(NotEqual, regT2, TrustedImm32(DoubleShape));
+    loadPtr(Address(regT0, JSObject::butterflyOffset()), regT2);
+    slowCases.append(branch32(AboveOrEqual, regT1, Address(regT2, Butterfly::offsetOfPublicLength())));
+    loadDouble(BaseIndex(regT2, regT1, TimesEight), fpRegT0);
+    slowCases.append(branchDouble(DoubleNotEqualOrUnordered, fpRegT0, fpRegT0));
+    moveDoubleTo64(fpRegT0, regT0);
+    sub64(tagTypeNumberRegister, regT0);
+    
+    return slowCases;
+}
+
+JIT::JumpList JIT::emitContiguousGetByVal(Instruction*, PatchableJump& badType, IndexingType expectedShape)
+{
+    JumpList slowCases;
+    
+    badType = patchableBranch32(NotEqual, regT2, TrustedImm32(expectedShape));
     loadPtr(Address(regT0, JSObject::butterflyOffset()), regT2);
     slowCases.append(branch32(AboveOrEqual, regT1, Address(regT2, Butterfly::offsetOfPublicLength())));
     load64(BaseIndex(regT2, regT1, TimesEight), regT0);
@@ -304,6 +325,12 @@ void JIT::emit_op_put_by_val(Instruction* currentInstruction)
     
     JITArrayMode mode = chooseArrayMode(profile);
     switch (mode) {
+    case JITInt32:
+        slowCases = emitInt32PutByVal(currentInstruction, badType);
+        break;
+    case JITDouble:
+        slowCases = emitDoublePutByVal(currentInstruction, badType);
+        break;
     case JITContiguous:
         slowCases = emitContiguousPutByVal(currentInstruction, badType);
         break;
@@ -325,24 +352,49 @@ void JIT::emit_op_put_by_val(Instruction* currentInstruction)
     emitWriteBarrier(regT0, regT3, regT1, regT3, ShouldFilterImmediates, WriteBarrierForPropertyAccess);
 }
 
-JIT::JumpList JIT::emitContiguousPutByVal(Instruction* currentInstruction, PatchableJump& badType)
+template<IndexingType indexingShape>
+JIT::JumpList JIT::emitGenericContiguousPutByVal(Instruction* currentInstruction, PatchableJump& badType)
 {
     unsigned value = currentInstruction[3].u.operand;
     ArrayProfile* profile = currentInstruction[4].u.arrayProfile;
     
-    badType = patchableBranch32(NotEqual, regT2, TrustedImm32(ContiguousShape));
+    JumpList slowCases;
+
+    badType = patchableBranch32(NotEqual, regT2, TrustedImm32(indexingShape));
     
     loadPtr(Address(regT0, JSObject::butterflyOffset()), regT2);
     Jump outOfBounds = branch32(AboveOrEqual, regT1, Address(regT2, Butterfly::offsetOfPublicLength()));
 
     Label storeResult = label();
     emitGetVirtualRegister(value, regT3);
-    store64(regT3, BaseIndex(regT2, regT1, TimesEight));
+    switch (indexingShape) {
+    case Int32Shape:
+        slowCases.append(emitJumpIfNotImmediateInteger(regT3));
+        store64(regT3, BaseIndex(regT2, regT1, TimesEight));
+        break;
+    case DoubleShape: {
+        Jump notInt = emitJumpIfNotImmediateInteger(regT3);
+        convertInt32ToDouble(regT3, fpRegT0);
+        Jump ready = jump();
+        notInt.link(this);
+        add64(tagTypeNumberRegister, regT3);
+        move64ToDouble(regT3, fpRegT0);
+        slowCases.append(branchDouble(DoubleNotEqualOrUnordered, fpRegT0, fpRegT0));
+        ready.link(this);
+        storeDouble(fpRegT0, BaseIndex(regT2, regT1, TimesEight));
+        break;
+    }
+    case ContiguousShape:
+        store64(regT3, BaseIndex(regT2, regT1, TimesEight));
+        break;
+    default:
+        CRASH();
+        break;
+    }
     
     Jump done = jump();
     outOfBounds.link(this);
     
-    JumpList slowCases;
     slowCases.append(branch32(AboveOrEqual, regT1, Address(regT2, Butterfly::offsetOfVectorLength())));
     
     emitArrayProfileStoreToHoleSpecialCase(profile);
@@ -394,12 +446,23 @@ void JIT::emitSlow_op_put_by_val(Instruction* currentInstruction, Vector<SlowCas
     unsigned base = currentInstruction[1].u.operand;
     unsigned property = currentInstruction[2].u.operand;
     unsigned value = currentInstruction[3].u.operand;
+    ArrayProfile* profile = currentInstruction[4].u.arrayProfile;
 
     linkSlowCase(iter); // property int32 check
     linkSlowCaseIfNotJSCell(iter, base); // base cell check
     linkSlowCase(iter); // base not array check
     linkSlowCase(iter); // out of bounds
     
+    JITArrayMode mode = chooseArrayMode(profile);
+    switch (mode) {
+    case JITInt32:
+    case JITDouble:
+        linkSlowCase(iter); // value type check
+        break;
+    default:
+        break;
+    }
+    
     Label slowPath = label();
 
     JITStubCall stubPutByValCall(this, cti_op_put_by_val);
@@ -1312,6 +1375,12 @@ void JIT::privateCompileGetByVal(ByValInfo* byValInfo, ReturnAddressPtr returnAd
     JumpList slowCases;
     
     switch (arrayMode) {
+    case JITInt32:
+        slowCases = emitInt32GetByVal(currentInstruction, badType);
+        break;
+    case JITDouble:
+        slowCases = emitDoubleGetByVal(currentInstruction, badType);
+        break;
     case JITContiguous:
         slowCases = emitContiguousGetByVal(currentInstruction, badType);
         break;
@@ -1375,6 +1444,12 @@ void JIT::privateCompilePutByVal(ByValInfo* byValInfo, ReturnAddressPtr returnAd
     JumpList slowCases;
     
     switch (arrayMode) {
+    case JITInt32:
+        slowCases = emitInt32PutByVal(currentInstruction, badType);
+        break;
+    case JITDouble:
+        slowCases = emitDoublePutByVal(currentInstruction, badType);
+        break;
     case JITContiguous:
         slowCases = emitContiguousPutByVal(currentInstruction, badType);
         break;
index 939766f..7ebcc41 100644 (file)
@@ -153,6 +153,12 @@ void JIT::emit_op_get_by_val(Instruction* currentInstruction)
     
     JITArrayMode mode = chooseArrayMode(profile);
     switch (mode) {
+    case JITInt32:
+        slowCases = emitInt32GetByVal(currentInstruction, badType);
+        break;
+    case JITDouble:
+        slowCases = emitDoubleGetByVal(currentInstruction, badType);
+        break;
     case JITContiguous:
         slowCases = emitContiguousGetByVal(currentInstruction, badType);
         break;
@@ -181,11 +187,11 @@ void JIT::emit_op_get_by_val(Instruction* currentInstruction)
     m_byValCompilationInfo.append(ByValCompilationInfo(m_bytecodeOffset, badType, mode, done));
 }
 
-JIT::JumpList JIT::emitContiguousGetByVal(Instruction*, PatchableJump& badType)
+JIT::JumpList JIT::emitContiguousGetByVal(Instruction*, PatchableJump& badType, IndexingType expectedShape)
 {
     JumpList slowCases;
     
-    badType = patchableBranch32(NotEqual, regT1, TrustedImm32(ContiguousShape));
+    badType = patchableBranch32(NotEqual, regT1, TrustedImm32(expectedShape));
     
     loadPtr(Address(regT0, JSObject::butterflyOffset()), regT3);
     slowCases.append(branch32(AboveOrEqual, regT2, Address(regT3, Butterfly::offsetOfPublicLength())));
@@ -197,6 +203,22 @@ JIT::JumpList JIT::emitContiguousGetByVal(Instruction*, PatchableJump& badType)
     return slowCases;
 }
 
+JIT::JumpList JIT::emitDoubleGetByVal(Instruction*, PatchableJump& badType)
+{
+    JumpList slowCases;
+    
+    badType = patchableBranch32(NotEqual, regT1, TrustedImm32(DoubleShape));
+    
+    loadPtr(Address(regT0, JSObject::butterflyOffset()), regT3);
+    slowCases.append(branch32(AboveOrEqual, regT2, Address(regT3, Butterfly::offsetOfPublicLength())));
+    
+    loadDouble(BaseIndex(regT3, regT2, TimesEight), fpRegT0);
+    slowCases.append(branchDouble(DoubleNotEqualOrUnordered, fpRegT0, fpRegT0));
+    moveDoubleToInts(fpRegT0, regT0, regT1);
+    
+    return slowCases;
+}
+
 JIT::JumpList JIT::emitArrayStorageGetByVal(Instruction*, PatchableJump& badType)
 {
     JumpList slowCases;
@@ -270,6 +292,12 @@ void JIT::emit_op_put_by_val(Instruction* currentInstruction)
     
     JITArrayMode mode = chooseArrayMode(profile);
     switch (mode) {
+    case JITInt32:
+        slowCases = emitInt32PutByVal(currentInstruction, badType);
+        break;
+    case JITDouble:
+        slowCases = emitDoublePutByVal(currentInstruction, badType);
+        break;
     case JITContiguous:
         slowCases = emitContiguousPutByVal(currentInstruction, badType);
         break;
@@ -289,7 +317,8 @@ void JIT::emit_op_put_by_val(Instruction* currentInstruction)
     m_byValCompilationInfo.append(ByValCompilationInfo(m_bytecodeOffset, badType, mode, done));
 }
 
-JIT::JumpList JIT::emitContiguousPutByVal(Instruction* currentInstruction, PatchableJump& badType)
+template<IndexingType indexingShape>
+JIT::JumpList JIT::emitGenericContiguousPutByVal(Instruction* currentInstruction, PatchableJump& badType)
 {
     unsigned value = currentInstruction[3].u.operand;
     ArrayProfile* profile = currentInstruction[4].u.arrayProfile;
@@ -303,8 +332,30 @@ JIT::JumpList JIT::emitContiguousPutByVal(Instruction* currentInstruction, Patch
     
     Label storeResult = label();
     emitLoad(value, regT1, regT0);
-    store32(regT0, BaseIndex(regT3, regT2, TimesEight, OBJECT_OFFSETOF(JSValue, u.asBits.payload)));
-    store32(regT1, BaseIndex(regT3, regT2, TimesEight, OBJECT_OFFSETOF(JSValue, u.asBits.tag)));
+    switch (indexingShape) {
+    case Int32Shape:
+        slowCases.append(branch32(NotEqual, regT1, TrustedImm32(JSValue::Int32Tag)));
+        // Fall through.
+    case ContiguousShape:
+        store32(regT0, BaseIndex(regT3, regT2, TimesEight, OBJECT_OFFSETOF(JSValue, u.asBits.payload)));
+        store32(regT1, BaseIndex(regT3, regT2, TimesEight, OBJECT_OFFSETOF(JSValue, u.asBits.tag)));
+        break;
+    case DoubleShape: {
+        Jump notInt = branch32(NotEqual, regT1, TrustedImm32(JSValue::Int32Tag));
+        convertInt32ToDouble(regT0, fpRegT0);
+        Jump ready = jump();
+        notInt.link(this);
+        moveIntsToDouble(regT0, regT1, fpRegT0, fpRegT1);
+        slowCases.append(branchDouble(DoubleNotEqualOrUnordered, fpRegT0, fpRegT0));
+        ready.link(this);
+        storeDouble(fpRegT0, BaseIndex(regT3, regT2, TimesEight));
+        break;
+    }
+    default:
+        CRASH();
+        break;
+    }
+        
     Jump done = jump();
     
     outOfBounds.link(this);
@@ -364,12 +415,23 @@ void JIT::emitSlow_op_put_by_val(Instruction* currentInstruction, Vector<SlowCas
     unsigned base = currentInstruction[1].u.operand;
     unsigned property = currentInstruction[2].u.operand;
     unsigned value = currentInstruction[3].u.operand;
+    ArrayProfile* profile = currentInstruction[4].u.arrayProfile;
     
     linkSlowCase(iter); // property int32 check
     linkSlowCaseIfNotJSCell(iter, base); // base cell check
     linkSlowCase(iter); // base not array check
     linkSlowCase(iter); // out of bounds
     
+    JITArrayMode mode = chooseArrayMode(profile);
+    switch (mode) {
+    case JITInt32:
+    case JITDouble:
+        linkSlowCase(iter); // value type check
+        break;
+    default:
+        break;
+    }
+    
     Label slowPath = label();
     
     JITStubCall stubPutByValCall(this, cti_op_put_by_val);
index 5ddb98d..521dfac 100644 (file)
@@ -1877,6 +1877,11 @@ DEFINE_STUB_FUNCTION(void, optimize)
     ASSERT(optimizedCodeBlock->getJITType() == JITCode::DFGJIT);
     
     if (void* address = DFG::prepareOSREntry(callFrame, optimizedCodeBlock, bytecodeIndex)) {
+        if (Options::showDFGDisassembly()) {
+            dataLog(
+                "Performing OSR from code block %p to code block %p, address %p to %p.\n",
+                codeBlock, optimizedCodeBlock, (STUB_RETURN_ADDRESS).value(), address);
+        }
 #if ENABLE(JIT_VERBOSE_OSR)
         dataLog("Optimizing %p succeeded, performing OSR after a delay of %u.\n", codeBlock, codeBlock->optimizationDelayCounter());
 #endif
@@ -2228,21 +2233,21 @@ DEFINE_STUB_FUNCTION(JSObject*, op_new_array)
 {
     STUB_INIT_STACK_FRAME(stackFrame);
 
-    return constructArray(stackFrame.callFrame, reinterpret_cast<JSValue*>(&stackFrame.callFrame->registers()[stackFrame.args[0].int32()]), stackFrame.args[1].int32());
+    return constructArray(stackFrame.callFrame, stackFrame.args[2].arrayAllocationProfile(), reinterpret_cast<JSValue*>(&stackFrame.callFrame->registers()[stackFrame.args[0].int32()]), stackFrame.args[1].int32());
 }
 
 DEFINE_STUB_FUNCTION(JSObject*, op_new_array_with_size)
 {
     STUB_INIT_STACK_FRAME(stackFrame);
     
-    return constructArrayWithSizeQuirk(stackFrame.callFrame, stackFrame.callFrame->lexicalGlobalObject(), stackFrame.args[0].jsValue());
+    return constructArrayWithSizeQuirk(stackFrame.callFrame, stackFrame.args[1].arrayAllocationProfile(), stackFrame.callFrame->lexicalGlobalObject(), stackFrame.args[0].jsValue());
 }
 
 DEFINE_STUB_FUNCTION(JSObject*, op_new_array_buffer)
 {
     STUB_INIT_STACK_FRAME(stackFrame);
     
-    return constructArray(stackFrame.callFrame, stackFrame.callFrame->codeBlock()->constantBuffer(stackFrame.args[0].int32()), stackFrame.args[1].int32());
+    return constructArray(stackFrame.callFrame, stackFrame.args[2].arrayAllocationProfile(), stackFrame.callFrame->codeBlock()->constantBuffer(stackFrame.args[0].int32()), stackFrame.args[1].int32());
 }
 
 DEFINE_STUB_FUNCTION(void, op_init_global_const_check)
@@ -2470,7 +2475,7 @@ DEFINE_STUB_FUNCTION(void, op_put_by_val)
     JSValue baseValue = stackFrame.args[0].jsValue();
     JSValue subscript = stackFrame.args[1].jsValue();
     JSValue value = stackFrame.args[2].jsValue();
-
+    
     if (baseValue.isObject() && subscript.isInt32()) {
         // See if it's worth optimizing at all.
         JSObject* object = asObject(baseValue);
index 5761236..3bf13bb 100644 (file)
@@ -45,6 +45,7 @@ namespace JSC {
 
     struct StructureStubInfo;
 
+    class ArrayAllocationProfile;
     class CodeBlock;
     class ExecutablePool;
     class FunctionExecutable;
@@ -85,6 +86,7 @@ namespace JSC {
         ReturnAddressPtr returnAddress() { return ReturnAddressPtr(asPointer); }
         ResolveOperations* resolveOperations() { return static_cast<ResolveOperations*>(asPointer); }
         PutToBaseOperation* putToBaseOperation() { return static_cast<PutToBaseOperation*>(asPointer); }
+        ArrayAllocationProfile* arrayAllocationProfile() { return static_cast<ArrayAllocationProfile*>(asPointer); }
     };
     
     struct TrampolineStructure {
index b8cf49d..1771a17 100644 (file)
@@ -231,7 +231,7 @@ protected:
         addConstructableFunction(globalData, "Float32Array", constructJSFloat32Array, 1);
         addConstructableFunction(globalData, "Float64Array", constructJSFloat64Array, 1);
 
-        JSArray* array = constructEmptyArray(globalExec());
+        JSArray* array = constructEmptyArray(globalExec(), 0);
         for (size_t i = 0; i < arguments.size(); ++i)
             array->putDirectIndex(globalExec(), i, jsString(globalExec(), arguments[i]));
         putDirect(globalData, Identifier(globalExec(), "arguments"), array);
index ba44bf4..8a578ff 100644 (file)
@@ -275,7 +275,7 @@ inline bool shouldJIT(ExecState* exec)
 // Returns true if we should try to OSR.
 inline bool jitCompileAndSetHeuristics(CodeBlock* codeBlock, ExecState* exec)
 {
-    codeBlock->updateAllPredictions();
+    codeBlock->updateAllValueProfilePredictions();
     
     if (!codeBlock->checkIfJITThresholdReached()) {
 #if ENABLE(JIT_VERBOSE_OSR)
@@ -510,19 +510,19 @@ LLINT_SLOW_PATH_DECL(slow_path_new_object)
 LLINT_SLOW_PATH_DECL(slow_path_new_array)
 {
     LLINT_BEGIN();
-    LLINT_RETURN(constructArray(exec, bitwise_cast<JSValue*>(&LLINT_OP(2)), pc[3].u.operand));
+    LLINT_RETURN(constructArray(exec, pc[4].u.arrayAllocationProfile, bitwise_cast<JSValue*>(&LLINT_OP(2)), pc[3].u.operand));
 }
 
 LLINT_SLOW_PATH_DECL(slow_path_new_array_with_size)
 {
     LLINT_BEGIN();
-    LLINT_RETURN(constructArrayWithSizeQuirk(exec, exec->lexicalGlobalObject(), LLINT_OP_C(2).jsValue()));
+    LLINT_RETURN(constructArrayWithSizeQuirk(exec, pc[3].u.arrayAllocationProfile, exec->lexicalGlobalObject(), LLINT_OP_C(2).jsValue()));
 }
 
 LLINT_SLOW_PATH_DECL(slow_path_new_array_buffer)
 {
     LLINT_BEGIN();
-    LLINT_RETURN(constructArray(exec, exec->codeBlock()->constantBuffer(pc[2].u.operand), pc[3].u.operand));
+    LLINT_RETURN(constructArray(exec, pc[4].u.arrayAllocationProfile, exec->codeBlock()->constantBuffer(pc[2].u.operand), pc[3].u.operand));
 }
 
 LLINT_SLOW_PATH_DECL(slow_path_new_regexp)
index ba5b67d..00d5c4f 100644 (file)
@@ -88,10 +88,13 @@ else
 end
 
 # Constant for reasoning about butterflies.
-const IsArray = 1
-const IndexingShapeMask = 30
-const ContiguousShape = 26
-const ArrayStorageShape = 28
+const IsArray                  = 1
+const IndexingShapeMask        = 30
+const NoIndexingShape          = 0
+const Int32Shape               = 20
+const DoubleShape              = 22
+const ContiguousShape          = 26
+const ArrayStorageShape        = 28
 const SlowPutArrayStorageShape = 30
 
 # Type constants.
@@ -462,19 +465,19 @@ end
 _llint_op_new_array:
     traceExecution()
     callSlowPath(_llint_slow_path_new_array)
-    dispatch(4)
+    dispatch(5)
 
 
 _llint_op_new_array_with_size:
     traceExecution()
     callSlowPath(_llint_slow_path_new_array_with_size)
-    dispatch(3)
+    dispatch(4)
 
 
 _llint_op_new_array_buffer:
     traceExecution()
     callSlowPath(_llint_slow_path_new_array_buffer)
-    dispatch(4)
+    dispatch(5)
 
 
 _llint_op_new_regexp:
index ffb1462..e3ef909 100644 (file)
@@ -1185,7 +1185,9 @@ _llint_op_get_by_val:
     loadConstantOrVariablePayload(t3, Int32Tag, t1, .opGetByValSlow)
     loadp JSObject::m_butterfly[t0], t3
     andi IndexingShapeMask, t2
+    bieq t2, Int32Shape, .opGetByValIsContiguous
     bineq t2, ContiguousShape, .opGetByValNotContiguous
+.opGetByValIsContiguous:
     
     biaeq t1, -sizeof IndexingHeader + IndexingHeader::m_publicLength[t3], .opGetByValSlow
     loadi TagOffset[t3, t1, 8], t2
@@ -1193,6 +1195,16 @@ _llint_op_get_by_val:
     jmp .opGetByValDone
 
 .opGetByValNotContiguous:
+    bineq t2, DoubleShape, .opGetByValNotDouble
+    biaeq t1, -sizeof IndexingHeader + IndexingHeader::m_publicLength[t3], .opGetByValSlow
+    loadd [t3, t1, 8], ft0
+    bdnequn ft0, ft0, .opGetByValSlow
+    # FIXME: This could be massively optimized.
+    fd2ii ft0, t1, t2
+    loadi 4[PC], t0
+    jmp .opGetByValNotEmpty
+
+.opGetByValNotDouble:
     subi ArrayStorageShape, t2
     bia t2, SlowPutArrayStorageShape - ArrayStorageShape, .opGetByValSlow
     biaeq t1, -sizeof IndexingHeader + IndexingHeader::m_vectorLength[t3], .opGetByValSlow
@@ -1202,6 +1214,7 @@ _llint_op_get_by_val:
 .opGetByValDone:
     loadi 4[PC], t0
     bieq t2, EmptyValueTag, .opGetByValSlow
+.opGetByValNotEmpty:
     storei t2, TagOffset[cfr, t0, 8]
     storei t1, PayloadOffset[cfr, t0, 8]
     loadi 20[PC], t0
@@ -1270,6 +1283,24 @@ _llint_op_get_by_pname:
     dispatch(7)
 
 
+macro contiguousPutByVal(storeCallback)
+    biaeq t3, -sizeof IndexingHeader + IndexingHeader::m_publicLength[t0], .outOfBounds
+.storeResult:
+    loadi 12[PC], t2
+    storeCallback(t2, t1, t0, t3)
+    dispatch(5)
+
+.outOfBounds:
+    biaeq t3, -sizeof IndexingHeader + IndexingHeader::m_vectorLength[t0], .opPutByValSlow
+    if VALUE_PROFILER
+        loadp 16[PC], t2
+        storeb 1, ArrayProfile::m_mayStoreToHole[t2]
+    end
+    addi 1, t3, t2
+    storei t2, -sizeof IndexingHeader + IndexingHeader::m_publicLength[t0]
+    jmp .storeResult
+end
+
 _llint_op_put_by_val:
     traceExecution()
     loadi 4[PC], t0
@@ -1281,26 +1312,42 @@ _llint_op_put_by_val:
     loadConstantOrVariablePayload(t0, Int32Tag, t3, .opPutByValSlow)
     loadp JSObject::m_butterfly[t1], t0
     andi IndexingShapeMask, t2
-    bineq t2, ContiguousShape, .opPutByValNotContiguous
+    bineq t2, Int32Shape, .opPutByValNotInt32
+    contiguousPutByVal(
+        macro (operand, scratch, base, index)
+            loadConstantOrVariablePayload(operand, Int32Tag, scratch, .opPutByValSlow)
+            storei Int32Tag, TagOffset[base, index, 8]
+            storei scratch, PayloadOffset[base, index, 8]
+        end)
 
-    biaeq t3, -sizeof IndexingHeader + IndexingHeader::m_publicLength[t0], .opPutByValContiguousOutOfBounds
-.opPutByValContiguousStoreResult:
-    loadi 12[PC], t2
-    loadConstantOrVariable2Reg(t2, t1, t2)
-    writeBarrier(t1, t2)
-    storei t1, TagOffset[t0, t3, 8]
-    storei t2, PayloadOffset[t0, t3, 8]
-    dispatch(5)
+.opPutByValNotInt32:
+    bineq t2, DoubleShape, .opPutByValNotDouble
+    contiguousPutByVal(
+        macro (operand, scratch, base, index)
+            const tag = scratch
+            const payload = operand
+            loadConstantOrVariable2Reg(operand, tag, payload)
+            bineq tag, Int32Tag, .notInt
+            ci2d payload, ft0
+            jmp .ready
+        .notInt:
+            fii2d payload, tag, ft0
+            bdnequn ft0, ft0, .opPutByValSlow
+        .ready:
+            stored ft0, [base, index, 8]
+        end)
 
-.opPutByValContiguousOutOfBounds:
-    biaeq t3, -sizeof IndexingHeader + IndexingHeader::m_vectorLength[t0], .opPutByValSlow
-    if VALUE_PROFILER
-        loadp 16[PC], t1
-        storeb 1, ArrayProfile::m_mayStoreToHole[t1]
-    end
-    addi 1, t3, t2
-    storei t2, -sizeof IndexingHeader + IndexingHeader::m_publicLength[t0]
-    jmp .opPutByValContiguousStoreResult
+.opPutByValNotDouble:
+    bineq t2, ContiguousShape, .opPutByValNotContiguous
+    contiguousPutByVal(
+        macro (operand, scratch, base, index)
+            const tag = scratch
+            const payload = operand
+            loadConstantOrVariable2Reg(operand, tag, payload)
+            writeBarrier(tag, payload)
+            storei tag, TagOffset[base, index, 8]
+            storei payload, PayloadOffset[base, index, 8]
+        end)
 
 .opPutByValNotContiguous:
     bineq t2, ArrayStorageShape, .opPutByValSlow
index c9900b3..d8a2933 100644 (file)
@@ -1025,7 +1025,9 @@ _llint_op_get_by_val:
     sxi2q t1, t1
     loadp JSObject::m_butterfly[t0], t3
     andi IndexingShapeMask, t2
+    bieq t2, Int32Shape, .opGetByValIsContiguous
     bineq t2, ContiguousShape, .opGetByValNotContiguous
+.opGetByValIsContiguous:
 
     biaeq t1, -sizeof IndexingHeader + IndexingHeader::m_publicLength[t3], .opGetByValSlow
     loadisFromInstruction(1, t0)
@@ -1034,6 +1036,16 @@ _llint_op_get_by_val:
     jmp .opGetByValDone
 
 .opGetByValNotContiguous:
+    bineq t2, DoubleShape, .opGetByValNotDouble
+    biaeq t1, -sizeof IndexingHeader + IndexingHeader::m_publicLength[t3], .opGetByValSlow
+    loadis 8[PB, PC, 8], t0
+    loadd [t3, t1, 8], ft0
+    bdnequn ft0, ft0, .opGetByValSlow
+    fd2q ft0, t2
+    subq tagTypeNumber, t2
+    jmp .opGetByValDone
+    
+.opGetByValNotDouble:
     subi ArrayStorageShape, t2
     bia t2, SlowPutArrayStorageShape - ArrayStorageShape, .opGetByValSlow
     biaeq t1, -sizeof IndexingHeader + IndexingHeader::m_vectorLength[t3], .opGetByValSlow
@@ -1109,6 +1121,24 @@ _llint_op_get_by_pname:
     dispatch(7)
 
 
+macro contiguousPutByVal(storeCallback)
+    biaeq t3, -sizeof IndexingHeader + IndexingHeader::m_publicLength[t0], .outOfBounds
+.storeResult:
+    loadisFromInstruction(3, t2)
+    storeCallback(t2, t1, [t0, t3, 8])
+    dispatch(5)
+
+.outOfBounds:
+    biaeq t3, -sizeof IndexingHeader + IndexingHeader::m_vectorLength[t0], .opPutByValSlow
+    if VALUE_PROFILER
+        loadp 32[PB, PC, 8], t2
+        storeb 1, ArrayProfile::m_mayStoreToHole[t2]
+    end
+    addi 1, t3, t2
+    storei t2, -sizeof IndexingHeader + IndexingHeader::m_publicLength[t0]
+    jmp .storeResult
+end
+
 _llint_op_put_by_val:
     traceExecution()
     loadisFromInstruction(1, t0)
@@ -1121,25 +1151,38 @@ _llint_op_put_by_val:
     sxi2q t3, t3
     loadp JSObject::m_butterfly[t1], t0
     andi IndexingShapeMask, t2
-    bineq t2, ContiguousShape, .opPutByValNotContiguous
-    
-    biaeq t3, -sizeof IndexingHeader + IndexingHeader::m_publicLength[t0], .opPutByValContiguousOutOfBounds
-.opPutByValContiguousStoreResult:
-    loadisFromInstruction(3, t2)
-    loadConstantOrVariable(t2, t1)
-    writeBarrier(t1)
-    storeq t1, [t0, t3, 8]
-    dispatch(5)
+    bineq t2, Int32Shape, .opPutByValNotInt32
+    contiguousPutByVal(
+        macro (operand, scratch, address)
+            loadConstantOrVariable(operand, scratch)
+            bpb scratch, tagTypeNumber, .opPutByValSlow
+            storep scratch, address
+        end)
 
-.opPutByValContiguousOutOfBounds:
-    biaeq t3, -sizeof IndexingHeader + IndexingHeader::m_vectorLength[t0], .opPutByValSlow
-    if VALUE_PROFILER
-        loadpFromInstruction(4, t2)
-        storeb 1, ArrayProfile::m_mayStoreToHole[t2]
-    end
-    addi 1, t3, t2
-    storei t2, -sizeof IndexingHeader + IndexingHeader::m_publicLength[t0]
-    jmp .opPutByValContiguousStoreResult
+.opPutByValNotInt32:
+    bineq t2, DoubleShape, .opPutByValNotDouble
+    contiguousPutByVal(
+        macro (operand, scratch, address)
+            loadConstantOrVariable(operand, scratch)
+            bqb scratch, tagTypeNumber, .notInt
+            ci2d scratch, ft0
+            jmp .ready
+        .notInt:
+            addp tagTypeNumber, scratch
+            fq2d scratch, ft0
+            bdnequn ft0, ft0, .opPutByValSlow
+        .ready:
+            stored ft0, address
+        end)
+
+.opPutByValNotDouble:
+    bineq t2, ContiguousShape, .opPutByValNotContiguous
+    contiguousPutByVal(
+        macro (operand, scratch, address)
+            loadConstantOrVariable(operand, scratch)
+            writeBarrier(scratch)
+            storep scratch, address
+        end)
 
 .opPutByValNotContiguous:
     bineq t2, ArrayStorageShape, .opPutByValSlow
index 67cbd14..f78b439 100644 (file)
@@ -764,11 +764,16 @@ class Instruction
         when "ci2d"
             $asm.puts "cvtsi2sd #{operands[0].x86Operand(:int)}, #{operands[1].x86Operand(:double)}"
         when "bdeq"
-            isUnordered = LocalLabel.unique("bdeq")
             $asm.puts "ucomisd #{operands[0].x86Operand(:double)}, #{operands[1].x86Operand(:double)}"
-            $asm.puts "jp #{LabelReference.new(codeOrigin, isUnordered).asmLabel}"
-            $asm.puts "je #{LabelReference.new(codeOrigin, operands[2]).asmLabel}"
-            isUnordered.lower("X86")
+            if operands[0] == operands[1]
+                # This is just a jump ordered, which is a jnp.
+                $asm.puts "jnp #{operands[2].asmLabel}"
+            else
+                isUnordered = LocalLabel.unique("bdeq")
+                $asm.puts "jp #{LabelReference.new(codeOrigin, isUnordered).asmLabel}"
+                $asm.puts "je #{LabelReference.new(codeOrigin, operands[2]).asmLabel}"
+                isUnordered.lower("X86")
+            end
         when "bdneq"
             handleX86DoubleBranch("jne", :normal)
         when "bdgt"
@@ -782,14 +787,19 @@ class Instruction
         when "bdequn"
             handleX86DoubleBranch("je", :normal)
         when "bdnequn"
-            isUnordered = LocalLabel.unique("bdnequn")
-            isEqual = LocalLabel.unique("bdnequn")
             $asm.puts "ucomisd #{operands[0].x86Operand(:double)}, #{operands[1].x86Operand(:double)}"
-            $asm.puts "jp #{LabelReference.new(codeOrigin, isUnordered).asmLabel}"
-            $asm.puts "je #{LabelReference.new(codeOrigin, isEqual).asmLabel}"
-            isUnordered.lower("X86")
-            $asm.puts "jmp #{operands[2].asmLabel}"
-            isEqual.lower("X86")
+            if operands[0] == operands[1]
+                # This is just a jump unordered, which is a jp.
+                $asm.puts "jp #{operands[2].asmLabel}"
+            else
+                isUnordered = LocalLabel.unique("bdnequn")
+                isEqual = LocalLabel.unique("bdnequn")
+                $asm.puts "jp #{LabelReference.new(codeOrigin, isUnordered).asmLabel}"
+                $asm.puts "je #{LabelReference.new(codeOrigin, isEqual).asmLabel}"
+                isUnordered.lower("X86")
+                $asm.puts "jmp #{operands[2].asmLabel}"
+                isEqual.lower("X86")
+            end
         when "bdgtun"
             handleX86DoubleBranch("jb", :reverse)
         when "bdgtequn"
@@ -1115,7 +1125,7 @@ class Instruction
             $asm.puts "movd #{operands[0].x86Operand(:double)}, #{operands[1].x86Operand(:int)}"
             $asm.puts "movsd #{operands[0].x86Operand(:double)}, %xmm7"
             $asm.puts "psrlq $32, %xmm7"
-            $asm.puts "movsd %xmm7, #{operands[2].x86Operand(:int)}"
+            $asm.puts "movd %xmm7, #{operands[2].x86Operand(:int)}"
         when "fq2d"
             $asm.puts "movd #{operands[0].x86Operand(:quad)}, #{operands[1].x86Operand(:double)}"
         when "fd2q"
index 5c2cd71..1f54158 100644 (file)
@@ -77,15 +77,15 @@ bool ArrayConstructor::getOwnPropertyDescriptor(JSObject* object, ExecState* exe
 
 // ------------------------------ Functions ---------------------------
 
-JSObject* constructArrayWithSizeQuirk(ExecState* exec, JSGlobalObject* globalObject, JSValue length)
+JSObject* constructArrayWithSizeQuirk(ExecState* exec, ArrayAllocationProfile* profile, JSGlobalObject* globalObject, JSValue length)
 {
     if (!length.isNumber())
-        return constructArray(exec, globalObject, &length, 1);
+        return constructArray(exec, profile, globalObject, &length, 1);
     
     uint32_t n = length.toUInt32(exec);
     if (n != length.toNumber(exec))
         return throwError(exec, createRangeError(exec, ASCIILiteral("Array size is not a small enough positive integer.")));
-    return constructEmptyArray(exec, globalObject, n);
+    return constructEmptyArray(exec, profile, globalObject, n);
 }
 
 static inline JSObject* constructArrayWithSizeQuirk(ExecState* exec, const ArgList& args)
@@ -94,10 +94,10 @@ static inline JSObject* constructArrayWithSizeQuirk(ExecState* exec, const ArgLi
 
     // a single numeric argument denotes the array size (!)
     if (args.size() == 1)
-        return constructArrayWithSizeQuirk(exec, globalObject, args.at(0));
+        return constructArrayWithSizeQuirk(exec, 0, globalObject, args.at(0));
 
     // otherwise the array is constructed with the arguments in it
-    return constructArray(exec, globalObject, args);
+    return constructArray(exec, 0, globalObject, args);
 }
 
 static EncodedJSValue JSC_HOST_CALL constructWithArrayConstructor(ExecState* exec)
index dcbf0a1..fda0870 100644 (file)
@@ -60,7 +60,7 @@ namespace JSC {
         static CallType getCallData(JSCell*, CallData&);
     };
 
-    JSObject* constructArrayWithSizeQuirk(ExecState*, JSGlobalObject*, JSValue);
+    JSObject* constructArrayWithSizeQuirk(ExecState*, ArrayAllocationProfile*, JSGlobalObject*, JSValue);
 
 } // namespace JSC
 
index 6975dc7..405ea63 100644 (file)
@@ -456,7 +456,7 @@ EncodedJSValue JSC_HOST_CALL arrayProtoFuncJoin(ExecState* exec)
 EncodedJSValue JSC_HOST_CALL arrayProtoFuncConcat(ExecState* exec)
 {
     JSValue thisValue = exec->hostThisValue();
-    JSArray* arr = constructEmptyArray(exec);
+    JSArray* arr = constructEmptyArray(exec, 0);
     unsigned n = 0;
     JSValue curArg = thisValue.toObject(exec);
     if (exec->hadException())
@@ -618,7 +618,7 @@ EncodedJSValue JSC_HOST_CALL arrayProtoFuncSlice(ExecState* exec)
         return JSValue::encode(jsUndefined());
 
     // We return a new array
-    JSArray* resObj = constructEmptyArray(exec);
+    JSArray* resObj = constructEmptyArray(exec, 0);
     JSValue result = resObj;
 
     unsigned begin = argumentClampedIndexFromStartOrEnd(exec, 0, length);
@@ -733,7 +733,7 @@ EncodedJSValue JSC_HOST_CALL arrayProtoFuncSplice(ExecState* exec)
         return JSValue::encode(jsUndefined());
     
     if (!exec->argumentCount())
-        return JSValue::encode(constructEmptyArray(exec));
+        return JSValue::encode(constructEmptyArray(exec, 0));
 
     unsigned begin = argumentClampedIndexFromStartOrEnd(exec, 0, length);
 
@@ -748,7 +748,7 @@ EncodedJSValue JSC_HOST_CALL arrayProtoFuncSplice(ExecState* exec)
             deleteCount = static_cast<unsigned>(deleteDouble);
     }
 
-    JSArray* resObj = JSArray::tryCreateUninitialized(exec->globalData(), exec->lexicalGlobalObject()->arrayStructure(), deleteCount);
+    JSArray* resObj = JSArray::tryCreateUninitialized(exec->globalData(), exec->lexicalGlobalObject()->arrayStructureForIndexingTypeDuringAllocation(ArrayWithUndecided), deleteCount);
     if (!resObj)
         return JSValue::encode(throwOutOfMemoryError(exec));
 
@@ -820,7 +820,7 @@ EncodedJSValue JSC_HOST_CALL arrayProtoFuncFilter(ExecState* exec)
         return throwVMTypeError(exec);
 
     JSValue applyThis = exec->argument(1);
-    JSArray* resultArray = constructEmptyArray(exec);
+    JSArray* resultArray = constructEmptyArray(exec, 0);
 
     unsigned filterIndex = 0;
     unsigned k = 0;
@@ -880,7 +880,7 @@ EncodedJSValue JSC_HOST_CALL arrayProtoFuncMap(ExecState* exec)
 
     JSValue applyThis = exec->argument(1);
 
-    JSArray* resultArray = constructEmptyArray(exec, length);
+    JSArray* resultArray = constructEmptyArray(exec, 0, length);
     unsigned k = 0;
     if (callType == CallTypeJS && isJSArray(thisObj)) {
         JSFunction* f = jsCast<JSFunction*>(function);
index cb93aea..4b8d53f 100644 (file)
@@ -88,12 +88,18 @@ public:
     template<typename T>
     T* indexingPayload() { return reinterpret_cast<T*>(this); }
     ArrayStorage* arrayStorage() { return indexingPayload<ArrayStorage>(); }
+    WriteBarrier<Unknown>* contiguousInt32() { return indexingPayload<WriteBarrier<Unknown> >(); }
+    double* contiguousDouble() { return indexingPayload<double>(); }
     WriteBarrier<Unknown>* contiguous() { return indexingPayload<WriteBarrier<Unknown> >(); }
     
     static Butterfly* fromContiguous(WriteBarrier<Unknown>* contiguous)
     {
         return reinterpret_cast<Butterfly*>(contiguous);
     }
+    static Butterfly* fromContiguous(double* contiguous)
+    {
+        return reinterpret_cast<Butterfly*>(contiguous);
+    }
     
     static ptrdiff_t offsetOfPropertyStorage() { return -static_cast<ptrdiff_t>(sizeof(IndexingHeader)); }
     static int indexOfPropertyStorage()
index 86a836b..01bab40 100644 (file)
@@ -61,8 +61,9 @@ inline Butterfly* Butterfly::create(JSGlobalData& globalData, Structure* structu
 
 inline Butterfly* Butterfly::createUninitializedDuringCollection(CopyVisitor& visitor, size_t preCapacity, size_t propertyCapacity, bool hasIndexingHeader, size_t indexingPayloadSizeInBytes)
 {
+    size_t size = totalSize(preCapacity, propertyCapacity, hasIndexingHeader, indexingPayloadSizeInBytes);
     Butterfly* result = fromBase(
-        visitor.allocateNewSpace(totalSize(preCapacity, propertyCapacity, hasIndexingHeader, indexingPayloadSizeInBytes)),
+        visitor.allocateNewSpace(size),
         preCapacity, propertyCapacity);
     return result;
 }
index a4b2202..8e4390b 100644 (file)
@@ -186,7 +186,7 @@ EncodedJSValue JSC_HOST_CALL functionProtoFuncBind(ExecState* exec)
 
     // Let A be a new (possibly empty) internal list of all of the argument values provided after thisArg (arg1, arg2 etc), in order.
     size_t numBoundArgs = exec->argumentCount() > 1 ? exec->argumentCount() - 1 : 0;
-    JSArray* boundArgs = JSArray::tryCreateUninitialized(exec->globalData(), globalObject->arrayStructure(), numBoundArgs);
+    JSArray* boundArgs = JSArray::tryCreateUninitialized(exec->globalData(), globalObject->arrayStructureForIndexingTypeDuringAllocation(ArrayWithUndecided), numBoundArgs);
     if (!boundArgs)
         return JSValue::encode(throwOutOfMemoryError(exec));
 
index 22785ce..ab9be15 100644 (file)
@@ -43,6 +43,9 @@ inline size_t IndexingHeader::preCapacity(Structure* structure)
 inline size_t IndexingHeader::indexingPayloadSizeInBytes(Structure* structure)
 {
     switch (structure->indexingType()) {
+    case ALL_UNDECIDED_INDEXING_TYPES:
+    case ALL_INT32_INDEXING_TYPES:
+    case ALL_DOUBLE_INDEXING_TYPES:
     case ALL_CONTIGUOUS_INDEXING_TYPES:
         return vectorLength() * sizeof(EncodedJSValue);
         
index 7261847..dc2733a 100644 (file)
 
 namespace JSC {
 
+IndexingType leastUpperBoundOfIndexingTypes(IndexingType a, IndexingType b)
+{
+    // It doesn't make sense to LUB something that is an array with something that isn't.
+    ASSERT((a & IsArray) == (b & IsArray));
+
+    // Boy, this sure is easy right now.
+    return std::max(a, b);
+}
+
+IndexingType leastUpperBoundOfIndexingTypeAndType(IndexingType indexingType, SpeculatedType type)
+{
+    if (!type)
+        return indexingType;
+    switch (indexingType) {
+    case ALL_BLANK_INDEXING_TYPES:
+    case ALL_UNDECIDED_INDEXING_TYPES:
+    case ALL_INT32_INDEXING_TYPES:
+        if (isInt32Speculation(type))
+            return (indexingType & ~IndexingShapeMask) | Int32Shape;
+        if (isNumberSpeculation(type))
+            return (indexingType & ~IndexingShapeMask) | DoubleShape;
+        return (indexingType & ~IndexingShapeMask) | ContiguousShape;
+    case ALL_DOUBLE_INDEXING_TYPES:
+        if (isNumberSpeculation(type))
+            return indexingType;
+        return (indexingType & ~IndexingShapeMask) | ContiguousShape;
+    case ALL_CONTIGUOUS_INDEXING_TYPES:
+    case ALL_ARRAY_STORAGE_INDEXING_TYPES:
+        return indexingType;
+    default:
+        CRASH();
+        return 0;
+    }
+}
+
+IndexingType leastUpperBoundOfIndexingTypeAndValue(IndexingType indexingType, JSValue value)
+{
+    return leastUpperBoundOfIndexingTypeAndType(indexingType, speculationFromValue(value));
+}
+
 const char* indexingTypeToString(IndexingType indexingType)
 {
     static char result[128];
@@ -39,6 +79,12 @@ const char* indexingTypeToString(IndexingType indexingType)
     case NonArray:
         basicName = "NonArray";
         break;
+    case NonArrayWithInt32:
+        basicName = "NonArrayWithInt32";
+        break;
+    case NonArrayWithDouble:
+        basicName = "NonArrayWithDouble";
+        break;
     case NonArrayWithContiguous:
         basicName = "NonArrayWithContiguous";
         break;
@@ -51,6 +97,15 @@ const char* indexingTypeToString(IndexingType indexingType)
     case ArrayClass:
         basicName = "ArrayClass";
         break;
+    case ArrayWithUndecided:
+        basicName = "ArrayWithUndecided";
+        break;
+    case ArrayWithInt32:
+        basicName = "ArrayWithInt32";
+        break;
+    case ArrayWithDouble:
+        basicName = "ArrayWithDouble";
+        break;
     case ArrayWithContiguous:
         basicName = "ArrayWithContiguous";
         break;
index 4bbe3cf..ab253be 100644 (file)
@@ -26,6 +26,7 @@
 #ifndef IndexingType_h
 #define IndexingType_h
 
+#include "SpeculatedType.h"
 #include <wtf/StdLibExtras.h>
 
 namespace JSC {
@@ -37,21 +38,32 @@ static const IndexingType IsArray                  = 1;
 
 // The shape of the indexed property storage.
 static const IndexingType IndexingShapeMask        = 30;
-static const IndexingType NoIndexingShape          = 0; 
+static const IndexingType NoIndexingShape          = 0;
+static const IndexingType UndecidedShape           = 2; // Only useful for arrays.
+static const IndexingType Int32Shape               = 20;
+static const IndexingType DoubleShape              = 22;
 static const IndexingType ContiguousShape          = 26;
 static const IndexingType ArrayStorageShape        = 28;
 static const IndexingType SlowPutArrayStorageShape = 30;
 
+static const IndexingType IndexingShapeShift       = 1;
+static const IndexingType NumberOfIndexingShapes   = 16;
+
 // Additional flags for tracking the history of the type. These are usually
 // masked off unless you ask for them directly.
 static const IndexingType MayHaveIndexedAccessors  = 32;
 
 // List of acceptable array types.
 static const IndexingType NonArray                        = 0;
+static const IndexingType NonArrayWithInt32               = Int32Shape;
+static const IndexingType NonArrayWithDouble              = DoubleShape;
 static const IndexingType NonArrayWithContiguous          = ContiguousShape;
 static const IndexingType NonArrayWithArrayStorage        = ArrayStorageShape;
 static const IndexingType NonArrayWithSlowPutArrayStorage = SlowPutArrayStorageShape;
 static const IndexingType ArrayClass                      = IsArray; // I'd want to call this "Array" but this would lead to disastrous namespace pollution.
+static const IndexingType ArrayWithUndecided              = IsArray | UndecidedShape;
+static const IndexingType ArrayWithInt32                  = IsArray | Int32Shape;
+static const IndexingType ArrayWithDouble                 = IsArray | DoubleShape;
 static const IndexingType ArrayWithContiguous             = IsArray | ContiguousShape;
 static const IndexingType ArrayWithArrayStorage           = IsArray | ArrayStorageShape;
 static const IndexingType ArrayWithSlowPutArrayStorage    = IsArray | SlowPutArrayStorageShape;
@@ -60,6 +72,17 @@ static const IndexingType ArrayWithSlowPutArrayStorage    = IsArray | SlowPutArr
     NonArray:                    \
     case ArrayClass
 
+#define ALL_UNDECIDED_INDEXING_TYPES \
+    ArrayWithUndecided
+
+#define ALL_INT32_INDEXING_TYPES      \
+    NonArrayWithInt32:                \
+    case ArrayWithInt32
+
+#define ALL_DOUBLE_INDEXING_TYPES     \
+    NonArrayWithDouble:               \
+    case ArrayWithDouble
+
 #define ALL_CONTIGUOUS_INDEXING_TYPES \
     NonArrayWithContiguous:           \
     case ArrayWithContiguous
@@ -83,6 +106,21 @@ static inline bool hasIndexingHeader(IndexingType type)
     return hasIndexedProperties(type);
 }
 
+static inline bool hasUndecided(IndexingType indexingType)
+{
+    return (indexingType & IndexingShapeMask) == UndecidedShape;
+}
+
+static inline bool hasInt32(IndexingType indexingType)
+{
+    return (indexingType & IndexingShapeMask) == Int32Shape;
+}
+
+static inline bool hasDouble(IndexingType indexingType)
+{
+    return (indexingType & IndexingShapeMask) == DoubleShape;
+}
+
 static inline bool hasContiguous(IndexingType indexingType)
 {
     return (indexingType & IndexingShapeMask) == ContiguousShape;
@@ -105,6 +143,12 @@ static inline bool shouldUseSlowPut(IndexingType indexingType)
     return (indexingType & IndexingShapeMask) == SlowPutArrayStorageShape;
 }
 
+// Return an indexing type that can handle all of the elements of both indexing types.
+IndexingType leastUpperBoundOfIndexingTypes(IndexingType, IndexingType);
+
+IndexingType leastUpperBoundOfIndexingTypeAndType(IndexingType, SpeculatedType);
+IndexingType leastUpperBoundOfIndexingTypeAndValue(IndexingType, JSValue);
+
 const char* indexingTypeToString(IndexingType);
 
 // Mask of all possible types.
index d1ece1a..14830bb 100644 (file)
@@ -410,25 +410,33 @@ bool JSArray::setLength(ExecState* exec, unsigned newLength, bool throwException
                 exec, newLength, throwException,
                 convertContiguousToArrayStorage(exec->globalData()));
         }
-        createInitialContiguous(exec->globalData(), newLength);
+        createInitialUndecided(exec->globalData(), newLength);
         return true;
         
+    case ArrayWithUndecided:
+    case ArrayWithInt32:
+    case ArrayWithDouble:
     case ArrayWithContiguous:
         if (newLength == m_butterfly->publicLength())
             return true;
         if (newLength >= MAX_ARRAY_INDEX // This case ensures that we can do fast push.
             || (newLength >= MIN_SPARSE_ARRAY_INDEX
-                && !isDenseEnoughForVector(newLength, countElementsInContiguous(m_butterfly)))) {
+                && !isDenseEnoughForVector(newLength, countElements()))) {
             return setLengthWithArrayStorage(
                 exec, newLength, throwException,
-                convertContiguousToArrayStorage(exec->globalData()));
+                ensureArrayStorage(exec->globalData()));
         }
         if (newLength > m_butterfly->publicLength()) {
-            ensureContiguousLength(exec->globalData(), newLength);
+            ensureLength(exec->globalData(), newLength);
             return true;
         }
-        for (unsigned i = m_butterfly->publicLength(); i-- > newLength;)
-            m_butterfly->contiguous()[i].clear();
+        if (structure()->indexingType() == ArrayWithDouble) {
+            for (unsigned i = m_butterfly->publicLength(); i-- > newLength;)
+                m_butterfly->contiguousDouble()[i] = QNaN;
+        } else {
+            for (unsigned i = m_butterfly->publicLength(); i-- > newLength;)
+                m_butterfly->contiguous()[i].clear();
+        }
         m_butterfly->setPublicLength(newLength);
         return true;
         
@@ -448,6 +456,13 @@ JSValue JSArray::pop(ExecState* exec)
     case ArrayClass:
         return jsUndefined();
         
+    case ArrayWithUndecided:
+        if (!m_butterfly->publicLength())
+            return jsUndefined();
+        // We have nothing but holes. So, drop down to the slow version.
+        break;
+        
+    case ArrayWithInt32:
     case ArrayWithContiguous: {
         unsigned length = m_butterfly->publicLength();
         
@@ -464,6 +479,22 @@ JSValue JSArray::pop(ExecState* exec)
         break;
     }
         
+    case ArrayWithDouble: {
+        unsigned length = m_butterfly->publicLength();
+        
+        if (!length--)
+            return jsUndefined();
+        
+        ASSERT(length < m_butterfly->vectorLength());
+        double value = m_butterfly->contiguousDouble()[length];
+        if (value == value) {
+            m_butterfly->contiguousDouble()[length] = QNaN;
+            m_butterfly->setPublicLength(length);
+            return JSValue(JSValue::EncodeAsDouble, value);
+        }
+        break;
+    }
+        
     case ARRAY_WITH_ARRAY_STORAGE_INDEXING_TYPES: {
         ArrayStorage* storage = m_butterfly->arrayStorage();
     
@@ -518,10 +549,42 @@ void JSArray::push(ExecState* exec, JSValue value)
 {
     switch (structure()->indexingType()) {
     case ArrayClass: {
-        putByIndexBeyondVectorLengthWithArrayStorage(exec, 0, value, true, createInitialArrayStorage(exec->globalData()));
-        break;
+        createInitialUndecided(exec->globalData(), 0);
+        // Fall through.
+    }
+        
+    case ArrayWithUndecided: {
+        convertUndecidedForValue(exec->globalData(), value);
+        push(exec, value);
+        return;
     }
         
+    case ArrayWithInt32: {
+        if (!value.isInt32()) {
+            convertInt32ForValue(exec->globalData(), value);
+            push(exec, value);
+            return;
+        }
+
+        unsigned length = m_butterfly->publicLength();
+        ASSERT(length <= m_butterfly->vectorLength());
+        if (length < m_butterfly->vectorLength()) {
+            m_butterfly->contiguousInt32()[length].setWithoutWriteBarrier(value);
+            m_butterfly->setPublicLength(length + 1);
+            return;
+        }
+        
+        if (length > MAX_ARRAY_INDEX) {
+            methodTable()->putByIndex(this, exec, length, value, true);
+            if (!exec->hadException())
+                throwError(exec, createRangeError(exec, "Invalid array length"));
+            return;
+        }
+        
+        putByIndexBeyondVectorLengthWithoutAttributes<Int32Shape>(exec, length, value);
+        return;
+    }
+
     case ArrayWithContiguous: {
         unsigned length = m_butterfly->publicLength();
         ASSERT(length <= m_butterfly->vectorLength());
@@ -538,10 +601,42 @@ void JSArray::push(ExecState* exec, JSValue value)
             return;
         }
         
-        putByIndexBeyondVectorLengthContiguousWithoutAttributes(exec, length, value);
+        putByIndexBeyondVectorLengthWithoutAttributes<ContiguousShape>(exec, length, value);
         return;
     }
         
+    case ArrayWithDouble: {
+        if (!value.isNumber()) {
+            convertDoubleToContiguous(exec->globalData());
+            push(exec, value);
+            return;
+        }
+        double valueAsDouble = value.asNumber();
+        if (valueAsDouble != valueAsDouble) {
+            convertDoubleToContiguous(exec->globalData());
+            push(exec, value);
+            return;
+        }
+
+        unsigned length = m_butterfly->publicLength();
+        ASSERT(length <= m_butterfly->vectorLength());
+        if (length < m_butterfly->vectorLength()) {
+            m_butterfly->contiguousDouble()[length] = valueAsDouble;
+            m_butterfly->setPublicLength(length + 1);
+            return;
+        }
+        
+        if (length > MAX_ARRAY_INDEX) {
+            methodTable()->putByIndex(this, exec, length, value, true);
+            if (!exec->hadException())
+                throwError(exec, createRangeError(exec, "Invalid array length"));
+            return;
+        }
+        
+        putByIndexBeyondVectorLengthWithoutAttributes<DoubleShape>(exec, length, value);
+        break;
+    }
+        
     case ArrayWithSlowPutArrayStorage: {
         unsigned oldLength = length();
         if (attemptToInterceptPutByIndexOnHole(exec, oldLength, value, true)) {
@@ -647,6 +742,11 @@ bool JSArray::shiftCountWithAnyIndexingType(ExecState* exec, unsigned startIndex
     case ArrayClass:
         return true;
         
+    case ArrayWithUndecided:
+        // Don't handle this because it's confusing and it shouldn't come up.
+        return false;
+        
+    case ArrayWithInt32:
     case ArrayWithContiguous: {
         unsigned oldLength = m_butterfly->publicLength();
         ASSERT(count <= oldLength);
@@ -654,7 +754,7 @@ bool JSArray::shiftCountWithAnyIndexingType(ExecState* exec, unsigned startIndex
         // We may have to walk the entire array to do the shift. We're willing to do
         // so only if it's not horribly slow.
         if (oldLength - (startIndex + count) >= MIN_SPARSE_ARRAY_INDEX)
-            return shiftCountWithArrayStorage(startIndex, count, convertContiguousToArrayStorage(exec->globalData()));
+            return shiftCountWithArrayStorage(startIndex, count, ensureArrayStorage(exec->globalData()));
         
         unsigned end = oldLength - count;
         for (unsigned i = startIndex; i < end; ++i) {
@@ -668,7 +768,7 @@ bool JSArray::shiftCountWithAnyIndexingType(ExecState* exec, unsigned startIndex
                 // about holes (at least for now), but it can detect them quickly. So
                 // we convert to array storage and then allow the array storage path to
                 // figure it out.
-                return shiftCountWithArrayStorage(startIndex, count, convertContiguousToArrayStorage(exec->globalData()));
+                return shiftCountWithArrayStorage(startIndex, count, ensureArrayStorage(exec->globalData()));
             }
             // No need for a barrier since we're just moving data around in the same vector.
             // This is in line with our standing assumption that we won't have a deletion
@@ -682,6 +782,41 @@ bool JSArray::shiftCountWithAnyIndexingType(ExecState* exec, unsigned startIndex
         return true;
     }
         
+    case ArrayWithDouble: {
+        unsigned oldLength = m_butterfly->publicLength();
+        ASSERT(count <= oldLength);
+        
+        // We may have to walk the entire array to do the shift. We're willing to do
+        // so only if it's not horribly slow.
+        if (oldLength - (startIndex + count) >= MIN_SPARSE_ARRAY_INDEX)
+            return shiftCountWithArrayStorage(startIndex, count, ensureArrayStorage(exec->globalData()));
+        
+        unsigned end = oldLength - count;
+        for (unsigned i = startIndex; i < end; ++i) {
+            // Storing to a hole is fine since we're still having a good time. But reading
+            // from a hole is totally not fine, since we might have to read from the proto
+            // chain.
+            double v = m_butterfly->contiguousDouble()[i + count];
+            if (UNLIKELY(v != v)) {
+                // The purpose of this path is to ensure that we don't make the same
+                // mistake in the future: shiftCountWithArrayStorage() can't do anything
+                // about holes (at least for now), but it can detect them quickly. So
+                // we convert to array storage and then allow the array storage path to
+                // figure it out.
+                return shiftCountWithArrayStorage(startIndex, count, ensureArrayStorage(exec->globalData()));
+            }
+            // No need for a barrier since we're just moving data around in the same vector.
+            // This is in line with our standing assumption that we won't have a deletion
+            // barrier.
+            m_butterfly->contiguousDouble()[i] = v;
+        }
+        for (unsigned i = end; i < oldLength; ++i)
+            m_butterfly->contiguousDouble()[i] = QNaN;
+        
+        m_butterfly->setPublicLength(oldLength - count);
+        return true;
+    }
+        
     case ArrayWithArrayStorage:
     case ArrayWithSlowPutArrayStorage:
         return shiftCountWithArrayStorage(startIndex, count, arrayStorage());
@@ -740,23 +875,25 @@ bool JSArray::unshiftCountWithAnyIndexingType(ExecState* exec, unsigned startInd
 {
     switch (structure()->indexingType()) {
     case ArrayClass:
+    case ArrayWithUndecided:
         // We could handle this. But it shouldn't ever come up, so we won't.
         return false;
-        
+
+    case ArrayWithInt32:
     case ArrayWithContiguous: {
         unsigned oldLength = m_butterfly->publicLength();
         
         // We may have to walk the entire array to do the unshift. We're willing to do so
         // only if it's not horribly slow.
         if (oldLength - startIndex >= MIN_SPARSE_ARRAY_INDEX)
-            return unshiftCountWithArrayStorage(exec, startIndex, count, convertContiguousToArrayStorage(exec->globalData()));
+            return unshiftCountWithArrayStorage(exec, startIndex, count, ensureArrayStorage(exec->globalData()));
         
-        ensureContiguousLength(exec->globalData(), oldLength + count);
+        ensureLength(exec->globalData(), oldLength + count);
         
         for (unsigned i = oldLength; i-- > startIndex;) {
             JSValue v = m_butterfly->contiguous()[i].get();
             if (UNLIKELY(!v))
-                return unshiftCountWithArrayStorage(exec, startIndex, count, convertContiguousToArrayStorage(exec->globalData()));
+                return unshiftCountWithArrayStorage(exec, startIndex, count, ensureArrayStorage(exec->globalData()));
             m_butterfly->contiguous()[i + count].setWithoutWriteBarrier(v);
         }
         
@@ -768,6 +905,31 @@ bool JSArray::unshiftCountWithAnyIndexingType(ExecState* exec, unsigned startInd
         return true;
     }
         
+    case ArrayWithDouble: {
+        unsigned oldLength = m_butterfly->publicLength();
+        
+        // We may have to walk the entire array to do the unshift. We're willing to do so
+        // only if it's not horribly slow.
+        if (oldLength - startIndex >= MIN_SPARSE_ARRAY_INDEX)
+            return unshiftCountWithArrayStorage(exec, startIndex, count, ensureArrayStorage(exec->globalData()));
+        
+        ensureLength(exec->globalData(), oldLength + count);
+        
+        for (unsigned i = oldLength; i-- > startIndex;) {
+            double v = m_butterfly->contiguousDouble()[i];
+            if (UNLIKELY(v != v))
+                return unshiftCountWithArrayStorage(exec, startIndex, count, ensureArrayStorage(exec->globalData()));
+            m_butterfly->contiguousDouble()[i + count] = v;
+        }
+        
+        // NOTE: we're leaving being garbage in the part of the array that we shifted out
+        // of. This is fine because the caller is required to store over that area, and
+        // in contiguous mode storing into a hole is guaranteed to behave exactly the same
+        // as storing over an existing element.
+        
+        return true;
+    }
+        
     case ArrayWithArrayStorage:
     case ArrayWithSlowPutArrayStorage:
         return unshiftCountWithArrayStorage(exec, startIndex, count, arrayStorage());
@@ -778,6 +940,20 @@ bool JSArray::unshiftCountWithAnyIndexingType(ExecState* exec, unsigned startInd
     }
 }
 
+static int compareNumbersForQSortWithInt32(const void* a, const void* b)
+{
+    int32_t ia = static_cast<const JSValue*>(a)->asInt32();
+    int32_t ib = static_cast<const JSValue*>(b)->asInt32();
+    return ia - ib;
+}
+
+static int compareNumbersForQSortWithDouble(const void* a, const void* b)
+{
+    double da = *static_cast<const double*>(a);
+    double db = *static_cast<const double*>(b);
+    return (da > db) - (da < db);
+}
+
 static int compareNumbersForQSort(const void* a, const void* b)
 {
     double da = static_cast<const JSValue*>(a)->asNumber();
@@ -795,7 +971,7 @@ static int compareByStringPairForQSort(const void* a, const void* b)
 template<IndexingType indexingType>
 void JSArray::sortNumericVector(ExecState* exec, JSValue compareFunction, CallType callType, const CallData& callData)
 {
-    ASSERT(indexingType == ArrayWithContiguous || indexingType == ArrayWithArrayStorage);
+    ASSERT(indexingType == ArrayWithInt32 || indexingType == ArrayWithDouble || indexingType == ArrayWithContiguous || indexingType == ArrayWithArrayStorage);
     
     unsigned lengthNotIncludingUndefined;
     unsigned newRelevantLength;
@@ -814,11 +990,19 @@ void JSArray::sortNumericVector(ExecState* exec, JSValue compareFunction, CallTy
         return;
     
     bool allValuesAreNumbers = true;
-    for (size_t i = 0; i < newRelevantLength; ++i) {
-        if (!data[i].isNumber()) {
-            allValuesAreNumbers = false;
-            break;
+    switch (indexingType) {
+    case ArrayWithInt32:
+    case ArrayWithDouble:
+        break;
+        
+    default:
+        for (size_t i = 0; i < newRelevantLength; ++i) {
+            if (!data[i].isNumber()) {
+                allValuesAreNumbers = false;
+                break;
+            }
         }
+        break;
     }
     
     if (!allValuesAreNumbers)
@@ -827,7 +1011,23 @@ void JSArray::sortNumericVector(ExecState* exec, JSValue compareFunction, CallTy
     // 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(data, newRelevantLength, sizeof(WriteBarrier<Unknown>), compareNumbersForQSort);
+    int (*compare)(const void*, const void*);
+    switch (indexingType) {
+    case ArrayWithInt32:
+        compare = compareNumbersForQSortWithInt32;
+        break;
+        
+    case ArrayWithDouble:
+        compare = compareNumbersForQSortWithDouble;
+        ASSERT(sizeof(WriteBarrier<Unknown>) == sizeof(double));
+        break;
+        
+    default:
+        compare = compareNumbersForQSort;
+        break;
+    }
+    
+    qsort(data, newRelevantLength, sizeof(WriteBarrier<Unknown>), compare);
     return;
 }
 
@@ -839,6 +1039,14 @@ void JSArray::sortNumeric(ExecState* exec, JSValue compareFunction, CallType cal
     case ArrayClass:
         return;
         
+    case ArrayWithInt32:
+        sortNumericVector<ArrayWithInt32>(exec, compareFunction, callType, callData);
+        break;
+        
+    case ArrayWithDouble:
+        sortNumericVector<ArrayWithDouble>(exec, compareFunction, callType, callData);
+        break;
+        
     case ArrayWithContiguous:
         sortNumericVector<ArrayWithContiguous>(exec, compareFunction, callType, callData);
         return;
@@ -854,7 +1062,7 @@ void JSArray::sortNumeric(ExecState* exec, JSValue compareFunction, CallType cal
 }
 
 template<IndexingType indexingType>
-void JSArray::sortCompactedVector(ExecState* exec, WriteBarrier<Unknown>* begin, unsigned relevantLength)
+void JSArray::sortCompactedVector(ExecState* exec, void* begin, unsigned relevantLength)
 {
     if (!relevantLength)
         return;
@@ -875,11 +1083,31 @@ void JSArray::sortCompactedVector(ExecState* exec, WriteBarrier<Unknown>* begin,
     Heap::heap(this)->pushTempSortVector(&values);
         
     bool isSortingPrimitiveValues = true;
-    for (size_t i = 0; i < relevantLength; i++) {
-        JSValue value = begin[i].get();
-        ASSERT(!value.isUndefined());
-        values[i].first = value;
-        isSortingPrimitiveValues = isSortingPrimitiveValues && value.isPrimitive();
+    switch (indexingType) {
+    case ArrayWithInt32:
+        for (size_t i = 0; i < relevantLength; i++) {
+            JSValue value = static_cast<WriteBarrier<Unknown>*>(begin)[i].get();
+            ASSERT(value.isInt32());
+            values[i].first = value;
+        }
+        break;
+        
+    case ArrayWithDouble:
+        for (size_t i = 0; i < relevantLength; i++) {
+            double value = static_cast<double*>(begin)[i];
+            ASSERT(value == value);
+            values[i].first = JSValue(JSValue::EncodeAsDouble, value);
+        }
+        break;
+        
+    default:
+        for (size_t i = 0; i < relevantLength; i++) {
+            JSValue value = static_cast<WriteBarrier<Unknown>*>(begin)[i].get();
+            ASSERT(!value.isUndefined());
+            values[i].first = value;
+            isSortingPrimitiveValues = isSortingPrimitiveValues && value.isPrimitive();
+        }
+        break;
     }
         
     // FIXME: The following loop continues to call toString on subsequent values even after
@@ -910,8 +1138,10 @@ void JSArray::sortCompactedVector(ExecState* exec, WriteBarrier<Unknown>* begin,
     // If the toString function changed the length of the array or vector storage,
     // increase the length to handle the orignal number of actual values.
     switch (indexingType) {
+    case ArrayWithInt32:
+    case ArrayWithDouble:
     case ArrayWithContiguous:
-        ensureContiguousLength(globalData, relevantLength);
+        ensureLength(globalData, relevantLength);
         break;
         
     case ArrayWithArrayStorage:
@@ -927,8 +1157,12 @@ void JSArray::sortCompactedVector(ExecState* exec, WriteBarrier<Unknown>* begin,
         CRASH();
     }
 
-    for (size_t i = 0; i < relevantLength; i++)
-        begin[i].set(globalData, this, values[i].first);
+    for (size_t i = 0; i < relevantLength; i++) {
+        if (indexingType == ArrayWithDouble)
+            static_cast<double*>(begin)[i] = values[i].first.asNumber();
+        else
+            static_cast<WriteBarrier<Unknown>*>(begin)[i].set(globalData, this, values[i].first);
+    }
     
     Heap::heap(this)->popTempSortVector(&values);
 }
@@ -939,7 +1173,30 @@ void JSArray::sort(ExecState* exec)
     
     switch (structure()->indexingType()) {
     case ArrayClass:
+    case ArrayWithUndecided:
+        return;
+        
+    case ArrayWithInt32: {
+        unsigned lengthNotIncludingUndefined;
+        unsigned newRelevantLength;
+        compactForSorting<ArrayWithInt32>(
+            lengthNotIncludingUndefined, newRelevantLength);
+        
+        sortCompactedVector<ArrayWithInt32>(
+            exec, m_butterfly->contiguousInt32(), lengthNotIncludingUndefined);
+        return;
+    }
+        
+    case ArrayWithDouble: {
+        unsigned lengthNotIncludingUndefined;
+        unsigned newRelevantLength;
+        compactForSorting<ArrayWithDouble>(
+            lengthNotIncludingUndefined, newRelevantLength);
+        
+        sortCompactedVector<ArrayWithDouble>(
+            exec, m_butterfly->contiguousDouble(), lengthNotIncludingUndefined);
         return;
+    }
         
     case ArrayWithContiguous: {
         unsigned lengthNotIncludingUndefined;
@@ -1087,12 +1344,12 @@ void JSArray::sortVector(ExecState* exec, JSValue compareFunction, CallType call
         
     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) {
         if (numDefined > m_butterfly->vectorLength())
             break;
-        JSValue v = currentIndexingData()[numDefined].get();
+        JSValue v = getHolyIndexQuickly(numDefined);
         if (!v || v.isUndefined())
             break;
         tree.abstractor().m_nodes[numDefined].value = v;
@@ -1101,7 +1358,7 @@ void JSArray::sortVector(ExecState* exec, JSValue compareFunction, CallType call
     for (unsigned i = numDefined; i < usedVectorLength; ++i) {
         if (i > m_butterfly->vectorLength())
             break;
-        JSValue v = currentIndexingData()[i].get();
+        JSValue v = getHolyIndexQuickly(i);
         if (v) {
             if (v.isUndefined())
                 ++numUndefined;
@@ -1112,7 +1369,7 @@ void JSArray::sortVector(ExecState* exec, JSValue compareFunction, CallType call
             }
         }
     }
-        
+    
     unsigned newUsedVectorLength = numDefined + numUndefined;
         
     // The array size may have changed. Figure out the new bounds.
@@ -1127,16 +1384,31 @@ void JSArray::sortVector(ExecState* exec, JSValue compareFunction, CallType call
     iter.start_iter_least(tree);
     JSGlobalData& globalData = exec->globalData();
     for (unsigned i = 0; i < elementsToExtractThreshold; ++i) {
-        currentIndexingData()[i].set(globalData, this, tree.abstractor().m_nodes[*iter].value);
+        if (structure()->indexingType() == ArrayWithDouble)
+            butterfly()->contiguousDouble()[i] = tree.abstractor().m_nodes[*iter].value.asNumber();
+        else
+            currentIndexingData()[i].set(globalData, this, tree.abstractor().m_nodes[*iter].value);
         ++iter;
     }
     // Put undefined values back in.
-    for (unsigned i = elementsToExtractThreshold; i < undefinedElementsThreshold; ++i)
-        currentIndexingData()[i].setUndefined();
+    switch (structure()->indexingType()) {
+    case ArrayWithInt32:
+    case ArrayWithDouble:
+        ASSERT(elementsToExtractThreshold == undefinedElementsThreshold);
+        break;
+        
+    default:
+        for (unsigned i = elementsToExtractThreshold; i < undefinedElementsThreshold; ++i)
+            currentIndexingData()[i].setUndefined();
+    }
 
     // Ensure that unused values in the vector are zeroed out.
-    for (unsigned i = undefinedElementsThreshold; i < clearElementsThreshold; ++i)
-        currentIndexingData()[i].clear();
+    for (unsigned i = undefinedElementsThreshold; i < clearElementsThreshold; ++i) {
+        if (structure()->indexingType() == ArrayWithDouble)
+            butterfly()->contiguousDouble()[i] = QNaN;
+        else
+            currentIndexingData()[i].clear();
+    }
     
     if (hasArrayStorage(structure()->indexingType()))
         arrayStorage()->m_numValuesInVector = newUsedVectorLength;
@@ -1148,8 +1420,17 @@ void JSArray::sort(ExecState* exec, JSValue compareFunction, CallType callType,
     
     switch (structure()->indexingType()) {
     case ArrayClass:
+    case ArrayWithUndecided:
         return;
         
+    case ArrayWithInt32:
+        sortVector<ArrayWithInt32>(exec, compareFunction, callType, callData);
+        return;
+
+    case ArrayWithDouble:
+        sortVector<ArrayWithDouble>(exec, compareFunction, callType, callData);
+        return;
+
     case ArrayWithContiguous:
         sortVector<ArrayWithContiguous>(exec, compareFunction, callType, callData);
         return;
@@ -1173,11 +1454,30 @@ void JSArray::fillArgList(ExecState* exec, MarkedArgumentBuffer& args)
     case ArrayClass:
         return;
         
+    case ArrayWithUndecided: {
+        vector = 0;
+        vectorEnd = 0;
+        break;
+    }
+        
+    case ArrayWithInt32:
     case ArrayWithContiguous: {
         vectorEnd = m_butterfly->publicLength();
         vector = m_butterfly->contiguous();
         break;
     }
+        
+    case ArrayWithDouble: {
+        vector = 0;
+        vectorEnd = 0;
+        for (; i < m_butterfly->publicLength(); ++i) {
+            double v = butterfly()->contiguousDouble()[i];
+            if (v != v)
+                break;
+            args.append(JSValue(JSValue::EncodeAsDouble, v));
+        }
+        break;
+    }
     
     case ARRAY_WITH_ARRAY_STORAGE_INDEXING_TYPES: {
         ArrayStorage* storage = m_butterfly->arrayStorage();
@@ -1216,12 +1516,31 @@ void JSArray::copyToArguments(ExecState* exec, CallFrame* callFrame, uint32_t le
     case ArrayClass:
         return;
         
+    case ArrayWithUndecided: {
+        vector = 0;
+        vectorEnd = 0;
+        break;
+    }
+        
+    case ArrayWithInt32:
     case ArrayWithContiguous: {
         vector = m_butterfly->contiguous();
         vectorEnd = m_butterfly->publicLength();
         break;
     }
         
+    case ArrayWithDouble: {
+        vector = 0;
+        vectorEnd = 0;
+        for (; i < m_butterfly->publicLength(); ++i) {
+            double v = m_butterfly->contiguousDouble()[i];
+            if (v != v)
+                break;
+            callFrame->setArgument(i, JSValue(JSValue::EncodeAsDouble, v));
+        }
+        break;
+    }
+        
     case ARRAY_WITH_ARRAY_STORAGE_INDEXING_TYPES: {
         ArrayStorage* storage = m_butterfly->arrayStorage();
         vector = storage->m_vector;
@@ -1259,12 +1578,40 @@ void JSArray::compactForSorting(unsigned& numDefined, unsigned& newRelevantLengt
     unsigned numUndefined = 0;
         
     for (; numDefined < myRelevantLength; ++numDefined) {
+        if (indexingType == ArrayWithInt32) {
+            JSValue v = m_butterfly->contiguousInt32()[numDefined].get();
+            if (!v)
+                break;
+            ASSERT(v.isInt32());
+            continue;
+        }
+        if (indexingType == ArrayWithDouble) {
+            double v = m_butterfly->contiguousDouble()[numDefined];
+            if (v != v)
+                break;
+            continue;
+        }
         JSValue v = indexingData<indexingType>()[numDefined].get();
         if (!v || v.isUndefined())
             break;
     }
         
     for (unsigned i = numDefined; i < myRelevantLength; ++i) {
+        if (indexingType == ArrayWithInt32) {
+            JSValue v = m_butterfly->contiguousInt32()[i].get();
+            if (!v)
+                continue;
+            ASSERT(v.isInt32());
+            m_butterfly->contiguousInt32()[numDefined++].setWithoutWriteBarrier(v);
+            continue;
+        }
+        if (indexingType == ArrayWithDouble) {
+            double v = m_butterfly->contiguousDouble()[i];
+            if (v != v)
+                continue;
+            m_butterfly->contiguousDouble()[numDefined++] = v;
+            continue;
+        }
         JSValue v = indexingData<indexingType>()[i].get();
         if (v) {
             if (v.isUndefined())
@@ -1279,10 +1626,23 @@ void JSArray::compactForSorting(unsigned& numDefined, unsigned& newRelevantLengt
     if (hasArrayStorage(indexingType))
         ASSERT(!arrayStorage()->m_sparseMap);
     
-    for (unsigned i = numDefined; i < newRelevantLength; ++i)
-        indexingData<indexingType>()[i].setUndefined();
-    for (unsigned i = newRelevantLength; i < myRelevantLength; ++i)
-        indexingData<indexingType>()[i].clear();
+    switch (indexingType) {
+    case ArrayWithInt32:
+    case ArrayWithDouble:
+        ASSERT(numDefined == newRelevantLength);
+        break;
+        
+    default:
+        for (unsigned i = numDefined; i < newRelevantLength; ++i)
+            indexingData<indexingType>()[i].setUndefined();
+        break;
+    }
+    for (unsigned i = newRelevantLength; i < myRelevantLength; ++i) {
+        if (indexingType == ArrayWithDouble)
+            m_butterfly->contiguousDouble()[i] = QNaN;
+        else
+            indexingData<indexingType>()[i].clear();
+    }
 
     if (hasArrayStorage(indexingType))
         arrayStorage()->m_numValuesInVector = newRelevantLength;
index 1d1e641..c96319c 100644 (file)
@@ -162,7 +162,7 @@ private:
     void sortNumericVector(ExecState*, JSValue compareFunction, CallType, const CallData&);
         
     template<IndexingType indexingType>
-    void sortCompactedVector(ExecState*, WriteBarrier<Unknown>* begin, unsigned relevantLength);
+    void sortCompactedVector(ExecState*, void* begin, unsigned relevantLength);
         
     template<IndexingType indexingType>
     void sortVector(ExecState*, JSValue compareFunction, CallType, const CallData&);
@@ -174,13 +174,14 @@ private:
     void compactForSorting(unsigned& numDefined, unsigned& newRelevantLength);
 };
 
-inline Butterfly* createContiguousArrayButterfly(JSGlobalData& globalData, unsigned length)
+inline Butterfly* createContiguousArrayButterfly(JSGlobalData& globalData, unsigned length, unsigned& vectorLength)
 {
     IndexingHeader header;
-    header.setVectorLength(std::max(length, BASE_VECTOR_LEN));
+    vectorLength = std::max(length, BASE_VECTOR_LEN);
+    header.setVectorLength(vectorLength);
     header.setPublicLength(length);
     Butterfly* result = Butterfly::create(
-        globalData, 0, 0, true, header, header.vectorLength() * sizeof(EncodedJSValue));
+        globalData, 0, 0, true, header, vectorLength * sizeof(EncodedJSValue));
     return result;
 }
 
@@ -200,13 +201,23 @@ Butterfly* createArrayButterflyInDictionaryIndexingMode(JSGlobalData&, unsigned
 inline JSArray* JSArray::create(JSGlobalData& globalData, Structure* structure, unsigned initialLength)
 {
     Butterfly* butterfly;
-    if (LIKELY(structure->indexingType() == ArrayWithContiguous)) {
-        butterfly = createContiguousArrayButterfly(globalData, initialLength);
+    if (LIKELY(!hasArrayStorage(structure->indexingType()))) {
+        ASSERT(
+            hasUndecided(structure->indexingType())
+            || hasInt32(structure->indexingType())
+            || hasDouble(structure->indexingType())
+            || hasContiguous(structure->indexingType()));
+        unsigned vectorLength;
+        butterfly = createContiguousArrayButterfly(globalData, initialLength, vectorLength);
         ASSERT(initialLength < MIN_SPARSE_ARRAY_INDEX);
+        if (hasDouble(structure->indexingType())) {
+            for (unsigned i = 0; i < vectorLength; ++i)
+                butterfly->contiguousDouble()[i] = QNaN;
+        }
     } else {
         ASSERT(
             structure->indexingType() == ArrayWithSlowPutArrayStorage
-            || (initialLength && structure->indexingType() == ArrayWithArrayStorage));
+            || structure->indexingType() == ArrayWithArrayStorage);
         butterfly = createArrayButterfly(globalData, initialLength);
     }
     JSArray* array = new (NotNull, allocateCell<JSArray>(globalData.heap)) JSArray(globalData, structure, butterfly);
@@ -221,8 +232,13 @@ inline JSArray* JSArray::tryCreateUninitialized(JSGlobalData& globalData, Struct
         return 0;
         
     Butterfly* butterfly;
-    if (LIKELY(structure->indexingType() == ArrayWithContiguous)) {
-            
+    if (LIKELY(!hasArrayStorage(structure->indexingType()))) {
+        ASSERT(
+            hasUndecided(structure->indexingType())
+            || hasInt32(structure->indexingType())
+            || hasDouble(structure->indexingType())
+            || hasContiguous(structure->indexingType()));
+
         void* temp;
         if (!globalData.heap.tryAllocateStorage(Butterfly::totalSize(0, 0, true, vectorLength * sizeof(EncodedJSValue)), &temp))
             return 0;
index c466a2b..a7c6c8c 100644 (file)
@@ -230,9 +230,16 @@ void JSGlobalObject::reset(JSValue prototype)
     m_callbackObjectStructure.set(exec->globalData(), this, JSCallbackObject<JSDestructibleObject>::createStructure(exec->globalData(), this, m_objectPrototype.get()));
 
     m_arrayPrototype.set(exec->globalData(), this, ArrayPrototype::create(exec, this, ArrayPrototype::createStructure(exec->globalData(), this, m_objectPrototype.get())));
-    m_arrayStructure.set(exec->globalData(), this, JSArray::createStructure(exec->globalData(), this, m_arrayPrototype.get(), ArrayWithContiguous));
-    m_arrayStructureWithArrayStorage.set(exec->globalData(), this, JSArray::createStructure(exec->globalData(), this, m_arrayPrototype.get(), ArrayWithArrayStorage));
-    m_arrayStructureForSlowPut.set(exec->globalData(), this, JSArray::createStructure(exec->globalData(), this, m_arrayPrototype.get(), ArrayWithSlowPutArrayStorage));
+    
+    m_originalArrayStructureForIndexingShape[UndecidedShape >> IndexingShapeShift].set(exec->globalData(), this, JSArray::createStructure(exec->globalData(), this, m_arrayPrototype.get(), ArrayWithUndecided));
+    m_originalArrayStructureForIndexingShape[Int32Shape >> IndexingShapeShift].set(exec->globalData(), this, JSArray::createStructure(exec->globalData(), this, m_arrayPrototype.get(), ArrayWithInt32));
+    m_originalArrayStructureForIndexingShape[DoubleShape >> IndexingShapeShift].set(exec->globalData(), this, JSArray::createStructure(exec->globalData(), this, m_arrayPrototype.get(), ArrayWithDouble));
+    m_originalArrayStructureForIndexingShape[ContiguousShape >> IndexingShapeShift].set(exec->globalData(), this, JSArray::createStructure(exec->globalData(), this, m_arrayPrototype.get(), ArrayWithContiguous));
+    m_originalArrayStructureForIndexingShape[ArrayStorageShape >> IndexingShapeShift].set(exec->globalData(), this, JSArray::createStructure(exec->globalData(), this, m_arrayPrototype.get(), ArrayWithArrayStorage));
+    m_originalArrayStructureForIndexingShape[SlowPutArrayStorageShape >> IndexingShapeShift].set(exec->globalData(), this, JSArray::createStructure(exec->globalData(), this, m_arrayPrototype.get(), ArrayWithSlowPutArrayStorage));
+    for (unsigned i = 0; i < NumberOfIndexingShapes; ++i)
+        m_arrayStructureForIndexingShapeDuringAllocation[i] = m_originalArrayStructureForIndexingShape[i];
+    
     m_regExpMatchesArrayStructure.set(exec->globalData(), this, RegExpMatchesArray::createStructure(exec->globalData(), this, m_arrayPrototype.get()));
 
     m_stringPrototype.set(exec->globalData(), this, StringPrototype::create(exec, this, StringPrototype::createStructure(exec->globalData(), this, m_objectPrototype.get())));
@@ -360,7 +367,9 @@ inline bool hasBrokenIndexing(JSObject* object)
 {
     // This will change if we have more indexing types.
     IndexingType type = object->structure()->indexingType();
-    return hasContiguous(type) || hasFastArrayStorage(type);
+    // This could be made obviously more efficient, but isn't made so right now, because
+    // we expect this to be an unlikely slow path anyway.
+    return hasUndecided(type) || hasInt32(type) || hasDouble(type) || hasContiguous(type) || hasFastArrayStorage(type);
 }
 
 void ObjectsWithBrokenIndexingFinder::operator()(JSCell* cell)
@@ -412,8 +421,8 @@ void JSGlobalObject::haveABadTime(JSGlobalData& globalData)
     
     // Make sure that all JSArray allocations that load the appropriate structure from
     // this object now load a structure that uses SlowPut.
-    m_arrayStructure.set(globalData, this, m_arrayStructureForSlowPut.get());
-    m_arrayStructureWithArrayStorage.set(globalData, this, m_arrayStructureForSlowPut.get());
+    for (unsigned i = 0; i < NumberOfIndexingShapes; ++i)
+        m_arrayStructureForIndexingShapeDuringAllocation[i].set(globalData, this, originalArrayStructureForIndexingType(ArrayWithSlowPutArrayStorage));
     
     // Make sure that all objects that have indexed storage switch to the slow kind of
     // indexed storage.
@@ -488,9 +497,10 @@ void JSGlobalObject::visitChildren(JSCell* cell, SlotVisitor& visitor)
     visitor.append(&thisObject->m_activationStructure);
     visitor.append(&thisObject->m_nameScopeStructure);
     visitor.append(&thisObject->m_argumentsStructure);
-    visitor.append(&thisObject->m_arrayStructure);
-    visitor.append(&thisObject->m_arrayStructureWithArrayStorage);
-    visitor.append(&thisObject->m_arrayStructureForSlowPut);
+    for (unsigned i = 0; i < NumberOfIndexingShapes; ++i)
+        visitor.append(&thisObject->m_originalArrayStructureForIndexingShape[i]);
+    for (unsigned i = 0; i < NumberOfIndexingShapes; ++i)
+        visitor.append(&thisObject->m_arrayStructureForIndexingShapeDuringAllocation[i]);
     visitor.append(&thisObject->m_booleanObjectStructure);
     visitor.append(&thisObject->m_callbackConstructorStructure);
     visitor.append(&thisObject->m_callbackFunctionStructure);
index 3212363..121b71b 100644 (file)
@@ -22,6 +22,7 @@
 #ifndef JSGlobalObject_h
 #define JSGlobalObject_h
 
+#include "ArrayAllocationProfile.h"
 #include "JSArray.h"
 #include "JSGlobalData.h"
 #include "JSSegmentedVariableObject.h"
@@ -130,9 +131,12 @@ namespace JSC {
         WriteBarrier<Structure> m_activationStructure;
         WriteBarrier<Structure> m_nameScopeStructure;
         WriteBarrier<Structure> m_argumentsStructure;
-        WriteBarrier<Structure> m_arrayStructure; // This gets set to m_arrayStructureForSlowPut as soon as we decide to have a bad time.
-        WriteBarrier<Structure> m_arrayStructureWithArrayStorage; // This gets set to m_arrayStructureForSlowPut as soon as we decide to have a bad time.
-        WriteBarrier<Structure> m_arrayStructureForSlowPut;
+        
+        // Lists the actual structures used for having these particular indexing shapes.
+        WriteBarrier<Structure> m_originalArrayStructureForIndexingShape[NumberOfIndexingShapes];
+        // Lists the structures we should use during allocation for these particular indexing shapes.
+        WriteBarrier<Structure> m_arrayStructureForIndexingShapeDuringAllocation[NumberOfIndexingShapes];
+        
         WriteBarrier<Structure> m_booleanObjectStructure;
         WriteBarrier<Structure> m_callbackConstructorStructure;
         WriteBarrier<Structure> m_callbackFunctionStructure;
@@ -275,14 +279,26 @@ namespace JSC {
         Structure* activationStructure() const { return m_activationStructure.get(); }
         Structure* nameScopeStructure() const { return m_nameScopeStructure.get(); }
         Structure* argumentsStructure() const { return m_argumentsStructure.get(); }
-        Structure* arrayStructure() const { return m_arrayStructure.get(); }
-        Structure* arrayStructureWithArrayStorage() const { return m_arrayStructureWithArrayStorage.get(); }
-        void* addressOfArrayStructure() { return &m_arrayStructure; }
-        void* addressOfArrayStructureWithArrayStorage() { return &m_arrayStructureWithArrayStorage; }
+        Structure* originalArrayStructureForIndexingType(IndexingType indexingType) const
+        {
+            ASSERT(indexingType & IsArray);
+            return m_originalArrayStructureForIndexingShape[(indexingType & IndexingShapeMask) >> IndexingShapeShift].get();
+        }
+        Structure* arrayStructureForIndexingTypeDuringAllocation(IndexingType indexingType) const
+        {
+            ASSERT(indexingType & IsArray);
+            return m_arrayStructureForIndexingShapeDuringAllocation[(indexingType & IndexingShapeMask) >> IndexingShapeShift].get();
+        }
+        Structure* arrayStructureForProfileDuringAllocation(ArrayAllocationProfile* profile) const
+        {
+            return arrayStructureForIndexingTypeDuringAllocation(ArrayAllocationProfile::selectIndexingTypeFor(profile));
+        }
+        
         bool isOriginalArrayStructure(Structure* structure)
         {
-            return structure == m_arrayStructure.get() || structure == m_arrayStructureWithArrayStorage.get();
+            return originalArrayStructureForIndexingType(structure->indexingType() | IsArray) == structure;
         }
+        
         Structure* booleanObjectStructure() const { return m_booleanObjectStructure.get(); }
         Structure* callbackConstructorStructure() const { return m_callbackConstructorStructure.get(); }
         Structure* callbackFunctionStructure() const { return m_callbackFunctionStructure.get(); }
@@ -497,34 +513,34 @@ namespace JSC {
         return constructEmptyObject(exec, exec->lexicalGlobalObject());
     }
 
-    inline JSArray* constructEmptyArray(ExecState* exec, JSGlobalObject* globalObject, unsigned initialLength = 0)
+    inline JSArray* constructEmptyArray(ExecState* exec, ArrayAllocationProfile* profile, JSGlobalObject* globalObject, unsigned initialLength = 0)
     {
-        return JSArray::create(exec->globalData(), initialLength >= MIN_SPARSE_ARRAY_INDEX ? globalObject->arrayStructureWithArrayStorage() : globalObject->arrayStructure(), initialLength);
+        return ArrayAllocationProfile::updateLastAllocationFor(profile, JSArray::create(exec->globalData(), initialLength >= MIN_SPARSE_ARRAY_INDEX ? globalObject->arrayStructureForIndexingTypeDuringAllocation(ArrayWithArrayStorage) : globalObject->arrayStructureForProfileDuringAllocation(profile), initialLength));
     }
 
-    inline JSArray* constructEmptyArray(ExecState* exec, unsigned initialLength = 0)
+    inline JSArray* constructEmptyArray(ExecState* exec, ArrayAllocationProfile* profile, unsigned initialLength = 0)
     {
-        return constructEmptyArray(exec, exec->lexicalGlobalObject(), initialLength);
+        return constructEmptyArray(exec, profile, exec->lexicalGlobalObject(), initialLength);
     }
  
-    inline JSArray* constructArray(ExecState* exec, JSGlobalObject* globalObject, const ArgList& values)
+    inline JSArray* constructArray(ExecState* exec, ArrayAllocationProfile* profile, JSGlobalObject* globalObject, const ArgList& values)
     {
-        return constructArray(exec, globalObject->arrayStructure(), values);
+        return ArrayAllocationProfile::updateLastAllocationFor(profile, constructArray(exec, globalObject->arrayStructureForProfileDuringAllocation(profile), values));
     }
 
-    inline JSArray* constructArray(ExecState* exec, const ArgList& values)
+    inline JSArray* constructArray(ExecState* exec, ArrayAllocationProfile* profile, const ArgList& values)
     {
-        return constructArray(exec, exec->lexicalGlobalObject(), values);
+        return constructArray(exec, profile, exec->lexicalGlobalObject(), values);
     }
 
-    inline JSArray* constructArray(ExecState* exec, JSGlobalObject* globalObject, const JSValue* values, unsigned length)
+    inline JSArray* constructArray(ExecState* exec, ArrayAllocationProfile* profile, JSGlobalObject* globalObject, const JSValue* values, unsigned length)
     {
-        return constructArray(exec, globalObject->arrayStructure(), values, length);
+        return ArrayAllocationProfile::updateLastAllocationFor(profile, constructArray(exec, globalObject->arrayStructureForProfileDuringAllocation(profile), values, length));
     }
 
-    inline JSArray* constructArray(ExecState* exec, const JSValue* values, unsigned length)
+    inline JSArray* constructArray(ExecState* exec, ArrayAllocationProfile* profile, const JSValue* values, unsigned length)
     {
-        return constructArray(exec, exec->lexicalGlobalObject(), values, length);
+        return constructArray(exec, profile, exec->lexicalGlobalObject(), values, length);
     }
 
     class DynamicGlobalObjectScope {
index 6a3fb84..c81dfde 100644 (file)
@@ -129,7 +129,16 @@ ALWAYS_INLINE void JSObject::copyButterfly(CopyVisitor& visitor, Butterfly* butt
             size_t count;
             
             switch (structure->indexingType()) {
-            case ALL_CONTIGUOUS_INDEXING_TYPES: {
+            case ALL_UNDECIDED_INDEXING_TYPES: {
+                currentTarget = 0;
+                currentSource = 0;
+                count = 0;
+                break;
+            }
+                
+            case ALL_CONTIGUOUS_INDEXING_TYPES:
+            case ALL_INT32_INDEXING_TYPES:
+            case ALL_DOUBLE_INDEXING_TYPES: {
                 currentTarget = newButterfly->contiguous();
                 currentSource = butterfly->contiguous();
                 ASSERT(newButterfly->publicLength() <= newButterfly->vectorLength());
@@ -152,8 +161,7 @@ ALWAYS_INLINE void JSObject::copyButterfly(CopyVisitor& visitor, Butterfly* butt
                 break;
             }
 
-            while (count--)
-                (currentTarget++)->setWithoutWriteBarrier((currentSource++)->get());
+            memcpy(currentTarget, currentSource, count * sizeof(EncodedJSValue));
         }
         
         m_butterfly = newButterfly;
@@ -272,8 +280,10 @@ bool JSObject::getOwnPropertySlotByIndex(JSCell* cell, ExecState* exec, unsigned
     
     switch (thisObject->structure()->indexingType()) {
     case ALL_BLANK_INDEXING_TYPES:
+    case ALL_UNDECIDED_INDEXING_TYPES:
         break;
         
+    case ALL_INT32_INDEXING_TYPES:
     case ALL_CONTIGUOUS_INDEXING_TYPES: {
         Butterfly* butterfly = thisObject->m_butterfly;
         if (i >= butterfly->vectorLength())
@@ -288,6 +298,20 @@ bool JSObject::getOwnPropertySlotByIndex(JSCell* cell, ExecState* exec, unsigned
         return false;
     }
         
+    case ALL_DOUBLE_INDEXING_TYPES: {
+        Butterfly* butterfly = thisObject->m_butterfly;
+        if (i >= butterfly->vectorLength())
+            return false;
+        
+        double value = butterfly->contiguousDouble()[i];
+        if (value == value) {
+            slot.setValue(JSValue(JSValue::EncodeAsDouble, value));
+            return true;
+        }
+        
+        return false;
+    }
+        
     case ALL_ARRAY_STORAGE_INDEXING_TYPES: {
         ArrayStorage* storage = thisObject->m_butterfly->arrayStorage();
         if (i >= storage->length())
@@ -405,6 +429,22 @@ void JSObject::putByIndex(JSCell* cell, ExecState* exec, unsigned propertyName,
     case ALL_BLANK_INDEXING_TYPES:
         break;
         
+    case ALL_UNDECIDED_INDEXING_TYPES: {
+        thisObject->convertUndecidedForValue(exec->globalData(), value);
+        // Reloop.
+        putByIndex(cell, exec, propertyName, value, shouldThrow);
+        return;
+    }
+        
+    case ALL_INT32_INDEXING_TYPES: {
+        if (!value.isInt32()) {
+            thisObject->convertInt32ForValue(exec->globalData(), value);
+            putByIndex(cell, exec, propertyName, value, shouldThrow);
+            return;
+        }
+        // Fall through.
+    }
+        
     case ALL_CONTIGUOUS_INDEXING_TYPES: {
         Butterfly* butterfly = thisObject->m_butterfly;
         if (propertyName >= butterfly->vectorLength())
@@ -415,6 +455,29 @@ void JSObject::putByIndex(JSCell* cell, ExecState* exec, unsigned propertyName,
         return;
     }
         
+    case ALL_DOUBLE_INDEXING_TYPES: {
+        if (!value.isNumber()) {
+            thisObject->convertDoubleToContiguous(exec->globalData());
+            // Reloop.
+            putByIndex(cell, exec, propertyName, value, shouldThrow);
+            return;
+        }
+        double valueAsDouble = value.asNumber();
+        if (valueAsDouble != valueAsDouble) {
+            thisObject->convertDoubleToContiguous(exec->globalData());
+            // Reloop.
+            putByIndex(cell, exec, propertyName, value, shouldThrow);
+            return;
+        }
+        Butterfly* butterfly = thisObject->m_butterfly;
+        if (propertyName >= butterfly->vectorLength())
+            break;
+        butterfly->contiguousDouble()[propertyName] = valueAsDouble;
+        if (propertyName >= butterfly->publicLength())
+            butterfly->setPublicLength(propertyName + 1);
+        return;
+    }
+        
     case NonArrayWithArrayStorage:
     case ArrayWithArrayStorage: {
         ArrayStorage* storage = thisObject->m_butterfly->arrayStorage();
@@ -507,10 +570,13 @@ ArrayStorage* JSObject::enterDictionaryIndexingModeWhenArrayStorageAlreadyExists
 void JSObject::enterDictionaryIndexingMode(JSGlobalData& globalData)
 {
     switch (structure()->indexingType()) {
+    case ALL_UNDECIDED_INDEXING_TYPES:
+    case ALL_INT32_INDEXING_TYPES:
+    case ALL_DOUBLE_INDEXING_TYPES:
     case ALL_CONTIGUOUS_INDEXING_TYPES:
         // NOTE: this is horribly inefficient, as it will perform two conversions. We could optimize
         // this case if we ever cared.
-        enterDictionaryIndexingModeWhenArrayStorageAlreadyExists(globalData, convertContiguousToArrayStorage(globalData));
+        enterDictionaryIndexingModeWhenArrayStorageAlreadyExists(globalData, ensureArrayStorageSlow(globalData));
         break;
     case ALL_ARRAY_STORAGE_INDEXING_TYPES:
         enterDictionaryIndexingModeWhenArrayStorageAlreadyExists(globalData, m_butterfly->arrayStorage());