DFG should support Int52 for local variables
https://bugs.webkit.org/show_bug.cgi?id=121064
Source/JavaScriptCore:
Reviewed by Oliver Hunt.
This adds Int52 support for local variables to the DFG and FTL. It's a speed-up on
programs that have local int32 overflows but where a larger int representation can
prevent us from having to convert all the way up to double.
It's a small speed-up for now. But we're just supporting Int52 for a handful of
operations (add, sub, mul, neg, compare, bitops, typed array access) and this lays
the groundwork for adding Int52 to JSValue, which will probably be a bigger
speed-up.
The basic approach is:
- We have a notion of Int52 in our typesystem. Int52 doesn't belong to BytecodeTop
or HeapTop - i.e. it doesn't arise from JSValues.
- DFG treats Int52 as being part of its FullTop and will treat it as being a
subtype of double unless instructed otherwise.
- Prediction propagator creates Int52s whenever we have a node going doubly but due
to large values rather than fractional values, and that node is known to be able
to produce Int52 natively in the DFG backend.
- Fixup phase converts edges to MachineIntUses in nodes that are known to be able
to deal with Int52, and where we have a subtype of Int32|Int52 as the predicted
input.
- The DFG backend and FTL LLVM IR lowering have two notions of Int52s - ones that
are left-shifted by 16 (great for overflow checks) and ones that are
sign-extended. Both backends know how to convert between Int52s and the other
representations.
* assembler/MacroAssemblerX86_64.h:
(JSC::MacroAssemblerX86_64::rshift64):
(JSC::MacroAssemblerX86_64::mul64):
(JSC::MacroAssemblerX86_64::branchMul64):
(JSC::MacroAssemblerX86_64::branchNeg64):
(JSC::MacroAssemblerX86_64::convertInt64ToDouble):
* assembler/X86Assembler.h:
(JSC::X86Assembler::imulq_rr):
(JSC::X86Assembler::cvtsi2sdq_rr):
* bytecode/DataFormat.h:
(JSC::dataFormatToString):
* bytecode/ExitKind.cpp:
(JSC::exitKindToString):
* bytecode/ExitKind.h:
* bytecode/OperandsInlines.h:
(JSC::::dumpInContext):
* bytecode/SpeculatedType.cpp:
(JSC::dumpSpeculation):
(JSC::speculationToAbbreviatedString):
(JSC::speculationFromValue):
* bytecode/SpeculatedType.h:
(JSC::isInt32SpeculationForArithmetic):
(JSC::isInt52Speculation):
(JSC::isMachineIntSpeculationForArithmetic):
(JSC::isInt52AsDoubleSpeculation):
(JSC::isBytecodeRealNumberSpeculation):
(JSC::isFullRealNumberSpeculation):
(JSC::isBytecodeNumberSpeculation):
(JSC::isFullNumberSpeculation):
(JSC::isBytecodeNumberSpeculationExpectingDefined):
(JSC::isFullNumberSpeculationExpectingDefined):
* bytecode/ValueRecovery.h:
(JSC::ValueRecovery::alreadyInJSStackAsUnboxedInt52):
(JSC::ValueRecovery::inGPR):
(JSC::ValueRecovery::displacedInJSStack):
(JSC::ValueRecovery::isAlreadyInJSStack):
(JSC::ValueRecovery::gpr):
(JSC::ValueRecovery::virtualRegister):
(JSC::ValueRecovery::dumpInContext):
* dfg/DFGAbstractInterpreter.h:
(JSC::DFG::AbstractInterpreter::needsTypeCheck):
(JSC::DFG::AbstractInterpreter::filterByType):
* dfg/DFGAbstractInterpreterInlines.h:
(JSC::DFG::::executeEffects):
* dfg/DFGAbstractValue.cpp:
(JSC::DFG::AbstractValue::set):
(JSC::DFG::AbstractValue::checkConsistency):
* dfg/DFGAbstractValue.h:
(JSC::DFG::AbstractValue::couldBeType):
(JSC::DFG::AbstractValue::isType):
(JSC::DFG::AbstractValue::checkConsistency):
(JSC::DFG::AbstractValue::validateType):
* dfg/DFGArrayMode.cpp:
(JSC::DFG::ArrayMode::refine):
* dfg/DFGAssemblyHelpers.h:
(JSC::DFG::AssemblyHelpers::boxInt52):
* dfg/DFGByteCodeParser.cpp:
(JSC::DFG::ByteCodeParser::makeSafe):
* dfg/DFGCSEPhase.cpp:
(JSC::DFG::CSEPhase::pureCSE):
(JSC::DFG::CSEPhase::getByValLoadElimination):
(JSC::DFG::CSEPhase::performNodeCSE):
* dfg/DFGClobberize.h:
(JSC::DFG::clobberize):
* dfg/DFGCommon.h:
(JSC::DFG::enableInt52):
* dfg/DFGDCEPhase.cpp:
(JSC::DFG::DCEPhase::fixupBlock):
* dfg/DFGFixupPhase.cpp:
(JSC::DFG::FixupPhase::run):
(JSC::DFG::FixupPhase::fixupNode):
(JSC::DFG::FixupPhase::fixupSetLocalsInBlock):
(JSC::DFG::FixupPhase::fixupUntypedSetLocalsInBlock):
(JSC::DFG::FixupPhase::observeUseKindOnNode):
(JSC::DFG::FixupPhase::fixEdge):
(JSC::DFG::FixupPhase::injectInt32ToDoubleNode):
(JSC::DFG::FixupPhase::attemptToMakeIntegerAdd):
* dfg/DFGFlushFormat.cpp:
(WTF::printInternal):
* dfg/DFGFlushFormat.h:
(JSC::DFG::resultFor):
(JSC::DFG::useKindFor):
* dfg/DFGGenerationInfo.h:
(JSC::DFG::GenerationInfo::initInt52):
(JSC::DFG::GenerationInfo::initStrictInt52):
(JSC::DFG::GenerationInfo::isFormat):
(JSC::DFG::GenerationInfo::isInt52):
(JSC::DFG::GenerationInfo::isStrictInt52):
(JSC::DFG::GenerationInfo::fillInt52):
(JSC::DFG::GenerationInfo::fillStrictInt52):
* dfg/DFGGraph.cpp:
(JSC::DFG::Graph::dump):
* dfg/DFGGraph.h:
(JSC::DFG::Graph::addShouldSpeculateMachineInt):
(JSC::DFG::Graph::mulShouldSpeculateMachineInt):
(JSC::DFG::Graph::negateShouldSpeculateMachineInt):
* dfg/DFGInPlaceAbstractState.cpp:
(JSC::DFG::InPlaceAbstractState::mergeStateAtTail):
* dfg/DFGJITCode.cpp:
(JSC::DFG::JITCode::reconstruct):
* dfg/DFGJITCompiler.h:
(JSC::DFG::JITCompiler::noticeOSREntry):
* dfg/DFGMinifiedNode.h:
(JSC::DFG::belongsInMinifiedGraph):
(JSC::DFG::MinifiedNode::hasChild):
* dfg/DFGNode.h:
(JSC::DFG::Node::shouldSpeculateNumber):
(JSC::DFG::Node::shouldSpeculateNumberExpectingDefined):
(JSC::DFG::Node::canSpeculateInt52):
* dfg/DFGNodeFlags.h:
(JSC::DFG::nodeCanSpeculateInt52):
* dfg/DFGNodeType.h:
(JSC::DFG::permitsOSRBackwardRewiring):
(JSC::DFG::forwardRewiringSelectionScore):
* dfg/DFGOSREntry.cpp:
(JSC::DFG::prepareOSREntry):
* dfg/DFGOSREntry.h:
* dfg/DFGOSRExitCompiler.cpp:
* dfg/DFGOSRExitCompiler64.cpp:
(JSC::DFG::OSRExitCompiler::compileExit):
* dfg/DFGPredictionPropagationPhase.cpp:
(JSC::DFG::PredictionPropagationPhase::speculatedDoubleTypeForPrediction):
(JSC::DFG::PredictionPropagationPhase::propagate):
(JSC::DFG::PredictionPropagationPhase::doDoubleVoting):
* dfg/DFGSafeToExecute.h:
(JSC::DFG::SafeToExecuteEdge::operator()):
(JSC::DFG::safeToExecute):
* dfg/DFGSilentRegisterSavePlan.h:
* dfg/DFGSpeculativeJIT.cpp:
(JSC::DFG::SpeculativeJIT::silentSavePlanForGPR):
(JSC::DFG::SpeculativeJIT::silentFill):
(JSC::DFG::SpeculativeJIT::compilePeepHoleBranch):
(JSC::DFG::SpeculativeJIT::compileInlineStart):
(JSC::DFG::SpeculativeJIT::compileDoublePutByVal):
(JSC::DFG::SpeculativeJIT::compileValueToInt32):
(JSC::DFG::SpeculativeJIT::compileInt32ToDouble):
(JSC::DFG::SpeculativeJIT::compileGetByValOnIntTypedArray):
(JSC::DFG::SpeculativeJIT::compilePutByValForIntTypedArray):
(JSC::DFG::SpeculativeJIT::compileAdd):
(JSC::DFG::SpeculativeJIT::compileArithSub):
(JSC::DFG::SpeculativeJIT::compileArithNegate):
(JSC::DFG::SpeculativeJIT::compileArithMul):
(JSC::DFG::SpeculativeJIT::compare):
(JSC::DFG::SpeculativeJIT::compileStrictEq):
(JSC::DFG::SpeculativeJIT::speculateMachineInt):
(JSC::DFG::SpeculativeJIT::speculateNumber):
(JSC::DFG::SpeculativeJIT::speculateRealNumber):
(JSC::DFG::SpeculativeJIT::speculate):
* dfg/DFGSpeculativeJIT.h:
(JSC::DFG::SpeculativeJIT::canReuse):
(JSC::DFG::SpeculativeJIT::isFilled):
(JSC::DFG::SpeculativeJIT::isFilledDouble):
(JSC::DFG::SpeculativeJIT::use):
(JSC::DFG::SpeculativeJIT::isKnownInteger):
(JSC::DFG::SpeculativeJIT::isKnownCell):
(JSC::DFG::SpeculativeJIT::isKnownNotNumber):
(JSC::DFG::SpeculativeJIT::int52Result):
(JSC::DFG::SpeculativeJIT::strictInt52Result):
(JSC::DFG::SpeculativeJIT::initConstantInfo):
(JSC::DFG::SpeculativeJIT::isInteger):
(JSC::DFG::SpeculativeJIT::betterUseStrictInt52):
(JSC::DFG::SpeculativeJIT::generationInfo):
(JSC::DFG::SpeculateInt52Operand::SpeculateInt52Operand):
(JSC::DFG::SpeculateInt52Operand::~SpeculateInt52Operand):
(JSC::DFG::SpeculateInt52Operand::edge):
(JSC::DFG::SpeculateInt52Operand::node):
(JSC::DFG::SpeculateInt52Operand::gpr):
(JSC::DFG::SpeculateInt52Operand::use):
(JSC::DFG::SpeculateStrictInt52Operand::SpeculateStrictInt52Operand):
(JSC::DFG::SpeculateStrictInt52Operand::~SpeculateStrictInt52Operand):
(JSC::DFG::SpeculateStrictInt52Operand::edge):
(JSC::DFG::SpeculateStrictInt52Operand::node):
(JSC::DFG::SpeculateStrictInt52Operand::gpr):
(JSC::DFG::SpeculateStrictInt52Operand::use):
(JSC::DFG::SpeculateWhicheverInt52Operand::SpeculateWhicheverInt52Operand):
(JSC::DFG::SpeculateWhicheverInt52Operand::~SpeculateWhicheverInt52Operand):
(JSC::DFG::SpeculateWhicheverInt52Operand::edge):
(JSC::DFG::SpeculateWhicheverInt52Operand::node):
(JSC::DFG::SpeculateWhicheverInt52Operand::gpr):
(JSC::DFG::SpeculateWhicheverInt52Operand::use):
(JSC::DFG::SpeculateWhicheverInt52Operand::format):
* dfg/DFGSpeculativeJIT32_64.cpp:
(JSC::DFG::SpeculativeJIT::fillSpeculateDouble):
(JSC::DFG::SpeculativeJIT::compile):
* dfg/DFGSpeculativeJIT64.cpp:
(JSC::DFG::SpeculativeJIT::boxInt52):
(JSC::DFG::SpeculativeJIT::fillJSValue):
(JSC::DFG::SpeculativeJIT::fillSpeculateInt32Internal):
(JSC::DFG::SpeculativeJIT::fillSpeculateInt52):
(JSC::DFG::SpeculativeJIT::fillSpeculateDouble):
(JSC::DFG::SpeculativeJIT::fillSpeculateCell):
(JSC::DFG::SpeculativeJIT::fillSpeculateBoolean):
(JSC::DFG::SpeculativeJIT::compileInt52Compare):
(JSC::DFG::SpeculativeJIT::compilePeepHoleInt52Branch):
(JSC::DFG::SpeculativeJIT::compile):
* dfg/DFGUseKind.cpp:
(WTF::printInternal):
* dfg/DFGUseKind.h:
(JSC::DFG::typeFilterFor):
(JSC::DFG::isNumerical):
* dfg/DFGValueSource.cpp:
(JSC::DFG::ValueSource::dump):
* dfg/DFGValueSource.h:
(JSC::DFG::dataFormatToValueSourceKind):
(JSC::DFG::valueSourceKindToDataFormat):
(JSC::DFG::ValueSource::forFlushFormat):
(JSC::DFG::ValueSource::valueRecovery):
* dfg/DFGVariableAccessData.h:
(JSC::DFG::VariableAccessData::shouldUseDoubleFormatAccordingToVote):
(JSC::DFG::VariableAccessData::flushFormat):
* ftl/FTLCArgumentGetter.cpp:
(JSC::FTL::CArgumentGetter::loadNextAndBox):
* ftl/FTLCArgumentGetter.h:
* ftl/FTLCapabilities.cpp:
(JSC::FTL::canCompile):
* ftl/FTLExitValue.cpp:
(JSC::FTL::ExitValue::dumpInContext):
* ftl/FTLExitValue.h:
(JSC::FTL::ExitValue::inJSStackAsInt52):
* ftl/FTLIntrinsicRepository.h:
* ftl/FTLLowerDFGToLLVM.cpp:
(JSC::FTL::LowerDFGToLLVM::createPhiVariables):
(JSC::FTL::LowerDFGToLLVM::compileNode):
(JSC::FTL::LowerDFGToLLVM::compileUpsilon):
(JSC::FTL::LowerDFGToLLVM::compilePhi):
(JSC::FTL::LowerDFGToLLVM::compileSetLocal):
(JSC::FTL::LowerDFGToLLVM::compileAdd):
(JSC::FTL::LowerDFGToLLVM::compileArithSub):
(JSC::FTL::LowerDFGToLLVM::compileArithMul):
(JSC::FTL::LowerDFGToLLVM::compileArithNegate):
(JSC::FTL::LowerDFGToLLVM::compilePutByVal):
(JSC::FTL::LowerDFGToLLVM::compileCompareEq):
(JSC::FTL::LowerDFGToLLVM::compileCompareStrictEq):
(JSC::FTL::LowerDFGToLLVM::compileCompareLess):
(JSC::FTL::LowerDFGToLLVM::compileCompareLessEq):
(JSC::FTL::LowerDFGToLLVM::compileCompareGreater):
(JSC::FTL::LowerDFGToLLVM::compileCompareGreaterEq):
(JSC::FTL::LowerDFGToLLVM::lowInt32):
(JSC::FTL::LowerDFGToLLVM::lowInt52):
(JSC::FTL::LowerDFGToLLVM::lowStrictInt52):
(JSC::FTL::LowerDFGToLLVM::betterUseStrictInt52):
(JSC::FTL::LowerDFGToLLVM::bestInt52Kind):
(JSC::FTL::LowerDFGToLLVM::opposite):
(JSC::FTL::LowerDFGToLLVM::lowWhicheverInt52):
(JSC::FTL::LowerDFGToLLVM::lowCell):
(JSC::FTL::LowerDFGToLLVM::lowBoolean):
(JSC::FTL::LowerDFGToLLVM::lowDouble):
(JSC::FTL::LowerDFGToLLVM::lowJSValue):
(JSC::FTL::LowerDFGToLLVM::strictInt52ToInt32):
(JSC::FTL::LowerDFGToLLVM::strictInt52ToDouble):
(JSC::FTL::LowerDFGToLLVM::strictInt52ToJSValue):
(JSC::FTL::LowerDFGToLLVM::setInt52WithStrictValue):
(JSC::FTL::LowerDFGToLLVM::strictInt52ToInt52):
(JSC::FTL::LowerDFGToLLVM::int52ToStrictInt52):
(JSC::FTL::LowerDFGToLLVM::speculateRealNumber):
(JSC::FTL::LowerDFGToLLVM::initializeOSRExitStateForBlock):
(JSC::FTL::LowerDFGToLLVM::emitOSRExitCall):
(JSC::FTL::LowerDFGToLLVM::addExitArgumentForNode):
(JSC::FTL::LowerDFGToLLVM::setInt52):
(JSC::FTL::LowerDFGToLLVM::setStrictInt52):
* ftl/FTLOSRExitCompiler.cpp:
(JSC::FTL::compileStub):
* ftl/FTLOutput.h:
(JSC::FTL::Output::addWithOverflow64):
(JSC::FTL::Output::subWithOverflow64):
(JSC::FTL::Output::mulWithOverflow64):
* ftl/FTLValueFormat.cpp:
(WTF::printInternal):
* ftl/FTLValueFormat.h:
* ftl/FTLValueSource.cpp:
(JSC::FTL::ValueSource::dump):
* ftl/FTLValueSource.h:
* interpreter/Register.h:
(JSC::Register::unboxedInt52):
* runtime/Arguments.cpp:
(JSC::Arguments::tearOffForInlineCallFrame):
* runtime/IndexingType.cpp:
(JSC::leastUpperBoundOfIndexingTypeAndType):
* runtime/JSCJSValue.h:
* runtime/JSCJSValueInlines.h:
(JSC::JSValue::isMachineInt):
(JSC::JSValue::asMachineInt):
Source/WTF:
Reviewed by Oliver Hunt.
* wtf/PrintStream.h:
(WTF::ValueIgnoringContext::ValueIgnoringContext):
(WTF::ValueIgnoringContext::dump):
(WTF::ignoringContext):
Tools:
Reviewed by Oliver Hunt.
* Scripts/run-jsc-stress-tests:
LayoutTests:
Reviewed by Oliver Hunt.
* js/dfg-int-overflow-large-constants-in-a-line-expected.txt:
* js/regress/large-int-captured-expected.txt: Added.
* js/regress/large-int-captured.html: Added.
* js/regress/large-int-expected.txt: Added.
* js/regress/large-int-neg-expected.txt: Added.
* js/regress/large-int-neg.html: Added.
* js/regress/large-int.html: Added.
* js/regress/marsaglia-larger-ints-expected.txt: Added.
* js/regress/marsaglia-larger-ints.html: Added.
* js/regress/script-tests/large-int-captured.js: Added.
(.bar):
(foo):
* js/regress/script-tests/large-int-neg.js: Added.
(foo):
* js/regress/script-tests/large-int.js: Added.
(foo):
* js/regress/script-tests/marsaglia-larger-ints.js: Added.
(uint):
(marsaglia):
* js/script-tests/dfg-int-overflow-large-constants-in-a-line.js:
git-svn-id: http://svn.webkit.org/repository/webkit/trunk@156047 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp b/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp
index d03f63e..e862d63 100644
--- a/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp
+++ b/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp
@@ -64,6 +64,9 @@
fixupSetLocalsInBlock(m_graph.block(blockIndex));
}
+ for (BlockIndex blockIndex = 0; blockIndex < m_graph.numBlocks(); ++blockIndex)
+ fixupUntypedSetLocalsInBlock(m_graph.block(blockIndex));
+
return true;
}
@@ -92,7 +95,7 @@
switch (op) {
case SetLocal: {
// This gets handled by fixupSetLocalsInBlock().
- break;
+ return;
}
case BitAnd:
@@ -124,6 +127,11 @@
break;
}
+ if (node->child1()->shouldSpeculateMachineInt()) {
+ fixEdge<MachineIntUse>(node->child1());
+ break;
+ }
+
if (node->child1()->shouldSpeculateNumber()) {
fixEdge<NumberUse>(node->child1());
break;
@@ -197,6 +205,10 @@
fixEdge<Int32Use>(node->child1());
break;
}
+ if (m_graph.negateShouldSpeculateMachineInt(node)) {
+ fixEdge<MachineIntUse>(node->child1());
+ break;
+ }
fixEdge<NumberUse>(node->child1());
break;
}
@@ -207,6 +219,11 @@
fixEdge<Int32Use>(node->child2());
break;
}
+ if (m_graph.mulShouldSpeculateMachineInt(node)) {
+ fixEdge<MachineIntUse>(node->child1());
+ fixEdge<MachineIntUse>(node->child2());
+ break;
+ }
fixEdge<NumberUse>(node->child1());
fixEdge<NumberUse>(node->child2());
break;
@@ -300,6 +317,12 @@
fixEdge<Int32Use>(node->child2());
break;
}
+ if (enableInt52()
+ && Node::shouldSpeculateMachineInt(node->child1().node(), node->child2().node())) {
+ fixEdge<MachineIntUse>(node->child1());
+ fixEdge<MachineIntUse>(node->child2());
+ break;
+ }
if (Node::shouldSpeculateNumber(node->child1().node(), node->child2().node())) {
fixEdge<NumberUse>(node->child1());
fixEdge<NumberUse>(node->child2());
@@ -355,6 +378,12 @@
fixEdge<Int32Use>(node->child2());
break;
}
+ if (enableInt52()
+ && Node::shouldSpeculateMachineInt(node->child1().node(), node->child2().node())) {
+ fixEdge<MachineIntUse>(node->child1());
+ fixEdge<MachineIntUse>(node->child2());
+ break;
+ }
if (Node::shouldSpeculateNumber(node->child1().node(), node->child2().node())) {
fixEdge<NumberUse>(node->child1());
fixEdge<NumberUse>(node->child2());
@@ -476,6 +505,10 @@
fixEdge<KnownCellUse>(child1);
fixEdge<Int32Use>(child2);
fixEdge<Int32Use>(child3);
+ if (child3->prediction() & SpecInt52)
+ fixEdge<MachineIntUse>(child3);
+ else
+ fixEdge<Int32Use>(child3);
break;
case Array::Double:
fixEdge<KnownCellUse>(child1);
@@ -493,6 +526,8 @@
fixEdge<Int32Use>(child2);
if (child3->shouldSpeculateInt32())
fixEdge<Int32Use>(child3);
+ else if (child3->shouldSpeculateMachineInt())
+ fixEdge<MachineIntUse>(child3);
else
fixEdge<NumberUse>(child3);
break;
@@ -847,6 +882,8 @@
case CheckTierUpInLoop:
case CheckTierUpAtReturn:
case CheckTierUpAndOSREnter:
+ case Int52ToDouble:
+ case Int52ToValue:
RELEASE_ASSERT_NOT_REACHED();
break;
@@ -1189,6 +1226,9 @@
case FlushedInt32:
fixEdge<Int32Use>(node->child1());
break;
+ case FlushedInt52:
+ fixEdge<MachineIntUse>(node->child1());
+ break;
case FlushedCell:
fixEdge<CellUse>(node->child1());
break;
@@ -1203,6 +1243,23 @@
m_insertionSet.execute(block);
}
+ void fixupUntypedSetLocalsInBlock(BasicBlock* block)
+ {
+ if (!block)
+ return;
+ ASSERT(block->isReachable);
+ m_block = block;
+ for (m_indexInBlock = 0; m_indexInBlock < block->size(); ++m_indexInBlock) {
+ Node* node = m_currentNode = block->at(m_indexInBlock);
+ if (node->op() != SetLocal)
+ continue;
+
+ if (node->child1().useKind() == UntypedUse)
+ fixEdge<UntypedUse>(node->child1());
+ }
+ m_insertionSet.execute(block);
+ }
+
Node* checkArray(ArrayMode arrayMode, const CodeOrigin& codeOrigin, Node* array, Node* index, bool (*storageCheck)(const ArrayMode&) = canCSEStorage)
{
ASSERT(arrayMode.isSpecific());
@@ -1304,6 +1361,9 @@
if (node->op() != GetLocal)
return;
+ // FIXME: The way this uses alwaysUnboxSimplePrimitives() is suspicious.
+ // https://bugs.webkit.org/show_bug.cgi?id=121518
+
VariableAccessData* variable = node->variableAccessData();
switch (useKind) {
case Int32Use:
@@ -1321,6 +1381,10 @@
|| isBooleanSpeculation(variable->prediction()))
m_profitabilityChanged |= variable->mergeIsProfitableToUnbox(true);
break;
+ case MachineIntUse:
+ if (isMachineIntSpeculation(variable->prediction()))
+ m_profitabilityChanged |= variable->mergeIsProfitableToUnbox(true);
+ break;
case CellUse:
case KnownCellUse:
case ObjectUse:
@@ -1347,12 +1411,80 @@
template<UseKind useKind>
void fixEdge(Edge& edge, SpeculationDirection direction = BackwardSpeculation)
{
- if (isDouble(useKind) && edge->shouldSpeculateInt32ForArithmetic()) {
- injectInt32ToDoubleNode(edge, useKind, direction);
+ if (isDouble(useKind)) {
+ if (edge->shouldSpeculateInt32ForArithmetic()) {
+ injectInt32ToDoubleNode(edge, useKind, direction);
+ return;
+ }
+
+ if (enableInt52() && edge->shouldSpeculateMachineInt()) {
+ // Make all double uses of int52 values have an intermediate Int52ToDouble.
+ // This is for the same reason as Int52ToValue (see below) except that
+ // Int8ToDouble will convert int52's that fit in an int32 into a double
+ // rather than trying to create a boxed int32 like Int52ToValue does.
+
+ Node* result = m_insertionSet.insertNode(
+ m_indexInBlock, SpecInt52AsDouble, Int52ToDouble,
+ m_currentNode->codeOrigin, Edge(edge.node(), NumberUse));
+ edge = Edge(result, useKind);
+ return;
+ }
+ }
+
+ if (enableInt52() && useKind != MachineIntUse
+ && edge->shouldSpeculateMachineInt() && !edge->shouldSpeculateInt32()) {
+ // We make all non-int52 uses of int52 values have an intermediate Int52ToValue
+ // node to ensure that we handle this properly:
+ //
+ // a: SomeInt52
+ // b: ArithAdd(@a, ...)
+ // c: Call(..., @a)
+ // d: ArithAdd(@a, ...)
+ //
+ // Without an intermediate node and just labeling the uses, we will get:
+ //
+ // a: SomeInt52
+ // b: ArithAdd(Int52:@a, ...)
+ // c: Call(..., Untyped:@a)
+ // d: ArithAdd(Int52:@a, ...)
+ //
+ // And now the c->Untyped:@a edge will box the value of @a into a double. This
+ // is bad, because now the d->Int52:@a edge will either have to do double-to-int
+ // conversions, or will have to OSR exit unconditionally. Alternatively we could
+ // have the c->Untyped:@a edge box the value by copying rather than in-place.
+ // But these boxings are also costly so this wouldn't be great.
+ //
+ // The solution we use is to always have non-Int52 uses of predicted Int52's use
+ // an intervening Int52ToValue node:
+ //
+ // a: SomeInt52
+ // b: ArithAdd(Int52:@a, ...)
+ // x: Int52ToValue(Int52:@a)
+ // c: Call(..., Untyped:@x)
+ // d: ArithAdd(Int52:@a, ...)
+ //
+ // Note that even if we had multiple non-int52 uses of @a, the multiple
+ // Int52ToValue's would get CSE'd together. So the boxing would only happen once.
+ // At the same time, @a would continue to be represented as a native int52.
+ //
+ // An alternative would have been to insert ToNativeInt52 nodes on int52 uses of
+ // int52's. This would have handled the above example but would fall over for:
+ //
+ // a: SomeInt52
+ // b: Call(..., @a)
+ // c: ArithAdd(@a, ...)
+ //
+ // But the solution we use handles the above gracefully.
+
+ Node* result = m_insertionSet.insertNode(
+ m_indexInBlock, SpecInt52, Int52ToValue,
+ m_currentNode->codeOrigin, Edge(edge.node(), UntypedUse));
+ edge = Edge(result, useKind);
return;
}
observeUseKindOnNode<useKind>(edge.node());
+
edge.setUseKind(useKind);
}
@@ -1378,7 +1510,7 @@
void injectInt32ToDoubleNode(Edge& edge, UseKind useKind = NumberUse, SpeculationDirection direction = BackwardSpeculation)
{
Node* result = m_insertionSet.insertNode(
- m_indexInBlock, SpecInt48, Int32ToDouble,
+ m_indexInBlock, SpecInt52AsDouble, Int32ToDouble,
m_currentNode->codeOrigin, Edge(edge.node(), NumberUse));
if (direction == ForwardSpeculation)
result->mergeFlags(NodeExitsForward);
@@ -1434,13 +1566,20 @@
bool attemptToMakeIntegerAdd(Node* node)
{
AddSpeculationMode mode = m_graph.addSpeculationMode(node);
- if (mode == DontSpeculateInt32)
- return false;
+ if (mode != DontSpeculateInt32) {
+ truncateConstantsIfNecessary(node, mode);
+ fixEdge<Int32Use>(node->child1());
+ fixEdge<Int32Use>(node->child2());
+ return true;
+ }
- truncateConstantsIfNecessary(node, mode);
- fixEdge<Int32Use>(node->child1());
- fixEdge<Int32Use>(node->child2());
- return true;
+ if (m_graph.addShouldSpeculateMachineInt(node)) {
+ fixEdge<MachineIntUse>(node->child1());
+ fixEdge<MachineIntUse>(node->child2());
+ return true;
+ }
+
+ return false;
}
bool attemptToMakeGetArrayLength(Node* node)