DFG should support Int52 for local variables
authorfpizlo@apple.com <fpizlo@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 18 Sep 2013 01:31:04 +0000 (01:31 +0000)
committerfpizlo@apple.com <fpizlo@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 18 Sep 2013 01:31:04 +0000 (01:31 +0000)
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/OperandsInlines.h:
(JSC::::dumpInContext):
* bytecode/SpeculatedType.cpp:
(JSC::dumpSpeculation):
(JSC::speculationToAbbreviatedString):
(JSC::speculationFromValue):
* bytecode/SpeculatedType.h:
(JSC::isInt32SpeculationForArithmetic):
(JSC::isMachineIntSpeculationForArithmetic):
(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/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/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/DFGMinifiedNode.h:
(JSC::DFG::belongsInMinifiedGraph):
(JSC::DFG::MinifiedNode::hasChild):
* dfg/DFGNode.h:
(JSC::DFG::Node::shouldSpeculateNumber):
(JSC::DFG::Node::shouldSpeculateNumberExpectingDefined):
* dfg/DFGNodeFlags.h:
* dfg/DFGNodeType.h:
(JSC::DFG::forwardRewiringSelectionScore):
* 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::Int52s::operator[]):
(JSC::FTL::LowerDFGToLLVM::lowWhicheverInt52):
(JSC::FTL::LowerDFGToLLVM::lowWhicheverInt52s):
(JSC::FTL::LowerDFGToLLVM::lowOpposingInt52s):
(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/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):

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

81 files changed:
LayoutTests/ChangeLog
LayoutTests/js/regress/large-int-captured-expected.txt [new file with mode: 0644]
LayoutTests/js/regress/large-int-captured.html [new file with mode: 0644]
LayoutTests/js/regress/large-int-expected.txt [new file with mode: 0644]
LayoutTests/js/regress/large-int-neg-expected.txt [new file with mode: 0644]
LayoutTests/js/regress/large-int-neg.html [new file with mode: 0644]
LayoutTests/js/regress/large-int.html [new file with mode: 0644]
LayoutTests/js/regress/marsaglia-larger-ints-expected.txt [new file with mode: 0644]
LayoutTests/js/regress/marsaglia-larger-ints.html [new file with mode: 0644]
LayoutTests/js/regress/script-tests/large-int-captured.js [new file with mode: 0644]
LayoutTests/js/regress/script-tests/large-int-neg.js [new file with mode: 0644]
LayoutTests/js/regress/script-tests/large-int.js [new file with mode: 0644]
LayoutTests/js/regress/script-tests/marsaglia-larger-ints.js [new file with mode: 0644]
Source/JavaScriptCore/ChangeLog
Source/JavaScriptCore/assembler/MacroAssemblerX86_64.h
Source/JavaScriptCore/assembler/X86Assembler.h
Source/JavaScriptCore/bytecode/DataFormat.h
Source/JavaScriptCore/bytecode/ExitKind.cpp
Source/JavaScriptCore/bytecode/ExitKind.h
Source/JavaScriptCore/bytecode/OperandsInlines.h
Source/JavaScriptCore/bytecode/SpeculatedType.cpp
Source/JavaScriptCore/bytecode/SpeculatedType.h
Source/JavaScriptCore/bytecode/ValueRecovery.h
Source/JavaScriptCore/dfg/DFGAbstractInterpreter.h
Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h
Source/JavaScriptCore/dfg/DFGAbstractValue.cpp
Source/JavaScriptCore/dfg/DFGAbstractValue.h
Source/JavaScriptCore/dfg/DFGArrayMode.cpp
Source/JavaScriptCore/dfg/DFGAssemblyHelpers.h
Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp
Source/JavaScriptCore/dfg/DFGCSEPhase.cpp
Source/JavaScriptCore/dfg/DFGClobberize.h
Source/JavaScriptCore/dfg/DFGCommon.h
Source/JavaScriptCore/dfg/DFGFixupPhase.cpp
Source/JavaScriptCore/dfg/DFGFlushFormat.cpp
Source/JavaScriptCore/dfg/DFGFlushFormat.h
Source/JavaScriptCore/dfg/DFGGenerationInfo.h
Source/JavaScriptCore/dfg/DFGGraph.cpp
Source/JavaScriptCore/dfg/DFGGraph.h
Source/JavaScriptCore/dfg/DFGInPlaceAbstractState.cpp
Source/JavaScriptCore/dfg/DFGJITCode.cpp
Source/JavaScriptCore/dfg/DFGMinifiedNode.h
Source/JavaScriptCore/dfg/DFGNode.h
Source/JavaScriptCore/dfg/DFGNodeFlags.h
Source/JavaScriptCore/dfg/DFGNodeType.h
Source/JavaScriptCore/dfg/DFGOSRExitCompiler.cpp
Source/JavaScriptCore/dfg/DFGOSRExitCompiler64.cpp
Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp
Source/JavaScriptCore/dfg/DFGSafeToExecute.h
Source/JavaScriptCore/dfg/DFGSilentRegisterSavePlan.h
Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp
Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h
Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp
Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp
Source/JavaScriptCore/dfg/DFGUseKind.cpp
Source/JavaScriptCore/dfg/DFGUseKind.h
Source/JavaScriptCore/dfg/DFGValueSource.cpp
Source/JavaScriptCore/dfg/DFGValueSource.h
Source/JavaScriptCore/dfg/DFGVariableAccessData.h
Source/JavaScriptCore/ftl/FTLCArgumentGetter.cpp
Source/JavaScriptCore/ftl/FTLCArgumentGetter.h
Source/JavaScriptCore/ftl/FTLCapabilities.cpp
Source/JavaScriptCore/ftl/FTLExitValue.cpp
Source/JavaScriptCore/ftl/FTLExitValue.h
Source/JavaScriptCore/ftl/FTLIntrinsicRepository.h
Source/JavaScriptCore/ftl/FTLLowerDFGToLLVM.cpp
Source/JavaScriptCore/ftl/FTLOSRExitCompiler.cpp
Source/JavaScriptCore/ftl/FTLOutput.h
Source/JavaScriptCore/ftl/FTLValueFormat.cpp
Source/JavaScriptCore/ftl/FTLValueFormat.h
Source/JavaScriptCore/ftl/FTLValueSource.cpp
Source/JavaScriptCore/ftl/FTLValueSource.h
Source/JavaScriptCore/interpreter/Register.h
Source/JavaScriptCore/runtime/Arguments.cpp
Source/JavaScriptCore/runtime/IndexingType.cpp
Source/JavaScriptCore/runtime/JSCJSValue.h
Source/JavaScriptCore/runtime/JSCJSValueInlines.h
Source/WTF/ChangeLog
Source/WTF/wtf/PrintStream.h
Tools/ChangeLog
Tools/Scripts/run-jsc-stress-tests

index 206dedd..0e00fe4 100644 (file)
@@ -1,3 +1,29 @@
+2013-09-17  Filip Pizlo  <fpizlo@apple.com>
+
+        DFG should support Int52 for local variables
+        https://bugs.webkit.org/show_bug.cgi?id=121064
+
+        Reviewed by Oliver Hunt.
+
+        * 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):
+
 2013-09-17  Alexey Proskuryakov  <ap@apple.com>
 
         Removed some Lion specific results - these tests are failing on Lion bots despite these,
diff --git a/LayoutTests/js/regress/large-int-captured-expected.txt b/LayoutTests/js/regress/large-int-captured-expected.txt
new file mode 100644 (file)
index 0000000..964032e
--- /dev/null
@@ -0,0 +1,10 @@
+JSRegress/large-int-captured
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS no exception thrown
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/js/regress/large-int-captured.html b/LayoutTests/js/regress/large-int-captured.html
new file mode 100644 (file)
index 0000000..56e9096
--- /dev/null
@@ -0,0 +1,12 @@
+<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
+<html>
+<head>
+<script src="../../resources/js-test-pre.js"></script>
+</head>
+<body>
+<script src="resources/regress-pre.js"></script>
+<script src="script-tests/large-int-captured.js"></script>
+<script src="resources/regress-post.js"></script>
+<script src="../../resources/js-test-post.js"></script>
+</body>
+</html>
diff --git a/LayoutTests/js/regress/large-int-expected.txt b/LayoutTests/js/regress/large-int-expected.txt
new file mode 100644 (file)
index 0000000..ef7c2ea
--- /dev/null
@@ -0,0 +1,10 @@
+JSRegress/large-int
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS no exception thrown
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/js/regress/large-int-neg-expected.txt b/LayoutTests/js/regress/large-int-neg-expected.txt
new file mode 100644 (file)
index 0000000..965c0c3
--- /dev/null
@@ -0,0 +1,10 @@
+JSRegress/large-int-neg
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS no exception thrown
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/js/regress/large-int-neg.html b/LayoutTests/js/regress/large-int-neg.html
new file mode 100644 (file)
index 0000000..9ee348c
--- /dev/null
@@ -0,0 +1,12 @@
+<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
+<html>
+<head>
+<script src="../../resources/js-test-pre.js"></script>
+</head>
+<body>
+<script src="resources/regress-pre.js"></script>
+<script src="script-tests/large-int-neg.js"></script>
+<script src="resources/regress-post.js"></script>
+<script src="../../resources/js-test-post.js"></script>
+</body>
+</html>
diff --git a/LayoutTests/js/regress/large-int.html b/LayoutTests/js/regress/large-int.html
new file mode 100644 (file)
index 0000000..3025559
--- /dev/null
@@ -0,0 +1,12 @@
+<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
+<html>
+<head>
+<script src="../../resources/js-test-pre.js"></script>
+</head>
+<body>
+<script src="resources/regress-pre.js"></script>
+<script src="script-tests/large-int.js"></script>
+<script src="resources/regress-post.js"></script>
+<script src="../../resources/js-test-post.js"></script>
+</body>
+</html>
diff --git a/LayoutTests/js/regress/marsaglia-larger-ints-expected.txt b/LayoutTests/js/regress/marsaglia-larger-ints-expected.txt
new file mode 100644 (file)
index 0000000..ac1bb08
--- /dev/null
@@ -0,0 +1,10 @@
+JSRegress/marsaglia-larger-ints
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS no exception thrown
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/js/regress/marsaglia-larger-ints.html b/LayoutTests/js/regress/marsaglia-larger-ints.html
new file mode 100644 (file)
index 0000000..e8edded
--- /dev/null
@@ -0,0 +1,12 @@
+<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
+<html>
+<head>
+<script src="../../resources/js-test-pre.js"></script>
+</head>
+<body>
+<script src="resources/regress-pre.js"></script>
+<script src="script-tests/marsaglia-larger-ints.js"></script>
+<script src="resources/regress-post.js"></script>
+<script src="../../resources/js-test-post.js"></script>
+</body>
+</html>
diff --git a/LayoutTests/js/regress/script-tests/large-int-captured.js b/LayoutTests/js/regress/script-tests/large-int-captured.js
new file mode 100644 (file)
index 0000000..8f49a1e
--- /dev/null
@@ -0,0 +1,19 @@
+function foo(x, y) {
+    var z = x;
+    function bar() {
+        return z;
+    }
+    for (var i = 0; i < 3; ++i)
+        z += y;
+    return bar();
+}
+
+eval("// Don't compile me");
+
+var result = 0;
+
+for (var i = 0; i < 100000; ++i)
+    result += foo(1000000000, 1000000000);
+
+if (result != 400000000000000)
+    throw "Error: bad result: " + result;
diff --git a/LayoutTests/js/regress/script-tests/large-int-neg.js b/LayoutTests/js/regress/script-tests/large-int-neg.js
new file mode 100644 (file)
index 0000000..8f4cd23
--- /dev/null
@@ -0,0 +1,19 @@
+function foo(x, y) {
+    var z = x;
+    var w = 0;
+    for (var i = 0; i < 3; ++i) {
+        z += y;
+        w = -z;
+    }
+    return w + 1;
+}
+
+eval("// Don't compile me");
+
+var result = 0;
+
+for (var i = 0; i < 1000000; ++i)
+    result += foo(1000000000, 1000000000);
+
+if (result != -3999999999000000)
+    throw "Error: bad result: " + result;
diff --git a/LayoutTests/js/regress/script-tests/large-int.js b/LayoutTests/js/regress/script-tests/large-int.js
new file mode 100644 (file)
index 0000000..22d0cae
--- /dev/null
@@ -0,0 +1,16 @@
+function foo(x, y) {
+    var z = x;
+    for (var i = 0; i < 3; ++i)
+        z += y;
+    return z;
+}
+
+eval("// Don't compile me");
+
+var result = 0;
+
+for (var i = 0; i < 1000000; ++i)
+    result += foo(1000000000, 1000000000);
+
+if (result != 4000000000000000)
+    throw "Error: bad result: " + result;
diff --git a/LayoutTests/js/regress/script-tests/marsaglia-larger-ints.js b/LayoutTests/js/regress/script-tests/marsaglia-larger-ints.js
new file mode 100644 (file)
index 0000000..ad7121f
--- /dev/null
@@ -0,0 +1,21 @@
+function uint(x) {
+    if (x < 0)
+        return x + 4294967296;
+    return x;
+}
+
+function marsaglia(m_z, m_w, n) {
+    var result;
+    for (var i = 0; i < n; ++i) {
+        m_z = (36969 * uint(m_z & 65535) + (m_z >> 16)) | 0;
+        m_w = (18000 * uint(m_w & 65535) + (m_w >> 16)) | 0;
+        result = ((m_z << 16) + m_w) | 0;
+    }
+    return result;
+}
+
+var result = marsaglia(5, 7, 10000000);
+
+if (result != -1047364056)
+    throw "Error: bad result: " + result;
+
index 93a48eb..15672d1 100644 (file)
@@ -1,3 +1,309 @@
+2013-09-16  Filip Pizlo  <fpizlo@apple.com>
+
+        DFG should support Int52 for local variables
+        https://bugs.webkit.org/show_bug.cgi?id=121064
+
+        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/OperandsInlines.h:
+        (JSC::::dumpInContext):
+        * bytecode/SpeculatedType.cpp:
+        (JSC::dumpSpeculation):
+        (JSC::speculationToAbbreviatedString):
+        (JSC::speculationFromValue):
+        * bytecode/SpeculatedType.h:
+        (JSC::isInt32SpeculationForArithmetic):
+        (JSC::isMachineIntSpeculationForArithmetic):
+        (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/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/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/DFGMinifiedNode.h:
+        (JSC::DFG::belongsInMinifiedGraph):
+        (JSC::DFG::MinifiedNode::hasChild):
+        * dfg/DFGNode.h:
+        (JSC::DFG::Node::shouldSpeculateNumber):
+        (JSC::DFG::Node::shouldSpeculateNumberExpectingDefined):
+        * dfg/DFGNodeFlags.h:
+        * dfg/DFGNodeType.h:
+        (JSC::DFG::forwardRewiringSelectionScore):
+        * 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::Int52s::operator[]):
+        (JSC::FTL::LowerDFGToLLVM::lowWhicheverInt52):
+        (JSC::FTL::LowerDFGToLLVM::lowWhicheverInt52s):
+        (JSC::FTL::LowerDFGToLLVM::lowOpposingInt52s):
+        (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):
+
 2013-09-17  Filip Pizlo  <fpizlo@apple.com>
 
         Use CheckStructure for checking the types of typed arrays whenever possible
index bea8a51..29d34f2 100644 (file)
@@ -230,6 +230,16 @@ public:
         m_assembler.shlq_i8r(imm.m_value, dest);
     }
     
+    void rshift64(TrustedImm32 imm, RegisterID dest)
+    {
+        m_assembler.sarq_i8r(imm.m_value, dest);
+    }
+    
+    void mul64(RegisterID src, RegisterID dest)
+    {
+        m_assembler.imulq_rr(src, dest);
+    }
+    
     void neg64(RegisterID dest)
     {
         m_assembler.negq_r(dest);
@@ -530,6 +540,14 @@ public:
         return Jump(m_assembler.jCC(x86Condition(cond)));
     }
 
+    Jump branchMul64(ResultCondition cond, RegisterID src, RegisterID dest)
+    {
+        mul64(src, dest);
+        if (cond != Overflow)
+            m_assembler.testq_rr(dest, dest);
+        return Jump(m_assembler.jCC(x86Condition(cond)));
+    }
+
     Jump branchSub64(ResultCondition cond, TrustedImm32 imm, RegisterID dest)
     {
         sub64(imm, dest);
@@ -548,6 +566,12 @@ public:
         return branchSub64(cond, src2, dest);
     }
 
+    Jump branchNeg64(ResultCondition cond, RegisterID srcDest)
+    {
+        neg64(srcDest);
+        return Jump(m_assembler.jCC(x86Condition(cond)));
+    }
+
     ConvertibleLoadLabel convertibleLoadPtr(Address address, RegisterID dest)
     {
         ConvertibleLoadLabel result = ConvertibleLoadLabel(this);
@@ -595,6 +619,11 @@ public:
         return MacroAssemblerX86Common::branchTest8(cond, Address(scratchRegister), mask);
     }
 
+    void convertInt64ToDouble(RegisterID src, FPRegisterID dest)
+    {
+        m_assembler.cvtsi2sdq_rr(src, dest);
+    }
+
     static bool supportsFloatingPoint() { return true; }
     // See comment on MacroAssemblerARMv7::supportsFloatingPointTruncate()
     static bool supportsFloatingPointTruncate() { return true; }
index 770f90c..3a859ea 100644 (file)
@@ -829,13 +829,20 @@ public:
             m_formatter.immediate8(imm);
         }
     }
-#endif
+#endif // CPU(X86_64)
 
     void imull_rr(RegisterID src, RegisterID dst)
     {
         m_formatter.twoByteOp(OP2_IMUL_GvEv, dst, src);
     }
 
+#if CPU(X86_64)
+    void imulq_rr(RegisterID src, RegisterID dst)
+    {
+        m_formatter.twoByteOp64(OP2_IMUL_GvEv, dst, src);
+    }
+#endif // CPU(X86_64)
+
     void imull_mr(int offset, RegisterID base, RegisterID dst)
     {
         m_formatter.twoByteOp(OP2_IMUL_GvEv, dst, base, offset);
@@ -1611,6 +1618,14 @@ public:
         m_formatter.twoByteOp(OP2_CVTSI2SD_VsdEd, (RegisterID)dst, src);
     }
 
