Changeset 198981 in webkit


Ignore:
Timestamp:
Apr 3, 2016 1:37:26 AM (8 years ago)
Author:
Yusuke Suzuki
Message:

[JSC] Add truncate operation (rounding to zero)
https://bugs.webkit.org/show_bug.cgi?id=156072

Reviewed by Saam Barati.

Source/JavaScriptCore:

Add TruncIntrinsic for Math.trunc. DFG handles it as ArithTrunc.
In DFG, ArithTrunc behaves similar to ArithRound, ArithCeil, and ArithFloor.
ArithTrunc rounds the value towards zero.

And we rewrite @toInteger to use @trunc instead of @abs, @floor, negation and branch.
This is completely the same to what we do in JSValue::toInteger.

Since DFG recognize it, DFG can convert ArithTrunc to Identity if the given argument is Int32.
This is useful because almost all the argument is Int32 in @toLength -> @toInteger -> @trunc case.
In such cases, we can eliminate trunc() call.

As a bonus, to speed up Math.trunc operation, we use x86 SSE round and frintz in ARM64 for ArithRound.
In DFG, we emit these instructions. In FTL, we use Patchpoint to emit these instructions to avoid adding a new B3 IR.

  • assembler/MacroAssemblerARM64.h:

(JSC::MacroAssemblerARM64::roundTowardZeroDouble):
(JSC::MacroAssemblerARM64::roundTowardZeroFloat):

  • assembler/MacroAssemblerARMv7.h:

(JSC::MacroAssemblerARMv7::roundTowardZeroDouble):

  • assembler/MacroAssemblerMIPS.h:

(JSC::MacroAssemblerMIPS::roundTowardZeroDouble):

  • assembler/MacroAssemblerSH4.h:

(JSC::MacroAssemblerSH4::roundTowardZeroDouble):

  • assembler/MacroAssemblerX86Common.h:

(JSC::MacroAssemblerX86Common::roundTowardZeroDouble):
(JSC::MacroAssemblerX86Common::roundTowardZeroFloat):

  • builtins/GlobalObject.js:

(toInteger):

  • dfg/DFGAbstractInterpreterInlines.h:

(JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects):

  • dfg/DFGByteCodeParser.cpp:

(JSC::DFG::ByteCodeParser::handleIntrinsicCall):

  • dfg/DFGClobberize.h:

(JSC::DFG::clobberize):

  • dfg/DFGDoesGC.cpp:

(JSC::DFG::doesGC):

  • dfg/DFGFixupPhase.cpp:

(JSC::DFG::FixupPhase::fixupNode):

  • dfg/DFGGraph.h:

(JSC::DFG::Graph::roundShouldSpeculateInt32):

  • dfg/DFGNode.h:

(JSC::DFG::Node::arithNodeFlags):
(JSC::DFG::Node::hasHeapPrediction):
(JSC::DFG::Node::hasArithRoundingMode):

  • dfg/DFGNodeType.h:
  • dfg/DFGPredictionPropagationPhase.cpp:

(JSC::DFG::PredictionPropagationPhase::propagate):

  • dfg/DFGSafeToExecute.h:

(JSC::DFG::safeToExecute):

  • dfg/DFGSpeculativeJIT.cpp:

(JSC::DFG::SpeculativeJIT::compileArithRounding):

  • dfg/DFGSpeculativeJIT.h:
  • dfg/DFGSpeculativeJIT32_64.cpp:

(JSC::DFG::SpeculativeJIT::compile):

  • dfg/DFGSpeculativeJIT64.cpp:

(JSC::DFG::SpeculativeJIT::compile):

  • ftl/FTLCapabilities.cpp:

(JSC::FTL::canCompile):

  • ftl/FTLLowerDFGToB3.cpp:

(JSC::FTL::DFG::LowerDFGToB3::compileNode):
(JSC::FTL::DFG::LowerDFGToB3::compileArithTrunc):

  • ftl/FTLOutput.cpp:

(JSC::FTL::Output::doubleTrunc):

  • ftl/FTLOutput.h:
  • jit/ThunkGenerators.cpp:

(JSC::truncThunkGenerator):

  • jit/ThunkGenerators.h:
  • runtime/CommonIdentifiers.h:
  • runtime/Intrinsic.h:
  • runtime/JSGlobalObject.cpp:

(JSC::JSGlobalObject::init):

  • runtime/MathObject.cpp:

(JSC::MathObject::finishCreation):

  • runtime/MathObject.h:
  • runtime/VM.cpp:

(JSC::thunkGeneratorForIntrinsic):

  • tests/stress/math-rounding-infinity.js:

