Ignore:
Timestamp:
Mar 1, 2016, 1:18:42 PM (9 years ago)
Author:
[email protected]
Message:

Turn String.prototype.replace into an intrinsic
https://bugs.webkit.org/show_bug.cgi?id=154835

Reviewed by Michael Saboff.

Source/JavaScriptCore:

Octane/regexp spends a lot of time in String.prototype.replace(). That function does a lot
of checks to see if the parameters are what they are likely to often be (a string, a
regexp, and a string). The intuition of this patch is that it's good to remove those checks
and it's good to call the native function as directly as possible.

This yields a 10% speed-up on a replace microbenchmark and a 3% speed-up on Octane/regexp.
It also improves Octane/jquery.

This is only the beginning of what I want to do with replace optimizations. The other
optimizations will rely on StringReplace being revealed as a construct in DFG IR.

  • JavaScriptCore.xcodeproj/project.pbxproj:
  • bytecode/SpeculatedType.cpp:

(JSC::dumpSpeculation):
(JSC::speculationToAbbreviatedString):
(JSC::speculationFromClassInfo):

  • bytecode/SpeculatedType.h:

(JSC::isStringOrStringObjectSpeculation):
(JSC::isRegExpObjectSpeculation):
(JSC::isBoolInt32Speculation):

  • 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/DFGNode.h:

(JSC::DFG::Node::shouldSpeculateStringOrStringObject):
(JSC::DFG::Node::shouldSpeculateRegExpObject):
(JSC::DFG::Node::shouldSpeculateSymbol):

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

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

  • dfg/DFGSafeToExecute.h:

(JSC::DFG::SafeToExecuteEdge::operator()):
(JSC::DFG::safeToExecute):

  • dfg/DFGSpeculativeJIT.cpp:

(JSC::DFG::SpeculativeJIT::speculateFinalObject):
(JSC::DFG::SpeculativeJIT::speculateRegExpObject):
(JSC::DFG::SpeculativeJIT::speculateObjectOrOther):
(JSC::DFG::SpeculativeJIT::speculate):

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

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

  • dfg/DFGSpeculativeJIT64.cpp:

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

  • dfg/DFGUseKind.cpp:

(WTF::printInternal):

  • dfg/DFGUseKind.h:

(JSC::DFG::typeFilterFor):
(JSC::DFG::isCell):

  • ftl/FTLCapabilities.cpp:

(JSC::FTL::canCompile):

  • ftl/FTLLowerDFGToB3.cpp:

(JSC::FTL::DFG::LowerDFGToB3::compileNode):
(JSC::FTL::DFG::LowerDFGToB3::compileNewRegexp):
(JSC::FTL::DFG::LowerDFGToB3::compileStringReplace):
(JSC::FTL::DFG::LowerDFGToB3::didOverflowStack):
(JSC::FTL::DFG::LowerDFGToB3::speculate):
(JSC::FTL::DFG::LowerDFGToB3::speculateFinalObject):
(JSC::FTL::DFG::LowerDFGToB3::speculateRegExpObject):
(JSC::FTL::DFG::LowerDFGToB3::speculateString):

  • jit/JITOperations.h:
  • runtime/Intrinsic.h:
  • runtime/JSType.h:
  • runtime/RegExpObject.h:

(JSC::RegExpObject::createStructure):

  • runtime/StringPrototype.cpp:

(JSC::StringPrototype::finishCreation):
(JSC::removeUsingRegExpSearch):
(JSC::replaceUsingRegExpSearch):
(JSC::operationStringProtoFuncReplaceRegExpString):
(JSC::replaceUsingStringSearch):
(JSC::stringProtoFuncRepeat):
(JSC::replace):
(JSC::stringProtoFuncReplace):
(JSC::operationStringProtoFuncReplaceGeneric):
(JSC::stringProtoFuncToString):

  • runtime/StringPrototype.h:

LayoutTests:

  • js/regress/script-tests/string-replace.js: Added.
  • js/regress/string-replace-expected.txt: Added.
  • js/regress/string-replace.html: Added.