+#if CPU(X86_64)
+    void cvtsi2sdq_rr(RegisterID src, XMMRegisterID dst)
+    {
+        m_formatter.prefix(PRE_SSE_F2);
+        m_formatter.twoByteOp64(OP2_CVTSI2SD_VsdEd, (RegisterID)dst, src);
+    }
+#endif
+
     void cvtsi2sd_mr(int offset, RegisterID base, XMMRegisterID dst)
     {
         m_formatter.prefix(PRE_SSE_F2);
index d604808..bb9da4c 100644 (file)
@@ -39,10 +39,12 @@ namespace JSC {
 enum DataFormat {
     DataFormatNone = 0,
     DataFormatInt32 = 1,
-    DataFormatDouble = 2,
-    DataFormatBoolean = 3,
-    DataFormatCell = 4,
-    DataFormatStorage = 5,
+    DataFormatInt52 = 2, // Int52's are left-shifted by 16 by default.
+    DataFormatStrictInt52 = 3, // "Strict" Int52 means it's not shifted.
+    DataFormatDouble = 4,
+    DataFormatBoolean = 5,
+    DataFormatCell = 6,
+    DataFormatStorage = 7,
     DataFormatJS = 8,
     DataFormatJSInt32 = DataFormatJS | DataFormatInt32,
     DataFormatJSDouble = DataFormatJS | DataFormatDouble,
@@ -64,6 +66,10 @@ inline const char* dataFormatToString(DataFormat dataFormat)
         return "None";
     case DataFormatInt32:
         return "Int32";
+    case DataFormatInt52:
+        return "Int52";
+    case DataFormatStrictInt52:
+        return "StrictInt52";
     case DataFormatDouble:
         return "Double";
     case DataFormatCell:
index 8a451d6..dcb81bf 100644 (file)
@@ -52,8 +52,8 @@ const char* exitKindToString(ExitKind kind)
         return "Overflow";
     case NegativeZero:
         return "NegativeZero";
-    case Int48Overflow:
-        return "Int48Overflow";
+    case Int52Overflow:
+        return "Int52Overflow";
     case StoreToHole:
         return "StoreToHole";
     case LoadFromHole:
index 0c03b64..ec5a00c 100644 (file)
@@ -38,7 +38,7 @@ enum ExitKind {
     BadIndexingType, // We exited because an indexing type was wrong.
     Overflow, // We exited because of overflow.
     NegativeZero, // We exited because we encountered negative zero.
-    Int48Overflow, // We exited because of an Int48 overflow.
+    Int52Overflow, // We exited because of an Int52 overflow.
     StoreToHole, // We had a store to a hole.
     LoadFromHole, // We had a load from a hole.
     OutOfBounds, // We had an out-of-bounds access to an array.
index 160763b..74ad60b 100644 (file)
@@ -43,7 +43,7 @@ void Operands<T, Traits>::dumpInContext(PrintStream& out, DumpContext* context)
     for (size_t localIndex = 0; localIndex < numberOfLocals(); ++localIndex) {
         if (Traits::isEmptyForDump(local(localIndex)))
             continue;
-        out.print(comma, "r", localIndex, ":", inContext(local(localIndex), context));
+        out.print(comma, "loc", localIndex, ":", inContext(local(localIndex), context));
     }
 }
 
index 35d67f4..3917cca 100644 (file)
@@ -154,20 +154,18 @@ void dumpSpeculation(PrintStream& out, SpeculatedType value)
     }
     
     if (value & SpecInt32)
-        myOut.print("Int");
+        myOut.print("Int32");
     else
         isTop = false;
     
+    if (value & SpecInt52)
+        myOut.print("Int52");
+        
     if ((value & SpecDouble) == SpecDouble)
         myOut.print("Double");
     else {
-        if (value & SpecInt48AsDouble)
-            myOut.print("Int48asdouble");
-        else
-            isTop = false;
-        
-        if (value & SpecInt48)
-            myOut.print("Int48");
+        if (value & SpecInt52AsDouble)
+            myOut.print("Int52asdouble");
         else
             isTop = false;
         
@@ -243,13 +241,15 @@ static const char* speculationToAbbreviatedString(SpeculatedType prediction)
         return "<Cell>";
     if (isInt32Speculation(prediction))
         return "<Int32>";
-    if (isInt48AsDoubleSpeculation(prediction))
-        return "<Int48AsDouble>";
-    if (isInt48Speculation(prediction))
-        return "<Int48>";
+    if (isInt52AsDoubleSpeculation(prediction))
+        return "<Int52AsDouble>";
+    if (isInt52Speculation(prediction))
+        return "<Int52>";
+    if (isMachineIntSpeculation(prediction))
+        return "<MachineInt>";
     if (isDoubleSpeculation(prediction))
         return "<Double>";
-    if (isNumberSpeculation(prediction))
+    if (isFullNumberSpeculation(prediction))
         return "<Number>";
     if (isBooleanSpeculation(prediction))
         return "<Boolean>";
@@ -345,16 +345,11 @@ SpeculatedType speculationFromValue(JSValue value)
         return SpecInt32;
     if (value.isDouble()) {
         double number = value.asNumber();
-        if (number == number) {
-            int64_t asInt64 = static_cast<int64_t>(number);
-            if (asInt64 == number && (asInt64 || !std::signbit(number))
-                && asInt64 < (static_cast<int64_t>(1) << 47)
-                && asInt64 >= -(static_cast<int64_t>(1) << 47)) {
-                return SpecInt48AsDouble;
-            }
-            return SpecNonIntAsDouble;
-        }
-        return SpecDoubleNaN;
+        if (number != number)
+            return SpecDoubleNaN;
+        if (value.isMachineInt())
+            return SpecInt52AsDouble;
+        return SpecNonIntAsDouble;
     }
     if (value.isCell())
         return speculationFromCell(value.asCell());
index 6c7b4d1..eaf0af3 100644 (file)
@@ -38,46 +38,48 @@ namespace JSC {
 class Structure;
 
 typedef uint32_t SpeculatedType;
-static const SpeculatedType SpecNone              = 0x00000000; // We don't know anything yet.
-static const SpeculatedType SpecFinalObject       = 0x00000001; // It's definitely a JSFinalObject.
-static const SpeculatedType SpecArray             = 0x00000002; // It's definitely a JSArray.
-static const SpeculatedType SpecFunction          = 0x00000008; // It's definitely a JSFunction or one of its subclasses.
-static const SpeculatedType SpecInt8Array         = 0x00000010; // It's definitely an Int8Array or one of its subclasses.
-static const SpeculatedType SpecInt16Array        = 0x00000020; // It's definitely an Int16Array or one of its subclasses.
-static const SpeculatedType SpecInt32Array        = 0x00000040; // It's definitely an Int32Array or one of its subclasses.
-static const SpeculatedType SpecUint8Array        = 0x00000080; // It's definitely an Uint8Array or one of its subclasses.
-static const SpeculatedType SpecUint8ClampedArray = 0x00000100; // It's definitely an Uint8ClampedArray or one of its subclasses.
-static const SpeculatedType SpecUint16Array       = 0x00000200; // It's definitely an Uint16Array or one of its subclasses.
-static const SpeculatedType SpecUint32Array       = 0x00000400; // It's definitely an Uint32Array or one of its subclasses.
-static const SpeculatedType SpecFloat32Array      = 0x00000800; // It's definitely an Uint16Array or one of its subclasses.
-static const SpeculatedType SpecFloat64Array      = 0x00001000; // It's definitely an Uint16Array or one of its subclasses.
-static const SpeculatedType SpecTypedArrayView    = SpecInt8Array | SpecInt16Array | SpecInt32Array | SpecUint8Array | SpecUint8ClampedArray | SpecUint16Array | SpecUint32Array | SpecFloat32Array | SpecFloat64Array;
-static const SpeculatedType SpecArguments         = 0x00002000; // It's definitely an Arguments object.
-static const SpeculatedType SpecStringObject      = 0x00004000; // It's definitely a StringObject.
-static const SpeculatedType SpecObjectOther       = 0x00008000; // It's definitely an object but not JSFinalObject, JSArray, or JSFunction.
-static const SpeculatedType SpecObject            = 0x0000ffff; // Bitmask used for testing for any kind of object prediction.
-static const SpeculatedType SpecStringIdent       = 0x00010000; // It's definitely a JSString, and it's an identifier.
-static const SpeculatedType SpecStringVar         = 0x00020000; // It's definitely a JSString, and it's not an identifier.
-static const SpeculatedType SpecString            = 0x00030000; // It's definitely a JSString.
-static const SpeculatedType SpecCellOther         = 0x00040000; // It's definitely a JSCell but not a subclass of JSObject and definitely not a JSString.
-static const SpeculatedType SpecCell              = 0x0007ffff; // It's definitely a JSCell.
-static const SpeculatedType SpecInt32             = 0x00800000; // It's definitely an Int32.
-static const SpeculatedType SpecInt48             = 0x01000000; // It's definitely an Int48, it's inside a double, but it doesn't need to be.
-static const SpeculatedType SpecMachineInt        = 0x01800000; // It's something that we can do machine int arithmetic on.
-static const SpeculatedType SpecInt48AsDouble     = 0x02000000; // It's definitely an Int48 and it's inside a double.
-static const SpeculatedType SpecInteger           = 0x03800000; // It's definitely some kind of integer.
-static const SpeculatedType SpecNonIntAsDouble    = 0x04000000; // It's definitely not an Int48 but it's a real number and it's a double.
-static const SpeculatedType SpecDoubleReal        = 0x07000000; // It's definitely a non-NaN double.
-static const SpeculatedType SpecDoubleNaN         = 0x08000000; // It's definitely a NaN.
-static const SpeculatedType SpecDouble            = 0x0f000000; // It's either a non-NaN or a NaN double.
-static const SpeculatedType SpecRealNumber        = 0x07800000; // It's either an Int32 or a DoubleReal.
-static const SpeculatedType SpecNumber            = 0x0f800000; // It's either an Int32 or a Double.
-static const SpeculatedType SpecBoolean           = 0x10000000; // It's definitely a Boolean.
-static const SpeculatedType SpecOther             = 0x20000000; // It's definitely none of the above.
-static const SpeculatedType SpecHeapTop           = 0x3fffffff; // It can be any of the above.
-static const SpeculatedType SpecEmpty             = 0x40000000; // It's definitely an empty value marker.
-static const SpeculatedType SpecBytecodeTop       = 0x7fffffff; // It can be any of the above.
-static const SpeculatedType SpecFullTop           = 0x7fffffff; // It can be any of the above plus anything the DFG chooses.
+static const SpeculatedType SpecNone               = 0x00000000; // We don't know anything yet.
+static const SpeculatedType SpecFinalObject        = 0x00000001; // It's definitely a JSFinalObject.
+static const SpeculatedType SpecArray              = 0x00000002; // It's definitely a JSArray.
+static const SpeculatedType SpecFunction           = 0x00000008; // It's definitely a JSFunction or one of its subclasses.
+static const SpeculatedType SpecInt8Array          = 0x00000010; // It's definitely an Int8Array or one of its subclasses.
+static const SpeculatedType SpecInt16Array         = 0x00000020; // It's definitely an Int16Array or one of its subclasses.
+static const SpeculatedType SpecInt32Array         = 0x00000040; // It's definitely an Int32Array or one of its subclasses.
+static const SpeculatedType SpecUint8Array         = 0x00000080; // It's definitely an Uint8Array or one of its subclasses.
+static const SpeculatedType SpecUint8ClampedArray  = 0x00000100; // It's definitely an Uint8ClampedArray or one of its subclasses.
+static const SpeculatedType SpecUint16Array        = 0x00000200; // It's definitely an Uint16Array or one of its subclasses.
+static const SpeculatedType SpecUint32Array        = 0x00000400; // It's definitely an Uint32Array or one of its subclasses.
+static const SpeculatedType SpecFloat32Array       = 0x00000800; // It's definitely an Uint16Array or one of its subclasses.
+static const SpeculatedType SpecFloat64Array       = 0x00001000; // It's definitely an Uint16Array or one of its subclasses.
+static const SpeculatedType SpecTypedArrayView     = SpecInt8Array | SpecInt16Array | SpecInt32Array | SpecUint8Array | SpecUint8ClampedArray | SpecUint16Array | SpecUint32Array | SpecFloat32Array | SpecFloat64Array;
+static const SpeculatedType SpecArguments          = 0x00002000; // It's definitely an Arguments object.
+static const SpeculatedType SpecStringObject       = 0x00004000; // It's definitely a StringObject.
+static const SpeculatedType SpecObjectOther        = 0x00008000; // It's definitely an object but not JSFinalObject, JSArray, or JSFunction.
+static const SpeculatedType SpecObject             = 0x0000ffff; // Bitmask used for testing for any kind of object prediction.
+static const SpeculatedType SpecStringIdent        = 0x00010000; // It's definitely a JSString, and it's an identifier.
+static const SpeculatedType SpecStringVar          = 0x00020000; // It's definitely a JSString, and it's not an identifier.
+static const SpeculatedType SpecString             = 0x00030000; // It's definitely a JSString.
+static const SpeculatedType SpecCellOther          = 0x00040000; // It's definitely a JSCell but not a subclass of JSObject and definitely not a JSString.
+static const SpeculatedType SpecCell               = 0x0007ffff; // It's definitely a JSCell.
+static const SpeculatedType SpecInt32              = 0x00800000; // It's definitely an Int32.
+static const SpeculatedType SpecInt52              = 0x01000000; // It's definitely an Int52 and we intend it to unbox it.
+static const SpeculatedType SpecMachineInt         = 0x01800000; // It's something that we can do machine int arithmetic on.
+static const SpeculatedType SpecInt52AsDouble      = 0x02000000; // It's definitely an Int52 and it's inside a double.
+static const SpeculatedType SpecInteger            = 0x03800000; // It's definitely some kind of integer.
+static const SpeculatedType SpecNonIntAsDouble     = 0x04000000; // It's definitely not an Int52 but it's a real number and it's a double.
+static const SpeculatedType SpecDoubleReal         = 0x06000000; // It's definitely a non-NaN double.
+static const SpeculatedType SpecDoubleNaN          = 0x08000000; // It's definitely a NaN.
+static const SpeculatedType SpecDouble             = 0x0e000000; // It's either a non-NaN or a NaN double.
+static const SpeculatedType SpecBytecodeRealNumber = 0x06800000; // It's either an Int32 or a DoubleReal.
+static const SpeculatedType SpecFullRealNumber     = 0x07800000; // It's either an Int32 or a DoubleReal, or a Int52.
+static const SpeculatedType SpecBytecodeNumber     = 0x0e800000; // It's either an Int32 or a Double.
+static const SpeculatedType SpecFullNumber         = 0x0f800000; // It's either an Int32, Int52, or a Double.
+static const SpeculatedType SpecBoolean            = 0x10000000; // It's definitely a Boolean.
+static const SpeculatedType SpecOther              = 0x20000000; // It's definitely none of the above.
+static const SpeculatedType SpecHeapTop            = 0x3effffff; // It can be any of the above, except for SpecInt52.
+static const SpeculatedType SpecEmpty              = 0x40000000; // It's definitely an empty value marker.
+static const SpeculatedType SpecBytecodeTop        = 0x7effffff; // It can be any of the above, except for SpecInt52.
+static const SpeculatedType SpecFullTop            = 0x7fffffff; // It can be any of the above plus anything the DFG chooses.
 
 typedef bool (*SpeculatedTypeChecker)(SpeculatedType);
 
@@ -240,7 +242,7 @@ inline bool isInt32Speculation(SpeculatedType value)
 
 inline bool isInt32SpeculationForArithmetic(SpeculatedType value)
 {
-    return !(value & SpecDouble);
+    return !(value & (SpecDouble | SpecInt52));
 }
 
 inline bool isInt32SpeculationExpectingDefined(SpeculatedType value)
@@ -248,9 +250,9 @@ inline bool isInt32SpeculationExpectingDefined(SpeculatedType value)
     return isInt32Speculation(value & ~SpecOther);
 }
 
-inline bool isInt48Speculation(SpeculatedType value)
+inline bool isInt52Speculation(SpeculatedType value)
 {
-    return value == SpecInt48;
+    return value == SpecInt52;
 }
 
 inline bool isMachineIntSpeculation(SpeculatedType value)
@@ -265,12 +267,12 @@ inline bool isMachineIntSpeculationExpectingDefined(SpeculatedType value)
 
 inline bool isMachineIntSpeculationForArithmetic(SpeculatedType value)
 {
-    return !(value & (SpecDouble & ~SpecMachineInt));
+    return !(value & SpecDouble);
 }
 
-inline bool isInt48AsDoubleSpeculation(SpeculatedType value)
+inline bool isInt52AsDoubleSpeculation(SpeculatedType value)
 {
-    return value == SpecInt48AsDouble;
+    return value == SpecInt52AsDouble;
 }
 
 inline bool isIntegerSpeculation(SpeculatedType value)
@@ -293,19 +295,34 @@ inline bool isDoubleSpeculationForArithmetic(SpeculatedType value)
     return !!(value & SpecDouble);
 }
 
-inline bool isRealNumberSpeculation(SpeculatedType value)
+inline bool isBytecodeRealNumberSpeculation(SpeculatedType value)
+{
+    return !!(value & SpecBytecodeRealNumber) && !(value & ~SpecBytecodeRealNumber);
+}
+
+inline bool isFullRealNumberSpeculation(SpeculatedType value)
+{
+    return !!(value & SpecFullRealNumber) && !(value & ~SpecFullRealNumber);
+}
+
+inline bool isBytecodeNumberSpeculation(SpeculatedType value)
+{
+    return !!(value & SpecBytecodeNumber) && !(value & ~SpecBytecodeNumber);
+}
+
+inline bool isFullNumberSpeculation(SpeculatedType value)
 {
-    return !!(value & SpecRealNumber) && !(value & ~SpecRealNumber);
+    return !!(value & SpecFullNumber) && !(value & ~SpecFullNumber);
 }
 
-inline bool isNumberSpeculation(SpeculatedType value)
+inline bool isBytecodeNumberSpeculationExpectingDefined(SpeculatedType value)
 {
-    return !!(value & SpecNumber) && !(value & ~SpecNumber);
+    return isBytecodeNumberSpeculation(value & ~SpecOther);
 }
 
-inline bool isNumberSpeculationExpectingDefined(SpeculatedType value)
+inline bool isFullNumberSpeculationExpectingDefined(SpeculatedType value)
 {
-    return isNumberSpeculation(value & ~SpecOther);
+    return isFullNumberSpeculation(value & ~SpecOther);
 }
 
 inline bool isBooleanSpeculation(SpeculatedType value)
index 632e206..439770e 100644 (file)
@@ -44,12 +44,15 @@ enum ValueRecoveryTechnique {
     AlreadyInJSStack,
     // It's already in the stack but unboxed.
     AlreadyInJSStackAsUnboxedInt32,
+    AlreadyInJSStackAsUnboxedInt52,
     AlreadyInJSStackAsUnboxedCell,
     AlreadyInJSStackAsUnboxedBoolean,
     AlreadyInJSStackAsUnboxedDouble,
     // It's in a register.
     InGPR,
     UnboxedInt32InGPR,
+    UnboxedInt52InGPR,
+    UnboxedStrictInt52InGPR,
     UnboxedBooleanInGPR,
 #if USE(JSVALUE32_64)
     InPair,
@@ -60,6 +63,8 @@ enum ValueRecoveryTechnique {
     DisplacedInJSStack,
     // It's in the stack, at a different location, and it's unboxed.
     Int32DisplacedInJSStack,
+    Int52DisplacedInJSStack,
+    StrictInt52DisplacedInJSStack,
     DoubleDisplacedInJSStack,
     CellDisplacedInJSStack,
     BooleanDisplacedInJSStack,
@@ -95,6 +100,13 @@ public:
         return result;
     }
     
+    static ValueRecovery alreadyInJSStackAsUnboxedInt52()
+    {
+        ValueRecovery result;
+        result.m_technique = AlreadyInJSStackAsUnboxedInt52;
+        return result;
+    }
+    
     static ValueRecovery alreadyInJSStackAsUnboxedCell()
     {
         ValueRecovery result;
@@ -125,6 +137,10 @@ public:
         ValueRecovery result;
         if (dataFormat == DataFormatInt32)
             result.m_technique = UnboxedInt32InGPR;
+        else if (dataFormat == DataFormatInt52)
+            result.m_technique = UnboxedInt52InGPR;
+        else if (dataFormat == DataFormatStrictInt52)
+            result.m_technique = UnboxedStrictInt52InGPR;
         else if (dataFormat == DataFormatBoolean)
             result.m_technique = UnboxedBooleanInGPR;
         else
@@ -168,6 +184,14 @@ public:
             result.m_technique = Int32DisplacedInJSStack;
             break;
             
+        case DataFormatInt52:
+            result.m_technique = Int52DisplacedInJSStack;
+            break;
+            
+        case DataFormatStrictInt52:
+            result.m_technique = StrictInt52DisplacedInJSStack;
+            break;
+            
         case DataFormatDouble:
             result.m_technique = DoubleDisplacedInJSStack;
             break;
@@ -229,6 +253,7 @@ public:
         switch (technique()) {
         case AlreadyInJSStack:
         case AlreadyInJSStackAsUnboxedInt32:
+        case AlreadyInJSStackAsUnboxedInt52:
         case AlreadyInJSStackAsUnboxedCell:
         case AlreadyInJSStackAsUnboxedBoolean:
         case AlreadyInJSStackAsUnboxedDouble:
@@ -240,7 +265,7 @@ public:
     
     MacroAssembler::RegisterID gpr() const
     {
-        ASSERT(m_technique == InGPR || m_technique == UnboxedInt32InGPR || m_technique == UnboxedBooleanInGPR || m_technique == UInt32InGPR);
+        ASSERT(m_technique == InGPR || m_technique == UnboxedInt32InGPR || m_technique == UnboxedBooleanInGPR || m_technique == UInt32InGPR || m_technique == UnboxedInt52InGPR || m_technique == UnboxedStrictInt52InGPR);
         return m_source.gpr;
     }
     
@@ -266,7 +291,7 @@ public:
     
     VirtualRegister virtualRegister() const
     {
-        ASSERT(m_technique == DisplacedInJSStack || m_technique == Int32DisplacedInJSStack || m_technique == DoubleDisplacedInJSStack || m_technique == CellDisplacedInJSStack || m_technique == BooleanDisplacedInJSStack);
+        ASSERT(m_technique == DisplacedInJSStack || m_technique == Int32DisplacedInJSStack || m_technique == DoubleDisplacedInJSStack || m_technique == CellDisplacedInJSStack || m_technique == BooleanDisplacedInJSStack || m_technique == Int52DisplacedInJSStack || m_technique == StrictInt52DisplacedInJSStack);
         return m_source.virtualReg;
     }
     
@@ -285,6 +310,9 @@ public:
         case AlreadyInJSStackAsUnboxedInt32:
             out.printf("(int32)");
             return;
+        case AlreadyInJSStackAsUnboxedInt52:
+            out.printf("(int52)");
+            return;
         case AlreadyInJSStackAsUnboxedCell:
             out.printf("(cell)");
             return;
@@ -300,6 +328,12 @@ public:
         case UnboxedInt32InGPR:
             out.printf("int32(%%r%d)", gpr());
             return;
+        case UnboxedInt52InGPR:
+            out.printf("int52(%%r%d)", gpr());
+            return;
+        case UnboxedStrictInt52InGPR:
+            out.printf("strictInt52(%%r%d)", gpr());
+            return;
         case UnboxedBooleanInGPR:
             out.printf("bool(%%r%d)", gpr());
             return;
@@ -320,6 +354,12 @@ public:
         case Int32DisplacedInJSStack:
             out.printf("*int32(%d)", virtualRegister());
             return;
+        case Int52DisplacedInJSStack:
+            out.printf("*int52(%d)", virtualRegister());
+            return;
+        case StrictInt52DisplacedInJSStack:
+            out.printf("*strictInt52(%d)", virtualRegister());
+            return;
         case DoubleDisplacedInJSStack:
             out.printf("*double(%d)", virtualRegister());
             return;
index f0e5e42..eb4e521 100644 (file)
@@ -60,7 +60,7 @@ public:
     
     bool needsTypeCheck(Node* node, SpeculatedType typesPassedThrough)
     {
-        return forNode(node).m_type & ~typesPassedThrough;
+        return !forNode(node).isType(typesPassedThrough);
     }
     
     bool needsTypeCheck(Edge edge, SpeculatedType typesPassedThrough)
@@ -168,7 +168,7 @@ private:
     ALWAYS_INLINE void filterByType(Node* node, Edge& edge, SpeculatedType type)
     {
         AbstractValue& value = forNode(edge);
-        if (value.m_type & ~type) {
+        if (!value.isType(type)) {
             node->setCanExit(true);
             edge.setProofStatus(NeedsCheck);
         } else
index 7cd084c..6be317b 100644 (file)
@@ -310,6 +310,29 @@ bool AbstractInterpreter<AbstractStateType>::executeEffects(unsigned clobberLimi
         break;
     }
         
+    case Int52ToDouble: {
+        JSValue child = forNode(node->child1()).value();
+        if (child && child.isNumber()) {
+            setConstant(node, child);
+            break;
+        }
+        forNode(node).setType(SpecDouble);
+        break;
+    }
+        
+    case Int52ToValue: {
+        JSValue child = forNode(node->child1()).value();
+        if (child && child.isNumber()) {
+            setConstant(node, child);
+            break;
+        }
+        SpeculatedType type = forNode(node->child1()).m_type;
+        if (type & SpecInt52)
+            type = (type | SpecInt32 | SpecInt52AsDouble) & ~SpecInt52;
+        forNode(node).setType(type);
+        break;
+    }
+        
     case ValueAdd:
     case ArithAdd: {
         JSValue left = forNode(node->child1()).value();
@@ -324,9 +347,15 @@ bool AbstractInterpreter<AbstractStateType>::executeEffects(unsigned clobberLimi
             if (!bytecodeCanTruncateInteger(node->arithNodeFlags()))
                 node->setCanExit(true);
             break;
+        case MachineIntUse:
+            forNode(node).setType(SpecInt52);
+            if (!forNode(node->child1()).isType(SpecInt32)
+                || !forNode(node->child2()).isType(SpecInt32))
+                node->setCanExit(true);
+            break;
         case NumberUse:
-            if (isRealNumberSpeculation(forNode(node->child1()).m_type)
-                && isRealNumberSpeculation(forNode(node->child2()).m_type))
+            if (isFullRealNumberSpeculation(forNode(node->child1()).m_type)
+                && isFullRealNumberSpeculation(forNode(node->child2()).m_type))
                 forNode(node).setType(SpecDoubleReal);
             else
                 forNode(node).setType(SpecDouble);
@@ -334,7 +363,7 @@ bool AbstractInterpreter<AbstractStateType>::executeEffects(unsigned clobberLimi
         default:
             RELEASE_ASSERT(node->op() == ValueAdd);
             clobberWorld(node->codeOrigin, clobberLimit);
-            forNode(node).setType(SpecString | SpecInt32 | SpecNumber);
+            forNode(node).setType(SpecString | SpecBytecodeNumber);
             break;
         }
         break;
@@ -358,6 +387,12 @@ bool AbstractInterpreter<AbstractStateType>::executeEffects(unsigned clobberLimi
             if (!bytecodeCanTruncateInteger(node->arithNodeFlags()))
                 node->setCanExit(true);
             break;
+        case MachineIntUse:
+            forNode(node).setType(SpecInt52);
+            if (!forNode(node->child1()).isType(SpecInt32)
+                || !forNode(node->child2()).isType(SpecInt32))
+                node->setCanExit(true);
+            break;
         case NumberUse:
             forNode(node).setType(SpecDouble);
             break;
@@ -380,6 +415,13 @@ bool AbstractInterpreter<AbstractStateType>::executeEffects(unsigned clobberLimi
             if (!bytecodeCanTruncateInteger(node->arithNodeFlags()))
                 node->setCanExit(true);
             break;
+        case MachineIntUse:
+            forNode(node).setType(SpecInt52);
+            if (m_state.forNode(node->child1()).couldBeType(SpecInt52))
+                node->setCanExit(true);
+            if (!bytecodeCanIgnoreNegativeZero(node->arithNodeFlags()))
+                node->setCanExit(true);
+            break;
         case NumberUse:
             forNode(node).setType(SpecDouble);
             break;
@@ -404,9 +446,13 @@ bool AbstractInterpreter<AbstractStateType>::executeEffects(unsigned clobberLimi
                 || !bytecodeCanIgnoreNegativeZero(node->arithNodeFlags()))
                 node->setCanExit(true);
             break;
+        case MachineIntUse:
+            forNode(node).setType(SpecInt52);
+            node->setCanExit(true);
+            break;
         case NumberUse:
-            if (isRealNumberSpeculation(forNode(node->child1()).m_type)
-                || isRealNumberSpeculation(forNode(node->child2()).m_type))
+            if (isFullRealNumberSpeculation(forNode(node->child1()).m_type)
+                || isFullRealNumberSpeculation(forNode(node->child2()).m_type))
                 forNode(node).setType(SpecDoubleReal);
             else
                 forNode(node).setType(SpecDouble);
@@ -586,7 +632,7 @@ bool AbstractInterpreter<AbstractStateType>::executeEffects(unsigned clobberLimi
             break;
         }
         
-        if (isNumberSpeculation(abstractChild.m_type)) {
+        if (isFullNumberSpeculation(abstractChild.m_type)) {
             setConstant(node, vm->smallStrings.numberString());
             break;
         }
@@ -811,6 +857,8 @@ bool AbstractInterpreter<AbstractStateType>::executeEffects(unsigned clobberLimi
         case Array::Uint32Array:
             if (node->shouldSpeculateInt32())
                 forNode(node).setType(SpecInt32);
+            else if (enableInt52() && node->shouldSpeculateMachineInt())
+                forNode(node).setType(SpecInt52);
             else
                 forNode(node).setType(SpecDouble);
             break;
@@ -863,7 +911,7 @@ bool AbstractInterpreter<AbstractStateType>::executeEffects(unsigned clobberLimi
     case ArrayPush:
         node->setCanExit(true);
         clobberWorld(node->codeOrigin, clobberLimit);
-        forNode(node).setType(SpecNumber);
+        forNode(node).setType(SpecBytecodeNumber);
         break;
             
     case ArrayPop:
@@ -934,8 +982,8 @@ bool AbstractInterpreter<AbstractStateType>::executeEffects(unsigned clobberLimi
         // NB. The more canonical way of writing this would have been:
         //
         // destination = source;
-        // if (destination.m_type & !(SpecNumber | SpecString | SpecBoolean)) {
-        //     destination.filter(SpecNumber | SpecString | SpecBoolean);
+        // if (destination.m_type & !(SpecFullNumber | SpecString | SpecBoolean)) {
+        //     destination.filter(SpecFullNumber | SpecString | SpecBoolean);
         //     AbstractValue string;
         //     string.set(vm->stringStructure);
         //     destination.merge(string);
@@ -955,7 +1003,7 @@ bool AbstractInterpreter<AbstractStateType>::executeEffects(unsigned clobberLimi
         clobberWorld(node->codeOrigin, clobberLimit);
         
         SpeculatedType type = source.m_type;
-        if (type & ~(SpecNumber | SpecString | SpecBoolean))
+        if (type & ~(SpecFullNumber | SpecString | SpecBoolean))
             type = (SpecHeapTop & ~SpecCell) | SpecString;
 
         destination.setType(type);
index 9f634a5..37215b2 100644 (file)
@@ -67,6 +67,8 @@ void AbstractValue::set(Graph& graph, JSValue value)
     }
         
     m_type = speculationFromValue(value);
+    if (m_type == SpecInt52AsDouble)
+        m_type = SpecInt52;
     m_value = value;
         
     checkConsistency();
@@ -227,6 +229,7 @@ FiltrationResult AbstractValue::normalizeClarity()
     return result;
 }
 
+#if !ASSERT_DISABLED
 void AbstractValue::checkConsistency() const
 {
     if (!(m_type & SpecCell)) {
@@ -238,14 +241,19 @@ void AbstractValue::checkConsistency() const
     if (isClear())
         ASSERT(!m_value);
     
-    if (!!m_value)
-        ASSERT(mergeSpeculations(m_type, speculationFromValue(m_value)) == m_type);
+    if (!!m_value) {
+        SpeculatedType type = m_type;
+        if (type & SpecInt52)
+            type |= SpecInt52AsDouble;
+        ASSERT(mergeSpeculations(type, speculationFromValue(m_value)) == type);
+    }
     
     // Note that it's possible for a prediction like (Final, []). This really means that
     // the value is bottom and that any code that uses the value is unreachable. But
     // we don't want to get pedantic about this as it would only increase the computational
     // complexity of the code.
 }
+#endif
 
 void AbstractValue::dump(PrintStream& out) const
 {
index ec2d2fa..db313d2 100644 (file)
@@ -185,6 +185,16 @@ struct AbstractValue {
         checkConsistency();
     }
     
+    bool couldBeType(SpeculatedType desiredType)
+    {
+        return !!(m_type & desiredType);
+    }
+    
+    bool isType(SpeculatedType desiredType)
+    {
+        return !(m_type & ~desiredType);
+    }
+    
     FiltrationResult filter(Graph&, const StructureSet&);
     
     FiltrationResult filterArrayModes(ArrayModes arrayModes);
@@ -193,22 +203,6 @@ struct AbstractValue {
     
     FiltrationResult filterByValue(JSValue value);
     
-    bool validateType(JSValue value) const
-    {
-        if (isHeapTop())
-            return true;
-        
-        if (mergeSpeculations(m_type, speculationFromValue(value)) != m_type)
-            return false;
-        
-        if (value.isEmpty()) {
-            ASSERT(m_type & SpecEmpty);
-            return true;
-        }
-        
-        return true;
-    }
-    
     bool validate(JSValue value) const
     {
         if (isHeapTop())
@@ -251,7 +245,11 @@ struct AbstractValue {
             || !arrayModesAreClearOrTop(m_arrayModes);
     }
     
+#if ASSERT_DISABLED
+    void checkConsistency() const { }
+#else
     void checkConsistency() const;
+#endif
     
     void dumpInContext(PrintStream&, DumpContext*) const;
     void dump(PrintStream&) const;
@@ -363,6 +361,29 @@ private:
         m_arrayModes = ALL_ARRAY_MODES;
     }
     
+    bool validateType(JSValue value) const
+    {
+        if (isHeapTop())
+            return true;
+        
+        // Constant folding always represents Int52's in a double (i.e. Int52AsDouble).
+        // So speculationFromValue(value) for an Int52 value will return Int52AsDouble,
+        // and that's fine - the type validates just fine.
+        SpeculatedType type = m_type;
+        if (type & SpecInt52)
+            type |= SpecInt52AsDouble;
+        
+        if (mergeSpeculations(type, speculationFromValue(value)) != type)
+            return false;
+        
+        if (value.isEmpty()) {
+            ASSERT(m_type & SpecEmpty);
+            return true;
+        }
+        
+        return true;
+    }
+    
     void makeTop(SpeculatedType top)
     {
         m_type |= top;
index 652184d..2785cf4 100644 (file)
@@ -163,21 +163,21 @@ ArrayMode ArrayMode::refine(SpeculatedType base, SpeculatedType index, Speculate
             return withType(Array::ForceExit);
         if (isInt32Speculation(value))
             return withTypeAndConversion(Array::Int32, Array::Convert);
-        if (isNumberSpeculation(value))
+        if (isFullNumberSpeculation(value))
             return withTypeAndConversion(Array::Double, Array::Convert);
         return withTypeAndConversion(Array::Contiguous, Array::Convert);
         
     case Array::Int32:
         if (!value || isInt32Speculation(value))
             return *this;
-        if (isNumberSpeculation(value))
+        if (isFullNumberSpeculation(value))
             return withTypeAndConversion(Array::Double, Array::Convert);
         return withTypeAndConversion(Array::Contiguous, Array::Convert);
         
     case Array::Double:
         if (flags & NodeBytecodeUsesAsInt)
             return withTypeAndConversion(Array::Contiguous, Array::RageConvert);
-        if (!value || isNumberSpeculation(value))
+        if (!value || isFullNumberSpeculation(value))
             return *this;
         return withTypeAndConversion(Array::Contiguous, Array::Convert);
         
index 7b11002..be615ad 100644 (file)
@@ -293,6 +293,24 @@ public:
         move64ToDouble(gpr, fpr);
         return fpr;
     }
+    
+    void boxInt52(GPRReg source, GPRReg target, GPRReg scratch, FPRReg fpScratch)
+    {
+        // Is it an int32?
+        signExtend32ToPtr(source, scratch);
+        Jump isInt32 = branch64(Equal, source, scratch);
+        
+        // Nope, it's not, but regT0 contains the int64 value.
+        convertInt64ToDouble(source, fpScratch);
+        boxDouble(fpScratch, target);
+        Jump done = jump();
+        
+        isInt32.link(this);
+        zeroExtend32ToPtr(source, target);
+        or64(GPRInfo::tagTypeNumberRegister, target);
+        
+        done.link(this);
+    }
 #endif
 
 #if USE(JSVALUE32_64)
index 709b7e7..18521bd 100644 (file)
@@ -874,12 +874,19 @@ private:
         case UInt32ToNumber:
         case ArithAdd:
         case ArithSub:
-        case ArithNegate:
         case ValueAdd:
         case ArithMod: // for ArithMod "MayOverflow" means we tried to divide by zero, or we saw double.
             node->mergeFlags(NodeMayOverflow);
             break;
             
+        case ArithNegate:
+            // Currently we can't tell the difference between a negation overflowing
+            // (i.e. -(1 << 31)) or generating negative zero (i.e. -0). If it took slow
+            // path then we assume that it did both of those things.
+            node->mergeFlags(NodeMayOverflow);
+            node->mergeFlags(NodeMayNegZero);
+            break;
+
         case ArithMul:
             if (m_inlineStackTop->m_profiledBlock->likelyToTakeDeepestSlowCase(m_currentIndex)
                 || m_inlineStackTop->m_exitProfile.hasExitSite(m_currentIndex, Overflow)) {
index 3ced528..ca9a121 100644 (file)
@@ -63,21 +63,6 @@ public:
     
 private:
     
-    Node* canonicalize(Node* node)
-    {
-        if (!node)
-            return 0;
-        
-        if (node->op() == ValueToInt32)
-            node = node->child1().node();
-        
-        return node;
-    }
-    Node* canonicalize(Edge edge)
-    {
-        return canonicalize(edge.node());
-    }
-    
     unsigned endIndexForPureCSE()
     {
         unsigned result = m_lastSeen[m_currentNode->op()];
@@ -94,9 +79,9 @@ private:
 
     Node* pureCSE(Node* node)
     {
-        Node* child1 = canonicalize(node->child1());
-        Node* child2 = canonicalize(node->child2());
-        Node* child3 = canonicalize(node->child3());
+        Edge child1 = node->child1();
+        Edge child2 = node->child2();
+        Edge child3 = node->child3();
         
         for (unsigned i = endIndexForPureCSE(); i--;) {
             Node* otherNode = m_currentBlock->at(i);
@@ -109,19 +94,19 @@ private:
             if (node->arithNodeFlags() != otherNode->arithNodeFlags())
                 continue;
             
-            Node* otherChild = canonicalize(otherNode->child1());
+            Edge otherChild = otherNode->child1();
             if (!otherChild)
                 return otherNode;
             if (otherChild != child1)
                 continue;
             
-            otherChild = canonicalize(otherNode->child2());
+            otherChild = otherNode->child2();
             if (!otherChild)
                 return otherNode;
             if (otherChild != child2)
                 continue;
             
-            otherChild = canonicalize(otherNode->child3());
+            otherChild = otherNode->child3();
             if (!otherChild)
                 return otherNode;
             if (otherChild != child3)
@@ -377,21 +362,21 @@ private:
     {
         for (unsigned i = m_indexInBlock; i--;) {
             Node* node = m_currentBlock->at(i);
-            if (node == child1 || node == canonicalize(child2)
+            if (node == child1 || node == child2
                 break;
 
             switch (node->op()) {
             case GetByVal:
                 if (!m_graph.byValIsPure(node))
                     return 0;
-                if (node->child1() == child1 && canonicalize(node->child2()) == canonicalize(child2))
+                if (node->child1() == child1 && node->child2() == child2)
                     return node;
                 break;
             case PutByVal:
             case PutByValAlias: {
                 if (!m_graph.byValIsPure(node))
                     return 0;
-                if (m_graph.varArgChild(node, 0) == child1 && canonicalize(m_graph.varArgChild(node, 1)) == canonicalize(child2))
+                if (m_graph.varArgChild(node, 0) == child1 && m_graph.varArgChild(node, 1) == child2)
                     return m_graph.varArgChild(node, 2).node();
                 // We must assume that the PutByVal will clobber the location we're getting from.
                 // FIXME: We can do better; if we know that the PutByVal is accessing an array of a
@@ -1090,6 +1075,8 @@ private:
         case CompareEqConstant:
         case ValueToInt32:
         case MakeRope:
+        case Int52ToDouble:
+        case Int52ToValue:
             if (cseMode == StoreElimination)
                 break;
             setReplacement(pureCSE(node));
index e82fd71..5f14e24 100644 (file)
@@ -112,6 +112,8 @@ void clobberize(Graph& graph, Node* node, ReadFunctor& read, WriteFunctor& write
     case LogicalNot:
     case Int32ToDouble:
     case ExtractOSREntryLocal:
+    case Int52ToDouble:
+    case Int52ToValue:
         return;
         
     case MovHintAndCheck:
@@ -180,6 +182,7 @@ void clobberize(Graph& graph, Node* node, ReadFunctor& read, WriteFunctor& write
         switch (node->binaryUseKind()) {
         case Int32Use:
         case NumberUse:
+        case MachineIntUse:
             return;
         case UntypedUse:
             read(World);
index 68199a8..a010d1d 100644 (file)
@@ -143,6 +143,15 @@ inline bool enableConcurrentJIT()
 #endif
 }
 
+inline bool enableInt52()
+{
+#if USE(JSVALUE64)
+    return true;
+#else
+    return false;
+#endif
+}
+
 enum SpillRegistersMode { NeedToSpill, DontSpill };
 
 enum NoResultTag { NoResult };
index d03f63e..e862d63 100644 (file)
@@ -64,6 +64,9 @@ public:
                 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 @@ private:
         switch (op) {
         case SetLocal: {
             // This gets handled by fixupSetLocalsInBlock().
-            break;
+            return;
         }
             
         case BitAnd:
@@ -124,6 +127,11 @@ private:
                 break;
             }
             
+            if (node->child1()->shouldSpeculateMachineInt()) {
+                fixEdge<MachineIntUse>(node->child1());
+                break;
+            }
+            
             if (node->child1()->shouldSpeculateNumber()) {
                 fixEdge<NumberUse>(node->child1());
                 break;
@@ -197,6 +205,10 @@ private:
                 fixEdge<Int32Use>(node->child1());
                 break;
             }
+            if (m_graph.negateShouldSpeculateMachineInt(node)) {
+                fixEdge<MachineIntUse>(node->child1());
+                break;
+            }
             fixEdge<NumberUse>(node->child1());
             break;
         }
@@ -207,6 +219,11 @@ private:
                 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 @@ private:
                 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 @@ private:
                 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 @@ private:
                 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 @@ private:
                 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 @@ private:
         case CheckTierUpInLoop:
         case CheckTierUpAtReturn:
         case CheckTierUpAndOSREnter:
+        case Int52ToDouble:
+        case Int52ToValue:
             RELEASE_ASSERT_NOT_REACHED();
             break;
         
@@ -1189,6 +1226,9 @@ private:
             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 @@ private:
         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 @@ private:
         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 @@ private:
                 || 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 @@ private:
     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 @@ private:
     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 @@ private:
     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)
index 54d8e6b..8e3f26b 100644 (file)
@@ -41,6 +41,9 @@ void printInternal(PrintStream& out, FlushFormat format)
     case FlushedInt32:
         out.print("FlushedInt32");
         return;
+    case FlushedInt52:
+        out.print("FlushedInt52");
+        return;
     case FlushedDouble:
         out.print("FlushedDouble");
         return;
index 7c75406..cbcea8d 100644 (file)
@@ -40,6 +40,7 @@ namespace JSC { namespace DFG {
 enum FlushFormat {
     DeadFlush,
     FlushedInt32,
+    FlushedInt52,
     FlushedDouble,
     FlushedCell,
     FlushedBoolean,
@@ -55,6 +56,8 @@ inline NodeFlags resultFor(FlushFormat format)
         return NodeResultJS;
     case FlushedInt32:
         return NodeResultInt32;
+    case FlushedInt52:
+        return NodeResultInt52;
     case FlushedDouble:
         return NodeResultNumber;
     case FlushedBoolean:
@@ -74,6 +77,8 @@ inline UseKind useKindFor(FlushFormat format)
         return CellUse;
     case FlushedInt32:
         return Int32Use;
+    case FlushedInt52:
+        return MachineIntUse;
     case FlushedDouble:
         return NumberUse;
     case FlushedBoolean:
index 68b299b..e3330fa 100644 (file)
@@ -86,6 +86,19 @@ public:
     {
         initGPR(node, useCount, gpr, DataFormatInt32);
     }
+    void initInt52(Node* node, uint32_t useCount, GPRReg reg, DataFormat format)
+    {
+        ASSERT(format == DataFormatInt52 || format == DataFormatStrictInt52);
+        initGPR(node, useCount, reg, format);
+    }
+    void initInt52(Node* node, uint32_t useCount, GPRReg reg)
+    {
+        initGPR(node, useCount, reg, DataFormatInt52);
+    }
+    void initStrictInt52(Node* node, uint32_t useCount, GPRReg reg)
+    {
+        initGPR(node, useCount, reg, DataFormatStrictInt52);
+    }
 #if USE(JSVALUE64)
     void initJSValue(Node* node, uint32_t useCount, GPRReg gpr, DataFormat format = DataFormatJS)
     {
@@ -187,6 +200,11 @@ public:
     // Get the format of the value as it is spilled in the JSStack (or 'none').
     DataFormat spillFormat() { return m_spillFormat; }
     
+    bool isFormat(DataFormat expectedFormat)
+    {
+        return registerFormat() == expectedFormat || spillFormat() == expectedFormat;
+    }
+    
     bool isJSFormat(DataFormat expectedFormat)
     {
         return JSC::isJSFormat(registerFormat(), expectedFormat) || JSC::isJSFormat(spillFormat(), expectedFormat);
@@ -197,6 +215,16 @@ public:
         return isJSFormat(DataFormatJSInt32);
     }
     
+    bool isInt52()
+    {
+        return isFormat(DataFormatInt52);
+    }
+    
+    bool isStrictInt52()
+    {
+        return isFormat(DataFormatStrictInt52);
+    }
+    
     bool isJSDouble()
     {
         return isJSFormat(DataFormatJSDouble);
@@ -314,6 +342,19 @@ public:
     {
         fillGPR(stream, gpr, DataFormatInt32);
     }
+    void fillInt52(VariableEventStream& stream, GPRReg gpr, DataFormat format)
+    {
+        ASSERT(format == DataFormatInt52 || format == DataFormatStrictInt52);
+        fillGPR(stream, gpr, format);
+    }
+    void fillInt52(VariableEventStream& stream, GPRReg gpr)
+    {
+        fillGPR(stream, gpr, DataFormatInt52);
+    }
+    void fillStrictInt52(VariableEventStream& stream, GPRReg gpr)
+    {
+        fillGPR(stream, gpr, DataFormatStrictInt52);
+    }
     void fillBoolean(VariableEventStream& stream, GPRReg gpr)
     {
         fillGPR(stream, gpr, DataFormatBoolean);
index f08bba1..fd3908c 100644 (file)
@@ -236,14 +236,14 @@ void Graph::dump(PrintStream& out, const char* prefix, Node* node, DumpContext*
         if (operandIsArgument(operand))
             out.print(comma, "arg", operandToArgument(operand), "(", VariableAccessDataDump(*this, variableAccessData), ")");
         else
-            out.print(comma, "r", operand, "(", VariableAccessDataDump(*this, variableAccessData), ")");
+            out.print(comma, "loc", operandToLocal(operand), "(", VariableAccessDataDump(*this, variableAccessData), ")");
     }
     if (node->hasUnlinkedLocal()) {
         int operand = node->unlinkedLocal();
         if (operandIsArgument(operand))
             out.print(comma, "arg", operandToArgument(operand));
         else
-            out.print(comma, "r", operand);
+            out.print(comma, "loc", operandToLocal(operand));
     }
     if (node->hasConstantBuffer()) {
         out.print(comma);
index 24853f1..dbc1721 100644 (file)
@@ -230,16 +230,19 @@ public:
     
     bool addShouldSpeculateMachineInt(Node* add)
     {
+        if (!enableInt52())
+            return false;
+        
         Node* left = add->child1().node();
         Node* right = add->child2().node();
 
         bool speculation;
         if (add->op() == ValueAdd)
-            speculation = Node::shouldSpeculateMachineIntExpectingDefined(left, right);
+            speculation = Node::shouldSpeculateMachineInt(left, right);
         else
-            speculation = Node::shouldSpeculateMachineIntForArithmetic(left, right);
+            speculation = Node::shouldSpeculateMachineInt(left, right);
 
-        return speculation && !hasExitSite(add, Int48Overflow);
+        return speculation && !hasExitSite(add, Int52Overflow);
     }
     
     bool mulShouldSpeculateInt32(Node* mul)
@@ -257,12 +260,15 @@ public:
     {
         ASSERT(mul->op() == ArithMul);
         
+        if (!enableInt52())
+            return false;
+        
         Node* left = mul->child1().node();
         Node* right = mul->child2().node();
 
-        return Node::shouldSpeculateMachineIntForArithmetic(left, right)
-            && mul->canSpeculateInt48()
-            && !hasExitSite(mul, Int48Overflow);
+        return Node::shouldSpeculateMachineInt(left, right)
+            && mul->canSpeculateInt52()
+            && !hasExitSite(mul, Int52Overflow);
     }
     
     bool negateShouldSpeculateInt32(Node* negate)
@@ -274,9 +280,11 @@ public:
     bool negateShouldSpeculateMachineInt(Node* negate)
     {
         ASSERT(negate->op() == ArithNegate);
-        return negate->child1()->shouldSpeculateMachineIntForArithmetic()
-            && !hasExitSite(negate, Int48Overflow)
-            && negate->canSpeculateInt48();
+        if (!enableInt52())
+            return false;
+        return negate->child1()->shouldSpeculateMachineInt()
+            && !hasExitSite(negate, Int52Overflow)
+            && negate->canSpeculateInt52();
     }
     
     // Helper methods to check nodes for constants.
index a5e3af2..f9f6cbe 100644 (file)
@@ -313,10 +313,10 @@ bool InPlaceAbstractState::mergeStateAtTail(AbstractValue& destination, Abstract
             // before and after setting it.
             source = forNode(node->child1());
             if (node->variableAccessData()->flushFormat() == FlushedDouble) {
-                ASSERT(!(source.m_type & ~SpecNumber));
-                ASSERT(!!(source.m_type & ~SpecDouble) == !!(source.m_type & SpecInt32));
+                ASSERT(!(source.m_type & ~SpecFullNumber));
+                ASSERT(!!(source.m_type & ~SpecDouble) == !!(source.m_type & SpecMachineInt));
                 if (!(source.m_type & ~SpecDouble)) {
-                    source.merge(SpecInt48AsDouble);
+                    source.merge(SpecInt52AsDouble);
                     source.filter(SpecDouble);
                 }
             }
index a3f1f37..a0db5a4 100644 (file)
@@ -103,6 +103,9 @@ void JITCode::reconstruct(
         case AlreadyInJSStackAsUnboxedInt32:
             value = jsNumber(exec->r(operand).unboxedInt32());
             break;
+        case AlreadyInJSStackAsUnboxedInt52:
+            value = jsNumber(exec->r(operand).unboxedInt52());
+            break;
         case AlreadyInJSStackAsUnboxedDouble:
             value = jsDoubleNumber(exec->r(operand).unboxedDouble());
             break;
index 1a24e39..1571371 100644 (file)
@@ -48,6 +48,8 @@ inline bool belongsInMinifiedGraph(NodeType type)
     case UInt32ToNumber:
     case DoubleAsInt32:
     case PhantomArguments:
+    case Int52ToValue:
+    case Int52ToDouble:
         return true;
     default:
         ASSERT(!permitsOSRBackwardRewiring(type) && !permitsOSRForwardRewiring(type));
@@ -104,6 +106,8 @@ private:
         case Int32ToDouble:
         case UInt32ToNumber:
         case DoubleAsInt32:
+        case Int52ToDouble:
+        case Int52ToValue:
             return true;
         default:
             return false;
index 7e7d1a5..c8dbb1e 100644 (file)
@@ -1241,12 +1241,12 @@ struct Node {
     
     bool shouldSpeculateNumber()
     {
-        return isNumberSpeculation(prediction());
+        return isFullNumberSpeculation(prediction());
     }
     
     bool shouldSpeculateNumberExpectingDefined()
     {
-        return isNumberSpeculationExpectingDefined(prediction());
+        return isFullNumberSpeculationExpectingDefined(prediction());
     }
     
     bool shouldSpeculateBoolean()
@@ -1424,9 +1424,9 @@ struct Node {
         return nodeCanSpeculateInt32(arithNodeFlags());
     }
     
-    bool canSpeculateInt48()
+    bool canSpeculateInt52()
     {
-        return nodeCanSpeculateInt48(arithNodeFlags());
+        return nodeCanSpeculateInt52(arithNodeFlags());
     }
     
     void dumpChildren(PrintStream& out)
index 72e8d77..9a66efb 100644 (file)
@@ -41,8 +41,9 @@ namespace JSC { namespace DFG {
 #define NodeResultJS                     0x0001
 #define NodeResultNumber                 0x0002
 #define NodeResultInt32                  0x0003
-#define NodeResultBoolean                0x0004
-#define NodeResultStorage                0x0005
+#define NodeResultInt52                  0x0004
+#define NodeResultBoolean                0x0005
+#define NodeResultStorage                0x0006
                                 
 #define NodeMustGenerate                 0x0008 // set on nodes that have side effects, and may not trivially be removed by DCE.
 #define NodeHasVarArgs                   0x0010
@@ -107,7 +108,7 @@ static inline bool nodeCanSpeculateInt32(NodeFlags flags)
     return true;
 }
 
-static inline bool nodeCanSpeculateInt48(NodeFlags flags)
+static inline bool nodeCanSpeculateInt52(NodeFlags flags)
 {
     if (nodeMayNegZero(flags))
         return bytecodeCanIgnoreNegativeZero(flags);
index 82d373f..641aefe 100644 (file)
@@ -114,6 +114,10 @@ namespace JSC { namespace DFG {
     macro(Int32ToDouble, NodeResultNumber) \
     /* Used to speculate that a double value is actually an integer. */\
     macro(DoubleAsInt32, NodeResultInt32 | NodeExitsForward) \
+    /* Used to separate representation and register allocation of Int52's represented */\
+    /* as values. */\
+    macro(Int52ToValue, NodeResultJS) \
+    macro(Int52ToDouble, NodeResultNumber) \
     \
     /* Nodes for arithmetic operations. */\
     macro(ArithAdd, NodeResultNumber | NodeMustGenerate) \
@@ -356,6 +360,17 @@ inline unsigned forwardRewiringSelectionScore(NodeType op)
         // This loses information. Only use it if there are no better alternatives.
         return 25;
         
+    case Int52ToValue:
+        // Loses no information. It just boxes the value, which is what OSR wants
+        // to do anyway.
+        return 100;
+        
+    case Int52ToDouble:
+        // This is like Int32ToDouble; we can use it because it gives a semantically
+        // equivalent value but that value may be an int32 in a double, so we'd
+        // rather not if we can avoid it.
+        return 75;
+        
     default:
         return 0;
     }
index 063c282..d7c0074 100644 (file)
 
 namespace JSC { namespace DFG {
 
-static CString shortOperandsDump(const Operands<ValueRecovery>& operands)
-{
-    DumpContext context;
-    StringPrintStream out;
-    out.print(inContext(operands, &context));
-    return out.toCString();
-}
-
 extern "C" {
 
 void compileOSRExit(ExecState* exec)
@@ -117,7 +109,7 @@ void compileOSRExit(ExecState* exec)
             ("DFG OSR exit #%u (%s, %s) from %s, with operands = %s",
                 exitIndex, toCString(exit.m_codeOrigin).data(),
                 exitKindToString(exit.m_kind), toCString(*codeBlock).data(),
-                shortOperandsDump(operands).data()));
+                toCString(ignoringContext<DumpContext>(operands)).data()));
     }
     
     {
index 3e148c9..523ac38 100644 (file)
@@ -195,6 +195,8 @@ void OSRExitCompiler::compileExit(const OSRExit& exit, const Operands<ValueRecov
         case InGPR:
         case UnboxedInt32InGPR:
         case UInt32InGPR:
+        case UnboxedInt52InGPR:
+        case UnboxedStrictInt52InGPR:
             m_jit.store64(recovery.gpr(), scratch + index);
             break;
             
@@ -235,12 +237,15 @@ void OSRExitCompiler::compileExit(const OSRExit& exit, const Operands<ValueRecov
         case DisplacedInJSStack:
         case Int32DisplacedInJSStack:
         case DoubleDisplacedInJSStack:
+        case Int52DisplacedInJSStack:
+        case StrictInt52DisplacedInJSStack:
             m_jit.load64(AssemblyHelpers::addressFor(recovery.virtualRegister()), GPRInfo::regT0);
             m_jit.store64(GPRInfo::regT0, scratch + index);
             break;
             
         case AlreadyInJSStackAsUnboxedInt32:
         case AlreadyInJSStackAsUnboxedDouble:
+        case AlreadyInJSStackAsUnboxedInt52:
             m_jit.load64(AssemblyHelpers::addressFor(operand), GPRInfo::regT0);
             m_jit.store64(GPRInfo::regT0, scratch + index);
             break;
@@ -274,33 +279,38 @@ void OSRExitCompiler::compileExit(const OSRExit& exit, const Operands<ValueRecov
             m_jit.store64(GPRInfo::regT0, AssemblyHelpers::addressFor(operand));
             break;
             
-        case AlreadyInJSStackAsUnboxedDouble:
-        case InFPR:
-        case DoubleDisplacedInJSStack:
-            m_jit.move(AssemblyHelpers::TrustedImmPtr(scratch + index), GPRInfo::regT0);
-            m_jit.loadDouble(GPRInfo::regT0, FPRInfo::fpRegT0);
-            m_jit.boxDouble(FPRInfo::fpRegT0, GPRInfo::regT0);
+        case AlreadyInJSStackAsUnboxedInt52:
+        case UnboxedInt52InGPR:
+        case Int52DisplacedInJSStack:
+            m_jit.load64(scratch + index, GPRInfo::regT0);
+            m_jit.rshift64(
+                AssemblyHelpers::TrustedImm32(JSValue::int52ShiftAmount), GPRInfo::regT0);
+            m_jit.boxInt52(GPRInfo::regT0, GPRInfo::regT0, GPRInfo::regT1, FPRInfo::fpRegT0);
+            m_jit.store64(GPRInfo::regT0, AssemblyHelpers::addressFor(operand));
+            break;
+            
+        case UnboxedStrictInt52InGPR:
+        case StrictInt52DisplacedInJSStack:
+            m_jit.load64(scratch + index, GPRInfo::regT0);
+            m_jit.boxInt52(GPRInfo::regT0, GPRInfo::regT0, GPRInfo::regT1, FPRInfo::fpRegT0);
             m_jit.store64(GPRInfo::regT0, AssemblyHelpers::addressFor(operand));
             break;
             
-        case UInt32InGPR: {
+        case UInt32InGPR:
             m_jit.load64(scratch + index, GPRInfo::regT0);
             m_jit.zeroExtend32ToPtr(GPRInfo::regT0, GPRInfo::regT0);
-            AssemblyHelpers::Jump positive = m_jit.branch32(
-                AssemblyHelpers::GreaterThanOrEqual,
-                GPRInfo::regT0, AssemblyHelpers::TrustedImm32(0));
-            m_jit.convertInt32ToDouble(GPRInfo::regT0, FPRInfo::fpRegT0);
-            m_jit.addDouble(
-                AssemblyHelpers::AbsoluteAddress(&AssemblyHelpers::twoToThe32),
-                FPRInfo::fpRegT0);
+            m_jit.boxInt52(GPRInfo::regT0, GPRInfo::regT0, GPRInfo::regT1, FPRInfo::fpRegT0);
+            m_jit.store64(GPRInfo::regT0, AssemblyHelpers::addressFor(operand));
+            break;
+            
+        case AlreadyInJSStackAsUnboxedDouble:
+        case InFPR:
+        case DoubleDisplacedInJSStack:
+            m_jit.move(AssemblyHelpers::TrustedImmPtr(scratch + index), GPRInfo::regT0);
+            m_jit.loadDouble(GPRInfo::regT0, FPRInfo::fpRegT0);
             m_jit.boxDouble(FPRInfo::fpRegT0, GPRInfo::regT0);
-            AssemblyHelpers::Jump done = m_jit.jump();
-            positive.link(&m_jit);
-            m_jit.or64(GPRInfo::tagTypeNumberRegister, GPRInfo::regT0);
-            done.link(&m_jit);
             m_jit.store64(GPRInfo::regT0, AssemblyHelpers::addressFor(operand));
             break;
-        }
             
         case Constant:
             m_jit.store64(
index ec58456..612010a 100644 (file)
@@ -116,7 +116,7 @@ private:
     
     SpeculatedType speculatedDoubleTypeForPrediction(SpeculatedType value)
     {
-        if (!isNumberSpeculation(value))
+        if (!isFullNumberSpeculation(value))
             return SpecDouble;
         if (value & SpecDoubleNaN)
             return SpecDouble;
@@ -142,15 +142,17 @@ private:
         case JSConstant:
         case WeakJSConstant: {
             SpeculatedType type = speculationFromValue(m_graph.valueOfJSConstant(node));
-            if (type == SpecInt48AsDouble)
-                type = SpecInt48;
+            if (type == SpecInt52AsDouble)
+                type = SpecInt52;
             changed |= setPrediction(type);
             break;
         }
             
         case GetLocal: {
-            VariableAccessData* variableAccessData = node->variableAccessData();
-            SpeculatedType prediction = variableAccessData->prediction();
+            VariableAccessData* variable = node->variableAccessData();
+            SpeculatedType prediction = variable->prediction();
+            if (variable->shouldNeverUnbox() && (prediction & SpecInt52))
+                prediction = (prediction | SpecInt52AsDouble) & ~SpecInt52;
             if (prediction)
                 changed |= mergePrediction(prediction);
             break;
@@ -203,7 +205,7 @@ private:
             if (nodeCanSpeculateInt32(node->arithNodeFlags()))
                 changed |= mergePrediction(SpecInt32);
             else
-                changed |= mergePrediction(SpecNumber);
+                changed |= mergePrediction(SpecBytecodeNumber);
             break;
         }
 
@@ -212,14 +214,14 @@ private:
             SpeculatedType right = node->child2()->prediction();
             
             if (left && right) {
-                if (isNumberSpeculationExpectingDefined(left) && isNumberSpeculationExpectingDefined(right)) {
+                if (isFullNumberSpeculationExpectingDefined(left) && isFullNumberSpeculationExpectingDefined(right)) {
                     if (m_graph.addSpeculationMode(node) != DontSpeculateInt32)
                         changed |= mergePrediction(SpecInt32);
                     else if (m_graph.addShouldSpeculateMachineInt(node))
-                        changed |= mergePrediction(SpecInt48);
+                        changed |= mergePrediction(SpecInt52);
                     else
                         changed |= mergePrediction(speculatedDoubleTypeForPredictions(left, right));
-                } else if (!(left & SpecNumber) || !(right & SpecNumber)) {
+                } else if (!(left & SpecFullNumber) || !(right & SpecFullNumber)) {
                     // left or right is definitely something other than a number.
                     changed |= mergePrediction(SpecString);
                 } else
@@ -236,7 +238,7 @@ private:
                 if (m_graph.addSpeculationMode(node) != DontSpeculateInt32)
                     changed |= mergePrediction(SpecInt32);
                 else if (m_graph.addShouldSpeculateMachineInt(node))
-                    changed |= mergePrediction(SpecInt48);
+                    changed |= mergePrediction(SpecInt52);
                 else
                     changed |= mergePrediction(speculatedDoubleTypeForPredictions(left, right));
             }
@@ -251,7 +253,7 @@ private:
                 if (m_graph.addSpeculationMode(node) != DontSpeculateInt32)
                     changed |= mergePrediction(SpecInt32);
                 else if (m_graph.addShouldSpeculateMachineInt(node))
-                    changed |= mergePrediction(SpecInt48);
+                    changed |= mergePrediction(SpecInt52);
                 else
                     changed |= mergePrediction(speculatedDoubleTypeForPredictions(left, right));
             }
@@ -263,7 +265,7 @@ private:
                 if (m_graph.negateShouldSpeculateInt32(node))
                     changed |= mergePrediction(SpecInt32);
                 else if (m_graph.negateShouldSpeculateMachineInt(node))
-                    changed |= mergePrediction(SpecInt48);
+                    changed |= mergePrediction(SpecInt52);
                 else
                     changed |= mergePrediction(speculatedDoubleTypeForPrediction(node->child1()->prediction()));
             }
@@ -292,7 +294,7 @@ private:
                 if (m_graph.mulShouldSpeculateInt32(node))
                     changed |= mergePrediction(SpecInt32);
                 else if (m_graph.mulShouldSpeculateMachineInt(node))
-                    changed |= mergePrediction(SpecInt48);
+                    changed |= mergePrediction(SpecInt52);
                 else
                     changed |= mergePrediction(speculatedDoubleTypeForPredictions(left, right));
             }
@@ -368,10 +370,20 @@ private:
         }
 
         case GetByVal: {
+            if (!node->child1()->prediction())
+                break;
+            if (!node->getHeapPrediction())
+                break;
+            
             if (node->child1()->shouldSpeculateFloat32Array()
                 || node->child1()->shouldSpeculateFloat64Array())
                 changed |= mergePrediction(SpecDouble);
-            else
+            else if (node->child1()->shouldSpeculateUint32Array()) {
+                if (isInt32Speculation(node->getHeapPrediction()))
+                    changed |= mergePrediction(SpecInt32);
+                else
+                    changed |= mergePrediction(SpecInt52);
+            } else
                 changed |= mergePrediction(node->getHeapPrediction());
             break;
         }
@@ -566,6 +578,8 @@ private:
         case CheckWatchdogTimer:
         case Unreachable:
         case LoopHint:
+        case Int52ToValue:
+        case Int52ToDouble:
             break;
             
         // This gets ignored because it already has a prediction.
@@ -640,8 +654,9 @@ private:
                 
             DoubleBallot ballot;
                 
-            if (isNumberSpeculationExpectingDefined(left) && isNumberSpeculationExpectingDefined(right)
-                && !m_graph.addShouldSpeculateInt32(node))
+            if (isFullNumberSpeculationExpectingDefined(left) && isFullNumberSpeculationExpectingDefined(right)
+                && !m_graph.addShouldSpeculateInt32(node)
+                && !m_graph.addShouldSpeculateMachineInt(node))
                 ballot = VoteDouble;
             else
                 ballot = VoteValue;
@@ -657,8 +672,9 @@ private:
                 
             DoubleBallot ballot;
                 
-            if (isNumberSpeculation(left) && isNumberSpeculation(right)
-                && !m_graph.mulShouldSpeculateInt32(node))
+            if (isFullNumberSpeculation(left) && isFullNumberSpeculation(right)
+                && !m_graph.mulShouldSpeculateInt32(node)
+                && !m_graph.mulShouldSpeculateMachineInt(node))
                 ballot = VoteDouble;
             else
                 ballot = VoteValue;
@@ -677,7 +693,7 @@ private:
                 
             DoubleBallot ballot;
                 
-            if (isNumberSpeculation(left) && isNumberSpeculation(right)
+            if (isFullNumberSpeculation(left) && isFullNumberSpeculation(right)
                 && !(Node::shouldSpeculateInt32ForArithmetic(node->child1().node(), node->child2().node()) && node->canSpeculateInt32()))
                 ballot = VoteDouble;
             else
@@ -706,7 +722,9 @@ private:
             SpeculatedType prediction = node->child1()->prediction();
             if (isDoubleSpeculation(prediction))
                 node->variableAccessData()->vote(VoteDouble);
-            else if (!isNumberSpeculation(prediction) || isInt32Speculation(prediction))
+            else if (
+                !isFullNumberSpeculation(prediction)
+                || isInt32Speculation(prediction) || isMachineIntSpeculation(prediction))
                 node->variableAccessData()->vote(VoteValue);
             break;
         }
index 2491c35..97552c0 100644 (file)
@@ -61,6 +61,7 @@ public:
         case StringOrStringObjectUse:
         case NotCellUse:
         case OtherUse:
+        case MachineIntUse:
             return;
             
         case KnownInt32Use:
@@ -69,7 +70,7 @@ public:
             return;
             
         case KnownNumberUse:
-            if (m_state.forNode(edge).m_type & ~SpecNumber)
+            if (m_state.forNode(edge).m_type & ~SpecFullNumber)
                 m_result = false;
             return;
             
@@ -239,6 +240,8 @@ bool safeToExecute(AbstractStateType& state, Graph& graph, Node* node)
     case CheckTierUpAtReturn:
     case CheckTierUpAndOSREnter:
     case LoopHint:
+    case Int52ToDouble:
+    case Int52ToValue:
         return true;
         
     case GetByVal:
index 6b9df19..8ac800d 100644 (file)
@@ -48,6 +48,8 @@ enum SilentSpillAction {
 enum SilentFillAction {
     DoNothingForFill,
     SetInt32Constant,
+    SetInt52Constant,
+    SetStrictInt52Constant,
     SetBooleanConstant,
     SetCellConstant,
     SetTrustedJSConstant,
@@ -61,8 +63,12 @@ enum SilentFillAction {
     Load32Tag,
     Load32Payload,
     Load32PayloadBoxInt,
+    Load32PayloadConvertToInt52,
+    Load32PayloadSignExtend,
     LoadPtr,
     Load64,
+    Load64ShiftInt52Right,
+    Load64ShiftInt52Left,
     LoadDouble,
     LoadDoubleBoxDouble,
     LoadJSUnboxDouble
index c5f4e01..fe541e2 100644 (file)
@@ -335,6 +335,8 @@ SilentRegisterSavePlan SpeculativeJIT::silentSavePlanForGPR(VirtualRegister spil
             spillAction = Store32Payload;
         else if (registerFormat == DataFormatCell || registerFormat == DataFormatStorage)
             spillAction = StorePtr;
+        else if (registerFormat == DataFormatInt52 || registerFormat == DataFormatStrictInt52)
+            spillAction = Store64;
         else {
             ASSERT(registerFormat & DataFormatJS);
             spillAction = Store64;
@@ -386,6 +388,42 @@ SilentRegisterSavePlan SpeculativeJIT::silentSavePlanForGPR(VirtualRegister spil
     } else if (registerFormat == DataFormatStorage) {
         ASSERT(info.gpr() == source);
         fillAction = LoadPtr;
+    } else if (registerFormat == DataFormatInt52) {
+        if (node->hasConstant())
+            fillAction = SetInt52Constant;
+        else if (isJSInt32(info.spillFormat()) || info.spillFormat() == DataFormatJS)
+            fillAction = Load32PayloadConvertToInt52;
+        else if (info.spillFormat() == DataFormatInt52)
+            fillAction = Load64;
+        else if (info.spillFormat() == DataFormatStrictInt52)
+            fillAction = Load64ShiftInt52Left;
+        else if (info.spillFormat() == DataFormatNone)
+            fillAction = Load64;
+        else {
+            // Should never happen. Anything that qualifies as an int32 will never
+            // be turned into a cell (immediate spec fail) or a double (to-double
+            // conversions involve a separate node).
+            RELEASE_ASSERT_NOT_REACHED();
+            fillAction = Load64; // Make GCC happy.
+        }
+    } else if (registerFormat == DataFormatStrictInt52) {
+        if (node->hasConstant())
+            fillAction = SetStrictInt52Constant;
+        else if (isJSInt32(info.spillFormat()) || info.spillFormat() == DataFormatJS)
+            fillAction = Load32PayloadSignExtend;
+        else if (info.spillFormat() == DataFormatInt52)
+            fillAction = Load64ShiftInt52Right;
+        else if (info.spillFormat() == DataFormatStrictInt52)
+            fillAction = Load64;
+        else if (info.spillFormat() == DataFormatNone)
+            fillAction = Load64;
+        else {
+            // Should never happen. Anything that qualifies as an int32 will never
+            // be turned into a cell (immediate spec fail) or a double (to-double
+            // conversions involve a separate node).
+            RELEASE_ASSERT_NOT_REACHED();
+            fillAction = Load64; // Make GCC happy.
+        }
     } else {
         ASSERT(registerFormat & DataFormatJS);
 #if USE(JSVALUE64)
@@ -393,7 +431,6 @@ SilentRegisterSavePlan SpeculativeJIT::silentSavePlanForGPR(VirtualRegister spil
         if (node->hasConstant()) {
             if (valueOfJSConstant(node).isCell())
                 fillAction = SetTrustedJSConstant;
-            else
                 fillAction = SetJSConstant;
         } else if (info.spillFormat() == DataFormatInt32) {
             ASSERT(registerFormat == DataFormatJSInt32);
@@ -512,6 +549,14 @@ void SpeculativeJIT::silentFill(const SilentRegisterSavePlan& plan, GPRReg canTr
     case SetInt32Constant:
         m_jit.move(Imm32(valueOfInt32Constant(plan.node())), plan.gpr());
         break;
+#if USE(JSVALUE64)
+    case SetInt52Constant:
+        m_jit.move(Imm64(valueOfJSConstant(plan.node()).asMachineInt() << JSValue::int52ShiftAmount), plan.gpr());
+        break;
+    case SetStrictInt52Constant:
+        m_jit.move(Imm64(valueOfJSConstant(plan.node()).asMachineInt()), plan.gpr());
+        break;
+#endif // USE(JSVALUE64)
     case SetBooleanConstant:
         m_jit.move(TrustedImm32(valueOfBooleanConstant(plan.node())), plan.gpr());
         break;
@@ -533,6 +578,15 @@ void SpeculativeJIT::silentFill(const SilentRegisterSavePlan& plan, GPRReg canTr
         m_jit.load32(JITCompiler::payloadFor(plan.node()->virtualRegister()), plan.gpr());
         m_jit.or64(GPRInfo::tagTypeNumberRegister, plan.gpr());
         break;
+    case Load32PayloadConvertToInt52:
+        m_jit.load32(JITCompiler::payloadFor(plan.node()->virtualRegister()), plan.gpr());
+        m_jit.signExtend32ToPtr(plan.gpr(), plan.gpr());
+        m_jit.lshift64(TrustedImm32(JSValue::int52ShiftAmount), plan.gpr());
+        break;
+    case Load32PayloadSignExtend:
+        m_jit.load32(JITCompiler::payloadFor(plan.node()->virtualRegister()), plan.gpr());
+        m_jit.signExtend32ToPtr(plan.gpr(), plan.gpr());
+        break;
     case LoadDoubleBoxDouble:
         m_jit.load64(JITCompiler::addressFor(plan.node()->virtualRegister()), plan.gpr());
         m_jit.sub64(GPRInfo::tagTypeNumberRegister, plan.gpr());
@@ -574,6 +628,14 @@ void SpeculativeJIT::silentFill(const SilentRegisterSavePlan& plan, GPRReg canTr
     case Load64:
         m_jit.load64(JITCompiler::addressFor(plan.node()->virtualRegister()), plan.gpr());
         break;
+    case Load64ShiftInt52Right:
+        m_jit.load64(JITCompiler::addressFor(plan.node()->virtualRegister()), plan.gpr());
+        m_jit.rshift64(TrustedImm32(JSValue::int52ShiftAmount), plan.gpr());
+        break;
+    case Load64ShiftInt52Left:
+        m_jit.load64(JITCompiler::addressFor(plan.node()->virtualRegister()), plan.gpr());
+        m_jit.lshift64(TrustedImm32(JSValue::int52ShiftAmount), plan.gpr());
+        break;
 #endif
     case LoadDouble:
         m_jit.loadDouble(JITCompiler::addressFor(plan.node()->virtualRegister()), plan.fpr());
@@ -1416,6 +1478,10 @@ bool SpeculativeJIT::compilePeepHoleBranch(Node* node, MacroAssembler::Relationa
 
         if (node->isBinaryUseKind(Int32Use))
             compilePeepHoleInt32Branch(node, branchNode, condition);
+#if USE(JSVALUE64)
+        else if (node->isBinaryUseKind(MachineIntUse))
+            compilePeepHoleInt52Branch(node, branchNode, condition);
+#endif // USE(JSVALUE64)
         else if (node->isBinaryUseKind(NumberUse))
             compilePeepHoleDoubleBranch(node, branchNode, doubleCondition);
         else if (node->op() == CompareEq) {
@@ -1507,6 +1573,9 @@ void SpeculativeJIT::compileInlineStart(Node* node)
             case FlushedInt32:
                 valueSource = ValueSource(Int32InJSStack);
                 break;
+            case FlushedInt52:
+                valueSource = ValueSource(Int52InJSStack);
+                break;
             case FlushedCell:
                 valueSource = ValueSource(CellInJSStack);
                 break;
@@ -1873,7 +1942,7 @@ void SpeculativeJIT::compileDoublePutByVal(Node* node, SpeculateCellOperand& bas
     FPRReg valueReg = value.fpr();
     
     DFG_TYPE_CHECK(
-        JSValueRegs(), child3, SpecRealNumber,
+        JSValueRegs(), child3, SpecFullRealNumber,
         m_jit.branchDouble(
             MacroAssembler::DoubleNotEqualOrUnordered, valueReg, valueReg));
     
@@ -2149,6 +2218,18 @@ void SpeculativeJIT::compileValueToInt32(Node* node)
         int32Result(result.gpr(), node, op1.format());
         return;
     }
+        
+#if USE(JSVALUE64)
+    case MachineIntUse: {
+        SpeculateStrictInt52Operand op1(this, node->child1());
+        GPRTemporary result(this, Reuse, op1);
+        GPRReg op1GPR = op1.gpr();
+        GPRReg resultGPR = result.gpr();
+        m_jit.zeroExtend32ToPtr(op1GPR, resultGPR);
+        int32Result(resultGPR, node, DataFormatInt32);
+        return;
+    }
+#endif // USE(JSVALUE64)
     
     case NumberUse:
     case NotCellUse: {
@@ -2187,7 +2268,7 @@ void SpeculativeJIT::compileValueToInt32(Node* node)
 
             if (node->child1().useKind() == NumberUse) {
                 DFG_TYPE_CHECK(
-                    JSValueRegs(gpr), node->child1(), SpecNumber,
+                    JSValueRegs(gpr), node->child1(), SpecFullNumber,
                     m_jit.branchTest64(
                         MacroAssembler::Zero, gpr, GPRInfo::tagTypeNumberRegister));
             } else {
@@ -2243,7 +2324,7 @@ void SpeculativeJIT::compileValueToInt32(Node* node)
 
                 if (node->child1().useKind() == NumberUse) {
                     DFG_TYPE_CHECK(
-                        JSValueRegs(tagGPR, payloadGPR), node->child1(), SpecNumber,
+                        JSValueRegs(tagGPR, payloadGPR), node->child1(), SpecFullNumber,
                         m_jit.branch32(
                             MacroAssembler::AboveOrEqual, tagGPR,
                             TrustedImm32(JSValue::LowestTag)));
@@ -2389,15 +2470,15 @@ void SpeculativeJIT::compileInt32ToDouble(Node* node)
     JITCompiler::Jump isInteger = m_jit.branch64(
         MacroAssembler::AboveOrEqual, op1GPR, GPRInfo::tagTypeNumberRegister);
     
-    if (needsTypeCheck(node->child1(), SpecNumber)) {
+    if (needsTypeCheck(node->child1(), SpecFullNumber)) {
         if (node->flags() & NodeExitsForward) {
             forwardTypeCheck(
-                JSValueRegs(op1GPR), node->child1(), SpecNumber,
+                JSValueRegs(op1GPR), node->child1(), SpecFullNumber,
                 m_jit.branchTest64(MacroAssembler::Zero, op1GPR, GPRInfo::tagTypeNumberRegister),
                 ValueRecovery::inGPR(op1GPR, DataFormatJS));
         } else {
             backwardTypeCheck(
-                JSValueRegs(op1GPR), node->child1(), SpecNumber,
+                JSValueRegs(op1GPR), node->child1(), SpecFullNumber,
                 m_jit.branchTest64(MacroAssembler::Zero, op1GPR, GPRInfo::tagTypeNumberRegister));
         }
     }
@@ -2420,15 +2501,15 @@ void SpeculativeJIT::compileInt32ToDouble(Node* node)
     JITCompiler::Jump isInteger = m_jit.branch32(
         MacroAssembler::Equal, op1TagGPR, TrustedImm32(JSValue::Int32Tag));
     
-    if (needsTypeCheck(node->child1(), SpecNumber)) {
+    if (needsTypeCheck(node->child1(), SpecFullNumber)) {
         if (node->flags() & NodeExitsForward) {
             forwardTypeCheck(
-                JSValueRegs(op1TagGPR, op1PayloadGPR), node->child1(), SpecNumber,
+                JSValueRegs(op1TagGPR, op1PayloadGPR), node->child1(), SpecFullNumber,
                 m_jit.branch32(MacroAssembler::AboveOrEqual, op1TagGPR, TrustedImm32(JSValue::LowestTag)),
                 ValueRecovery::inPair(op1TagGPR, op1PayloadGPR));
         } else {
             backwardTypeCheck(
-                JSValueRegs(op1TagGPR, op1PayloadGPR), node->child1(), SpecNumber,
+                JSValueRegs(op1TagGPR, op1PayloadGPR), node->child1(), SpecFullNumber,
                 m_jit.branch32(MacroAssembler::AboveOrEqual, op1TagGPR, TrustedImm32(JSValue::LowestTag)));
         }
     }
@@ -2549,6 +2630,14 @@ void SpeculativeJIT::compileGetByValOnIntTypedArray(Node* node, TypedArrayType t
         return;
     }
     
+#if USE(JSVALUE64)
+    if (node->shouldSpeculateMachineInt()) {
+        m_jit.zeroExtend32ToPtr(resultReg, resultReg);
+        strictInt52Result(resultReg, node);
+        return;
+    }
+#endif
+    
     FPRTemporary fresult(this);
     m_jit.convertInt32ToDouble(resultReg, fresult.fpr());
     JITCompiler::Jump positive = m_jit.branch32(MacroAssembler::GreaterThanOrEqual, resultReg, TrustedImm32(0));
@@ -2602,6 +2691,31 @@ void SpeculativeJIT::compilePutByValForIntTypedArray(GPRReg base, GPRReg propert
             break;
         }
             
+#if USE(JSVALUE64)
+        case MachineIntUse: {
+            SpeculateStrictInt52Operand valueOp(this, valueUse);
+            GPRTemporary scratch(this);
+            GPRReg scratchReg = scratch.gpr();
+            m_jit.move(valueOp.gpr(), scratchReg);
+            if (isClamped(type)) {
+                ASSERT(elementSize(type) == 1);
+                MacroAssembler::Jump inBounds = m_jit.branch64(
+                    MacroAssembler::BelowOrEqual, scratchReg, JITCompiler::TrustedImm64(0xff));
+                MacroAssembler::Jump tooBig = m_jit.branch64(
+                    MacroAssembler::GreaterThan, scratchReg, JITCompiler::TrustedImm64(0xff));
+                m_jit.move(TrustedImm32(0), scratchReg);
+                MacroAssembler::Jump clamped = m_jit.jump();
+                tooBig.link(&m_jit);
+                m_jit.move(JITCompiler::TrustedImm32(255), scratchReg);
+                clamped.link(&m_jit);
+                inBounds.link(&m_jit);
+            }
+            value.adopt(scratch);
+            valueGPR = scratchReg;
+            break;
+        }
+#endif // USE(JSVALUE64)
+            
         case NumberUse: {
             if (isClamped(type)) {
                 ASSERT(elementSize(type) == 1);
@@ -2870,7 +2984,7 @@ void SpeculativeJIT::compileAdd(Node* node)
             int32Result(result.gpr(), node);
             return;
         }
-                
+        
         if (isNumberConstant(node->child2().node())) {
             SpeculateInt32Operand op1(this, node->child1());
             int32_t imm2 = valueOfInt32Constant(node->child2().node());
@@ -2915,6 +3029,33 @@ void SpeculativeJIT::compileAdd(Node* node)
         int32Result(gprResult, node);
         return;
     }
+        
+#if USE(JSVALUE64)
+    case MachineIntUse: {
+        // Will we need an overflow check? If we can prove that neither input can be
+        // Int52 then the overflow check will not be necessary.
+        if (!m_state.forNode(node->child1()).couldBeType(SpecInt52)
+            && !m_state.forNode(node->child2()).couldBeType(SpecInt52)) {
+            SpeculateWhicheverInt52Operand op1(this, node->child1());
+            SpeculateWhicheverInt52Operand op2(this, node->child2(), op1);
+            GPRTemporary result(this, Reuse, op1);
+            m_jit.move(op1.gpr(), result.gpr());
+            m_jit.add64(op2.gpr(), result.gpr());
+            int52Result(result.gpr(), node, op1.format());
+            return;
+        }
+        
+        SpeculateInt52Operand op1(this, node->child1());
+        SpeculateInt52Operand op2(this, node->child2());
+        GPRTemporary result(this, Reuse, op1, op2);
+        m_jit.move(op1.gpr(), result.gpr());
+        speculationCheck(
+            Int52Overflow, JSValueRegs(), 0,
+            m_jit.branchAdd64(MacroAssembler::Overflow, op2.gpr(), result.gpr()));
+        int52Result(result.gpr(), node);
+        return;
+    }
+#endif // USE(JSVALUE64)
     
     case NumberUse: {
         SpeculateDoubleOperand op1(this, node->child1());
@@ -3060,6 +3201,33 @@ void SpeculativeJIT::compileArithSub(Node* node)
         return;
     }
         
+#if USE(JSVALUE64)
+    case MachineIntUse: {
+        // Will we need an overflow check? If we can prove that neither input can be
+        // Int52 then the overflow check will not be necessary.
+        if (!m_state.forNode(node->child1()).couldBeType(SpecInt52)
+            && !m_state.forNode(node->child2()).couldBeType(SpecInt52)) {
+            SpeculateWhicheverInt52Operand op1(this, node->child1());
+            SpeculateWhicheverInt52Operand op2(this, node->child2(), op1);
+            GPRTemporary result(this, Reuse, op1);
+            m_jit.move(op1.gpr(), result.gpr());
+            m_jit.sub64(op2.gpr(), result.gpr());
+            int52Result(result.gpr(), node, op1.format());
+            return;
+        }
+        
+        SpeculateInt52Operand op1(this, node->child1());
+        SpeculateInt52Operand op2(this, node->child2());
+        GPRTemporary result(this, Reuse, op1, op2);
+        m_jit.move(op1.gpr(), result.gpr());
+        speculationCheck(
+            Int52Overflow, JSValueRegs(), 0,
+            m_jit.branchSub64(MacroAssembler::Overflow, op2.gpr(), result.gpr()));
+        int52Result(result.gpr(), node);
+        return;
+    }
+#endif // USE(JSVALUE64)
+
     case NumberUse: {
         SpeculateDoubleOperand op1(this, node->child1());
         SpeculateDoubleOperand op2(this, node->child2());
@@ -3088,6 +3256,9 @@ void SpeculativeJIT::compileArithNegate(Node* node)
 
         m_jit.move(op1.gpr(), result.gpr());
 
+        // Note: there is no notion of being not used as a number, but someone
+        // caring about negative zero.
+        
         if (bytecodeCanTruncateInteger(node->arithNodeFlags()))
             m_jit.neg32(result.gpr());
         else if (bytecodeCanIgnoreNegativeZero(node->arithNodeFlags()))
@@ -3100,6 +3271,42 @@ void SpeculativeJIT::compileArithNegate(Node* node)
         int32Result(result.gpr(), node);
         return;
     }
+
+#if USE(JSVALUE64)
+    case MachineIntUse: {
+        if (!m_state.forNode(node->child1()).couldBeType(SpecInt52)) {
+            SpeculateWhicheverInt52Operand op1(this, node->child1());
+            GPRTemporary result(this);
+            GPRReg op1GPR = op1.gpr();
+            GPRReg resultGPR = result.gpr();
+            m_jit.move(op1GPR, resultGPR);
+            m_jit.neg64(resultGPR);
+            if (!bytecodeCanIgnoreNegativeZero(node->arithNodeFlags())) {
+                speculationCheck(
+                    NegativeZero, JSValueRegs(), 0,
+                    m_jit.branchTest64(MacroAssembler::Zero, resultGPR));
+            }
+            int52Result(resultGPR, node, op1.format());
+            return;
+        }
+        
+        SpeculateInt52Operand op1(this, node->child1());
+        GPRTemporary result(this);
+        GPRReg op1GPR = op1.gpr();
+        GPRReg resultGPR = result.gpr();
+        m_jit.move(op1GPR, resultGPR);
+        speculationCheck(
+            Int52Overflow, JSValueRegs(), 0,
+            m_jit.branchNeg64(MacroAssembler::Overflow, resultGPR));
+        if (!bytecodeCanIgnoreNegativeZero(node->arithNodeFlags())) {
+            speculationCheck(
+                NegativeZero, JSValueRegs(), 0,
+                m_jit.branchTest64(MacroAssembler::Zero, resultGPR));
+        }
+        int52Result(resultGPR, node);
+        return;
+    }
+#endif // USE(JSVALUE64)
         
     case NumberUse: {
         SpeculateDoubleOperand op1(this, node->child1());
@@ -3165,6 +3372,62 @@ void SpeculativeJIT::compileArithMul(Node* node)
         int32Result(result.gpr(), node);
         return;
     }
+    
+#if USE(JSVALUE64)   
+    case MachineIntUse: {
+        // This is super clever. We want to do an int52 multiplication and check the
+        // int52 overflow bit. There is no direct hardware support for this, but we do
+        // have the ability to do an int64 multiplication and check the int64 overflow
+        // bit. We leverage that. Consider that a, b are int52 numbers inside int64
+        // registers, with the high 12 bits being sign-extended. We can do:
+        //
+        //     (a * (b << 12))
+        //
+        // This will give us a left-shifted int52 (value is in high 52 bits, low 16
+        // bits are zero) plus the int52 overflow bit. I.e. whether this 64-bit
+        // multiplication overflows is identical to whether the 'a * b' 52-bit
+        // multiplication overflows.
+        //
+        // In our nomenclature, this is:
+        //
+        //     strictInt52(a) * int52(b) => int52
+        //
+        // That is "strictInt52" means unshifted and "int52" means left-shifted by 16
+        // bits.
+        //
+        // We don't care which of op1 or op2 serves as the left-shifted operand, so
+        // we just do whatever is more convenient for op1 and have op2 do the
+        // opposite. This ensures that we do at most one shift.
+
+        SpeculateWhicheverInt52Operand op1(this, node->child1());
+        SpeculateWhicheverInt52Operand op2(this, node->child2(), OppositeShift, op1);
+        GPRTemporary result(this);
+        
+        GPRReg op1GPR = op1.gpr();
+        GPRReg op2GPR = op2.gpr();
+        GPRReg resultGPR = result.gpr();
+        
+        m_jit.move(op1GPR, resultGPR);
+        speculationCheck(
+            Int52Overflow, JSValueRegs(), 0,
+            m_jit.branchMul64(MacroAssembler::Overflow, op2GPR, resultGPR));
+        
+        if (!bytecodeCanIgnoreNegativeZero(node->arithNodeFlags())) {
+            MacroAssembler::Jump resultNonZero = m_jit.branchTest64(
+                MacroAssembler::NonZero, resultGPR);
+            speculationCheck(
+                NegativeZero, JSValueRegs(), 0,
+                m_jit.branch64(MacroAssembler::LessThan, op1GPR, TrustedImm64(0)));
+            speculationCheck(
+                NegativeZero, JSValueRegs(), 0,
+                m_jit.branch64(MacroAssembler::LessThan, op2GPR, TrustedImm64(0)));
+            resultNonZero.link(&m_jit);
+        }
+        
+        int52Result(resultGPR, node);
+        return;
+    }
+#endif // USE(JSVALUE64)
         
     case NumberUse: {
         SpeculateDoubleOperand op1(this, node->child1());
@@ -3588,7 +3851,14 @@ bool SpeculativeJIT::compare(Node* node, MacroAssembler::RelationalCondition con
         compileInt32Compare(node, condition);
         return false;
     }
-
+    
+#if USE(JSVALUE64)
+    if (node->isBinaryUseKind(MachineIntUse)) {
+        compileInt52Compare(node, condition);
+        return false;
+    }
+#endif // USE(JSVALUE64)
+    
     if (node->isBinaryUseKind(NumberUse)) {
         compileDoubleCompare(node, doubleCondition);
         return false;
@@ -3738,6 +4008,23 @@ bool SpeculativeJIT::compileStrictEq(Node* node)
         compileInt32Compare(node, MacroAssembler::Equal);
         return false;
     }
+    
+#if USE(JSVALUE64)   
+    case MachineIntUse: {
+        unsigned branchIndexInBlock = detectPeepHoleBranch();
+        if (branchIndexInBlock != UINT_MAX) {
+            Node* branchNode = m_block->at(branchIndexInBlock);
+            compilePeepHoleInt52Branch(node, branchNode, MacroAssembler::Equal);
+            use(node->child1());
+            use(node->child2());
+            m_indexInBlock = branchIndexInBlock;
+            m_currentNode = branchNode;
+            return true;
+        }
+        compileInt52Compare(node, MacroAssembler::Equal);
+        return false;
+    }
+#endif // USE(JSVALUE64)
         
     case NumberUse: {
         unsigned branchIndexInBlock = detectPeepHoleBranch();
@@ -4493,9 +4780,22 @@ void SpeculativeJIT::speculateInt32(Edge edge)
     (SpeculateInt32Operand(this, edge)).gpr();
 }
 
+void SpeculativeJIT::speculateMachineInt(Edge edge)
+{
+#if USE(JSVALUE64)
+    if (!needsTypeCheck(edge, SpecMachineInt))
+        return;
+    
+    (SpeculateWhicheverInt52Operand(this, edge)).gpr();
+#else // USE(JSVALUE64)
+    UNUSED_PARAM(edge);
+    UNREACHABLE_FOR_PLATFORM();
+#endif // USE(JSVALUE64)
+}
+
 void SpeculativeJIT::speculateNumber(Edge edge)
 {
-    if (!needsTypeCheck(edge, SpecNumber))
+    if (!needsTypeCheck(edge, SpecFullNumber))
         return;
     
     (SpeculateDoubleOperand(this, edge)).fpr();
@@ -4503,13 +4803,13 @@ void SpeculativeJIT::speculateNumber(Edge edge)
 
 void SpeculativeJIT::speculateRealNumber(Edge edge)
 {
-    if (!needsTypeCheck(edge, SpecRealNumber))
+    if (!needsTypeCheck(edge, SpecFullRealNumber))
         return;
     
     SpeculateDoubleOperand operand(this, edge);
     FPRReg fpr = operand.fpr();
     DFG_TYPE_CHECK(
-        JSValueRegs(), edge, SpecRealNumber,
+        JSValueRegs(), edge, SpecFullRealNumber,
         m_jit.branchDouble(
             MacroAssembler::DoubleNotEqualOrUnordered, fpr, fpr));
 }
@@ -4771,7 +5071,7 @@ void SpeculativeJIT::speculate(Node*, Edge edge)
         ASSERT(!needsTypeCheck(edge, SpecInt32));
         break;
     case KnownNumberUse:
-        ASSERT(!needsTypeCheck(edge, SpecNumber));
+        ASSERT(!needsTypeCheck(edge, SpecFullNumber));
         break;
     case KnownCellUse:
         ASSERT(!needsTypeCheck(edge, SpecCell));
@@ -4782,6 +5082,9 @@ void SpeculativeJIT::speculate(Node*, Edge edge)
     case Int32Use:
         speculateInt32(edge);
         break;
+    case MachineIntUse:
+        speculateMachineInt(edge);
+        break;
     case RealNumberUse:
         speculateRealNumber(edge);
         break;
index 08050a7..dd29385 100644 (file)
@@ -159,9 +159,7 @@ public:
     // and its machine registers may be reused.
     bool canReuse(Node* node)
     {
-        VirtualRegister virtualRegister = node->virtualRegister();
-        GenerationInfo& info = generationInfoFromVirtualRegister(virtualRegister);
-        return info.canReuse();
+        return generationInfo(node).canReuse();
     }
     bool canReuse(Edge nodeUse)
     {
@@ -237,15 +235,11 @@ public:
     // avoid spilling values we will need immediately).
     bool isFilled(Node* node)
     {
-        VirtualRegister virtualRegister = node->virtualRegister();
-        GenerationInfo& info = generationInfoFromVirtualRegister(virtualRegister);
-        return info.registerFormat() != DataFormatNone;
+        return generationInfo(node).registerFormat() != DataFormatNone;
     }
     bool isFilledDouble(Node* node)
     {
-        VirtualRegister virtualRegister = node->virtualRegister();
-        GenerationInfo& info = generationInfoFromVirtualRegister(virtualRegister);
-        return info.registerFormat() == DataFormatDouble;
+        return generationInfo(node).registerFormat() == DataFormatDouble;
     }
 
     // Called on an operand once it has been consumed by a parent node.
@@ -253,8 +247,7 @@ public:
     {
         if (!node->hasResult())
             return;
-        VirtualRegister virtualRegister = node->virtualRegister();
-        GenerationInfo& info = generationInfoFromVirtualRegister(virtualRegister);
+        GenerationInfo& info = generationInfo(node);
 
         // use() returns true when the value becomes dead, and any
         // associated resources may be freed.
@@ -333,6 +326,7 @@ public:
     // machine registers, implicitly generating speculation checks as needed.
     GPRReg fillSpeculateInt32(Edge, DataFormat& returnFormat);
     GPRReg fillSpeculateInt32Strict(Edge);
+    GPRReg fillSpeculateInt52(Edge, DataFormat desiredFormat);
     FPRReg fillSpeculateDouble(Edge);
     GPRReg fillSpeculateCell(Edge);
     GPRReg fillSpeculateBoolean(Edge);
@@ -468,6 +462,8 @@ public:
     {
         return boxDouble(fpr, allocate());
     }
+    
+    void boxInt52(GPRReg sourceGPR, GPRReg targetGPR, DataFormat);
 #elif USE(JSVALUE32_64)
     void boxDouble(FPRReg fpr, GPRReg tagGPR, GPRReg payloadGPR)
     {
@@ -559,11 +555,11 @@ public:
         }
     }
     
-    bool isKnownInteger(Node* node) { return !(m_state.forNode(node).m_type & ~SpecInt32); }
-    bool isKnownCell(Node* node) { return !(m_state.forNode(node).m_type & ~SpecCell); }
+    bool isKnownInteger(Node* node) { return m_state.forNode(node).isType(SpecInt32); }
+    bool isKnownCell(Node* node) { return m_state.forNode(node).isType(SpecCell); }
     
     bool isKnownNotInteger(Node* node) { return !(m_state.forNode(node).m_type & SpecInt32); }
-    bool isKnownNotNumber(Node* node) { return !(m_state.forNode(node).m_type & SpecNumber); }
+    bool isKnownNotNumber(Node* node) { return !(m_state.forNode(node).m_type & SpecFullNumber); }
     bool isKnownNotCell(Node* node) { return !(m_state.forNode(node).m_type & SpecCell); }
     
     // Checks/accessors for constant values.
@@ -816,6 +812,25 @@ public:
     {
         int32Result(reg, node, DataFormatInt32, mode);
     }
+    void int52Result(GPRReg reg, Node* node, DataFormat format, UseChildrenMode mode = CallUseChildren)
+    {
+        if (mode == CallUseChildren)
+            useChildren(node);
+
+        VirtualRegister virtualRegister = node->virtualRegister();
+        GenerationInfo& info = generationInfoFromVirtualRegister(virtualRegister);
+
+        m_gprs.retain(reg, virtualRegister, SpillOrderJS);
+        info.initInt52(node, node->refCount(), reg, format);
+    }
+    void int52Result(GPRReg reg, Node* node, UseChildrenMode mode = CallUseChildren)
+    {
+        int52Result(reg, node, DataFormatInt52, mode);
+    }
+    void strictInt52Result(GPRReg reg, Node* node, UseChildrenMode mode = CallUseChildren)
+    {
+        int52Result(reg, node, DataFormatStrictInt52, mode);
+    }
     void noResult(Node* node, UseChildrenMode mode = CallUseChildren)
     {
         if (mode == UseChildrenCalledExplicitly)
@@ -900,7 +915,7 @@ public:
     void initConstantInfo(Node* node)
     {
         ASSERT(isInt32Constant(node) || isNumberConstant(node) || isJSConstant(node));
-        generationInfoFromVirtualRegister(node->virtualRegister()).initConstant(node, node->refCount());
+        generationInfo(node).initConstant(node, node->refCount());
     }
     
     // These methods add calls to C++ helper functions.
@@ -1889,15 +1904,22 @@ public:
         if (isInt32Constant(node))
             return true;
 
-        VirtualRegister virtualRegister = node->virtualRegister();
-        GenerationInfo& info = generationInfoFromVirtualRegister(virtualRegister);
-        
-        return info.isJSInt32();
+        return generationInfo(node).isJSInt32();
+    }
+    
+    bool betterUseStrictInt52(Node* node)
+    {
+        return !generationInfo(node).isInt52();
+    }
+    bool betterUseStrictInt52(Edge edge)
+    {
+        return betterUseStrictInt52(edge.node());
     }
     
     bool compare(Node*, MacroAssembler::RelationalCondition, MacroAssembler::DoubleCondition, S_DFGOperation_EJJ);
     bool compilePeepHoleBranch(Node*, MacroAssembler::RelationalCondition, MacroAssembler::DoubleCondition, S_DFGOperation_EJJ);
     void compilePeepHoleInt32Branch(Node*, Node* branchNode, JITCompiler::RelationalCondition);
+    void compilePeepHoleInt52Branch(Node*, Node* branchNode, JITCompiler::RelationalCondition);
     void compilePeepHoleBooleanBranch(Node*, Node* branchNode, JITCompiler::RelationalCondition);
     void compilePeepHoleDoubleBranch(Node*, Node* branchNode, JITCompiler::DoubleCondition);
     void compilePeepHoleObjectEquality(Node*, Node* branchNode);
@@ -1945,6 +1967,7 @@ public:
     void compileNewTypedArray(Node*);
     
     void compileInt32Compare(Node*, MacroAssembler::RelationalCondition);
+    void compileInt52Compare(Node*, MacroAssembler::RelationalCondition);
     void compileBooleanCompare(Node*, MacroAssembler::RelationalCondition);
     void compileDoubleCompare(Node*, MacroAssembler::DoubleCondition);
     
@@ -2118,6 +2141,7 @@ public:
     void forwardTypeCheck(JSValueSource, Edge, SpeculatedType typesPassedThrough, MacroAssembler::Jump jumpToFail, const ValueRecovery&);
 
     void speculateInt32(Edge);
+    void speculateMachineInt(Edge);
     void speculateNumber(Edge);
     void speculateRealNumber(Edge);
     void speculateBoolean(Edge);
@@ -2195,6 +2219,16 @@ public:
     {
         return m_generationInfo[operandToLocal(virtualRegister)];
     }
+    
+    GenerationInfo& generationInfo(Node* node)
+    {
+        return generationInfoFromVirtualRegister(node->virtualRegister());
+    }
+    
+    GenerationInfo& generationInfo(Edge edge)
+    {
+        return generationInfo(edge.node());
+    }
 
     // The JIT, while also provides MacroAssembler functionality.
     JITCompiler& m_jit;
@@ -2676,6 +2710,179 @@ private:
     GPRReg m_gprOrInvalid;
 };
 
+// Gives you a canonical Int52 (i.e. it's left-shifted by 16, low bits zero).
+class SpeculateInt52Operand {
+public:
+    explicit SpeculateInt52Operand(SpeculativeJIT* jit, Edge edge, OperandSpeculationMode mode = AutomaticOperandSpeculation)
+        : m_jit(jit)
+        , m_edge(edge)
+        , m_gprOrInvalid(InvalidGPRReg)
+    {
+        ASSERT_UNUSED(mode, mode == ManualOperandSpeculation || edge.useKind() == MachineIntUse);
+        if (jit->isFilled(node()))
+            gpr();
+    }
+    
+    ~SpeculateInt52Operand()
+    {
+        ASSERT(m_gprOrInvalid != InvalidGPRReg);
+        m_jit->unlock(m_gprOrInvalid);
+    }
+    
+    Edge edge() const
+    {
+        return m_edge;
+    }
+    
+    Node* node() const
+    {
+        return edge().node();
+    }
+    
+    GPRReg gpr()
+    {
+        if (m_gprOrInvalid == InvalidGPRReg)
+            m_gprOrInvalid = m_jit->fillSpeculateInt52(edge(), DataFormatInt52);
+        return m_gprOrInvalid;
+    }
+    
+    void use()
+    {
+        m_jit->use(node());
+    }
+    
+private:
+    SpeculativeJIT* m_jit;
+    Edge m_edge;
+    GPRReg m_gprOrInvalid;
+};
+
+// Gives you a strict Int52 (i.e. the payload is in the low 48 bits, high 16 bits are sign-extended).
+class SpeculateStrictInt52Operand {
+public:
+    explicit SpeculateStrictInt52Operand(SpeculativeJIT* jit, Edge edge, OperandSpeculationMode mode = AutomaticOperandSpeculation)
+        : m_jit(jit)
+        , m_edge(edge)
+        , m_gprOrInvalid(InvalidGPRReg)
+    {
+        ASSERT_UNUSED(mode, mode == ManualOperandSpeculation || edge.useKind() == MachineIntUse);
+        if (jit->isFilled(node()))
+            gpr();
+    }
+    
+    ~SpeculateStrictInt52Operand()
+    {
+        ASSERT(m_gprOrInvalid != InvalidGPRReg);
+        m_jit->unlock(m_gprOrInvalid);
+    }
+    
+    Edge edge() const
+    {
+        return m_edge;
+    }
+    
+    Node* node() const
+    {
+        return edge().node();
+    }
+    
+    GPRReg gpr()
+    {
+        if (m_gprOrInvalid == InvalidGPRReg)
+            m_gprOrInvalid = m_jit->fillSpeculateInt52(edge(), DataFormatStrictInt52);
+        return m_gprOrInvalid;
+    }
+    
+    void use()
+    {
+        m_jit->use(node());
+    }
+    
+private:
+    SpeculativeJIT* m_jit;
+    Edge m_edge;
+    GPRReg m_gprOrInvalid;
+};
+
+enum OppositeShiftTag { OppositeShift };
+
+class SpeculateWhicheverInt52Operand {
+public:
+    explicit SpeculateWhicheverInt52Operand(SpeculativeJIT* jit, Edge edge, OperandSpeculationMode mode = AutomaticOperandSpeculation)
+        : m_jit(jit)
+        , m_edge(edge)
+        , m_gprOrInvalid(InvalidGPRReg)
+        , m_strict(jit->betterUseStrictInt52(edge))
+    {
+        ASSERT_UNUSED(mode, mode == ManualOperandSpeculation || edge.useKind() == MachineIntUse);
+        if (jit->isFilled(node()))
+            gpr();
+    }
+    
+    explicit SpeculateWhicheverInt52Operand(SpeculativeJIT* jit, Edge edge, const SpeculateWhicheverInt52Operand& other, OperandSpeculationMode mode = AutomaticOperandSpeculation)
+        : m_jit(jit)
+        , m_edge(edge)
+        , m_gprOrInvalid(InvalidGPRReg)
+        , m_strict(other.m_strict)
+    {
+        ASSERT_UNUSED(mode, mode == ManualOperandSpeculation || edge.useKind() == MachineIntUse);
+        if (jit->isFilled(node()))
+            gpr();
+    }
+    
+    explicit SpeculateWhicheverInt52Operand(SpeculativeJIT* jit, Edge edge, OppositeShiftTag, const SpeculateWhicheverInt52Operand& other, OperandSpeculationMode mode = AutomaticOperandSpeculation)
+        : m_jit(jit)
+        , m_edge(edge)
+        , m_gprOrInvalid(InvalidGPRReg)
+        , m_strict(!other.m_strict)
+    {
+        ASSERT_UNUSED(mode, mode == ManualOperandSpeculation || edge.useKind() == MachineIntUse);
+        if (jit->isFilled(node()))
+            gpr();
+    }
+    
+    ~SpeculateWhicheverInt52Operand()
+    {
+        ASSERT(m_gprOrInvalid != InvalidGPRReg);
+        m_jit->unlock(m_gprOrInvalid);
+    }
+    
+    Edge edge() const
+    {
+        return m_edge;
+    }
+    
+    Node* node() const
+    {
+        return edge().node();
+    }
+    
+    GPRReg gpr()
+    {
+        if (m_gprOrInvalid == InvalidGPRReg) {
+            m_gprOrInvalid = m_jit->fillSpeculateInt52(
+                edge(), m_strict ? DataFormatStrictInt52 : DataFormatInt52);
+        }
+        return m_gprOrInvalid;
+    }
+    
+    void use()
+    {
+        m_jit->use(node());
+    }
+    
+    DataFormat format() const
+    {
+        return m_strict ? DataFormatStrictInt52 : DataFormatInt52;
+    }
+
+private:
+    SpeculativeJIT* m_jit;
+    Edge m_edge;
+    GPRReg m_gprOrInvalid;
+    bool m_strict;
+};
+
 class SpeculateDoubleOperand {
 public:
     explicit SpeculateDoubleOperand(SpeculativeJIT* jit, Edge edge, OperandSpeculationMode mode = AutomaticOperandSpeculation)
index 1842cf6..ae64d2e 100644 (file)
@@ -888,8 +888,8 @@ FPRReg SpeculativeJIT::fillSpeculateDouble(Edge edge)
 #endif
     AbstractValue& value = m_state.forNode(edge);
     SpeculatedType type = value.m_type;
-    ASSERT(edge.useKind() != KnownNumberUse || !(value.m_type & ~SpecNumber));
-    m_interpreter.filter(value, SpecNumber);
+    ASSERT(edge.useKind() != KnownNumberUse || !(value.m_type & ~SpecFullNumber));
+    m_interpreter.filter(value, SpecFullNumber);
     VirtualRegister virtualRegister = edge->virtualRegister();
     GenerationInfo& info = generationInfoFromVirtualRegister(virtualRegister);
 
@@ -928,7 +928,7 @@ FPRReg SpeculativeJIT::fillSpeculateDouble(Edge edge)
 
             if (spillFormat != DataFormatJSInt32 && spillFormat != DataFormatInt32) {
                 JITCompiler::Jump isInteger = m_jit.branch32(MacroAssembler::Equal, JITCompiler::tagFor(virtualRegister), TrustedImm32(JSValue::Int32Tag));
-                if (type & ~SpecNumber)
+                if (type & ~SpecFullNumber)
                     speculationCheck(BadType, JSValueSource(JITCompiler::addressFor(virtualRegister)), edge, m_jit.branch32(MacroAssembler::AboveOrEqual, JITCompiler::tagFor(virtualRegister), TrustedImm32(JSValue::LowestTag)));
                 m_jit.loadDouble(JITCompiler::addressFor(virtualRegister), fpr);
                 hasUnboxedDouble = m_jit.jump();
@@ -963,7 +963,7 @@ FPRReg SpeculativeJIT::fillSpeculateDouble(Edge edge)
         if (info.registerFormat() != DataFormatJSInt32) {
             FPRTemporary scratch(this);
             JITCompiler::Jump isInteger = m_jit.branch32(MacroAssembler::Equal, tagGPR, TrustedImm32(JSValue::Int32Tag));
-            if (type & ~SpecNumber)
+            if (type & ~SpecFullNumber)
                 speculationCheck(BadType, JSValueRegs(tagGPR, payloadGPR), edge, m_jit.branch32(MacroAssembler::AboveOrEqual, tagGPR, TrustedImm32(JSValue::LowestTag)));
             unboxDouble(tagGPR, payloadGPR, fpr, scratch.fpr());
             hasUnboxedDouble = m_jit.jump();
@@ -2923,7 +2923,7 @@ void SpeculativeJIT::compile(Node* node)
             FPRReg valueFPR = value.fpr();
 
             DFG_TYPE_CHECK(
-                JSValueRegs(), node->child2(), SpecRealNumber,
+                JSValueRegs(), node->child2(), SpecFullRealNumber,
                 m_jit.branchDouble(MacroAssembler::DoubleNotEqualOrUnordered, valueFPR, valueFPR));
             
             m_jit.load32(MacroAssembler::Address(storageGPR, Butterfly::offsetOfPublicLength()), storageLengthGPR);
@@ -3187,7 +3187,7 @@ void SpeculativeJIT::compile(Node* node)
         
         op1.use();
         
-        if (!(m_state.forNode(node->child1()).m_type & ~(SpecNumber | SpecBoolean))) {
+        if (!(m_state.forNode(node->child1()).m_type & ~(SpecFullNumber | SpecBoolean))) {
             m_jit.move(op1TagGPR, resultTagGPR);
             m_jit.move(op1PayloadGPR, resultPayloadGPR);
         } else {
@@ -3289,7 +3289,7 @@ void SpeculativeJIT::compile(Node* node)
                     SpeculateDoubleOperand operand(this, use);
                     FPRReg opFPR = operand.fpr();
                     DFG_TYPE_CHECK(
-                        JSValueRegs(), use, SpecRealNumber,
+                        JSValueRegs(), use, SpecFullRealNumber,
                         m_jit.branchDouble(MacroAssembler::DoubleNotEqualOrUnordered, opFPR, opFPR));
         
                     m_jit.storeDouble(opFPR, MacroAssembler::Address(storageGPR, sizeof(double) * operandIdx));
@@ -3354,7 +3354,7 @@ void SpeculativeJIT::compile(Node* node)
                 SpeculateDoubleOperand operand(this, use);
                 FPRReg opFPR = operand.fpr();
                 DFG_TYPE_CHECK(
-                    JSValueRegs(), use, SpecRealNumber,
+                    JSValueRegs(), use, SpecFullRealNumber,
                     m_jit.branchDouble(MacroAssembler::DoubleNotEqualOrUnordered, opFPR, opFPR));
                 
                 m_jit.storeDouble(opFPR, reinterpret_cast<char*>(buffer + operandIdx));
@@ -4797,6 +4797,8 @@ void SpeculativeJIT::compile(Node* node)
     case CheckTierUpInLoop:
     case CheckTierUpAtReturn:
     case CheckTierUpAndOSREnter:
+    case Int52ToDouble:
+    case Int52ToValue:
         RELEASE_ASSERT_NOT_REACHED();
         break;
     }
index fb82123..ffdf135 100644 (file)
@@ -40,6 +40,29 @@ namespace JSC { namespace DFG {
 
 #if USE(JSVALUE64)
 
+void SpeculativeJIT::boxInt52(GPRReg sourceGPR, GPRReg targetGPR, DataFormat format)
+{
+    GPRReg tempGPR;
+    if (sourceGPR == targetGPR)
+        tempGPR = allocate();
+    else
+        tempGPR = targetGPR;
+    
+    FPRReg fpr = fprAllocate();
+
+    if (format == DataFormatInt52)
+        m_jit.rshift64(TrustedImm32(JSValue::int52ShiftAmount), sourceGPR);
+    else
+        ASSERT(format == DataFormatStrictInt52);
+    
+    m_jit.boxInt52(sourceGPR, targetGPR, tempGPR, fpr);
+    
+    if (tempGPR != targetGPR)
+        unlock(tempGPR);
+    
+    unlock(fpr);
+}
+
 GPRReg SpeculativeJIT::fillJSValue(Edge edge)
 {
     VirtualRegister virtualRegister = edge->virtualRegister();
@@ -69,11 +92,22 @@ GPRReg SpeculativeJIT::fillJSValue(Edge edge)
         } else {
             DataFormat spillFormat = info.spillFormat();
             m_gprs.retain(gpr, virtualRegister, SpillOrderSpilled);
-            if (spillFormat == DataFormatInt32) {
+            switch (spillFormat) {
+            case DataFormatInt32: {
                 m_jit.load32(JITCompiler::addressFor(virtualRegister), gpr);
                 m_jit.or64(GPRInfo::tagTypeNumberRegister, gpr);
                 spillFormat = DataFormatJSInt32;
-            } else {
+                break;
+            }
+                
+            case DataFormatInt52:
+            case DataFormatStrictInt52: {
+                m_jit.load64(JITCompiler::addressFor(virtualRegister), gpr);
+                boxInt52(gpr, gpr, spillFormat);
+                return gpr;
+            }
+                
+            default:
                 m_jit.load64(JITCompiler::addressFor(virtualRegister), gpr);
                 if (spillFormat == DataFormatDouble) {
                     // Need to box the double, since we want a JSValue.
@@ -81,6 +115,7 @@ GPRReg SpeculativeJIT::fillJSValue(Edge edge)
                     spillFormat = DataFormatJSDouble;
                 } else
                     RELEASE_ASSERT(spillFormat & DataFormatJS);
+                break;
             }
             info.fillJSValue(*m_stream, gpr, spillFormat);
         }
@@ -113,6 +148,16 @@ GPRReg SpeculativeJIT::fillJSValue(Edge edge)
 
         return gpr;
     }
+        
+    case DataFormatInt52:
+    case DataFormatStrictInt52: {
+        GPRReg gpr = info.gpr();
+        lock(gpr);
+        GPRReg resultGPR = allocate();
+        boxInt52(gpr, resultGPR, info.registerFormat());
+        unlock(gpr);
+        return resultGPR;
+    }
 
     case DataFormatCell:
         // No retag required on JSVALUE64!
@@ -768,7 +813,7 @@ GPRReg SpeculativeJIT::fillSpeculateInt32Internal(Edge edge, DataFormat& returnF
         
         DataFormat spillFormat = info.spillFormat();
         
-        RELEASE_ASSERT((spillFormat & DataFormatJS) || spillFormat == DataFormatInt32);
+        RELEASE_ASSERT((spillFormat & DataFormatJS) || spillFormat == DataFormatInt32 || spillFormat == DataFormatInt52 || spillFormat == DataFormatStrictInt52);
         
         m_gprs.retain(gpr, virtualRegister, SpillOrderSpilled);
         
@@ -789,6 +834,36 @@ GPRReg SpeculativeJIT::fillSpeculateInt32Internal(Edge edge, DataFormat& returnF
             returnFormat = DataFormatJSInt32;
             return gpr;
         }
+        if (spillFormat == DataFormatInt52 || spillFormat == DataFormatStrictInt52) {
+            // Generally, this can only happen if we've already proved that the
+            // value is an int32. That's because if a value originated as a JSValue
+            // then we would speculate that it's an int32 before representing it as
+            // an int52. Otherwise, if we knowingly produced an int52, then we would
+            // be boxing it into a value using Int52ToValue. This assertion is valid
+            // only because Int52 is something that we introduce at prediction time.
+            // However: we may have an int32-producing node replaced by an
+            // int52-producing node due to CSE. So we must do a check.
+            RELEASE_ASSERT(!(type & ~SpecMachineInt));
+            if (type & SpecInt52) {
+                GPRReg temp = allocate();
+                m_jit.signExtend32ToPtr(gpr, temp);
+                // Currently, we can't supply value profiling information here. :-/
+                speculationCheck(
+                    BadType, JSValueRegs(), 0,
+                    m_jit.branch64(MacroAssembler::NotEqual, gpr, temp));
+                unlock(temp);
+            }
+            if (spillFormat == DataFormatStrictInt52)
+                m_jit.load32(JITCompiler::addressFor(virtualRegister), gpr);
+            else {
+                m_jit.load64(JITCompiler::addressFor(virtualRegister), gpr);
+                m_jit.rshift64(TrustedImm32(JSValue::int52ShiftAmount), gpr);
+                m_jit.zeroExtend32ToPtr(gpr, gpr);
+            }
+            info.fillInt32(*m_stream, gpr);
+            returnFormat = DataFormatInt32;
+            return gpr;
+        }
         m_jit.load64(JITCompiler::addressFor(virtualRegister), gpr);
 
         // Fill as JSValue, and fall through.
@@ -797,6 +872,7 @@ GPRReg SpeculativeJIT::fillSpeculateInt32Internal(Edge edge, DataFormat& returnF
     }
 
     case DataFormatJS: {
+        RELEASE_ASSERT(!(type & SpecInt52));
         // Check the value is an integer.
         GPRReg gpr = info.gpr();
         m_gprs.lock(gpr);
@@ -843,6 +919,35 @@ GPRReg SpeculativeJIT::fillSpeculateInt32Internal(Edge edge, DataFormat& returnF
         returnFormat = DataFormatInt32;
         return gpr;
     }
+        
+    case DataFormatStrictInt52:
+    case DataFormatInt52: {
+        GPRReg gpr = info.gpr();
+        GPRReg result;
+        if (m_gprs.isLocked(gpr)) {
+            result = allocate();
+            m_jit.move(gpr, result);
+        } else {
+            lock(gpr);
+            info.fillInt32(*m_stream, gpr);
+            result = gpr;
+        }
+        RELEASE_ASSERT(!(type & ~SpecMachineInt));
+        if (info.registerFormat() == DataFormatInt52)
+            m_jit.rshift64(TrustedImm32(JSValue::int52ShiftAmount), result);
+        if (type & SpecInt52) {
+            GPRReg temp = allocate();
+            m_jit.signExtend32ToPtr(result, temp);
+            // Currently, we can't supply value profiling information here. :-/
+            speculationCheck(
+                BadType, JSValueRegs(), 0,
+                m_jit.branch64(MacroAssembler::NotEqual, result, temp));
+            unlock(temp);
+        }
+        m_jit.zeroExtend32ToPtr(result, result);
+        returnFormat = DataFormatInt32;
+        return gpr;
+    }
 
     case DataFormatDouble:
     case DataFormatJSDouble: {
@@ -885,6 +990,180 @@ GPRReg SpeculativeJIT::fillSpeculateInt32Strict(Edge edge)
     return result;
 }
 
+GPRReg SpeculativeJIT::fillSpeculateInt52(Edge edge, DataFormat desiredFormat)
+{
+    ASSERT(desiredFormat == DataFormatInt52 || desiredFormat == DataFormatStrictInt52);
+    AbstractValue& value = m_state.forNode(edge);
+    SpeculatedType type = value.m_type;
+    m_interpreter.filter(value, SpecMachineInt);
+    VirtualRegister virtualRegister = edge->virtualRegister();
+    GenerationInfo& info = generationInfoFromVirtualRegister(virtualRegister);
+
+    switch (info.registerFormat()) {
+    case DataFormatNone: {
+        if ((edge->hasConstant() && !valueOfJSConstant(edge.node()).isMachineInt()) || info.spillFormat() == DataFormatDouble) {
+            terminateSpeculativeExecution(Uncountable, JSValueRegs(), 0);
+            return allocate();
+        }
+        
+        GPRReg gpr = allocate();
+
+        if (edge->hasConstant()) {
+            JSValue jsValue = valueOfJSConstant(edge.node());
+            ASSERT(jsValue.isMachineInt());
+            m_gprs.retain(gpr, virtualRegister, SpillOrderConstant);
+            int64_t value = jsValue.asMachineInt();
+            if (desiredFormat == DataFormatInt52)
+                value = value << JSValue::int52ShiftAmount;
+            m_jit.move(MacroAssembler::Imm64(value), gpr);
+            info.fillGPR(*m_stream, gpr, desiredFormat);
+            return gpr;
+        }
+        
+        DataFormat spillFormat = info.spillFormat();
+        
+        RELEASE_ASSERT((spillFormat & DataFormatJS) || spillFormat == DataFormatInt32 || spillFormat == DataFormatInt52 || spillFormat == DataFormatStrictInt52);
+        
+        m_gprs.retain(gpr, virtualRegister, SpillOrderSpilled);
+        
+        if (spillFormat == DataFormatJSInt32 || spillFormat == DataFormatInt32) {
+            // If we know this was spilled as an integer we can fill without checking.
+            m_jit.load32(JITCompiler::addressFor(virtualRegister), gpr);
+            m_jit.signExtend32ToPtr(gpr, gpr);
+            if (desiredFormat == DataFormatStrictInt52) {
+                info.fillStrictInt52(*m_stream, gpr);
+                return gpr;
+            }
+            m_jit.lshift64(TrustedImm32(JSValue::int52ShiftAmount), gpr);
+            info.fillInt52(*m_stream, gpr);
+            return gpr;
+        }
+        if (spillFormat == DataFormatInt52 || spillFormat == DataFormatStrictInt52) {
+            m_jit.load64(JITCompiler::addressFor(virtualRegister), gpr);
+            if (desiredFormat == DataFormatStrictInt52) {
+                if (spillFormat == DataFormatInt52)
+                    m_jit.rshift64(TrustedImm32(JSValue::int52ShiftAmount), gpr);
+                info.fillStrictInt52(*m_stream, gpr);
+                return gpr;
+            }
+            if (spillFormat == DataFormatStrictInt52)
+                m_jit.lshift64(TrustedImm32(JSValue::int52ShiftAmount), gpr);
+            info.fillInt52(*m_stream, gpr);
+            return gpr;
+        }
+        m_jit.load64(JITCompiler::addressFor(virtualRegister), gpr);
+
+        // Fill as JSValue, and fall through.
+        info.fillJSValue(*m_stream, gpr, DataFormatJSInt32);
+        m_gprs.unlock(gpr);
+    }
+
+    case DataFormatJS: {
+        // Check the value is an integer. Note that we would *like* to unbox an Int52
+        // at this point but this is too costly. We only *prove* that this is an Int52
+        // even though we check if it's an int32.
+        GPRReg gpr = info.gpr();
+        GPRReg result;
+        if (m_gprs.isLocked(gpr)) {
+            result = allocate();
+            m_jit.move(gpr, result);
+        } else {
+            m_gprs.lock(gpr);
+            result = gpr;
+        }
+        if (type & ~SpecInt32)
+            speculationCheck(BadType, JSValueRegs(result), edge, m_jit.branch64(MacroAssembler::Below, result, GPRInfo::tagTypeNumberRegister));
+        if (result == gpr) // The not-already-locked, so fill in-place, case.
+            info.fillInt52(*m_stream, gpr, desiredFormat);
+        m_jit.signExtend32ToPtr(result, result);
+        if (desiredFormat == DataFormatInt52)
+            m_jit.lshift64(TrustedImm32(JSValue::int52ShiftAmount), result);
+        return result;
+    }
+
+    case DataFormatInt32:
+    case DataFormatJSInt32: {
+        GPRReg gpr = info.gpr();
+        GPRReg result;
+        if (m_gprs.isLocked(gpr)) {
+            result = allocate();
+            m_jit.move(gpr, result);
+        } else {
+            m_gprs.lock(gpr);
+            info.fillInt52(*m_stream, gpr, desiredFormat);
+            result = gpr;
+        }
+        m_jit.signExtend32ToPtr(result, result);
+        if (desiredFormat == DataFormatInt52)
+            m_jit.lshift64(TrustedImm32(JSValue::int52ShiftAmount), result);
+        return result;
+    }
+
+    case DataFormatStrictInt52: {
+        GPRReg gpr = info.gpr();
+        bool wasLocked = m_gprs.isLocked(gpr);
+        lock(gpr);
+        if (desiredFormat == DataFormatStrictInt52)
+            return gpr;
+        if (wasLocked) {
+            GPRReg result = allocate();
+            m_jit.move(gpr, result);
+            unlock(gpr);
+            gpr = result;
+        } else
+            info.fillStrictInt52(*m_stream, gpr);
+        m_jit.lshift64(TrustedImm32(JSValue::int52ShiftAmount), gpr);
+        return gpr;
+    }
+        
+    case DataFormatInt52: {
+        GPRReg gpr = info.gpr();
+        bool wasLocked = m_gprs.isLocked(gpr);
+        lock(gpr);
+        if (desiredFormat == DataFormatInt52)
+            return gpr;
+        if (wasLocked) {
+            GPRReg result = allocate();
+            m_jit.move(gpr, result);
+            unlock(gpr);
+            gpr = result;
+        } else
+            info.fillInt52(*m_stream, gpr);
+        m_jit.rshift64(TrustedImm32(JSValue::int52ShiftAmount), gpr);
+        return gpr;
+    }
+
+    case DataFormatDouble:
+    case DataFormatJSDouble:
+        if (edge->hasConstant()) {
+            JSValue jsValue = valueOfJSConstant(edge.node());
+            if (jsValue.isMachineInt()) {
+                int64_t value = jsValue.asMachineInt();
+                if (desiredFormat == DataFormatInt52)
+                    value = value << JSValue::int52ShiftAmount;
+                GPRReg gpr = allocate();
+                m_jit.move(MacroAssembler::Imm64(value), gpr);
+                return gpr;
+            }
+        }
+        
+    case DataFormatCell:
+    case DataFormatBoolean:
+    case DataFormatJSCell:
+    case DataFormatJSBoolean: {
+        terminateSpeculativeExecution(Uncountable, JSValueRegs(), 0);
+        return allocate();
+    }
+
+    case DataFormatStorage:
+        RELEASE_ASSERT_NOT_REACHED();
+        
+    default:
+        RELEASE_ASSERT_NOT_REACHED();
+        return InvalidGPRReg;
+    }
+}
+
 FPRReg SpeculativeJIT::fillSpeculateDouble(Edge edge)
 {
 #if DFG_ENABLE(DEBUG_VERBOSE)
@@ -892,8 +1171,8 @@ FPRReg SpeculativeJIT::fillSpeculateDouble(Edge edge)
 #endif
     AbstractValue& value = m_state.forNode(edge);
     SpeculatedType type = value.m_type;
-    ASSERT(edge.useKind() != KnownNumberUse || !(value.m_type & ~SpecNumber));
-    m_interpreter.filter(value, SpecNumber);
+    ASSERT(edge.useKind() != KnownNumberUse || !(value.m_type & ~SpecFullNumber));
+    m_interpreter.filter(value, SpecFullNumber);
     VirtualRegister virtualRegister = edge->virtualRegister();
     GenerationInfo& info = generationInfoFromVirtualRegister(virtualRegister);
 
@@ -945,6 +1224,24 @@ FPRReg SpeculativeJIT::fillSpeculateDouble(Edge edge)
             unlock(gpr);
             break;
         }
+            
+        case DataFormatInt52: {
+            GPRReg gpr = allocate();
+            m_gprs.retain(gpr, virtualRegister, SpillOrderSpilled);
+            m_jit.load64(JITCompiler::addressFor(virtualRegister), gpr);
+            info.fillInt52(*m_stream, gpr);
+            unlock(gpr);
+            break;
+        }
+            
+        case DataFormatStrictInt52: {
+            GPRReg gpr = allocate();
+            m_gprs.retain(gpr, virtualRegister, SpillOrderSpilled);
+            m_jit.load64(JITCompiler::addressFor(virtualRegister), gpr);
+            info.fillStrictInt52(*m_stream, gpr);
+            unlock(gpr);
+            break;
+        }
 
         default:
             GPRReg gpr = allocate();
@@ -978,7 +1275,7 @@ FPRReg SpeculativeJIT::fillSpeculateDouble(Edge edge)
 
         JITCompiler::Jump isInteger = m_jit.branch64(MacroAssembler::AboveOrEqual, jsValueGpr, GPRInfo::tagTypeNumberRegister);
 
-        if (type & ~SpecNumber)
+        if (type & ~SpecFullNumber)
             speculationCheck(BadType, JSValueRegs(jsValueGpr), edge, m_jit.branchTest64(MacroAssembler::Zero, jsValueGpr, GPRInfo::tagTypeNumberRegister));
 
         // First, if we get here we have a double encoded as a JSValue
@@ -1009,6 +1306,28 @@ FPRReg SpeculativeJIT::fillSpeculateDouble(Edge edge)
         m_gprs.unlock(gpr);
         return fpr;
     }
+        
+    case DataFormatInt52: {
+        FPRReg fpr = fprAllocate();
+        GPRReg gpr = info.gpr();
+        m_gprs.lock(gpr);
+        GPRReg temp = allocate();
+        m_jit.move(gpr, temp);
+        m_jit.rshift64(TrustedImm32(JSValue::int52ShiftAmount), temp);
+        m_jit.convertInt64ToDouble(temp, fpr);
+        unlock(temp);
+        m_gprs.unlock(gpr);
+        return fpr;
+    }
+        
+    case DataFormatStrictInt52: {
+        FPRReg fpr = fprAllocate();
+        GPRReg gpr = info.gpr();
+        m_gprs.lock(gpr);
+        m_jit.convertInt64ToDouble(gpr, fpr);
+        m_gprs.unlock(gpr);
+        return fpr;
+    }
 
     // Unbox the double
     case DataFormatJSDouble: {
@@ -1111,7 +1430,9 @@ GPRReg SpeculativeJIT::fillSpeculateCell(Edge edge)
     case DataFormatJSDouble:
     case DataFormatDouble:
     case DataFormatJSBoolean:
-    case DataFormatBoolean: {
+    case DataFormatBoolean:
+    case DataFormatInt52:
+    case DataFormatStrictInt52: {
         terminateSpeculativeExecution(Uncountable, JSValueRegs(), 0);
         return allocate();
     }
@@ -1194,7 +1515,9 @@ GPRReg SpeculativeJIT::fillSpeculateBoolean(Edge edge)
     case DataFormatJSDouble:
     case DataFormatDouble:
     case DataFormatJSCell:
-    case DataFormatCell: {
+    case DataFormatCell:
+    case DataFormatInt52:
+    case DataFormatStrictInt52: {
         terminateSpeculativeExecution(Uncountable, JSValueRegs(), 0);
         return allocate();
     }
@@ -1503,6 +1826,40 @@ void SpeculativeJIT::compileInt32Compare(Node* node, MacroAssembler::RelationalC
     jsValueResult(result.gpr(), m_currentNode, DataFormatJSBoolean);
 }
 
+void SpeculativeJIT::compileInt52Compare(Node* node, MacroAssembler::RelationalCondition condition)
+{
+    SpeculateWhicheverInt52Operand op1(this, node->child1());
+    SpeculateWhicheverInt52Operand op2(this, node->child2(), op1);
+    GPRTemporary result(this, Reuse, op1, op2);
+    
+    m_jit.compare64(condition, op1.gpr(), op2.gpr(), result.gpr());
+    
+    // If we add a DataFormatBool, we should use it here.
+    m_jit.or32(TrustedImm32(ValueFalse), result.gpr());
+    jsValueResult(result.gpr(), m_currentNode, DataFormatJSBoolean);
+}
+
+void SpeculativeJIT::compilePeepHoleInt52Branch(Node* node, Node* branchNode, JITCompiler::RelationalCondition condition)
+{
+    BasicBlock* taken = branchNode->takenBlock();
+    BasicBlock* notTaken = branchNode->notTakenBlock();
+
+    // The branch instruction will branch to the taken block.
+    // If taken is next, switch taken with notTaken & invert the branch condition so we can fall through.
+    if (taken == nextBlock()) {
+        condition = JITCompiler::invert(condition);
+        BasicBlock* tmp = taken;
+        taken = notTaken;
+        notTaken = tmp;
+    }
+    
+    SpeculateWhicheverInt52Operand op1(this, node->child1());
+    SpeculateWhicheverInt52Operand op2(this, node->child2(), op1);
+    
+    branch64(condition, op1.gpr(), op2.gpr(), taken);
+    jump(notTaken);
+}
+
 void SpeculativeJIT::compileDoubleCompare(Node* node, MacroAssembler::DoubleCondition condition)
 {
     SpeculateDoubleOperand op1(this, node->child1());
@@ -1906,6 +2263,16 @@ void SpeculativeJIT::compile(Node* node)
             break;
         }
             
+        case FlushedInt52: {
+            GPRTemporary result(this);
+            m_jit.load64(JITCompiler::addressFor(node->local()), result.gpr());
+            
+            VirtualRegister virtualRegister = node->virtualRegister();
+            m_gprs.retain(result.gpr(), virtualRegister, SpillOrderJS);
+            generationInfoFromVirtualRegister(virtualRegister).initInt52(node, node->refCount(), result.gpr());
+            break;
+        }
+            
         default:
             GPRTemporary result(this);
             m_jit.load64(JITCompiler::addressFor(node->local()), result.gpr());
@@ -1981,6 +2348,14 @@ void SpeculativeJIT::compile(Node* node)
             break;
         }
             
+        case FlushedInt52: {
+            SpeculateInt52Operand value(this, node->child1());
+            m_jit.store64(value.gpr(), JITCompiler::addressFor(node->local()));
+            noResult(node);
+            recordSetLocal(node->local(), ValueSource(Int52InJSStack));
+            break;
+        }
+            
         case FlushedCell: {
             SpeculateCellOperand cell(this, node->child1());
             GPRReg cellGPR = cell.gpr();
@@ -2104,6 +2479,22 @@ void SpeculativeJIT::compile(Node* node)
         break;
     }
         
+    case Int52ToValue: {
+        JSValueOperand operand(this, node->child1());
+        GPRTemporary result(this, Reuse, operand);
+        m_jit.move(operand.gpr(), result.gpr());
+        jsValueResult(result.gpr(), node);
+        break;
+    }
+        
+    case Int52ToDouble: {
+        SpeculateDoubleOperand operand(this, node->child1());
+        FPRTemporary result(this, operand);
+        m_jit.moveDouble(operand.fpr(), result.fpr());
+        doubleResult(result.fpr(), node);
+        break;
+    }
+        
     case ValueAdd:
     case ArithAdd:
         compileAdd(node);
@@ -2889,7 +3280,7 @@ void SpeculativeJIT::compile(Node* node)
             FPRReg valueFPR = value.fpr();
 
             DFG_TYPE_CHECK(
-                JSValueRegs(), node->child2(), SpecRealNumber,
+                JSValueRegs(), node->child2(), SpecFullRealNumber,
                 m_jit.branchDouble(MacroAssembler::DoubleNotEqualOrUnordered, valueFPR, valueFPR));
             
             m_jit.load32(MacroAssembler::Address(storageGPR, Butterfly::offsetOfPublicLength()), storageLengthGPR);
@@ -3105,7 +3496,7 @@ void SpeculativeJIT::compile(Node* node)
         
         op1.use();
         
-        if (!(m_state.forNode(node->child1()).m_type & ~(SpecNumber | SpecBoolean)))
+        if (!(m_state.forNode(node->child1()).m_type & ~(SpecFullNumber | SpecBoolean)))
             m_jit.move(op1GPR, resultGPR);
         else {
             MacroAssembler::Jump alreadyPrimitive = m_jit.branchTest64(MacroAssembler::NonZero, op1GPR, GPRInfo::tagMaskRegister);
@@ -3202,7 +3593,7 @@ void SpeculativeJIT::compile(Node* node)
                     SpeculateDoubleOperand operand(this, use);
                     FPRReg opFPR = operand.fpr();
                     DFG_TYPE_CHECK(
-                        JSValueRegs(), use, SpecRealNumber,
+                        JSValueRegs(), use, SpecFullRealNumber,
                         m_jit.branchDouble(
                             MacroAssembler::DoubleNotEqualOrUnordered, opFPR, opFPR));
                     m_jit.storeDouble(opFPR, MacroAssembler::Address(storageGPR, sizeof(double) * operandIdx));
@@ -3267,7 +3658,7 @@ void SpeculativeJIT::compile(Node* node)
                 FPRReg opFPR = operand.fpr();
                 GPRReg scratchGPR = scratch.gpr();
                 DFG_TYPE_CHECK(
-                    JSValueRegs(), use, SpecRealNumber,
+                    JSValueRegs(), use, SpecFullRealNumber,
                     m_jit.branchDouble(
                         MacroAssembler::DoubleNotEqualOrUnordered, opFPR, opFPR));
                 m_jit.boxDouble(opFPR, scratchGPR);
index 56ae6ad..073eb0e 100644 (file)
@@ -44,6 +44,9 @@ void printInternal(PrintStream& out, UseKind useKind)
     case KnownInt32Use:
         out.print("KnownInt32");
         break;
+    case MachineIntUse:
+        out.print("MachineInt");
+        break;
     case RealNumberUse:
         out.print("RealNumber");
         break;
index ecc63f6..7ad3905 100644 (file)
@@ -39,6 +39,7 @@ enum UseKind {
     UntypedUse,
     Int32Use,
     KnownInt32Use,
+    MachineIntUse,
     RealNumberUse,
     NumberUse,
     KnownNumberUse,
@@ -66,11 +67,13 @@ ALWAYS_INLINE SpeculatedType typeFilterFor(UseKind useKind)
     case Int32Use:
     case KnownInt32Use:
         return SpecInt32;
+    case MachineIntUse:
+        return SpecMachineInt;
     case RealNumberUse:
-        return SpecRealNumber;
+        return SpecFullRealNumber;
     case NumberUse:
     case KnownNumberUse:
-        return SpecNumber;
+        return SpecFullNumber;
     case BooleanUse:
         return SpecBoolean;
     case CellUse:
@@ -125,6 +128,7 @@ ALWAYS_INLINE bool isNumerical(UseKind kind)
     switch (kind) {
     case Int32Use:
     case KnownInt32Use:
+    case MachineIntUse:
     case RealNumberUse:
     case NumberUse:
     case KnownNumberUse:
index 879aa30..ef702e4 100644 (file)
@@ -45,6 +45,9 @@ void ValueSource::dump(PrintStream& out) const
     case Int32InJSStack:
         out.print("Int32");
         break;
+    case Int52InJSStack:
+        out.print("Int52");
+        break;
     case CellInJSStack:
         out.print("Cell");
         break;
index e6381de..159456f 100644 (file)
@@ -43,6 +43,7 @@ enum ValueSourceKind {
     SourceNotSet,
     ValueInJSStack,
     Int32InJSStack,
+    Int52InJSStack,
     CellInJSStack,
     BooleanInJSStack,
     DoubleInJSStack,
@@ -56,6 +57,8 @@ static inline ValueSourceKind dataFormatToValueSourceKind(DataFormat dataFormat)
     switch (dataFormat) {
     case DataFormatInt32:
         return Int32InJSStack;
+    case DataFormatInt52:
+        return Int52InJSStack;
     case DataFormatDouble:
         return DoubleInJSStack;
     case DataFormatBoolean:
@@ -79,6 +82,8 @@ static inline DataFormat valueSourceKindToDataFormat(ValueSourceKind kind)
         return DataFormatJS;
     case Int32InJSStack:
         return DataFormatInt32;
+    case Int52InJSStack:
+        return DataFormatInt52;
     case CellInJSStack:
         return DataFormatCell;
     case BooleanInJSStack:
@@ -139,6 +144,8 @@ public:
             return ValueSource(DoubleInJSStack);
         case FlushedInt32:
             return ValueSource(Int32InJSStack);
+        case FlushedInt52:
+            return ValueSource(Int52InJSStack);
         case FlushedCell:
             return ValueSource(CellInJSStack);
         case FlushedBoolean:
@@ -181,6 +188,9 @@ public:
         case Int32InJSStack:
             return ValueRecovery::alreadyInJSStackAsUnboxedInt32();
             
+        case Int52InJSStack:
+            return ValueRecovery::alreadyInJSStackAsUnboxedInt52();
+            
         case CellInJSStack:
             return ValueRecovery::alreadyInJSStackAsUnboxedCell();
             
index a13838a..3e68f44 100644 (file)
@@ -235,7 +235,7 @@ public:
         
         // If the variable is not a number prediction, then this doesn't
         // make any sense.
-        if (!isNumberSpeculation(prediction())) {
+        if (!isFullNumberSpeculation(prediction())) {
             // FIXME: we may end up forcing a local in inlined argument position to be a double even
             // if it is sometimes not even numeric, since this never signals the fact that it doesn't
             // want doubles. https://bugs.webkit.org/show_bug.cgi?id=109511
@@ -333,6 +333,9 @@ public:
         if (isInt32Speculation(prediction))
             return FlushedInt32;
         
+        if (enableInt52() && !operandIsArgument(m_local) && isMachineIntSpeculation(prediction))
+            return FlushedInt52;
+        
         if (isCellSpeculation(prediction))
             return FlushedCell;
         
index 5403eb3..ac5858a 100644 (file)
@@ -32,13 +32,23 @@ namespace JSC { namespace FTL {
 
 using namespace DFG;
 
-void CArgumentGetter::loadNextAndBox(ValueFormat format, GPRReg destination, GPRReg scratch)
+void CArgumentGetter::loadNextAndBox(
+    ValueFormat format, GPRReg destination, GPRReg scratch1, GPRReg scratch2)
 {
-    if (scratch == InvalidGPRReg) {
+    if (scratch1 == InvalidGPRReg) {
+        ASSERT(scratch2 == InvalidGPRReg);
         if (destination == GPRInfo::nonArgGPR0)
-            scratch = GPRInfo::nonArgGPR1;
+            scratch1 = GPRInfo::nonArgGPR1;
         else
-            scratch = GPRInfo::nonArgGPR0;
+            scratch1 = GPRInfo::nonArgGPR0;
+    }
+    if (scratch2 == InvalidGPRReg) {
+        if (destination != GPRInfo::nonArgGPR0 && scratch1 != GPRInfo::nonArgGPR0)
+            scratch2 = GPRInfo::nonArgGPR0;
+        else if (destination != GPRInfo::nonArgGPR1 && scratch1 != GPRInfo::nonArgGPR1)
+            scratch2 = GPRInfo::nonArgGPR1;
+        else
+            scratch2 = GPRInfo::nonArgGPR2;
     }
     
     switch (format) {
@@ -50,21 +60,26 @@ void CArgumentGetter::loadNextAndBox(ValueFormat format, GPRReg destination, GPR
             
     case ValueFormatUInt32: {
         loadNext32(destination);
-        MacroAssembler::Jump isInt = m_jit.branch32(
-            MacroAssembler::GreaterThanOrEqual,
-            destination, MacroAssembler::TrustedImm32(0));
-            
-        m_jit.moveDoubleTo64(FPRInfo::fpRegT0, scratch);
-        m_jit.convertInt32ToDouble(destination, FPRInfo::fpRegT0);
-        m_jit.boxDouble(FPRInfo::fpRegT0, destination);
-        m_jit.move64ToDouble(scratch, FPRInfo::fpRegT0);
-            
-        MacroAssembler::Jump done = m_jit.jump();
-            
-        isInt.link(&m_jit);
-        m_jit.or64(GPRInfo::tagTypeNumberRegister, destination);
+        m_jit.moveDoubleTo64(FPRInfo::fpRegT0, scratch2);
+        m_jit.boxInt52(destination, destination, scratch1, FPRInfo::fpRegT0);
+        m_jit.move64ToDouble(scratch2, FPRInfo::fpRegT0);
+        break;
+    }
+        
+    case ValueFormatInt52: {
+        loadNext64(destination);
+        m_jit.rshift64(AssemblyHelpers::TrustedImm32(JSValue::int52ShiftAmount), destination);
+        m_jit.moveDoubleTo64(FPRInfo::fpRegT0, scratch2);
+        m_jit.boxInt52(destination, destination, scratch1, FPRInfo::fpRegT0);
+        m_jit.move64ToDouble(scratch2, FPRInfo::fpRegT0);
+        break;
+    }
             
-        done.link(&m_jit);
+    case ValueFormatStrictInt52: {
+        loadNext64(destination);
+        m_jit.moveDoubleTo64(FPRInfo::fpRegT0, scratch2);
+        m_jit.boxInt52(destination, destination, scratch1, FPRInfo::fpRegT0);
+        m_jit.move64ToDouble(scratch2, FPRInfo::fpRegT0);
         break;
     }
             
@@ -80,10 +95,10 @@ void CArgumentGetter::loadNextAndBox(ValueFormat format, GPRReg destination, GPR
     }
             
     case ValueFormatDouble: {
-        m_jit.moveDoubleTo64(FPRInfo::fpRegT0, scratch);
+        m_jit.moveDoubleTo64(FPRInfo::fpRegT0, scratch1);
         loadNextDouble(FPRInfo::fpRegT0);
         m_jit.boxDouble(FPRInfo::fpRegT0, destination);
-        m_jit.move64ToDouble(scratch, FPRInfo::fpRegT0);
+        m_jit.move64ToDouble(scratch1, FPRInfo::fpRegT0);
         break;
     }
             
index 18fbb02..f80ffcc 100644 (file)
@@ -115,7 +115,8 @@ public:
     }
     
     void loadNextAndBox(
-        ValueFormat format, DFG::GPRReg destination, DFG::GPRReg scratch = InvalidGPRReg);
+        ValueFormat, DFG::GPRReg destination,
+        DFG::GPRReg scratch1 = InvalidGPRReg, DFG::GPRReg scratch2 = InvalidGPRReg);
 
 private:
     MacroAssembler::Address nextAddress()
index 7960667..4ad275a 100644 (file)
@@ -164,6 +164,8 @@ inline CapabilityLevel canCompile(Node* node)
     case CompareStrictEq:
         if (node->isBinaryUseKind(Int32Use))
             break;
+        if (node->isBinaryUseKind(MachineIntUse))
+            break;
         if (node->isBinaryUseKind(NumberUse))
             break;
         if (node->isBinaryUseKind(ObjectUse))
@@ -175,6 +177,8 @@ inline CapabilityLevel canCompile(Node* node)
     case CompareGreaterEq:
         if (node->isBinaryUseKind(Int32Use))
             break;
+        if (node->isBinaryUseKind(MachineIntUse))
+            break;
         if (node->isBinaryUseKind(NumberUse))
             break;
         return CannotCompile;
@@ -236,6 +240,7 @@ CapabilityLevel canCompile(Graph& graph)
                 case UntypedUse:
                 case Int32Use:
                 case KnownInt32Use:
+                case MachineIntUse:
                 case NumberUse:
                 case KnownNumberUse:
                 case RealNumberUse:
index b90c5cf..95dc82c 100644 (file)
@@ -53,6 +53,9 @@ void ExitValue::dumpInContext(PrintStream& out, DumpContext* context) const
     case ExitValueInJSStackAsInt32:
         out.print("InJSStackAsInt32");
         return;
+    case ExitValueInJSStackAsInt52:
+        out.print("InJSStackAsInt52");
+        return;
     case ExitValueInJSStackAsDouble:
         out.print("InJSStackAsDouble");
         return;
index 5814fc9..0abae2c 100644 (file)
@@ -49,6 +49,7 @@ enum ExitValueKind {
     ExitValueConstant,
     ExitValueInJSStack,
     ExitValueInJSStackAsInt32,
+    ExitValueInJSStackAsInt52,
     ExitValueInJSStackAsDouble
 };
 
@@ -82,6 +83,13 @@ public:
         return result;
     }
     
+    static ExitValue inJSStackAsInt52()
+    {
+        ExitValue result;
+        result.m_kind = ExitValueInJSStackAsInt52;
+        return result;
+    }
+    
     static ExitValue inJSStackAsDouble()
     {
         ExitValue result;
index c646af4..23d1541 100644 (file)
@@ -38,9 +38,12 @@ namespace JSC { namespace FTL {
 
 #define FOR_EACH_FTL_INTRINSIC(macro) \
     macro(addWithOverflow32, "llvm.sadd.with.overflow.i32", functionType(structType(m_context, int32, boolean), int32, int32)) \
+    macro(addWithOverflow64, "llvm.sadd.with.overflow.i64", functionType(structType(m_context, int64, boolean), int64, int64)) \
     macro(doubleAbs, "llvm.fabs.f64", functionType(doubleType, doubleType)) \
     macro(mulWithOverflow32, "llvm.smul.with.overflow.i32", functionType(structType(m_context, int32, boolean), int32, int32)) \
+    macro(mulWithOverflow64, "llvm.smul.with.overflow.i64", functionType(structType(m_context, int64, boolean), int64, int64)) \
     macro(subWithOverflow32, "llvm.ssub.with.overflow.i32", functionType(structType(m_context, int32, boolean), int32, int32)) \
+    macro(subWithOverflow64, "llvm.ssub.with.overflow.i64", functionType(structType(m_context, int64, boolean), int64, int64)) \
     macro(trap, "llvm.trap", functionType(voidType)) \
     macro(osrExit, "webkit_osr_exit", functionType(voidType, boolean, int32, Variadic))
 
index 3bc0875..89614ca 100644 (file)
@@ -151,6 +151,9 @@ private:
                 case NodeResultInt32:
                     type = m_out.int32;
                     break;
+                case NodeResultInt52:
+                    type = m_out.int64;
+                    break;
                 case NodeResultBoolean:
                     type = m_out.boolean;
                     break;
@@ -239,7 +242,6 @@ private:
             compilePhi();
             break;
         case JSConstant:
-            compileJSConstant();
             break;
         case WeakJSConstant:
             compileWeakJSConstant();
@@ -461,6 +463,9 @@ private:
         case Int32Use:
             m_out.set(lowInt32(m_node->child1()), destination);
             break;
+        case MachineIntUse:
+            m_out.set(lowInt52(m_node->child1()), destination);
+            break;
         case BooleanUse:
             m_out.set(lowBoolean(m_node->child1()), destination);
             break;
@@ -487,6 +492,9 @@ private:
         case NodeResultInt32:
             setInt32(m_out.get(source));
             break;
+        case NodeResultInt52:
+            setInt52(m_out.get(source));
+            break;
         case NodeResultBoolean:
             setBoolean(m_out.get(source));
             break;
@@ -591,6 +599,13 @@ private:
             return;
         }
             
+        case FlushedInt52: {
+            LValue value = lowInt52(m_node->child1());
+            m_out.store64(value, addressFor(variable->local()));
+            m_valueSources.operand(variable->local()) = ValueSource(Int52InJSStack);
+            return;
+        }
+            
         case FlushedCell: {
             LValue value = lowCell(m_node->child1());
             m_out.store64(value, addressFor(variable->local()));
@@ -655,6 +670,24 @@ private:
             break;
         }
             
+        case MachineIntUse: {
+            if (!m_state.forNode(m_node->child1()).couldBeType(SpecInt52)
+                && !m_state.forNode(m_node->child2()).couldBeType(SpecInt52)) {
+                Int52Kind kind;
+                LValue left = lowWhicheverInt52(m_node->child1(), kind);
+                LValue right = lowInt52(m_node->child2(), kind);
+                setInt52(m_out.add(left, right), kind);
+                break;
+            }
+            
+            LValue left = lowInt52(m_node->child1());
+            LValue right = lowInt52(m_node->child2());
+            LValue result = m_out.addWithOverflow64(left, right);
+            speculate(Int52Overflow, noValue(), 0, m_out.extractValue(result, 1));
+            setInt52(m_out.extractValue(result, 0));
+            break;
+        }
+            
         case NumberUse: {
             setDouble(
                 m_out.doubleAdd(lowDouble(m_node->child1()), lowDouble(m_node->child2())));
@@ -685,6 +718,24 @@ private:
             break;
         }
             
+        case MachineIntUse: {
+            if (!m_state.forNode(m_node->child1()).couldBeType(SpecInt52)
+                && !m_state.forNode(m_node->child2()).couldBeType(SpecInt52)) {
+                Int52Kind kind;
+                LValue left = lowWhicheverInt52(m_node->child1(), kind);
+                LValue right = lowInt52(m_node->child2(), kind);
+                setInt52(m_out.sub(left, right), kind);
+                break;
+            }
+            
+            LValue left = lowInt52(m_node->child1());
+            LValue right = lowInt52(m_node->child2());
+            LValue result = m_out.subWithOverflow64(left, right);
+            speculate(Int52Overflow, noValue(), 0, m_out.extractValue(result, 1));
+            setInt52(m_out.extractValue(result, 0));
+            break;
+        }
+            
         case NumberUse: {
             setDouble(
                 m_out.doubleSub(lowDouble(m_node->child1()), lowDouble(m_node->child2())));
@@ -730,6 +781,32 @@ private:
             break;
         }
             
+        case MachineIntUse: {
+            Int52Kind kind;
+            LValue left = lowWhicheverInt52(m_node->child1(), kind);
+            LValue right = lowInt52(m_node->child2(), opposite(kind));
+            
+            LValue overflowResult = m_out.mulWithOverflow64(left, right);
+            speculate(Int52Overflow, noValue(), 0, m_out.extractValue(overflowResult, 1));
+            LValue result = m_out.extractValue(overflowResult, 0);
+            
+            if (!bytecodeCanIgnoreNegativeZero(m_node->arithNodeFlags())) {
+                LBasicBlock slowCase = FTL_NEW_BLOCK(m_out, ("ArithMul slow case"));
+                LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("ArithMul continuation"));
+                
+                m_out.branch(m_out.notZero64(result), continuation, slowCase);
+                
+                LBasicBlock lastNext = m_out.appendTo(slowCase, continuation);
+                speculate(NegativeZero, noValue(), 0, m_out.lessThan(left, m_out.int64Zero));
+                speculate(NegativeZero, noValue(), 0, m_out.lessThan(right, m_out.int64Zero));
+                m_out.jump(continuation);
+                m_out.appendTo(continuation, lastNext);
+            }
+            
+            setInt52(result);
+            break;
+        }
+            
         case NumberUse: {
             setDouble(
                 m_out.doubleMul(lowDouble(m_node->child1()), lowDouble(m_node->child2())));
@@ -1032,6 +1109,26 @@ private:
             break;
         }
             
+        case MachineIntUse: {
+            if (!m_state.forNode(m_node->child1()).couldBeType(SpecInt52)) {
+                Int52Kind kind;
+                LValue value = lowWhicheverInt52(m_node->child1(), kind);
+                LValue result = m_out.neg(value);
+                if (!bytecodeCanIgnoreNegativeZero(m_node->arithNodeFlags()))
+                    speculate(NegativeZero, noValue(), 0, m_out.isZero64(result));
+                setInt52(result, kind);
+                break;
+            }
+            
+            LValue value = lowInt52(m_node->child1());
+            LValue overflowResult = m_out.subWithOverflow64(m_out.int64Zero, value);
+            speculate(Int52Overflow, noValue(), 0, m_out.extractValue(overflowResult, 1));
+            LValue result = m_out.extractValue(overflowResult, 0);
+            speculate(NegativeZero, noValue(), 0, m_out.isZero64(result));
+            setInt52(result);
+            break;
+        }
+            
         case NumberUse: {
             setDouble(m_out.doubleNeg(lowDouble(m_node->child1())));
             break;
@@ -1473,7 +1570,7 @@ private:
                 LValue value = lowDouble(child3);
                 
                 FTL_TYPE_CHECK(
-                    doubleValue(value), child3, SpecRealNumber,
+                    doubleValue(value), child3, SpecFullRealNumber,
                     m_out.doubleNotEqualOrUnordered(value, value));
                 
                 TypedPointer elementPointer = m_out.baseIndex(
@@ -1708,6 +1805,7 @@ private:
     void compileCompareEq()
     {
         if (m_node->isBinaryUseKind(Int32Use)
+            || m_node->isBinaryUseKind(MachineIntUse)
             || m_node->isBinaryUseKind(NumberUse)
             || m_node->isBinaryUseKind(ObjectUse)) {
             compileCompareStrictEq();
@@ -1734,6 +1832,14 @@ private:
             return;
         }
         
+        if (m_node->isBinaryUseKind(MachineIntUse)) {
+            Int52Kind kind;
+            LValue left = lowWhicheverInt52(m_node->child1(), kind);
+            LValue right = lowInt52(m_node->child2(), kind);
+            setBoolean(m_out.equal(left, right));
+            return;
+        }
+        
         if (m_node->isBinaryUseKind(NumberUse)) {
             setBoolean(
                 m_out.doubleEqual(lowDouble(m_node->child1()), lowDouble(m_node->child2())));
@@ -1782,6 +1888,14 @@ private:
             return;
         }
         
+        if (m_node->isBinaryUseKind(MachineIntUse)) {
+            Int52Kind kind;
+            LValue left = lowWhicheverInt52(m_node->child1(), kind);
+            LValue right = lowInt52(m_node->child2(), kind);
+            setBoolean(m_out.lessThan(left, right));
+            return;
+        }
+        
         if (m_node->isBinaryUseKind(NumberUse)) {
             setBoolean(
                 m_out.doubleLessThan(lowDouble(m_node->child1()), lowDouble(m_node->child2())));
@@ -1799,6 +1913,14 @@ private:
             return;
         }
         
+        if (m_node->isBinaryUseKind(MachineIntUse)) {
+            Int52Kind kind;
+            LValue left = lowWhicheverInt52(m_node->child1(), kind);
+            LValue right = lowInt52(m_node->child2(), kind);
+            setBoolean(m_out.lessThanOrEqual(left, right));
+            return;
+        }
+        
         if (m_node->isBinaryUseKind(NumberUse)) {
             setBoolean(
                 m_out.doubleLessThanOrEqual(
@@ -1817,6 +1939,14 @@ private:
             return;
         }
         
+        if (m_node->isBinaryUseKind(MachineIntUse)) {
+            Int52Kind kind;
+            LValue left = lowWhicheverInt52(m_node->child1(), kind);
+            LValue right = lowInt52(m_node->child2(), kind);
+            setBoolean(m_out.greaterThan(left, right));
+            return;
+        }
+        
         if (m_node->isBinaryUseKind(NumberUse)) {
             setBoolean(
                 m_out.doubleGreaterThan(
@@ -1836,6 +1966,14 @@ private:
             return;
         }
         
+        if (m_node->isBinaryUseKind(MachineIntUse)) {
+            Int52Kind kind;
+            LValue left = lowWhicheverInt52(m_node->child1(), kind);
+            LValue right = lowInt52(m_node->child2(), kind);
+            setBoolean(m_out.greaterThanOrEqual(left, right));
+            return;
+        }
+        
         if (m_node->isBinaryUseKind(NumberUse)) {
             setBoolean(
                 m_out.doubleGreaterThanOrEqual(
@@ -2352,10 +2490,27 @@ private:
     {
         ASSERT_UNUSED(mode, mode == ManualOperandSpeculation || (edge.useKind() == Int32Use || edge.useKind() == KnownInt32Use));
         
+        if (edge->hasConstant()) {
+            JSValue value = m_graph.valueOfJSConstant(edge.node());
+            if (!value.isInt32()) {
+                terminate(Uncountable);
+                return m_out.int32Zero;
+            }
+            return m_out.constInt32(value.asInt32());
+        }
+        
         LoweredNodeValue value = m_int32Values.get(edge.node());
         if (isValid(value))
             return value.value();
         
+        value = m_strictInt52Values.get(edge.node());
+        if (isValid(value))
+            return strictInt52ToInt32(edge, value.value());
+        
+        value = m_int52Values.get(edge.node());
+        if (isValid(value))
+            return strictInt52ToInt32(edge, int52ToStrictInt52(value.value()));
+        
         value = m_jsValueValues.get(edge.node());
         if (isValid(value)) {
             LValue boxedResult = value.value();
@@ -2371,10 +2526,122 @@ private:
         return m_out.int32Zero;
     }
     
+    enum Int52Kind { StrictInt52, Int52 };
+    LValue lowInt52(Edge edge, Int52Kind kind, OperandSpeculationMode mode = AutomaticOperandSpeculation)
+    {
+        ASSERT_UNUSED(mode, mode == ManualOperandSpeculation || edge.useKind() == MachineIntUse);
+        
+        if (edge->hasConstant()) {
+            JSValue value = m_graph.valueOfJSConstant(edge.node());
+            if (!value.isMachineInt()) {
+                terminate(Uncountable);
+                return m_out.int64Zero;
+            }
+            int64_t result = value.asMachineInt();
+            if (kind == Int52)
+                result <<= JSValue::int52ShiftAmount;
+            return m_out.constInt64(result);
+        }
+        
+        LoweredNodeValue value;
+        
+        switch (kind) {
+        case Int52:
+            value = m_int52Values.get(edge.node());
+            if (isValid(value))
+                return value.value();
+            
+            value = m_strictInt52Values.get(edge.node());
+            if (isValid(value))
+                return strictInt52ToInt52(value.value());
+            break;
+            
+        case StrictInt52:
+            value = m_strictInt52Values.get(edge.node());
+            if (isValid(value))
+                return value.value();
+            
+            value = m_int52Values.get(edge.node());
+            if (isValid(value))
+                return int52ToStrictInt52(value.value());
+            break;
+        }
+        
+        value = m_int32Values.get(edge.node());
+        if (isValid(value)) {
+            return setInt52WithStrictValue(
+                edge.node(), m_out.signExt(value.value(), m_out.int64), kind);
+        }
+        
+        RELEASE_ASSERT(!(m_state.forNode(edge).m_type & SpecInt52));
+        
+        value = m_jsValueValues.get(edge.node());
+        if (isValid(value)) {
+            LValue boxedResult = value.value();
+            FTL_TYPE_CHECK(
+                jsValueValue(boxedResult), edge, SpecMachineInt, isNotInt32(boxedResult));
+            return setInt52WithStrictValue(
+                edge.node(), m_out.signExt(unboxInt32(boxedResult), m_out.int64), kind);
+        }
+        
+        RELEASE_ASSERT(!(m_state.forNode(edge).m_type & SpecMachineInt));
+        terminate(Uncountable);
+        return m_out.int64Zero;
+    }
+    
+    LValue lowInt52(Edge edge, OperandSpeculationMode mode = AutomaticOperandSpeculation)
+    {
+        return lowInt52(edge, Int52, mode);
+    }
+    
+    LValue lowStrictInt52(Edge edge, OperandSpeculationMode mode = AutomaticOperandSpeculation)
+    {
+        return lowInt52(edge, StrictInt52, mode);
+    }
+    
+    bool betterUseStrictInt52(Node* node)
+    {
+        return !isValid(m_int52Values.get(node));
+    }
+    bool betterUseStrictInt52(Edge edge)
+    {
+        return betterUseStrictInt52(edge.node());
+    }
+    template<typename T>
+    Int52Kind bestInt52Kind(T node)
+    {
+        return betterUseStrictInt52(node) ? StrictInt52 : Int52;
+    }
+    Int52Kind opposite(Int52Kind kind)
+    {
+        switch (kind) {
+        case Int52:
+            return StrictInt52;
+        case StrictInt52:
+            return Int52;
+        }
+        RELEASE_ASSERT_NOT_REACHED();
+    }
+    
+    LValue lowWhicheverInt52(Edge edge, Int52Kind& kind, OperandSpeculationMode mode = AutomaticOperandSpeculation)
+    {
+        kind = bestInt52Kind(edge);
+        return lowInt52(edge, kind, mode);
+    }
+    
     LValue lowCell(Edge edge, OperandSpeculationMode mode = AutomaticOperandSpeculation)
     {
         ASSERT_UNUSED(mode, mode == ManualOperandSpeculation || isCell(edge.useKind()));
         
+        if (edge->op() == JSConstant) {
+            JSValue value = m_graph.valueOfJSConstant(edge.node());
+            if (!value.isCell()) {
+                terminate(Uncountable);
+                return m_out.intPtrZero;
+            }
+            return m_out.constIntPtr(value.asCell());
+        }
+        
         LoweredNodeValue value = m_jsValueValues.get(edge.node());
         if (isValid(value)) {
             LValue uncheckedValue = value.value();
@@ -2419,6 +2686,15 @@ private:
     {
         ASSERT_UNUSED(mode, mode == ManualOperandSpeculation || edge.useKind() == BooleanUse);
         
+        if (edge->hasConstant()) {
+            JSValue value = m_graph.valueOfJSConstant(edge.node());
+            if (!value.isBoolean()) {
+                terminate(Uncountable);
+                return m_out.booleanFalse;
+            }
+            return m_out.constBool(value.asBoolean());
+        }
+        
         LoweredNodeValue value = m_booleanValues.get(edge.node());
         if (isValid(value))
             return value.value();
@@ -2442,6 +2718,15 @@ private:
     {
         ASSERT_UNUSED(mode, mode == ManualOperandSpeculation || isDouble(edge.useKind()));
         
+        if (edge->hasConstant()) {
+            JSValue value = m_graph.valueOfJSConstant(edge.node());
+            if (!value.isNumber()) {
+                terminate(Uncountable);
+                return m_out.doubleZero;
+            }
+            return m_out.constDouble(value.asNumber());
+        }
+        
         LoweredNodeValue value = m_doubleValues.get(edge.node());
         if (isValid(value))
             return value.value();
@@ -2453,6 +2738,14 @@ private:
             return result;
         }
         
+        value = m_strictInt52Values.get(edge.node());
+        if (isValid(value))
+            return strictInt52ToDouble(edge, value.value());
+        
+        value = m_int52Values.get(edge.node());
+        if (isValid(value))
+            return strictInt52ToDouble(edge, int52ToStrictInt52(value.value()));
+        
         value = m_jsValueValues.get(edge.node());
         if (isValid(value)) {
             LValue boxedResult = value.value();
@@ -2472,7 +2765,7 @@ private:
             m_out.appendTo(doubleCase, continuation);
             
             FTL_TYPE_CHECK(
-                jsValueValue(boxedResult), edge, SpecNumber, isCellOrMisc(boxedResult));
+                jsValueValue(boxedResult), edge, SpecFullNumber, isCellOrMisc(boxedResult));
             
             ValueFromBlock unboxedDouble = m_out.anchor(unboxDouble(boxedResult));
             m_out.jump(continuation);
@@ -2485,7 +2778,7 @@ private:
             return result;
         }
         
-        RELEASE_ASSERT(!(m_state.forNode(edge).m_type & SpecNumber));
+        RELEASE_ASSERT(!(m_state.forNode(edge).m_type & SpecFullNumber));
         terminate(Uncountable);
         return m_out.doubleZero;
     }
@@ -2494,6 +2787,9 @@ private:
     {
         ASSERT_UNUSED(mode, mode == ManualOperandSpeculation || edge.useKind() == UntypedUse);
         
+        if (edge->hasConstant())
+            return m_out.constInt64(JSValue::encode(m_graph.valueOfJSConstant(edge.node())));
+        
         LoweredNodeValue value = m_jsValueValues.get(edge.node());
         if (isValid(value))
             return value.value();
@@ -2505,6 +2801,14 @@ private:
             return result;
         }
         
+        value = m_strictInt52Values.get(edge.node());
+        if (isValid(value))
+            return strictInt52ToJSValue(value.value());
+        
+        value = m_int52Values.get(edge.node());
+        if (isValid(value))
+            return strictInt52ToJSValue(int52ToStrictInt52(value.value()));
+        
         value = m_booleanValues.get(edge.node());
         if (isValid(value)) {
             LValue result = boxBoolean(value.value());
@@ -2534,6 +2838,77 @@ private:
         return result;
     }
     
+    LValue strictInt52ToInt32(Edge edge, LValue value)
+    {
+        LValue result = m_out.castToInt32(value);
+        FTL_TYPE_CHECK(
+            noValue(), edge, SpecInt32,
+            m_out.notEqual(m_out.signExt(result, m_out.int64), value));
+        setInt32(edge.node(), result);
+        return result;
+    }
+    
+    LValue strictInt52ToDouble(Edge edge, LValue value)
+    {
+        LValue result = m_out.intToDouble(value);
+        setDouble(edge.node(), result);
+        return result;
+    }
+    
+    LValue strictInt52ToJSValue(LValue value)
+    {
+        LBasicBlock isInt32 = FTL_NEW_BLOCK(m_out, ("strictInt52ToJSValue isInt32 case"));
+        LBasicBlock isDouble = FTL_NEW_BLOCK(m_out, ("strictInt52ToJSValue isDouble case"));
+        LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("strictInt52ToJSValue continuation"));
+        
+        Vector<ValueFromBlock, 2> results;
+            
+        LValue int32Value = m_out.castToInt32(value);
+        m_out.branch(
+            m_out.equal(m_out.signExt(int32Value, m_out.int64), value),
+            isInt32, isDouble);
+        
+        LBasicBlock lastNext = m_out.appendTo(isInt32, isDouble);
+        
+        results.append(m_out.anchor(boxInt32(int32Value)));
+        m_out.jump(continuation);
+        
+        m_out.appendTo(isDouble, continuation);
+        
+        results.append(m_out.anchor(boxDouble(m_out.intToDouble(value))));
+        m_out.jump(continuation);
+        
+        m_out.appendTo(continuation, lastNext);
+        return m_out.phi(m_out.int64, results);
+    }
+    
+    LValue setInt52WithStrictValue(Node* node, LValue value, Int52Kind kind)
+    {
+        switch (kind) {
+        case StrictInt52:
+            setStrictInt52(node, value);
+            return value;
+            
+        case Int52:
+            value = strictInt52ToInt52(value);
+            setInt52(node, value);
+            return value;
+        }
+        
+        RELEASE_ASSERT_NOT_REACHED();
+        return 0;
+    }
+
+    LValue strictInt52ToInt52(LValue value)
+    {
+        return m_out.shl(value, m_out.constInt64(JSValue::int52ShiftAmount));
+    }
+    
+    LValue int52ToStrictInt52(LValue value)
+    {
+        return m_out.aShr(value, m_out.constInt64(JSValue::int52ShiftAmount));
+    }
+    
     LValue isNotInt32(LValue jsValue)
     {
         return m_out.below(jsValue, m_tagTypeNumber);
@@ -2794,7 +3169,7 @@ private:
         
         LValue value = lowDouble(edge);
         FTL_TYPE_CHECK(
-            doubleValue(value), edge, SpecRealNumber,
+            doubleValue(value), edge, SpecFullRealNumber,
             m_out.doubleNotEqualOrUnordered(value, value));
     }
     
@@ -2802,7 +3177,7 @@ private:
     {
         lowBoolean(edge);
     }
-
+    
     bool masqueradesAsUndefinedWatchpointIsStillValid()
     {
         return m_graph.masqueradesAsUndefinedWatchpointIsStillValid(m_node->codeOrigin);
@@ -2933,6 +3308,10 @@ private:
                 m_valueSources[i] = ValueSource(Int32InJSStack);
                 break;
                 
+            case FlushedInt52:
+                m_valueSources[i] = ValueSource(Int52InJSStack);
+                break;
+                
             case FlushedDouble:
                 m_valueSources[i] = ValueSource(DoubleInJSStack);
                 break;
@@ -3036,6 +3415,9 @@ private:
             case Int32InJSStack:
                 exit.m_values[i] = ExitValue::inJSStackAsInt32();
                 break;
+            case Int52InJSStack:
+                exit.m_values[i] = ExitValue::inJSStackAsInt52();
+                break;
             case DoubleInJSStack:
                 exit.m_values[i] = ExitValue::inJSStackAsDouble();
                 break;
@@ -3139,6 +3521,18 @@ private:
             return;
         }
         
+        value = m_int52Values.get(node);
+        if (isValid(value)) {
+            addExitArgument(exit, arguments, index, ValueFormatInt52, value.value());
+            return;
+        }
+        
+        value = m_strictInt52Values.get(node);
+        if (isValid(value)) {
+            addExitArgument(exit, arguments, index, ValueFormatStrictInt52, value.value());
+            return;
+        }
+        
         value = m_booleanValues.get(node);
         if (isValid(value)) {
             addExitArgument(exit, arguments, index, ValueFormatBoolean, value.value());
@@ -3242,6 +3636,28 @@ private:
     {
         m_int32Values.set(node, LoweredNodeValue(value, m_highBlock));
     }
+    void setInt52(Node* node, LValue value)
+    {
+        m_int52Values.set(node, LoweredNodeValue(value, m_highBlock));
+    }
+    void setStrictInt52(Node* node, LValue value)
+    {
+        m_strictInt52Values.set(node, LoweredNodeValue(value, m_highBlock));
+    }
+    void setInt52(Node* node, LValue value, Int52Kind kind)
+    {
+        switch (kind) {
+        case Int52:
+            setInt52(node, value);
+            return;
+            
+        case StrictInt52:
+            setStrictInt52(node, value);
+            return;
+        }
+        
+        RELEASE_ASSERT_NOT_REACHED();
+    }
     void setJSValue(Node* node, LValue value)
     {
         m_jsValueValues.set(node, LoweredNodeValue(value, m_highBlock));
@@ -3263,6 +3679,18 @@ private:
     {
         setInt32(m_node, value);
     }
+    void setInt52(LValue value)
+    {
+        setInt52(m_node, value);
+    }
+    void setStrictInt52(LValue value)
+    {
+        setStrictInt52(m_node, value);
+    }
+    void setInt52(LValue value, Int52Kind kind)
+    {
+        setInt52(m_node, value, kind);
+    }
     void setJSValue(LValue value)
     {
         setJSValue(m_node, value);
@@ -3342,6 +3770,8 @@ private:
     LValue m_tagMask;
     
     HashMap<Node*, LoweredNodeValue> m_int32Values;
+    HashMap<Node*, LoweredNodeValue> m_strictInt52Values;
+    HashMap<Node*, LoweredNodeValue> m_int52Values;
     HashMap<Node*, LoweredNodeValue> m_jsValueValues;
     HashMap<Node*, LoweredNodeValue> m_booleanValues;
     HashMap<Node*, LoweredNodeValue> m_storageValues;
index 8fd15bb..cf0605a 100644 (file)
@@ -104,6 +104,8 @@ static void compileStub(
         jit.store64(GPRInfo::nonArgGPR0, AssemblyHelpers::addressFor(argument.operand()));
     }
     
+    // All temp registers are free at this point.
+    
     // Box anything that is already on the stack, or that is a constant.
     
     for (unsigned i = exit.m_values.size(); i--;) {
@@ -128,6 +130,13 @@ static void compileStub(
             jit.or64(GPRInfo::tagTypeNumberRegister, GPRInfo::regT0);
             jit.store64(GPRInfo::regT0, address);
             break;
+        case ExitValueInJSStackAsInt52:
+            jit.load64(address, GPRInfo::regT0);
+            jit.rshift64(
+                AssemblyHelpers::TrustedImm32(JSValue::int52ShiftAmount), GPRInfo::regT0);
+            jit.boxInt52(GPRInfo::regT0, GPRInfo::regT0, GPRInfo::regT1, FPRInfo::fpRegT0);
+            jit.store64(GPRInfo::regT0, address);
+            break;
         case ExitValueInJSStackAsDouble:
             jit.loadDouble(address, FPRInfo::fpRegT0);
             jit.boxDouble(FPRInfo::fpRegT0, GPRInfo::regT0);
@@ -160,9 +169,10 @@ static void compileStub(
     exit.m_code = FINALIZE_CODE_IF(
         shouldShowDisassembly(),
         patchBuffer,
-        ("FTL OSR exit #%u (bc#%u, %s) from %s",
+        ("FTL OSR exit #%u (bc#%u, %s) from %s, with operands = %s",
             exitID, exit.m_codeOrigin.bytecodeIndex,
-            exitKindToString(exit.m_kind), toCString(*codeBlock).data()));
+            exitKindToString(exit.m_kind), toCString(*codeBlock).data(),
+            toCString(ignoringContext<DumpContext>(exit.m_values)).data()));
 }
 
 extern "C" void* compileFTLOSRExit(ExecState* exec, unsigned exitID)
index dbc2d32..af68dd3 100644 (file)
@@ -166,6 +166,18 @@ public:
     {
         return call(mulWithOverflow32Intrinsic(), left, right);
     }
+    LValue addWithOverflow64(LValue left, LValue right)
+    {
+        return call(addWithOverflow64Intrinsic(), left, right);
+    }
+    LValue subWithOverflow64(LValue left, LValue right)
+    {
+        return call(subWithOverflow64Intrinsic(), left, right);
+    }
+    LValue mulWithOverflow64(LValue left, LValue right)
+    {
+        return call(mulWithOverflow64Intrinsic(), left, right);
+    }
     LValue doubleAbs(LValue value)
     {
         return call(doubleAbsIntrinsic(), value);
index 92f9709..fa200d7 100644 (file)
@@ -44,6 +44,12 @@ void printInternal(PrintStream& out, ValueFormat format)
     case ValueFormatUInt32:
         out.print("UInt32");
         return;
+    case ValueFormatInt52:
+        out.print("Int52");
+        return;
+    case ValueFormatStrictInt52:
+        out.print("StrictInt52");
+        return;
     case ValueFormatBoolean:
         out.print("Boolean");
         return;
index 357af50..f14e8c7 100644 (file)
@@ -41,6 +41,8 @@ enum ValueFormat {
     InvalidValueFormat,
     ValueFormatInt32,
     ValueFormatUInt32,
+    ValueFormatInt52,
+    ValueFormatStrictInt52,
     ValueFormatBoolean,
     ValueFormatJSValue,
     ValueFormatDouble
index a559521..c6d9e8f 100644 (file)
@@ -42,6 +42,9 @@ void ValueSource::dump(PrintStream& out) const
     case Int32InJSStack:
         out.print("Int32InJSStack");
         return;
+    case Int52InJSStack:
+        out.print("Int52InJSStack");
+        return;
     case DoubleInJSStack:
         out.print("DoubleInJSStack");
         return;
index 16719ff..53a29db 100644 (file)
@@ -40,6 +40,7 @@ enum ValueSourceKind {
     SourceNotSet,
     ValueInJSStack,
     Int32InJSStack,
+    Int52InJSStack,
     DoubleInJSStack,
     SourceIsDead,
     HaveNode
index 52d6a62..aef56f1 100644 (file)
@@ -73,6 +73,7 @@ namespace JSC {
         Instruction* vPC() const;
         InlineCallFrame* asInlineCallFrame() const;
         int32_t unboxedInt32() const;
+        int64_t unboxedInt52() const;
         bool unboxedBoolean() const;
         double unboxedDouble() const;
         JSCell* unboxedCell() const;
@@ -98,6 +99,7 @@ namespace JSC {
             InlineCallFrame* inlineCallFrame;
             EncodedValueDescriptor encodedValue;
             double number;
+            int64_t integer;
         } u;
     };
 
@@ -185,6 +187,11 @@ namespace JSC {
         return payload();
     }
 
+    ALWAYS_INLINE int64_t Register::unboxedInt52() const
+    {
+        return u.integer >> JSValue::int52ShiftAmount;
+    }
+
     ALWAYS_INLINE bool Register::unboxedBoolean() const
     {
         return !!payload();
index bf22c57..5b53645 100644 (file)
@@ -383,6 +383,9 @@ void Arguments::tearOffForInlineCallFrame(VM& vm, Register* registers, InlineCal
         case AlreadyInJSStackAsUnboxedInt32:
             value = jsNumber(location->unboxedInt32());
             break;
+        case AlreadyInJSStackAsUnboxedInt52:
+            value = jsNumber(location->unboxedInt52());
+            break;
         case AlreadyInJSStackAsUnboxedCell:
             value = location->unboxedCell();
             break;
index 040a782..404f6b3 100644 (file)
@@ -50,11 +50,11 @@ IndexingType leastUpperBoundOfIndexingTypeAndType(IndexingType indexingType, Spe
     case ALL_INT32_INDEXING_TYPES:
         if (isInt32Speculation(type))
             return (indexingType & ~IndexingShapeMask) | Int32Shape;
-        if (isNumberSpeculation(type))
+        if (isFullNumberSpeculation(type))
             return (indexingType & ~IndexingShapeMask) | DoubleShape;
         return (indexingType & ~IndexingShapeMask) | ContiguousShape;
     case ALL_DOUBLE_INDEXING_TYPES:
-        if (isNumberSpeculation(type))
+        if (isFullNumberSpeculation(type))
             return indexingType;
         return (indexingType & ~IndexingShapeMask) | ContiguousShape;
     case ALL_CONTIGUOUS_INDEXING_TYPES:
index b0dee89..c7c2876 100644 (file)
@@ -191,6 +191,7 @@ public:
 
     int32_t asInt32() const;
     uint32_t asUInt32() const;
+    int64_t asMachineInt() const;
     double asDouble() const;
     bool asBoolean() const;
     double asNumber() const;
@@ -202,6 +203,7 @@ public:
     bool isNull() const;
     bool isUndefinedOrNull() const;
     bool isBoolean() const;
+    bool isMachineInt() const;
     bool isNumber() const;
     bool isString() const;
     bool isPrimitive() const;
@@ -274,6 +276,13 @@ public:
 
     JS_EXPORT_PRIVATE JSObject* synthesizePrototype(ExecState*) const;
 
+#if USE(JSVALUE64)
+    // Constants used for Int52. Int52 isn't part of JSValue right now, but JSValues may be
+    // converted to Int52s and back again.
+    static const unsigned numberOfInt52Bits = 52;
+    static const unsigned int52ShiftAmount = 12;
+#endif
+
 private:
     template <class T> JSValue(WriteBarrierBase<T>);
 
index 24dad12..b34adf8 100644 (file)
@@ -494,6 +494,35 @@ ALWAYS_INLINE JSCell* JSValue::asCell() const
 
 #endif // USE(JSVALUE64)
 
+inline bool JSValue::isMachineInt() const
+{
+    if (isInt32())
+        return true;
+    if (!isNumber())
+        return false;
+    double number = asDouble();
+    if (number != number)
+        return false;
+    int64_t asInt64 = static_cast<int64_t>(number);
+    if (asInt64 != number)
+        return false;
+    if (!asInt64 && std::signbit(number))
+        return false;
+    if (asInt64 >= (static_cast<int64_t>(1) << (numberOfInt52Bits - 1)))
+        return false;
+    if (asInt64 < -(static_cast<int64_t>(1) << (numberOfInt52Bits - 1)))
+        return false;
+    return true;
+}
+
+inline int64_t JSValue::asMachineInt() const
+{
+    ASSERT(isMachineInt());
+    if (isInt32())
+        return asInt32();
+    return static_cast<int64_t>(asDouble());
+}
+
 inline bool JSValue::isString() const
 {
     return isCell() && asCell()->isString();
index 91612a4..1916337 100644 (file)
@@ -1,3 +1,15 @@
+2013-09-16  Filip Pizlo  <fpizlo@apple.com>
+
+        DFG should support Int52 for local variables
+        https://bugs.webkit.org/show_bug.cgi?id=121064
+
+        Reviewed by Oliver Hunt.
+
+        * wtf/PrintStream.h:
+        (WTF::ValueIgnoringContext::ValueIgnoringContext):
+        (WTF::ValueIgnoringContext::dump):
+        (WTF::ignoringContext):
+
 2013-09-17  Anders Carlsson  <andersca@apple.com>
 
         Stop explicitly using PassOwnPtr in WebCore/html
index 78e689c..3eaf775 100644 (file)
@@ -360,11 +360,36 @@ ValueInContext<T, U> inContext(const T& value, U* context)
     return ValueInContext<T, U>(value, context);
 }
 
+template<typename T, typename U>
+class ValueIgnoringContext {
+public:
+    ValueIgnoringContext(const U& value)
+        : m_value(&value)
+    {
+    }
+    
+    void dump(PrintStream& out) const
+    {
+        T context;
+        m_value->dumpInContext(out, &context);
+    }
+
+private:
+    const U* m_value;
+};
+
+template<typename T, typename U>
+ValueIgnoringContext<T, U> ignoringContext(const U& value)
+{
+    return ValueIgnoringContext<T, U>(value);
+}
+
 } // namespace WTF
 
 using WTF::CharacterDump;
 using WTF::PointerDump;
 using WTF::PrintStream;
+using WTF::ignoringContext;
 using WTF::inContext;
 using WTF::pointerDump;
 
index 63a5c60..7d63c56 100644 (file)
@@ -1,3 +1,12 @@
+2013-09-17  Filip Pizlo  <fpizlo@apple.com>
+
+        DFG should support Int52 for local variables
+        https://bugs.webkit.org/show_bug.cgi?id=121064
+
+        Reviewed by Oliver Hunt.
+
+        * Scripts/run-jsc-stress-tests:
+
 2013-09-17  Alex Christensen  <alex.christensen@flexsim.com>
 
         Added back and forward buttons to WinLauncher.
index 5d9464e..2c3b813 100755 (executable)
@@ -214,12 +214,11 @@ def defaultRun
     runDefault
     runAlwaysTriggerCopyPhase
     runNoCJIT
+    runDFGEager
     if $enableFTL
         runDefaultFTL
         runFTLNoCJIT
         runFTLEager
-    else
-        runDFGEager
     end
 end