Changeset 228968 in webkit


Ignore:
Timestamp:
Feb 23, 2018 4:48:32 PM (6 years ago)
Author:
sbarati@apple.com
Message:

Make Number.isInteger an intrinsic
https://bugs.webkit.org/show_bug.cgi?id=183088

Reviewed by JF Bastien.

JSTests:

  • stress/number-is-integer-intrinsic.js: Added.

Source/JavaScriptCore:

When profiling the ML subtest in ARES, I noticed it was spending some
time in Number.isInteger. This patch makes that operation an intrinsic
in the DFG/FTL. It might be a speedup by 1% or so on that subtest, but
it's likely not an aggregate speedup on ARES. However, it is definitely
faster than calling into a builtin function, so we might as well have
it as an intrinsic.

  • 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/DFGNodeType.h:
  • dfg/DFGOperations.cpp:
  • dfg/DFGOperations.h:
  • dfg/DFGPredictionPropagationPhase.cpp:
  • dfg/DFGSafeToExecute.h:

(JSC::DFG::safeToExecute):

  • 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::compileNumberIsInteger):
(JSC::FTL::DFG::LowerDFGToB3::unboxDouble):

  • runtime/Intrinsic.cpp:

(JSC::intrinsicName):

  • runtime/Intrinsic.h:
  • runtime/NumberConstructor.cpp:

(JSC::NumberConstructor::finishCreation):
(JSC::numberConstructorFuncIsInteger):

  • runtime/NumberConstructor.h:

(JSC::NumberConstructor::isIntegerImpl):

Location:
trunk
Files:
1 added
20 edited

Legend:

