WebKit Bugzilla
New
Browse
Search+
Log In
×
Sign in with GitHub
or
Remember my login
Create Account
·
Forgot Password
Forgotten password account recovery
[patch]
rebased and fighting regressions
arraytype_14.patch (text/plain), 266.66 KB, created by
Filip Pizlo
on 2012-10-28 00:57:51 PDT
(
hide
)
Description:
rebased and fighting regressions
Filename:
MIME Type:
Creator:
Filip Pizlo
Created:
2012-10-28 00:57:51 PDT
Size:
266.66 KB
patch
obsolete
>Index: Source/JavaScriptCore/ChangeLog >=================================================================== >--- Source/JavaScriptCore/ChangeLog (revision 132745) >+++ Source/JavaScriptCore/ChangeLog (working copy) >@@ -1,3 +1,304 @@ >+2012-10-27 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 NOBODY (OOPS!). >+ >+ Work in progress. >+ >+ * API/JSObjectRef.cpp: >+ (JSObjectMakeArray): >+ * JavaScriptCore.xcodeproj/project.pbxproj: >+ * 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.h: >+ (JSC): >+ (JSC::arrayModesInclude): >+ (JSC::shouldUseSlowPutArrayStorage): >+ (JSC::shouldUseFastArrayStorage): >+ (JSC::shouldUseContiguous): >+ (JSC::shouldUseDouble): >+ (JSC::shouldUseInt32): >+ * bytecode/ByValInfo.h: >+ (JSC::isOptimizableIndexingType): >+ (JSC::jitArrayModeForIndexingType): >+ * bytecode/CodeBlock.cpp: >+ (JSC::CodeBlock::dump): >+ (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/Instruction.h: >+ (JSC): >+ (JSC::Instruction::Instruction): >+ * bytecode/Opcode.h: >+ (JSC): >+ (JSC::padOpcodeName): >+ * bytecode/SpeculatedType.h: >+ (JSC): >+ (JSC::isRealNumberSpeculation): >+ * bytecompiler/BytecodeGenerator.cpp: >+ (JSC::BytecodeGenerator::emitNewArray): >+ (JSC::BytecodeGenerator::emitExpectedFunctionSnippet): >+ * dfg/DFGAbstractState.cpp: >+ (JSC::DFG::AbstractState::execute): >+ * dfg/DFGArrayMode.cpp: >+ (JSC::DFG::fromObserved): >+ (JSC::DFG::refineArrayMode): >+ (JSC::DFG::modeAlreadyChecked): >+ (JSC::DFG::modeToString): >+ * dfg/DFGArrayMode.h: >+ (DFG): >+ (JSC::DFG::modeUsesButterfly): >+ (JSC::DFG::modeIsJSArray): >+ (JSC::DFG::modeIsInt32): >+ (JSC::DFG::modeIsDouble): >+ (JSC::DFG::isInBoundsAccess): >+ (JSC::DFG::mayStoreToTail): >+ (JSC::DFG::canCSEStorage): >+ (JSC::DFG::modeSupportsLength): >+ (JSC::DFG::arrayModesFor): >+ * dfg/DFGByteCodeParser.cpp: >+ (JSC::DFG::ByteCodeParser::getArrayMode): >+ (ByteCodeParser): >+ (JSC::DFG::ByteCodeParser::handleIntrinsic): >+ (JSC::DFG::ByteCodeParser::handleConstantInternalFunction): >+ (JSC::DFG::ByteCodeParser::parseBlock): >+ * dfg/DFGCCallHelpers.h: >+ (CCallHelpers): >+ (JSC::DFG::CCallHelpers::setupArgumentsWithExecState): >+ * dfg/DFGCSEPhase.cpp: >+ (JSC::DFG::CSEPhase::getArrayLengthElimination): >+ * dfg/DFGCallArrayAllocatorSlowPathGenerator.h: >+ (JSC::DFG::CallArrayAllocatorSlowPathGenerator::generateInternal): >+ (JSC::DFG::CallArrayAllocatorWithVariableSizeSlowPathGenerator::generateInternal): >+ * dfg/DFGFixupPhase.cpp: >+ (JSC::DFG::FixupPhase::fixupNode): >+ * 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): >+ (JSC::DFG::SpeculativeJIT::checkArray): >+ (JSC::DFG::SpeculativeJIT::arrayify): >+ (JSC::DFG::SpeculativeJIT::compileGetArrayLength): >+ * dfg/DFGSpeculativeJIT.h: >+ (JSC::DFG::SpeculativeJIT::callOperation): >+ (JSC::DFG::SpeculativeJIT::putByValWillNeedExtraRegister): >+ (SpeculateDoubleOperand): >+ (JSC::DFG::SpeculateDoubleOperand::use): >+ * dfg/DFGSpeculativeJIT64.cpp: >+ (JSC::DFG::SpeculativeJIT::compile): >+ * jit/JIT.h: >+ (JSC::JIT::emitInt32GetByVal): >+ (JIT): >+ * 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::emitInt32PutByVal): >+ (JSC::JIT::emitDoublePutByVal): >+ (JSC::JIT::emitContiguousPutByVal): >+ (JSC::JIT::emitGenericContiguousPutByVal): >+ (JSC::JIT::emitSlow_op_put_by_val): >+ (JSC::JIT::privateCompileGetByVal): >+ (JSC::JIT::privateCompilePutByVal): >+ * 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/LowLevelInterpreter64.asm: >+ * offlineasm/x86.rb: >+ * runtime/ArrayConstructor.cpp: >+ (JSC::constructArrayWithSizeQuirk): >+ * runtime/ArrayConstructor.h: >+ (JSC): >+ * runtime/ArrayConventions.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/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::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): >+ * 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-10-27 Filip Pizlo <fpizlo@apple.com> > > DFG::Array::Mode needs to be cleaned up >Index: Source/JavaScriptCore/jsc.cpp >=================================================================== >--- Source/JavaScriptCore/jsc.cpp (revision 132745) >+++ Source/JavaScriptCore/jsc.cpp (working copy) >@@ -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: Source/JavaScriptCore/API/JSObjectRef.cpp >=================================================================== >--- Source/JavaScriptCore/API/JSObjectRef.cpp (revision 132745) >+++ Source/JavaScriptCore/API/JSObjectRef.cpp (working copy) >@@ -144,9 +144,9 @@ JSObjectRef JSObjectMakeArray(JSContextR > 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: Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj >=================================================================== >--- Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj (revision 132745) >+++ Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj (working copy) >@@ -167,6 +167,8 @@ > 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 */; }; >@@ -952,6 +954,8 @@ > 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>"; }; >@@ -2512,6 +2516,8 @@ > 969A078F0ED1D3AE00F1F681 /* bytecode */ = { > isa = PBXGroup; > children = ( >+ 0F8335B41639C1E3001443B5 /* ArrayAllocationProfile.cpp */, >+ 0F8335B51639C1E3001443B5 /* ArrayAllocationProfile.h */, > 0F63945115D07051006A597C /* ArrayProfile.cpp */, > 0F63945215D07051006A597C /* ArrayProfile.h */, > 0F21C27E14BEAA8000ADC64B /* BytecodeConventions.h */, >@@ -3009,8 +3015,9 @@ > 862553D216136E1A009F17D0 /* JSProxy.h in Headers */, > 0F5541B21613C1FB00CE3E25 /* SpecialPointer.h in Headers */, > 0FEB3ECD16237F4D00AB67AD /* TypedArrayDescriptor.h in Headers */, >- 0F256C361627B0AD007F2783 /* DFGCallArrayAllocatorSlowPathGenerator.h in Headers */, >+ 0F256C361627B0AD007F2783 /* DFGCallArrayAllocatorSlowPathGenerator.h in Headers */, > C2239D1B16262BDD005AC5FD /* GCThread.h in Headers */, >+ 0F8335B81639C1EA001443B5 /* ArrayAllocationProfile.h in Headers */, > ); > runOnlyForDeploymentPostprocessing = 0; > }; >@@ -3621,6 +3628,7 @@ > C24D31E2161CD695002AA4DB /* HeapStatistics.cpp in Sources */, > C2239D1716262BDD005AC5FD /* CopyVisitor.cpp in Sources */, > C2239D1A16262BDD005AC5FD /* GCThread.cpp in Sources */, >+ 0F8335B71639C1E6001443B5 /* ArrayAllocationProfile.cpp in Sources */, > ); > runOnlyForDeploymentPostprocessing = 0; > }; >Index: Source/JavaScriptCore/assembler/AbstractMacroAssembler.h >=================================================================== >--- Source/JavaScriptCore/assembler/AbstractMacroAssembler.h (revision 132745) >+++ Source/JavaScriptCore/assembler/AbstractMacroAssembler.h (working copy) >@@ -586,6 +586,13 @@ public: > > public: > typedef Vector<Jump, 16> JumpVector; >+ >+ JumpList() { } >+ >+ JumpList(Jump jump) >+ { >+ append(jump); >+ } > > void link(AbstractMacroAssembler<AssemblerType>* masm) > { >Index: Source/JavaScriptCore/assembler/MacroAssemblerX86Common.h >=================================================================== >--- Source/JavaScriptCore/assembler/MacroAssemblerX86Common.h (revision 132745) >+++ Source/JavaScriptCore/assembler/MacroAssemblerX86Common.h (working copy) >@@ -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: Source/JavaScriptCore/assembler/X86Assembler.h >=================================================================== >--- Source/JavaScriptCore/assembler/X86Assembler.h (revision 132745) >+++ Source/JavaScriptCore/assembler/X86Assembler.h (working copy) >@@ -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)); > } > >Index: Source/JavaScriptCore/bytecode/ArrayAllocationProfile.cpp >=================================================================== >--- Source/JavaScriptCore/bytecode/ArrayAllocationProfile.cpp (revision 0) >+++ Source/JavaScriptCore/bytecode/ArrayAllocationProfile.cpp (revision 0) >@@ -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 >+ >Index: Source/JavaScriptCore/bytecode/ArrayAllocationProfile.h >=================================================================== >--- Source/JavaScriptCore/bytecode/ArrayAllocationProfile.h (revision 0) >+++ Source/JavaScriptCore/bytecode/ArrayAllocationProfile.h (revision 0) >@@ -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: Source/JavaScriptCore/bytecode/ArrayProfile.h >=================================================================== >--- Source/JavaScriptCore/bytecode/ArrayProfile.h (revision 132745) >+++ Source/JavaScriptCore/bytecode/ArrayProfile.h (working copy) >@@ -44,12 +44,17 @@ typedef unsigned ArrayModes; > > #define ALL_NON_ARRAY_ARRAY_MODES \ > (asArrayModes(NonArray) \ >+ | asArrayModes(NonArrayWithInt32) \ >+ | asArrayModes(NonArrayWithDouble) \ > | asArrayModes(NonArrayWithContiguous) \ > | asArrayModes(NonArrayWithArrayStorage) \ > | asArrayModes(NonArrayWithSlowPutArrayStorage)) > > #define ALL_ARRAY_ARRAY_MODES \ > (asArrayModes(ArrayClass) \ >+ | asArrayModes(ArrayWithUndecided) \ >+ | asArrayModes(ArrayWithInt32) \ >+ | asArrayModes(ArrayWithDouble) \ > | asArrayModes(ArrayWithContiguous) \ > | asArrayModes(ArrayWithArrayStorage) \ > | asArrayModes(ArrayWithSlowPutArrayStorage)) >@@ -78,6 +83,36 @@ inline bool arrayModesAlreadyChecked(Arr > 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() >Index: Source/JavaScriptCore/bytecode/ByValInfo.h >=================================================================== >--- Source/JavaScriptCore/bytecode/ByValInfo.h (revision 132745) >+++ Source/JavaScriptCore/bytecode/ByValInfo.h (working copy) >@@ -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(Struc > 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: Source/JavaScriptCore/bytecode/CodeBlock.cpp >=================================================================== >--- Source/JavaScriptCore/bytecode/CodeBlock.cpp (revision 132745) >+++ Source/JavaScriptCore/bytecode/CodeBlock.cpp (working copy) >@@ -658,6 +658,7 @@ void CodeBlock::dump(ExecState* exec, co > 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: { >@@ -665,6 +666,7 @@ void CodeBlock::dump(ExecState* exec, co > 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: { >@@ -673,6 +675,7 @@ void CodeBlock::dump(ExecState* exec, co > int argc = (++it)->u.operand; > dataLog("[%4d] new_array_buffer %s, %d, %d", location, registerName(exec, dst).data(), argv, argc); > dumpBytecodeCommentAndNewLine(location); >+ ++it; // Skip array allocation profile. > break; > } > case op_new_regexp: { >@@ -2720,18 +2723,28 @@ void CodeBlock::updateAllPredictionsAndC > #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(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() >@@ -2747,6 +2760,8 @@ bool CodeBlock::shouldOptimizeNow() > if (m_optimizationDelayCounter >= Options::maximumOptimizationDelay()) > return true; > >+ updateAllArrayPredictions(); >+ > unsigned numberOfLiveNonArgumentValueProfiles; > unsigned numberOfSamplesInProfiles; > updateAllPredictionsAndCountLiveness(NoOperation, numberOfLiveNonArgumentValueProfiles, numberOfSamplesInProfiles); >Index: Source/JavaScriptCore/bytecode/CodeBlock.h >=================================================================== >--- Source/JavaScriptCore/bytecode/CodeBlock.h (revision 132745) >+++ Source/JavaScriptCore/bytecode/CodeBlock.h (working copy) >@@ -790,6 +790,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 >@@ -1196,9 +1203,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 > >@@ -1378,6 +1389,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: Source/JavaScriptCore/bytecode/Instruction.h >=================================================================== >--- Source/JavaScriptCore/bytecode/Instruction.h (revision 132745) >+++ Source/JavaScriptCore/bytecode/Instruction.h (working copy) >@@ -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: Source/JavaScriptCore/bytecode/Opcode.h >=================================================================== >--- Source/JavaScriptCore/bytecode/Opcode.h (revision 132745) >+++ Source/JavaScriptCore/bytecode/Opcode.h (working copy) >@@ -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: Source/JavaScriptCore/bytecode/SpeculatedType.h >=================================================================== >--- Source/JavaScriptCore/bytecode/SpeculatedType.h (revision 132745) >+++ Source/JavaScriptCore/bytecode/SpeculatedType.h (working copy) >@@ -61,6 +61,7 @@ static const SpeculatedType SpecInt32 > 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(Speculat > 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: Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp >=================================================================== >--- Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp (revision 132745) >+++ Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp (working copy) >@@ -1722,6 +1722,7 @@ RegisterID* BytecodeGenerator::emitNewAr > instructions().append(dst->index()); > instructions().append(constantBufferIndex); > instructions().append(length); >+ instructions().append(m_codeBlock->addArrayAllocationProfile()); > return dst; > } > } >@@ -1739,6 +1740,7 @@ RegisterID* BytecodeGenerator::emitNewAr > instructions().append(dst->index()); > instructions().append(argv.size() ? argv[0]->index() : 0); // argv > instructions().append(argv.size()); // argc >+ instructions().append(m_codeBlock->addArrayAllocationProfile()); > return dst; > } > >@@ -1874,12 +1876,14 @@ ExpectedFunction BytecodeGenerator::emit > emitOpcode(op_new_array_with_size); > instructions().append(dst->index()); > instructions().append(callArguments.argumentRegister(0)->index()); >+ instructions().append(m_codeBlock->addArrayAllocationProfile()); > } else { > ASSERT(callArguments.argumentCountIncludingThis() == 1); > emitOpcode(op_new_array); > instructions().append(dst->index()); > instructions().append(0); > instructions().append(0); >+ instructions().append(m_codeBlock->addArrayAllocationProfile()); > } > } > break; >Index: Source/JavaScriptCore/dfg/DFGAbstractState.cpp >=================================================================== >--- Source/JavaScriptCore/dfg/DFGAbstractState.cpp (revision 132745) >+++ Source/JavaScriptCore/dfg/DFGAbstractState.cpp (working copy) >@@ -424,7 +424,10 @@ bool AbstractState::execute(unsigned ind > 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 ind > } > 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 ind > 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 ind > 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 ind > 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 ind > 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 ind > > 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 ind > > 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; > >@@ -1383,11 +1435,11 @@ bool AbstractState::execute(unsigned ind > 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: Source/JavaScriptCore/dfg/DFGArrayMode.cpp >=================================================================== >--- Source/JavaScriptCore/dfg/DFGArrayMode.cpp (revision 132745) >+++ Source/JavaScriptCore/dfg/DFGArrayMode.cpp (working copy) >@@ -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).withSpeculation(profile, makeSafe); >+ case asArrayModes(ArrayWithInt32): >+ return ArrayMode(Array::Int32, Array::Array, Array::AsIs).withSpeculation(profile, makeSafe); >+ case asArrayModes(NonArrayWithInt32) | asArrayModes(ArrayWithInt32): >+ return ArrayMode(Array::Int32, Array::PossiblyArray, Array::AsIs).withSpeculation(profile, makeSafe); >+ >+ case asArrayModes(NonArrayWithDouble): >+ return ArrayMode(Array::Double, Array::NonArray, Array::AsIs).withSpeculation(profile, makeSafe); >+ case asArrayModes(ArrayWithDouble): >+ return ArrayMode(Array::Double, Array::Array, Array::AsIs).withSpeculation(profile, makeSafe); >+ case asArrayModes(NonArrayWithDouble) | asArrayModes(ArrayWithDouble): >+ return ArrayMode(Array::Double, Array::PossiblyArray, Array::AsIs).withSpeculation(profile, makeSafe); >+ > case asArrayModes(NonArrayWithContiguous): > return ArrayMode(Array::Contiguous, Array::NonArray, Array::AsIs).withSpeculation(profile, makeSafe); > case asArrayModes(ArrayWithContiguous): > return ArrayMode(Array::Contiguous, Array::Array, Array::AsIs).withSpeculation(profile, makeSafe); > case asArrayModes(NonArrayWithContiguous) | asArrayModes(ArrayWithContiguous): > return ArrayMode(Array::Contiguous, Array::PossiblyArray, Array::AsIs).withSpeculation(profile, makeSafe); >+ > case asArrayModes(NonArrayWithArrayStorage): > return ArrayMode(Array::ArrayStorage, Array::NonArray, Array::AsIs).withSpeculation(profile, makeSafe); > case asArrayModes(NonArrayWithSlowPutArrayStorage): >@@ -62,36 +89,38 @@ ArrayMode ArrayMode::fromObserved(ArrayP > case asArrayModes(NonArrayWithSlowPutArrayStorage) | asArrayModes(ArrayWithSlowPutArrayStorage): > case asArrayModes(NonArrayWithArrayStorage) | asArrayModes(ArrayWithArrayStorage) | asArrayModes(NonArrayWithSlowPutArrayStorage) | asArrayModes(ArrayWithSlowPutArrayStorage): > return ArrayMode(Array::SlowPutArrayStorage, Array::PossiblyArray, Array::AsIs).withSpeculation(profile, makeSafe); >- case asArrayModes(NonArrayWithContiguous) | asArrayModes(NonArrayWithArrayStorage): >- return ArrayMode(Array::ArrayStorage, Array::NonArray, Array::Convert).withSpeculation(profile, makeSafe); >- case asArrayModes(ArrayWithContiguous) | asArrayModes(ArrayWithArrayStorage): >- return ArrayMode(Array::ArrayStorage, Array::Array, Array::Convert).withSpeculation(profile, makeSafe); >- case asArrayModes(NonArrayWithContiguous) | asArrayModes(NonArrayWithArrayStorage) | asArrayModes(ArrayWithContiguous) | asArrayModes(ArrayWithArrayStorage): >- return ArrayMode(Array::ArrayStorage, Array::PossiblyArray, Array::Convert).withSpeculation(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); >+ 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; >+ >+ dataLog("makeSafe = %d\n", makeSafe); >+ >+ return ArrayMode(type, arrayClass, Array::Convert).withSpeculation(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 +133,85 @@ ArrayMode ArrayMode::refine(SpeculatedTy > 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 withType(Array::Int32); >+ if (isNumberSpeculation(value)) >+ return withType(Array::Double); >+ return withType(Array::Contiguous); >+ >+ case Array::Int32: >+ if (!value || isInt32Speculation(value)) >+ return *this; >+ if (isNumberSpeculation(value)) >+ return withType(Array::Double); >+ return withType(Array::Contiguous); >+ >+ case Array::Double: >+ if (!value || isNumberSpeculation(value)) >+ return *this; >+ return withType(Array::Contiguous); >+ >+ 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 (arrayClass() == Array::Array) { >+ 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 +226,17 @@ bool ArrayMode::alreadyChecked(AbstractV > case Array::String: > return isStringSpeculation(value.m_type); > >+ case Array::Int32: >+ return alreadyChecked(value, Int32Shape); >+ >+ case Array::Double: >+ return alreadyChecked(value, DoubleShape); >+ > case Array::Contiguous: >- if (arrayClass() == Array::Array) { >- 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 (arrayClass() == Array::Array) { >- 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 (arrayClass() == Array::Array) { >@@ -232,6 +283,7 @@ bool ArrayMode::alreadyChecked(AbstractV > > case Array::SelectUsingPredictions: > case Array::Unprofiled: >+ case Array::Undecided: > break; > } > >@@ -252,6 +304,12 @@ const char* arrayTypeToString(Array::Typ > 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: Source/JavaScriptCore/dfg/DFGArrayMode.h >=================================================================== >--- Source/JavaScriptCore/dfg/DFGArrayMode.h (revision 132745) >+++ Source/JavaScriptCore/dfg/DFGArrayMode.h (working copy) >@@ -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, >@@ -80,7 +83,6 @@ enum Speculation { > ToHole, > OutOfBounds > }; >- > enum Conversion { > AsIs, > Convert >@@ -150,7 +152,12 @@ public: > return withSpeculation(makeSafe ? Array::OutOfBounds : (profile->mayStoreToHole() ? Array::ToHole : Array::InBounds)); > } > >- ArrayMode refine(SpeculatedType base, SpeculatedType index) const; >+ ArrayMode withType(Array::Type type) const >+ { >+ return ArrayMode(type, arrayClass(), speculation(), conversion()); >+ } >+ >+ ArrayMode refine(SpeculatedType base, SpeculatedType index, SpeculatedType value = SpecNone) const; > > bool alreadyChecked(AbstractValue&) const; > >@@ -159,6 +166,8 @@ public: > bool usesButterfly() const > { > switch (type()) { >+ case Array::Int32: >+ case Array::Double: > case Array::Contiguous: > case Array::ArrayStorage: > case Array::SlowPutArrayStorage: >@@ -233,6 +242,7 @@ public: > case Array::Unprofiled: > case Array::ForceExit: > case Array::Generic: >+ case Array::Undecided: > return false; > default: > return true; >@@ -247,6 +257,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: >@@ -279,6 +291,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: >@@ -323,6 +339,8 @@ private: > } > } > >+ bool alreadyChecked(AbstractValue&, IndexingType shape) const; >+ > union { > struct { > uint8_t type; >Index: Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp >=================================================================== >--- Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp (revision 132745) >+++ Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp (working copy) >@@ -906,21 +906,26 @@ private: > return getPrediction(m_graph.size(), m_currentProfilingIndex); > } > >- ArrayMode getArrayMode(ArrayProfile* profile) >+ ArrayMode getArrayMode(ArrayProfile* profile, Array::Action action) > { > profile->computeUpdatedPrediction(); >- 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) > { > profile->computeUpdatedPrediction(); > >-#if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE) >+//#if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE) > if (m_inlineStackTop->m_profiledBlock->numberOfRareCaseProfiles()) > dataLog("Slow case profile for bc#%u: %u\n", m_currentIndex, m_inlineStackTop->m_profiledBlock->rareCaseProfileForBytecodeOffset(m_currentIndex)->m_counter); > dataLog("Array profile for bc#%u: %p%s%s, %u\n", m_currentIndex, profile->expectedStructure(), profile->structureIsPolymorphic() ? " (polymorphic)" : "", profile->mayInterceptIndexedAccesses() ? " (may intercept)" : "", profile->observedArrayModes()); >-#endif >+//#endif > > bool makeSafe = > m_inlineStackTop->m_profiledBlock->couldTakeSlowCase(m_currentIndex) >@@ -1651,6 +1656,9 @@ bool ByteCodeParser::handleIntrinsic(boo > > ArrayMode arrayMode = getArrayMode(m_currentInstruction[5].u.arrayProfile); > 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))); >@@ -1671,6 +1679,9 @@ bool ByteCodeParser::handleIntrinsic(boo > > ArrayMode arrayMode = getArrayMode(m_currentInstruction[5].u.arrayProfile); > switch (arrayMode.type()) { >+ case Array::Undecided: >+ 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))); >@@ -1761,7 +1772,7 @@ bool ByteCodeParser::handleConstantInter > if (argumentCountIncludingThis == 2) { > setIntrinsicResult( > usesResult, resultOperand, >- addToGraph(NewArrayWithSize, get(registerOffset + argumentToOperand(1)))); >+ addToGraph(NewArrayWithSize, OpInfo(ArrayWithUndecided), get(registerOffset + argumentToOperand(1)))); > return true; > } > >@@ -1769,7 +1780,7 @@ bool ByteCodeParser::handleConstantInter > 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; > } > >@@ -2125,24 +2136,39 @@ bool ByteCodeParser::parseBlock(unsigned > 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 (!ASSERT_DISABLED) { >+ for (int i = 0; i < numConstants; ++i) { >+ ASSERT( >+ leastUpperBoundOfIndexingTypeAndValue( >+ data.indexingType, >+ m_codeBlock->constantBuffer(data.startConstant)[i]) >+ == data.indexingType); >+ } >+ } >+ > 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: Source/JavaScriptCore/dfg/DFGCCallHelpers.h >=================================================================== >--- Source/JavaScriptCore/dfg/DFGCCallHelpers.h (revision 132745) >+++ Source/JavaScriptCore/dfg/DFGCCallHelpers.h (working copy) >@@ -463,6 +463,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) >Index: Source/JavaScriptCore/dfg/DFGCallArrayAllocatorSlowPathGenerator.h >=================================================================== >--- Source/JavaScriptCore/dfg/DFGCallArrayAllocatorSlowPathGenerator.h (revision 132745) >+++ Source/JavaScriptCore/dfg/DFGCallArrayAllocatorSlowPathGenerator.h (working copy) >@@ -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: Source/JavaScriptCore/dfg/DFGFixupPhase.cpp >=================================================================== >--- Source/JavaScriptCore/dfg/DFGFixupPhase.cpp (revision 132745) >+++ Source/JavaScriptCore/dfg/DFGFixupPhase.cpp (working copy) >@@ -140,7 +140,26 @@ 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. >+ node.setArrayMode( >+ node.arrayMode().refine( >+ m_graph[node.child1()].prediction(), >+ 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; > } > >@@ -323,13 +342,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: >@@ -350,6 +373,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; > } >Index: Source/JavaScriptCore/dfg/DFGGraph.cpp >=================================================================== >--- Source/JavaScriptCore/dfg/DFGGraph.cpp (revision 132745) >+++ Source/JavaScriptCore/dfg/DFGGraph.cpp (working copy) >@@ -287,6 +287,11 @@ void Graph::dump(const char* prefix, Nod > 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: Source/JavaScriptCore/dfg/DFGGraph.h >=================================================================== >--- Source/JavaScriptCore/dfg/DFGGraph.h (revision 132745) >+++ Source/JavaScriptCore/dfg/DFGGraph.h (working copy) >@@ -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: Source/JavaScriptCore/dfg/DFGNode.h >=================================================================== >--- Source/JavaScriptCore/dfg/DFGNode.h (revision 132745) >+++ Source/JavaScriptCore/dfg/DFGNode.h (working copy) >@@ -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: Source/JavaScriptCore/dfg/DFGOperations.cpp >=================================================================== >--- Source/JavaScriptCore/dfg/DFGOperations.cpp (revision 132745) >+++ Source/JavaScriptCore/dfg/DFGOperations.cpp (working copy) >@@ -580,6 +580,40 @@ void DFG_OPERATION operationPutByValBeyo > 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 operationAr > 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(); >@@ -1328,30 +1371,36 @@ char* DFG_OPERATION operationReallocateB > 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: Source/JavaScriptCore/dfg/DFGOperations.h >=================================================================== >--- Source/JavaScriptCore/dfg/DFGOperations.h (revision 132745) >+++ Source/JavaScriptCore/dfg/DFGOperations.h (working copy) >@@ -64,6 +64,7 @@ typedef EncodedJSValue DFG_OPERATION (*J > 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_DFGOper > 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 operationPutByValCell > 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 operationAllocatePro > 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: Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp >=================================================================== >--- Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp (revision 132745) >+++ Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp (working copy) >@@ -848,6 +848,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: Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp >=================================================================== >--- Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp (revision 132745) >+++ Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp (working copy) >@@ -2597,6 +2597,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()); >@@ -2613,7 +2614,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; > } > >@@ -2646,6 +2647,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()) { >@@ -2788,6 +2843,7 @@ void SpeculativeJIT::compile(Node& node) > GPRReg propertyReg = property.gpr(); > > switch (arrayMode.type()) { >+ case Array::Int32: > case Array::Contiguous: { > JSValueOperand value(this, child3); > >@@ -2795,8 +2851,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()); > } >@@ -2856,6 +2919,77 @@ void SpeculativeJIT::compile(Node& node) > break; > } > >+ case Array::Double: { >+ 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); >+ break; >+ } >+ >+ 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); >+ break; >+ } >+ > case Array::ArrayStorage: > case Array::SlowPutArrayStorage: { > JSValueOperand value(this, child3); >@@ -3080,23 +3214,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)); >@@ -3113,7 +3255,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. >@@ -3151,13 +3329,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); >@@ -3166,14 +3348,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( >@@ -3183,6 +3378,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; > } >@@ -3337,10 +3533,15 @@ 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( >+ hasInt32(structure->indexingType()) >+ || hasDouble(structure->indexingType()) >+ || hasContiguous(structure->indexingType())); > > unsigned numElements = node.numChildren(); > >@@ -3350,15 +3551,48 @@ 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. > > 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())) { >+ 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 >@@ -3375,7 +3609,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; > } >@@ -3385,11 +3619,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())) { >+ 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(); >@@ -3405,7 +3693,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) { >@@ -3421,18 +3709,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))); >@@ -3445,17 +3741,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<intptr_t>(0.0 / 0.0)), 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); >@@ -3469,10 +3776,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); >@@ -3519,7 +3826,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(); >@@ -3530,13 +3838,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); >@@ -3546,7 +3864,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: Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp >=================================================================== >--- Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp (revision 132745) >+++ Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp (working copy) >@@ -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 > 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,16 @@ void SpeculativeJIT::emitAllocateJSArray > 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<intptr_t>(0.0 / 0.0)), scratchGPR); >+ for (unsigned i = numElements; i < vectorLength; ++i) >+ m_jit.store64(scratchGPR, MacroAssembler::Address(storageGPR, sizeof(double) * i)); >+#else >+ FIXME; >+#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 +354,31 @@ const TypedArrayDescriptor* SpeculativeJ > } > } > >+JITCompiler::Jump SpeculativeJIT::jumpSlowForUnwantedArrayMode(GPRReg tempGPR, ArrayMode arrayMode, IndexingType shape) >+{ >+ if (arrayMode.isJSArray()) { >+ m_jit.and32(TrustedImm32(IsArray | IndexingShapeMask), tempGPR); >+ return m_jit.branch32( >+ MacroAssembler::NotEqual, tempGPR, TrustedImm32(IsArray | shape)); >+ } >+ m_jit.and32(TrustedImm32(IndexingShapeMask), tempGPR); >+ return m_jit.branch32(MacroAssembler::NotEqual, tempGPR, TrustedImm32(shape)); >+} >+ > JITCompiler::JumpList SpeculativeJIT::jumpSlowForUnwantedArrayMode(GPRReg tempGPR, ArrayMode arrayMode) > { > JITCompiler::JumpList result; > > switch (arrayMode.type()) { >- case Array::Contiguous: { >- if (arrayMode.isJSArray()) { >- m_jit.and32(TrustedImm32(IsArray | IndexingShapeMask), tempGPR); >- result.append( >- m_jit.branch32( >- MacroAssembler::NotEqual, tempGPR, TrustedImm32(IsArray | ContiguousShape))); >- break; >- } >- m_jit.and32(TrustedImm32(IndexingShapeMask), tempGPR); >- result.append( >- m_jit.branch32(MacroAssembler::NotEqual, tempGPR, TrustedImm32(ContiguousShape))); >- break; >- } >+ case Array::Int32: >+ return jumpSlowForUnwantedArrayMode(tempGPR, arrayMode, Int32Shape); >+ >+ case Array::Double: >+ return jumpSlowForUnwantedArrayMode(tempGPR, arrayMode, DoubleShape); >+ >+ case Array::Contiguous: >+ return jumpSlowForUnwantedArrayMode(tempGPR, arrayMode, ContiguousShape); >+ > case Array::ArrayStorage: > case Array::SlowPutArrayStorage: { > if (arrayMode.isJSArray()) { >@@ -423,6 +441,8 @@ void SpeculativeJIT::checkArray(Node& no > case Array::String: > expectedClassInfo = &JSString::s_info; > break; >+ case Array::Int32: >+ case Array::Double: > case Array::Contiguous: > case Array::ArrayStorage: > case Array::SlowPutArrayStorage: { >@@ -498,11 +518,19 @@ void SpeculativeJIT::arrayify(Node& node > > // 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; >+ } > } > > // Next check that the object does not intercept indexed accesses. If it does, >@@ -517,6 +545,12 @@ void SpeculativeJIT::arrayify(Node& node > // 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; >@@ -3320,6 +3354,8 @@ void SpeculativeJIT::compileGetArrayLeng > 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: Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h >=================================================================== >--- Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h (revision 132745) >+++ Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h (working copy) >@@ -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,6 +1671,11 @@ 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); >@@ -1819,6 +1834,11 @@ 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); >@@ -2415,6 +2435,7 @@ public: > > const TypedArrayDescriptor* typedArrayDescriptor(ArrayMode); > >+ JITCompiler::Jump jumpSlowForUnwantedArrayMode(GPRReg tempWithIndexingTypeReg, ArrayMode, IndexingType); > JITCompiler::JumpList jumpSlowForUnwantedArrayMode(GPRReg tempWithIndexingTypeReg, ArrayMode); > void checkArray(Node&); > void arrayify(Node&, GPRReg baseReg, GPRReg propertyReg); >@@ -3035,6 +3056,11 @@ public: > m_fprOrInvalid = m_jit->fillSpeculateDouble(index()); > return m_fprOrInvalid; > } >+ >+ void use() >+ { >+ m_jit->use(m_index); >+ } > > private: > SpeculativeJIT* m_jit; >Index: Source/JavaScriptCore/jit/JIT.h >=================================================================== >--- Source/JavaScriptCore/jit/JIT.h (revision 132745) >+++ Source/JavaScriptCore/jit/JIT.h (working copy) >@@ -497,7 +497,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); >@@ -506,7 +508,11 @@ 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 emitInt32PutByVal(Instruction*, PatchableJump& badType); >+ JumpList emitDoublePutByVal(Instruction*, PatchableJump& badType); > JumpList emitContiguousPutByVal(Instruction*, PatchableJump& 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: Source/JavaScriptCore/jit/JITExceptions.cpp >=================================================================== >--- Source/JavaScriptCore/jit/JITExceptions.cpp (revision 132745) >+++ Source/JavaScriptCore/jit/JITExceptions.cpp (working copy) >@@ -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: Source/JavaScriptCore/jit/JITInlineMethods.h >=================================================================== >--- Source/JavaScriptCore/jit/JITInlineMethods.h (revision 132745) >+++ Source/JavaScriptCore/jit/JITInlineMethods.h (working copy) >@@ -531,7 +531,7 @@ inline void JIT::emitArrayProfileStoreTo > static inline bool arrayProfileSaw(ArrayProfile* profile, IndexingType capability) > { > #if ENABLE(VALUE_PROFILER) >- return !!(profile->observedArrayModes() & (asArrayModes(NonArray | capability) | asArrayModes(ArrayClass | capability))); >+ return arrayModesInclude(profile->observedArrayModes(), capability); > #else > UNUSED_PARAM(profile); > UNUSED_PARAM(capability); >@@ -541,6 +541,10 @@ static inline bool arrayProfileSaw(Array > > inline JITArrayMode JIT::chooseArrayMode(ArrayProfile* profile) > { >+ if (arrayProfileSaw(profile, Int32Shape)) >+ return JITInt32; >+ if (arrayProfileSaw(profile, DoubleShape)) >+ return JITDouble; > if (arrayProfileSaw(profile, ArrayStorageShape)) > return JITArrayStorage; > return JITContiguous; >Index: Source/JavaScriptCore/jit/JITOpcodes.cpp >=================================================================== >--- Source/JavaScriptCore/jit/JITOpcodes.cpp (revision 132745) >+++ Source/JavaScriptCore/jit/JITOpcodes.cpp (working copy) >@@ -1951,6 +1951,7 @@ void JIT::emit_op_new_array(Instruction* > 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); > } > >@@ -1962,6 +1963,7 @@ void JIT::emit_op_new_array_with_size(In > #else > stubCall.addArgument(currentInstruction[2].u.operand); > #endif >+ stubCall.addArgument(TrustedImmPtr(currentInstruction[3].u.arrayAllocationProfile)); > stubCall.call(currentInstruction[1].u.operand); > } > >@@ -1970,6 +1972,7 @@ void JIT::emit_op_new_array_buffer(Instr > 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: Source/JavaScriptCore/jit/JITPropertyAccess.cpp >=================================================================== >--- Source/JavaScriptCore/jit/JITPropertyAccess.cpp (revision 132745) >+++ Source/JavaScriptCore/jit/JITPropertyAccess.cpp (working copy) >@@ -120,6 +120,12 @@ void JIT::emit_op_get_by_val(Instruction > > 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 > 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(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(ContiguousShape)); >+ 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 > > 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,64 @@ void JIT::emit_op_put_by_val(Instruction > emitWriteBarrier(regT0, regT3, regT1, regT3, ShouldFilterImmediates, WriteBarrierForPropertyAccess); > } > >+JIT::JumpList JIT::emitInt32PutByVal(Instruction* currentInstruction, PatchableJump& badType) >+{ >+ return emitGenericContiguousPutByVal<Int32Shape>(currentInstruction, badType); >+} >+ >+JIT::JumpList JIT::emitDoublePutByVal(Instruction* currentInstruction, PatchableJump& badType) >+{ >+ return emitGenericContiguousPutByVal<DoubleShape>(currentInstruction, badType); >+} >+ > JIT::JumpList JIT::emitContiguousPutByVal(Instruction* currentInstruction, PatchableJump& badType) > { >+ return emitGenericContiguousPutByVal<ContiguousShape>(currentInstruction, 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 +461,23 @@ void JIT::emitSlow_op_put_by_val(Instruc > 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); >@@ -1361,6 +1439,12 @@ void JIT::privateCompileGetByVal(ByValIn > 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; >@@ -1422,6 +1506,12 @@ void JIT::privateCompilePutByVal(ByValIn > 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: Source/JavaScriptCore/jit/JITStubs.cpp >=================================================================== >--- Source/JavaScriptCore/jit/JITStubs.cpp (revision 132745) >+++ Source/JavaScriptCore/jit/JITStubs.cpp (working copy) >@@ -2392,21 +2392,21 @@ DEFINE_STUB_FUNCTION(JSObject*, op_new_a > { > 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) >@@ -2634,7 +2634,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: Source/JavaScriptCore/jit/JITStubs.h >=================================================================== >--- Source/JavaScriptCore/jit/JITStubs.h (revision 132745) >+++ Source/JavaScriptCore/jit/JITStubs.h (working copy) >@@ -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: Source/JavaScriptCore/llint/LLIntSlowPaths.cpp >=================================================================== >--- Source/JavaScriptCore/llint/LLIntSlowPaths.cpp (revision 132745) >+++ Source/JavaScriptCore/llint/LLIntSlowPaths.cpp (working copy) >@@ -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_objec > 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: Source/JavaScriptCore/llint/LowLevelInterpreter64.asm >=================================================================== >--- Source/JavaScriptCore/llint/LowLevelInterpreter64.asm (revision 132745) >+++ Source/JavaScriptCore/llint/LowLevelInterpreter64.asm (working copy) >@@ -1017,7 +1017,9 @@ _llint_op_get_by_val: > sxi2p 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 > loadis 8[PB, PC, 8], t0 >@@ -1026,6 +1028,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 >+ fd2p ft0, t2 >+ subp tagTypeNumber, t2 >+ jmp .opGetByValDone >+ >+.opGetByValNotDouble: > subi ArrayStorageShape, t2 > bia t2, SlowPutArrayStorageShape - ArrayStorageShape, .opGetByValSlow > biaeq t1, -sizeof IndexingHeader + IndexingHeader::m_vectorLength[t3], .opGetByValSlow >@@ -1101,6 +1113,24 @@ _llint_op_get_by_pname: > dispatch(7) > > >+macro contiguousPutByVal(storeCallback) >+ biaeq t3, -sizeof IndexingHeader + IndexingHeader::m_publicLength[t0], .outOfBounds >+.storeResult: >+ loadis 24[PB, PC, 8], 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() > loadis 8[PB, PC, 8], t0 >@@ -1113,25 +1143,38 @@ _llint_op_put_by_val: > sxi2p 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: >- loadis 24[PB, PC, 8], t2 >- loadConstantOrVariable(t2, t1) >- writeBarrier(t1) >- storep 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) >+ >+.opPutByValNotInt32: >+ bineq t2, DoubleShape, .opPutByValNotDouble >+ contiguousPutByVal( >+ macro (operand, scratch, address) >+ loadConstantOrVariable(operand, scratch) >+ bpb scratch, tagTypeNumber, .notInt >+ ci2d scratch, ft0 >+ jmp .ready >+ .notInt: >+ addp tagTypeNumber, scratch >+ fp2d scratch, ft0 >+ bdnequn ft0, ft0, .opPutByValSlow >+ .ready: >+ stored ft0, address >+ end) > >-.opPutByValContiguousOutOfBounds: >- 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 .opPutByValContiguousStoreResult >+.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: Source/JavaScriptCore/llint/LowLevelInterpreter.asm >=================================================================== >--- Source/JavaScriptCore/llint/LowLevelInterpreter.asm (revision 132745) >+++ Source/JavaScriptCore/llint/LowLevelInterpreter.asm (working copy) >@@ -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. >@@ -463,19 +466,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: Source/JavaScriptCore/offlineasm/x86.rb >=================================================================== >--- Source/JavaScriptCore/offlineasm/x86.rb (revision 132745) >+++ Source/JavaScriptCore/offlineasm/x86.rb (working copy) >@@ -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" >Index: Source/JavaScriptCore/runtime/ArrayConstructor.cpp >=================================================================== >--- Source/JavaScriptCore/runtime/ArrayConstructor.cpp (revision 132745) >+++ Source/JavaScriptCore/runtime/ArrayConstructor.cpp (working copy) >@@ -77,15 +77,15 @@ bool ArrayConstructor::getOwnPropertyDes > > // ------------------------------ 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* constructArrayWi > > // 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: Source/JavaScriptCore/runtime/ArrayConstructor.h >=================================================================== >--- Source/JavaScriptCore/runtime/ArrayConstructor.h (revision 132745) >+++ Source/JavaScriptCore/runtime/ArrayConstructor.h (working copy) >@@ -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: Source/JavaScriptCore/runtime/ArrayConventions.h >=================================================================== >--- Source/JavaScriptCore/runtime/ArrayConventions.h (revision 132745) >+++ Source/JavaScriptCore/runtime/ArrayConventions.h (working copy) >@@ -58,7 +58,7 @@ namespace JSC { > > // These values have to be macros to be used in max() and min() without introducing > // a PIC branch in Mach-O binaries, see <rdar://problem/5971391>. >-#define MIN_SPARSE_ARRAY_INDEX 10000U >+#define MIN_SPARSE_ARRAY_INDEX 100000U > #define MAX_STORAGE_VECTOR_INDEX (MAX_STORAGE_VECTOR_LENGTH - 1) > // 0xFFFFFFFF is a bit weird -- is not an array index even though it's an integer. > #define MAX_ARRAY_INDEX 0xFFFFFFFEU >Index: Source/JavaScriptCore/runtime/ArrayPrototype.cpp >=================================================================== >--- Source/JavaScriptCore/runtime/ArrayPrototype.cpp (revision 132745) >+++ Source/JavaScriptCore/runtime/ArrayPrototype.cpp (working copy) >@@ -456,7 +456,7 @@ EncodedJSValue JSC_HOST_CALL arrayProtoF > 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 arrayProtoF > 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 arrayProtoF > 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 arrayProtoF > 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 arrayProtoF > 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 arrayProtoF > > 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: Source/JavaScriptCore/runtime/Butterfly.h >=================================================================== >--- Source/JavaScriptCore/runtime/Butterfly.h (revision 132745) >+++ Source/JavaScriptCore/runtime/Butterfly.h (working copy) >@@ -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: Source/JavaScriptCore/runtime/FunctionPrototype.cpp >=================================================================== >--- Source/JavaScriptCore/runtime/FunctionPrototype.cpp (revision 132745) >+++ Source/JavaScriptCore/runtime/FunctionPrototype.cpp (working copy) >@@ -186,7 +186,7 @@ EncodedJSValue JSC_HOST_CALL functionPro > > // 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: Source/JavaScriptCore/runtime/IndexingHeaderInlineMethods.h >=================================================================== >--- Source/JavaScriptCore/runtime/IndexingHeaderInlineMethods.h (revision 132745) >+++ Source/JavaScriptCore/runtime/IndexingHeaderInlineMethods.h (working copy) >@@ -43,6 +43,9 @@ inline size_t IndexingHeader::preCapacit > 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: Source/JavaScriptCore/runtime/IndexingType.cpp >=================================================================== >--- Source/JavaScriptCore/runtime/IndexingType.cpp (revision 132745) >+++ Source/JavaScriptCore/runtime/IndexingType.cpp (working copy) >@@ -31,6 +31,46 @@ > > 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(Indexin > 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(Indexin > 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: Source/JavaScriptCore/runtime/IndexingType.h >=================================================================== >--- Source/JavaScriptCore/runtime/IndexingType.h (revision 132745) >+++ Source/JavaScriptCore/runtime/IndexingType.h (working copy) >@@ -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 > > // 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 ArrayWithSlowP > 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(Ind > 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(Inde > 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: Source/JavaScriptCore/runtime/JSArray.cpp >=================================================================== >--- Source/JavaScriptCore/runtime/JSArray.cpp (revision 132745) >+++ Source/JavaScriptCore/runtime/JSArray.cpp (working copy) >@@ -410,25 +410,33 @@ bool JSArray::setLength(ExecState* exec, > 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] = 0.0 / 0.0; >+ } else { >+ for (unsigned i = m_butterfly->publicLength(); i-- > newLength;) >+ m_butterfly->contiguous()[i].clear(); >+ } > m_butterfly->setPublicLength(newLength); > return true; > >@@ -448,6 +456,11 @@ JSValue JSArray::pop(ExecState* exec) > case ArrayClass: > return jsUndefined(); > >+ case ArrayWithUndecided: >+ // We have nothing but holes. So, drop down to the slow version. >+ break; >+ >+ case ArrayWithInt32: > case ArrayWithContiguous: { > unsigned length = m_butterfly->publicLength(); > >@@ -464,6 +477,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] = 0.0 / 0.0; >+ m_butterfly->setPublicLength(length); >+ return JSValue(JSValue::EncodeAsDouble, value); >+ } >+ break; >+ } >+ > case ARRAY_WITH_ARRAY_STORAGE_INDEXING_TYPES: { > ArrayStorage* storage = m_butterfly->arrayStorage(); > >@@ -518,10 +547,42 @@ void JSArray::push(ExecState* exec, JSVa > { > 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 +599,42 @@ void JSArray::push(ExecState* exec, JSVa > 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 +740,7 @@ bool JSArray::shiftCountWithAnyIndexingT > case ArrayClass: > return true; > >+ case ArrayWithInt32: > case ArrayWithContiguous: { > unsigned oldLength = m_butterfly->publicLength(); > ASSERT(count <= oldLength); >@@ -654,7 +748,7 @@ bool JSArray::shiftCountWithAnyIndexingT > // 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 +762,7 @@ bool JSArray::shiftCountWithAnyIndexingT > // 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 +776,41 @@ bool JSArray::shiftCountWithAnyIndexingT > 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] = 0.0 / 0.0; >+ >+ m_butterfly->setPublicLength(oldLength - count); >+ return true; >+ } >+ > case ArrayWithArrayStorage: > case ArrayWithSlowPutArrayStorage: > return shiftCountWithArrayStorage(startIndex, count, arrayStorage()); >@@ -742,21 +871,22 @@ bool JSArray::unshiftCountWithAnyIndexin > case ArrayClass: > // 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 +898,31 @@ bool JSArray::unshiftCountWithAnyIndexin > 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 +933,20 @@ bool JSArray::unshiftCountWithAnyIndexin > } > } > >+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(); >@@ -814,11 +983,19 @@ void JSArray::sortNumericVector(ExecStat > 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 +1004,23 @@ void JSArray::sortNumericVector(ExecStat > // 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 +1032,14 @@ void JSArray::sortNumeric(ExecState* exe > 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 +1055,7 @@ void JSArray::sortNumeric(ExecState* exe > } > > 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 +1076,31 @@ void JSArray::sortCompactedVector(ExecSt > 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 +1131,10 @@ void JSArray::sortCompactedVector(ExecSt > // 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 +1150,12 @@ void JSArray::sortCompactedVector(ExecSt > 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); > } >@@ -941,6 +1168,28 @@ void JSArray::sort(ExecState* exec) > case ArrayClass: > 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; > unsigned newRelevantLength; >@@ -1089,28 +1338,78 @@ void JSArray::sortVector(ExecState* exec > 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 = indexingData<indexingType>()[numDefined].get(); >- if (!v || v.isUndefined()) >- break; >- tree.abstractor().m_nodes[numDefined].value = v; >- tree.insert(numDefined); >- } >- for (unsigned i = numDefined; i < usedVectorLength; ++i) { >- if (i > m_butterfly->vectorLength()) >- break; >- JSValue v = indexingData<indexingType>()[i].get(); >- if (v) { >- if (v.isUndefined()) >- ++numUndefined; >- else { >- tree.abstractor().m_nodes[numDefined].value = v; >- tree.insert(numDefined); >- ++numDefined; >+ switch (indexingType) { >+ case ArrayWithInt32: >+ for (; numDefined < usedVectorLength; ++numDefined) { >+ if (numDefined > m_butterfly->vectorLength()) >+ break; >+ JSValue v = indexingData<indexingType>()[numDefined].get(); >+ if (!v) >+ break; >+ ASSERT(v.isInt32()); >+ tree.abstractor().m_nodes[numDefined].value = v; >+ tree.insert(numDefined); >+ } >+ for (unsigned i = numDefined; i < usedVectorLength; ++i) { >+ if (i > m_butterfly->vectorLength()) >+ break; >+ JSValue v = indexingData<indexingType>()[i].get(); >+ if (!v) >+ continue; >+ ASSERT(v.isInt32()); >+ tree.abstractor().m_nodes[numDefined].value = v; >+ tree.insert(numDefined); >+ ++numDefined; >+ } >+ break; >+ >+ case ArrayWithDouble: >+ for (; numDefined < usedVectorLength; ++numDefined) { >+ if (numDefined > m_butterfly->vectorLength()) >+ break; >+ double v = butterfly()->contiguousDouble()[numDefined]; >+ if (v != v) >+ break; >+ tree.abstractor().m_nodes[numDefined].value = JSValue(JSValue::EncodeAsDouble, v); >+ tree.insert(numDefined); >+ } >+ for (unsigned i = numDefined; i < usedVectorLength; ++i) { >+ if (i > m_butterfly->vectorLength()) >+ break; >+ double v = butterfly()->contiguousDouble()[i]; >+ if (v != v) >+ continue; >+ tree.abstractor().m_nodes[numDefined].value = JSValue(JSValue::EncodeAsDouble, v); >+ tree.insert(numDefined); >+ ++numDefined; >+ } >+ break; >+ >+ default: >+ for (; numDefined < usedVectorLength; ++numDefined) { >+ if (numDefined > m_butterfly->vectorLength()) >+ break; >+ JSValue v = indexingData<indexingType>()[numDefined].get(); >+ if (!v || v.isUndefined()) >+ break; >+ tree.abstractor().m_nodes[numDefined].value = v; >+ tree.insert(numDefined); >+ } >+ for (unsigned i = numDefined; i < usedVectorLength; ++i) { >+ if (i > m_butterfly->vectorLength()) >+ break; >+ JSValue v = indexingData<indexingType>()[i].get(); >+ if (v) { >+ if (v.isUndefined()) >+ ++numUndefined; >+ else { >+ tree.abstractor().m_nodes[numDefined].value = v; >+ tree.insert(numDefined); >+ ++numDefined; >+ } > } > } >+ break; > } > > unsigned newUsedVectorLength = numDefined + numUndefined; >@@ -1127,16 +1426,31 @@ void JSArray::sortVector(ExecState* exec > iter.start_iter_least(tree); > JSGlobalData& globalData = exec->globalData(); > for (unsigned i = 0; i < elementsToExtractThreshold; ++i) { >- indexingData<indexingType>()[i].set(globalData, this, tree.abstractor().m_nodes[*iter].value); >+ if (indexingType == ArrayWithDouble) >+ butterfly()->contiguousDouble()[i] = tree.abstractor().m_nodes[*iter].value.asNumber(); >+ else >+ indexingData<indexingType>()[i].set(globalData, this, tree.abstractor().m_nodes[*iter].value); > ++iter; > } > // Put undefined values back in. >- for (unsigned i = elementsToExtractThreshold; i < undefinedElementsThreshold; ++i) >- indexingData<indexingType>()[i].setUndefined(); >+ switch (indexingType) { >+ case ArrayWithInt32: >+ case ArrayWithDouble: >+ ASSERT(elementsToExtractThreshold == undefinedElementsThreshold); >+ break; >+ >+ default: >+ for (unsigned i = elementsToExtractThreshold; i < undefinedElementsThreshold; ++i) >+ indexingData<indexingType>()[i].setUndefined(); >+ } > > // Ensure that unused values in the vector are zeroed out. >- for (unsigned i = undefinedElementsThreshold; i < clearElementsThreshold; ++i) >- indexingData<indexingType>()[i].clear(); >+ for (unsigned i = undefinedElementsThreshold; i < clearElementsThreshold; ++i) { >+ if (indexingType == ArrayWithDouble) >+ butterfly()->contiguousDouble()[i] = 0.0 / 0.0; >+ else >+ indexingData<indexingType>()[i].clear(); >+ } > > if (hasArrayStorage(indexingType)) > arrayStorage()->m_numValuesInVector = newUsedVectorLength; >@@ -1150,6 +1464,14 @@ void JSArray::sort(ExecState* exec, JSVa > case ArrayClass: > 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 +1495,24 @@ void JSArray::fillArgList(ExecState* exe > case ArrayClass: > return; > >+ 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 +1551,25 @@ void JSArray::copyToArguments(ExecState* > case ArrayClass: > return; > >+ 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 +1607,40 @@ void JSArray::compactForSorting(unsigned > 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 +1655,23 @@ void JSArray::compactForSorting(unsigned > 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] = 0.0 / 0.0; >+ else >+ indexingData<indexingType>()[i].clear(); >+ } > > if (hasArrayStorage(indexingType)) > arrayStorage()->m_numValuesInVector = newRelevantLength; >Index: Source/JavaScriptCore/runtime/JSArray.h >=================================================================== >--- Source/JavaScriptCore/runtime/JSArray.h (revision 132745) >+++ Source/JavaScriptCore/runtime/JSArray.h (working copy) >@@ -162,7 +162,7 @@ namespace JSC { > 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 @@ namespace JSC { > 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,9 +201,19 @@ namespace JSC { > 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] = 0.0 / 0.0; >+ } > } else { > ASSERT( > structure->indexingType() == ArrayWithSlowPutArrayStorage >@@ -221,8 +232,13 @@ namespace JSC { > 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: Source/JavaScriptCore/runtime/JSGlobalObject.cpp >=================================================================== >--- Source/JavaScriptCore/runtime/JSGlobalObject.cpp (revision 132745) >+++ Source/JavaScriptCore/runtime/JSGlobalObject.cpp (working copy) >@@ -229,9 +229,16 @@ void JSGlobalObject::reset(JSValue proto > 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()))); >@@ -359,7 +366,9 @@ inline bool hasBrokenIndexing(JSObject* > { > // 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) >@@ -411,8 +420,8 @@ void JSGlobalObject::haveABadTime(JSGlob > > // 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(SlowPutArrayStorageShape)); > > // Make sure that all objects that have indexed storage switch to the slow kind of > // indexed storage. >@@ -487,9 +496,10 @@ void JSGlobalObject::visitChildren(JSCel > 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: Source/JavaScriptCore/runtime/JSGlobalObject.h >=================================================================== >--- Source/JavaScriptCore/runtime/JSGlobalObject.h (revision 132745) >+++ Source/JavaScriptCore/runtime/JSGlobalObject.h (working copy) >@@ -22,6 +22,7 @@ > #ifndef JSGlobalObject_h > #define JSGlobalObject_h > >+#include "ArrayAllocationProfile.h" > #include "JSArray.h" > #include "JSGlobalData.h" > #include "JSSegmentedVariableObject.h" >@@ -125,9 +126,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; >@@ -267,10 +271,21 @@ 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)); >+ } >+ > Structure* booleanObjectStructure() const { return m_booleanObjectStructure.get(); } > Structure* callbackConstructorStructure() const { return m_callbackConstructorStructure.get(); } > Structure* callbackFunctionStructure() const { return m_callbackFunctionStructure.get(); } >@@ -480,34 +495,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: Source/JavaScriptCore/runtime/JSObject.cpp >=================================================================== >--- Source/JavaScriptCore/runtime/JSObject.cpp (revision 132745) >+++ Source/JavaScriptCore/runtime/JSObject.cpp (working copy) >@@ -129,7 +129,16 @@ ALWAYS_INLINE void JSObject::copyButterf > 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::copyButterf > break; > } > >- while (count--) >- (currentTarget++)->setWithoutWriteBarrier((currentSource++)->get()); >+ memcpy(currentTarget, currentSource, count * sizeof(EncodedJSValue)); > } > > m_butterfly = newButterfly; >@@ -272,8 +280,10 @@ bool JSObject::getOwnPropertySlotByIndex > > 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 > 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, > 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, > 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::enterDictionaryI > 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()); >@@ -534,7 +600,7 @@ void JSObject::notifyPresenceOfIndexedAc > globalObject()->haveABadTime(globalData); > } > >-WriteBarrier<Unknown>* JSObject::createInitialContiguous(JSGlobalData& globalData, unsigned length) >+Butterfly* JSObject::createInitialIndexedStorage(JSGlobalData& globalData, unsigned length, size_t elementSize) > { > ASSERT(length < MAX_ARRAY_INDEX); > IndexingType oldType = structure()->indexingType(); >@@ -544,9 +610,41 @@ WriteBarrier<Unknown>* JSObject::createI > unsigned vectorLength = std::max(length, BASE_VECTOR_LEN); > Butterfly* newButterfly = m_butterfly->growArrayRight( > globalData, structure(), structure()->outOfLineCapacity(), false, 0, >- sizeof(EncodedJSValue) * vectorLength); >+ elementSize * vectorLength); > newButterfly->setPublicLength(length); > newButterfly->setVectorLength(vectorLength); >+ return newButterfly; >+} >+ >+Butterfly* JSObject::createInitialUndecided(JSGlobalData& globalData, unsigned length) >+{ >+ Butterfly* newButterfly = createInitialIndexedStorage(globalData, length, sizeof(EncodedJSValue)); >+ Structure* newStructure = Structure::nonPropertyTransition(globalData, structure(), AllocateUndecided); >+ setButterfly(globalData, newButterfly, newStructure); >+ return newButterfly; >+} >+ >+WriteBarrier<Unknown>* JSObject::createInitialInt32(JSGlobalData& globalData, unsigned length) >+{ >+ Butterfly* newButterfly = createInitialIndexedStorage(globalData, length, sizeof(EncodedJSValue)); >+ Structure* newStructure = Structure::nonPropertyTransition(globalData, structure(), AllocateInt32); >+ setButterfly(globalData, newButterfly, newStructure); >+ return newButterfly->contiguousInt32(); >+} >+ >+double* JSObject::createInitialDouble(JSGlobalData& globalData, unsigned length) >+{ >+ Butterfly* newButterfly = createInitialIndexedStorage(globalData, length, sizeof(double)); >+ for (unsigned i = newButterfly->vectorLength(); i--;) >+ newButterfly->contiguousDouble()[i] = 0.0 / 0.0; >+ Structure* newStructure = Structure::nonPropertyTransition(globalData, structure(), AllocateDouble); >+ setButterfly(globalData, newButterfly, newStructure); >+ return newButterfly->contiguousDouble(); >+} >+ >+WriteBarrier<Unknown>* JSObject::createInitialContiguous(JSGlobalData& globalData, unsigned length) >+{ >+ Butterfly* newButterfly = createInitialIndexedStorage(globalData, length, sizeof(EncodedJSValue)); > Structure* newStructure = Structure::nonPropertyTransition(globalData, structure(), AllocateContiguous); > setButterfly(globalData, newButterfly, newStructure); > return newButterfly->contiguous(); >@@ -577,10 +675,29 @@ ArrayStorage* JSObject::createInitialArr > return createArrayStorage(globalData, 0, BASE_VECTOR_LEN); > } > >-ArrayStorage* JSObject::convertContiguousToArrayStorage(JSGlobalData& globalData, NonPropertyTransition transition, unsigned neededLength) >+WriteBarrier<Unknown>* JSObject::convertUndecidedToInt32(JSGlobalData& globalData) >+{ >+ ASSERT(hasUndecided(structure()->indexingType())); >+ setStructure(globalData, Structure::nonPropertyTransition(globalData, structure(), AllocateInt32)); >+ return m_butterfly->contiguousInt32(); >+} >+ >+double* JSObject::convertUndecidedToDouble(JSGlobalData& globalData) >+{ >+ ASSERT(hasUndecided(structure()->indexingType())); >+ setStructure(globalData, Structure::nonPropertyTransition(globalData, structure(), AllocateDouble)); >+ return m_butterfly->contiguousDouble(); >+} >+ >+WriteBarrier<Unknown>* JSObject::convertUndecidedToContiguous(JSGlobalData& globalData) >+{ >+ ASSERT(hasUndecided(structure()->indexingType())); >+ setStructure(globalData, Structure::nonPropertyTransition(globalData, structure(), AllocateContiguous)); >+ return m_butterfly->contiguous(); >+} >+ >+ArrayStorage* JSObject::constructConvertedArrayStorageWithoutCopyingElements(JSGlobalData& globalData, unsigned neededLength) > { >- ASSERT(hasContiguous(structure()->indexingType())); >- > unsigned publicLength = m_butterfly->publicLength(); > unsigned propertyCapacity = structure()->outOfLineCapacity(); > unsigned propertySize = structure()->outOfLineSize(); >@@ -599,7 +716,66 @@ ArrayStorage* JSObject::convertContiguou > newStorage->m_sparseMap.clear(); > newStorage->m_indexBias = 0; > newStorage->m_numValuesInVector = 0; >- for (unsigned i = publicLength; i--;) { >+ >+ return newStorage; >+} >+ >+ArrayStorage* JSObject::convertUndecidedToArrayStorage(JSGlobalData& globalData, NonPropertyTransition transition, unsigned neededLength) >+{ >+ ASSERT(hasUndecided(structure()->indexingType())); >+ >+ ArrayStorage* storage = constructConvertedArrayStorageWithoutCopyingElements(globalData, neededLength); >+ // No need to copy elements. >+ >+ Structure* newStructure = Structure::nonPropertyTransition(globalData, structure(), transition); >+ setButterfly(globalData, storage->butterfly(), newStructure); >+ return storage; >+} >+ >+ArrayStorage* JSObject::convertUndecidedToArrayStorage(JSGlobalData& globalData, NonPropertyTransition transition) >+{ >+ return convertUndecidedToArrayStorage(globalData, transition, m_butterfly->vectorLength()); >+} >+ >+ArrayStorage* JSObject::convertUndecidedToArrayStorage(JSGlobalData& globalData) >+{ >+ return convertUndecidedToArrayStorage(globalData, structure()->suggestedArrayStorageTransition()); >+} >+ >+double* JSObject::convertInt32ToDouble(JSGlobalData& globalData) >+{ >+ ASSERT(hasInt32(structure()->indexingType())); >+ >+ for (unsigned i = m_butterfly->vectorLength(); i--;) { >+ WriteBarrier<Unknown>* current = &m_butterfly->contiguousInt32()[i]; >+ double* currentAsDouble = bitwise_cast<double*>(current); >+ JSValue v = current->get(); >+ if (!v) { >+ *currentAsDouble = 0.0 / 0.0; >+ continue; >+ } >+ ASSERT(v.isInt32()); >+ *currentAsDouble = v.asInt32(); >+ } >+ >+ setStructure(globalData, Structure::nonPropertyTransition(globalData, structure(), AllocateDouble)); >+ return m_butterfly->contiguousDouble(); >+} >+ >+WriteBarrier<Unknown>* JSObject::convertInt32ToContiguous(JSGlobalData& globalData) >+{ >+ ASSERT(hasInt32(structure()->indexingType())); >+ >+ setStructure(globalData, Structure::nonPropertyTransition(globalData, structure(), AllocateContiguous)); >+ return m_butterfly->contiguous(); >+} >+ >+ArrayStorage* JSObject::convertInt32ToArrayStorage(JSGlobalData& globalData, NonPropertyTransition transition, unsigned neededLength) >+{ >+ ASSERT(hasInt32(structure()->indexingType())); >+ >+ ArrayStorage* newStorage = constructConvertedArrayStorageWithoutCopyingElements(globalData, neededLength); >+ for (unsigned i = m_butterfly->publicLength(); i--;) { > JSValue v = m_butterfly->contiguous()[i].get(); > if (!v) > continue; >@@ -608,7 +784,82 @@ ArrayStorage* JSObject::convertContiguou > } > > Structure* newStructure = Structure::nonPropertyTransition(globalData, structure(), transition); >- setButterfly(globalData, newButterfly, newStructure); >+ setButterfly(globalData, newStorage->butterfly(), newStructure); >+ return newStorage; >+} >+ >+ArrayStorage* JSObject::convertInt32ToArrayStorage(JSGlobalData& globalData, NonPropertyTransition transition) >+{ >+ return convertInt32ToArrayStorage(globalData, transition, m_butterfly->vectorLength()); >+} >+ >+ArrayStorage* JSObject::convertInt32ToArrayStorage(JSGlobalData& globalData) >+{ >+ return convertInt32ToArrayStorage(globalData, structure()->suggestedArrayStorageTransition()); >+} >+ >+WriteBarrier<Unknown>* JSObject::convertDoubleToContiguous(JSGlobalData& globalData) >+{ >+ ASSERT(hasDouble(structure()->indexingType())); >+ >+ for (unsigned i = m_butterfly->vectorLength(); i--;) { >+ double* current = &m_butterfly->contiguousDouble()[i]; >+ WriteBarrier<Unknown>* currentAsValue = bitwise_cast<WriteBarrier<Unknown>*>(current); >+ double value = *current; >+ if (value != value) { >+ currentAsValue->clear(); >+ continue; >+ } >+ currentAsValue->setWithoutWriteBarrier(JSValue(JSValue::EncodeAsDouble, value)); >+ } >+ >+ setStructure(globalData, Structure::nonPropertyTransition(globalData, structure(), AllocateContiguous)); >+ return m_butterfly->contiguous(); >+} >+ >+ArrayStorage* JSObject::convertDoubleToArrayStorage(JSGlobalData& globalData, NonPropertyTransition transition, unsigned neededLength) >+{ >+ ASSERT(hasDouble(structure()->indexingType())); >+ >+ ArrayStorage* newStorage = constructConvertedArrayStorageWithoutCopyingElements(globalData, neededLength); >+ for (unsigned i = m_butterfly->publicLength(); i--;) { >+ double value = m_butterfly->contiguousDouble()[i]; >+ if (value != value) >+ continue; >+ newStorage->m_vector[i].setWithoutWriteBarrier(JSValue(JSValue::EncodeAsDouble, value)); >+ newStorage->m_numValuesInVector++; >+ } >+ >+ Structure* newStructure = Structure::nonPropertyTransition(globalData, structure(), transition); >+ setButterfly(globalData, newStorage->butterfly(), newStructure); >+ return newStorage; >+} >+ >+ArrayStorage* JSObject::convertDoubleToArrayStorage(JSGlobalData& globalData, NonPropertyTransition transition) >+{ >+ return convertDoubleToArrayStorage(globalData, transition, m_butterfly->vectorLength()); >+} >+ >+ArrayStorage* JSObject::convertDoubleToArrayStorage(JSGlobalData& globalData) >+{ >+ return convertDoubleToArrayStorage(globalData, structure()->suggestedArrayStorageTransition()); >+} >+ >+ArrayStorage* JSObject::convertContiguousToArrayStorage(JSGlobalData& globalData, NonPropertyTransition transition, unsigned neededLength) >+{ >+ ASSERT(hasContiguous(structure()->indexingType())); >+ >+ ArrayStorage* newStorage = constructConvertedArrayStorageWithoutCopyingElements(globalData, neededLength); >+ for (unsigned i = m_butterfly->publicLength(); i--;) { >+ JSValue v = m_butterfly->contiguous()[i].get(); >+ if (!v) >+ continue; >+ newStorage->m_vector[i].setWithoutWriteBarrier(v); >+ newStorage->m_numValuesInVector++; >+ } >+ >+ Structure* newStructure = Structure::nonPropertyTransition(globalData, structure(), transition); >+ setButterfly(globalData, newStorage->butterfly(), newStructure); > return newStorage; > } > >@@ -622,48 +873,146 @@ ArrayStorage* JSObject::convertContiguou > return convertContiguousToArrayStorage(globalData, structure()->suggestedArrayStorageTransition()); > } > >-WriteBarrier<Unknown>* JSObject::ensureContiguousSlow(JSGlobalData& globalData) >+void JSObject::convertUndecidedForValue(JSGlobalData& globalData, JSValue value) >+{ >+ if (value.isInt32()) >+ convertUndecidedToInt32(globalData); >+ else if (value.isDouble()) >+ convertUndecidedToDouble(globalData); >+ else >+ convertUndecidedToContiguous(globalData); >+} >+ >+void JSObject::convertInt32ForValue(JSGlobalData& globalData, JSValue value) >+{ >+ ASSERT(!value.isInt32()); >+ if (value.isDouble()) >+ convertInt32ToDouble(globalData); >+ else >+ convertInt32ToContiguous(globalData); >+} >+ >+void JSObject::setIndexQuicklyToUndecided(JSGlobalData& globalData, unsigned index, JSValue value) >+{ >+ ASSERT(index < m_butterfly->publicLength()); >+ ASSERT(index < m_butterfly->vectorLength()); >+ convertUndecidedForValue(globalData, value); >+ setIndexQuickly(globalData, index, value); >+} >+ >+void JSObject::convertInt32ToDoubleOrContiguousWhilePerformingSetIndex(JSGlobalData& globalData, unsigned index, JSValue value) >+{ >+ ASSERT(!value.isInt32()); >+ convertInt32ForValue(globalData, value); >+ setIndexQuickly(globalData, index, value); >+} >+ >+void JSObject::convertDoubleToContiguousWhilePerformingSetIndex(JSGlobalData& globalData, unsigned index, JSValue value) >+{ >+ ASSERT(!value.isNumber()); >+ convertDoubleToContiguous(globalData); >+ setIndexQuickly(globalData, index, value); >+} >+ >+WriteBarrier<Unknown>* JSObject::ensureInt32Slow(JSGlobalData& globalData) > { > switch (structure()->indexingType()) { > case ALL_BLANK_INDEXING_TYPES: > if (UNLIKELY(indexingShouldBeSparse() || structure()->needsSlowPutIndexing())) > return 0; >- return createInitialContiguous(globalData, 0); >+ return createInitialInt32(globalData, 0); >+ >+ case ALL_UNDECIDED_INDEXING_TYPES: >+ return convertUndecidedToInt32(globalData); >+ >+ case ALL_DOUBLE_INDEXING_TYPES: >+ case ALL_CONTIGUOUS_INDEXING_TYPES: >+ case ALL_ARRAY_STORAGE_INDEXING_TYPES: >+ return 0; > > default: >- ASSERT_NOT_REACHED(); >+ CRASH(); > return 0; > } > } > >-ArrayStorage* JSObject::ensureArrayStorageSlow(JSGlobalData& globalData) >+double* JSObject::ensureDoubleSlow(JSGlobalData& globalData) > { > switch (structure()->indexingType()) { >+ case ALL_BLANK_INDEXING_TYPES: >+ if (UNLIKELY(indexingShouldBeSparse() || structure()->needsSlowPutIndexing())) >+ return 0; >+ return createInitialDouble(globalData, 0); >+ >+ case ALL_UNDECIDED_INDEXING_TYPES: >+ return convertUndecidedToDouble(globalData); >+ >+ case ALL_INT32_INDEXING_TYPES: >+ return convertInt32ToDouble(globalData); >+ > case ALL_CONTIGUOUS_INDEXING_TYPES: >- ASSERT(!indexingShouldBeSparse()); >- ASSERT(!structure()->needsSlowPutIndexing()); >- return convertContiguousToArrayStorage(globalData); >+ case ALL_ARRAY_STORAGE_INDEXING_TYPES: >+ return 0; > >+ default: >+ CRASH(); >+ return 0; >+ } >+} >+ >+WriteBarrier<Unknown>* JSObject::ensureContiguousSlow(JSGlobalData& globalData) >+{ >+ switch (structure()->indexingType()) { > case ALL_BLANK_INDEXING_TYPES: >- if (UNLIKELY(indexingShouldBeSparse())) >- return ensureArrayStorageExistsAndEnterDictionaryIndexingMode(globalData); >- return createInitialArrayStorage(globalData); >+ if (UNLIKELY(indexingShouldBeSparse() || structure()->needsSlowPutIndexing())) >+ return 0; >+ return createInitialContiguous(globalData, 0); >+ >+ case ALL_UNDECIDED_INDEXING_TYPES: >+ return convertUndecidedToContiguous(globalData); >+ >+ case ALL_INT32_INDEXING_TYPES: >+ return convertInt32ToContiguous(globalData); >+ >+ case ALL_DOUBLE_INDEXING_TYPES: >+ return convertDoubleToContiguous(globalData); >+ >+ case ALL_ARRAY_STORAGE_INDEXING_TYPES: >+ return 0; > > default: >- ASSERT_NOT_REACHED(); >+ CRASH(); > return 0; > } > } > >-Butterfly* JSObject::ensureIndexedStorageSlow(JSGlobalData& globalData) >+ArrayStorage* JSObject::ensureArrayStorageSlow(JSGlobalData& globalData) > { > switch (structure()->indexingType()) { > case ALL_BLANK_INDEXING_TYPES: >- if (UNLIKELY(structure()->needsSlowPutIndexing())) >- return createInitialArrayStorage(globalData)->butterfly(); > if (UNLIKELY(indexingShouldBeSparse())) >- return ensureArrayStorageExistsAndEnterDictionaryIndexingMode(globalData)->butterfly(); >- return Butterfly::fromContiguous(createInitialContiguous(globalData, 0)); >+ return ensureArrayStorageExistsAndEnterDictionaryIndexingMode(globalData); >+ return createInitialArrayStorage(globalData); >+ >+ case ALL_UNDECIDED_INDEXING_TYPES: >+ ASSERT(!indexingShouldBeSparse()); >+ ASSERT(!structure()->needsSlowPutIndexing()); >+ return convertUndecidedToArrayStorage(globalData); >+ >+ case ALL_INT32_INDEXING_TYPES: >+ ASSERT(!indexingShouldBeSparse()); >+ ASSERT(!structure()->needsSlowPutIndexing()); >+ return convertInt32ToArrayStorage(globalData); >+ >+ case ALL_DOUBLE_INDEXING_TYPES: >+ ASSERT(!indexingShouldBeSparse()); >+ ASSERT(!structure()->needsSlowPutIndexing()); >+ return convertDoubleToArrayStorage(globalData); >+ >+ case ALL_CONTIGUOUS_INDEXING_TYPES: >+ ASSERT(!indexingShouldBeSparse()); >+ ASSERT(!structure()->needsSlowPutIndexing()); >+ return convertContiguousToArrayStorage(globalData); > > default: > ASSERT_NOT_REACHED(); >@@ -674,13 +1023,6 @@ Butterfly* JSObject::ensureIndexedStorag > ArrayStorage* JSObject::ensureArrayStorageExistsAndEnterDictionaryIndexingMode(JSGlobalData& globalData) > { > switch (structure()->indexingType()) { >- case ALL_CONTIGUOUS_INDEXING_TYPES: >- // FIXME: This could be made way more efficient, if we cared. >- return enterDictionaryIndexingModeWhenArrayStorageAlreadyExists(globalData, convertContiguousToArrayStorage(globalData)); >- >- case ALL_ARRAY_STORAGE_INDEXING_TYPES: >- return enterDictionaryIndexingModeWhenArrayStorageAlreadyExists(globalData, m_butterfly->arrayStorage()); >- > case ALL_BLANK_INDEXING_TYPES: { > createArrayStorage(globalData, 0, 0); > SparseArrayValueMap* map = allocateSparseIndexMap(globalData); >@@ -688,8 +1030,23 @@ ArrayStorage* JSObject::ensureArrayStora > return arrayStorage(); > } > >+ case ALL_UNDECIDED_INDEXING_TYPES: >+ return enterDictionaryIndexingModeWhenArrayStorageAlreadyExists(globalData, convertUndecidedToArrayStorage(globalData)); >+ >+ case ALL_INT32_INDEXING_TYPES: >+ return enterDictionaryIndexingModeWhenArrayStorageAlreadyExists(globalData, convertInt32ToArrayStorage(globalData)); >+ >+ case ALL_DOUBLE_INDEXING_TYPES: >+ return enterDictionaryIndexingModeWhenArrayStorageAlreadyExists(globalData, convertDoubleToArrayStorage(globalData)); >+ >+ case ALL_CONTIGUOUS_INDEXING_TYPES: >+ return enterDictionaryIndexingModeWhenArrayStorageAlreadyExists(globalData, convertContiguousToArrayStorage(globalData)); >+ >+ case ALL_ARRAY_STORAGE_INDEXING_TYPES: >+ return enterDictionaryIndexingModeWhenArrayStorageAlreadyExists(globalData, m_butterfly->arrayStorage()); >+ > default: >- ASSERT_NOT_REACHED(); >+ CRASH(); > return 0; > } > } >@@ -697,10 +1054,21 @@ ArrayStorage* JSObject::ensureArrayStora > void JSObject::switchToSlowPutArrayStorage(JSGlobalData& globalData) > { > switch (structure()->indexingType()) { >- case ALL_CONTIGUOUS_INDEXING_TYPES: { >+ case ALL_UNDECIDED_INDEXING_TYPES: >+ convertUndecidedToArrayStorage(globalData, AllocateSlowPutArrayStorage); >+ break; >+ >+ case ALL_INT32_INDEXING_TYPES: >+ convertInt32ToArrayStorage(globalData, AllocateSlowPutArrayStorage); >+ break; >+ >+ case ALL_DOUBLE_INDEXING_TYPES: >+ convertDoubleToArrayStorage(globalData, AllocateSlowPutArrayStorage); >+ break; >+ >+ case ALL_CONTIGUOUS_INDEXING_TYPES: > convertContiguousToArrayStorage(globalData, AllocateSlowPutArrayStorage); > break; >- } > > case NonArrayWithArrayStorage: > case ArrayWithArrayStorage: { >@@ -710,7 +1078,7 @@ void JSObject::switchToSlowPutArrayStora > } > > default: >- ASSERT_NOT_REACHED(); >+ CRASH(); > break; > } > } >@@ -877,8 +1245,10 @@ bool JSObject::deletePropertyByIndex(JSC > > switch (thisObject->structure()->indexingType()) { > case ALL_BLANK_INDEXING_TYPES: >+ case ALL_UNDECIDED_INDEXING_TYPES: > return true; > >+ case ALL_INT32_INDEXING_TYPES: > case ALL_CONTIGUOUS_INDEXING_TYPES: { > Butterfly* butterfly = thisObject->m_butterfly; > if (i >= butterfly->vectorLength()) >@@ -887,6 +1257,14 @@ bool JSObject::deletePropertyByIndex(JSC > return true; > } > >+ case ALL_DOUBLE_INDEXING_TYPES: { >+ Butterfly* butterfly = thisObject->m_butterfly; >+ if (i >= butterfly->vectorLength()) >+ return true; >+ butterfly->contiguousDouble()[i] = 0.0 / 0.0; >+ return true; >+ } >+ > case ALL_ARRAY_STORAGE_INDEXING_TYPES: { > ArrayStorage* storage = thisObject->m_butterfly->arrayStorage(); > >@@ -1060,6 +1438,7 @@ void JSObject::getOwnPropertyNames(JSObj > case ALL_BLANK_INDEXING_TYPES: > break; > >+ case ALL_INT32_INDEXING_TYPES: > case ALL_CONTIGUOUS_INDEXING_TYPES: { > Butterfly* butterfly = object->m_butterfly; > unsigned usedLength = butterfly->publicLength(); >@@ -1071,6 +1450,18 @@ void JSObject::getOwnPropertyNames(JSObj > break; > } > >+ case ALL_DOUBLE_INDEXING_TYPES: { >+ Butterfly* butterfly = object->m_butterfly; >+ unsigned usedLength = butterfly->publicLength(); >+ for (unsigned i = 0; i < usedLength; ++i) { >+ double value = butterfly->contiguousDouble()[i]; >+ if (value != value) >+ continue; >+ propertyNames.add(Identifier::from(exec, i)); >+ } >+ break; >+ } >+ > case ALL_ARRAY_STORAGE_INDEXING_TYPES: { > ArrayStorage* storage = object->m_butterfly->arrayStorage(); > >@@ -1460,9 +1851,10 @@ bool JSObject::attemptToInterceptPutByIn > return asObject(prototypeValue)->attemptToInterceptPutByIndexOnHoleForPrototype(exec, this, i, value, shouldThrow); > } > >-void JSObject::putByIndexBeyondVectorLengthContiguousWithoutAttributes(ExecState* exec, unsigned i, JSValue value) >+template<IndexingType indexingShape> >+void JSObject::putByIndexBeyondVectorLengthWithoutAttributes(ExecState* exec, unsigned i, JSValue value) > { >- ASSERT(hasContiguous(structure()->indexingType())); >+ ASSERT((structure()->indexingType() & IndexingShapeMask) == indexingShape); > ASSERT(!indexingShouldBeSparse()); > > // For us to get here, the index is either greater than the public length, or greater than >@@ -1473,9 +1865,9 @@ void JSObject::putByIndexBeyondVectorLen > > if (i >= MAX_ARRAY_INDEX - 1 > || (i >= MIN_SPARSE_ARRAY_INDEX >- && !isDenseEnoughForVector(i, countElementsInContiguous(m_butterfly)))) { >+ && !isDenseEnoughForVector(i, countElements<indexingShape>(m_butterfly)))) { > ASSERT(i <= MAX_ARRAY_INDEX); >- convertContiguousToArrayStorage(globalData, AllocateArrayStorage); >+ ensureArrayStorageSlow(globalData); > SparseArrayValueMap* map = allocateSparseIndexMap(globalData); > map->putEntry(exec, this, i, value, false); > ASSERT(i >= arrayStorage()->length()); >@@ -1483,10 +1875,30 @@ void JSObject::putByIndexBeyondVectorLen > return; > } > >- ensureContiguousLength(globalData, i + 1); >+ ensureLength(globalData, i + 1); > > ASSERT(i < m_butterfly->vectorLength()); >- m_butterfly->contiguous()[i].set(globalData, this, value); >+ switch (indexingShape) { >+ case Int32Shape: >+ ASSERT(value.isInt32()); >+ m_butterfly->contiguousInt32()[i].setWithoutWriteBarrier(value); >+ break; >+ >+ case DoubleShape: { >+ ASSERT(value.isNumber()); >+ double valueAsDouble = value.asNumber(); >+ ASSERT(valueAsDouble == valueAsDouble); >+ m_butterfly->contiguousDouble()[i] = valueAsDouble; >+ break; >+ } >+ >+ case ContiguousShape: >+ m_butterfly->contiguous()[i].set(globalData, this, value); >+ break; >+ >+ default: >+ CRASH(); >+ } > } > > void JSObject::putByIndexBeyondVectorLengthWithArrayStorage(ExecState* exec, unsigned i, JSValue value, bool shouldThrow, ArrayStorage* storage) >@@ -1592,8 +2004,23 @@ void JSObject::putByIndexBeyondVectorLen > break; > } > >+ case ALL_UNDECIDED_INDEXING_TYPES: { >+ CRASH(); >+ break; >+ } >+ >+ case ALL_INT32_INDEXING_TYPES: { >+ putByIndexBeyondVectorLengthWithoutAttributes<Int32Shape>(exec, i, value); >+ break; >+ } >+ >+ case ALL_DOUBLE_INDEXING_TYPES: { >+ putByIndexBeyondVectorLengthWithoutAttributes<DoubleShape>(exec, i, value); >+ break; >+ } >+ > case ALL_CONTIGUOUS_INDEXING_TYPES: { >- putByIndexBeyondVectorLengthContiguousWithoutAttributes(exec, i, value); >+ putByIndexBeyondVectorLengthWithoutAttributes<ContiguousShape>(exec, i, value); > break; > } > >@@ -1724,12 +2151,36 @@ bool JSObject::putDirectIndexBeyondVecto > return true; > } > >+ case ALL_UNDECIDED_INDEXING_TYPES: { >+ convertUndecidedForValue(exec->globalData(), value); >+ // Reloop. >+ return putDirectIndex(exec, i, value, attributes, mode); >+ } >+ >+ case ALL_INT32_INDEXING_TYPES: { >+ if (attributes & (ReadOnly | Accessor)) { >+ return putDirectIndexBeyondVectorLengthWithArrayStorage( >+ exec, i, value, attributes, mode, convertInt32ToArrayStorage(globalData)); >+ } >+ putByIndexBeyondVectorLengthWithoutAttributes<Int32Shape>(exec, i, value); >+ return true; >+ } >+ >+ case ALL_DOUBLE_INDEXING_TYPES: { >+ if (attributes & (ReadOnly | Accessor)) { >+ return putDirectIndexBeyondVectorLengthWithArrayStorage( >+ exec, i, value, attributes, mode, convertDoubleToArrayStorage(globalData)); >+ } >+ putByIndexBeyondVectorLengthWithoutAttributes<DoubleShape>(exec, i, value); >+ return true; >+ } >+ > case ALL_CONTIGUOUS_INDEXING_TYPES: { > if (attributes & (ReadOnly | Accessor)) { > return putDirectIndexBeyondVectorLengthWithArrayStorage( > exec, i, value, attributes, mode, convertContiguousToArrayStorage(globalData)); > } >- putByIndexBeyondVectorLengthContiguousWithoutAttributes(exec, i, value); >+ putByIndexBeyondVectorLengthWithoutAttributes<ContiguousShape>(exec, i, value); > return true; > } > >@@ -1769,33 +2220,65 @@ ALWAYS_INLINE unsigned JSObject::getNewV > unsigned vectorLength; > unsigned length; > >- switch (structure()->indexingType()) { >- case ALL_BLANK_INDEXING_TYPES: >- vectorLength = 0; >- length = 0; >- break; >- case ALL_CONTIGUOUS_INDEXING_TYPES: >- case ALL_ARRAY_STORAGE_INDEXING_TYPES: >+ if (hasIndexedProperties(structure()->indexingType())) { > vectorLength = m_butterfly->vectorLength(); > length = m_butterfly->publicLength(); >- break; >- default: >- CRASH(); >- return 0; >+ } else { >+ vectorLength = 0; >+ length = 0; > } >+ > return getNewVectorLength(vectorLength, length, desiredLength); > } > >-unsigned JSObject::countElementsInContiguous(Butterfly* butterfly) >+template<IndexingType indexingShape> >+unsigned JSObject::countElements(Butterfly* butterfly) > { > unsigned numValues = 0; > for (unsigned i = butterfly->publicLength(); i--;) { >- if (butterfly->contiguous()[i]) >- numValues++; >+ switch (indexingShape) { >+ case Int32Shape: >+ case ContiguousShape: >+ if (butterfly->contiguous()[i]) >+ numValues++; >+ break; >+ >+ case DoubleShape: { >+ double value = butterfly->contiguousDouble()[i]; >+ if (value == value) >+ numValues++; >+ break; >+ } >+ >+ default: >+ CRASH(); >+ } > } > return numValues; > } > >+unsigned JSObject::countElements() >+{ >+ switch (structure()->indexingType()) { >+ case ALL_BLANK_INDEXING_TYPES: >+ case ALL_UNDECIDED_INDEXING_TYPES: >+ return 0; >+ >+ case ALL_INT32_INDEXING_TYPES: >+ return countElements<Int32Shape>(m_butterfly); >+ >+ case ALL_DOUBLE_INDEXING_TYPES: >+ return countElements<DoubleShape>(m_butterfly); >+ >+ case ALL_CONTIGUOUS_INDEXING_TYPES: >+ return countElements<ContiguousShape>(m_butterfly); >+ >+ default: >+ CRASH(); >+ return 0; >+ } >+} >+ > bool JSObject::increaseVectorLength(JSGlobalData& globalData, unsigned newLength) > { > // This function leaves the array in an internally inconsistent state, because it does not move any values from sparse value map >@@ -1839,19 +2322,24 @@ bool JSObject::increaseVectorLength(JSGl > return true; > } > >-void JSObject::ensureContiguousLengthSlow(JSGlobalData& globalData, unsigned length) >+void JSObject::ensureLengthSlow(JSGlobalData& globalData, unsigned length) > { > ASSERT(length < MAX_ARRAY_INDEX); >- ASSERT(hasContiguous(structure()->indexingType())); >+ ASSERT(hasContiguous(structure()->indexingType()) || hasInt32(structure()->indexingType()) || hasDouble(structure()->indexingType())); > ASSERT(length > m_butterfly->vectorLength()); > > unsigned newVectorLength = std::min( > length << 1, > MAX_STORAGE_VECTOR_LENGTH); >+ unsigned oldVectorLength = m_butterfly->vectorLength(); > m_butterfly = m_butterfly->growArrayRight( > globalData, structure(), structure()->outOfLineCapacity(), true, >- m_butterfly->vectorLength() * sizeof(EncodedJSValue), >+ oldVectorLength * sizeof(EncodedJSValue), > newVectorLength * sizeof(EncodedJSValue)); >+ if (hasDouble(structure()->indexingType())) { >+ for (unsigned i = oldVectorLength; i < newVectorLength; ++i) >+ m_butterfly->contiguousDouble()[i] = 0.0 / 0.0; >+ } > m_butterfly->setVectorLength(newVectorLength); > } > >@@ -1881,8 +2369,10 @@ bool JSObject::getOwnPropertyDescriptor( > > switch (object->structure()->indexingType()) { > case ALL_BLANK_INDEXING_TYPES: >+ case ALL_UNDECIDED_INDEXING_TYPES: > return false; > >+ case ALL_INT32_INDEXING_TYPES: > case ALL_CONTIGUOUS_INDEXING_TYPES: { > Butterfly* butterfly = object->m_butterfly; > if (i >= butterfly->vectorLength()) >@@ -1894,6 +2384,17 @@ bool JSObject::getOwnPropertyDescriptor( > return true; > } > >+ case ALL_DOUBLE_INDEXING_TYPES: { >+ Butterfly* butterfly = object->m_butterfly; >+ if (i >= butterfly->vectorLength()) >+ return false; >+ double value = butterfly->contiguousDouble()[i]; >+ if (value != value) >+ return false; >+ descriptor.setDescriptor(JSValue(JSValue::EncodeAsDouble, value), 0); >+ return true; >+ } >+ > case ALL_ARRAY_STORAGE_INDEXING_TYPES: { > ArrayStorage* storage = object->m_butterfly->arrayStorage(); > if (i >= storage->length()) >Index: Source/JavaScriptCore/runtime/JSObject.h >=================================================================== >--- Source/JavaScriptCore/runtime/JSObject.h (revision 132745) >+++ Source/JavaScriptCore/runtime/JSObject.h (working copy) >@@ -151,30 +151,16 @@ namespace JSC { > > unsigned getArrayLength() const > { >- switch (structure()->indexingType()) { >- case ALL_BLANK_INDEXING_TYPES: >+ if (!hasIndexedProperties(structure()->indexingType())) > return 0; >- case ALL_CONTIGUOUS_INDEXING_TYPES: >- case ALL_ARRAY_STORAGE_INDEXING_TYPES: >- return m_butterfly->publicLength(); >- default: >- ASSERT_NOT_REACHED(); >- return 0; >- } >+ return m_butterfly->publicLength(); > } > > unsigned getVectorLength() > { >- switch (structure()->indexingType()) { >- case ALL_BLANK_INDEXING_TYPES: >- return 0; >- case ALL_CONTIGUOUS_INDEXING_TYPES: >- case ALL_ARRAY_STORAGE_INDEXING_TYPES: >- return m_butterfly->vectorLength(); >- default: >- ASSERT_NOT_REACHED(); >+ if (!hasIndexedProperties(structure()->indexingType())) > return 0; >- } >+ return m_butterfly->vectorLength(); > } > > JS_EXPORT_PRIVATE static void put(JSCell*, ExecState*, PropertyName, JSValue, PutPropertySlot&); >@@ -214,9 +200,19 @@ namespace JSC { > { > switch (structure()->indexingType()) { > case ALL_BLANK_INDEXING_TYPES: >+ case ALL_UNDECIDED_INDEXING_TYPES: > return false; >+ case ALL_INT32_INDEXING_TYPES: > case ALL_CONTIGUOUS_INDEXING_TYPES: > return i < m_butterfly->vectorLength() && m_butterfly->contiguous()[i]; >+ case ALL_DOUBLE_INDEXING_TYPES: { >+ if (i >= m_butterfly->vectorLength()) >+ return false; >+ double value = m_butterfly->contiguousDouble()[i]; >+ if (value != value) >+ return false; >+ return value; >+ } > case ALL_ARRAY_STORAGE_INDEXING_TYPES: > return i < m_butterfly->arrayStorage()->vectorLength() && m_butterfly->arrayStorage()->m_vector[i]; > default: >@@ -228,8 +224,11 @@ namespace JSC { > JSValue getIndexQuickly(unsigned i) > { > switch (structure()->indexingType()) { >+ case ALL_INT32_INDEXING_TYPES: > case ALL_CONTIGUOUS_INDEXING_TYPES: > return m_butterfly->contiguous()[i].get(); >+ case ALL_DOUBLE_INDEXING_TYPES: >+ return JSValue(JSValue::EncodeAsDouble, m_butterfly->contiguousDouble()[i]); > case ALL_ARRAY_STORAGE_INDEXING_TYPES: > return m_butterfly->arrayStorage()->m_vector[i].get(); > default: >@@ -243,10 +242,19 @@ namespace JSC { > switch (structure()->indexingType()) { > case ALL_BLANK_INDEXING_TYPES: > break; >+ case ALL_INT32_INDEXING_TYPES: > case ALL_CONTIGUOUS_INDEXING_TYPES: > if (i < m_butterfly->publicLength()) > return m_butterfly->contiguous()[i].get(); > break; >+ case ALL_DOUBLE_INDEXING_TYPES: { >+ if (i >= m_butterfly->publicLength()) >+ break; >+ double result = m_butterfly->contiguousDouble()[i]; >+ if (result != result) >+ break; >+ return JSValue(JSValue::EncodeAsDouble, result); >+ } > case ALL_ARRAY_STORAGE_INDEXING_TYPES: > if (i < m_butterfly->arrayStorage()->vectorLength()) > return m_butterfly->arrayStorage()->m_vector[i].get(); >@@ -279,7 +287,10 @@ namespace JSC { > { > switch (structure()->indexingType()) { > case ALL_BLANK_INDEXING_TYPES: >+ case ALL_UNDECIDED_INDEXING_TYPES: > return false; >+ case ALL_INT32_INDEXING_TYPES: >+ case ALL_DOUBLE_INDEXING_TYPES: > case ALL_CONTIGUOUS_INDEXING_TYPES: > case NonArrayWithArrayStorage: > case ArrayWithArrayStorage: >@@ -298,7 +309,10 @@ namespace JSC { > { > switch (structure()->indexingType()) { > case ALL_BLANK_INDEXING_TYPES: >+ case ALL_UNDECIDED_INDEXING_TYPES: > return false; >+ case ALL_INT32_INDEXING_TYPES: >+ case ALL_DOUBLE_INDEXING_TYPES: > case ALL_CONTIGUOUS_INDEXING_TYPES: > case ALL_ARRAY_STORAGE_INDEXING_TYPES: > return i < m_butterfly->vectorLength(); >@@ -311,6 +325,14 @@ namespace JSC { > void setIndexQuickly(JSGlobalData& globalData, unsigned i, JSValue v) > { > switch (structure()->indexingType()) { >+ case ALL_INT32_INDEXING_TYPES: { >+ ASSERT(i < m_butterfly->vectorLength()); >+ if (!v.isInt32()) { >+ convertInt32ToDoubleOrContiguousWhilePerformingSetIndex(globalData, i, v); >+ return; >+ } >+ // Fall through to contiguous case. >+ } > case ALL_CONTIGUOUS_INDEXING_TYPES: { > ASSERT(i < m_butterfly->vectorLength()); > m_butterfly->contiguous()[i].set(globalData, this, v); >@@ -318,6 +340,22 @@ namespace JSC { > m_butterfly->setPublicLength(i + 1); > break; > } >+ case ALL_DOUBLE_INDEXING_TYPES: { >+ ASSERT(i < m_butterfly->vectorLength()); >+ if (!v.isNumber()) { >+ convertDoubleToContiguousWhilePerformingSetIndex(globalData, i, v); >+ return; >+ } >+ double value = v.asNumber(); >+ if (value != value) { >+ convertDoubleToContiguousWhilePerformingSetIndex(globalData, i, v); >+ return; >+ } >+ m_butterfly->contiguousDouble()[i] = value; >+ if (i >= m_butterfly->publicLength()) >+ m_butterfly->setPublicLength(i + 1); >+ break; >+ } > case ALL_ARRAY_STORAGE_INDEXING_TYPES: { > ArrayStorage* storage = m_butterfly->arrayStorage(); > WriteBarrier<Unknown>& x = storage->m_vector[i]; >@@ -338,12 +376,40 @@ namespace JSC { > void initializeIndex(JSGlobalData& globalData, unsigned i, JSValue v) > { > switch (structure()->indexingType()) { >+ case ALL_UNDECIDED_INDEXING_TYPES: { >+ setIndexQuicklyToUndecided(globalData, i, v); >+ break; >+ } >+ case ALL_INT32_INDEXING_TYPES: { >+ ASSERT(i < m_butterfly->publicLength()); >+ ASSERT(i < m_butterfly->vectorLength()); >+ if (!v.isInt32()) { >+ convertInt32ToDoubleOrContiguousWhilePerformingSetIndex(globalData, i, v); >+ break; >+ } >+ // Fall through. >+ } > case ALL_CONTIGUOUS_INDEXING_TYPES: { > ASSERT(i < m_butterfly->publicLength()); > ASSERT(i < m_butterfly->vectorLength()); > m_butterfly->contiguous()[i].set(globalData, this, v); > break; > } >+ case ALL_DOUBLE_INDEXING_TYPES: { >+ ASSERT(i < m_butterfly->publicLength()); >+ ASSERT(i < m_butterfly->vectorLength()); >+ if (!v.isNumber()) { >+ convertDoubleToContiguousWhilePerformingSetIndex(globalData, i, v); >+ return; >+ } >+ double value = v.asNumber(); >+ if (value != value) { >+ convertDoubleToContiguousWhilePerformingSetIndex(globalData, i, v); >+ return; >+ } >+ m_butterfly->contiguousDouble()[i] = value; >+ break; >+ } > case ALL_ARRAY_STORAGE_INDEXING_TYPES: { > ArrayStorage* storage = m_butterfly->arrayStorage(); > ASSERT(i < storage->length()); >@@ -360,6 +426,9 @@ namespace JSC { > { > switch (structure()->indexingType()) { > case ALL_BLANK_INDEXING_TYPES: >+ case ALL_UNDECIDED_INDEXING_TYPES: >+ case ALL_INT32_INDEXING_TYPES: >+ case ALL_DOUBLE_INDEXING_TYPES: > case ALL_CONTIGUOUS_INDEXING_TYPES: > return false; > case ALL_ARRAY_STORAGE_INDEXING_TYPES: >@@ -374,6 +443,9 @@ namespace JSC { > { > switch (structure()->indexingType()) { > case ALL_BLANK_INDEXING_TYPES: >+ case ALL_UNDECIDED_INDEXING_TYPES: >+ case ALL_INT32_INDEXING_TYPES: >+ case ALL_DOUBLE_INDEXING_TYPES: > case ALL_CONTIGUOUS_INDEXING_TYPES: > return false; > case ALL_ARRAY_STORAGE_INDEXING_TYPES: >@@ -572,6 +644,30 @@ namespace JSC { > // foo->attemptToInterceptPutByIndexOnHole(...); > bool attemptToInterceptPutByIndexOnHoleForPrototype(ExecState*, JSValue thisValue, unsigned propertyName, JSValue, bool shouldThrow); > >+ // Returns 0 if int32 storage cannot be created - either because >+ // indexing should be sparse, we're having a bad time, or because >+ // we already have a more general form of storage (double, >+ // contiguous, array storage). >+ WriteBarrier<Unknown>* ensureInt32(JSGlobalData& globalData) >+ { >+ if (LIKELY(hasInt32(structure()->indexingType()))) >+ return m_butterfly->contiguousInt32(); >+ >+ return ensureInt32Slow(globalData); >+ } >+ >+ // Returns 0 if double storage cannot be created - either because >+ // indexing should be sparse, we're having a bad time, or because >+ // we already have a more general form of storage (contiguous, >+ // or array storage). >+ double* ensureDouble(JSGlobalData& globalData) >+ { >+ if (LIKELY(hasDouble(structure()->indexingType()))) >+ return m_butterfly->contiguousDouble(); >+ >+ return ensureDoubleSlow(globalData); >+ } >+ > // Returns 0 if contiguous storage cannot be created - either because > // indexing should be sparse or because we're having a bad time. > WriteBarrier<Unknown>* ensureContiguous(JSGlobalData& globalData) >@@ -594,14 +690,6 @@ namespace JSC { > return ensureArrayStorageSlow(globalData); > } > >- Butterfly* ensureIndexedStorage(JSGlobalData& globalData) >- { >- if (LIKELY(hasIndexedProperties(structure()->indexingType()))) >- return m_butterfly; >- >- return ensureIndexedStorageSlow(globalData); >- } >- > static size_t offsetOfInlineStorage(); > > static ptrdiff_t butterflyOffset() >@@ -662,19 +750,47 @@ namespace JSC { > return 0; > } > } >- >+ >+ Butterfly* createInitialUndecided(JSGlobalData&, unsigned length); >+ WriteBarrier<Unknown>* createInitialInt32(JSGlobalData&, unsigned length); >+ double* createInitialDouble(JSGlobalData&, unsigned length); >+ WriteBarrier<Unknown>* createInitialContiguous(JSGlobalData&, unsigned length); >+ >+ void convertUndecidedForValue(JSGlobalData&, JSValue); >+ void convertInt32ForValue(JSGlobalData&, JSValue); >+ > ArrayStorage* createArrayStorage(JSGlobalData&, unsigned length, unsigned vectorLength); > ArrayStorage* createInitialArrayStorage(JSGlobalData&); >- WriteBarrier<Unknown>* createInitialContiguous(JSGlobalData&, unsigned length); >+ >+ WriteBarrier<Unknown>* convertUndecidedToInt32(JSGlobalData&); >+ double* convertUndecidedToDouble(JSGlobalData&); >+ WriteBarrier<Unknown>* convertUndecidedToContiguous(JSGlobalData&); >+ ArrayStorage* convertUndecidedToArrayStorage(JSGlobalData&, NonPropertyTransition, unsigned neededLength); >+ ArrayStorage* convertUndecidedToArrayStorage(JSGlobalData&, NonPropertyTransition); >+ ArrayStorage* convertUndecidedToArrayStorage(JSGlobalData&); >+ >+ double* convertInt32ToDouble(JSGlobalData&); >+ WriteBarrier<Unknown>* convertInt32ToContiguous(JSGlobalData&); >+ ArrayStorage* convertInt32ToArrayStorage(JSGlobalData&, NonPropertyTransition, unsigned neededLength); >+ ArrayStorage* convertInt32ToArrayStorage(JSGlobalData&, NonPropertyTransition); >+ ArrayStorage* convertInt32ToArrayStorage(JSGlobalData&); >+ >+ WriteBarrier<Unknown>* convertDoubleToContiguous(JSGlobalData&); >+ ArrayStorage* convertDoubleToArrayStorage(JSGlobalData&, NonPropertyTransition, unsigned neededLength); >+ ArrayStorage* convertDoubleToArrayStorage(JSGlobalData&, NonPropertyTransition); >+ ArrayStorage* convertDoubleToArrayStorage(JSGlobalData&); >+ > ArrayStorage* convertContiguousToArrayStorage(JSGlobalData&, NonPropertyTransition, unsigned neededLength); > ArrayStorage* convertContiguousToArrayStorage(JSGlobalData&, NonPropertyTransition); > ArrayStorage* convertContiguousToArrayStorage(JSGlobalData&); >+ > > ArrayStorage* ensureArrayStorageExistsAndEnterDictionaryIndexingMode(JSGlobalData&); > > bool defineOwnNonIndexProperty(ExecState*, PropertyName, PropertyDescriptor&, bool throwException); > >- void putByIndexBeyondVectorLengthContiguousWithoutAttributes(ExecState*, unsigned propertyName, JSValue); >+ template<IndexingType indexingShape> >+ void putByIndexBeyondVectorLengthWithoutAttributes(ExecState*, unsigned propertyName, JSValue); > void putByIndexBeyondVectorLengthWithArrayStorage(ExecState*, unsigned propertyName, JSValue, bool shouldThrow, ArrayStorage*); > > bool increaseVectorLength(JSGlobalData&, unsigned newLength); >@@ -688,24 +804,33 @@ namespace JSC { > > // Call this if you want setIndexQuickly to succeed and you're sure that > // the array is contiguous. >- void ensureContiguousLength(JSGlobalData& globalData, unsigned length) >+ void ensureLength(JSGlobalData& globalData, unsigned length) > { > ASSERT(length < MAX_ARRAY_INDEX); >- ASSERT(hasContiguous(structure()->indexingType())); >+ ASSERT(hasContiguous(structure()->indexingType()) || hasInt32(structure()->indexingType()) || hasDouble(structure()->indexingType())); > > if (m_butterfly->vectorLength() < length) >- ensureContiguousLengthSlow(globalData, length); >+ ensureLengthSlow(globalData, length); > > if (m_butterfly->publicLength() < length) > m_butterfly->setPublicLength(length); > } > >- unsigned countElementsInContiguous(Butterfly*); >+ template<IndexingType indexingShape> >+ unsigned countElements(Butterfly*); > >+ // This is relevant to undecided, int32, double, and contiguous. >+ unsigned countElements(); >+ >+ // This strange method returns a pointer to the start of the indexed data >+ // as if it contained JSValues. But it won't always contain JSValues. >+ // Make sure you cast this to the appropriate type before using. > template<IndexingType indexingType> > WriteBarrier<Unknown>* indexingData() > { > switch (indexingType) { >+ case ALL_INT32_INDEXING_TYPES: >+ case ALL_DOUBLE_INDEXING_TYPES: > case ALL_CONTIGUOUS_INDEXING_TYPES: > return m_butterfly->contiguous(); > >@@ -747,6 +872,8 @@ namespace JSC { > void isObject(); > void isString(); > >+ Butterfly* createInitialIndexedStorage(JSGlobalData&, unsigned length, size_t elementSize); >+ > ArrayStorage* enterDictionaryIndexingModeWhenArrayStorageAlreadyExists(JSGlobalData&, ArrayStorage*); > > template<PutMode> >@@ -769,11 +896,18 @@ namespace JSC { > > JS_EXPORT_PRIVATE bool getOwnPropertySlotSlow(ExecState*, PropertyName, PropertySlot&); > >- void ensureContiguousLengthSlow(JSGlobalData&, unsigned length); >+ ArrayStorage* constructConvertedArrayStorageWithoutCopyingElements(JSGlobalData& globalData, unsigned neededLength); >+ >+ void setIndexQuicklyToUndecided(JSGlobalData&, unsigned index, JSValue); >+ JS_EXPORT_PRIVATE void convertInt32ToDoubleOrContiguousWhilePerformingSetIndex(JSGlobalData&, unsigned index, JSValue); >+ JS_EXPORT_PRIVATE void convertDoubleToContiguousWhilePerformingSetIndex(JSGlobalData&, unsigned index, JSValue); >+ >+ void ensureLengthSlow(JSGlobalData&, unsigned length); > >+ WriteBarrier<Unknown>* ensureInt32Slow(JSGlobalData&); >+ double* ensureDoubleSlow(JSGlobalData&); > WriteBarrier<Unknown>* ensureContiguousSlow(JSGlobalData&); > ArrayStorage* ensureArrayStorageSlow(JSGlobalData&); >- Butterfly* ensureIndexedStorageSlow(JSGlobalData&); > > protected: > Butterfly* m_butterfly; >Index: Source/JavaScriptCore/runtime/LiteralParser.cpp >=================================================================== >--- Source/JavaScriptCore/runtime/LiteralParser.cpp (revision 132745) >+++ Source/JavaScriptCore/runtime/LiteralParser.cpp (working copy) >@@ -548,7 +548,7 @@ JSValue LiteralParser<CharType>::parse(P > switch(state) { > startParseArray: > case StartParseArray: { >- JSArray* array = constructEmptyArray(m_exec); >+ JSArray* array = constructEmptyArray(m_exec, 0); > objectStack.append(array); > // fallthrough > } >Index: Source/JavaScriptCore/runtime/ObjectConstructor.cpp >=================================================================== >--- Source/JavaScriptCore/runtime/ObjectConstructor.cpp (revision 132745) >+++ Source/JavaScriptCore/runtime/ObjectConstructor.cpp (working copy) >@@ -182,7 +182,7 @@ EncodedJSValue JSC_HOST_CALL objectConst > return throwVMError(exec, createTypeError(exec, ASCIILiteral("Requested property names of a value that is not an object."))); > PropertyNameArray properties(exec); > asObject(exec->argument(0))->methodTable()->getOwnPropertyNames(asObject(exec->argument(0)), exec, properties, IncludeDontEnumProperties); >- JSArray* names = constructEmptyArray(exec); >+ JSArray* names = constructEmptyArray(exec, 0); > size_t numProperties = properties.size(); > for (size_t i = 0; i < numProperties; i++) > names->push(exec, jsOwnedString(exec, properties[i].string())); >@@ -196,7 +196,7 @@ EncodedJSValue JSC_HOST_CALL objectConst > return throwVMError(exec, createTypeError(exec, ASCIILiteral("Requested keys of a value that is not an object."))); > PropertyNameArray properties(exec); > asObject(exec->argument(0))->methodTable()->getOwnPropertyNames(asObject(exec->argument(0)), exec, properties, ExcludeDontEnumProperties); >- JSArray* keys = constructEmptyArray(exec); >+ JSArray* keys = constructEmptyArray(exec, 0); > size_t numProperties = properties.size(); > for (size_t i = 0; i < numProperties; i++) > keys->push(exec, jsOwnedString(exec, properties[i].string())); >Index: Source/JavaScriptCore/runtime/StringPrototype.cpp >=================================================================== >--- Source/JavaScriptCore/runtime/StringPrototype.cpp (revision 132745) >+++ Source/JavaScriptCore/runtime/StringPrototype.cpp (working copy) >@@ -870,7 +870,7 @@ EncodedJSValue JSC_HOST_CALL stringProto > return JSValue::encode(jsNull()); > } > >- return JSValue::encode(constructArray(exec, list)); >+ return JSValue::encode(constructArray(exec, static_cast<ArrayAllocationProfile*>(0), list)); > } > > EncodedJSValue JSC_HOST_CALL stringProtoFuncSearch(ExecState* exec) >@@ -973,7 +973,7 @@ EncodedJSValue JSC_HOST_CALL stringProto > > // 3. Let A be a new array created as if by the expression new Array() > // where Array is the standard built-in constructor with that name. >- JSArray* result = constructEmptyArray(exec); >+ JSArray* result = constructEmptyArray(exec, 0); > > // 4. Let lengthA be 0. > unsigned resultLength = 0; >Index: Source/JavaScriptCore/runtime/Structure.cpp >=================================================================== >--- Source/JavaScriptCore/runtime/Structure.cpp (revision 132745) >+++ Source/JavaScriptCore/runtime/Structure.cpp (working copy) >@@ -543,6 +543,15 @@ Structure* Structure::nonPropertyTransit > unsigned attributes = toAttributes(transitionKind); > IndexingType indexingType = newIndexingType(structure->indexingTypeIncludingHistory(), transitionKind); > >+ if (JSGlobalObject* globalObject = structure->m_globalObject.get()) { >+ if (globalObject->originalArrayStructureForIndexingType(structure->indexingType() | IsArray) == structure) { >+ Structure* result = globalObject->originalArrayStructureForIndexingType(indexingType); >+ ASSERT(result->indexingTypeIncludingHistory() == indexingType); >+ structure->notifyTransitionFromThisStructure(); >+ return result; >+ } >+ } >+ > if (Structure* existingTransition = structure->m_transitionTable.get(0, attributes)) { > ASSERT(existingTransition->m_attributesInPrevious == attributes); > ASSERT(existingTransition->indexingTypeIncludingHistory() == indexingType); >Index: Source/JavaScriptCore/runtime/StructureTransitionTable.h >=================================================================== >--- Source/JavaScriptCore/runtime/StructureTransitionTable.h (revision 132745) >+++ Source/JavaScriptCore/runtime/StructureTransitionTable.h (working copy) >@@ -43,6 +43,9 @@ static const unsigned FirstInternalAttri > // Support for attributes used to indicate transitions not related to properties. > // If any of these are used, the string portion of the key should be 0. > enum NonPropertyTransition { >+ AllocateUndecided, >+ AllocateInt32, >+ AllocateDouble, > AllocateContiguous, > AllocateArrayStorage, > AllocateSlowPutArrayStorage, >@@ -58,14 +61,23 @@ inline unsigned toAttributes(NonProperty > inline IndexingType newIndexingType(IndexingType oldType, NonPropertyTransition transition) > { > switch (transition) { >- case AllocateContiguous: >+ case AllocateUndecided: > ASSERT(!hasIndexedProperties(oldType)); >- return oldType | ContiguousShape; >+ return oldType | UndecidedShape; >+ case AllocateInt32: >+ ASSERT(!hasIndexedProperties(oldType) || hasUndecided(oldType)); >+ return (oldType & ~IndexingShapeMask) | Int32Shape; >+ case AllocateDouble: >+ ASSERT(!hasIndexedProperties(oldType) || hasUndecided(oldType) || hasInt32(oldType)); >+ return (oldType & ~IndexingShapeMask) | DoubleShape; >+ case AllocateContiguous: >+ ASSERT(!hasIndexedProperties(oldType) || hasUndecided(oldType) || hasInt32(oldType) || hasDouble(oldType)); >+ return (oldType & ~IndexingShapeMask) | ContiguousShape; > case AllocateArrayStorage: >- ASSERT(!hasIndexedProperties(oldType) || hasContiguous(oldType)); >+ ASSERT(!hasIndexedProperties(oldType) || hasUndecided(oldType) || hasInt32(oldType) || hasDouble(oldType) || hasContiguous(oldType)); > return (oldType & ~IndexingShapeMask) | ArrayStorageShape; > case AllocateSlowPutArrayStorage: >- ASSERT(!hasIndexedProperties(oldType) || hasContiguous(oldType)); >+ ASSERT(!hasIndexedProperties(oldType) || hasUndecided(oldType) || hasInt32(oldType) || hasDouble(oldType) || hasContiguous(oldType) || hasContiguous(oldType)); > return (oldType & ~IndexingShapeMask) | SlowPutArrayStorageShape; > case SwitchToSlowPutArrayStorage: > ASSERT(hasFastArrayStorage(oldType));
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Formatted Diff
|
Diff
Attachments on
bug 98606
:
169066
|
169069
|
169493
|
169678
|
169757
|
169771
|
170026
|
170475
|
170545
|
170699
|
170842
|
171066
|
171111
|
171125
|
171351
|
171507
|
171547
|
171759
|
171934
|
171941
|
172173
|
172249
|
172362
|
172458
|
172479
|
172493
|
172625
|
172680
|
172686
|
172731