WebKit Bugzilla
New
Browse
Search+
Log In
×
Sign in with GitHub
or
Remember my login
Create Account
·
Forgot Password
Forgotten password account recovery
[patch]
the patch
blah.patch (text/plain), 202.78 KB, created by
Filip Pizlo
on 2013-09-16 19:05:49 PDT
(
hide
)
Description:
the patch
Filename:
MIME Type:
Creator:
Filip Pizlo
Created:
2013-09-16 19:05:49 PDT
Size:
202.78 KB
patch
obsolete
>Index: Source/JavaScriptCore/ChangeLog >=================================================================== >--- Source/JavaScriptCore/ChangeLog (revision 155909) >+++ Source/JavaScriptCore/ChangeLog (working copy) >@@ -1,3 +1,309 @@ >+2013-09-16 Filip Pizlo <fpizlo@apple.com> >+ >+ DFG should support Int48 for local variables >+ https://bugs.webkit.org/show_bug.cgi?id=121064 >+ >+ Reviewed by NOBODY (OOPS!). >+ >+ This adds Int48 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 Int48 for a handful of >+ operations (add, sub, mul, neg, compare, bitops, typed array access) and this lays >+ the groundwork for adding Int48 to JSValue, which will probably be a bigger >+ speed-up. >+ >+ The basic approach is: >+ >+ - We have a notion of Int48 in our typesystem. Int48 doesn't belong to BytecodeTop >+ or HeapTop - i.e. it doesn't arise from JSValues. >+ >+ - DFG treats Int48 as being part of its FullTop and will treat it as being a >+ subtype of double unless instructed otherwise. >+ >+ - Prediction propagator creates Int48s 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 Int48 natively in the DFG backend. >+ >+ - Fixup phase converts edges to MachineIntUses in nodes that are known to be able >+ to deal with Int48, and where we have a subtype of Int32|Int48 as the predicted >+ input. >+ >+ - The DFG backend and FTL LLVM IR lowering have two notions of Int48s - ones that >+ are left-shifted by 16 (great for overflow checks) and ones that are >+ sign-extended. Both backends know how to convert between Int48s 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::alreadyInJSStackAsUnboxedInt48): >+ (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::boxInt48): >+ * 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::enableInt48): >+ * 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::initInt48): >+ (JSC::DFG::GenerationInfo::initStrictInt48): >+ (JSC::DFG::GenerationInfo::isFormat): >+ (JSC::DFG::GenerationInfo::isInt48): >+ (JSC::DFG::GenerationInfo::isStrictInt48): >+ (JSC::DFG::GenerationInfo::fillInt48): >+ (JSC::DFG::GenerationInfo::fillStrictInt48): >+ * 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::int48Result): >+ (JSC::DFG::SpeculativeJIT::strictInt48Result): >+ (JSC::DFG::SpeculativeJIT::initConstantInfo): >+ (JSC::DFG::SpeculativeJIT::isInteger): >+ (JSC::DFG::SpeculativeJIT::betterUseStrictInt48): >+ (JSC::DFG::SpeculativeJIT::generationInfo): >+ (JSC::DFG::SpeculateInt48Operand::SpeculateInt48Operand): >+ (JSC::DFG::SpeculateInt48Operand::~SpeculateInt48Operand): >+ (JSC::DFG::SpeculateInt48Operand::edge): >+ (JSC::DFG::SpeculateInt48Operand::node): >+ (JSC::DFG::SpeculateInt48Operand::gpr): >+ (JSC::DFG::SpeculateInt48Operand::use): >+ (JSC::DFG::SpeculateStrictInt48Operand::SpeculateStrictInt48Operand): >+ (JSC::DFG::SpeculateStrictInt48Operand::~SpeculateStrictInt48Operand): >+ (JSC::DFG::SpeculateStrictInt48Operand::edge): >+ (JSC::DFG::SpeculateStrictInt48Operand::node): >+ (JSC::DFG::SpeculateStrictInt48Operand::gpr): >+ (JSC::DFG::SpeculateStrictInt48Operand::use): >+ (JSC::DFG::SpeculateWhicheverInt48Operand::SpeculateWhicheverInt48Operand): >+ (JSC::DFG::SpeculateWhicheverInt48Operand::~SpeculateWhicheverInt48Operand): >+ (JSC::DFG::SpeculateWhicheverInt48Operand::edge): >+ (JSC::DFG::SpeculateWhicheverInt48Operand::node): >+ (JSC::DFG::SpeculateWhicheverInt48Operand::gpr): >+ (JSC::DFG::SpeculateWhicheverInt48Operand::use): >+ (JSC::DFG::SpeculateWhicheverInt48Operand::format): >+ * dfg/DFGSpeculativeJIT32_64.cpp: >+ (JSC::DFG::SpeculativeJIT::fillSpeculateDouble): >+ (JSC::DFG::SpeculativeJIT::compile): >+ * dfg/DFGSpeculativeJIT64.cpp: >+ (JSC::DFG::SpeculativeJIT::boxInt48): >+ (JSC::DFG::SpeculativeJIT::fillJSValue): >+ (JSC::DFG::SpeculativeJIT::fillSpeculateInt32Internal): >+ (JSC::DFG::SpeculativeJIT::fillSpeculateInt48): >+ (JSC::DFG::SpeculativeJIT::fillSpeculateDouble): >+ (JSC::DFG::SpeculativeJIT::fillSpeculateCell): >+ (JSC::DFG::SpeculativeJIT::fillSpeculateBoolean): >+ (JSC::DFG::SpeculativeJIT::compileInt48Compare): >+ (JSC::DFG::SpeculativeJIT::compilePeepHoleInt48Branch): >+ (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::inJSStackAsInt48): >+ * 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::lowInt48): >+ (JSC::FTL::LowerDFGToLLVM::lowStrictInt48): >+ (JSC::FTL::LowerDFGToLLVM::betterUseStrictInt48): >+ (JSC::FTL::LowerDFGToLLVM::bestInt48Kind): >+ (JSC::FTL::LowerDFGToLLVM::opposite): >+ (JSC::FTL::LowerDFGToLLVM::Int48s::operator[]): >+ (JSC::FTL::LowerDFGToLLVM::lowWhicheverInt48): >+ (JSC::FTL::LowerDFGToLLVM::lowWhicheverInt48s): >+ (JSC::FTL::LowerDFGToLLVM::lowOpposingInt48s): >+ (JSC::FTL::LowerDFGToLLVM::lowCell): >+ (JSC::FTL::LowerDFGToLLVM::lowBoolean): >+ (JSC::FTL::LowerDFGToLLVM::lowDouble): >+ (JSC::FTL::LowerDFGToLLVM::lowJSValue): >+ (JSC::FTL::LowerDFGToLLVM::strictInt48ToInt32): >+ (JSC::FTL::LowerDFGToLLVM::strictInt48ToDouble): >+ (JSC::FTL::LowerDFGToLLVM::strictInt48ToJSValue): >+ (JSC::FTL::LowerDFGToLLVM::setInt48WithStrictValue): >+ (JSC::FTL::LowerDFGToLLVM::strictInt48ToInt48): >+ (JSC::FTL::LowerDFGToLLVM::int48ToStrictInt48): >+ (JSC::FTL::LowerDFGToLLVM::speculateRealNumber): >+ (JSC::FTL::LowerDFGToLLVM::initializeOSRExitStateForBlock): >+ (JSC::FTL::LowerDFGToLLVM::emitOSRExitCall): >+ (JSC::FTL::LowerDFGToLLVM::addExitArgumentForNode): >+ (JSC::FTL::LowerDFGToLLVM::setInt48): >+ (JSC::FTL::LowerDFGToLLVM::setStrictInt48): >+ * 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::unboxedInt48): >+ * 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-13 Mark Hahnenberg <mhahnenberg@apple.com> > > MarkedBlocks shouldn't be put in Allocated state if they didn't produce a FreeList >Index: Source/JavaScriptCore/assembler/MacroAssemblerX86_64.h >=================================================================== >--- Source/JavaScriptCore/assembler/MacroAssemblerX86_64.h (revision 155903) >+++ Source/JavaScriptCore/assembler/MacroAssemblerX86_64.h (working copy) >@@ -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: Source/JavaScriptCore/assembler/X86Assembler.h >=================================================================== >--- Source/JavaScriptCore/assembler/X86Assembler.h (revision 155903) >+++ Source/JavaScriptCore/assembler/X86Assembler.h (working copy) >@@ -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: Source/JavaScriptCore/bytecode/DataFormat.h >=================================================================== >--- Source/JavaScriptCore/bytecode/DataFormat.h (revision 155903) >+++ Source/JavaScriptCore/bytecode/DataFormat.h (working copy) >@@ -39,10 +39,12 @@ namespace JSC { > enum DataFormat { > DataFormatNone = 0, > DataFormatInt32 = 1, >- DataFormatDouble = 2, >- DataFormatBoolean = 3, >- DataFormatCell = 4, >- DataFormatStorage = 5, >+ DataFormatInt48 = 2, // Int48's are left-shifted by 16 by default. >+ DataFormatStrictInt48 = 3, // "Strict" Int48 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(Da > return "None"; > case DataFormatInt32: > return "Int32"; >+ case DataFormatInt48: >+ return "Int48"; >+ case DataFormatStrictInt48: >+ return "StrictInt48"; > case DataFormatDouble: > return "Double"; > case DataFormatCell: >Index: Source/JavaScriptCore/bytecode/OperandsInlines.h >=================================================================== >--- Source/JavaScriptCore/bytecode/OperandsInlines.h (revision 155903) >+++ Source/JavaScriptCore/bytecode/OperandsInlines.h (working copy) >@@ -43,7 +43,7 @@ void Operands<T, Traits>::dumpInContext( > 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: Source/JavaScriptCore/bytecode/SpeculatedType.cpp >=================================================================== >--- Source/JavaScriptCore/bytecode/SpeculatedType.cpp (revision 155903) >+++ Source/JavaScriptCore/bytecode/SpeculatedType.cpp (working copy) >@@ -154,10 +154,13 @@ void dumpSpeculation(PrintStream& out, S > } > > if (value & SpecInt32) >- myOut.print("Int"); >+ myOut.print("Int32"); > else > isTop = false; > >+ if (value & SpecInt48) >+ myOut.print("Int48"); >+ > if ((value & SpecDouble) == SpecDouble) > myOut.print("Double"); > else { >@@ -166,11 +169,6 @@ void dumpSpeculation(PrintStream& out, S > else > isTop = false; > >- if (value & SpecInt48) >- myOut.print("Int48"); >- else >- isTop = false; >- > if (value & SpecNonIntAsDouble) > myOut.print("Nonintasdouble"); > else >@@ -247,9 +245,11 @@ static const char* speculationToAbbrevia > return "<Int48AsDouble>"; > if (isInt48Speculation(prediction)) > return "<Int48>"; >+ 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(JSVa > 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 SpecInt48AsDouble; >+ return SpecNonIntAsDouble; > } > if (value.isCell()) > return speculationFromCell(value.asCell()); >Index: Source/JavaScriptCore/bytecode/SpeculatedType.h >=================================================================== >--- Source/JavaScriptCore/bytecode/SpeculatedType.h (revision 155903) >+++ Source/JavaScriptCore/bytecode/SpeculatedType.h (working copy) >@@ -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 SpecInt48 = 0x01000000; // It's definitely an Int48 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 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 = 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 Int48. >+static const SpeculatedType SpecBytecodeNumber = 0x0e800000; // It's either an Int32 or a Double. >+static const SpeculatedType SpecFullNumber = 0x0f800000; // It's either an Int32, Int48, 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 SpecInt48. >+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 SpecInt48. >+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(Speculate > > inline bool isInt32SpeculationForArithmetic(SpeculatedType value) > { >- return !(value & SpecDouble); >+ return !(value & (SpecDouble | SpecInt48)); > } > > inline bool isInt32SpeculationExpectingDefined(SpeculatedType value) >@@ -265,7 +267,7 @@ inline bool isMachineIntSpeculationExpec > > inline bool isMachineIntSpeculationForArithmetic(SpeculatedType value) > { >- return !(value & (SpecDouble & ~SpecMachineInt)); >+ return !(value & SpecDouble); > } > > inline bool isInt48AsDoubleSpeculation(SpeculatedType value) >@@ -293,19 +295,34 @@ inline bool isDoubleSpeculationForArithm > 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: Source/JavaScriptCore/bytecode/ValueRecovery.h >=================================================================== >--- Source/JavaScriptCore/bytecode/ValueRecovery.h (revision 155903) >+++ Source/JavaScriptCore/bytecode/ValueRecovery.h (working copy) >@@ -44,12 +44,15 @@ enum ValueRecoveryTechnique { > AlreadyInJSStack, > // It's already in the stack but unboxed. > AlreadyInJSStackAsUnboxedInt32, >+ AlreadyInJSStackAsUnboxedInt48, > AlreadyInJSStackAsUnboxedCell, > AlreadyInJSStackAsUnboxedBoolean, > AlreadyInJSStackAsUnboxedDouble, > // It's in a register. > InGPR, > UnboxedInt32InGPR, >+ UnboxedInt48InGPR, >+ UnboxedStrictInt48InGPR, > 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, >+ Int48DisplacedInJSStack, >+ StrictInt48DisplacedInJSStack, > DoubleDisplacedInJSStack, > CellDisplacedInJSStack, > BooleanDisplacedInJSStack, >@@ -95,6 +100,13 @@ public: > return result; > } > >+ static ValueRecovery alreadyInJSStackAsUnboxedInt48() >+ { >+ ValueRecovery result; >+ result.m_technique = AlreadyInJSStackAsUnboxedInt48; >+ return result; >+ } >+ > static ValueRecovery alreadyInJSStackAsUnboxedCell() > { > ValueRecovery result; >@@ -125,6 +137,10 @@ public: > ValueRecovery result; > if (dataFormat == DataFormatInt32) > result.m_technique = UnboxedInt32InGPR; >+ else if (dataFormat == DataFormatInt48) >+ result.m_technique = UnboxedInt48InGPR; >+ else if (dataFormat == DataFormatStrictInt48) >+ result.m_technique = UnboxedStrictInt48InGPR; > else if (dataFormat == DataFormatBoolean) > result.m_technique = UnboxedBooleanInGPR; > else >@@ -168,6 +184,14 @@ public: > result.m_technique = Int32DisplacedInJSStack; > break; > >+ case DataFormatInt48: >+ result.m_technique = Int48DisplacedInJSStack; >+ break; >+ >+ case DataFormatStrictInt48: >+ result.m_technique = StrictInt48DisplacedInJSStack; >+ break; >+ > case DataFormatDouble: > result.m_technique = DoubleDisplacedInJSStack; > break; >@@ -229,6 +253,7 @@ public: > switch (technique()) { > case AlreadyInJSStack: > case AlreadyInJSStackAsUnboxedInt32: >+ case AlreadyInJSStackAsUnboxedInt48: > 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 == UnboxedInt48InGPR || m_technique == UnboxedStrictInt48InGPR); > 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 == Int48DisplacedInJSStack || m_technique == StrictInt48DisplacedInJSStack); > return m_source.virtualReg; > } > >@@ -285,6 +310,9 @@ public: > case AlreadyInJSStackAsUnboxedInt32: > out.printf("(int32)"); > return; >+ case AlreadyInJSStackAsUnboxedInt48: >+ out.printf("(int48)"); >+ return; > case AlreadyInJSStackAsUnboxedCell: > out.printf("(cell)"); > return; >@@ -300,6 +328,12 @@ public: > case UnboxedInt32InGPR: > out.printf("int32(%%r%d)", gpr()); > return; >+ case UnboxedInt48InGPR: >+ out.printf("int48(%%r%d)", gpr()); >+ return; >+ case UnboxedStrictInt48InGPR: >+ out.printf("strictInt48(%%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 Int48DisplacedInJSStack: >+ out.printf("*int48(%d)", virtualRegister()); >+ return; >+ case StrictInt48DisplacedInJSStack: >+ out.printf("*strictInt48(%d)", virtualRegister()); >+ return; > case DoubleDisplacedInJSStack: > out.printf("*double(%d)", virtualRegister()); > return; >Index: Source/JavaScriptCore/dfg/DFGAbstractInterpreter.h >=================================================================== >--- Source/JavaScriptCore/dfg/DFGAbstractInterpreter.h (revision 155903) >+++ Source/JavaScriptCore/dfg/DFGAbstractInterpreter.h (working copy) >@@ -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: Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h >=================================================================== >--- Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h (revision 155903) >+++ Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h (working copy) >@@ -310,6 +310,29 @@ bool AbstractInterpreter<AbstractStateTy > break; > } > >+ case Int48ToDouble: { >+ JSValue child = forNode(node->child1()).value(); >+ if (child && child.isNumber()) { >+ setConstant(node, child); >+ break; >+ } >+ forNode(node).setType(SpecDouble); >+ break; >+ } >+ >+ case Int48ToValue: { >+ JSValue child = forNode(node->child1()).value(); >+ if (child && child.isNumber()) { >+ setConstant(node, child); >+ break; >+ } >+ SpeculatedType type = forNode(node->child1()).m_type; >+ if (type & SpecInt48) >+ type = (type | SpecInt32 | SpecInt48AsDouble) & ~SpecInt48; >+ forNode(node).setType(type); >+ break; >+ } >+ > case ValueAdd: > case ArithAdd: { > JSValue left = forNode(node->child1()).value(); >@@ -324,9 +347,15 @@ bool AbstractInterpreter<AbstractStateTy > if (!bytecodeCanTruncateInteger(node->arithNodeFlags())) > node->setCanExit(true); > break; >+ case MachineIntUse: >+ forNode(node).setType(SpecInt48); >+ 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<AbstractStateTy > 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<AbstractStateTy > if (!bytecodeCanTruncateInteger(node->arithNodeFlags())) > node->setCanExit(true); > break; >+ case MachineIntUse: >+ forNode(node).setType(SpecInt48); >+ 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<AbstractStateTy > if (!bytecodeCanTruncateInteger(node->arithNodeFlags())) > node->setCanExit(true); > break; >+ case MachineIntUse: >+ forNode(node).setType(SpecInt48); >+ if (m_state.forNode(node->child1()).couldBeType(SpecInt48)) >+ node->setCanExit(true); >+ if (!bytecodeCanIgnoreNegativeZero(node->arithNodeFlags())) >+ node->setCanExit(true); >+ break; > case NumberUse: > forNode(node).setType(SpecDouble); > break; >@@ -404,9 +446,13 @@ bool AbstractInterpreter<AbstractStateTy > || !bytecodeCanIgnoreNegativeZero(node->arithNodeFlags())) > node->setCanExit(true); > break; >+ case MachineIntUse: >+ forNode(node).setType(SpecInt48); >+ 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<AbstractStateTy > break; > } > >- if (isNumberSpeculation(abstractChild.m_type)) { >+ if (isFullNumberSpeculation(abstractChild.m_type)) { > setConstant(node, vm->smallStrings.numberString()); > break; > } >@@ -811,6 +857,8 @@ bool AbstractInterpreter<AbstractStateTy > case Array::Uint32Array: > if (node->shouldSpeculateInt32()) > forNode(node).setType(SpecInt32); >+ else if (enableInt48() && node->shouldSpeculateMachineInt()) >+ forNode(node).setType(SpecInt48); > else > forNode(node).setType(SpecDouble); > break; >@@ -863,7 +911,7 @@ bool AbstractInterpreter<AbstractStateTy > 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<AbstractStateTy > // 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<AbstractStateTy > 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: Source/JavaScriptCore/dfg/DFGAbstractValue.cpp >=================================================================== >--- Source/JavaScriptCore/dfg/DFGAbstractValue.cpp (revision 155903) >+++ Source/JavaScriptCore/dfg/DFGAbstractValue.cpp (working copy) >@@ -67,6 +67,8 @@ void AbstractValue::set(Graph& graph, JS > } > > m_type = speculationFromValue(value); >+ if (m_type == SpecInt48AsDouble) >+ m_type = SpecInt48; > m_value = value; > > checkConsistency(); >@@ -227,6 +229,7 @@ FiltrationResult AbstractValue::normaliz > return result; > } > >+#if !ASSERT_DISABLED > void AbstractValue::checkConsistency() const > { > if (!(m_type & SpecCell)) { >@@ -238,14 +241,19 @@ void AbstractValue::checkConsistency() c > 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 & SpecInt48) >+ type |= SpecInt48AsDouble; >+ 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: Source/JavaScriptCore/dfg/DFGAbstractValue.h >=================================================================== >--- Source/JavaScriptCore/dfg/DFGAbstractValue.h (revision 155903) >+++ Source/JavaScriptCore/dfg/DFGAbstractValue.h (working copy) >@@ -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 Int48's in a double (i.e. Int48AsDouble). >+ // So speculationFromValue(value) for an Int48 value will return Int48AsDouble, >+ // and that's fine - the type validates just fine. >+ SpeculatedType type = m_type; >+ if (type & SpecInt48) >+ type |= SpecInt48AsDouble; >+ >+ 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: Source/JavaScriptCore/dfg/DFGArrayMode.cpp >=================================================================== >--- Source/JavaScriptCore/dfg/DFGArrayMode.cpp (revision 155903) >+++ Source/JavaScriptCore/dfg/DFGArrayMode.cpp (working copy) >@@ -157,21 +157,21 @@ ArrayMode ArrayMode::refine(SpeculatedTy > 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: Source/JavaScriptCore/dfg/DFGAssemblyHelpers.h >=================================================================== >--- Source/JavaScriptCore/dfg/DFGAssemblyHelpers.h (revision 155903) >+++ Source/JavaScriptCore/dfg/DFGAssemblyHelpers.h (working copy) >@@ -293,6 +293,24 @@ public: > move64ToDouble(gpr, fpr); > return fpr; > } >+ >+ void boxInt48(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: Source/JavaScriptCore/dfg/DFGCSEPhase.cpp >=================================================================== >--- Source/JavaScriptCore/dfg/DFGCSEPhase.cpp (revision 155903) >+++ Source/JavaScriptCore/dfg/DFGCSEPhase.cpp (working copy) >@@ -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 Int48ToDouble: >+ case Int48ToValue: > if (cseMode == StoreElimination) > break; > setReplacement(pureCSE(node)); >Index: Source/JavaScriptCore/dfg/DFGClobberize.h >=================================================================== >--- Source/JavaScriptCore/dfg/DFGClobberize.h (revision 155903) >+++ Source/JavaScriptCore/dfg/DFGClobberize.h (working copy) >@@ -112,6 +112,8 @@ void clobberize(Graph& graph, Node* node > case LogicalNot: > case Int32ToDouble: > case ExtractOSREntryLocal: >+ case Int48ToDouble: >+ case Int48ToValue: > return; > > case MovHintAndCheck: >@@ -180,6 +182,7 @@ void clobberize(Graph& graph, Node* node > switch (node->binaryUseKind()) { > case Int32Use: > case NumberUse: >+ case MachineIntUse: > return; > case UntypedUse: > read(World); >Index: Source/JavaScriptCore/dfg/DFGCommon.h >=================================================================== >--- Source/JavaScriptCore/dfg/DFGCommon.h (revision 155903) >+++ Source/JavaScriptCore/dfg/DFGCommon.h (working copy) >@@ -143,6 +143,15 @@ inline bool enableConcurrentJIT() > #endif > } > >+inline bool enableInt48() >+{ >+#if USE(JSVALUE64) >+ return true; >+#else >+ return false; >+#endif >+} >+ > enum SpillRegistersMode { NeedToSpill, DontSpill }; > > enum NoResultTag { NoResult }; >Index: Source/JavaScriptCore/dfg/DFGFixupPhase.cpp >=================================================================== >--- Source/JavaScriptCore/dfg/DFGFixupPhase.cpp (revision 155903) >+++ Source/JavaScriptCore/dfg/DFGFixupPhase.cpp (working copy) >@@ -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 (enableInt48() >+ && 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 (enableInt48() >+ && 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() & SpecInt48) >+ 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 Int48ToDouble: >+ case Int48ToValue: > RELEASE_ASSERT_NOT_REACHED(); > break; > >@@ -1189,6 +1226,9 @@ private: > case FlushedInt32: > fixEdge<Int32Use>(node->child1()); > break; >+ case FlushedInt48: >+ 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()); >@@ -1321,6 +1378,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 +1408,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 (enableInt48() && edge->shouldSpeculateMachineInt()) { >+ // Make all double uses of int48 values have an intermediate Int48ToDouble. >+ // This is for the same reason as Int48ToValue (see below) except that >+ // Int8ToDouble will convert int48's that fit in an int32 into a double >+ // rather than trying to create a boxed int32 like Int48ToValue does. >+ >+ Node* result = m_insertionSet.insertNode( >+ m_indexInBlock, SpecInt48AsDouble, Int48ToDouble, >+ m_currentNode->codeOrigin, Edge(edge.node(), NumberUse)); >+ edge = Edge(result, useKind); >+ return; >+ } >+ } >+ >+ if (enableInt48() && useKind != MachineIntUse >+ && edge->shouldSpeculateMachineInt() && !edge->shouldSpeculateInt32()) { >+ // We make all non-int48 uses of int48 values have an intermediate Int48ToValue >+ // node to ensure that we handle this properly: >+ // >+ // a: SomeInt48 >+ // b: ArithAdd(@a, ...) >+ // c: Call(..., @a) >+ // d: ArithAdd(@a, ...) >+ // >+ // Without an intermediate node and just labeling the uses, we will get: >+ // >+ // a: SomeInt48 >+ // b: ArithAdd(Int48:@a, ...) >+ // c: Call(..., Untyped:@a) >+ // d: ArithAdd(Int48:@a, ...) >+ // >+ // And now the c->Untyped:@a edge will box the value of @a into a double. This >+ // is bad, because now the d->Int48:@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-Int48 uses of predicted Int48's use >+ // an intervening Int48ToValue node: >+ // >+ // a: SomeInt48 >+ // b: ArithAdd(Int48:@a, ...) >+ // x: Int48ToValue(Int48:@a) >+ // c: Call(..., Untyped:@x) >+ // d: ArithAdd(Int48:@a, ...) >+ // >+ // Note that even if we had multiple non-int48 uses of @a, the multiple >+ // Int48ToValue'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 int48. >+ // >+ // An alternative would have been to insert ToNativeInt48 nodes on int48 uses of >+ // int48's. This would have handled the above example but would fall over for: >+ // >+ // a: SomeInt48 >+ // b: Call(..., @a) >+ // c: ArithAdd(@a, ...) >+ // >+ // But the solution we use handles the above gracefully. >+ >+ Node* result = m_insertionSet.insertNode( >+ m_indexInBlock, SpecInt48, Int48ToValue, >+ m_currentNode->codeOrigin, Edge(edge.node(), UntypedUse)); >+ edge = Edge(result, useKind); > return; > } > > observeUseKindOnNode<useKind>(edge.node()); >+ > edge.setUseKind(useKind); > } > >@@ -1378,7 +1507,7 @@ private: > void injectInt32ToDoubleNode(Edge& edge, UseKind useKind = NumberUse, SpeculationDirection direction = BackwardSpeculation) > { > Node* result = m_insertionSet.insertNode( >- m_indexInBlock, SpecInt48, Int32ToDouble, >+ m_indexInBlock, SpecInt48AsDouble, Int32ToDouble, > m_currentNode->codeOrigin, Edge(edge.node(), NumberUse)); > if (direction == ForwardSpeculation) > result->mergeFlags(NodeExitsForward); >@@ -1434,13 +1563,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: Source/JavaScriptCore/dfg/DFGFlushFormat.cpp >=================================================================== >--- Source/JavaScriptCore/dfg/DFGFlushFormat.cpp (revision 155903) >+++ Source/JavaScriptCore/dfg/DFGFlushFormat.cpp (working copy) >@@ -41,6 +41,9 @@ void printInternal(PrintStream& out, Flu > case FlushedInt32: > out.print("FlushedInt32"); > return; >+ case FlushedInt48: >+ out.print("FlushedInt48"); >+ return; > case FlushedDouble: > out.print("FlushedDouble"); > return; >Index: Source/JavaScriptCore/dfg/DFGFlushFormat.h >=================================================================== >--- Source/JavaScriptCore/dfg/DFGFlushFormat.h (revision 155903) >+++ Source/JavaScriptCore/dfg/DFGFlushFormat.h (working copy) >@@ -40,6 +40,7 @@ namespace JSC { namespace DFG { > enum FlushFormat { > DeadFlush, > FlushedInt32, >+ FlushedInt48, > FlushedDouble, > FlushedCell, > FlushedBoolean, >@@ -55,6 +56,8 @@ inline NodeFlags resultFor(FlushFormat f > return NodeResultJS; > case FlushedInt32: > return NodeResultInt32; >+ case FlushedInt48: >+ return NodeResultInt48; > case FlushedDouble: > return NodeResultNumber; > case FlushedBoolean: >@@ -74,6 +77,8 @@ inline UseKind useKindFor(FlushFormat fo > return CellUse; > case FlushedInt32: > return Int32Use; >+ case FlushedInt48: >+ return MachineIntUse; > case FlushedDouble: > return NumberUse; > case FlushedBoolean: >Index: Source/JavaScriptCore/dfg/DFGGenerationInfo.h >=================================================================== >--- Source/JavaScriptCore/dfg/DFGGenerationInfo.h (revision 155903) >+++ Source/JavaScriptCore/dfg/DFGGenerationInfo.h (working copy) >@@ -86,6 +86,19 @@ public: > { > initGPR(node, useCount, gpr, DataFormatInt32); > } >+ void initInt48(Node* node, uint32_t useCount, GPRReg reg, DataFormat format) >+ { >+ ASSERT(format == DataFormatInt48 || format == DataFormatStrictInt48); >+ initGPR(node, useCount, reg, format); >+ } >+ void initInt48(Node* node, uint32_t useCount, GPRReg reg) >+ { >+ initGPR(node, useCount, reg, DataFormatInt48); >+ } >+ void initStrictInt48(Node* node, uint32_t useCount, GPRReg reg) >+ { >+ initGPR(node, useCount, reg, DataFormatStrictInt48); >+ } > #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 isInt48() >+ { >+ return isFormat(DataFormatInt48); >+ } >+ >+ bool isStrictInt48() >+ { >+ return isFormat(DataFormatStrictInt48); >+ } >+ > bool isJSDouble() > { > return isJSFormat(DataFormatJSDouble); >@@ -314,6 +342,19 @@ public: > { > fillGPR(stream, gpr, DataFormatInt32); > } >+ void fillInt48(VariableEventStream& stream, GPRReg gpr, DataFormat format) >+ { >+ ASSERT(format == DataFormatInt48 || format == DataFormatStrictInt48); >+ fillGPR(stream, gpr, format); >+ } >+ void fillInt48(VariableEventStream& stream, GPRReg gpr) >+ { >+ fillGPR(stream, gpr, DataFormatInt48); >+ } >+ void fillStrictInt48(VariableEventStream& stream, GPRReg gpr) >+ { >+ fillGPR(stream, gpr, DataFormatStrictInt48); >+ } > void fillBoolean(VariableEventStream& stream, GPRReg gpr) > { > fillGPR(stream, gpr, DataFormatBoolean); >Index: Source/JavaScriptCore/dfg/DFGGraph.cpp >=================================================================== >--- Source/JavaScriptCore/dfg/DFGGraph.cpp (revision 155903) >+++ Source/JavaScriptCore/dfg/DFGGraph.cpp (working copy) >@@ -236,14 +236,14 @@ void Graph::dump(PrintStream& out, const > 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: Source/JavaScriptCore/dfg/DFGGraph.h >=================================================================== >--- Source/JavaScriptCore/dfg/DFGGraph.h (revision 155903) >+++ Source/JavaScriptCore/dfg/DFGGraph.h (working copy) >@@ -230,14 +230,17 @@ public: > > bool addShouldSpeculateMachineInt(Node* add) > { >+ if (!enableInt48()) >+ 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); > } >@@ -257,10 +260,13 @@ public: > { > ASSERT(mul->op() == ArithMul); > >+ if (!enableInt48()) >+ return false; >+ > Node* left = mul->child1().node(); > Node* right = mul->child2().node(); > >- return Node::shouldSpeculateMachineIntForArithmetic(left, right) >+ return Node::shouldSpeculateMachineInt(left, right) > && mul->canSpeculateInt48() > && !hasExitSite(mul, Int48Overflow); > } >@@ -274,7 +280,9 @@ public: > bool negateShouldSpeculateMachineInt(Node* negate) > { > ASSERT(negate->op() == ArithNegate); >- return negate->child1()->shouldSpeculateMachineIntForArithmetic() >+ if (!enableInt48()) >+ return false; >+ return negate->child1()->shouldSpeculateMachineInt() > && !hasExitSite(negate, Int48Overflow) > && negate->canSpeculateInt48(); > } >Index: Source/JavaScriptCore/dfg/DFGInPlaceAbstractState.cpp >=================================================================== >--- Source/JavaScriptCore/dfg/DFGInPlaceAbstractState.cpp (revision 155903) >+++ Source/JavaScriptCore/dfg/DFGInPlaceAbstractState.cpp (working copy) >@@ -313,8 +313,8 @@ bool InPlaceAbstractState::mergeStateAtT > // 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.filter(SpecDouble); >Index: Source/JavaScriptCore/dfg/DFGJITCode.cpp >=================================================================== >--- Source/JavaScriptCore/dfg/DFGJITCode.cpp (revision 155903) >+++ Source/JavaScriptCore/dfg/DFGJITCode.cpp (working copy) >@@ -103,6 +103,9 @@ void JITCode::reconstruct( > case AlreadyInJSStackAsUnboxedInt32: > value = jsNumber(exec->r(operand).unboxedInt32()); > break; >+ case AlreadyInJSStackAsUnboxedInt48: >+ value = jsNumber(exec->r(operand).unboxedInt48()); >+ break; > case AlreadyInJSStackAsUnboxedDouble: > value = jsDoubleNumber(exec->r(operand).unboxedDouble()); > break; >Index: Source/JavaScriptCore/dfg/DFGMinifiedNode.h >=================================================================== >--- Source/JavaScriptCore/dfg/DFGMinifiedNode.h (revision 155903) >+++ Source/JavaScriptCore/dfg/DFGMinifiedNode.h (working copy) >@@ -48,6 +48,8 @@ inline bool belongsInMinifiedGraph(NodeT > case UInt32ToNumber: > case DoubleAsInt32: > case PhantomArguments: >+ case Int48ToValue: >+ case Int48ToDouble: > return true; > default: > ASSERT(!permitsOSRBackwardRewiring(type) && !permitsOSRForwardRewiring(type)); >@@ -104,6 +106,8 @@ private: > case Int32ToDouble: > case UInt32ToNumber: > case DoubleAsInt32: >+ case Int48ToDouble: >+ case Int48ToValue: > return true; > default: > return false; >Index: Source/JavaScriptCore/dfg/DFGNode.h >=================================================================== >--- Source/JavaScriptCore/dfg/DFGNode.h (revision 155903) >+++ Source/JavaScriptCore/dfg/DFGNode.h (working copy) >@@ -1241,12 +1241,12 @@ struct Node { > > bool shouldSpeculateNumber() > { >- return isNumberSpeculation(prediction()); >+ return isFullNumberSpeculation(prediction()); > } > > bool shouldSpeculateNumberExpectingDefined() > { >- return isNumberSpeculationExpectingDefined(prediction()); >+ return isFullNumberSpeculationExpectingDefined(prediction()); > } > > bool shouldSpeculateBoolean() >Index: Source/JavaScriptCore/dfg/DFGNodeFlags.h >=================================================================== >--- Source/JavaScriptCore/dfg/DFGNodeFlags.h (revision 155903) >+++ Source/JavaScriptCore/dfg/DFGNodeFlags.h (working copy) >@@ -41,8 +41,9 @@ namespace JSC { namespace DFG { > #define NodeResultJS 0x0001 > #define NodeResultNumber 0x0002 > #define NodeResultInt32 0x0003 >-#define NodeResultBoolean 0x0004 >-#define NodeResultStorage 0x0005 >+#define NodeResultInt48 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 >Index: Source/JavaScriptCore/dfg/DFGNodeType.h >=================================================================== >--- Source/JavaScriptCore/dfg/DFGNodeType.h (revision 155903) >+++ Source/JavaScriptCore/dfg/DFGNodeType.h (working copy) >@@ -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 Int48's represented */\ >+ /* as values. */\ >+ macro(Int48ToValue, NodeResultJS) \ >+ macro(Int48ToDouble, NodeResultNumber) \ > \ > /* Nodes for arithmetic operations. */\ > macro(ArithAdd, NodeResultNumber | NodeMustGenerate) \ >@@ -356,6 +360,17 @@ inline unsigned forwardRewiringSelection > // This loses information. Only use it if there are no better alternatives. > return 25; > >+ case Int48ToValue: >+ // Loses no information. It just boxes the value, which is what OSR wants >+ // to do anyway. >+ return 100; >+ >+ case Int48ToDouble: >+ // 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: Source/JavaScriptCore/dfg/DFGOSRExitCompiler64.cpp >=================================================================== >--- Source/JavaScriptCore/dfg/DFGOSRExitCompiler64.cpp (revision 155903) >+++ Source/JavaScriptCore/dfg/DFGOSRExitCompiler64.cpp (working copy) >@@ -195,6 +195,8 @@ void OSRExitCompiler::compileExit(const > case InGPR: > case UnboxedInt32InGPR: > case UInt32InGPR: >+ case UnboxedInt48InGPR: >+ case UnboxedStrictInt48InGPR: > m_jit.store64(recovery.gpr(), scratch + index); > break; > >@@ -235,12 +237,15 @@ void OSRExitCompiler::compileExit(const > case DisplacedInJSStack: > case Int32DisplacedInJSStack: > case DoubleDisplacedInJSStack: >+ case Int48DisplacedInJSStack: >+ case StrictInt48DisplacedInJSStack: > m_jit.load64(AssemblyHelpers::addressFor(recovery.virtualRegister()), GPRInfo::regT0); > m_jit.store64(GPRInfo::regT0, scratch + index); > break; > > case AlreadyInJSStackAsUnboxedInt32: > case AlreadyInJSStackAsUnboxedDouble: >+ case AlreadyInJSStackAsUnboxedInt48: > m_jit.load64(AssemblyHelpers::addressFor(operand), GPRInfo::regT0); > m_jit.store64(GPRInfo::regT0, scratch + index); > break; >@@ -274,33 +279,37 @@ void OSRExitCompiler::compileExit(const > 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 AlreadyInJSStackAsUnboxedInt48: >+ case UnboxedInt48InGPR: >+ case Int48DisplacedInJSStack: >+ m_jit.load64(scratch + index, GPRInfo::regT0); >+ m_jit.rshift64(AssemblyHelpers::TrustedImm32(16), GPRInfo::regT0); >+ m_jit.boxInt48(GPRInfo::regT0, GPRInfo::regT0, GPRInfo::regT1, FPRInfo::fpRegT0); >+ m_jit.store64(GPRInfo::regT0, AssemblyHelpers::addressFor(operand)); >+ break; >+ >+ case UnboxedStrictInt48InGPR: >+ case StrictInt48DisplacedInJSStack: >+ m_jit.load64(scratch + index, GPRInfo::regT0); >+ m_jit.boxInt48(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.boxInt48(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: Source/JavaScriptCore/dfg/DFGOSRExitCompiler.cpp >=================================================================== >--- Source/JavaScriptCore/dfg/DFGOSRExitCompiler.cpp (revision 155903) >+++ Source/JavaScriptCore/dfg/DFGOSRExitCompiler.cpp (working copy) >@@ -40,14 +40,6 @@ > > 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) >@@ -113,7 +105,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: Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp >=================================================================== >--- Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp (revision 155903) >+++ Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp (working copy) >@@ -116,7 +116,7 @@ private: > > SpeculatedType speculatedDoubleTypeForPrediction(SpeculatedType value) > { >- if (!isNumberSpeculation(value)) >+ if (!isFullNumberSpeculation(value)) > return SpecDouble; > if (value & SpecDoubleNaN) > return SpecDouble; >@@ -149,8 +149,10 @@ private: > } > > case GetLocal: { >- VariableAccessData* variableAccessData = node->variableAccessData(); >- SpeculatedType prediction = variableAccessData->prediction(); >+ VariableAccessData* variable = node->variableAccessData(); >+ SpeculatedType prediction = variable->prediction(); >+ if (variable->shouldNeverUnbox() && (prediction & SpecInt48)) >+ prediction = (prediction | SpecInt48AsDouble) & ~SpecInt48; > 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); > 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 >@@ -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(SpecInt48); >+ } else > changed |= mergePrediction(node->getHeapPrediction()); > break; > } >@@ -566,6 +578,8 @@ private: > case CheckWatchdogTimer: > case Unreachable: > case LoopHint: >+ case Int48ToValue: >+ case Int48ToDouble: > 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: Source/JavaScriptCore/dfg/DFGSafeToExecute.h >=================================================================== >--- Source/JavaScriptCore/dfg/DFGSafeToExecute.h (revision 155903) >+++ Source/JavaScriptCore/dfg/DFGSafeToExecute.h (working copy) >@@ -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& st > case CheckTierUpAtReturn: > case CheckTierUpAndOSREnter: > case LoopHint: >+ case Int48ToDouble: >+ case Int48ToValue: > return true; > > case GetByVal: >Index: Source/JavaScriptCore/dfg/DFGSilentRegisterSavePlan.h >=================================================================== >--- Source/JavaScriptCore/dfg/DFGSilentRegisterSavePlan.h (revision 155903) >+++ Source/JavaScriptCore/dfg/DFGSilentRegisterSavePlan.h (working copy) >@@ -48,6 +48,8 @@ enum SilentSpillAction { > enum SilentFillAction { > DoNothingForFill, > SetInt32Constant, >+ SetInt48Constant, >+ SetStrictInt48Constant, > SetBooleanConstant, > SetCellConstant, > SetTrustedJSConstant, >@@ -61,8 +63,12 @@ enum SilentFillAction { > Load32Tag, > Load32Payload, > Load32PayloadBoxInt, >+ Load32PayloadConvertToInt48, >+ Load32PayloadSignExtend, > LoadPtr, > Load64, >+ Load64ShiftRight16, >+ Load64ShiftLeft16, > LoadDouble, > LoadDoubleBoxDouble, > LoadJSUnboxDouble >Index: Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp >=================================================================== >--- Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp (revision 155903) >+++ Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp (working copy) >@@ -888,8 +888,8 @@ FPRReg SpeculativeJIT::fillSpeculateDoub > #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::fillSpeculateDoub > > 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::fillSpeculateDoub > 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 Int48ToDouble: >+ case Int48ToValue: > RELEASE_ASSERT_NOT_REACHED(); > break; > } >Index: Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp >=================================================================== >--- Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp (revision 155903) >+++ Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp (working copy) >@@ -40,6 +40,29 @@ namespace JSC { namespace DFG { > > #if USE(JSVALUE64) > >+void SpeculativeJIT::boxInt48(GPRReg sourceGPR, GPRReg targetGPR, DataFormat format) >+{ >+ GPRReg tempGPR; >+ if (sourceGPR == targetGPR) >+ tempGPR = allocate(); >+ else >+ tempGPR = targetGPR; >+ >+ FPRReg fpr = fprAllocate(); >+ >+ if (format == DataFormatInt48) >+ m_jit.rshift64(TrustedImm32(16), sourceGPR); >+ else >+ ASSERT(format == DataFormatStrictInt48); >+ >+ m_jit.boxInt48(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 > } 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 DataFormatInt48: >+ case DataFormatStrictInt48: { >+ m_jit.load64(JITCompiler::addressFor(virtualRegister), gpr); >+ boxInt48(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 > spillFormat = DataFormatJSDouble; > } else > RELEASE_ASSERT(spillFormat & DataFormatJS); >+ break; > } > info.fillJSValue(*m_stream, gpr, spillFormat); > } >@@ -113,6 +148,16 @@ GPRReg SpeculativeJIT::fillJSValue(Edge > > return gpr; > } >+ >+ case DataFormatInt48: >+ case DataFormatStrictInt48: { >+ GPRReg gpr = info.gpr(); >+ lock(gpr); >+ GPRReg resultGPR = allocate(); >+ boxInt48(gpr, resultGPR, info.registerFormat()); >+ unlock(gpr); >+ return resultGPR; >+ } > > case DataFormatCell: > // No retag required on JSVALUE64! >@@ -768,7 +813,7 @@ GPRReg SpeculativeJIT::fillSpeculateInt3 > > DataFormat spillFormat = info.spillFormat(); > >- RELEASE_ASSERT((spillFormat & DataFormatJS) || spillFormat == DataFormatInt32); >+ RELEASE_ASSERT((spillFormat & DataFormatJS) || spillFormat == DataFormatInt32 || spillFormat == DataFormatInt48 || spillFormat == DataFormatStrictInt48); > > m_gprs.retain(gpr, virtualRegister, SpillOrderSpilled); > >@@ -789,6 +834,36 @@ GPRReg SpeculativeJIT::fillSpeculateInt3 > returnFormat = DataFormatJSInt32; > return gpr; > } >+ if (spillFormat == DataFormatInt48 || spillFormat == DataFormatStrictInt48) { >+ // 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 int48. Otherwise, if we knowingly produced an int48, then we would >+ // be boxing it into a value using Int48ToValue. This assertion is valid >+ // only because Int48 is something that we introduce at prediction time. >+ // However: we may have an int32-producing node replaced by an >+ // int48-producing node due to CSE. So we must do a check. >+ RELEASE_ASSERT(!(type & ~SpecMachineInt)); >+ if (type & SpecInt48) { >+ 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 == DataFormatStrictInt48) { >+ m_jit.load32(JITCompiler::addressFor(virtualRegister), gpr); >+ } else { >+ m_jit.load64(JITCompiler::addressFor(virtualRegister), gpr); >+ m_jit.rshift64(TrustedImm32(16), 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::fillSpeculateInt3 > } > > case DataFormatJS: { >+ RELEASE_ASSERT(!(type & SpecInt48)); > // Check the value is an integer. > GPRReg gpr = info.gpr(); > m_gprs.lock(gpr); >@@ -843,6 +919,35 @@ GPRReg SpeculativeJIT::fillSpeculateInt3 > returnFormat = DataFormatInt32; > return gpr; > } >+ >+ case DataFormatStrictInt48: >+ case DataFormatInt48: { >+ 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() == DataFormatInt48) >+ m_jit.rshift64(TrustedImm32(16), result); >+ if (type & SpecInt48) { >+ 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::fillSpeculateInt3 > return result; > } > >+GPRReg SpeculativeJIT::fillSpeculateInt48(Edge edge, DataFormat desiredFormat) >+{ >+ ASSERT(desiredFormat == DataFormatInt48 || desiredFormat == DataFormatStrictInt48); >+ 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 == DataFormatInt48) >+ value = value << 16; >+ 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 == DataFormatInt48 || spillFormat == DataFormatStrictInt48); >+ >+ 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 == DataFormatStrictInt48) { >+ info.fillStrictInt48(*m_stream, gpr); >+ return gpr; >+ } >+ m_jit.lshift64(TrustedImm32(16), gpr); >+ info.fillInt48(*m_stream, gpr); >+ return gpr; >+ } >+ if (spillFormat == DataFormatInt48 || spillFormat == DataFormatStrictInt48) { >+ m_jit.load64(JITCompiler::addressFor(virtualRegister), gpr); >+ if (desiredFormat == DataFormatStrictInt48) { >+ if (spillFormat == DataFormatInt48) >+ m_jit.rshift64(TrustedImm32(16), gpr); >+ info.fillStrictInt48(*m_stream, gpr); >+ return gpr; >+ } >+ if (spillFormat == DataFormatStrictInt48) >+ m_jit.lshift64(TrustedImm32(16), gpr); >+ info.fillInt48(*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 Int48 >+ // at this point but this is too costly. We only *prove* that this is an Int48 >+ // 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.fillInt48(*m_stream, gpr, desiredFormat); >+ m_jit.signExtend32ToPtr(result, result); >+ if (desiredFormat == DataFormatInt48) >+ m_jit.lshift64(TrustedImm32(16), 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.fillInt48(*m_stream, gpr, desiredFormat); >+ result = gpr; >+ } >+ m_jit.signExtend32ToPtr(result, result); >+ if (desiredFormat == DataFormatInt48) >+ m_jit.lshift64(TrustedImm32(16), result); >+ return result; >+ } >+ >+ case DataFormatStrictInt48: { >+ GPRReg gpr = info.gpr(); >+ bool wasLocked = m_gprs.isLocked(gpr); >+ lock(gpr); >+ if (desiredFormat == DataFormatStrictInt48) >+ return gpr; >+ if (wasLocked) { >+ GPRReg result = allocate(); >+ m_jit.move(gpr, result); >+ unlock(gpr); >+ gpr = result; >+ } else >+ info.fillStrictInt48(*m_stream, gpr); >+ m_jit.lshift64(TrustedImm32(16), gpr); >+ return gpr; >+ } >+ >+ case DataFormatInt48: { >+ GPRReg gpr = info.gpr(); >+ bool wasLocked = m_gprs.isLocked(gpr); >+ lock(gpr); >+ if (desiredFormat == DataFormatInt48) >+ return gpr; >+ if (wasLocked) { >+ GPRReg result = allocate(); >+ m_jit.move(gpr, result); >+ unlock(gpr); >+ gpr = result; >+ } else >+ info.fillInt48(*m_stream, gpr); >+ m_jit.rshift64(TrustedImm32(16), 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 == DataFormatInt48) >+ value = value << 16; >+ 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::fillSpeculateDoub > #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::fillSpeculateDoub > unlock(gpr); > break; > } >+ >+ case DataFormatInt48: { >+ GPRReg gpr = allocate(); >+ m_gprs.retain(gpr, virtualRegister, SpillOrderSpilled); >+ m_jit.load64(JITCompiler::addressFor(virtualRegister), gpr); >+ info.fillInt48(*m_stream, gpr); >+ unlock(gpr); >+ break; >+ } >+ >+ case DataFormatStrictInt48: { >+ GPRReg gpr = allocate(); >+ m_gprs.retain(gpr, virtualRegister, SpillOrderSpilled); >+ m_jit.load64(JITCompiler::addressFor(virtualRegister), gpr); >+ info.fillStrictInt48(*m_stream, gpr); >+ unlock(gpr); >+ break; >+ } > > default: > GPRReg gpr = allocate(); >@@ -978,7 +1275,7 @@ FPRReg SpeculativeJIT::fillSpeculateDoub > > 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::fillSpeculateDoub > m_gprs.unlock(gpr); > return fpr; > } >+ >+ case DataFormatInt48: { >+ FPRReg fpr = fprAllocate(); >+ GPRReg gpr = info.gpr(); >+ m_gprs.lock(gpr); >+ GPRReg temp = allocate(); >+ m_jit.move(gpr, temp); >+ m_jit.rshift64(TrustedImm32(16), temp); >+ m_jit.convertInt64ToDouble(temp, fpr); >+ unlock(temp); >+ m_gprs.unlock(gpr); >+ return fpr; >+ } >+ >+ case DataFormatStrictInt48: { >+ 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 > case DataFormatJSDouble: > case DataFormatDouble: > case DataFormatJSBoolean: >- case DataFormatBoolean: { >+ case DataFormatBoolean: >+ case DataFormatInt48: >+ case DataFormatStrictInt48: { > terminateSpeculativeExecution(Uncountable, JSValueRegs(), 0); > return allocate(); > } >@@ -1194,7 +1515,9 @@ GPRReg SpeculativeJIT::fillSpeculateBool > case DataFormatJSDouble: > case DataFormatDouble: > case DataFormatJSCell: >- case DataFormatCell: { >+ case DataFormatCell: >+ case DataFormatInt48: >+ case DataFormatStrictInt48: { > terminateSpeculativeExecution(Uncountable, JSValueRegs(), 0); > return allocate(); > } >@@ -1503,6 +1826,40 @@ void SpeculativeJIT::compileInt32Compare > jsValueResult(result.gpr(), m_currentNode, DataFormatJSBoolean); > } > >+void SpeculativeJIT::compileInt48Compare(Node* node, MacroAssembler::RelationalCondition condition) >+{ >+ SpeculateWhicheverInt48Operand op1(this, node->child1()); >+ SpeculateWhicheverInt48Operand 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::compilePeepHoleInt48Branch(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; >+ } >+ >+ SpeculateWhicheverInt48Operand op1(this, node->child1()); >+ SpeculateWhicheverInt48Operand 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 FlushedInt48: { >+ 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).initInt48(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 FlushedInt48: { >+ SpeculateInt48Operand value(this, node->child1()); >+ m_jit.store64(value.gpr(), JITCompiler::addressFor(node->local())); >+ noResult(node); >+ recordSetLocal(node->local(), ValueSource(Int48InJSStack)); >+ break; >+ } >+ > case FlushedCell: { > SpeculateCellOperand cell(this, node->child1()); > GPRReg cellGPR = cell.gpr(); >@@ -2104,6 +2479,22 @@ void SpeculativeJIT::compile(Node* node) > break; > } > >+ case Int48ToValue: { >+ JSValueOperand operand(this, node->child1()); >+ GPRTemporary result(this, Reuse, operand); >+ m_jit.move(operand.gpr(), result.gpr()); >+ jsValueResult(result.gpr(), node); >+ break; >+ } >+ >+ case Int48ToDouble: { >+ 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: Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp >=================================================================== >--- Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp (revision 155903) >+++ Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp (working copy) >@@ -335,7 +335,9 @@ SilentRegisterSavePlan SpeculativeJIT::s > spillAction = Store32Payload; > else if (registerFormat == DataFormatCell || registerFormat == DataFormatStorage) > spillAction = StorePtr; >- else { >+ else if (registerFormat == DataFormatInt48 || registerFormat == DataFormatStrictInt48) { >+ spillAction = Store64; >+ } else { > ASSERT(registerFormat & DataFormatJS); > spillAction = Store64; > } >@@ -386,6 +388,41 @@ SilentRegisterSavePlan SpeculativeJIT::s > } else if (registerFormat == DataFormatStorage) { > ASSERT(info.gpr() == source); > fillAction = LoadPtr; >+ } else if (registerFormat == DataFormatInt48) { >+ if (node->hasConstant()) >+ fillAction = SetInt48Constant; >+ else if (isJSInt32(info.spillFormat()) || info.spillFormat() == DataFormatJS) >+ fillAction = Load32PayloadConvertToInt48; >+ else if (info.spillFormat() == DataFormatInt48) >+ fillAction = Load64; >+ else if (info.spillFormat() == DataFormatStrictInt48) >+ fillAction = Load64ShiftLeft16; >+ 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(); >+ } >+ } else if (registerFormat == DataFormatStrictInt48) { >+ if (node->hasConstant()) >+ fillAction = SetStrictInt48Constant; >+ else if (isJSInt32(info.spillFormat()) || info.spillFormat() == DataFormatJS) >+ fillAction = Load32PayloadSignExtend; >+ else if (info.spillFormat() == DataFormatInt48) >+ fillAction = Load64ShiftRight16; >+ else if (info.spillFormat() == DataFormatStrictInt48) >+ 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 +430,6 @@ SilentRegisterSavePlan SpeculativeJIT::s > if (node->hasConstant()) { > if (valueOfJSConstant(node).isCell()) > fillAction = SetTrustedJSConstant; >- else > fillAction = SetJSConstant; > } else if (info.spillFormat() == DataFormatInt32) { > ASSERT(registerFormat == DataFormatJSInt32); >@@ -512,6 +548,14 @@ void SpeculativeJIT::silentFill(const Si > case SetInt32Constant: > m_jit.move(Imm32(valueOfInt32Constant(plan.node())), plan.gpr()); > break; >+#if USE(JSVALUE64) >+ case SetInt48Constant: >+ m_jit.move(Imm64(valueOfJSConstant(plan.node()).asMachineInt() << 16), plan.gpr()); >+ break; >+ case SetStrictInt48Constant: >+ 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 +577,15 @@ void SpeculativeJIT::silentFill(const Si > m_jit.load32(JITCompiler::payloadFor(plan.node()->virtualRegister()), plan.gpr()); > m_jit.or64(GPRInfo::tagTypeNumberRegister, plan.gpr()); > break; >+ case Load32PayloadConvertToInt48: >+ m_jit.load32(JITCompiler::payloadFor(plan.node()->virtualRegister()), plan.gpr()); >+ m_jit.signExtend32ToPtr(plan.gpr(), plan.gpr()); >+ m_jit.lshift64(TrustedImm32(16), 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 +627,14 @@ void SpeculativeJIT::silentFill(const Si > case Load64: > m_jit.load64(JITCompiler::addressFor(plan.node()->virtualRegister()), plan.gpr()); > break; >+ case Load64ShiftRight16: >+ m_jit.load64(JITCompiler::addressFor(plan.node()->virtualRegister()), plan.gpr()); >+ m_jit.rshift64(TrustedImm32(16), plan.gpr()); >+ break; >+ case Load64ShiftLeft16: >+ m_jit.load64(JITCompiler::addressFor(plan.node()->virtualRegister()), plan.gpr()); >+ m_jit.lshift64(TrustedImm32(16), plan.gpr()); >+ break; > #endif > case LoadDouble: > m_jit.loadDouble(JITCompiler::addressFor(plan.node()->virtualRegister()), plan.fpr()); >@@ -1416,6 +1477,10 @@ bool SpeculativeJIT::compilePeepHoleBran > > if (node->isBinaryUseKind(Int32Use)) > compilePeepHoleInt32Branch(node, branchNode, condition); >+#if USE(JSVALUE64) >+ else if (node->isBinaryUseKind(MachineIntUse)) >+ compilePeepHoleInt48Branch(node, branchNode, condition); >+#endif // USE(JSVALUE64) > else if (node->isBinaryUseKind(NumberUse)) > compilePeepHoleDoubleBranch(node, branchNode, doubleCondition); > else if (node->op() == CompareEq) { >@@ -1507,6 +1572,9 @@ void SpeculativeJIT::compileInlineStart( > case FlushedInt32: > valueSource = ValueSource(Int32InJSStack); > break; >+ case FlushedInt48: >+ valueSource = ValueSource(Int48InJSStack); >+ break; > case FlushedCell: > valueSource = ValueSource(CellInJSStack); > break; >@@ -1873,7 +1941,7 @@ void SpeculativeJIT::compileDoublePutByV > FPRReg valueReg = value.fpr(); > > DFG_TYPE_CHECK( >- JSValueRegs(), child3, SpecRealNumber, >+ JSValueRegs(), child3, SpecFullRealNumber, > m_jit.branchDouble( > MacroAssembler::DoubleNotEqualOrUnordered, valueReg, valueReg)); > >@@ -2149,6 +2217,18 @@ void SpeculativeJIT::compileValueToInt32 > int32Result(result.gpr(), node, op1.format()); > return; > } >+ >+#if USE(JSVALUE64) >+ case MachineIntUse: { >+ SpeculateStrictInt48Operand 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 +2267,7 @@ void SpeculativeJIT::compileValueToInt32 > > 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 +2323,7 @@ void SpeculativeJIT::compileValueToInt32 > > 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 +2469,15 @@ void SpeculativeJIT::compileInt32ToDoubl > 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 +2500,15 @@ void SpeculativeJIT::compileInt32ToDoubl > 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 +2629,14 @@ void SpeculativeJIT::compileGetByValOnIn > return; > } > >+#if USE(JSVALUE64) >+ if (node->shouldSpeculateMachineInt()) { >+ m_jit.zeroExtend32ToPtr(resultReg, resultReg); >+ strictInt48Result(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 +2690,31 @@ void SpeculativeJIT::compilePutByValForI > break; > } > >+#if USE(JSVALUE64) >+ case MachineIntUse: { >+ SpeculateStrictInt48Operand 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 +2983,7 @@ void SpeculativeJIT::compileAdd(Node* no > int32Result(result.gpr(), node); > return; > } >- >+ > if (isNumberConstant(node->child2().node())) { > SpeculateInt32Operand op1(this, node->child1()); > int32_t imm2 = valueOfInt32Constant(node->child2().node()); >@@ -2915,6 +3028,33 @@ void SpeculativeJIT::compileAdd(Node* no > int32Result(gprResult, node); > return; > } >+ >+#if USE(JSVALUE64) >+ case MachineIntUse: { >+ // Will we need an overflow check? If we can prove that neither input can be >+ // Int48 then the overflow check will not be necessary. >+ if (!m_state.forNode(node->child1()).couldBeType(SpecInt48) >+ && !m_state.forNode(node->child2()).couldBeType(SpecInt48)) { >+ SpeculateWhicheverInt48Operand op1(this, node->child1()); >+ SpeculateWhicheverInt48Operand op2(this, node->child2(), op1); >+ GPRTemporary result(this, Reuse, op1); >+ m_jit.move(op1.gpr(), result.gpr()); >+ m_jit.add64(op2.gpr(), result.gpr()); >+ int48Result(result.gpr(), node, op1.format()); >+ return; >+ } >+ >+ SpeculateInt48Operand op1(this, node->child1()); >+ SpeculateInt48Operand op2(this, node->child2()); >+ GPRTemporary result(this, Reuse, op1, op2); >+ m_jit.move(op1.gpr(), result.gpr()); >+ speculationCheck( >+ Int48Overflow, JSValueRegs(), 0, >+ m_jit.branchAdd64(MacroAssembler::Overflow, op2.gpr(), result.gpr())); >+ int48Result(result.gpr(), node); >+ return; >+ } >+#endif // USE(JSVALUE64) > > case NumberUse: { > SpeculateDoubleOperand op1(this, node->child1()); >@@ -3060,6 +3200,33 @@ void SpeculativeJIT::compileArithSub(Nod > return; > } > >+#if USE(JSVALUE64) >+ case MachineIntUse: { >+ // Will we need an overflow check? If we can prove that neither input can be >+ // Int48 then the overflow check will not be necessary. >+ if (!m_state.forNode(node->child1()).couldBeType(SpecInt48) >+ && !m_state.forNode(node->child2()).couldBeType(SpecInt48)) { >+ SpeculateWhicheverInt48Operand op1(this, node->child1()); >+ SpeculateWhicheverInt48Operand op2(this, node->child2(), op1); >+ GPRTemporary result(this, Reuse, op1); >+ m_jit.move(op1.gpr(), result.gpr()); >+ m_jit.sub64(op2.gpr(), result.gpr()); >+ int48Result(result.gpr(), node, op1.format()); >+ return; >+ } >+ >+ SpeculateInt48Operand op1(this, node->child1()); >+ SpeculateInt48Operand op2(this, node->child2()); >+ GPRTemporary result(this, Reuse, op1, op2); >+ m_jit.move(op1.gpr(), result.gpr()); >+ speculationCheck( >+ Int48Overflow, JSValueRegs(), 0, >+ m_jit.branchSub64(MacroAssembler::Overflow, op2.gpr(), result.gpr())); >+ int48Result(result.gpr(), node); >+ return; >+ } >+#endif // USE(JSVALUE64) >+ > case NumberUse: { > SpeculateDoubleOperand op1(this, node->child1()); > SpeculateDoubleOperand op2(this, node->child2()); >@@ -3088,6 +3255,9 @@ void SpeculativeJIT::compileArithNegate( > > 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 { >@@ -3099,6 +3269,42 @@ void SpeculativeJIT::compileArithNegate( > int32Result(result.gpr(), node); > return; > } >+ >+#if USE(JSVALUE64) >+ case MachineIntUse: { >+ if (!m_state.forNode(node->child1()).couldBeType(SpecInt48)) { >+ SpeculateWhicheverInt48Operand 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)); >+ } >+ int48Result(resultGPR, node, op1.format()); >+ return; >+ } >+ >+ SpeculateInt48Operand op1(this, node->child1()); >+ GPRTemporary result(this); >+ GPRReg op1GPR = op1.gpr(); >+ GPRReg resultGPR = result.gpr(); >+ m_jit.move(op1GPR, resultGPR); >+ speculationCheck( >+ Int48Overflow, JSValueRegs(), 0, >+ m_jit.branchNeg64(MacroAssembler::Overflow, resultGPR)); >+ if (!bytecodeCanIgnoreNegativeZero(node->arithNodeFlags())) { >+ speculationCheck( >+ NegativeZero, JSValueRegs(), 0, >+ m_jit.branchTest64(MacroAssembler::Zero, resultGPR)); >+ } >+ int48Result(resultGPR, node); >+ return; >+ } >+#endif // USE(JSVALUE64) > > case NumberUse: { > SpeculateDoubleOperand op1(this, node->child1()); >@@ -3164,6 +3370,62 @@ void SpeculativeJIT::compileArithMul(Nod > int32Result(result.gpr(), node); > return; > } >+ >+#if USE(JSVALUE64) >+ case MachineIntUse: { >+ // This is super clever. We want to do an int48 multiplication and check the >+ // int48 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 int48 numbers inside int64 >+ // registers, with the high 16 bits being sign-extended. We can do: >+ // >+ // (a * (b << 16)) >+ // >+ // This will give us a left-shifted int48 (value is in high 48 bits, low 16 >+ // bits are zero) plus the int48 overflow bit. I.e. whether this 64-bit >+ // multiplication overflows is identical to whether the 'a * b' 48-bit >+ // multiplication overflows. >+ // >+ // In our nomenclature, this is: >+ // >+ // strictInt48(a) * int48(b) => int48 >+ // >+ // That is "strictInt48" means unshifted and "int48" 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. >+ >+ SpeculateWhicheverInt48Operand op1(this, node->child1()); >+ SpeculateWhicheverInt48Operand 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( >+ Int48Overflow, 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); >+ } >+ >+ int48Result(resultGPR, node); >+ return; >+ } >+#endif // USE(JSVALUE64) > > case NumberUse: { > SpeculateDoubleOperand op1(this, node->child1()); >@@ -3587,7 +3849,14 @@ bool SpeculativeJIT::compare(Node* node, > compileInt32Compare(node, condition); > return false; > } >- >+ >+#if USE(JSVALUE64) >+ if (node->isBinaryUseKind(MachineIntUse)) { >+ compileInt48Compare(node, condition); >+ return false; >+ } >+#endif // USE(JSVALUE64) >+ > if (node->isBinaryUseKind(NumberUse)) { > compileDoubleCompare(node, doubleCondition); > return false; >@@ -3737,6 +4006,23 @@ bool SpeculativeJIT::compileStrictEq(Nod > compileInt32Compare(node, MacroAssembler::Equal); > return false; > } >+ >+#if USE(JSVALUE64) >+ case MachineIntUse: { >+ unsigned branchIndexInBlock = detectPeepHoleBranch(); >+ if (branchIndexInBlock != UINT_MAX) { >+ Node* branchNode = m_block->at(branchIndexInBlock); >+ compilePeepHoleInt48Branch(node, branchNode, MacroAssembler::Equal); >+ use(node->child1()); >+ use(node->child2()); >+ m_indexInBlock = branchIndexInBlock; >+ m_currentNode = branchNode; >+ return true; >+ } >+ compileInt48Compare(node, MacroAssembler::Equal); >+ return false; >+ } >+#endif // USE(JSVALUE64) > > case NumberUse: { > unsigned branchIndexInBlock = detectPeepHoleBranch(); >@@ -4492,9 +4778,22 @@ void SpeculativeJIT::speculateInt32(Edge > (SpeculateInt32Operand(this, edge)).gpr(); > } > >+void SpeculativeJIT::speculateMachineInt(Edge edge) >+{ >+#if USE(JSVALUE64) >+ if (!needsTypeCheck(edge, SpecMachineInt)) >+ return; >+ >+ (SpeculateWhicheverInt48Operand(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(); >@@ -4502,13 +4801,13 @@ void SpeculativeJIT::speculateNumber(Edg > > 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)); > } >@@ -4770,7 +5069,7 @@ void SpeculativeJIT::speculate(Node*, Ed > ASSERT(!needsTypeCheck(edge, SpecInt32)); > break; > case KnownNumberUse: >- ASSERT(!needsTypeCheck(edge, SpecNumber)); >+ ASSERT(!needsTypeCheck(edge, SpecFullNumber)); > break; > case KnownCellUse: > ASSERT(!needsTypeCheck(edge, SpecCell)); >@@ -4781,6 +5080,9 @@ void SpeculativeJIT::speculate(Node*, Ed > case Int32Use: > speculateInt32(edge); > break; >+ case MachineIntUse: >+ speculateMachineInt(edge); >+ break; > case RealNumberUse: > speculateRealNumber(edge); > break; >Index: Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h >=================================================================== >--- Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h (revision 155903) >+++ Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h (working copy) >@@ -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 fillSpeculateInt48(Edge, DataFormat desiredFormat); > FPRReg fillSpeculateDouble(Edge); > GPRReg fillSpeculateCell(Edge); > GPRReg fillSpeculateBoolean(Edge); >@@ -468,6 +462,8 @@ public: > { > return boxDouble(fpr, allocate()); > } >+ >+ void boxInt48(GPRReg sourceGPR, GPRReg targetGPR, DataFormat format); > #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 int48Result(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.initInt48(node, node->refCount(), reg, format); >+ } >+ void int48Result(GPRReg reg, Node* node, UseChildrenMode mode = CallUseChildren) >+ { >+ int48Result(reg, node, DataFormatInt48, mode); >+ } >+ void strictInt48Result(GPRReg reg, Node* node, UseChildrenMode mode = CallUseChildren) >+ { >+ int48Result(reg, node, DataFormatStrictInt48, 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 betterUseStrictInt48(Node* node) >+ { >+ return !generationInfo(node).isInt48(); >+ } >+ bool betterUseStrictInt48(Edge edge) >+ { >+ return betterUseStrictInt48(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 compilePeepHoleInt48Branch(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 compileInt48Compare(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 Int48 (i.e. it's left-shifted by 16, low bits zero). >+class SpeculateInt48Operand { >+public: >+ explicit SpeculateInt48Operand(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(); >+ } >+ >+ ~SpeculateInt48Operand() >+ { >+ 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->fillSpeculateInt48(edge(), DataFormatInt48); >+ return m_gprOrInvalid; >+ } >+ >+ void use() >+ { >+ m_jit->use(node()); >+ } >+ >+private: >+ SpeculativeJIT* m_jit; >+ Edge m_edge; >+ GPRReg m_gprOrInvalid; >+}; >+ >+// Gives you a strict Int48 (i.e. the payload is in the low 48 bits, high 16 bits are sign-extended). >+class SpeculateStrictInt48Operand { >+public: >+ explicit SpeculateStrictInt48Operand(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(); >+ } >+ >+ ~SpeculateStrictInt48Operand() >+ { >+ 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->fillSpeculateInt48(edge(), DataFormatStrictInt48); >+ return m_gprOrInvalid; >+ } >+ >+ void use() >+ { >+ m_jit->use(node()); >+ } >+ >+private: >+ SpeculativeJIT* m_jit; >+ Edge m_edge; >+ GPRReg m_gprOrInvalid; >+}; >+ >+enum OppositeShiftTag { OppositeShift }; >+ >+class SpeculateWhicheverInt48Operand { >+public: >+ explicit SpeculateWhicheverInt48Operand(SpeculativeJIT* jit, Edge edge, OperandSpeculationMode mode = AutomaticOperandSpeculation) >+ : m_jit(jit) >+ , m_edge(edge) >+ , m_gprOrInvalid(InvalidGPRReg) >+ , m_strict(jit->betterUseStrictInt48(edge)) >+ { >+ ASSERT_UNUSED(mode, mode == ManualOperandSpeculation || edge.useKind() == MachineIntUse); >+ if (jit->isFilled(node())) >+ gpr(); >+ } >+ >+ explicit SpeculateWhicheverInt48Operand(SpeculativeJIT* jit, Edge edge, const SpeculateWhicheverInt48Operand& 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 SpeculateWhicheverInt48Operand(SpeculativeJIT* jit, Edge edge, OppositeShiftTag, const SpeculateWhicheverInt48Operand& 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(); >+ } >+ >+ ~SpeculateWhicheverInt48Operand() >+ { >+ 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->fillSpeculateInt48( >+ edge(), m_strict ? DataFormatStrictInt48 : DataFormatInt48); >+ } >+ return m_gprOrInvalid; >+ } >+ >+ void use() >+ { >+ m_jit->use(node()); >+ } >+ >+ DataFormat format() const >+ { >+ return m_strict ? DataFormatStrictInt48 : DataFormatInt48; >+ } >+ >+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: Source/JavaScriptCore/dfg/DFGUseKind.cpp >=================================================================== >--- Source/JavaScriptCore/dfg/DFGUseKind.cpp (revision 155903) >+++ Source/JavaScriptCore/dfg/DFGUseKind.cpp (working copy) >@@ -44,6 +44,9 @@ void printInternal(PrintStream& out, Use > case KnownInt32Use: > out.print("KnownInt32"); > break; >+ case MachineIntUse: >+ out.print("MachineInt"); >+ break; > case RealNumberUse: > out.print("RealNumber"); > break; >Index: Source/JavaScriptCore/dfg/DFGUseKind.h >=================================================================== >--- Source/JavaScriptCore/dfg/DFGUseKind.h (revision 155903) >+++ Source/JavaScriptCore/dfg/DFGUseKind.h (working copy) >@@ -39,6 +39,7 @@ enum UseKind { > UntypedUse, > Int32Use, > KnownInt32Use, >+ MachineIntUse, > RealNumberUse, > NumberUse, > KnownNumberUse, >@@ -66,11 +67,13 @@ ALWAYS_INLINE SpeculatedType typeFilterF > 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 k > switch (kind) { > case Int32Use: > case KnownInt32Use: >+ case MachineIntUse: > case RealNumberUse: > case NumberUse: > case KnownNumberUse: >Index: Source/JavaScriptCore/dfg/DFGValueSource.cpp >=================================================================== >--- Source/JavaScriptCore/dfg/DFGValueSource.cpp (revision 155903) >+++ Source/JavaScriptCore/dfg/DFGValueSource.cpp (working copy) >@@ -45,6 +45,9 @@ void ValueSource::dump(PrintStream& out) > case Int32InJSStack: > out.print("Int32"); > break; >+ case Int48InJSStack: >+ out.print("Int48"); >+ break; > case CellInJSStack: > out.print("Cell"); > break; >Index: Source/JavaScriptCore/dfg/DFGValueSource.h >=================================================================== >--- Source/JavaScriptCore/dfg/DFGValueSource.h (revision 155903) >+++ Source/JavaScriptCore/dfg/DFGValueSource.h (working copy) >@@ -43,6 +43,7 @@ enum ValueSourceKind { > SourceNotSet, > ValueInJSStack, > Int32InJSStack, >+ Int48InJSStack, > CellInJSStack, > BooleanInJSStack, > DoubleInJSStack, >@@ -56,6 +57,8 @@ static inline ValueSourceKind dataFormat > switch (dataFormat) { > case DataFormatInt32: > return Int32InJSStack; >+ case DataFormatInt48: >+ return Int48InJSStack; > case DataFormatDouble: > return DoubleInJSStack; > case DataFormatBoolean: >@@ -79,6 +82,8 @@ static inline DataFormat valueSourceKind > return DataFormatJS; > case Int32InJSStack: > return DataFormatInt32; >+ case Int48InJSStack: >+ return DataFormatInt48; > case CellInJSStack: > return DataFormatCell; > case BooleanInJSStack: >@@ -139,6 +144,8 @@ public: > return ValueSource(DoubleInJSStack); > case FlushedInt32: > return ValueSource(Int32InJSStack); >+ case FlushedInt48: >+ return ValueSource(Int48InJSStack); > case FlushedCell: > return ValueSource(CellInJSStack); > case FlushedBoolean: >@@ -181,6 +188,9 @@ public: > case Int32InJSStack: > return ValueRecovery::alreadyInJSStackAsUnboxedInt32(); > >+ case Int48InJSStack: >+ return ValueRecovery::alreadyInJSStackAsUnboxedInt48(); >+ > case CellInJSStack: > return ValueRecovery::alreadyInJSStackAsUnboxedCell(); > >Index: Source/JavaScriptCore/dfg/DFGVariableAccessData.h >=================================================================== >--- Source/JavaScriptCore/dfg/DFGVariableAccessData.h (revision 155903) >+++ Source/JavaScriptCore/dfg/DFGVariableAccessData.h (working copy) >@@ -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 (enableInt48() && !operandIsArgument(m_local) && isMachineIntSpeculation(prediction)) >+ return FlushedInt48; >+ > if (isCellSpeculation(prediction)) > return FlushedCell; > >Index: Source/JavaScriptCore/ftl/FTLCArgumentGetter.cpp >=================================================================== >--- Source/JavaScriptCore/ftl/FTLCArgumentGetter.cpp (revision 155903) >+++ Source/JavaScriptCore/ftl/FTLCArgumentGetter.cpp (working copy) >@@ -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(Val > > 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.boxInt48(destination, destination, scratch1, FPRInfo::fpRegT0); >+ m_jit.move64ToDouble(scratch2, FPRInfo::fpRegT0); >+ break; >+ } >+ >+ case ValueFormatInt48: { >+ loadNext64(destination); >+ m_jit.rshift64(AssemblyHelpers::TrustedImm32(16), destination); >+ m_jit.moveDoubleTo64(FPRInfo::fpRegT0, scratch2); >+ m_jit.boxInt48(destination, destination, scratch1, FPRInfo::fpRegT0); >+ m_jit.move64ToDouble(scratch2, FPRInfo::fpRegT0); >+ break; >+ } > >- done.link(&m_jit); >+ case ValueFormatStrictInt48: { >+ loadNext64(destination); >+ m_jit.moveDoubleTo64(FPRInfo::fpRegT0, scratch2); >+ m_jit.boxInt48(destination, destination, scratch1, FPRInfo::fpRegT0); >+ m_jit.move64ToDouble(scratch2, FPRInfo::fpRegT0); > break; > } > >@@ -80,10 +95,10 @@ void CArgumentGetter::loadNextAndBox(Val > } > > 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: Source/JavaScriptCore/ftl/FTLCArgumentGetter.h >=================================================================== >--- Source/JavaScriptCore/ftl/FTLCArgumentGetter.h (revision 155903) >+++ Source/JavaScriptCore/ftl/FTLCArgumentGetter.h (working copy) >@@ -115,7 +115,8 @@ public: > } > > void loadNextAndBox( >- ValueFormat format, DFG::GPRReg destination, DFG::GPRReg scratch = InvalidGPRReg); >+ ValueFormat format, DFG::GPRReg destination, >+ DFG::GPRReg scratch1 = InvalidGPRReg, DFG::GPRReg scratch2 = InvalidGPRReg); > > private: > MacroAssembler::Address nextAddress() >Index: Source/JavaScriptCore/ftl/FTLCapabilities.cpp >=================================================================== >--- Source/JavaScriptCore/ftl/FTLCapabilities.cpp (revision 155903) >+++ Source/JavaScriptCore/ftl/FTLCapabilities.cpp (working copy) >@@ -164,6 +164,8 @@ inline CapabilityLevel canCompile(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* > 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: Source/JavaScriptCore/ftl/FTLExitValue.cpp >=================================================================== >--- Source/JavaScriptCore/ftl/FTLExitValue.cpp (revision 155903) >+++ Source/JavaScriptCore/ftl/FTLExitValue.cpp (working copy) >@@ -53,6 +53,9 @@ void ExitValue::dumpInContext(PrintStrea > case ExitValueInJSStackAsInt32: > out.print("InJSStackAsInt32"); > return; >+ case ExitValueInJSStackAsInt48: >+ out.print("InJSStackAsInt48"); >+ return; > case ExitValueInJSStackAsDouble: > out.print("InJSStackAsDouble"); > return; >Index: Source/JavaScriptCore/ftl/FTLExitValue.h >=================================================================== >--- Source/JavaScriptCore/ftl/FTLExitValue.h (revision 155903) >+++ Source/JavaScriptCore/ftl/FTLExitValue.h (working copy) >@@ -49,6 +49,7 @@ enum ExitValueKind { > ExitValueConstant, > ExitValueInJSStack, > ExitValueInJSStackAsInt32, >+ ExitValueInJSStackAsInt48, > ExitValueInJSStackAsDouble > }; > >@@ -82,6 +83,13 @@ public: > return result; > } > >+ static ExitValue inJSStackAsInt48() >+ { >+ ExitValue result; >+ result.m_kind = ExitValueInJSStackAsInt48; >+ return result; >+ } >+ > static ExitValue inJSStackAsDouble() > { > ExitValue result; >Index: Source/JavaScriptCore/ftl/FTLIntrinsicRepository.h >=================================================================== >--- Source/JavaScriptCore/ftl/FTLIntrinsicRepository.h (revision 155903) >+++ Source/JavaScriptCore/ftl/FTLIntrinsicRepository.h (working copy) >@@ -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: Source/JavaScriptCore/ftl/FTLLowerDFGToLLVM.cpp >=================================================================== >--- Source/JavaScriptCore/ftl/FTLLowerDFGToLLVM.cpp (revision 155903) >+++ Source/JavaScriptCore/ftl/FTLLowerDFGToLLVM.cpp (working copy) >@@ -151,6 +151,9 @@ private: > case NodeResultInt32: > type = m_out.int32; > break; >+ case NodeResultInt48: >+ 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(lowInt48(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 NodeResultInt48: >+ setInt48(m_out.get(source)); >+ break; > case NodeResultBoolean: > setBoolean(m_out.get(source)); > break; >@@ -591,6 +599,13 @@ private: > return; > } > >+ case FlushedInt48: { >+ LValue value = lowInt48(m_node->child1()); >+ m_out.store64(value, addressFor(variable->local())); >+ m_valueSources.operand(variable->local()) = ValueSource(Int48InJSStack); >+ return; >+ } >+ > case FlushedCell: { > LValue value = lowCell(m_node->child1()); > m_out.store64(value, addressFor(variable->local())); >@@ -655,6 +670,22 @@ private: > break; > } > >+ case MachineIntUse: { >+ if (!m_state.forNode(m_node->child1()).couldBeType(SpecInt48) >+ && !m_state.forNode(m_node->child2()).couldBeType(SpecInt48)) { >+ Int48s<2> int48s = lowWhicheverInt48s(m_node->child1(), m_node->child2()); >+ setInt48(m_out.add(int48s[0], int48s[1]), int48s.kind); >+ break; >+ } >+ >+ LValue left = lowInt48(m_node->child1()); >+ LValue right = lowInt48(m_node->child2()); >+ LValue result = m_out.addWithOverflow64(left, right); >+ speculate(Int48Overflow, noValue(), 0, m_out.extractValue(result, 1)); >+ setInt48(m_out.extractValue(result, 0)); >+ break; >+ } >+ > case NumberUse: { > setDouble( > m_out.doubleAdd(lowDouble(m_node->child1()), lowDouble(m_node->child2()))); >@@ -685,6 +716,22 @@ private: > break; > } > >+ case MachineIntUse: { >+ if (!m_state.forNode(m_node->child1()).couldBeType(SpecInt48) >+ && !m_state.forNode(m_node->child2()).couldBeType(SpecInt48)) { >+ Int48s<2> int48s = lowWhicheverInt48s(m_node->child1(), m_node->child2()); >+ setInt48(m_out.sub(int48s[0], int48s[1]), int48s.kind); >+ break; >+ } >+ >+ LValue left = lowInt48(m_node->child1()); >+ LValue right = lowInt48(m_node->child2()); >+ LValue result = m_out.subWithOverflow64(left, right); >+ speculate(Int48Overflow, noValue(), 0, m_out.extractValue(result, 1)); >+ setInt48(m_out.extractValue(result, 0)); >+ break; >+ } >+ > case NumberUse: { > setDouble( > m_out.doubleSub(lowDouble(m_node->child1()), lowDouble(m_node->child2()))); >@@ -730,6 +777,30 @@ private: > break; > } > >+ case MachineIntUse: { >+ Int48s<2> int48s = lowOpposingInt48s(m_node->child1(), m_node->child2()); >+ >+ LValue overflowResult = m_out.mulWithOverflow64(int48s[0], int48s[1]); >+ speculate(Int48Overflow, 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(int48s[0], m_out.int64Zero)); >+ speculate(NegativeZero, noValue(), 0, m_out.lessThan(int48s[0], m_out.int64Zero)); >+ m_out.jump(continuation); >+ m_out.appendTo(continuation, lastNext); >+ } >+ >+ setInt48(result); >+ break; >+ } >+ > case NumberUse: { > setDouble( > m_out.doubleMul(lowDouble(m_node->child1()), lowDouble(m_node->child2()))); >@@ -1030,6 +1101,25 @@ private: > break; > } > >+ case MachineIntUse: { >+ if (!m_state.forNode(m_node->child1()).couldBeType(SpecInt48)) { >+ Int48s<1> value = lowWhicheverInt48(m_node->child1()); >+ LValue result = m_out.neg(value[0]); >+ if (!bytecodeCanIgnoreNegativeZero(m_node->arithNodeFlags())) >+ speculate(NegativeZero, noValue(), 0, m_out.isZero64(result)); >+ setInt48(result, value.kind); >+ break; >+ } >+ >+ LValue value = lowInt48(m_node->child1()); >+ LValue overflowResult = m_out.subWithOverflow64(m_out.int64Zero, value); >+ speculate(Int48Overflow, noValue(), 0, m_out.extractValue(overflowResult, 1)); >+ LValue result = m_out.extractValue(overflowResult, 0); >+ speculate(NegativeZero, noValue(), 0, m_out.isZero64(result)); >+ setInt48(result); >+ break; >+ } >+ > case NumberUse: { > setDouble(m_out.doubleNeg(lowDouble(m_node->child1()))); > break; >@@ -1471,7 +1561,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( >@@ -1706,6 +1796,7 @@ private: > void compileCompareEq() > { > if (m_node->isBinaryUseKind(Int32Use) >+ || m_node->isBinaryUseKind(MachineIntUse) > || m_node->isBinaryUseKind(NumberUse) > || m_node->isBinaryUseKind(ObjectUse)) { > compileCompareStrictEq(); >@@ -1732,6 +1823,12 @@ private: > return; > } > >+ if (m_node->isBinaryUseKind(MachineIntUse)) { >+ Int48s<2> values = lowWhicheverInt48s(m_node->child1(), m_node->child2()); >+ setBoolean(m_out.equal(values[0], values[1])); >+ return; >+ } >+ > if (m_node->isBinaryUseKind(NumberUse)) { > setBoolean( > m_out.doubleEqual(lowDouble(m_node->child1()), lowDouble(m_node->child2()))); >@@ -1780,6 +1877,12 @@ private: > return; > } > >+ if (m_node->isBinaryUseKind(MachineIntUse)) { >+ Int48s<2> values = lowWhicheverInt48s(m_node->child1(), m_node->child2()); >+ setBoolean(m_out.lessThan(values[0], values[1])); >+ return; >+ } >+ > if (m_node->isBinaryUseKind(NumberUse)) { > setBoolean( > m_out.doubleLessThan(lowDouble(m_node->child1()), lowDouble(m_node->child2()))); >@@ -1797,6 +1900,12 @@ private: > return; > } > >+ if (m_node->isBinaryUseKind(MachineIntUse)) { >+ Int48s<2> values = lowWhicheverInt48s(m_node->child1(), m_node->child2()); >+ setBoolean(m_out.lessThanOrEqual(values[0], values[1])); >+ return; >+ } >+ > if (m_node->isBinaryUseKind(NumberUse)) { > setBoolean( > m_out.doubleLessThanOrEqual( >@@ -1815,6 +1924,12 @@ private: > return; > } > >+ if (m_node->isBinaryUseKind(MachineIntUse)) { >+ Int48s<2> values = lowWhicheverInt48s(m_node->child1(), m_node->child2()); >+ setBoolean(m_out.greaterThan(values[0], values[1])); >+ return; >+ } >+ > if (m_node->isBinaryUseKind(NumberUse)) { > setBoolean( > m_out.doubleGreaterThan( >@@ -1834,6 +1949,12 @@ private: > return; > } > >+ if (m_node->isBinaryUseKind(MachineIntUse)) { >+ Int48s<2> values = lowWhicheverInt48s(m_node->child1(), m_node->child2()); >+ setBoolean(m_out.greaterThanOrEqual(values[0], values[1])); >+ return; >+ } >+ > if (m_node->isBinaryUseKind(NumberUse)) { > setBoolean( > m_out.doubleGreaterThanOrEqual( >@@ -2350,10 +2471,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_strictInt48Values.get(edge.node()); >+ if (isValid(value)) >+ return strictInt48ToInt32(edge, value.value()); >+ >+ value = m_int48Values.get(edge.node()); >+ if (isValid(value)) >+ return strictInt48ToInt32(edge, int48ToStrictInt48(value.value())); >+ > value = m_jsValueValues.get(edge.node()); > if (isValid(value)) { > LValue boxedResult = value.value(); >@@ -2369,10 +2507,148 @@ private: > return m_out.int32Zero; > } > >+ enum Int48Kind { StrictInt48, Int48 }; >+ LValue lowInt48(Edge edge, Int48Kind 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 == Int48) >+ result <<= 16; >+ return m_out.constInt64(result); >+ } >+ >+ LoweredNodeValue value; >+ >+ switch (kind) { >+ case Int48: >+ value = m_int48Values.get(edge.node()); >+ if (isValid(value)) >+ return value.value(); >+ >+ value = m_strictInt48Values.get(edge.node()); >+ if (isValid(value)) >+ return strictInt48ToInt48(value.value()); >+ break; >+ >+ case StrictInt48: >+ value = m_strictInt48Values.get(edge.node()); >+ if (isValid(value)) >+ return value.value(); >+ >+ value = m_int48Values.get(edge.node()); >+ if (isValid(value)) >+ return int48ToStrictInt48(value.value()); >+ break; >+ } >+ >+ value = m_int32Values.get(edge.node()); >+ if (isValid(value)) { >+ return setInt48WithStrictValue( >+ edge.node(), m_out.signExt(value.value(), m_out.int64), kind); >+ } >+ >+ RELEASE_ASSERT(!(m_state.forNode(edge).m_type & SpecInt48)); >+ >+ value = m_jsValueValues.get(edge.node()); >+ if (isValid(value)) { >+ LValue boxedResult = value.value(); >+ FTL_TYPE_CHECK( >+ jsValueValue(boxedResult), edge, SpecMachineInt, isNotInt32(boxedResult)); >+ return setInt48WithStrictValue( >+ 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 lowInt48(Edge edge, OperandSpeculationMode mode = AutomaticOperandSpeculation) >+ { >+ return lowInt48(edge, Int48, mode); >+ } >+ >+ LValue lowStrictInt48(Edge edge, OperandSpeculationMode mode = AutomaticOperandSpeculation) >+ { >+ return lowInt48(edge, StrictInt48, mode); >+ } >+ >+ bool betterUseStrictInt48(Node* node) >+ { >+ return !isValid(m_int48Values.get(node)); >+ } >+ bool betterUseStrictInt48(Edge edge) >+ { >+ return betterUseStrictInt48(edge.node()); >+ } >+ template<typename T> >+ Int48Kind bestInt48Kind(T node) >+ { >+ return betterUseStrictInt48(node) ? StrictInt48 : Int48; >+ } >+ Int48Kind opposite(Int48Kind kind) >+ { >+ switch (kind) { >+ case Int48: >+ return StrictInt48; >+ case StrictInt48: >+ return Int48; >+ } >+ RELEASE_ASSERT_NOT_REACHED(); >+ } >+ >+ template<unsigned count> >+ struct Int48s { >+ LValue operator[](unsigned index) const { return values[index]; } >+ LValue& operator[](unsigned index) { return values[index]; } >+ >+ Int48Kind kind; >+ FixedArray<LValue, count> values; >+ }; >+ Int48s<1> lowWhicheverInt48(Edge edge, OperandSpeculationMode mode = AutomaticOperandSpeculation) >+ { >+ Int48s<1> result; >+ result.kind = bestInt48Kind(edge); >+ result[0] = lowInt48(edge, result.kind, mode); >+ return result; >+ } >+ Int48s<2> lowWhicheverInt48s(Edge edge1, Edge edge2, OperandSpeculationMode mode = AutomaticOperandSpeculation) >+ { >+ Int48s<2> result; >+ result.kind = bestInt48Kind(edge1); >+ result[0] = lowInt48(edge1, result.kind, mode); >+ result[1] = lowInt48(edge2, result.kind, mode); >+ return result; >+ } >+ Int48s<2> lowOpposingInt48s(Edge edge1, Edge edge2, OperandSpeculationMode mode = AutomaticOperandSpeculation) >+ { >+ Int48s<2> result; >+ result.kind = bestInt48Kind(edge1); >+ result[0] = lowInt48(edge1, result.kind, mode); >+ result[1] = lowInt48(edge2, opposite(result.kind), mode); >+ return result; >+ } >+ > 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(); >@@ -2417,6 +2693,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(); >@@ -2440,6 +2725,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(); >@@ -2451,6 +2745,14 @@ private: > return result; > } > >+ value = m_strictInt48Values.get(edge.node()); >+ if (isValid(value)) >+ return strictInt48ToDouble(edge, value.value()); >+ >+ value = m_int48Values.get(edge.node()); >+ if (isValid(value)) >+ return strictInt48ToDouble(edge, int48ToStrictInt48(value.value())); >+ > value = m_jsValueValues.get(edge.node()); > if (isValid(value)) { > LValue boxedResult = value.value(); >@@ -2470,7 +2772,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); >@@ -2483,7 +2785,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; > } >@@ -2492,6 +2794,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(); >@@ -2503,6 +2808,14 @@ private: > return result; > } > >+ value = m_strictInt48Values.get(edge.node()); >+ if (isValid(value)) >+ return strictInt48ToJSValue(value.value()); >+ >+ value = m_int48Values.get(edge.node()); >+ if (isValid(value)) >+ return strictInt48ToJSValue(int48ToStrictInt48(value.value())); >+ > value = m_booleanValues.get(edge.node()); > if (isValid(value)) { > LValue result = boxBoolean(value.value()); >@@ -2532,6 +2845,77 @@ private: > return result; > } > >+ LValue strictInt48ToInt32(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 strictInt48ToDouble(Edge edge, LValue value) >+ { >+ LValue result = m_out.intToDouble(value); >+ setDouble(edge.node(), result); >+ return result; >+ } >+ >+ LValue strictInt48ToJSValue(LValue value) >+ { >+ LBasicBlock isInt32 = FTL_NEW_BLOCK(m_out, ("strictInt48ToJSValue isInt32 case")); >+ LBasicBlock isDouble = FTL_NEW_BLOCK(m_out, ("strictInt48ToJSValue isDouble case")); >+ LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("strictInt48ToJSValue 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 setInt48WithStrictValue(Node* node, LValue value, Int48Kind kind) >+ { >+ switch (kind) { >+ case StrictInt48: >+ setStrictInt48(node, value); >+ return value; >+ >+ case Int48: >+ value = strictInt48ToInt48(value); >+ setInt48(node, value); >+ return value; >+ } >+ >+ RELEASE_ASSERT_NOT_REACHED(); >+ return 0; >+ } >+ >+ LValue strictInt48ToInt48(LValue value) >+ { >+ return m_out.shl(value, m_out.constInt64(16)); >+ } >+ >+ LValue int48ToStrictInt48(LValue value) >+ { >+ return m_out.aShr(value, m_out.constInt64(16)); >+ } >+ > LValue isNotInt32(LValue jsValue) > { > return m_out.below(jsValue, m_tagTypeNumber); >@@ -2792,7 +3176,7 @@ private: > > LValue value = lowDouble(edge); > FTL_TYPE_CHECK( >- doubleValue(value), edge, SpecRealNumber, >+ doubleValue(value), edge, SpecFullRealNumber, > m_out.doubleNotEqualOrUnordered(value, value)); > } > >@@ -2800,7 +3184,7 @@ private: > { > lowBoolean(edge); > } >- >+ > bool masqueradesAsUndefinedWatchpointIsStillValid() > { > return m_graph.masqueradesAsUndefinedWatchpointIsStillValid(m_node->codeOrigin); >@@ -2931,6 +3315,10 @@ private: > m_valueSources[i] = ValueSource(Int32InJSStack); > break; > >+ case FlushedInt48: >+ m_valueSources[i] = ValueSource(Int48InJSStack); >+ break; >+ > case FlushedDouble: > m_valueSources[i] = ValueSource(DoubleInJSStack); > break; >@@ -3034,6 +3422,9 @@ private: > case Int32InJSStack: > exit.m_values[i] = ExitValue::inJSStackAsInt32(); > break; >+ case Int48InJSStack: >+ exit.m_values[i] = ExitValue::inJSStackAsInt48(); >+ break; > case DoubleInJSStack: > exit.m_values[i] = ExitValue::inJSStackAsDouble(); > break; >@@ -3137,6 +3528,18 @@ private: > return; > } > >+ value = m_int48Values.get(node); >+ if (isValid(value)) { >+ addExitArgument(exit, arguments, index, ValueFormatInt48, value.value()); >+ return; >+ } >+ >+ value = m_strictInt48Values.get(node); >+ if (isValid(value)) { >+ addExitArgument(exit, arguments, index, ValueFormatStrictInt48, value.value()); >+ return; >+ } >+ > value = m_booleanValues.get(node); > if (isValid(value)) { > addExitArgument(exit, arguments, index, ValueFormatBoolean, value.value()); >@@ -3240,6 +3643,28 @@ private: > { > m_int32Values.set(node, LoweredNodeValue(value, m_highBlock)); > } >+ void setInt48(Node* node, LValue value) >+ { >+ m_int48Values.set(node, LoweredNodeValue(value, m_highBlock)); >+ } >+ void setStrictInt48(Node* node, LValue value) >+ { >+ m_strictInt48Values.set(node, LoweredNodeValue(value, m_highBlock)); >+ } >+ void setInt48(Node* node, LValue value, Int48Kind kind) >+ { >+ switch (kind) { >+ case Int48: >+ setInt48(node, value); >+ return; >+ >+ case StrictInt48: >+ setStrictInt48(node, value); >+ return; >+ } >+ >+ RELEASE_ASSERT_NOT_REACHED(); >+ } > void setJSValue(Node* node, LValue value) > { > m_jsValueValues.set(node, LoweredNodeValue(value, m_highBlock)); >@@ -3261,6 +3686,18 @@ private: > { > setInt32(m_node, value); > } >+ void setInt48(LValue value) >+ { >+ setInt48(m_node, value); >+ } >+ void setStrictInt48(LValue value) >+ { >+ setStrictInt48(m_node, value); >+ } >+ void setInt48(LValue value, Int48Kind kind) >+ { >+ setInt48(m_node, value, kind); >+ } > void setJSValue(LValue value) > { > setJSValue(m_node, value); >@@ -3340,6 +3777,8 @@ private: > LValue m_tagMask; > > HashMap<Node*, LoweredNodeValue> m_int32Values; >+ HashMap<Node*, LoweredNodeValue> m_strictInt48Values; >+ HashMap<Node*, LoweredNodeValue> m_int48Values; > HashMap<Node*, LoweredNodeValue> m_jsValueValues; > HashMap<Node*, LoweredNodeValue> m_booleanValues; > HashMap<Node*, LoweredNodeValue> m_storageValues; >Index: Source/JavaScriptCore/ftl/FTLOSRExitCompiler.cpp >=================================================================== >--- Source/JavaScriptCore/ftl/FTLOSRExitCompiler.cpp (revision 155903) >+++ Source/JavaScriptCore/ftl/FTLOSRExitCompiler.cpp (working copy) >@@ -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,12 @@ static void compileStub( > jit.or64(GPRInfo::tagTypeNumberRegister, GPRInfo::regT0); > jit.store64(GPRInfo::regT0, address); > break; >+ case ExitValueInJSStackAsInt48: >+ jit.load64(address, GPRInfo::regT0); >+ jit.rshift64(AssemblyHelpers::TrustedImm32(16), GPRInfo::regT0); >+ jit.boxInt48(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 +168,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: Source/JavaScriptCore/ftl/FTLOutput.h >=================================================================== >--- Source/JavaScriptCore/ftl/FTLOutput.h (revision 155903) >+++ Source/JavaScriptCore/ftl/FTLOutput.h (working copy) >@@ -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: Source/JavaScriptCore/ftl/FTLValueFormat.cpp >=================================================================== >--- Source/JavaScriptCore/ftl/FTLValueFormat.cpp (revision 155903) >+++ Source/JavaScriptCore/ftl/FTLValueFormat.cpp (working copy) >@@ -44,6 +44,12 @@ void printInternal(PrintStream& out, Val > case ValueFormatUInt32: > out.print("UInt32"); > return; >+ case ValueFormatInt48: >+ out.print("Int48"); >+ return; >+ case ValueFormatStrictInt48: >+ out.print("StrictInt48"); >+ return; > case ValueFormatBoolean: > out.print("Boolean"); > return; >Index: Source/JavaScriptCore/ftl/FTLValueFormat.h >=================================================================== >--- Source/JavaScriptCore/ftl/FTLValueFormat.h (revision 155903) >+++ Source/JavaScriptCore/ftl/FTLValueFormat.h (working copy) >@@ -41,6 +41,8 @@ enum ValueFormat { > InvalidValueFormat, > ValueFormatInt32, > ValueFormatUInt32, >+ ValueFormatInt48, >+ ValueFormatStrictInt48, > ValueFormatBoolean, > ValueFormatJSValue, > ValueFormatDouble >Index: Source/JavaScriptCore/ftl/FTLValueSource.cpp >=================================================================== >--- Source/JavaScriptCore/ftl/FTLValueSource.cpp (revision 155903) >+++ Source/JavaScriptCore/ftl/FTLValueSource.cpp (working copy) >@@ -42,6 +42,9 @@ void ValueSource::dump(PrintStream& out) > case Int32InJSStack: > out.print("Int32InJSStack"); > return; >+ case Int48InJSStack: >+ out.print("Int48InJSStack"); >+ return; > case DoubleInJSStack: > out.print("DoubleInJSStack"); > return; >Index: Source/JavaScriptCore/ftl/FTLValueSource.h >=================================================================== >--- Source/JavaScriptCore/ftl/FTLValueSource.h (revision 155903) >+++ Source/JavaScriptCore/ftl/FTLValueSource.h (working copy) >@@ -40,6 +40,7 @@ enum ValueSourceKind { > SourceNotSet, > ValueInJSStack, > Int32InJSStack, >+ Int48InJSStack, > DoubleInJSStack, > SourceIsDead, > HaveNode >Index: Source/JavaScriptCore/interpreter/Register.h >=================================================================== >--- Source/JavaScriptCore/interpreter/Register.h (revision 155903) >+++ Source/JavaScriptCore/interpreter/Register.h (working copy) >@@ -73,6 +73,7 @@ namespace JSC { > Instruction* vPC() const; > InlineCallFrame* asInlineCallFrame() const; > int32_t unboxedInt32() const; >+ int64_t unboxedInt48() 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::unboxedInt48() const >+ { >+ return u.integer >> 16; >+ } >+ > ALWAYS_INLINE bool Register::unboxedBoolean() const > { > return !!payload(); >Index: Source/JavaScriptCore/runtime/Arguments.cpp >=================================================================== >--- Source/JavaScriptCore/runtime/Arguments.cpp (revision 155903) >+++ Source/JavaScriptCore/runtime/Arguments.cpp (working copy) >@@ -383,6 +383,9 @@ void Arguments::tearOffForInlineCallFram > case AlreadyInJSStackAsUnboxedInt32: > value = jsNumber(location->unboxedInt32()); > break; >+ case AlreadyInJSStackAsUnboxedInt48: >+ value = jsNumber(location->unboxedInt48()); >+ break; > case AlreadyInJSStackAsUnboxedCell: > value = location->unboxedCell(); > break; >Index: Source/JavaScriptCore/runtime/IndexingType.cpp >=================================================================== >--- Source/JavaScriptCore/runtime/IndexingType.cpp (revision 155903) >+++ Source/JavaScriptCore/runtime/IndexingType.cpp (working copy) >@@ -50,11 +50,11 @@ IndexingType leastUpperBoundOfIndexingTy > 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: Source/JavaScriptCore/runtime/JSCJSValue.h >=================================================================== >--- Source/JavaScriptCore/runtime/JSCJSValue.h (revision 155903) >+++ Source/JavaScriptCore/runtime/JSCJSValue.h (working copy) >@@ -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; >Index: Source/JavaScriptCore/runtime/JSCJSValueInlines.h >=================================================================== >--- Source/JavaScriptCore/runtime/JSCJSValueInlines.h (revision 155903) >+++ Source/JavaScriptCore/runtime/JSCJSValueInlines.h (working copy) >@@ -494,6 +494,35 @@ ALWAYS_INLINE JSCell* JSValue::asCell() > > #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) << 47)) >+ return false; >+ if (asInt64 < -(static_cast<int64_t>(1) << 47)) >+ 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: Source/WTF/ChangeLog >=================================================================== >--- Source/WTF/ChangeLog (revision 155925) >+++ Source/WTF/ChangeLog (working copy) >@@ -1,3 +1,15 @@ >+2013-09-16 Filip Pizlo <fpizlo@apple.com> >+ >+ DFG should support Int48 for local variables >+ https://bugs.webkit.org/show_bug.cgi?id=121064 >+ >+ Reviewed by NOBODY (OOPS!). >+ >+ * wtf/PrintStream.h: >+ (WTF::ValueIgnoringContext::ValueIgnoringContext): >+ (WTF::ValueIgnoringContext::dump): >+ (WTF::ignoringContext): >+ > 2013-09-16 Benjamin Poulain <benjamin@webkit.org> > > Fix WebKit1 build after r155910 >Index: Source/WTF/wtf/PrintStream.h >=================================================================== >--- Source/WTF/wtf/PrintStream.h (revision 155903) >+++ Source/WTF/wtf/PrintStream.h (working copy) >@@ -360,11 +360,36 @@ ValueInContext<T, U> inContext(const T& > 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; >
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Flags:
webkit-ews
:
commit-queue-
Actions:
View
|
Formatted Diff
|
Diff
Attachments on
bug 121064
:
211385
|
211463
|
211477
|
211507
|
211614
|
211619
|
211655
|
211666
|
211679
|
211723
|
211730
|
211732
|
211735
|
211736
|
211737
|
211842
|
211853
|
211854
|
211866
|
211929