Changeset 214219 in webkit


Ignore:
Timestamp:
Mar 21, 2017 4:31:43 AM (7 years ago)
Author:
Yusuke Suzuki
Message:

[JSC] Optimize Number.prototype.toString on Int32 / Int52 / Double
https://bugs.webkit.org/show_bug.cgi?id=167454

Reviewed by Saam Barati.

JSTests:

  • stress/number-to-string-abstract-operation.js: Added.

(shouldBe):
(int32ToString):
(shouldBe.int32ToString.new.Number.int52ToString):
(shouldBe.int32ToString.new.Number):
(shouldBe.doubleToString):

  • stress/number-to-string-radix.js: Added.

(shouldBe):
(int32ToString):
(shouldBe.int32ToString.new.Number.int52ToString):
(shouldBe.int32ToString.new.Number):
(shouldBe.doubleToString):

  • stress/number-to-string.js: Added.

(shouldBe):
(int32ToString):
(shouldBe.int32ToString.new.Number.int52ToString):
(shouldBe.int32ToString.new.Number):
(shouldBe.doubleToString):

Source/JavaScriptCore:

This patch improves Number.toString(radix) performance
by introducing NumberToStringWithRadix DFG node. It directly
calls the operation and it always returns String.

baseline patched

stanford-crypto-sha256-iterative 45.130+-0.928 44.032+-1.184 might be 1.0250x faster

Location:
trunk
Files:
3 added
25 edited

Legend:

Unmodified
Added
Removed
  • trunk/JSTests/ChangeLog

    r214145 r214219  
     12017-03-21  Yusuke Suzuki  <utatane.tea@gmail.com>
     2
     3        [JSC] Optimize Number.prototype.toString on Int32 / Int52 / Double
     4        https://bugs.webkit.org/show_bug.cgi?id=167454
     5
     6        Reviewed by Saam Barati.
     7
     8        * stress/number-to-string-abstract-operation.js: Added.
     9        (shouldBe):
     10        (int32ToString):
     11        (shouldBe.int32ToString.new.Number.int52ToString):
     12        (shouldBe.int32ToString.new.Number):
     13        (shouldBe.doubleToString):
     14        * stress/number-to-string-radix.js: Added.
     15        (shouldBe):
     16        (int32ToString):
     17        (shouldBe.int32ToString.new.Number.int52ToString):
     18        (shouldBe.int32ToString.new.Number):
     19        (shouldBe.doubleToString):
     20        * stress/number-to-string.js: Added.
     21        (shouldBe):
     22        (int32ToString):
     23        (shouldBe.int32ToString.new.Number.int52ToString):
     24        (shouldBe.int32ToString.new.Number):
     25        (shouldBe.doubleToString):
     26
    1272017-03-19  Chris Dumez  <cdumez@apple.com>
    228
  • trunk/Source/JavaScriptCore/ChangeLog

    r214218 r214219  
     12017-03-21  Yusuke Suzuki  <utatane.tea@gmail.com>
     2
     3        [JSC] Optimize Number.prototype.toString on Int32 / Int52 / Double
     4        https://bugs.webkit.org/show_bug.cgi?id=167454
     5
     6        Reviewed by Saam Barati.
     7
     8        This patch improves Number.toString(radix) performance
     9        by introducing NumberToStringWithRadix DFG node. It directly
     10        calls the operation and it always returns String.
     11
     12                                                       baseline                  patched
     13
     14            stanford-crypto-sha256-iterative        45.130+-0.928             44.032+-1.184           might be 1.0250x faster
     15
    1162017-03-21  Yusuke Suzuki  <utatane.tea@gmail.com>
    217
     
    2742        * assembler/MacroAssemblerMIPS.h:
    2843        (JSC::MacroAssemblerMIPS::branchPtr): Added.
     44
     45        * dfg/DFGAbstractInterpreterInlines.h:
     46        (JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects):
     47        * dfg/DFGByteCodeParser.cpp:
     48        (JSC::DFG::ByteCodeParser::handleIntrinsicCall):
     49        * dfg/DFGClobberize.h:
     50        (JSC::DFG::clobberize):
     51        * dfg/DFGDoesGC.cpp:
     52        (JSC::DFG::doesGC):
     53        * dfg/DFGFixupPhase.cpp:
     54        (JSC::DFG::FixupPhase::fixupNode):
     55        (JSC::DFG::FixupPhase::fixupToStringOrCallStringConstructor):
     56        * dfg/DFGNodeType.h:
     57        * dfg/DFGOperations.cpp:
     58        * dfg/DFGOperations.h:
     59        * dfg/DFGPredictionPropagationPhase.cpp:
     60        * dfg/DFGSafeToExecute.h:
     61        (JSC::DFG::safeToExecute):
     62        * dfg/DFGSpeculativeJIT.cpp:
     63        (JSC::DFG::SpeculativeJIT::compileToStringOrCallStringConstructor):
     64        (JSC::DFG::SpeculativeJIT::compileToStringOrCallStringConstructorOnNumber):
     65        (JSC::DFG::SpeculativeJIT::compileNumberToStringWithRadix):
     66        (JSC::DFG::SpeculativeJIT::compileToStringOrCallStringConstructorOnCell): Deleted.
     67        * dfg/DFGSpeculativeJIT.h:
     68        (JSC::DFG::SpeculativeJIT::callOperation):
     69        * dfg/DFGSpeculativeJIT32_64.cpp:
     70        (JSC::DFG::SpeculativeJIT::compile):
     71        * dfg/DFGSpeculativeJIT64.cpp:
     72        (JSC::DFG::SpeculativeJIT::compile):
     73        * dfg/DFGStrengthReductionPhase.cpp:
     74        (JSC::DFG::StrengthReductionPhase::handleNode):
     75        * ftl/FTLCapabilities.cpp:
     76        (JSC::FTL::canCompile):
     77        * ftl/FTLLowerDFGToB3.cpp:
     78        (JSC::FTL::DFG::LowerDFGToB3::compileNode):
     79        (JSC::FTL::DFG::LowerDFGToB3::compileToStringOrCallStringConstructor):
     80        (JSC::FTL::DFG::LowerDFGToB3::compileNumberToStringWithRadix):
     81        * jit/CCallHelpers.h:
     82        (JSC::CCallHelpers::setupArgumentsWithExecState):
     83        * jit/JITOperations.h:
     84        * runtime/Intrinsic.h:
     85        * runtime/NumberPrototype.cpp:
     86        (JSC::int52ToStringWithRadix):
     87        (JSC::int32ToStringInternal):
     88        (JSC::numberToStringInternal):
     89        (JSC::int32ToString):
     90        (JSC::int52ToString):
     91        (JSC::numberToString):
     92        (JSC::numberProtoFuncToString):
     93        (JSC::integerValueToString): Deleted.
     94        * runtime/NumberPrototype.h:
     95        * runtime/StringPrototype.cpp:
     96        (JSC::StringPrototype::finishCreation):
    2997
    30982017-03-20  Filip Pizlo  <fpizlo@apple.com>
  • trunk/Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h

    r214028 r214219  
    18591859            break;
    18601860        case StringOrStringObjectUse:
     1861        case Int32Use:
     1862        case Int52RepUse:
     1863        case DoubleRepUse:
    18611864        case NotCellUse:
    18621865            break;
     
    18721875        break;
    18731876    }
     1877
     1878    case NumberToStringWithRadix:
     1879        clobberWorld(node->origin.semantic, clobberLimit);
     1880        forNode(node).set(m_graph, m_graph.m_vm.stringStructure.get());
     1881        break;
    18741882       
    18751883    case NewStringObject: {
  • trunk/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp

    r214029 r214219  
    27122712    }
    27132713
    2714     case ToLowerCaseIntrinsic: {
     2714    case StringPrototypeToLowerCaseIntrinsic: {
    27152715        if (argumentCountIncludingThis != 1)
    27162716            return false;
     
    27232723        Node* result = addToGraph(ToLowerCase, thisString);
    27242724        set(VirtualRegister(resultOperand), result);
     2725        return true;
     2726    }
     2727
     2728    case NumberPrototypeToStringIntrinsic: {
     2729        if (argumentCountIncludingThis != 1 && argumentCountIncludingThis != 2)
     2730            return false;
     2731
     2732        if (m_inlineStackTop->m_exitProfile.hasExitSite(m_currentIndex, BadType))
     2733            return false;
     2734
     2735        insertChecks();
     2736        Node* thisNumber = get(virtualRegisterForArgument(0, registerOffset));
     2737        if (argumentCountIncludingThis == 1) {
     2738            Node* result = addToGraph(ToString, thisNumber);
     2739            set(VirtualRegister(resultOperand), result);
     2740        } else {
     2741            Node* radix = get(virtualRegisterForArgument(1, registerOffset));
     2742            Node* result = addToGraph(NumberToStringWithRadix, thisNumber, radix);
     2743            set(VirtualRegister(resultOperand), result);
     2744        }
    27252745        return true;
    27262746    }
  • trunk/Source/JavaScriptCore/dfg/DFGClobberize.h

    r214028 r214219  
    14101410            return;
    14111411
     1412        case Int32Use:
     1413        case Int52RepUse:
     1414        case DoubleRepUse:
    14121415        case NotCellUse:
    14131416            def(PureValue(node));
     
    14561459    case ToLowerCase:
    14571460        def(PureValue(node));
     1461        return;
     1462
     1463    case NumberToStringWithRadix:
     1464        read(World);
     1465        write(Heap);
    14581466        return;
    14591467       
  • trunk/Source/JavaScriptCore/dfg/DFGDoesGC.cpp

    r213107 r214219  
    179179    case ToString:
    180180    case CallStringConstructor:
     181    case NumberToStringWithRadix:
    181182    case In:
    182183    case HasOwnProperty:
  • trunk/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp

    r214028 r214219  
    17591759            // are correct.
    17601760            fixEdge<StringUse>(node->child1());
     1761            break;
     1762        }
     1763
     1764        case NumberToStringWithRadix: {
     1765            if (node->child1()->shouldSpeculateInt32())
     1766                fixEdge<Int32Use>(node->child1());
     1767            else if (enableInt52() && node->child1()->shouldSpeculateAnyInt())
     1768                fixEdge<Int52RepUse>(node->child1());
     1769            else
     1770                fixEdge<DoubleRepUse>(node->child1());
     1771            fixEdge<Int32Use>(node->child2());
    17611772            break;
    17621773        }
     
    22372248        }
    22382249
     2250        if (node->child1()->shouldSpeculateInt32()) {
     2251            fixEdge<Int32Use>(node->child1());
     2252            node->clearFlags(NodeMustGenerate);
     2253            return;
     2254        }
     2255
     2256        if (enableInt52() && node->child1()->shouldSpeculateAnyInt()) {
     2257            fixEdge<Int52RepUse>(node->child1());
     2258            node->clearFlags(NodeMustGenerate);
     2259            return;
     2260        }
     2261
     2262        if (node->child1()->shouldSpeculateNumber()) {
     2263            fixEdge<DoubleRepUse>(node->child1());
     2264            node->clearFlags(NodeMustGenerate);
     2265            return;
     2266        }
     2267
    22392268        // ToString(Symbol) throws an error. So if the child1 can include Symbols,
    22402269        // we need to care about it in the clobberize. In the following case,
  • trunk/Source/JavaScriptCore/dfg/DFGNodeType.h

    r213652 r214219  
    336336    macro(CallObjectConstructor, NodeResultJS) \
    337337    macro(CallStringConstructor, NodeResultJS | NodeMustGenerate) \
     338    macro(NumberToStringWithRadix, NodeResultJS | NodeMustGenerate) \
    338339    macro(NewStringObject, NodeResultJS) \
    339340    macro(MakeRope, NodeResultJS) \
  • trunk/Source/JavaScriptCore/dfg/DFGOperations.cpp

    r214071 r214219  
    16451645}
    16461646
     1647char* JIT_OPERATION operationInt32ToString(ExecState* exec, int32_t value, int32_t radix)
     1648{
     1649    VM& vm = exec->vm();
     1650    NativeCallFrameTracer tracer(&vm, exec);
     1651
     1652    auto scope = DECLARE_THROW_SCOPE(vm);
     1653
     1654    if (radix < 2 || radix > 36) {
     1655        throwVMError(exec, scope, createRangeError(exec, ASCIILiteral("toString() radix argument must be between 2 and 36")));
     1656        return nullptr;
     1657    }
     1658
     1659    return reinterpret_cast<char*>(int32ToString(vm, value, radix));
     1660}
     1661
     1662char* JIT_OPERATION operationInt52ToString(ExecState* exec, int64_t value, int32_t radix)
     1663{
     1664    VM& vm = exec->vm();
     1665    NativeCallFrameTracer tracer(&vm, exec);
     1666
     1667    auto scope = DECLARE_THROW_SCOPE(vm);
     1668
     1669    if (radix < 2 || radix > 36) {
     1670        throwVMError(exec, scope, createRangeError(exec, ASCIILiteral("toString() radix argument must be between 2 and 36")));
     1671        return nullptr;
     1672    }
     1673
     1674    return reinterpret_cast<char*>(int52ToString(vm, value, radix));
     1675}
     1676
     1677char* JIT_OPERATION operationDoubleToString(ExecState* exec, double value, int32_t radix)
     1678{
     1679    VM& vm = exec->vm();
     1680    NativeCallFrameTracer tracer(&vm, exec);
     1681
     1682    auto scope = DECLARE_THROW_SCOPE(vm);
     1683
     1684    if (radix < 2 || radix > 36) {
     1685        throwVMError(exec, scope, createRangeError(exec, ASCIILiteral("toString() radix argument must be between 2 and 36")));
     1686        return nullptr;
     1687    }
     1688
     1689    return reinterpret_cast<char*>(numberToString(vm, value, radix));
     1690}
     1691
     1692char* JIT_OPERATION operationInt32ToStringWithValidRadix(ExecState* exec, int32_t value, int32_t radix)
     1693{
     1694    VM& vm = exec->vm();
     1695    NativeCallFrameTracer tracer(&vm, exec);
     1696
     1697    return reinterpret_cast<char*>(int32ToString(vm, value, radix));
     1698}
     1699
     1700char* JIT_OPERATION operationInt52ToStringWithValidRadix(ExecState* exec, int64_t value, int32_t radix)
     1701{
     1702    VM& vm = exec->vm();
     1703    NativeCallFrameTracer tracer(&vm, exec);
     1704
     1705    return reinterpret_cast<char*>(int52ToString(vm, value, radix));
     1706}
     1707
     1708char* JIT_OPERATION operationDoubleToStringWithValidRadix(ExecState* exec, double value, int32_t radix)
     1709{
     1710    VM& vm = exec->vm();
     1711    NativeCallFrameTracer tracer(&vm, exec);
     1712
     1713    return reinterpret_cast<char*>(numberToString(vm, value, radix));
     1714}
     1715
    16471716JSString* JIT_OPERATION operationSingleCharacterString(ExecState* exec, int32_t character)
    16481717{
  • trunk/Source/JavaScriptCore/dfg/DFGOperations.h

    r212939 r214219  
    160160JSString* JIT_OPERATION operationToLowerCase(ExecState*, JSString*, uint32_t);
    161161
     162char* JIT_OPERATION operationInt32ToString(ExecState*, int32_t, int32_t);
     163char* JIT_OPERATION operationInt52ToString(ExecState*, int64_t, int32_t);
     164char* JIT_OPERATION operationDoubleToString(ExecState*, double, int32_t);
     165char* JIT_OPERATION operationInt32ToStringWithValidRadix(ExecState*, int32_t, int32_t);
     166char* JIT_OPERATION operationInt52ToStringWithValidRadix(ExecState*, int64_t, int32_t);
     167char* JIT_OPERATION operationDoubleToStringWithValidRadix(ExecState*, double, int32_t);
     168
    162169int32_t JIT_OPERATION operationMapHash(ExecState*, EncodedJSValue input);
    163170JSCell* JIT_OPERATION operationJSMapFindBucket(ExecState*, JSCell*, EncodedJSValue, int32_t);
  • trunk/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp

    r213107 r214219  
    898898        case CallStringConstructor:
    899899        case ToString:
     900        case NumberToStringWithRadix:
    900901        case MakeRope:
    901902        case StrCat: {
  • trunk/Source/JavaScriptCore/dfg/DFGSafeToExecute.h

    r213107 r214219  
    289289    case ToString:
    290290    case ToNumber:
     291    case NumberToStringWithRadix:
    291292    case SetFunctionName:
    292293    case StrCat:
  • trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp

    r214071 r214219  
    79247924}
    79257925
    7926 void SpeculativeJIT::compileToStringOrCallStringConstructorOnCell(Node* node)
    7927 {
    7928     if (node->child1().useKind() == NotCellUse) {
     7926void SpeculativeJIT::compileToStringOrCallStringConstructor(Node* node)
     7927{
     7928    switch (node->child1().useKind()) {
     7929    case NotCellUse: {
    79297930        JSValueOperand op1(this, node->child1(), ManualOperandSpeculation);
    79307931        JSValueRegs op1Regs = op1.jsValueRegs();
     
    79487949    }
    79497950
    7950     if (node->child1().useKind() == UntypedUse) {
     7951    case UntypedUse: {
    79517952        JSValueOperand op1(this, node->child1());
    79527953        JSValueRegs op1Regs = op1.jsValueRegs();
     
    79807981    }
    79817982
     7983    case Int32Use:
     7984    case Int52RepUse:
     7985    case DoubleRepUse:
     7986        compileToStringOrCallStringConstructorOnNumber(node);
     7987        return;
     7988
     7989    default:
     7990        break;
     7991    }
    79827992
    79837993    SpeculateCellOperand op1(this, node->child1());
     
    80508060    }
    80518061       
     8062    default:
     8063        RELEASE_ASSERT_NOT_REACHED();
     8064    }
     8065}
     8066
     8067void SpeculativeJIT::compileToStringOrCallStringConstructorOnNumber(Node* node)
     8068{
     8069    auto callToString = [&] (auto operation, GPRReg resultGPR, auto valueReg) {
     8070        flushRegisters();
     8071        callOperation(operation, resultGPR, valueReg, CCallHelpers::TrustedImm32(10));
     8072        m_jit.exceptionCheck();
     8073        cellResult(resultGPR, node);
     8074    };
     8075
     8076    switch (node->child1().useKind()) {
     8077    case Int32Use: {
     8078        SpeculateStrictInt32Operand value(this, node->child1());
     8079        GPRFlushedCallResult result(this);
     8080        callToString(operationInt32ToStringWithValidRadix, result.gpr(), value.gpr());
     8081        break;
     8082    }
     8083
     8084#if USE(JSVALUE64)
     8085    case Int52RepUse: {
     8086        SpeculateStrictInt52Operand value(this, node->child1());
     8087        GPRFlushedCallResult result(this);
     8088        callToString(operationInt52ToStringWithValidRadix, result.gpr(), value.gpr());
     8089        break;
     8090    }
     8091#endif
     8092
     8093    case DoubleRepUse: {
     8094        SpeculateDoubleOperand value(this, node->child1());
     8095        GPRFlushedCallResult result(this);
     8096        callToString(operationDoubleToStringWithValidRadix, result.gpr(), value.fpr());
     8097        break;
     8098    }
     8099
     8100    default:
     8101        RELEASE_ASSERT_NOT_REACHED();
     8102    }
     8103}
     8104
     8105void SpeculativeJIT::compileNumberToStringWithRadix(Node* node)
     8106{
     8107    bool validRadixIsGuaranteed = false;
     8108    if (node->child2()->isInt32Constant()) {
     8109        int32_t radix = node->child2()->asInt32();
     8110        if (radix >= 2 && radix <= 36)
     8111            validRadixIsGuaranteed = true;
     8112    }
     8113
     8114    auto callToString = [&] (auto operation, GPRReg resultGPR, auto valueReg, GPRReg radixGPR) {
     8115        flushRegisters();
     8116        callOperation(operation, resultGPR, valueReg, radixGPR);
     8117        m_jit.exceptionCheck();
     8118        cellResult(resultGPR, node);
     8119    };
     8120
     8121    switch (node->child1().useKind()) {
     8122    case Int32Use: {
     8123        SpeculateStrictInt32Operand value(this, node->child1());
     8124        SpeculateStrictInt32Operand radix(this, node->child2());
     8125        GPRFlushedCallResult result(this);
     8126        callToString(validRadixIsGuaranteed ? operationInt32ToStringWithValidRadix : operationInt32ToString, result.gpr(), value.gpr(), radix.gpr());
     8127        break;
     8128    }
     8129
     8130#if USE(JSVALUE64)
     8131    case Int52RepUse: {
     8132        SpeculateStrictInt52Operand value(this, node->child1());
     8133        SpeculateStrictInt32Operand radix(this, node->child2());
     8134        GPRFlushedCallResult result(this);
     8135        callToString(validRadixIsGuaranteed ? operationInt52ToStringWithValidRadix : operationInt52ToString, result.gpr(), value.gpr(), radix.gpr());
     8136        break;
     8137    }
     8138#endif
     8139
     8140    case DoubleRepUse: {
     8141        SpeculateDoubleOperand value(this, node->child1());
     8142        SpeculateStrictInt32Operand radix(this, node->child2());
     8143        GPRFlushedCallResult result(this);
     8144        callToString(validRadixIsGuaranteed ? operationDoubleToStringWithValidRadix : operationDoubleToString, result.gpr(), value.fpr(), radix.gpr());
     8145        break;
     8146    }
     8147
    80528148    default:
    80538149        RELEASE_ASSERT_NOT_REACHED();
  • trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h

    r214028 r214219  
    13821382    }
    13831383
     1384    JITCompiler::Call callOperation(P_JITOperation_EZZ operation, GPRReg result, GPRReg arg1, GPRReg arg2)
     1385    {
     1386        m_jit.setupArgumentsWithExecState(arg1, arg2);
     1387        return appendCallSetResult(operation, result);
     1388    }
     1389
     1390    JITCompiler::Call callOperation(P_JITOperation_EZZ operation, GPRReg result, GPRReg arg1, TrustedImm32 arg2)
     1391    {
     1392        m_jit.setupArgumentsWithExecState(arg1, arg2);
     1393        return appendCallSetResult(operation, result);
     1394    }
     1395
     1396    JITCompiler::Call callOperation(P_JITOperation_EDZ operation, GPRReg result, FPRReg arg1, GPRReg arg2)
     1397    {
     1398        m_jit.setupArgumentsWithExecState(arg1, arg2);
     1399        return appendCallSetResult(operation, result);
     1400    }
     1401
     1402    JITCompiler::Call callOperation(P_JITOperation_EDZ operation, GPRReg result, FPRReg arg1, TrustedImm32 arg2)
     1403    {
     1404        m_jit.setupArgumentsWithExecState(arg1, arg2);
     1405        return appendCallSetResult(operation, result);
     1406    }
    13841407
    13851408#if USE(JSVALUE64)
     
    16111634        return appendCallSetResult(operation, result);
    16121635    }
     1636    JITCompiler::Call callOperation(P_JITOperation_EQZ operation, GPRReg result, GPRReg arg1, GPRReg arg2)
     1637    {
     1638        m_jit.setupArgumentsWithExecState(arg1, arg2);
     1639        return appendCallSetResult(operation, result);
     1640    }
     1641    JITCompiler::Call callOperation(P_JITOperation_EQZ operation, GPRReg result, GPRReg arg1, TrustedImm32 arg2)
     1642    {
     1643        m_jit.setupArgumentsWithExecState(arg1, arg2);
     1644        return appendCallSetResult(operation, result);
     1645    }
     1646
    16131647    JITCompiler::Call callOperation(J_JITOperation_EZIcfZ operation, GPRReg result, int32_t arg1, InlineCallFrame* inlineCallFrame, GPRReg arg2)
    16141648    {
     
    26822716    void emitSwitch(Node*);
    26832717   
    2684     void compileToStringOrCallStringConstructorOnCell(Node*);
     2718    void compileToStringOrCallStringConstructor(Node*);
     2719    void compileToStringOrCallStringConstructorOnNumber(Node*);
     2720    void compileNumberToStringWithRadix(Node*);
    26852721    void compileNewStringObject(Node*);
    26862722   
  • trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp

    r214028 r214219  
    28362836    }
    28372837
     2838    case NumberToStringWithRadix: {
     2839        compileNumberToStringWithRadix(node);
     2840        break;
     2841    }
     2842
    28382843    case GetByValWithThis: {
    28392844        JSValueOperand base(this, node->child1());
     
    37703775    case ToString:
    37713776    case CallStringConstructor: {
    3772         compileToStringOrCallStringConstructorOnCell(node);
     3777        compileToStringOrCallStringConstructor(node);
    37733778        break;
    37743779    }
  • trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp

    r214028 r214219  
    37403740    case ToString:
    37413741    case CallStringConstructor: {
    3742         compileToStringOrCallStringConstructorOnCell(node);
     3742        compileToStringOrCallStringConstructor(node);
    37433743        break;
    37443744    }
     
    50585058    }
    50595059
     5060    case NumberToStringWithRadix: {
     5061        compileNumberToStringWithRadix(node);
     5062        break;
     5063    }
     5064
    50605065    case IsObject: {
    50615066        JSValueOperand value(this, node->child1());
  • trunk/Source/JavaScriptCore/dfg/DFGStrengthReductionPhase.cpp

    r211247 r214219  
    391391        }
    392392
     393        case ToString:
     394        case CallStringConstructor: {
     395            Edge& child1 = m_node->child1();
     396            switch (child1.useKind()) {
     397            case Int32Use:
     398            case Int52RepUse:
     399            case DoubleRepUse: {
     400                if (child1->hasConstant()) {
     401                    JSValue value = child1->constant()->value();
     402                    if (value) {
     403                        String result;
     404                        if (value.isInt32())
     405                            result = String::number(value.asInt32());
     406                        else if (value.isNumber())
     407                            result = String::numberToStringECMAScript(value.asNumber());
     408
     409                        if (!result.isNull()) {
     410                            m_node->convertToLazyJSConstant(m_graph, LazyJSValue::newString(m_graph, result));
     411                            m_changed = true;
     412                        }
     413                    }
     414                }
     415                break;
     416            }
     417
     418            default:
     419                break;
     420            }
     421            break;
     422        }
     423
    393424        case GetArrayLength: {
    394425            if (m_node->arrayMode().type() == Array::Generic
  • trunk/Source/JavaScriptCore/ftl/FTLCapabilities.cpp

    r214069 r214219  
    280280    case DefineAccessorProperty:
    281281    case ToLowerCase:
     282    case NumberToStringWithRadix:
    282283    case CheckDOM:
    283284    case CallDOM:
  • trunk/Source/JavaScriptCore/ftl/FTLLowerDFGToB3.cpp

    r214071 r214219  
    10791079            compileToLowerCase();
    10801080            break;
     1081        case NumberToStringWithRadix:
     1082            compileNumberToStringWithRadix();
     1083            break;
    10811084        case CheckDOM:
    10821085            compileCheckDOM();
     
    49824985            return;
    49834986        }
     4987
     4988        case Int32Use:
     4989            setJSValue(vmCall(Int64, m_out.operation(operationInt32ToStringWithValidRadix), m_callFrame, lowInt32(m_node->child1()), m_out.constInt32(10)));
     4990            return;
     4991
     4992        case Int52RepUse:
     4993            setJSValue(vmCall(Int64, m_out.operation(operationInt52ToStringWithValidRadix), m_callFrame, lowStrictInt52(m_node->child1()), m_out.constInt32(10)));
     4994            return;
     4995
     4996        case DoubleRepUse:
     4997            setJSValue(vmCall(Int64, m_out.operation(operationDoubleToStringWithValidRadix), m_callFrame, lowDouble(m_node->child1()), m_out.constInt32(10)));
     4998            return;
    49844999           
    49855000        default:
     
    99839998        m_out.appendTo(continuation, lastNext);
    99849999        setJSValue(m_out.phi(pointerType(), fastResult, slowResult));
     10000    }
     10001
     10002    void compileNumberToStringWithRadix()
     10003    {
     10004        bool validRadixIsGuaranteed = false;
     10005        if (m_node->child2()->isInt32Constant()) {
     10006            int32_t radix = m_node->child2()->asInt32();
     10007            if (radix >= 2 && radix <= 36)
     10008                validRadixIsGuaranteed = true;
     10009        }
     10010
     10011        switch (m_node->child1().useKind()) {
     10012        case Int32Use:
     10013            setJSValue(vmCall(pointerType(), m_out.operation(validRadixIsGuaranteed ? operationInt32ToStringWithValidRadix : operationInt32ToString), m_callFrame, lowInt32(m_node->child1()), lowInt32(m_node->child2())));
     10014            break;
     10015        case Int52RepUse:
     10016            setJSValue(vmCall(pointerType(), m_out.operation(validRadixIsGuaranteed ? operationInt52ToStringWithValidRadix : operationInt52ToString), m_callFrame, lowStrictInt52(m_node->child1()), lowInt32(m_node->child2())));
     10017            break;
     10018        case DoubleRepUse:
     10019            setJSValue(vmCall(pointerType(), m_out.operation(validRadixIsGuaranteed ? operationDoubleToStringWithValidRadix : operationDoubleToString), m_callFrame, lowDouble(m_node->child1()), lowInt32(m_node->child2())));
     10020            break;
     10021        default:
     10022            RELEASE_ASSERT_NOT_REACHED();
     10023        }
    998510024    }
    998610025
  • trunk/Source/JavaScriptCore/jit/CCallHelpers.h

    r213467 r214219  
    886886
    887887    ALWAYS_INLINE void setupArgumentsWithExecState(FPRReg arg1, GPRReg arg2)
     888    {
     889        resetCallArguments();
     890        addCallArgument(GPRInfo::callFrameRegister);
     891        addCallArgument(arg1);
     892        addCallArgument(arg2);
     893    }
     894
     895    ALWAYS_INLINE void setupArgumentsWithExecState(FPRReg arg1, TrustedImm32 arg2)
    888896    {
    889897        resetCallArguments();
     
    10941102    }
    10951103
     1104    ALWAYS_INLINE void setupArgumentsWithExecState(FPRReg arg1, TrustedImm32 arg2)
     1105    {
     1106#if OS(WINDOWS) && CPU(X86_64)
     1107        // On Windows, arguments map to designated registers based on the argument positions, even when there are interlaced scalar and floating point arguments.
     1108        // See http://msdn.microsoft.com/en-us/library/zthk2dkh.aspx
     1109        moveDouble(arg1, FPRInfo::argumentFPR1);
     1110        move(arg2, GPRInfo::argumentGPR2);
     1111#else
     1112        moveDouble(arg1, FPRInfo::argumentFPR0);
     1113        move(arg2, GPRInfo::argumentGPR1);
     1114#endif
     1115        move(GPRInfo::callFrameRegister, GPRInfo::argumentGPR0);
     1116    }
     1117
    10961118    ALWAYS_INLINE void setupArgumentsWithExecState(GPRReg arg1, GPRReg arg2, FPRReg arg3)
    10971119    {
     
    11361158    }
    11371159
     1160    ALWAYS_INLINE void setupArgumentsWithExecState(FPRReg arg1, TrustedImm32 arg2)
     1161    {
     1162        moveDouble(arg1, FPRInfo::argumentFPR0);
     1163        move(arg2, GPRInfo::argumentGPR1);
     1164        move(GPRInfo::callFrameRegister, GPRInfo::argumentGPR0);
     1165    }
     1166
    11381167    ALWAYS_INLINE void setupArgumentsWithExecState(GPRReg arg1, GPRReg arg2, FPRReg arg3)
    11391168    {
     
    11701199
    11711200    ALWAYS_INLINE void setupArgumentsWithExecState(FPRReg arg1, GPRReg arg2)
     1201    {
     1202        move(arg2, GPRInfo::argumentGPR3);
     1203        assembler().vmov(GPRInfo::argumentGPR1, GPRInfo::argumentGPR2, arg1);
     1204        move(GPRInfo::callFrameRegister, GPRInfo::argumentGPR0);
     1205    }
     1206
     1207    ALWAYS_INLINE void setupArgumentsWithExecState(FPRReg arg1, TrustedImm32 arg2)
    11721208    {
    11731209        move(arg2, GPRInfo::argumentGPR3);
     
    12231259
    12241260    ALWAYS_INLINE void setupArgumentsWithExecState(FPRReg arg1, GPRReg arg2)
     1261    {
     1262        assembler().vmov(GPRInfo::argumentGPR2, GPRInfo::argumentGPR3, arg1);
     1263        move(GPRInfo::callFrameRegister, GPRInfo::argumentGPR0);
     1264        poke(arg2, 4);
     1265    }
     1266
     1267    ALWAYS_INLINE void setupArgumentsWithExecState(FPRReg arg1, TrustedImm32 arg2)
    12251268    {
    12261269        assembler().vmov(GPRInfo::argumentGPR2, GPRInfo::argumentGPR3, arg1);
  • trunk/Source/JavaScriptCore/jit/JITOperations.h

    r213467 r214219  
    313313typedef char* (JIT_OPERATION *P_JITOperation_EStZP)(ExecState*, Structure*, int32_t, char*);
    314314typedef char* (JIT_OPERATION *P_JITOperation_EZZ)(ExecState*, int32_t, int32_t);
     315typedef char* (JIT_OPERATION *P_JITOperation_EQZ)(ExecState*, int64_t, int32_t);
     316typedef char* (JIT_OPERATION *P_JITOperation_EDZ)(ExecState*, double, int32_t);
    315317typedef SlowPathReturnType (JIT_OPERATION *Sprt_JITOperation_ECli)(ExecState*, CallLinkInfo*);
    316318typedef StringImpl* (JIT_OPERATION *T_JITOperation_EJss)(ExecState*, JSString*);
  • trunk/Source/JavaScriptCore/runtime/Intrinsic.h

    r212939 r214219  
    5757    StringPrototypeReplaceIntrinsic,
    5858    StringPrototypeReplaceRegExpIntrinsic,
     59    StringPrototypeToLowerCaseIntrinsic,
     60    NumberPrototypeToStringIntrinsic,
    5961    IMulIntrinsic,
    6062    RandomIntrinsic,
     
    7981    AtomicsWakeIntrinsic,
    8082    AtomicsXorIntrinsic,
    81     ToLowerCaseIntrinsic,
    8283    ParseIntIntrinsic,
    8384
  • trunk/Source/JavaScriptCore/runtime/NumberPrototype.cpp

    r211247 r214219  
    5959/* Source for NumberPrototype.lut.h
    6060@begin numberPrototypeTable
    61   toString          numberProtoFuncToString         DontEnum|Function 1
     61  toString          numberProtoFuncToString         DontEnum|Function 1 NumberPrototypeToStringIntrinsic
    6262  toLocaleString    numberProtoFuncToLocaleString   DontEnum|Function 0
    6363  valueOf           numberProtoFuncValueOf          DontEnum|Function 0
     
    145145static const char radixDigits[] = "0123456789abcdefghijklmnopqrstuvwxyz";
    146146
    147 static char* int52ToStringWithRadix(char* startOfResultString, int64_t int52Value, unsigned radix)
     147static inline char* int52ToStringWithRadix(char* startOfResultString, int64_t int52Value, unsigned radix)
    148148{
    149149    bool negative = false;
     
    500500}
    501501
    502 static inline EncodedJSValue integerValueToString(ExecState* exec, int32_t radix, int32_t value)
    503 {
     502static inline JSString* int32ToStringInternal(VM& vm, int32_t value, int32_t radix)
     503{
     504    ASSERT(!(radix < 2 || radix > 36));
    504505    // A negative value casted to unsigned would be bigger than 36 (the max radix).
    505506    if (static_cast<unsigned>(value) < static_cast<unsigned>(radix)) {
    506507        ASSERT(value <= 36);
    507508        ASSERT(value >= 0);
    508         VM* vm = &exec->vm();
    509         return JSValue::encode(vm->smallStrings.singleCharacterString(radixDigits[value]));
     509        return vm.smallStrings.singleCharacterString(radixDigits[value]);
    510510    }
    511511
    512512    if (radix == 10) {
    513         VM* vm = &exec->vm();
    514         return JSValue::encode(jsString(vm, vm->numericStrings.add(value)));
    515     }
    516 
    517     return JSValue::encode(jsString(exec, toStringWithRadix(value, radix)));
    518 
     513        return jsString(&vm, vm.numericStrings.add(value));
     514    }
     515
     516    return jsString(&vm, toStringWithRadix(value, radix));
     517
     518}
     519
     520static ALWAYS_INLINE JSString* numberToStringInternal(VM& vm, double doubleValue, int32_t radix)
     521{
     522    ASSERT(!(radix < 2 || radix > 36));
     523
     524    int32_t integerValue = static_cast<int32_t>(doubleValue);
     525    if (integerValue == doubleValue)
     526        return int32ToStringInternal(vm, integerValue, radix);
     527
     528    if (radix == 10)
     529        return jsString(&vm, vm.numericStrings.add(doubleValue));
     530
     531    if (!std::isfinite(doubleValue))
     532        return jsNontrivialString(&vm, String::numberToStringECMAScript(doubleValue));
     533
     534    RadixBuffer buffer;
     535    return jsString(&vm, toStringWithRadix(buffer, doubleValue, radix));
     536}
     537
     538JSString* int32ToString(VM& vm, int32_t value, int32_t radix)
     539{
     540    return int32ToStringInternal(vm, value, radix);
     541}
     542
     543JSString* int52ToString(VM& vm, int64_t value, int32_t radix)
     544{
     545    ASSERT(!(radix < 2 || radix > 36));
     546    if (radix == 10)
     547        return jsString(&vm, vm.numericStrings.add(static_cast<double>(value)));
     548
     549    // Position the decimal point at the center of the string, set
     550    // the startOfResultString pointer to point at the decimal point.
     551    RadixBuffer buffer;
     552    char* decimalPoint = buffer + sizeof(buffer) / 2;
     553    char* startOfResultString = decimalPoint;
     554    *decimalPoint = '\0';
     555
     556    return jsString(&vm, int52ToStringWithRadix(startOfResultString, value, radix));
     557}
     558
     559JSString* numberToString(VM& vm, double doubleValue, int32_t radix)
     560{
     561    return numberToStringInternal(vm, doubleValue, radix);
    519562}
    520563
     
    532575        return throwVMError(exec, scope, createRangeError(exec, ASCIILiteral("toString() radix argument must be between 2 and 36")));
    533576
    534     int32_t integerValue = static_cast<int32_t>(doubleValue);
    535     if (integerValue == doubleValue)
    536         return integerValueToString(exec, radix, integerValue);
    537 
    538     if (radix == 10)
    539         return JSValue::encode(jsString(&vm, vm.numericStrings.add(doubleValue)));
    540 
    541     if (!std::isfinite(doubleValue))
    542         return JSValue::encode(jsNontrivialString(exec, String::numberToStringECMAScript(doubleValue)));
    543 
    544     RadixBuffer s;
    545     return JSValue::encode(jsString(exec, toStringWithRadix(s, doubleValue, radix)));
     577    return JSValue::encode(numberToStringInternal(vm, doubleValue, radix));
    546578}
    547579
  • trunk/Source/JavaScriptCore/runtime/NumberPrototype.h

    r206525 r214219  
    5252
    5353EncodedJSValue JSC_HOST_CALL numberProtoFuncValueOf(ExecState*);
     54JSString* int32ToString(VM&, int32_t value, int32_t radix);
     55JSString* int52ToString(VM&, int64_t value, int32_t radix);
     56JSString* numberToString(VM&, double value, int32_t radix);
    5457
    5558} // namespace JSC
  • trunk/Source/JavaScriptCore/runtime/StringPrototype.cpp

    r212939 r214219  
    143143    JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION("substr", stringProtoFuncSubstr, DontEnum, 2);
    144144    JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION("substring", stringProtoFuncSubstring, DontEnum, 2);
    145     JSC_NATIVE_INTRINSIC_FUNCTION_WITHOUT_TRANSITION("toLowerCase", stringProtoFuncToLowerCase, DontEnum, 0, ToLowerCaseIntrinsic);
     145    JSC_NATIVE_INTRINSIC_FUNCTION_WITHOUT_TRANSITION("toLowerCase", stringProtoFuncToLowerCase, DontEnum, 0, StringPrototypeToLowerCaseIntrinsic);
    146146    JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION("toUpperCase", stringProtoFuncToUpperCase, DontEnum, 0);
    147147#if ENABLE(INTL)
Note: See TracChangeset for help on using the changeset viewer.