Unmodified
Added
Removed
  • trunk/JSTests/ChangeLog

    r228966 r228968  
     12018-02-23  Saam Barati  <sbarati@apple.com>
     2
     3        Make Number.isInteger an intrinsic
     4        https://bugs.webkit.org/show_bug.cgi?id=183088
     5
     6        Reviewed by JF Bastien.
     7
     8        * stress/number-is-integer-intrinsic.js: Added.
     9
    1102018-02-23  Oleksandr Skachkov  <gskachkov@gmail.com>
    211
  • trunk/Source/JavaScriptCore/ChangeLog

    r228966 r228968  
     12018-02-23  Saam Barati  <sbarati@apple.com>
     2
     3        Make Number.isInteger an intrinsic
     4        https://bugs.webkit.org/show_bug.cgi?id=183088
     5
     6        Reviewed by JF Bastien.
     7
     8        When profiling the ML subtest in ARES, I noticed it was spending some
     9        time in Number.isInteger. This patch makes that operation an intrinsic
     10        in the DFG/FTL. It might be a speedup by 1% or so on that subtest, but
     11        it's likely not an aggregate speedup on ARES. However, it is definitely
     12        faster than calling into a builtin function, so we might as well have
     13        it as an intrinsic.
     14
     15        * dfg/DFGAbstractInterpreterInlines.h:
     16        (JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects):
     17        * dfg/DFGByteCodeParser.cpp:
     18        (JSC::DFG::ByteCodeParser::handleIntrinsicCall):
     19        * dfg/DFGClobberize.h:
     20        (JSC::DFG::clobberize):
     21        * dfg/DFGDoesGC.cpp:
     22        (JSC::DFG::doesGC):
     23        * dfg/DFGFixupPhase.cpp:
     24        (JSC::DFG::FixupPhase::fixupNode):
     25        * dfg/DFGNodeType.h:
     26        * dfg/DFGOperations.cpp:
     27        * dfg/DFGOperations.h:
     28        * dfg/DFGPredictionPropagationPhase.cpp:
     29        * dfg/DFGSafeToExecute.h:
     30        (JSC::DFG::safeToExecute):
     31        * dfg/DFGSpeculativeJIT32_64.cpp:
     32        (JSC::DFG::SpeculativeJIT::compile):
     33        * dfg/DFGSpeculativeJIT64.cpp:
     34        (JSC::DFG::SpeculativeJIT::compile):
     35        * ftl/FTLCapabilities.cpp:
     36        (JSC::FTL::canCompile):
     37        * ftl/FTLLowerDFGToB3.cpp:
     38        (JSC::FTL::DFG::LowerDFGToB3::compileNode):
     39        (JSC::FTL::DFG::LowerDFGToB3::compileNumberIsInteger):
     40        (JSC::FTL::DFG::LowerDFGToB3::unboxDouble):
     41        * runtime/Intrinsic.cpp:
     42        (JSC::intrinsicName):
     43        * runtime/Intrinsic.h:
     44        * runtime/NumberConstructor.cpp:
     45        (JSC::NumberConstructor::finishCreation):
     46        (JSC::numberConstructorFuncIsInteger):
     47        * runtime/NumberConstructor.h:
     48        (JSC::NumberConstructor::isIntegerImpl):
     49
    1502018-02-23  Oleksandr Skachkov  <gskachkov@gmail.com>
    251
  • trunk/Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h

    r228693 r228968  
    3737#include "JITOperations.h"
    3838#include "MathCommon.h"
     39#include "NumberConstructor.h"
    3940#include "Operations.h"
    4041#include "PutByIdStatus.h"
     
    11771178    case IsBoolean:
    11781179    case IsNumber:
     1180    case NumberIsInteger:
    11791181    case IsObject:
    11801182    case IsObjectOrNull:
     
    12001202            case IsNumber:
    12011203                setConstant(node, jsBoolean(child.value().isNumber()));
     1204                break;
     1205            case NumberIsInteger:
     1206                setConstant(node, jsBoolean(NumberConstructor::isIntegerImpl(child.value())));
    12021207                break;
    12031208            case IsObject:
     
    13081313           
    13091314            break;
     1315
     1316        case NumberIsInteger:
     1317            if (!(child.m_type & ~SpecInt32Only)) {
     1318                setConstant(node, jsBoolean(true));
     1319                constantWasSet = true;
     1320                break;
     1321            }
     1322           
     1323            if (!(child.m_type & SpecFullNumber)) {
     1324                setConstant(node, jsBoolean(false));
     1325                constantWasSet = true;
     1326                break;
     1327            }
     1328           
     1329            break;
     1330
    13101331        case IsObject:
    13111332            if (!(child.m_type & ~SpecObject)) {
  • trunk/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp

    r228950 r228968  
    31243124            set(VirtualRegister(resultOperand), result);
    31253125        }
     3126        return true;
     3127    }
     3128
     3129    case NumberIsIntegerIntrinsic: {
     3130        if (argumentCountIncludingThis < 2)
     3131            return false;
     3132
     3133        insertChecks();
     3134        Node* input = get(virtualRegisterForArgument(1, registerOffset));
     3135        Node* result = addToGraph(NumberIsInteger, input);
     3136        set(VirtualRegister(resultOperand), result);
    31263137        return true;
    31273138    }
  • trunk/Source/JavaScriptCore/dfg/DFGClobberize.h

    r228860 r228968  
    170170    case IsBoolean:
    171171    case IsNumber:
     172    case NumberIsInteger:
    172173    case IsObject:
    173174    case IsTypedArrayView:
  • trunk/Source/JavaScriptCore/dfg/DFGDoesGC.cpp

    r228411 r228968  
    175175    case IsBoolean:
    176176    case IsNumber:
     177    case NumberIsInteger:
    177178    case IsObject:
    178179    case IsObjectOrNull:
  • trunk/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp

    r228720 r228968  
    21072107        case ThrowStaticError:
    21082108            fixEdge<StringUse>(node->child1());
     2109            break;
     2110
     2111        case NumberIsInteger:
     2112            if (node->child1()->shouldSpeculateInt32()) {
     2113                m_insertionSet.insertNode(
     2114                    m_indexInBlock, SpecNone, Check, node->origin,
     2115                    Edge(node->child1().node(), Int32Use));
     2116                m_graph.convertToConstant(node, jsBoolean(true));
     2117                break;
     2118            }
    21092119            break;
    21102120
  • trunk/Source/JavaScriptCore/dfg/DFGNodeType.h

    r228411 r228968  
    349349    macro(IsBoolean, NodeResultBoolean) \
    350350    macro(IsNumber, NodeResultBoolean) \
     351    macro(NumberIsInteger, NodeResultBoolean) \
    351352    macro(IsObject, NodeResultBoolean) \
    352353    macro(IsObjectOrNull, NodeResultBoolean) \
  • trunk/Source/JavaScriptCore/dfg/DFGOperations.cpp

    r228725 r228968  
    6060#include "JSWeakMap.h"
    6161#include "JSWeakSet.h"
     62#include "NumberConstructor.h"
    6263#include "ObjectConstructor.h"
    6364#include "Operations.h"
     
    22552256}
    22562257
     2258int32_t JIT_OPERATION operationNumberIsInteger(ExecState* exec, EncodedJSValue value)
     2259{
     2260    VM& vm = exec->vm();
     2261    NativeCallFrameTracer tracer(&vm, exec);
     2262    return NumberConstructor::isIntegerImpl(JSValue::decode(value));
     2263}
     2264
    22572265int32_t JIT_OPERATION operationArrayIndexOfString(ExecState* exec, Butterfly* butterfly, JSString* searchElement, int32_t index)
    22582266{
  • trunk/Source/JavaScriptCore/dfg/DFGOperations.h

    r227723 r228968  
    255255int64_t JIT_OPERATION operationConvertDoubleToInt52(double);
    256256
     257int32_t JIT_OPERATION operationNumberIsInteger(ExecState*, EncodedJSValue);
     258
    257259size_t JIT_OPERATION operationDefaultHasInstance(ExecState*, JSCell* value, JSCell* proto);
    258260
  • trunk/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp

    r228411 r228968  
    850850        case IsBoolean:
    851851        case IsNumber:
     852        case NumberIsInteger:
    852853        case IsObject:
    853854        case IsObjectOrNull:
  • trunk/Source/JavaScriptCore/dfg/DFGSafeToExecute.h

    r228411 r228968  
    307307    case IsBoolean:
    308308    case IsNumber:
     309    case NumberIsInteger:
    309310    case IsObject:
    310311    case IsObjectOrNull:
  • trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp

    r228438 r228968  
    44034403        m_jit.compare32(JITCompiler::Below, result.gpr(), JITCompiler::TrustedImm32(JSValue::LowestTag + 1), result.gpr());
    44044404        booleanResult(result.gpr(), node);
     4405        break;
     4406    }
     4407
     4408    case NumberIsInteger: {
     4409        JSValueOperand input(this, node->child1());
     4410        JSValueRegs inputRegs = input.jsValueRegs();
     4411        flushRegisters();
     4412        GPRFlushedCallResult result(this);
     4413        GPRReg resultGPR = result.gpr();
     4414        callOperation(operationNumberIsInteger, resultGPR, inputRegs);
     4415        booleanResult(resultGPR, node);
    44054416        break;
    44064417    }
  • trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp

    r228420 r228968  
    46454645        break;
    46464646    }
    4647        
     4647
     4648    case NumberIsInteger: {
     4649        JSValueOperand value(this, node->child1());
     4650        GPRTemporary result(this, Reuse, value);
     4651
     4652        FPRTemporary temp1(this);
     4653        FPRTemporary temp2(this);
     4654
     4655        JSValueRegs valueRegs = JSValueRegs(value.gpr());
     4656        GPRReg resultGPR = value.gpr();
     4657
     4658        FPRReg tempFPR1 = temp1.fpr();
     4659        FPRReg tempFPR2 = temp2.fpr();
     4660
     4661        MacroAssembler::JumpList done;
     4662
     4663        auto isInt32 = m_jit.branchIfInt32(valueRegs);
     4664        auto notNumber = m_jit.branchIfNotDoubleKnownNotInt32(valueRegs);
     4665
     4666        // We're a double here.
     4667        m_jit.unboxDouble(valueRegs.gpr(), resultGPR, tempFPR1);
     4668        m_jit.urshift64(TrustedImm32(52), resultGPR);
     4669        m_jit.and32(TrustedImm32(0x7ff), resultGPR);
     4670        auto notNanNorInfinity = m_jit.branch32(JITCompiler::NotEqual, TrustedImm32(0x7ff), resultGPR);
     4671        m_jit.move(TrustedImm32(ValueFalse), resultGPR);
     4672        done.append(m_jit.jump());
     4673
     4674        notNanNorInfinity.link(&m_jit);
     4675        m_jit.roundTowardZeroDouble(tempFPR1, tempFPR2);
     4676        m_jit.compareDouble(JITCompiler::DoubleEqual, tempFPR1, tempFPR2, resultGPR);
     4677        m_jit.or32(TrustedImm32(ValueFalse), resultGPR);
     4678        done.append(m_jit.jump());
     4679
     4680        isInt32.link(&m_jit);
     4681        m_jit.move(TrustedImm32(ValueTrue), resultGPR);
     4682        done.append(m_jit.jump());
     4683
     4684        notNumber.link(&m_jit);
     4685        m_jit.move(TrustedImm32(ValueFalse), resultGPR);
     4686
     4687        done.link(&m_jit);
     4688        jsValueResult(resultGPR, node, DataFormatJSBoolean);
     4689        break;
     4690    }
     4691
    46484692    case MapHash: {
    46494693        switch (node->child1().useKind()) {
  • trunk/Source/JavaScriptCore/ftl/FTLCapabilities.cpp

    r228943 r228968  
    222222    case IsBoolean:
    223223    case IsNumber:
     224    case NumberIsInteger:
    224225    case IsObject:
    225226    case IsObjectOrNull:
  • trunk/Source/JavaScriptCore/ftl/FTLLowerDFGToB3.cpp

    r228943 r228968  
    10621062        case IsNumber:
    10631063            compileIsNumber();
     1064            break;
     1065        case NumberIsInteger:
     1066            compileNumberIsInteger();
    10641067            break;
    10651068        case IsCellWithType:
     
    87788781    {
    87798782        setBoolean(isNumber(lowJSValue(m_node->child1()), provenType(m_node->child1())));
     8783    }
     8784
     8785    void compileNumberIsInteger()
     8786    {
     8787        LBasicBlock notInt32 = m_out.newBlock();
     8788        LBasicBlock doubleCase = m_out.newBlock();
     8789        LBasicBlock doubleNotNanOrInf = m_out.newBlock();
     8790        LBasicBlock continuation = m_out.newBlock();
     8791
     8792        LValue input = lowJSValue(m_node->child1());
     8793
     8794        ValueFromBlock trueResult = m_out.anchor(m_out.booleanTrue);
     8795        m_out.branch(
     8796            isInt32(input, provenType(m_node->child1())), unsure(continuation), unsure(notInt32));
     8797
     8798        LBasicBlock lastNext = m_out.appendTo(notInt32, doubleCase);
     8799        ValueFromBlock falseResult = m_out.anchor(m_out.booleanFalse);
     8800        m_out.branch(
     8801            isNotNumber(input, provenType(m_node->child1())), unsure(continuation), unsure(doubleCase));
     8802
     8803        m_out.appendTo(doubleCase, doubleNotNanOrInf);
     8804        LValue doubleAsInt;
     8805        LValue asDouble = unboxDouble(input, &doubleAsInt);
     8806        LValue expBits = m_out.bitAnd(m_out.lShr(doubleAsInt, m_out.constInt32(52)), m_out.constInt64(0x7ff));
     8807        m_out.branch(
     8808            m_out.equal(expBits, m_out.constInt64(0x7ff)),
     8809            unsure(continuation), unsure(doubleNotNanOrInf));
     8810
     8811        m_out.appendTo(doubleNotNanOrInf, continuation);
     8812        B3::PatchpointValue* patchpoint = m_out.patchpoint(Int32);
     8813        patchpoint->appendSomeRegister(asDouble);
     8814        patchpoint->numFPScratchRegisters = 1;
     8815        patchpoint->effects = Effects::none();
     8816        patchpoint->setGenerator([=] (CCallHelpers& jit, const StackmapGenerationParams& params) {
     8817            GPRReg result = params[0].gpr();
     8818            FPRReg input = params[1].fpr();
     8819            FPRReg temp = params.fpScratch(0);
     8820            jit.roundTowardZeroDouble(input, temp);
     8821            jit.compareDouble(MacroAssembler::DoubleEqual, input, temp, result);
     8822        });
     8823        ValueFromBlock patchpointResult = m_out.anchor(patchpoint);
     8824        m_out.jump(continuation);
     8825
     8826        m_out.appendTo(continuation, lastNext);
     8827        setBoolean(m_out.phi(Int32, trueResult, falseResult, patchpointResult));
    87808828    }
    87818829   
     
    1431914367    }
    1432014368
    14321     LValue unboxDouble(LValue jsValue)
    14322     {
    14323         return m_out.bitCast(m_out.add(jsValue, m_tagTypeNumber), Double);
     14369    LValue unboxDouble(LValue jsValue, LValue* unboxedAsInt = nullptr)
     14370    {
     14371        LValue asInt = m_out.add(jsValue, m_tagTypeNumber);
     14372        if (unboxedAsInt)
     14373            *unboxedAsInt = asInt;
     14374        return m_out.bitCast(asInt, Double);
    1432414375    }
    1432514376    LValue boxDouble(LValue doubleValue)
  • trunk/Source/JavaScriptCore/runtime/Intrinsic.cpp

    r228950 r228968  
    130130    case NumberPrototypeToStringIntrinsic:
    131131        return "NumberPrototypeToStringIntrinsic";
     132    case NumberIsIntegerIntrinsic:
     133        return "NumberIsIntegerIntrinsic";
    132134    case IMulIntrinsic:
    133135        return "IMulIntrinsic";
  • trunk/Source/JavaScriptCore/runtime/Intrinsic.h

    r228950 r228968  
    7878    StringPrototypeToLowerCaseIntrinsic,
    7979    NumberPrototypeToStringIntrinsic,
     80    NumberIsIntegerIntrinsic,
    8081    IMulIntrinsic,
    8182    RandomIntrinsic,
  • trunk/Source/JavaScriptCore/runtime/NumberConstructor.cpp

    r224487 r228968  
    4848@begin numberConstructorTable
    4949  isFinite       JSBuiltin                           DontEnum|Function 1
    50   isInteger      numberConstructorFuncIsInteger      DontEnum|Function 1
    5150  isNaN          JSBuiltin                           DontEnum|Function 1
    5251  isSafeInteger  numberConstructorFuncIsSafeInteger  DontEnum|Function 1
     
    6766    ASSERT(inherits(vm, info()));
    6867
     68    JSGlobalObject* globalObject = numberPrototype->globalObject();
     69
    6970    putDirectWithoutTransition(vm, vm.propertyNames->prototype, numberPrototype, PropertyAttribute::DontEnum | PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly);
    7071    putDirectWithoutTransition(vm, vm.propertyNames->length, jsNumber(1), PropertyAttribute::ReadOnly | PropertyAttribute::DontEnum);
     
    8182    putDirectWithoutTransition(vm, vm.propertyNames->parseInt, numberPrototype->globalObject()->parseIntFunction(), static_cast<unsigned>(PropertyAttribute::DontEnum));
    8283    putDirectWithoutTransition(vm, vm.propertyNames->parseFloat, numberPrototype->globalObject()->parseFloatFunction(), static_cast<unsigned>(PropertyAttribute::DontEnum));
     84
     85    JSC_NATIVE_INTRINSIC_FUNCTION_WITHOUT_TRANSITION(Identifier::fromString(&vm, "isInteger"), numberConstructorFuncIsInteger, static_cast<unsigned>(PropertyAttribute::DontEnum), 1, NumberIsIntegerIntrinsic);
    8386}
    8487
     
    107110static EncodedJSValue JSC_HOST_CALL numberConstructorFuncIsInteger(ExecState* exec)
    108111{
    109     JSValue argument = exec->argument(0);
    110     bool isInteger;
    111     if (argument.isInt32())
    112         isInteger = true;
    113     else if (!argument.isDouble())
    114         isInteger = false;
    115     else {
    116         double number = argument.asDouble();
    117         isInteger = std::isfinite(number) && trunc(number) == number;
    118     }
    119     return JSValue::encode(jsBoolean(isInteger));
     112    return JSValue::encode(jsBoolean(NumberConstructor::isIntegerImpl(exec->argument(0))));
    120113}
    121114
  • trunk/Source/JavaScriptCore/runtime/NumberConstructor.h

    r224487 r228968  
    4747    }
    4848
     49    static bool isIntegerImpl(JSValue value)
     50    {
     51        if (value.isInt32())
     52            return true;
     53        if (!value.isDouble())
     54            return false;
     55
     56        double number = value.asDouble();
     57        return std::isfinite(number) && trunc(number) == number;
     58    }
     59
    4960protected:
    5061    void finishCreation(VM&, NumberPrototype*);
Note: See TracChangeset for help on using the changeset viewer.