(testTrunc):

  • tests/stress/math-rounding-nan.js:

(testTrunc):

  • tests/stress/math-rounding-negative-zero.js:

(testTrunc):

  • tests/stress/math-trunc-arith-rounding-mode.js: Added.

(firstCareAboutZeroSecondDoesNot):
(firstDoNotCareAboutZeroSecondDoes):
(warmup):
(verifyNegativeZeroIsPreserved):

  • tests/stress/math-trunc-basics.js: Added.

(mathTruncOnIntegers):
(mathTruncOnDoubles):
(mathTruncOnBooleans):
(uselessMathTrunc):
(mathTruncWithOverflow):
(mathTruncConsumedAsDouble):
(mathTruncDoesNotCareAboutMinusZero):
(mathTruncNoArguments):
(mathTruncTooManyArguments):
(testMathTruncOnConstants):
(mathTruncStructTransition):
(Math.trunc):

  • tests/stress/math-trunc-should-be-truncate.js: Added.

(mathTrunc):

LayoutTests:

  • js/regress/many-foreach-calls-expected.txt: Added.
  • js/regress/many-foreach-calls.html: Added.
  • js/regress/math-trunc-expected.txt: Added.
  • js/regress/math-trunc.html: Added.
  • js/regress/script-tests/many-foreach-calls.js: Added.

forEach calls @toInteger. It includes @trunc now.
(i.array.forEach):

  • js/regress/script-tests/math-trunc.js: Added.

Call Math.trunc repeatedly.
(mathTruncInt):
(mathTruncDouble):
(mathTruncMixed):
(mathTruncDoubleDoesNotCareNegativeZero):