Location:
trunk/Source/JavaScriptCore/runtime
Files:
5 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/JavaScriptCore/runtime/Intrinsic.h

    r194087 r197408  
    11/*
    2  * Copyright (C) 2011 Apple Inc. All rights reserved.
     2 * Copyright (C) 2011, 2016 Apple Inc. All rights reserved.
    33 *
    44 * Redistribution and use in source and binary forms, with or without
     
    5353    RegExpTestIntrinsic,
    5454    StringPrototypeValueOfIntrinsic,
     55    StringPrototypeReplaceIntrinsic,
    5556    IMulIntrinsic,
    5657    RandomIntrinsic,
  • trunk/Source/JavaScriptCore/runtime/JSType.h

    r197136 r197408  
    11/*
    2  *  Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011, 2015 Apple Inc. All rights reserved.
     2 *  Copyright (C) 2006-2011, 2015-2016 Apple Inc. All rights reserved.
    33 *
    44 *  This library is free software; you can redistribute it and/or
     
    7878    GlobalObjectType,
    7979    ClosureObjectType,
    80 
     80    RegExpObjectType,
    8181    ProxyObjectType,
    8282
  • trunk/Source/JavaScriptCore/runtime/RegExpObject.h

    r182747 r197408  
    11/*
    22 *  Copyright (C) 1999-2000 Harri Porten ([email protected])
    3  *  Copyright (C) 2003, 2007, 2008, 2012 Apple Inc. All Rights Reserved.
     3 *  Copyright (C) 2003, 2007, 2008, 2012, 2016 Apple Inc. All Rights Reserved.
    44 *
    55 *  This library is free software; you can redistribute it and/or
     
    7272    static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
    7373    {
    74         return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info());
     74        return Structure::create(vm, globalObject, prototype, TypeInfo(RegExpObjectType, StructureFlags), info());
    7575    }
    7676
  • trunk/Source/JavaScriptCore/runtime/StringPrototype.cpp

    r197261 r197408  
    136136    JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION("match", stringProtoFuncMatch, DontEnum, 1);
    137137    JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION("repeat", stringProtoFuncRepeat, DontEnum, 1);
    138     JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION("replace", stringProtoFuncReplace, DontEnum, 2);
     138    JSC_NATIVE_INTRINSIC_FUNCTION_WITHOUT_TRANSITION("replace", stringProtoFuncReplace, DontEnum, 2, StringPrototypeReplaceIntrinsic);
    139139    JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION("slice", stringProtoFuncSlice, DontEnum, 2);
    140140    JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION("split", stringProtoFuncSplit, DontEnum, 2);
     
    485485}
    486486
    487 static NEVER_INLINE EncodedJSValue replaceUsingRegExpSearch(ExecState* exec, JSString* string, JSValue searchValue)
    488 {
    489     JSValue replaceValue = exec->argument(1);
    490     String replacementString;
    491     CallData callData;
    492     CallType callType = getCallData(replaceValue, callData);
    493     if (callType == CallTypeNone) {
    494         replacementString = replaceValue.toString(exec)->value(exec);
    495         if (exec->hadException())
    496             return JSValue::encode(jsUndefined());
    497     }
    498 
     487static ALWAYS_INLINE EncodedJSValue replaceUsingRegExpSearch(
     488    ExecState* exec, JSString* string, JSValue searchValue, CallData& callData, CallType callType,
     489    String& replacementString, JSValue replaceValue)
     490{
    499491    const String& source = string->value(exec);
    500492    unsigned sourceLen = source.length();
     
    673665}
    674666
    675 static inline EncodedJSValue replaceUsingStringSearch(ExecState* exec, JSString* jsString, JSValue searchValue)
     667EncodedJSValue JIT_OPERATION operationStringProtoFuncReplaceRegExpString(
     668    ExecState* exec, JSString* thisValue, RegExpObject* searchValue, JSString* replaceString)
     669{
     670    CallData callData;
     671    String replacementString = replaceString->value(exec);
     672    return replaceUsingRegExpSearch(
     673        exec, thisValue, searchValue, callData, CallTypeNone, replacementString, replaceString);
     674}
     675
     676static ALWAYS_INLINE EncodedJSValue replaceUsingRegExpSearch(ExecState* exec, JSString* string, JSValue searchValue, JSValue replaceValue)
     677{
     678    String replacementString;
     679    CallData callData;
     680    CallType callType = getCallData(replaceValue, callData);
     681    if (callType == CallTypeNone) {
     682        replacementString = replaceValue.toString(exec)->value(exec);
     683        if (exec->hadException())
     684            return JSValue::encode(jsUndefined());
     685    }
     686
     687    return replaceUsingRegExpSearch(
     688        exec, string, searchValue, callData, callType, replacementString, replaceValue);
     689}
     690
     691static ALWAYS_INLINE EncodedJSValue replaceUsingStringSearch(ExecState* exec, JSString* jsString, JSValue searchValue, JSValue replaceValue)
    676692{
    677693    const String& string = jsString->value(exec);
     
    685701        return JSValue::encode(jsString);
    686702
    687     JSValue replaceValue = exec->argument(1);
    688703    CallData callData;
    689704    CallType callType = getCallData(replaceValue, callData);
     
    788803}
    789804
     805ALWAYS_INLINE EncodedJSValue replace(
     806    ExecState* exec, JSString* string, JSValue searchValue, JSValue replaceValue)
     807{
     808    if (searchValue.inherits(RegExpObject::info()))
     809        return replaceUsingRegExpSearch(exec, string, searchValue, replaceValue);
     810    return replaceUsingStringSearch(exec, string, searchValue, replaceValue);
     811}
     812
     813ALWAYS_INLINE EncodedJSValue replace(
     814    ExecState* exec, JSValue thisValue, JSValue searchValue, JSValue replaceValue)
     815{
     816    if (!checkObjectCoercible(thisValue))
     817        return throwVMTypeError(exec);
     818    JSString* string = thisValue.toString(exec);
     819    if (exec->hadException())
     820        return JSValue::encode(jsUndefined());
     821    return replace(exec, string, searchValue, replaceValue);
     822}
     823
    790824EncodedJSValue JSC_HOST_CALL stringProtoFuncReplace(ExecState* exec)
    791825{
    792     JSValue thisValue = exec->thisValue();
    793     if (!checkObjectCoercible(thisValue))
    794         return throwVMTypeError(exec);
    795     JSString* string = thisValue.toString(exec);
    796     JSValue searchValue = exec->argument(0);
    797 
    798     if (searchValue.inherits(RegExpObject::info()))
    799         return replaceUsingRegExpSearch(exec, string, searchValue);
    800     return replaceUsingStringSearch(exec, string, searchValue);
     826    return replace(exec, exec->thisValue(), exec->argument(0), exec->argument(1));
     827}
     828
     829EncodedJSValue JIT_OPERATION operationStringProtoFuncReplaceGeneric(
     830    ExecState* exec, EncodedJSValue thisValue, EncodedJSValue searchValue,
     831    EncodedJSValue replaceValue)
     832{
     833    return replace(
     834        exec, JSValue::decode(thisValue), JSValue::decode(searchValue),
     835        JSValue::decode(replaceValue));
    801836}
    802837
  • trunk/Source/JavaScriptCore/runtime/StringPrototype.h

    r196498 r197408  
    11/*
    22 *  Copyright (C) 1999-2000 Harri Porten ([email protected])
    3  *  Copyright (C) 2007, 2008, 2013 Apple Inc. All rights reserved.
     3 *  Copyright (C) 2007, 2008, 2013, 2016 Apple Inc. All rights reserved.
    44 *
    55 *  This library is free software; you can redistribute it and/or
     
    2222#define StringPrototype_h
    2323
     24#include "JITOperations.h"
    2425#include "StringObject.h"
    2526
     
    2728
    2829class ObjectPrototype;
     30class RegExpObject;
    2931
    3032class StringPrototype : public StringObject {
     
    5254};
    5355
     56EncodedJSValue JIT_OPERATION operationStringProtoFuncReplaceGeneric(
     57    ExecState* exec, EncodedJSValue thisValue, EncodedJSValue searchValue,
     58    EncodedJSValue replaceValue);
     59
     60EncodedJSValue JIT_OPERATION operationStringProtoFuncReplaceRegExpString(
     61    ExecState* exec, JSString* thisValue, RegExpObject* searchValue, JSString* replaceValue);
     62
    5463} // namespace JSC
    5564
Note: See TracChangeset for help on using the changeset viewer.