Changeset 212939 in webkit


Ignore:
Timestamp:
Feb 23, 2017 8:07:30 PM (7 years ago)
Author:
sbarati@apple.com
Message:

Intrinsicify parseInt
https://bugs.webkit.org/show_bug.cgi?id=168627

Reviewed by Filip Pizlo.

JSTests:

  • stress/parse-int-intrinsic.js: Added.

(assert):
(testIntrinsic.let.s):
(testIntrinsic):
(testIntrinsic2.baz):
(testIntrinsic2):
(testIntrinsic3.foo):
(testIntrinsic3):
(testIntrinsic4.foo):
(testIntrinsic4):
(testIntrinsic5.foo):
(testIntrinsic5):
(testIntrinsic6.foo):
(testIntrinsic6):
(testIntrinsic7.foo):
(testIntrinsic7):

Source/JavaScriptCore:

This patch makes parseInt an intrinsic in the DFG and FTL.
We do our best to eliminate this node. If we speculate that
the first operand to the operation is an int32, and that there
isn't a second operand, we convert to the identity of the first
operand. That's because parseInt(someInt) === someInt.

If the first operand is proven to be an integer, and the second
operand is the integer 0 or the integer 10, we can eliminate the
node by making it an identity over its first operand. That's
because parseInt(someInt, 0) === someInt and parseInt(someInt, 10) === someInt.

If we are not able to constant fold the node away, we try to remove
checks. The most common use case of parseInt is that its first operand
is a proven string. The DFG might be able to remove type checks in this
case. We also set up CSE rules for parseInt(someString, someIntRadix)
because it's a "pure" operation (modulo resolving a rope).

This looks to be a 4% Octane/Box2D progression.

  • dfg/DFGAbstractInterpreterInlines.h:

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

  • dfg/DFGByteCodeParser.cpp:

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

  • dfg/DFGClobberize.h:

(JSC::DFG::clobberize):

  • dfg/DFGConstantFoldingPhase.cpp:

(JSC::DFG::ConstantFoldingPhase::foldConstants):

  • dfg/DFGDoesGC.cpp:

(JSC::DFG::doesGC):

  • dfg/DFGFixupPhase.cpp:

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

  • dfg/DFGNode.h:

(JSC::DFG::Node::hasHeapPrediction):

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

(JSC::DFG::parseIntResult):

  • dfg/DFGOperations.h:
  • dfg/DFGPredictionPropagationPhase.cpp:
  • dfg/DFGSafeToExecute.h:

(JSC::DFG::safeToExecute):

  • dfg/DFGSpeculativeJIT.cpp:

(JSC::DFG::SpeculativeJIT::compileParseInt):

  • dfg/DFGSpeculativeJIT.h:

(JSC::DFG::SpeculativeJIT::callOperation):
(JSC::DFG::SpeculativeJIT::appendCallSetResult):

  • 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::compileParseInt):

  • jit/JITOperations.h:
  • parser/Lexer.cpp:
  • runtime/ErrorInstance.cpp:
  • runtime/Intrinsic.h:
  • runtime/JSGlobalObject.cpp:

(JSC::JSGlobalObject::init):

  • runtime/JSGlobalObjectFunctions.cpp:

(JSC::toStringView): Deleted.
(JSC::isStrWhiteSpace): Deleted.
(JSC::parseDigit): Deleted.
(JSC::parseIntOverflow): Deleted.
(JSC::parseInt): Deleted.

  • runtime/JSGlobalObjectFunctions.h:
  • runtime/ParseInt.h: Added.

(JSC::parseDigit):
(JSC::parseIntOverflow):
(JSC::isStrWhiteSpace):
(JSC::parseInt):
(JSC::toStringView):

  • runtime/StringPrototype.cpp:
Location:
trunk
Files:
2 added
28 edited

Legend:

Unmodified
Added
Removed
  • trunk/JSTests/ChangeLog

    r212922 r212939  
     12017-02-23  Saam Barati  <sbarati@apple.com>
     2
     3        Intrinsicify parseInt
     4        https://bugs.webkit.org/show_bug.cgi?id=168627
     5
     6        Reviewed by Filip Pizlo.
     7
     8        * stress/parse-int-intrinsic.js: Added.
     9        (assert):
     10        (testIntrinsic.let.s):
     11        (testIntrinsic):
     12        (testIntrinsic2.baz):
     13        (testIntrinsic2):
     14        (testIntrinsic3.foo):
     15        (testIntrinsic3):
     16        (testIntrinsic4.foo):
     17        (testIntrinsic4):
     18        (testIntrinsic5.foo):
     19        (testIntrinsic5):
     20        (testIntrinsic6.foo):
     21        (testIntrinsic6):
     22        (testIntrinsic7.foo):
     23        (testIntrinsic7):
     24
    1252017-02-23  JF Bastien  <jfbastien@apple.com>
    226
  • trunk/Source/JavaScriptCore/ChangeLog

    r212922 r212939  
     12017-02-23  Saam Barati  <sbarati@apple.com>
     2
     3        Intrinsicify parseInt
     4        https://bugs.webkit.org/show_bug.cgi?id=168627
     5
     6        Reviewed by Filip Pizlo.
     7
     8        This patch makes parseInt an intrinsic in the DFG and FTL.
     9        We do our best to eliminate this node. If we speculate that
     10        the first operand to the operation is an int32, and that there
     11        isn't a second operand, we convert to the identity of the first
     12        operand. That's because parseInt(someInt) === someInt.
     13       
     14        If the first operand is proven to be an integer, and the second
     15        operand is the integer 0 or the integer 10, we can eliminate the
     16        node by making it an identity over its first operand. That's
     17        because parseInt(someInt, 0) === someInt and parseInt(someInt, 10) === someInt.
     18       
     19        If we are not able to constant fold the node away, we try to remove
     20        checks. The most common use case of parseInt is that its first operand
     21        is a proven string. The DFG might be able to remove type checks in this
     22        case. We also set up CSE rules for parseInt(someString, someIntRadix)
     23        because it's a "pure" operation (modulo resolving a rope).
     24
     25        This looks to be a 4% Octane/Box2D progression.
     26
     27        * dfg/DFGAbstractInterpreterInlines.h:
     28        (JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects):
     29        * dfg/DFGByteCodeParser.cpp:
     30        (JSC::DFG::ByteCodeParser::handleIntrinsicCall):
     31        * dfg/DFGClobberize.h:
     32        (JSC::DFG::clobberize):
     33        * dfg/DFGConstantFoldingPhase.cpp:
     34        (JSC::DFG::ConstantFoldingPhase::foldConstants):
     35        * dfg/DFGDoesGC.cpp:
     36        (JSC::DFG::doesGC):
     37        * dfg/DFGFixupPhase.cpp:
     38        (JSC::DFG::FixupPhase::fixupNode):
     39        * dfg/DFGNode.h:
     40        (JSC::DFG::Node::hasHeapPrediction):
     41        * dfg/DFGNodeType.h:
     42        * dfg/DFGOperations.cpp:
     43        (JSC::DFG::parseIntResult):
     44        * dfg/DFGOperations.h:
     45        * dfg/DFGPredictionPropagationPhase.cpp:
     46        * dfg/DFGSafeToExecute.h:
     47        (JSC::DFG::safeToExecute):
     48        * dfg/DFGSpeculativeJIT.cpp:
     49        (JSC::DFG::SpeculativeJIT::compileParseInt):
     50        * dfg/DFGSpeculativeJIT.h:
     51        (JSC::DFG::SpeculativeJIT::callOperation):
     52        (JSC::DFG::SpeculativeJIT::appendCallSetResult):
     53        * dfg/DFGSpeculativeJIT32_64.cpp:
     54        (JSC::DFG::SpeculativeJIT::compile):
     55        * dfg/DFGSpeculativeJIT64.cpp:
     56        (JSC::DFG::SpeculativeJIT::compile):
     57        * ftl/FTLCapabilities.cpp:
     58        (JSC::FTL::canCompile):
     59        * ftl/FTLLowerDFGToB3.cpp:
     60        (JSC::FTL::DFG::LowerDFGToB3::compileNode):
     61        (JSC::FTL::DFG::LowerDFGToB3::compileParseInt):
     62        * jit/JITOperations.h:
     63        * parser/Lexer.cpp:
     64        * runtime/ErrorInstance.cpp:
     65        * runtime/Intrinsic.h:
     66        * runtime/JSGlobalObject.cpp:
     67        (JSC::JSGlobalObject::init):
     68        * runtime/JSGlobalObjectFunctions.cpp:
     69        (JSC::toStringView): Deleted.
     70        (JSC::isStrWhiteSpace): Deleted.
     71        (JSC::parseDigit): Deleted.
     72        (JSC::parseIntOverflow): Deleted.
     73        (JSC::parseInt): Deleted.
     74        * runtime/JSGlobalObjectFunctions.h:
     75        * runtime/ParseInt.h: Added.
     76        (JSC::parseDigit):
     77        (JSC::parseIntOverflow):
     78        (JSC::isStrWhiteSpace):
     79        (JSC::parseInt):
     80        (JSC::toStringView):
     81        * runtime/StringPrototype.cpp:
     82
    1832017-02-23  JF Bastien  <jfbastien@apple.com>
    284
  • trunk/Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h

    r211463 r212939  
    29292929        break;
    29302930
     2931    case ParseInt: {
     2932        AbstractValue value = forNode(node->child1());
     2933        if (value.m_type && !(value.m_type & ~SpecInt32Only)) {
     2934            JSValue radix;
     2935            if (!node->child2())
     2936                radix = jsNumber(0);
     2937            else
     2938                radix = forNode(node->child2()).m_value;
     2939
     2940            if (radix.isNumber()
     2941                && (radix.asNumber() == 0 || radix.asNumber() == 10)) {
     2942                m_state.setFoundConstants(true);
     2943                forNode(node).setType(SpecInt32Only);
     2944                break;
     2945            }
     2946        }
     2947
     2948        if (node->child1().useKind() == UntypedUse)
     2949            clobberWorld(node->origin.semantic, clobberLimit);
     2950        forNode(node).setType(m_graph, SpecBytecodeNumber);
     2951        break;
     2952    }
     2953
    29312954    case CreateRest:
    29322955        if (!m_graph.isWatchingHavingABadTimeWatchpoint(node)) {
  • trunk/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp

    r212818 r212939  
    23592359            return false;
    23602360        }
     2361    }
     2362
     2363    case ParseIntIntrinsic: {
     2364        if (argumentCountIncludingThis < 2)
     2365            return false;
     2366
     2367        if (m_inlineStackTop->m_exitProfile.hasExitSite(m_currentIndex, BadCell) || m_inlineStackTop->m_exitProfile.hasExitSite(m_currentIndex, BadType))
     2368            return false;
     2369
     2370        insertChecks();
     2371        VirtualRegister valueOperand = virtualRegisterForArgument(1, registerOffset);
     2372        Node* parseInt;
     2373        if (argumentCountIncludingThis == 2)
     2374            parseInt = addToGraph(ParseInt, OpInfo(), OpInfo(prediction), get(valueOperand));
     2375        else {
     2376            ASSERT(argumentCountIncludingThis > 2);
     2377            VirtualRegister radixOperand = virtualRegisterForArgument(2, registerOffset);
     2378            parseInt = addToGraph(ParseInt, OpInfo(), OpInfo(prediction), get(valueOperand), get(radixOperand));
     2379        }
     2380        set(VirtualRegister(resultOperand), parseInt);
     2381        return true;
    23612382    }
    23622383
  • trunk/Source/JavaScriptCore/dfg/DFGClobberize.h

    r210695 r212939  
    889889        return;
    890890
     891    case ParseInt:
     892        // Note: We would have eliminated a ParseInt that has just a single child as an Int32Use inside fixup.
     893        if (node->child1().useKind() == StringUse && (!node->child2() || node->child2().useKind() == Int32Use)) {
     894            def(PureValue(node));
     895            return;
     896        }
     897
     898        read(World);
     899        write(Heap);
     900        return;
     901
    891902    case OverridesHasInstance:
    892903        read(JSCell_typeInfoFlags);
  • trunk/Source/JavaScriptCore/dfg/DFGConstantFoldingPhase.cpp

    r211247 r212939  
    603603            }
    604604
     605            case ParseInt: {
     606                AbstractValue& value = m_state.forNode(node->child1());
     607                if (!value.m_type || (value.m_type & ~SpecInt32Only))
     608                    break;
     609
     610                JSValue radix;
     611                if (!node->child2())
     612                    radix = jsNumber(0);
     613                else
     614                    radix = m_state.forNode(node->child2()).m_value;
     615
     616                if (!radix.isNumber())
     617                    break;
     618
     619                if (radix.asNumber() == 0 || radix.asNumber() == 10) {
     620                    node->child2() = Edge();
     621                    node->convertToIdentity();
     622                    changed = true;
     623                }
     624
     625                break;
     626            }
     627
    605628            case Check: {
    606629                alreadyHandled = true;
  • trunk/Source/JavaScriptCore/dfg/DFGDoesGC.cpp

    r210695 r212939  
    311311    case CallDOM:
    312312    case ArraySlice:
     313    case ParseInt: // We might resolve a rope even though we don't clobber anything.
    313314        return true;
    314315       
  • trunk/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp

    r211908 r212939  
    17911791        case Call: {
    17921792            attemptToMakeCallDOM(node);
     1793            break;
     1794        }
     1795
     1796        case ParseInt: {
     1797            if (node->child1()->shouldSpeculateInt32() && !node->child2()) {
     1798                fixEdge<Int32Use>(node->child1());
     1799                node->convertToIdentity();
     1800                break;
     1801            }
     1802
     1803            if (node->child1()->shouldSpeculateString()) {
     1804                fixEdge<StringUse>(node->child1());
     1805                node->clearFlags(NodeMustGenerate);
     1806            }
     1807
     1808            if (node->child2())
     1809                fixEdge<Int32Use>(node->child2());
     1810
    17931811            break;
    17941812        }
  • trunk/Source/JavaScriptCore/dfg/DFGNode.h

    r211908 r212939  
    14851485        case CallDOMGetter:
    14861486        case CallDOM:
     1487        case ParseInt:
    14871488            return true;
    14881489        default:
  • trunk/Source/JavaScriptCore/dfg/DFGNodeType.h

    r210695 r212939  
    245245    macro(CheckStringIdent, NodeMustGenerate) \
    246246    macro(CheckTypeInfoFlags, NodeMustGenerate) /* Takes an OpInfo with the flags you want to test are set */\
     247    macro(ParseInt, NodeMustGenerate | NodeResultJS) \
    247248    \
    248249    /* Optimizations for array mutation. */\
  • trunk/Source/JavaScriptCore/dfg/DFGOperations.cpp

    r211658 r212939  
    5757#include "ObjectConstructor.h"
    5858#include "Operations.h"
     59#include "ParseInt.h"
    5960#include "RegExpObject.h"
    6061#include "Repatch.h"
     
    173174    PutPropertySlot slot(thisVal, strict);
    174175    baseValue.putInline(exec, ident, putValue, slot);
     176}
     177
     178static ALWAYS_INLINE EncodedJSValue parseIntResult(double input)
     179{
     180    int asInt = static_cast<int>(input);
     181    if (static_cast<double>(asInt) == input)
     182        return JSValue::encode(jsNumber(asInt));
     183    return JSValue::encode(jsNumber(input));
    175184}
    176185
     
    849858    return JSValue::encode(asRegExpObject(base)->exec(exec, globalObject, input));
    850859}
     860
     861EncodedJSValue JIT_OPERATION operationParseIntNoRadixGeneric(ExecState* exec, EncodedJSValue value)
     862{
     863    VM& vm = exec->vm();
     864    NativeCallFrameTracer tracer(&vm, exec);
     865
     866    return toStringView(exec, JSValue::decode(value), [&] (StringView view) {
     867        // This version is as if radix was undefined. Hence, undefined.toNumber() === 0.
     868        return parseIntResult(parseInt(view, 0));
     869    });
     870}
     871
     872EncodedJSValue JIT_OPERATION operationParseIntStringNoRadix(ExecState* exec, JSString* string)
     873{
     874    VM& vm = exec->vm();
     875    NativeCallFrameTracer tracer(&vm, exec);
     876    auto scope = DECLARE_THROW_SCOPE(vm);
     877
     878    auto viewWithString = string->viewWithUnderlyingString(*exec);
     879    RETURN_IF_EXCEPTION(scope, { });
     880
     881    // This version is as if radix was undefined. Hence, undefined.toNumber() === 0.
     882    return parseIntResult(parseInt(viewWithString.view, 0));
     883}
     884
     885EncodedJSValue JIT_OPERATION operationParseIntString(ExecState* exec, JSString* string, int32_t radix)
     886{
     887    VM& vm = exec->vm();
     888    NativeCallFrameTracer tracer(&vm, exec);
     889    auto scope = DECLARE_THROW_SCOPE(vm);
     890
     891    auto viewWithString = string->viewWithUnderlyingString(*exec);
     892    RETURN_IF_EXCEPTION(scope, { });
     893
     894    // This version is as if radix was undefined. Hence, undefined.toNumber() === 0.
     895    return parseIntResult(parseInt(viewWithString.view, radix));
     896}
     897
     898EncodedJSValue JIT_OPERATION operationParseIntGeneric(ExecState* exec, EncodedJSValue value, int32_t radix)
     899{
     900    VM& vm = exec->vm();
     901    NativeCallFrameTracer tracer(&vm, exec);
     902
     903    return toStringView(exec, JSValue::decode(value), [&] (StringView view) {
     904        return parseIntResult(parseInt(view, radix));
     905    });
     906}
    851907       
    852908size_t JIT_OPERATION operationRegExpTestString(ExecState* exec, JSGlobalObject* globalObject, RegExpObject* regExpObject, JSString* input)
  • trunk/Source/JavaScriptCore/dfg/DFGOperations.h

    r211245 r212939  
    164164JSCell* JIT_OPERATION operationJSSetFindBucket(ExecState*, JSCell*, EncodedJSValue, int32_t);
    165165
     166EncodedJSValue JIT_OPERATION operationParseIntNoRadixGeneric(ExecState*, EncodedJSValue);
     167EncodedJSValue JIT_OPERATION operationParseIntStringNoRadix(ExecState*, JSString*);
     168EncodedJSValue JIT_OPERATION operationParseIntString(ExecState*, JSString*, int32_t);
     169EncodedJSValue JIT_OPERATION operationParseIntGeneric(ExecState*, EncodedJSValue, int32_t);
     170
    166171JSCell* JIT_OPERATION operationNewStringObject(ExecState*, JSString*, Structure*);
    167172JSCell* JIT_OPERATION operationToStringOnCell(ExecState*, JSCell*);
  • trunk/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp

    r210695 r212939  
    965965        case ToIndexString: {
    966966            setPrediction(SpecString);
     967            break;
     968        }
     969        case ParseInt: {
     970            // We expect this node to almost always produce an int32. However,
     971            // it's possible it produces NaN or integers out of int32 range. We
     972            // rely on the heap prediction since the parseInt() call profiled
     973            // its result.
     974            setPrediction(m_currentNode->getHeapPrediction());
    967975            break;
    968976        }
  • trunk/Source/JavaScriptCore/dfg/DFGSafeToExecute.h

    r211247 r212939  
    270270    case ProfileControlFlow:
    271271    case CheckTypeInfoFlags:
     272    case ParseInt:
    272273    case OverridesHasInstance:
    273274    case InstanceOf:
  • trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp

    r212909 r212939  
    31193119
    31203120    noResult(node);
     3121}
     3122
     3123void SpeculativeJIT::compileParseInt(Node* node)
     3124{
     3125    RELEASE_ASSERT(node->child1().useKind() == UntypedUse || node->child1().useKind() == StringUse);
     3126
     3127    GPRFlushedCallResult resultPayload(this);
     3128    GPRReg resultPayloadGPR = resultPayload.gpr();
     3129#if USE(JSVALUE64)
     3130    JSValueRegs resultRegs(resultPayloadGPR);
     3131#else
     3132    GPRFlushedCallResult2 resultTag(this);
     3133    GPRReg resultTagGPR = resultTag.gpr();
     3134    JSValueRegs resultRegs(resultTagGPR, resultPayloadGPR);
     3135#endif
     3136
     3137    if (node->child2()) {
     3138        SpeculateInt32Operand radix(this, node->child2());
     3139        GPRReg radixGPR = radix.gpr();
     3140        if (node->child1().useKind() == UntypedUse) {
     3141            JSValueOperand value(this, node->child1());
     3142
     3143            flushRegisters();
     3144#if USE(JSVALUE64)
     3145            callOperation(operationParseIntGeneric, resultRegs.gpr(), value.gpr(), radixGPR);
     3146#else
     3147            callOperation(operationParseIntGeneric, resultRegs, value.jsValueRegs(), radixGPR);
     3148#endif
     3149            m_jit.exceptionCheck();
     3150        } else {
     3151            SpeculateCellOperand value(this, node->child1());
     3152            GPRReg valueGPR = value.gpr();
     3153            speculateString(node->child1(), valueGPR);
     3154
     3155            flushRegisters();
     3156#if USE(JSVALUE64)
     3157            callOperation(operationParseIntString, resultRegs.gpr(), valueGPR, radixGPR);
     3158#else
     3159            callOperation(operationParseIntString, resultRegs, valueGPR, radixGPR);
     3160#endif
     3161            m_jit.exceptionCheck();
     3162        }
     3163    } else {
     3164        if (node->child1().useKind() == UntypedUse) {
     3165            JSValueOperand value(this, node->child1());
     3166
     3167            flushRegisters();
     3168#if USE(JSVALUE64)
     3169            callOperation(operationParseIntNoRadixGeneric, resultRegs.gpr(), value.jsValueRegs());
     3170#else
     3171            callOperation(operationParseIntNoRadixGeneric, resultRegs, value.jsValueRegs());
     3172#endif
     3173            m_jit.exceptionCheck();
     3174        } else {
     3175            SpeculateCellOperand value(this, node->child1());
     3176            GPRReg valueGPR = value.gpr();
     3177            speculateString(node->child1(), valueGPR);
     3178
     3179            flushRegisters();
     3180            callOperation(operationParseIntStringNoRadix, resultRegs, valueGPR);
     3181            m_jit.exceptionCheck();
     3182        }
     3183    }
     3184
     3185    jsValueResult(resultRegs, node);
    31213186}
    31223187
  • trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h

    r211908 r212939  
    13081308        return appendCallSetResult(operation, result);
    13091309    }
     1310
     1311    JITCompiler::Call callOperation(J_JITOperation_EJss operation, JSValueRegs result, GPRReg arg1)
     1312    {
     1313        m_jit.setupArgumentsWithExecState(arg1);
     1314        return appendCallSetResult(operation, result);
     1315    }
     1316
    13101317    JITCompiler::Call callOperation(T_JITOperation_EJss operation, GPRReg result, GPRReg arg1)
    13111318    {
     
    18891896        m_jit.setupArgumentsWithExecState(EABI_32BIT_DUMMY_ARG arg.payloadGPR(), arg.tagGPR(), mathIC);
    18901897        return appendCallSetResult(operation, result.payloadGPR(), result.tagGPR());
     1898    }
     1899    JITCompiler::Call callOperation(J_JITOperation_EJZ operation, JSValueRegs result, JSValueRegs arg1, GPRReg arg2)
     1900    {
     1901        m_jit.setupArgumentsWithExecState(EABI_32BIT_DUMMY_ARG arg1.payloadGPR(), arg1.tagGPR(), arg2);
     1902        return appendCallSetResult(operation, result);
    18911903    }
    18921904    JITCompiler::Call callOperation(J_JITOperation_EJJMic operation, JSValueRegs result, JSValueRegs arg1, JSValueRegs arg2, TrustedImmPtr mathIC)
     
    24352447        m_jit.setupResults(result1, result2);
    24362448        return call;
     2449    }
     2450    JITCompiler::Call appendCallSetResult(const FunctionPtr& function, JSValueRegs resultRegs)
     2451    {
     2452#if USE(JSVALUE64)
     2453        return appendCallSetResult(function, resultRegs.gpr());
     2454#else
     2455        return appendCallSetResult(function, resultRegs.payloadGPR(), resultRegs.tagGPR());
     2456#endif
    24372457    }
    24382458#if CPU(X86)
     
    26852705    void compileCheckTypeInfoFlags(Node*);
    26862706    void compileCheckStringIdent(Node*);
     2707
     2708    void compileParseInt(Node*);
    26872709   
    26882710    void compileValueRep(Node*);
  • trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp

    r211908 r212939  
    46674667    }
    46684668
     4669    case ParseInt: {
     4670        compileParseInt(node);
     4671        break;
     4672    }
     4673
    46694674    case CheckTypeInfoFlags: {
    46704675        compileCheckTypeInfoFlags(node);
  • trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp

    r211908 r212939  
    46354635    }
    46364636
     4637    case ParseInt: {
     4638        compileParseInt(node);
     4639        break;
     4640    }
     4641
    46374642    case OverridesHasInstance: {
    46384643
  • trunk/Source/JavaScriptCore/ftl/FTLCapabilities.cpp

    r210695 r212939  
    284284    case CallDOMGetter:
    285285    case ArraySlice:
     286    case ParseInt:
    286287        // These are OK.
    287288        break;
  • trunk/Source/JavaScriptCore/ftl/FTLLowerDFGToB3.cpp

    r212453 r212939  
    960960        case IsTypedArrayView:
    961961            compileIsTypedArrayView();
     962            break;
     963        case ParseInt:
     964            compileParseInt();
    962965            break;
    963966        case TypeOf:
     
    82208223        m_out.appendTo(continuation, lastNext);
    82218224        setBoolean(m_out.phi(Int32, fastResult, slowResult));
     8225    }
     8226
     8227    void compileParseInt()
     8228    {
     8229        RELEASE_ASSERT(m_node->child1().useKind() == UntypedUse || m_node->child1().useKind() == StringUse);
     8230        LValue result;
     8231        if (m_node->child2()) {
     8232            LValue radix = lowInt32(m_node->child2());
     8233            if (m_node->child1().useKind() == UntypedUse)
     8234                result = vmCall(Int64, m_out.operation(operationParseIntGeneric), m_callFrame, lowJSValue(m_node->child1()), radix);
     8235            else
     8236                result = vmCall(Int64, m_out.operation(operationParseIntString), m_callFrame, lowString(m_node->child1()), radix);
     8237        } else {
     8238            if (m_node->child1().useKind() == UntypedUse)
     8239                result = vmCall(Int64, m_out.operation(operationParseIntNoRadixGeneric), m_callFrame, lowJSValue(m_node->child1()));
     8240            else
     8241                result = vmCall(Int64, m_out.operation(operationParseIntStringNoRadix), m_callFrame, lowString(m_node->child1()));
     8242        }
     8243        setJSValue(result);
    82228244    }
    82238245
  • trunk/Source/JavaScriptCore/jit/JITOperations.h

    r211908 r212939  
    154154typedef EncodedJSValue (JIT_OPERATION *J_JITOperation_EJMic)(ExecState*, EncodedJSValue, void*);
    155155typedef EncodedJSValue (JIT_OPERATION *J_JITOperation_EJssZ)(ExecState*, JSString*, int32_t);
     156typedef EncodedJSValue (JIT_OPERATION *J_JITOperation_EJss)(ExecState*, JSString*);
    156157typedef EncodedJSValue (JIT_OPERATION *J_JITOperation_EJssReo)(ExecState*, JSString*, RegExpObject*);
    157158typedef EncodedJSValue (JIT_OPERATION *J_JITOperation_EJssReoJss)(ExecState*, JSString*, RegExpObject*, JSString*);
  • trunk/Source/JavaScriptCore/parser/Lexer.cpp

    r211319 r212939  
    3030#include "JSCInlines.h"
    3131#include "JSFunctionInlines.h"
    32 #include "JSGlobalObjectFunctions.h"
    3332#include "KeywordLookup.h"
    3433#include "Lexer.lut.h"
    3534#include "Nodes.h"
     35#include "ParseInt.h"
    3636#include "Parser.h"
    3737#include <ctype.h>
  • trunk/Source/JavaScriptCore/runtime/ErrorInstance.cpp

    r211247 r212939  
    2626#include "JSScope.h"
    2727#include "JSCInlines.h"
    28 #include "JSGlobalObjectFunctions.h"
     28#include "ParseInt.h"
    2929#include <wtf/text/StringBuilder.h>
    3030
  • trunk/Source/JavaScriptCore/runtime/Intrinsic.h

    r210695 r212939  
    8080    AtomicsXorIntrinsic,
    8181    ToLowerCaseIntrinsic,
     82    ParseIntIntrinsic,
    8283
    8384    // Getter intrinsics.
  • trunk/Source/JavaScriptCore/runtime/JSGlobalObject.cpp

    r212378 r212939  
    577577    m_proxyRevokeStructure.set(vm, this, ProxyRevoke::createStructure(vm, this, m_functionPrototype.get()));
    578578
    579     m_parseIntFunction.set(vm, this, JSFunction::create(vm, this, 2, vm.propertyNames->parseInt.string(), globalFuncParseInt, NoIntrinsic));
     579    m_parseIntFunction.set(vm, this, JSFunction::create(vm, this, 2, vm.propertyNames->parseInt.string(), globalFuncParseInt, ParseIntIntrinsic));
    580580    putDirectWithoutTransition(vm, vm.propertyNames->parseInt, m_parseIntFunction.get(), DontEnum);
    581581   
  • trunk/Source/JavaScriptCore/runtime/JSGlobalObjectFunctions.cpp

    r212438 r212939  
    4242#include "Nodes.h"
    4343#include "JSCInlines.h"
     44#include "ParseInt.h"
    4445#include "Parser.h"
    4546#include "StackVisitor.h"
     
    6162
    6263static const char* const ObjectProtoCalledOnNullOrUndefinedError = "Object.prototype.__proto__ called on null or undefined";
    63 
    64 template<typename CallbackWhenNoException>
    65 static ALWAYS_INLINE typename std::result_of<CallbackWhenNoException(StringView)>::type toStringView(ExecState* exec, JSValue value, CallbackWhenNoException callback)
    66 {
    67     VM& vm = exec->vm();
    68     auto scope = DECLARE_THROW_SCOPE(vm);
    69     JSString* string = value.toStringOrNull(exec);
    70     if (UNLIKELY(!string))
    71         return { };
    72     auto viewWithString = string->viewWithUnderlyingString(*exec);
    73     RETURN_IF_EXCEPTION(scope, { });
    74     return callback(viewWithString.view);
    75 }
    7664
    7765template<unsigned charactersCount>
     
    252240}
    253241
    254 bool isStrWhiteSpace(UChar c)
    255 {
    256     switch (c) {
    257         // ECMA-262-5th 7.2 & 7.3
    258         case 0x0009:
    259         case 0x000A:
    260         case 0x000B:
    261         case 0x000C:
    262         case 0x000D:
    263         case 0x0020:
    264         case 0x00A0:
    265         case 0x180E: // This character used to be in Zs category before Unicode 6.3, and EcmaScript says that we should keep treating it as such.
    266         case 0x2028:
    267         case 0x2029:
    268         case 0xFEFF:
    269             return true;
    270         default:
    271             return c > 0xFF && u_charType(c) == U_SPACE_SEPARATOR;
    272     }
    273 }
    274 
    275 static int parseDigit(unsigned short c, int radix)
    276 {
    277     int digit = -1;
    278 
    279     if (isASCIIDigit(c))
    280         digit = c - '0';
    281     else if (isASCIIUpper(c))
    282         digit = c - 'A' + 10;
    283     else if (isASCIILower(c))
    284         digit = c - 'a' + 10;
    285 
    286     if (digit >= radix)
    287         return -1;
    288     return digit;
    289 }
    290 
    291 double parseIntOverflow(const LChar* s, unsigned length, int radix)
    292 {
    293     double number = 0.0;
    294     double radixMultiplier = 1.0;
    295 
    296     for (const LChar* p = s + length - 1; p >= s; p--) {
    297         if (radixMultiplier == std::numeric_limits<double>::infinity()) {
    298             if (*p != '0') {
    299                 number = std::numeric_limits<double>::infinity();
    300                 break;
    301             }
    302         } else {
    303             int digit = parseDigit(*p, radix);
    304             number += digit * radixMultiplier;
    305         }
    306 
    307         radixMultiplier *= radix;
    308     }
    309 
    310     return number;
    311 }
    312 
    313 static double parseIntOverflow(const UChar* s, unsigned length, int radix)
    314 {
    315     double number = 0.0;
    316     double radixMultiplier = 1.0;
    317 
    318     for (const UChar* p = s + length - 1; p >= s; p--) {
    319         if (radixMultiplier == std::numeric_limits<double>::infinity()) {
    320             if (*p != '0') {
    321                 number = std::numeric_limits<double>::infinity();
    322                 break;
    323             }
    324         } else {
    325             int digit = parseDigit(*p, radix);
    326             number += digit * radixMultiplier;
    327         }
    328 
    329         radixMultiplier *= radix;
    330     }
    331 
    332     return number;
    333 }
    334 
    335 static double parseIntOverflow(StringView string, int radix)
    336 {
    337     if (string.is8Bit())
    338         return parseIntOverflow(string.characters8(), string.length(), radix);
    339     return parseIntOverflow(string.characters16(), string.length(), radix);
    340 }
    341 
    342 // ES5.1 15.1.2.2
    343 template <typename CharType>
    344 ALWAYS_INLINE
    345 static double parseInt(StringView s, const CharType* data, int radix)
    346 {
    347     // 1. Let inputString be ToString(string).
    348     // 2. Let S be a newly created substring of inputString consisting of the first character that is not a
    349     //    StrWhiteSpaceChar and all characters following that character. (In other words, remove leading white
    350     //    space.) If inputString does not contain any such characters, let S be the empty string.
    351     int length = s.length();
    352     int p = 0;
    353     while (p < length && isStrWhiteSpace(data[p]))
    354         ++p;
    355 
    356     // 3. Let sign be 1.
    357     // 4. If S is not empty and the first character of S is a minus sign -, let sign be -1.
    358     // 5. If S is not empty and the first character of S is a plus sign + or a minus sign -, then remove the first character from S.
    359     double sign = 1;
    360     if (p < length) {
    361         if (data[p] == '+')
    362             ++p;
    363         else if (data[p] == '-') {
    364             sign = -1;
    365             ++p;
    366         }
    367     }
    368 
    369     // 6. Let R = ToInt32(radix).
    370     // 7. Let stripPrefix be true.
    371     // 8. If R != 0,then
    372     //   b. If R != 16, let stripPrefix be false.
    373     // 9. Else, R == 0
    374     //   a. LetR = 10.
    375     // 10. If stripPrefix is true, then
    376     //   a. If the length of S is at least 2 and the first two characters of S are either ―0x or ―0X,
    377     //      then remove the first two characters from S and let R = 16.
    378     // 11. If S contains any character that is not a radix-R digit, then let Z be the substring of S
    379     //     consisting of all characters before the first such character; otherwise, let Z be S.
    380     if ((radix == 0 || radix == 16) && length - p >= 2 && data[p] == '0' && (data[p + 1] == 'x' || data[p + 1] == 'X')) {
    381         radix = 16;
    382         p += 2;
    383     } else if (radix == 0)
    384         radix = 10;
    385 
    386     // 8.a If R < 2 or R > 36, then return NaN.
    387     if (radix < 2 || radix > 36)
    388         return PNaN;
    389 
    390     // 13. Let mathInt be the mathematical integer value that is represented by Z in radix-R notation, using the letters
    391     //     A-Z and a-z for digits with values 10 through 35. (However, if R is 10 and Z contains more than 20 significant
    392     //     digits, every significant digit after the 20th may be replaced by a 0 digit, at the option of the implementation;
    393     //     and if R is not 2, 4, 8, 10, 16, or 32, then mathInt may be an implementation-dependent approximation to the
    394     //     mathematical integer value that is represented by Z in radix-R notation.)
    395     // 14. Let number be the Number value for mathInt.
    396     int firstDigitPosition = p;
    397     bool sawDigit = false;
    398     double number = 0;
    399     while (p < length) {
    400         int digit = parseDigit(data[p], radix);
    401         if (digit == -1)
    402             break;
    403         sawDigit = true;
    404         number *= radix;
    405         number += digit;
    406         ++p;
    407     }
    408 
    409     // 12. If Z is empty, return NaN.
    410     if (!sawDigit)
    411         return PNaN;
    412 
    413     // Alternate code path for certain large numbers.
    414     if (number >= mantissaOverflowLowerBound) {
    415         if (radix == 10) {
    416             size_t parsedLength;
    417             number = parseDouble(s.substring(firstDigitPosition, p - firstDigitPosition), parsedLength);
    418         } else if (radix == 2 || radix == 4 || radix == 8 || radix == 16 || radix == 32)
    419             number = parseIntOverflow(s.substring(firstDigitPosition, p - firstDigitPosition), radix);
    420     }
    421 
    422     // 15. Return sign x number.
    423     return sign * number;
    424 }
    425 
    426 static double parseInt(StringView s, int radix)
    427 {
    428     if (s.is8Bit())
    429         return parseInt(s, s.characters8(), radix);
    430     return parseInt(s, s.characters16(), radix);
    431 }
    432 
    433242static const int SizeOfInfinity = 8;
    434243
  • trunk/Source/JavaScriptCore/runtime/JSGlobalObjectFunctions.h

    r210522 r212939  
    5353EncodedJSValue JSC_HOST_CALL globalFuncImportModule(ExecState*);
    5454
    55 static const double mantissaOverflowLowerBound = 9007199254740992.0;
    56 double parseIntOverflow(const LChar*, unsigned length, int radix);
    57 bool isStrWhiteSpace(UChar);
    5855double jsToNumber(StringView);
    5956
  • trunk/Source/JavaScriptCore/runtime/StringPrototype.cpp

    r212791 r212939  
    3838#include "Lookup.h"
    3939#include "ObjectPrototype.h"
     40#include "ParseInt.h"
    4041#include "PropertyNameArray.h"
    4142#include "RegExpCache.h"
Note: See TracChangeset for help on using the changeset viewer.