Location:
trunk
Files:
9 added
37 edited

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/ChangeLog

    r198978 r198981  
     12016-04-03  Yusuke Suzuki  <utatane.tea@gmail.com>
     2
     3        [JSC] Add truncate operation (rounding to zero)
     4        https://bugs.webkit.org/show_bug.cgi?id=156072
     5
     6        Reviewed by Saam Barati.
     7
     8        * js/regress/many-foreach-calls-expected.txt: Added.
     9        * js/regress/many-foreach-calls.html: Added.
     10        * js/regress/math-trunc-expected.txt: Added.
     11        * js/regress/math-trunc.html: Added.
     12        * js/regress/script-tests/many-foreach-calls.js: Added.
     13        forEach calls @toInteger. It includes @trunc now.
     14        (i.array.forEach):
     15        * js/regress/script-tests/math-trunc.js: Added.
     16        Call Math.trunc repeatedly.
     17        (mathTruncInt):
     18        (mathTruncDouble):
     19        (mathTruncMixed):
     20        (mathTruncDoubleDoesNotCareNegativeZero):
     21
    1222016-04-02  Skachkov Oleksandr  <gskachkov@gmail.com>
    223
  • trunk/Source/JavaScriptCore/ChangeLog

    r198980 r198981  
     12016-04-03  Yusuke Suzuki  <utatane.tea@gmail.com>
     2
     3        [JSC] Add truncate operation (rounding to zero)
     4        https://bugs.webkit.org/show_bug.cgi?id=156072
     5
     6        Reviewed by Saam Barati.
     7
     8        Add TruncIntrinsic for Math.trunc. DFG handles it as ArithTrunc.
     9        In DFG, ArithTrunc behaves similar to ArithRound, ArithCeil, and ArithFloor.
     10        ArithTrunc rounds the value towards zero.
     11
     12        And we rewrite @toInteger to use @trunc instead of @abs, @floor, negation and branch.
     13        This is completely the same to what we do in JSValue::toInteger.
     14
     15        Since DFG recognize it, DFG can convert ArithTrunc to Identity if the given argument is Int32.
     16        This is useful because almost all the argument is Int32 in @toLength -> @toInteger -> @trunc case.
     17        In such cases, we can eliminate trunc() call.
     18
     19        As a bonus, to speed up Math.trunc operation, we use x86 SSE round and frintz in ARM64 for ArithRound.
     20        In DFG, we emit these instructions. In FTL, we use Patchpoint to emit these instructions to avoid adding a new B3 IR.
     21
     22        * assembler/MacroAssemblerARM64.h:
     23        (JSC::MacroAssemblerARM64::roundTowardZeroDouble):
     24        (JSC::MacroAssemblerARM64::roundTowardZeroFloat):
     25        * assembler/MacroAssemblerARMv7.h:
     26        (JSC::MacroAssemblerARMv7::roundTowardZeroDouble):
     27        * assembler/MacroAssemblerMIPS.h:
     28        (JSC::MacroAssemblerMIPS::roundTowardZeroDouble):
     29        * assembler/MacroAssemblerSH4.h:
     30        (JSC::MacroAssemblerSH4::roundTowardZeroDouble):
     31        * assembler/MacroAssemblerX86Common.h:
     32        (JSC::MacroAssemblerX86Common::roundTowardZeroDouble):
     33        (JSC::MacroAssemblerX86Common::roundTowardZeroFloat):
     34        * builtins/GlobalObject.js:
     35        (toInteger):
     36        * dfg/DFGAbstractInterpreterInlines.h:
     37        (JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects):
     38        * dfg/DFGByteCodeParser.cpp:
     39        (JSC::DFG::ByteCodeParser::handleIntrinsicCall):
     40        * dfg/DFGClobberize.h:
     41        (JSC::DFG::clobberize):
     42        * dfg/DFGDoesGC.cpp:
     43        (JSC::DFG::doesGC):
     44        * dfg/DFGFixupPhase.cpp:
     45        (JSC::DFG::FixupPhase::fixupNode):
     46        * dfg/DFGGraph.h:
     47        (JSC::DFG::Graph::roundShouldSpeculateInt32):
     48        * dfg/DFGNode.h:
     49        (JSC::DFG::Node::arithNodeFlags):
     50        (JSC::DFG::Node::hasHeapPrediction):
     51        (JSC::DFG::Node::hasArithRoundingMode):
     52        * dfg/DFGNodeType.h:
     53        * dfg/DFGPredictionPropagationPhase.cpp:
     54        (JSC::DFG::PredictionPropagationPhase::propagate):
     55        * dfg/DFGSafeToExecute.h:
     56        (JSC::DFG::safeToExecute):
     57        * dfg/DFGSpeculativeJIT.cpp:
     58        (JSC::DFG::SpeculativeJIT::compileArithRounding):
     59        * dfg/DFGSpeculativeJIT.h:
     60        * dfg/DFGSpeculativeJIT32_64.cpp:
     61        (JSC::DFG::SpeculativeJIT::compile):
     62        * dfg/DFGSpeculativeJIT64.cpp:
     63        (JSC::DFG::SpeculativeJIT::compile):
     64        * ftl/FTLCapabilities.cpp:
     65        (JSC::FTL::canCompile):
     66        * ftl/FTLLowerDFGToB3.cpp:
     67        (JSC::FTL::DFG::LowerDFGToB3::compileNode):
     68        (JSC::FTL::DFG::LowerDFGToB3::compileArithTrunc):
     69        * ftl/FTLOutput.cpp:
     70        (JSC::FTL::Output::doubleTrunc):
     71        * ftl/FTLOutput.h:
     72        * jit/ThunkGenerators.cpp:
     73        (JSC::truncThunkGenerator):
     74        * jit/ThunkGenerators.h:
     75        * runtime/CommonIdentifiers.h:
     76        * runtime/Intrinsic.h:
     77        * runtime/JSGlobalObject.cpp:
     78        (JSC::JSGlobalObject::init):
     79        * runtime/MathObject.cpp:
     80        (JSC::MathObject::finishCreation):
     81        * runtime/MathObject.h:
     82        * runtime/VM.cpp:
     83        (JSC::thunkGeneratorForIntrinsic):
     84        * tests/stress/math-rounding-infinity.js:
     85        (testTrunc):
     86        * tests/stress/math-rounding-nan.js:
     87        (testTrunc):
     88        * tests/stress/math-rounding-negative-zero.js:
     89        (testTrunc):
     90        * tests/stress/math-trunc-arith-rounding-mode.js: Added.
     91        (firstCareAboutZeroSecondDoesNot):
     92        (firstDoNotCareAboutZeroSecondDoes):
     93        (warmup):
     94        (verifyNegativeZeroIsPreserved):
     95        * tests/stress/math-trunc-basics.js: Added.
     96        (mathTruncOnIntegers):
     97        (mathTruncOnDoubles):
     98        (mathTruncOnBooleans):
     99        (uselessMathTrunc):
     100        (mathTruncWithOverflow):
     101        (mathTruncConsumedAsDouble):
     102        (mathTruncDoesNotCareAboutMinusZero):
     103        (mathTruncNoArguments):
     104        (mathTruncTooManyArguments):
     105        (testMathTruncOnConstants):
     106        (mathTruncStructTransition):
     107        (Math.trunc):
     108        * tests/stress/math-trunc-should-be-truncate.js: Added.
     109        (mathTrunc):
     110
    11112016-04-03  Skachkov Oleksandr  <gskachkov@gmail.com>
    2112
  • trunk/Source/JavaScriptCore/assembler/MacroAssemblerARM64.h

    r197895 r198981  
    15011501    }
    15021502
     1503    void roundTowardZeroDouble(FPRegisterID src, FPRegisterID dest)
     1504    {
     1505        m_assembler.frintz<64>(dest, src);
     1506    }
     1507
     1508    void roundTowardZeroFloat(FPRegisterID src, FPRegisterID dest)
     1509    {
     1510        m_assembler.frintz<32>(dest, src);
     1511    }
     1512
    15031513    // Convert 'src' to an integer, and places the resulting 'dest'.
    15041514    // If the result is not representable as a 32 bit value, branch.
  • trunk/Source/JavaScriptCore/assembler/MacroAssemblerARMv7.h

    r197687 r198981  
    10851085    }
    10861086
     1087    NO_RETURN_DUE_TO_CRASH void roundTowardZeroDouble(FPRegisterID, FPRegisterID)
     1088    {
     1089        ASSERT(!supportsFloatingPointRounding());
     1090        CRASH();
     1091    }
     1092
    10871093    void convertInt32ToDouble(RegisterID src, FPRegisterID dest)
    10881094    {
  • trunk/Source/JavaScriptCore/assembler/MacroAssemblerMIPS.h

    r197380 r198981  
    655655
    656656    NO_RETURN_DUE_TO_CRASH void floorDouble(FPRegisterID, FPRegisterID)
     657    {
     658        ASSERT(!supportsFloatingPointRounding());
     659        CRASH();
     660    }
     661
     662    NO_RETURN_DUE_TO_CRASH void roundTowardZeroDouble(FPRegisterID, FPRegisterID)
    657663    {
    658664        ASSERT(!supportsFloatingPointRounding());
  • trunk/Source/JavaScriptCore/assembler/MacroAssemblerSH4.h

    r197380 r198981  
    15881588    }
    15891589
     1590    NO_RETURN_DUE_TO_CRASH void roundTowardZeroDouble(FPRegisterID, FPRegisterID)
     1591    {
     1592        ASSERT(!supportsFloatingPointRounding());
     1593        CRASH();
     1594    }
     1595
    15901596    Jump branchTest8(ResultCondition cond, Address address, TrustedImm32 mask = TrustedImm32(-1))
    15911597    {
  • trunk/Source/JavaScriptCore/assembler/MacroAssemblerX86Common.h

    r198953 r198981  
    734734    {
    735735        m_assembler.roundss_mr(src.offset, src.base, dst, X86Assembler::RoundingType::TowardNegativeInfiniti);
     736    }
     737
     738    void roundTowardZeroDouble(FPRegisterID src, FPRegisterID dst)
     739    {
     740        m_assembler.roundsd_rr(src, dst, X86Assembler::RoundingType::TowardZero);
     741    }
     742
     743    void roundTowardZeroDouble(Address src, FPRegisterID dst)
     744    {
     745        m_assembler.roundsd_mr(src.offset, src.base, dst, X86Assembler::RoundingType::TowardZero);
     746    }
     747
     748    void roundTowardZeroFloat(FPRegisterID src, FPRegisterID dst)
     749    {
     750        m_assembler.roundss_rr(src, dst, X86Assembler::RoundingType::TowardZero);
     751    }
     752
     753    void roundTowardZeroFloat(Address src, FPRegisterID dst)
     754    {
     755        m_assembler.roundss_mr(src.offset, src.base, dst, X86Assembler::RoundingType::TowardZero);
    736756    }
    737757
  • trunk/Source/JavaScriptCore/builtins/GlobalObject.js

    r196276 r198981  
    3535    if (numberValue !== numberValue)
    3636        return 0;
    37 
    38     if (numberValue === 0 || !@isFinite(numberValue))
    39         return numberValue;
    40 
    41     return (numberValue > 0 ? 1 : -1) * @floor(@abs(numberValue));
     37    return @trunc(numberValue);
    4238}
    4339
  • trunk/Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h

    r198902 r198981  
    851851    case ArithRound:
    852852    case ArithFloor:
    853     case ArithCeil: {
     853    case ArithCeil:
     854    case ArithTrunc: {
    854855        JSValue operand = forNode(node->child1()).value();
    855856        if (operand && operand.isNumber()) {
     
    859860            else if (node->op() == ArithFloor)
    860861                roundedValue = floor(operand.asNumber());
     862            else if (node->op() == ArithCeil)
     863                roundedValue = ceil(operand.asNumber());
    861864            else {
    862                 ASSERT(node->op() == ArithCeil);
    863                 roundedValue = ceil(operand.asNumber());
     865                ASSERT(node->op() == ArithTrunc);
     866                roundedValue = trunc(operand.asNumber());
    864867            }
    865868
  • trunk/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp

    r198844 r198981  
    22042204    case RoundIntrinsic:
    22052205    case FloorIntrinsic:
    2206     case CeilIntrinsic: {
     2206    case CeilIntrinsic:
     2207    case TruncIntrinsic: {
    22072208        if (argumentCountIncludingThis == 1) {
    22082209            insertChecks();
     
    22182219            else if (intrinsic == FloorIntrinsic)
    22192220                op = ArithFloor;
     2221            else if (intrinsic == CeilIntrinsic)
     2222                op = ArithCeil;
    22202223            else {
    2221                 ASSERT(intrinsic == CeilIntrinsic);
    2222                 op = ArithCeil;
     2224                ASSERT(intrinsic == TruncIntrinsic);
     2225                op = ArithTrunc;
    22232226            }
    22242227            Node* roundNode = addToGraph(op, OpInfo(0), OpInfo(prediction), operand);
  • trunk/Source/JavaScriptCore/dfg/DFGClobberize.h

    r198844 r198981  
    306306    case ArithFloor:
    307307    case ArithCeil:
     308    case ArithTrunc:
    308309        def(PureValue(node, static_cast<uintptr_t>(node->arithRoundingMode())));
    309310        return;
  • trunk/Source/JavaScriptCore/dfg/DFGDoesGC.cpp

    r198844 r198981  
    9191    case ArithFloor:
    9292    case ArithCeil:
     93    case ArithTrunc:
    9394    case ArithFRound:
    9495    case ArithSin:
  • trunk/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp

    r198844 r198981  
    366366        case ArithRound:
    367367        case ArithFloor:
    368         case ArithCeil: {
     368        case ArithCeil:
     369        case ArithTrunc: {
    369370            if (m_graph.unaryArithShouldSpeculateInt32(node, FixupPass)) {
    370371                fixIntOrBooleanEdge(node->child1());
  • trunk/Source/JavaScriptCore/dfg/DFGGraph.h

    r198600 r198981  
    317317    bool roundShouldSpeculateInt32(Node* arithRound, PredictionPass pass)
    318318    {
    319         ASSERT(arithRound->op() == ArithRound || arithRound->op() == ArithFloor || arithRound->op() == ArithCeil);
     319        ASSERT(arithRound->op() == ArithRound || arithRound->op() == ArithFloor || arithRound->op() == ArithCeil || arithRound->op() == ArithTrunc);
    320320        return arithRound->canSpeculateInt32(pass) && !hasExitSite(arithRound->origin.semantic, Overflow) && !hasExitSite(arithRound->origin.semantic, NegativeZero);
    321321    }
  • trunk/Source/JavaScriptCore/dfg/DFGNode.h

    r198935 r198981  
    944944    {
    945945        NodeFlags result = m_flags & NodeArithFlagsMask;
    946         if (op() == ArithMul || op() == ArithDiv || op() == ArithMod || op() == ArithNegate || op() == ArithPow || op() == ArithRound || op() == ArithFloor || op() == ArithCeil || op() == DoubleAsInt32)
     946        if (op() == ArithMul || op() == ArithDiv || op() == ArithMod || op() == ArithNegate || op() == ArithPow || op() == ArithRound || op() == ArithFloor || op() == ArithCeil || op() == ArithTrunc || op() == DoubleAsInt32)
    947947            return result;
    948948        return result & ~NodeBytecodeNeedsNegZero;
     
    13521352        case ArithFloor:
    13531353        case ArithCeil:
     1354        case ArithTrunc:
    13541355        case GetDirectPname:
    13551356        case GetById:
     
    17341735    bool hasArithRoundingMode()
    17351736    {
    1736         return op() == ArithRound || op() == ArithFloor || op() == ArithCeil;
     1737        return op() == ArithRound || op() == ArithFloor || op() == ArithCeil || op() == ArithTrunc;
    17371738    }
    17381739
  • trunk/Source/JavaScriptCore/dfg/DFGNodeType.h

    r198844 r198981  
    159159    macro(ArithFloor, NodeResultNumber) \
    160160    macro(ArithCeil, NodeResultNumber) \
     161    macro(ArithTrunc, NodeResultNumber) \
    161162    macro(ArithSqrt, NodeResultNumber) \
    162163    macro(ArithSin, NodeResultNumber) \
  • trunk/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp

    r198844 r198981  
    390390        case ArithRound:
    391391        case ArithFloor:
    392         case ArithCeil: {
     392        case ArithCeil:
     393        case ArithTrunc: {
    393394            if (isInt32OrBooleanSpeculation(node->getHeapPrediction()) && m_graph.roundShouldSpeculateInt32(node, m_pass))
    394395                changed |= setPrediction(SpecInt32);
  • trunk/Source/JavaScriptCore/dfg/DFGSafeToExecute.h

    r198844 r198981  
    187187    case ArithFloor:
    188188    case ArithCeil:
     189    case ArithTrunc:
    189190    case ArithSin:
    190191    case ArithCos:
  • trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp

    r198844 r198981  
    45064506        }
    45074507
     4508        case ArithTrunc: {
     4509            FPRTemporary rounded(this);
     4510            FPRReg resultFPR = rounded.fpr();
     4511            m_jit.roundTowardZeroDouble(valueFPR, resultFPR);
     4512            setResult(resultFPR);
     4513            return;
     4514        }
     4515
    45084516        default:
    45094517            RELEASE_ASSERT_NOT_REACHED();
     
    45174525        else if (node->op() == ArithFloor)
    45184526            callOperation(floor, resultFPR, valueFPR);
     4527        else if (node->op() == ArithCeil)
     4528            callOperation(ceil, resultFPR, valueFPR);
    45194529        else {
    4520             ASSERT(node->op() == ArithCeil);
    4521             callOperation(ceil, resultFPR, valueFPR);
     4530            ASSERT(node->op() == ArithTrunc);
     4531            callOperation(trunc, resultFPR, valueFPR);
    45224532        }
    45234533        m_jit.exceptionCheck();
  • trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h

    r198844 r198981  
    23742374    void compileArithPow(Node*);
    23752375    void compileArithRounding(Node*);
    2376     void compileArithFloor(Node*);
    2377     void compileArithCeil(Node*);
    23782376    void compileArithRandom(Node*);
    23792377    void compileArithSqrt(Node*);
  • trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp

    r198844 r198981  
    23072307    case ArithFloor:
    23082308    case ArithCeil:
     2309    case ArithTrunc:
    23092310        compileArithRounding(node);
    23102311        break;
  • trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp

    r198844 r198981  
    24452445    case ArithFloor:
    24462446    case ArithCeil:
     2447    case ArithTrunc:
    24472448        compileArithRounding(node);
    24482449        break;
  • trunk/Source/JavaScriptCore/ftl/FTLCapabilities.cpp

    r198844 r198981  
    100100    case ArithFloor:
    101101    case ArithCeil:
     102    case ArithTrunc:
    102103    case ArithSqrt:
    103104    case ArithLog:
  • trunk/Source/JavaScriptCore/ftl/FTLLowerDFGToB3.cpp

    r198844 r198981  
    533533            compileArithCeil();
    534534            break;
     535        case ArithTrunc:
     536            compileArithTrunc();
     537            break;
    535538        case ArithSqrt:
    536539            compileArithSqrt();
     
    19751978        else
    19761979            setDouble(integerValue);
     1980    }
     1981
     1982    void compileArithTrunc()
     1983    {
     1984        LValue value = lowDouble(m_node->child1());
     1985        LValue result = m_out.doubleTrunc(value);
     1986        if (producesInteger(m_node->arithRoundingMode()))
     1987            setInt32(convertDoubleToInt32(result, shouldCheckNegativeZero(m_node->arithRoundingMode())));
     1988        else
     1989            setDouble(result);
    19771990    }
    19781991
  • trunk/Source/JavaScriptCore/ftl/FTLOutput.cpp

    r198364 r198981  
    147147}
    148148
     149LValue Output::doubleTrunc(LValue value)
     150{
     151    if (MacroAssembler::supportsFloatingPointRounding()) {
     152        PatchpointValue* result = patchpoint(Double);
     153        result->append(value, ValueRep::SomeRegister);
     154        result->setGenerator(
     155            [] (CCallHelpers& jit, const StackmapGenerationParams& params) {
     156                jit.roundTowardZeroDouble(params[1].fpr(), params[0].fpr());
     157            });
     158        result->effects = Effects::none();
     159        return result;
     160    }
     161    double (*truncDouble)(double) = trunc;
     162    return callWithoutSideEffects(Double, truncDouble, value);
     163}
     164
    149165LValue Output::unsignedToDouble(LValue value)
    150166{
  • trunk/Source/JavaScriptCore/ftl/FTLOutput.h

    r198364 r198981  
    157157    LValue doubleCeil(LValue operand) { return m_block->appendNew<B3::Value>(m_proc, B3::Ceil, origin(), operand); }
    158158    LValue doubleFloor(LValue operand) { return m_block->appendNew<B3::Value>(m_proc, B3::Floor, origin(), operand); }
     159    LValue doubleTrunc(LValue);
    159160
    160161    LValue doubleSin(LValue value)
  • trunk/Source/JavaScriptCore/jit/ThunkGenerators.cpp

    r198513 r198981  
    741741static double (_cdecl *floorFunction)(double) = floor;
    742742static double (_cdecl *ceilFunction)(double) = ceil;
     743static double (_cdecl *truncFunction)(double) = trunc;
    743744static double (_cdecl *expFunction)(double) = exp;
    744745static double (_cdecl *logFunction)(double) = log;
     
    772773defineUnaryDoubleOpWrapper(floor);
    773774defineUnaryDoubleOpWrapper(ceil);
     775defineUnaryDoubleOpWrapper(trunc);
    774776
    775777static const double oneConstant = 1.0;
     
    841843    jit.returnDouble(SpecializedThunkJIT::fpRegT0);
    842844    return jit.finalize(vm->jitStubs->ctiNativeTailCall(vm), "ceil");
     845}
     846
     847MacroAssemblerCodeRef truncThunkGenerator(VM* vm)
     848{
     849    SpecializedThunkJIT jit(vm, 1);
     850    if (!UnaryDoubleOpWrapper(trunc) || !jit.supportsFloatingPoint())
     851        return MacroAssemblerCodeRef::createSelfManagedCodeRef(vm->jitStubs->ctiNativeCall(vm));
     852    MacroAssembler::Jump nonIntJump;
     853    jit.loadInt32Argument(0, SpecializedThunkJIT::regT0, nonIntJump);
     854    jit.returnInt32(SpecializedThunkJIT::regT0);
     855    nonIntJump.link(&jit);
     856    jit.loadDoubleArgument(0, SpecializedThunkJIT::fpRegT0, SpecializedThunkJIT::regT0);
     857    if (jit.supportsFloatingPointRounding())
     858        jit.roundTowardZeroDouble(SpecializedThunkJIT::fpRegT0, SpecializedThunkJIT::fpRegT0);
     859    else
     860        jit.callDoubleToDoublePreservingReturn(UnaryDoubleOpWrapper(trunc));
     861
     862    SpecializedThunkJIT::JumpList doubleResult;
     863    jit.branchConvertDoubleToInt32(SpecializedThunkJIT::fpRegT0, SpecializedThunkJIT::regT0, doubleResult, SpecializedThunkJIT::fpRegT1);
     864    jit.returnInt32(SpecializedThunkJIT::regT0);
     865    doubleResult.link(&jit);
     866    jit.returnDouble(SpecializedThunkJIT::fpRegT0);
     867    return jit.finalize(vm->jitStubs->ctiNativeTailCall(vm), "trunc");
    843868}
    844869
  • trunk/Source/JavaScriptCore/jit/ThunkGenerators.h

    r194087 r198981  
    6464MacroAssemblerCodeRef imulThunkGenerator(VM*);
    6565MacroAssemblerCodeRef randomThunkGenerator(VM*);
     66MacroAssemblerCodeRef truncThunkGenerator(VM*);
    6667
    6768}
  • trunk/Source/JavaScriptCore/runtime/CommonIdentifiers.h

    r198844 r198981  
    316316    macro(abs) \
    317317    macro(floor) \
     318    macro(trunc) \
    318319    macro(isFinite) \
    319320    macro(isNaN) \
  • trunk/Source/JavaScriptCore/runtime/Intrinsic.h

    r198844 r198981  
    5757    RandomIntrinsic,
    5858    FRoundIntrinsic,
     59    TruncIntrinsic,
    5960
    6061    // Getter intrinsics.
  • trunk/Source/JavaScriptCore/runtime/JSGlobalObject.cpp

    r198980 r198981  
    527527    JSFunction* privateFuncIsFinite = JSFunction::create(vm, this, 0, String(), globalFuncIsFinite);
    528528    JSFunction* privateFuncIsNaN = JSFunction::create(vm, this, 0, String(), globalFuncIsNaN);
     529    JSFunction* privateFuncTrunc = JSFunction::create(vm, this, 0, String(), mathProtoFuncTrunc, TruncIntrinsic);
    529530
    530531    JSFunction* privateFuncGetTemplateObject = JSFunction::create(vm, this, 0, String(), getTemplateObject);
     
    564565        GlobalPropertyInfo(vm.propertyNames->absPrivateName, privateFuncAbs, DontEnum | DontDelete | ReadOnly),
    565566        GlobalPropertyInfo(vm.propertyNames->floorPrivateName, privateFuncFloor, DontEnum | DontDelete | ReadOnly),
     567        GlobalPropertyInfo(vm.propertyNames->truncPrivateName, privateFuncTrunc, DontEnum | DontDelete | ReadOnly),
    566568        GlobalPropertyInfo(vm.propertyNames->isFinitePrivateName, privateFuncIsFinite, DontEnum | DontDelete | ReadOnly),
    567569        GlobalPropertyInfo(vm.propertyNames->isNaNPrivateName, privateFuncIsNaN, DontEnum | DontDelete | ReadOnly),
  • trunk/Source/JavaScriptCore/runtime/MathObject.cpp

    r194087 r198981  
    6868EncodedJSValue JSC_HOST_CALL mathProtoFuncTan(ExecState*);
    6969EncodedJSValue JSC_HOST_CALL mathProtoFuncTanh(ExecState*);
    70 EncodedJSValue JSC_HOST_CALL mathProtoFuncTrunc(ExecState*);
    7170EncodedJSValue JSC_HOST_CALL mathProtoFuncIMul(ExecState*);
    7271
     
    130129    putDirectNativeFunctionWithoutTransition(vm, globalObject, Identifier::fromString(&vm, "tan"), 1, mathProtoFuncTan, NoIntrinsic, DontEnum);
    131130    putDirectNativeFunctionWithoutTransition(vm, globalObject, Identifier::fromString(&vm, "tanh"), 1, mathProtoFuncTanh, NoIntrinsic, DontEnum);
    132     putDirectNativeFunctionWithoutTransition(vm, globalObject, Identifier::fromString(&vm, "trunc"), 1, mathProtoFuncTrunc, NoIntrinsic, DontEnum);
     131    putDirectNativeFunctionWithoutTransition(vm, globalObject, Identifier::fromString(&vm, "trunc"), 1, mathProtoFuncTrunc, TruncIntrinsic, DontEnum);
    133132    putDirectNativeFunctionWithoutTransition(vm, globalObject, Identifier::fromString(&vm, "imul"), 2, mathProtoFuncIMul, IMulIntrinsic, DontEnum);
    134133}
  • trunk/Source/JavaScriptCore/runtime/MathObject.h

    r183785 r198981  
    5454EncodedJSValue JSC_HOST_CALL mathProtoFuncAbs(ExecState*);
    5555EncodedJSValue JSC_HOST_CALL mathProtoFuncFloor(ExecState*);
     56EncodedJSValue JSC_HOST_CALL mathProtoFuncTrunc(ExecState*);
    5657
    5758} // namespace JSC
  • trunk/Source/JavaScriptCore/runtime/VM.cpp

    r198364 r198981  
    480480    case CeilIntrinsic:
    481481        return ceilThunkGenerator;
     482    case TruncIntrinsic:
     483        return truncThunkGenerator;
    482484    case RoundIntrinsic:
    483485        return roundThunkGenerator;
  • trunk/Source/JavaScriptCore/tests/stress/math-rounding-infinity.js

    r197380 r198981  
    2222noInline(testCeil);
    2323
     24function testTrunc(value)
     25{
     26    return Math.trunc(value);
     27}
     28noInline(testTrunc);
     29
    2430for (var i = 0; i < 1e4; ++i) {
    2531    shouldBe(testRound(Infinity), Infinity);
     
    2935    shouldBe(testCeil(Infinity), Infinity);
    3036    shouldBe(testCeil(-Infinity), -Infinity);
     37    shouldBe(testTrunc(Infinity), Infinity);
     38    shouldBe(testTrunc(-Infinity), -Infinity);
    3139}
  • trunk/Source/JavaScriptCore/tests/stress/math-rounding-nan.js

    r197380 r198981  
    2222noInline(testCeil);
    2323
     24function testTrunc(value)
     25{
     26    return Math.trunc(value);
     27}
     28noInline(testTrunc);
     29
    2430for (var i = 0; i < 1e4; ++i) {
    2531    shouldBe(Number.isNaN(testRound(NaN)), true);
    2632    shouldBe(Number.isNaN(testFloor(NaN)), true);
    2733    shouldBe(Number.isNaN(testCeil(NaN)), true);
     34    shouldBe(Number.isNaN(testTrunc(NaN)), true);
    2835}
  • trunk/Source/JavaScriptCore/tests/stress/math-rounding-negative-zero.js

    r197380 r198981  
    6868}
    6969
     70function testTrunc(value)
     71{
     72    return Math.trunc(value);
     73}
     74noInline(testTrunc);
    7075
     76for (var i = 0; i < 1e4; ++i) {
     77    shouldBe(1 / testTrunc(0.0), Infinity);
     78    shouldBe(1 / testTrunc(-0.0), -Infinity);
     79}
Note: See TracChangeset for help on using the changeset viewer.