JSC should infer when indexed storage is contiguous, and optimize for it
https://bugs.webkit.org/show_bug.cgi?id=97288
Reviewed by Mark Hahnenberg.
Source/JavaScriptCore:
This introduces a new kind of indexed property storage called Contiguous,
which has the following properties:
- No header bits beyond IndexedHeader. This results in a 16 byte reduction
in memory usage per array versus an ArrayStorage array. It also means
that the total memory usage for an empty array is now just 3 * 8 on both
32-bit and 64-bit. Of that, only 8 bytes are array-specific; the rest is
our standard object header overhead.
- No need for hole checks on store. This results in a ~4% speed-up on
Kraken and a ~1% speed-up on V8v7.
- publicLength <= vectorLength. This means that doing new Array(blah)
immediately allocates room for blah elements.
- No sparse map or index bias.
If you ever do things to an array that would require publicLength >
vectorLength, a sparse map, or index bias, then we switch to ArrayStorage
mode. This seems to never happen in any benchmark we track, and is unlikely
to happen very frequently on any website.
* CMakeLists.txt:
* GNUmakefile.list.am:
* JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.vcproj:
* JavaScriptCore.xcodeproj/project.pbxproj:
* Target.pri:
* assembler/AbstractMacroAssembler.h:
(JSC::AbstractMacroAssembler::JumpList::append):
* assembler/MacroAssembler.h:
(MacroAssembler):
(JSC::MacroAssembler::patchableBranchTest32):
* bytecode/ByValInfo.h: Added.
(JSC):
(JSC::isOptimizableIndexingType):
(JSC::jitArrayModeForIndexingType):
(JSC::ByValInfo::ByValInfo):
(ByValInfo):
(JSC::getByValInfoBytecodeIndex):
* bytecode/CodeBlock.h:
(CodeBlock):
(JSC::CodeBlock::getByValInfo):
(JSC::CodeBlock::setNumberOfByValInfos):
(JSC::CodeBlock::numberOfByValInfos):
(JSC::CodeBlock::byValInfo):
* bytecode/SamplingTool.h:
* dfg/DFGAbstractState.cpp:
(JSC::DFG::AbstractState::execute):
* dfg/DFGArrayMode.cpp:
(JSC::DFG::fromObserved):
(JSC::DFG::modeAlreadyChecked):
(JSC::DFG::modeToString):
* dfg/DFGArrayMode.h:
(DFG):
(JSC::DFG::modeUsesButterfly):
(JSC::DFG::modeIsJSArray):
(JSC::DFG::isInBoundsAccess):
(JSC::DFG::mayStoreToTail):
(JSC::DFG::mayStoreToHole):
(JSC::DFG::modeIsPolymorphic):
(JSC::DFG::polymorphicIncludesContiguous):
(JSC::DFG::polymorphicIncludesArrayStorage):
(JSC::DFG::canCSEStorage):
(JSC::DFG::modeSupportsLength):
(JSC::DFG::benefitsFromStructureCheck):
(JSC::DFG::isEffectful):
* dfg/DFGByteCodeParser.cpp:
(JSC::DFG::ByteCodeParser::handleIntrinsic):
* dfg/DFGCSEPhase.cpp:
(JSC::DFG::CSEPhase::getArrayLengthElimination):
(JSC::DFG::CSEPhase::getByValLoadElimination):
(JSC::DFG::CSEPhase::performNodeCSE):
* dfg/DFGFixupPhase.cpp:
(JSC::DFG::FixupPhase::fixupNode):
(JSC::DFG::FixupPhase::checkArray):
(JSC::DFG::FixupPhase::blessArrayOperation):
* dfg/DFGGraph.h:
(JSC::DFG::Graph::byValIsPure):
* dfg/DFGOperations.cpp:
* dfg/DFGOperations.h:
* dfg/DFGRepatch.cpp:
(JSC::DFG::tryCacheGetByID):
* dfg/DFGSpeculativeJIT.cpp:
(JSC::DFG::SpeculativeJIT::checkArray):
(JSC::DFG::SpeculativeJIT::arrayify):
(JSC::DFG::SpeculativeJIT::compileGetArrayLength):
(JSC::DFG::SpeculativeJIT::temporaryRegisterForPutByVal):
(DFG):
* dfg/DFGSpeculativeJIT.h:
(DFG):
(JSC::DFG::SpeculativeJIT::callOperation):
(SpeculativeJIT):
(JSC::DFG::SpeculativeJIT::putByValWillNeedExtraRegister):
(JSC::DFG::SpeculativeJIT::temporaryRegisterForPutByVal):
* dfg/DFGSpeculativeJIT32_64.cpp:
(JSC::DFG::SpeculativeJIT::compileContiguousGetByVal):
(DFG):
(JSC::DFG::SpeculativeJIT::compileArrayStorageGetByVal):
(JSC::DFG::SpeculativeJIT::compileContiguousPutByVal):
(JSC::DFG::SpeculativeJIT::compileArrayStoragePutByVal):
(JSC::DFG::SpeculativeJIT::compile):
* dfg/DFGSpeculativeJIT64.cpp:
(JSC::DFG::SpeculativeJIT::compileContiguousGetByVal):
(DFG):
(JSC::DFG::SpeculativeJIT::compileArrayStorageGetByVal):
(JSC::DFG::SpeculativeJIT::compileContiguousPutByVal):
(JSC::DFG::SpeculativeJIT::compileArrayStoragePutByVal):
(JSC::DFG::SpeculativeJIT::compile):
* interpreter/Interpreter.cpp:
(SamplingScope):
(JSC::SamplingScope::SamplingScope):
(JSC::SamplingScope::~SamplingScope):
(JSC):
(JSC::Interpreter::execute):
* jit/JIT.cpp:
(JSC::JIT::privateCompileSlowCases):
(JSC::JIT::privateCompile):
* jit/JIT.h:
(JSC::ByValCompilationInfo::ByValCompilationInfo):
(ByValCompilationInfo):
(JSC):
(JIT):
(JSC::JIT::compileGetByVal):
(JSC::JIT::compilePutByVal):
* jit/JITInlineMethods.h:
(JSC::JIT::emitAllocateJSArray):
(JSC::JIT::emitArrayProfileStoreToHoleSpecialCase):
(JSC):
(JSC::arrayProfileSaw):
(JSC::JIT::chooseArrayMode):
* jit/JITOpcodes.cpp:
(JSC::JIT::emitSlow_op_get_argument_by_val):
(JSC::JIT::emit_op_new_array):
(JSC::JIT::emitSlow_op_new_array):
* jit/JITOpcodes32_64.cpp:
(JSC::JIT::emitSlow_op_get_argument_by_val):
* jit/JITPropertyAccess.cpp:
(JSC::JIT::emit_op_get_by_val):
(JSC):
(JSC::JIT::emitContiguousGetByVal):
(JSC::JIT::emitArrayStorageGetByVal):
(JSC::JIT::emitSlow_op_get_by_val):
(JSC::JIT::emit_op_put_by_val):
(JSC::JIT::emitContiguousPutByVal):
(JSC::JIT::emitArrayStoragePutByVal):
(JSC::JIT::emitSlow_op_put_by_val):
(JSC::JIT::privateCompilePatchGetArrayLength):
(JSC::JIT::privateCompileGetByVal):
(JSC::JIT::privateCompilePutByVal):
* jit/JITPropertyAccess32_64.cpp:
(JSC::JIT::emit_op_get_by_val):
(JSC):
(JSC::JIT::emitContiguousGetByVal):
(JSC::JIT::emitArrayStorageGetByVal):
(JSC::JIT::emitSlow_op_get_by_val):
(JSC::JIT::emit_op_put_by_val):
(JSC::JIT::emitContiguousPutByVal):
(JSC::JIT::emitArrayStoragePutByVal):
(JSC::JIT::emitSlow_op_put_by_val):
* jit/JITStubs.cpp:
(JSC::getByVal):
(JSC):
(JSC::DEFINE_STUB_FUNCTION):
(JSC::putByVal):
* jit/JITStubs.h:
* llint/LowLevelInterpreter.asm:
* llint/LowLevelInterpreter32_64.asm:
* llint/LowLevelInterpreter64.asm:
* runtime/ArrayConventions.h:
(JSC::isDenseEnoughForVector):
* runtime/ArrayPrototype.cpp:
(JSC):
(JSC::shift):
(JSC::unshift):
(JSC::arrayProtoFuncPush):
(JSC::arrayProtoFuncShift):
(JSC::arrayProtoFuncSplice):
(JSC::arrayProtoFuncUnShift):
* runtime/Butterfly.h:
(Butterfly):
(JSC::Butterfly::fromPointer):
(JSC::Butterfly::pointer):
(JSC::Butterfly::publicLength):
(JSC::Butterfly::vectorLength):
(JSC::Butterfly::setPublicLength):
(JSC::Butterfly::setVectorLength):
(JSC::Butterfly::contiguous):
(JSC::Butterfly::fromContiguous):
* runtime/ButterflyInlineMethods.h:
(JSC::Butterfly::unshift):
(JSC::Butterfly::shift):
* runtime/IndexingHeaderInlineMethods.h:
(JSC::IndexingHeader::indexingPayloadSizeInBytes):
* runtime/IndexingType.cpp: Added.
(JSC):
(JSC::indexingTypeToString):
* runtime/IndexingType.h:
(JSC):
(JSC::hasContiguous):
* runtime/JSArray.cpp:
(JSC::JSArray::setLengthWithArrayStorage):
(JSC::JSArray::setLength):
(JSC):
(JSC::JSArray::pop):
(JSC::JSArray::push):
(JSC::JSArray::shiftCountWithArrayStorage):
(JSC::JSArray::shiftCountWithAnyIndexingType):
(JSC::JSArray::unshiftCountWithArrayStorage):
(JSC::JSArray::unshiftCountWithAnyIndexingType):
(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:
(JSC::JSArray::shiftCountForShift):
(JSC::JSArray::shiftCountForSplice):
(JSArray):
(JSC::JSArray::shiftCount):
(JSC::JSArray::unshiftCountForShift):
(JSC::JSArray::unshiftCountForSplice):
(JSC::JSArray::unshiftCount):
(JSC::JSArray::isLengthWritable):
(JSC::createContiguousArrayButterfly):
(JSC):
(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::arrayStructureWithArrayStorage):
(JSC::JSGlobalObject::addressOfArrayStructureWithArrayStorage):
(JSC::constructEmptyArray):
* runtime/JSObject.cpp:
(JSC::JSObject::visitButterfly):
(JSC::JSObject::getOwnPropertySlotByIndex):
(JSC::JSObject::putByIndex):
(JSC::JSObject::enterDictionaryIndexingMode):
(JSC::JSObject::createInitialContiguous):
(JSC):
(JSC::JSObject::createArrayStorage):
(JSC::JSObject::convertContiguousToArrayStorage):
(JSC::JSObject::ensureContiguousSlow):
(JSC::JSObject::ensureArrayStorageSlow):
(JSC::JSObject::ensureIndexedStorageSlow):
(JSC::JSObject::ensureArrayStorageExistsAndEnterDictionaryIndexingMode):
(JSC::JSObject::switchToSlowPutArrayStorage):
(JSC::JSObject::setPrototype):
(JSC::JSObject::deletePropertyByIndex):
(JSC::JSObject::getOwnPropertyNames):
(JSC::JSObject::defineOwnIndexedProperty):
(JSC::JSObject::putByIndexBeyondVectorLengthContiguousWithoutAttributes):
(JSC::JSObject::putByIndexBeyondVectorLength):
(JSC::JSObject::putDirectIndexBeyondVectorLengthWithArrayStorage):
(JSC::JSObject::putDirectIndexBeyondVectorLength):
(JSC::JSObject::getNewVectorLength):
(JSC::JSObject::countElementsInContiguous):
(JSC::JSObject::increaseVectorLength):
(JSC::JSObject::ensureContiguousLengthSlow):
(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::ensureContiguous):
(JSC::JSObject::ensureIndexedStorage):
(JSC::JSObject::ensureContiguousLength):
(JSC::JSObject::indexingData):
(JSC::JSObject::relevantLength):
* runtime/JSValue.cpp:
(JSC::JSValue::description):
* runtime/Options.cpp:
(JSC::Options::initialize):
* runtime/Structure.cpp:
(JSC::Structure::needsSlowPutIndexing):
(JSC):
(JSC::Structure::suggestedArrayStorageTransition):
* runtime/Structure.h:
(Structure):
* runtime/StructureTransitionTable.h:
(JSC::newIndexingType):
Source/WTF:
Moved out this helpful math utility to MathExtras, since we now use it in
multiple places.
* wtf/MathExtras.h:
(timesThreePlusOneDividedByTwo):
git-svn-id: http://svn.webkit.org/repository/webkit/trunk@130826 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp b/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp
index aa2d5df..c1095b4 100644
--- a/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp
+++ b/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp
@@ -116,7 +116,7 @@
m_graph.deref(m_compileIndex);
nodePtr->setArrayMode(arrayMode);
- NodeIndex storage = checkArray(arrayMode, nodePtr->codeOrigin, nodePtr->child1().index(), lengthNeedsStorage, nodePtr->shouldGenerate());
+ NodeIndex storage = checkArray(arrayMode, nodePtr->codeOrigin, nodePtr->child1().index(), NoNode, lengthNeedsStorage, nodePtr->shouldGenerate());
if (storage == NoNode)
break;
@@ -137,17 +137,17 @@
m_graph[node.child1()].prediction(),
m_graph[node.child2()].prediction()));
- blessArrayOperation(node.child1(), 2);
+ blessArrayOperation(node.child1(), node.child2(), 2);
break;
}
case ArrayPush: {
- blessArrayOperation(node.child1(), 2);
+ blessArrayOperation(node.child1(), node.child2(), 2);
break;
}
case ArrayPop: {
- blessArrayOperation(node.child1(), 1);
+ blessArrayOperation(node.child1(), node.child2(), 1);
}
case ValueToInt32: {
@@ -327,7 +327,7 @@
m_graph[child1].prediction(),
m_graph[child2].prediction()));
- blessArrayOperation(child1, 3);
+ blessArrayOperation(child1, child2, 3);
Node* nodePtr = &m_graph[m_compileIndex];
@@ -375,14 +375,16 @@
return nodeIndex;
}
- NodeIndex checkArray(Array::Mode arrayMode, CodeOrigin codeOrigin, NodeIndex array, bool (*storageCheck)(Array::Mode) = canCSEStorage, bool shouldGenerate = true)
+ NodeIndex checkArray(Array::Mode arrayMode, CodeOrigin codeOrigin, NodeIndex array, NodeIndex index, bool (*storageCheck)(Array::Mode) = canCSEStorage, bool shouldGenerate = true)
{
ASSERT(modeIsSpecific(arrayMode));
m_graph.ref(array);
if (isEffectful(arrayMode)) {
- Node arrayify(Arrayify, codeOrigin, OpInfo(arrayMode), array);
+ ASSERT(index != NoNode);
+ m_graph.ref(index);
+ Node arrayify(Arrayify, codeOrigin, OpInfo(arrayMode), array, index);
arrayify.ref(); // Once because it's used as a butterfly.
arrayify.ref(); // And twice because it's must-generate.
NodeIndex arrayifyIndex = m_graph.size();
@@ -415,14 +417,15 @@
return addNode(Node(GetIndexedPropertyStorage, codeOrigin, OpInfo(arrayMode), array), shouldGenerate);
}
- void blessArrayOperation(Edge base, unsigned storageChildIdx)
+ void blessArrayOperation(Edge base, Edge index, unsigned storageChildIdx)
{
if (m_graph.m_fixpointState > BeforeFixpoint)
return;
Node* nodePtr = &m_graph[m_compileIndex];
- if (nodePtr->arrayMode() == Array::ForceExit) {
+ switch (nodePtr->arrayMode()) {
+ case Array::ForceExit: {
Node forceExit(ForceOSRExit, nodePtr->codeOrigin);
forceExit.ref();
NodeIndex forceExitIndex = m_graph.size();
@@ -430,15 +433,24 @@
m_insertionSet.append(m_indexInBlock, forceExitIndex);
return;
}
-
- if (!modeIsSpecific(nodePtr->arrayMode()))
+
+ case Array::Undecided:
+ case Array::Unprofiled:
+ ASSERT_NOT_REACHED();
return;
- NodeIndex storage = checkArray(nodePtr->arrayMode(), nodePtr->codeOrigin, base.index());
- if (storage == NoNode)
+ case Array::Generic:
+ case ALL_POLYMORPHIC_MODES:
return;
- m_graph.child(m_graph[m_compileIndex], storageChildIdx) = Edge(storage);
+ default: {
+ NodeIndex storage = checkArray(nodePtr->arrayMode(), nodePtr->codeOrigin, base.index(), index.indexUnchecked());
+ if (storage == NoNode)
+ return;
+
+ m_graph.child(m_graph[m_compileIndex], storageChildIdx) = Edge(storage);
+ return;
+ } }
}
void fixIntEdge(Edge& edge)