Commit 4c466ec6 authored by fpizlo@apple.com's avatar fpizlo@apple.com

DFG should support Int52 for local variables

https://bugs.webkit.org/show_bug.cgi?id=121064

Source/JavaScriptCore: 

Reviewed by Oliver Hunt.
        
This adds Int52 support for local variables to the DFG and FTL. It's a speed-up on
programs that have local int32 overflows but where a larger int representation can
prevent us from having to convert all the way up to double.
        
It's a small speed-up for now. But we're just supporting Int52 for a handful of
operations (add, sub, mul, neg, compare, bitops, typed array access) and this lays
the groundwork for adding Int52 to JSValue, which will probably be a bigger
speed-up.
        
The basic approach is:
        
- We have a notion of Int52 in our typesystem. Int52 doesn't belong to BytecodeTop
  or HeapTop - i.e. it doesn't arise from JSValues.
        
- DFG treats Int52 as being part of its FullTop and will treat it as being a
  subtype of double unless instructed otherwise.
        
- Prediction propagator creates Int52s whenever we have a node going doubly but due
  to large values rather than fractional values, and that node is known to be able
  to produce Int52 natively in the DFG backend.
        
- Fixup phase converts edges to MachineIntUses in nodes that are known to be able
  to deal with Int52, and where we have a subtype of Int32|Int52 as the predicted
  input.
        
- The DFG backend and FTL LLVM IR lowering have two notions of Int52s - ones that
  are left-shifted by 16 (great for overflow checks) and ones that are
  sign-extended. Both backends know how to convert between Int52s and the other
  representations.

* assembler/MacroAssemblerX86_64.h:
(JSC::MacroAssemblerX86_64::rshift64):
(JSC::MacroAssemblerX86_64::mul64):
(JSC::MacroAssemblerX86_64::branchMul64):
(JSC::MacroAssemblerX86_64::branchNeg64):
(JSC::MacroAssemblerX86_64::convertInt64ToDouble):
* assembler/X86Assembler.h:
(JSC::X86Assembler::imulq_rr):
(JSC::X86Assembler::cvtsi2sdq_rr):
* bytecode/DataFormat.h:
(JSC::dataFormatToString):
* bytecode/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: http://svn.webkit.org/repository/webkit/trunk@156019 268f45cc-cd09-0410-ab3c-d52691b4dbfc
parent 4df0b920
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,
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
<!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>
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
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
<!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>
<!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>
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
<!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>
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;
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;
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;
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;
This diff is collapsed.
......@@ -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; }
......
......@@ -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);
......
......@@ -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:
......
......@@ -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:
......
......@@ -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.
......
......@@ -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));
}
}
......
......@@ -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());
......
......@@ -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;
......
......@@ -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
......
......@@ -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);