Turn String.prototype.replace into an intrinsic
authorfpizlo@apple.com <fpizlo@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 1 Mar 2016 21:18:42 +0000 (21:18 +0000)
committerfpizlo@apple.com <fpizlo@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 1 Mar 2016 21:18:42 +0000 (21:18 +0000)
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.

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@197408 268f45cc-cd09-0410-ab3c-d52691b4dbfc

31 files changed:
LayoutTests/ChangeLog
LayoutTests/js/regress/script-tests/string-replace.js [new file with mode: 0644]
LayoutTests/js/regress/string-replace-expected.txt [new file with mode: 0644]
LayoutTests/js/regress/string-replace.html [new file with mode: 0644]
Source/JavaScriptCore/ChangeLog
Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj
Source/JavaScriptCore/bytecode/SpeculatedType.cpp
Source/JavaScriptCore/bytecode/SpeculatedType.h
Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h
Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp
Source/JavaScriptCore/dfg/DFGClobberize.h
Source/JavaScriptCore/dfg/DFGDoesGC.cpp
Source/JavaScriptCore/dfg/DFGFixupPhase.cpp
Source/JavaScriptCore/dfg/DFGNode.h
Source/JavaScriptCore/dfg/DFGNodeType.h
Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp
Source/JavaScriptCore/dfg/DFGSafeToExecute.h
Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp
Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h
Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp
Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp
Source/JavaScriptCore/dfg/DFGUseKind.cpp
Source/JavaScriptCore/dfg/DFGUseKind.h
Source/JavaScriptCore/ftl/FTLCapabilities.cpp
Source/JavaScriptCore/ftl/FTLLowerDFGToB3.cpp
Source/JavaScriptCore/jit/JITOperations.h
Source/JavaScriptCore/runtime/Intrinsic.h
Source/JavaScriptCore/runtime/JSType.h
Source/JavaScriptCore/runtime/RegExpObject.h
Source/JavaScriptCore/runtime/StringPrototype.cpp
Source/JavaScriptCore/runtime/StringPrototype.h

index c56ce20..8e9eb66 100644 (file)
@@ -1,3 +1,14 @@
+2016-02-29  Filip Pizlo  <fpizlo@apple.com>
+
+        Turn String.prototype.replace into an intrinsic
+        https://bugs.webkit.org/show_bug.cgi?id=154835
+
+        Reviewed by Michael Saboff.
+
+        * js/regress/script-tests/string-replace.js: Added.
+        * js/regress/string-replace-expected.txt: Added.
+        * js/regress/string-replace.html: Added.
+
 2016-03-01  Ryan Haddad  <ryanhaddad@apple.com>
 
         Rebaseline isplaylists/extent-includes tests for mac-wk1
diff --git a/LayoutTests/js/regress/script-tests/string-replace.js b/LayoutTests/js/regress/script-tests/string-replace.js
new file mode 100644 (file)
index 0000000..2a31929
--- /dev/null
@@ -0,0 +1,8 @@
+(function() {
+    var result;
+    for (var i = 0; i < 400000; ++i) {
+        result = "foo".replace(/f/, "b");
+    }
+    if (result != "boo")
+        throw "Error: bad result: "+ result;
+})();
diff --git a/LayoutTests/js/regress/string-replace-expected.txt b/LayoutTests/js/regress/string-replace-expected.txt
new file mode 100644 (file)
index 0000000..958555c
--- /dev/null
@@ -0,0 +1,10 @@
+JSRegress/string-replace
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS no exception thrown
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/js/regress/string-replace.html b/LayoutTests/js/regress/string-replace.html
new file mode 100644 (file)
index 0000000..282a0a5
--- /dev/null
@@ -0,0 +1,12 @@
+<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
+<html>
+<head>
+<script src="../../resources/js-test-pre.js"></script>
+</head>
+<body>
+<script src="../../resources/regress-pre.js"></script>
+<script src="script-tests/string-replace.js"></script>
+<script src="../../resources/regress-post.js"></script>
+<script src="../../resources/js-test-post.js"></script>
+</body>
+</html>
index 2d80557..b1d1c1d 100644 (file)
@@ -1,3 +1,94 @@
+2016-02-29  Filip Pizlo  <fpizlo@apple.com>
+
+        Turn String.prototype.replace into an intrinsic
+        https://bugs.webkit.org/show_bug.cgi?id=154835
+
+        Reviewed by Michael Saboff.
+
+        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:
+
 2016-03-01  Commit Queue  <commit-queue@webkit.org>
 
         Unreviewed, rolling out r197056.
index 307e52e..e1b98b3 100644 (file)
                0F24E54317EA9F5900ABB217 /* FPRInfo.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F24E53E17EA9F5900ABB217 /* FPRInfo.h */; settings = {ATTRIBUTES = (Private, ); }; };
                0F24E54417EA9F5900ABB217 /* GPRInfo.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F24E53F17EA9F5900ABB217 /* GPRInfo.h */; settings = {ATTRIBUTES = (Private, ); }; };
                0F24E54C17EE274900ABB217 /* JITOperations.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F24E54517EE274900ABB217 /* JITOperations.cpp */; };
-               0F24E54D17EE274900ABB217 /* JITOperations.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F24E54617EE274900ABB217 /* JITOperations.h */; };
+               0F24E54D17EE274900ABB217 /* JITOperations.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F24E54617EE274900ABB217 /* JITOperations.h */; settings = {ATTRIBUTES = (Private, ); }; };
                0F24E54F17EE274900ABB217 /* TempRegisterSet.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F24E54817EE274900ABB217 /* TempRegisterSet.h */; settings = {ATTRIBUTES = (Private, ); }; };
                0F24E55017EE274900ABB217 /* Repatch.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F24E54917EE274900ABB217 /* Repatch.cpp */; };
                0F24E55117EE274900ABB217 /* Repatch.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F24E54A17EE274900ABB217 /* Repatch.h */; };
                0F5A52D017ADD717008ECB2D /* CopyToken.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F5A52CF17ADD717008ECB2D /* CopyToken.h */; settings = {ATTRIBUTES = (Private, ); }; };
                0F5A6283188C98D40072C9DF /* FTLValueRange.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F5A6281188C98D40072C9DF /* FTLValueRange.cpp */; };
                0F5A6284188C98D40072C9DF /* FTLValueRange.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F5A6282188C98D40072C9DF /* FTLValueRange.h */; settings = {ATTRIBUTES = (Private, ); }; };
-               0F5B4A331C84F0D600F1B17E /* SlowPathReturnType.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F5B4A321C84F0D600F1B17E /* SlowPathReturnType.h */; };
+               0F5B4A331C84F0D600F1B17E /* SlowPathReturnType.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F5B4A321C84F0D600F1B17E /* SlowPathReturnType.h */; settings = {ATTRIBUTES = (Private, ); }; };
                0F5D085D1B8CF99D001143B4 /* DFGNodeOrigin.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F5D085C1B8CF99D001143B4 /* DFGNodeOrigin.cpp */; };
                0F5EF91E16878F7A003E5C25 /* JITThunks.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F5EF91B16878F78003E5C25 /* JITThunks.cpp */; };
                0F5EF91F16878F7D003E5C25 /* JITThunks.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F5EF91C16878F78003E5C25 /* JITThunks.h */; settings = {ATTRIBUTES = (Private, ); }; };
index ca9514c..af67f45 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2011-2013, 2015 Apple Inc. All rights reserved.
+ * Copyright (C) 2011-2013, 2015-2016 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -141,6 +141,11 @@ void dumpSpeculation(PrintStream& out, SpeculatedType value)
                 myOut.print("Stringobject");
             else
                 isTop = false;
+    
+            if (value & SpecRegExpObject)
+                myOut.print("Regexpobject");
+            else
+                isTop = false;
         }
 
         if ((value & SpecString) == SpecString)
@@ -257,6 +262,8 @@ static const char* speculationToAbbreviatedString(SpeculatedType prediction)
         return "<ScopedArguments>";
     if (isStringObjectSpeculation(prediction))
         return "<StringObject>";
+    if (isRegExpObjectSpeculation(prediction))
+        return "<RegExpObject>";
     if (isStringOrStringObjectSpeculation(prediction))
         return "<StringOrStringObject>";
     if (isObjectSpeculation(prediction))
@@ -336,6 +343,9 @@ SpeculatedType speculationFromClassInfo(const ClassInfo* classInfo)
     
     if (classInfo == StringObject::info())
         return SpecStringObject;
+
+    if (classInfo == RegExpObject::info())
+        return SpecRegExpObject;
     
     if (classInfo->isSubClassOf(JSFunction::info()))
         return SpecFunction;
index 1abb643..3326ed8 100644 (file)
@@ -55,25 +55,26 @@ static const SpeculatedType SpecTypedArrayView     = SpecInt8Array | SpecInt16Ar
 static const SpeculatedType SpecDirectArguments    = 1u << 12; // It's definitely a DirectArguments object.
 static const SpeculatedType SpecScopedArguments    = 1u << 13; // It's definitely a ScopedArguments object.
 static const SpeculatedType SpecStringObject       = 1u << 14; // It's definitely a StringObject.
-static const SpeculatedType SpecObjectOther        = 1u << 15; // It's definitely an object but not JSFinalObject, JSArray, or JSFunction.
-static const SpeculatedType SpecObject             = SpecFinalObject | SpecArray | SpecFunction | SpecTypedArrayView | SpecDirectArguments | SpecScopedArguments | SpecStringObject | SpecObjectOther; // Bitmask used for testing for any kind of object prediction.
-static const SpeculatedType SpecStringIdent        = 1u << 16; // It's definitely a JSString, and it's an identifier.
-static const SpeculatedType SpecStringVar          = 1u << 17; // It's definitely a JSString, and it's not an identifier.
+static const SpeculatedType SpecRegExpObject       = 1u << 15; // It's definitely a RegExpObject (and not any subclass of RegExpObject).
+static const SpeculatedType SpecObjectOther        = 1u << 16; // It's definitely an object but not JSFinalObject, JSArray, or JSFunction.
+static const SpeculatedType SpecObject             = SpecFinalObject | SpecArray | SpecFunction | SpecTypedArrayView | SpecDirectArguments | SpecScopedArguments | SpecStringObject | SpecRegExpObject | SpecObjectOther; // Bitmask used for testing for any kind of object prediction.
+static const SpeculatedType SpecStringIdent        = 1u << 17; // It's definitely a JSString, and it's an identifier.
+static const SpeculatedType SpecStringVar          = 1u << 18; // It's definitely a JSString, and it's not an identifier.
 static const SpeculatedType SpecString             = SpecStringIdent | SpecStringVar; // It's definitely a JSString.
-static const SpeculatedType SpecSymbol             = 1u << 18; // It's definitely a Symbol.
-static const SpeculatedType SpecCellOther          = 1u << 19; // It's definitely a JSCell but not a subclass of JSObject and definitely not a JSString or a Symbol. FIXME: This shouldn't be part of heap-top or bytecode-top. https://bugs.webkit.org/show_bug.cgi?id=133078
+static const SpeculatedType SpecSymbol             = 1u << 19; // It's definitely a Symbol.
+static const SpeculatedType SpecCellOther          = 1u << 20; // It's definitely a JSCell but not a subclass of JSObject and definitely not a JSString or a Symbol. FIXME: This shouldn't be part of heap-top or bytecode-top. https://bugs.webkit.org/show_bug.cgi?id=133078
 static const SpeculatedType SpecCell               = SpecObject | SpecString | SpecSymbol | SpecCellOther; // It's definitely a JSCell.
-static const SpeculatedType SpecBoolInt32          = 1u << 20; // It's definitely an Int32 with value 0 or 1.
-static const SpeculatedType SpecNonBoolInt32       = 1u << 21; // It's definitely an Int32 with value other than 0 or 1.
+static const SpeculatedType SpecBoolInt32          = 1u << 21; // It's definitely an Int32 with value 0 or 1.
+static const SpeculatedType SpecNonBoolInt32       = 1u << 22; // It's definitely an Int32 with value other than 0 or 1.
 static const SpeculatedType SpecInt32              = SpecBoolInt32 | SpecNonBoolInt32; // It's definitely an Int32.
-static const SpeculatedType SpecInt52              = 1u << 22; // It's definitely an Int52 and we intend it to unbox it.
+static const SpeculatedType SpecInt52              = 1u << 23; // It's definitely an Int52 and we intend it to unbox it.
 static const SpeculatedType SpecMachineInt         = SpecInt32 | SpecInt52; // It's something that we can do machine int arithmetic on.
-static const SpeculatedType SpecInt52AsDouble      = 1u << 23; // It's definitely an Int52 and it's inside a double.
+static const SpeculatedType SpecInt52AsDouble      = 1u << 24; // It's definitely an Int52 and it's inside a double.
 static const SpeculatedType SpecInteger            = SpecMachineInt | SpecInt52AsDouble; // It's definitely some kind of integer.
-static const SpeculatedType SpecNonIntAsDouble     = 1u << 24; // It's definitely not an Int52 but it's a real number and it's a double.
+static const SpeculatedType SpecNonIntAsDouble     = 1u << 25; // It's definitely not an Int52 but it's a real number and it's a double.
 static const SpeculatedType SpecDoubleReal         = SpecNonIntAsDouble | SpecInt52AsDouble; // It's definitely a non-NaN double.
-static const SpeculatedType SpecDoublePureNaN      = 1u << 25; // It's definitely a NaN that is sae to tag (i.e. pure).
-static const SpeculatedType SpecDoubleImpureNaN    = 1u << 26; // It's definitely a NaN that is unsafe to tag (i.e. impure).
+static const SpeculatedType SpecDoublePureNaN      = 1u << 26; // It's definitely a NaN that is sae to tag (i.e. pure).
+static const SpeculatedType SpecDoubleImpureNaN    = 1u << 27; // It's definitely a NaN that is unsafe to tag (i.e. impure).
 static const SpeculatedType SpecDoubleNaN          = SpecDoublePureNaN | SpecDoubleImpureNaN; // It's definitely some kind of NaN.
 static const SpeculatedType SpecBytecodeDouble     = SpecDoubleReal | SpecDoublePureNaN; // It's either a non-NaN or a NaN double, but it's definitely not impure NaN.
 static const SpeculatedType SpecFullDouble         = SpecDoubleReal | SpecDoubleNaN; // It's either a non-NaN or a NaN double.
@@ -81,12 +82,12 @@ static const SpeculatedType SpecBytecodeRealNumber = SpecInt32 | SpecDoubleReal;
 static const SpeculatedType SpecFullRealNumber     = SpecMachineInt | SpecDoubleReal; // It's either an Int32 or a DoubleReal, or a Int52.
 static const SpeculatedType SpecBytecodeNumber     = SpecInt32 | SpecBytecodeDouble; // It's either an Int32 or a Double, and the Double cannot be an impure NaN.
 static const SpeculatedType SpecFullNumber         = SpecMachineInt | SpecFullDouble; // It's either an Int32, Int52, or a Double, and the Double can be impure NaN.
-static const SpeculatedType SpecBoolean            = 1u << 27; // It's definitely a Boolean.
-static const SpeculatedType SpecOther              = 1u << 28; // It's definitely either Null or Undefined.
+static const SpeculatedType SpecBoolean            = 1u << 28; // It's definitely a Boolean.
+static const SpeculatedType SpecOther              = 1u << 29; // It's definitely either Null or Undefined.
 static const SpeculatedType SpecMisc               = SpecBoolean | SpecOther; // It's definitely either a boolean, Null, or Undefined.
 static const SpeculatedType SpecHeapTop            = SpecCell | SpecBytecodeNumber | SpecMisc; // It can be any of the above, except for SpecInt52 and SpecDoubleImpureNaN.
-static const SpeculatedType SpecPrimitive          = SpecString | SpecSymbol | SpecBytecodeNumber | SpecMisc; // It's any non-Object JSValue. This is (~SpecObject & SpecHeapTop)
-static const SpeculatedType SpecEmpty              = 1u << 29; // It's definitely an empty value marker.
+static const SpeculatedType SpecPrimitive          = SpecString | SpecSymbol | SpecBytecodeNumber | SpecMisc; // It's any non-Object JSValue.
+static const SpeculatedType SpecEmpty              = 1u << 30; // It's definitely an empty value marker.
 static const SpeculatedType SpecBytecodeTop        = SpecHeapTop | SpecEmpty; // It can be any of the above, except for SpecInt52 and SpecDoubleImpureNaN. Corresponds to what could be found in a bytecode local.
 static const SpeculatedType SpecFullTop            = SpecBytecodeTop | SpecFullNumber; // It can be anything that bytecode could see plus exotic encodings of numbers.
 
@@ -265,6 +266,11 @@ inline bool isStringOrStringObjectSpeculation(SpeculatedType value)
     return !!value && !(value & ~(SpecString | SpecStringObject));
 }
 
+inline bool isRegExpObjectSpeculation(SpeculatedType value)
+{
+    return value == SpecRegExpObject;
+}
+
 inline bool isBoolInt32Speculation(SpeculatedType value)
 {
     return value == SpecBoolInt32;
index a541ef2..338a903 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2013-2015 Apple Inc. All rights reserved.
+ * Copyright (C) 2013-2016 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -1561,6 +1561,16 @@ bool AbstractInterpreter<AbstractStateType>::executeEffects(unsigned clobberLimi
         forNode(node).setType(SpecBoolean);
         break;
             
+    case StringReplace:
+        if (node->child1().useKind() == StringUse
+            && node->child2().useKind() == RegExpObjectUse
+            && node->child3().useKind() == StringUse) {
+            // This doesn't clobber the world. It just reads and writes regexp state.
+        } else
+            clobberWorld(node->origin.semantic, clobberLimit);
+        forNode(node).set(m_graph, m_graph.m_vm.stringStructure.get());
+        break;
+
     case Jump:
         break;
             
@@ -1693,7 +1703,7 @@ bool AbstractInterpreter<AbstractStateType>::executeEffects(unsigned clobberLimi
             m_graph.globalObjectFor(node->origin.semantic)->typedArrayStructure(
                 node->typedArrayType()));
         break;
-            
+        
     case NewRegexp:
         forNode(node).set(m_graph, m_graph.globalObjectFor(node->origin.semantic)->regExpStructure());
         break;
index bbc0521..2f3f12d 100644 (file)
@@ -2188,6 +2188,23 @@ bool ByteCodeParser::handleIntrinsicCall(int resultOperand, Intrinsic intrinsic,
         
         return true;
     }
+
+    case StringPrototypeReplaceIntrinsic: {
+        if (!isFTL(m_graph.m_plan.mode)) {
+            // This is a marginally profitable intrinsic. We've only the work to make it an
+            // intrinsic on the fourth tier.
+            return false;
+        }
+
+        if (argumentCountIncludingThis != 3)
+            return false;
+
+        insertChecks();
+        Node* result = addToGraph(StringReplace, OpInfo(0), OpInfo(prediction), get(virtualRegisterForArgument(0, registerOffset)), get(virtualRegisterForArgument(1, registerOffset)), get(virtualRegisterForArgument(2, registerOffset)));
+        set(VirtualRegister(resultOperand), result);
+        return true;
+    }
+        
     case RoundIntrinsic:
     case FloorIntrinsic:
     case CeilIntrinsic: {
index 458086e..4612177 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2013-2015 Apple Inc. All rights reserved.
+ * Copyright (C) 2013-2016 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -1072,6 +1072,18 @@ void clobberize(Graph& graph, Node* node, const ReadFunctor& read, const WriteFu
         write(RegExpState);
         return;
 
+    case StringReplace:
+        if (node->child1().useKind() == StringUse
+            && node->child2().useKind() == RegExpObjectUse
+            && node->child3().useKind() == StringUse) {
+            read(RegExpState);
+            write(RegExpState);
+            return;
+        }
+        read(World);
+        write(Heap);
+        return;
+
     case StringCharAt:
         if (node->arrayMode().isOutOfBounds()) {
             read(World);
index 4521adb..eec32fe 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2014, 2015 Apple Inc. All rights reserved.
+ * Copyright (C) 2014-2016 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -262,6 +262,7 @@ bool doesGC(Graph& graph, Node* node)
     case MaterializeNewObject:
     case MaterializeCreateActivation:
     case StrCat:
+    case StringReplace:
         return true;
         
     case MultiPutByOffset:
index f01c146..af86a46 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2012-2015 Apple Inc. All rights reserved.
+ * Copyright (C) 2012-2016 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -883,6 +883,18 @@ private:
             fixEdge<CellUse>(node->child2());
             break;
         }
+
+        case StringReplace: {
+            if (node->child1()->shouldSpeculateString()
+                && node->child2()->shouldSpeculateRegExpObject()
+                && node->child3()->shouldSpeculateString()) {
+                fixEdge<StringUse>(node->child1());
+                fixEdge<RegExpObjectUse>(node->child2());
+                fixEdge<StringUse>(node->child3());
+                break;
+            }
+            break;
+        }
             
         case Branch: {
             if (node->child1()->shouldSpeculateBoolean()) {
index 5499deb..7b77132 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2011-2015 Apple Inc. All rights reserved.
+ * Copyright (C) 2011-2016 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -1358,6 +1358,7 @@ struct Node {
         case RegExpTest:
         case GetGlobalVar:
         case GetGlobalLexicalVariable:
+        case StringReplace:
             return true;
         default:
             return false;
@@ -1966,6 +1967,11 @@ struct Node {
         return isStringOrStringObjectSpeculation(prediction());
     }
 
+    bool shouldSpeculateRegExpObject()
+    {
+        return isRegExpObjectSpeculation(prediction());
+    }
+    
     bool shouldSpeculateSymbol()
     {
         return isSymbolSpeculation(prediction());
index 71c075a..4035dd9 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2012-2015 Apple Inc. All rights reserved.
+ * Copyright (C) 2012-2016 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -233,6 +233,7 @@ namespace JSC { namespace DFG {
     /* Optimizations for regular expression matching. */\
     macro(RegExpExec, NodeResultJS | NodeMustGenerate) \
     macro(RegExpTest, NodeResultJS | NodeMustGenerate) \
+    macro(StringReplace, NodeResultJS | NodeMustGenerate) \
     \
     /* Optimizations for string access */ \
     macro(StringCharCodeAt, NodeResultInt32) \
index 4596053..9283ae3 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2011-2015 Apple Inc. All rights reserved.
+ * Copyright (C) 2011-2016 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -177,6 +177,7 @@ private:
         case ArrayPush:
         case RegExpExec:
         case RegExpTest:
+        case StringReplace:
         case GetById:
         case GetByIdFlush:
         case GetByOffset:
@@ -572,7 +573,11 @@ private:
             break;
         }
             
-        case NewRegexp:
+        case NewRegexp: {
+            changed |= setPrediction(SpecRegExpObject);
+            break;
+        }
+            
         case CreateActivation: {
             changed |= setPrediction(SpecObjectOther);
             break;
index 98592c7..1924978 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2013-2015 Apple Inc. All rights reserved.
+ * Copyright (C) 2013-2016 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -57,6 +57,7 @@ public:
         case ObjectUse:
         case FunctionUse:
         case FinalObjectUse:
+        case RegExpObjectUse:
         case ObjectOrOtherUse:
         case StringIdentUse:
         case StringUse:
@@ -330,6 +331,7 @@ bool safeToExecute(AbstractStateType& state, Graph& graph, Node* node)
     case GetMyArgumentByVal:
     case ForwardVarargs:
     case CopyRest:
+    case StringReplace:
         return true;
 
     case BottomValue:
index f03af97..ed82a04 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2011-2015 Apple Inc. All rights reserved.
+ * Copyright (C) 2011-2016 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -6623,6 +6623,15 @@ void SpeculativeJIT::speculateFinalObject(Edge edge)
     speculateCellType(edge, operand.gpr(), SpecFinalObject, FinalObjectType);
 }
 
+void SpeculativeJIT::speculateRegExpObject(Edge edge)
+{
+    if (!needsTypeCheck(edge, SpecRegExpObject))
+        return;
+    
+    SpeculateCellOperand operand(this, edge);
+    speculateCellType(edge, operand.gpr(), SpecRegExpObject, RegExpObjectType);
+}
+
 void SpeculativeJIT::speculateObjectOrOther(Edge edge)
 {
     if (!needsTypeCheck(edge, SpecObject | SpecOther))
@@ -6886,6 +6895,9 @@ void SpeculativeJIT::speculate(Node*, Edge edge)
     case FinalObjectUse:
         speculateFinalObject(edge);
         break;
+    case RegExpObjectUse:
+        speculateRegExpObject(edge);
+        break;
     case ObjectOrOtherUse:
         speculateObjectOrOther(edge);
         break;
index 5d6fba4..20036fa 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2011-2015 Apple Inc. All rights reserved.
+ * Copyright (C) 2011-2016 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -2470,6 +2470,7 @@ public:
     void speculateObject(Edge);
     void speculateFunction(Edge);
     void speculateFinalObject(Edge);
+    void speculateRegExpObject(Edge);
     void speculateObjectOrOther(Edge);
     void speculateString(Edge edge, GPRReg cell);
     void speculateStringIdentAndLoadStorage(Edge edge, GPRReg string, GPRReg storage);
index 2009a02..e39237b 100644 (file)
@@ -4828,6 +4828,7 @@ void SpeculativeJIT::compile(Node* node)
     case KillStack:
     case GetStack:
     case GetMyArgumentByVal:
+    case StringReplace:
         DFG_CRASH(m_jit.graph(), node, "unexpected node in DFG backend");
         break;
     }
index 38cb2cd..06b4008 100644 (file)
@@ -4882,6 +4882,7 @@ void SpeculativeJIT::compile(Node* node)
     case PutStack:
     case KillStack:
     case GetStack:
+    case StringReplace:
         DFG_CRASH(m_jit.graph(), node, "Unexpected node");
         break;
     }
index 86a1bda..3b9ad74 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2013-2015 Apple Inc. All rights reserved.
+ * Copyright (C) 2013-2016 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -91,6 +91,9 @@ void printInternal(PrintStream& out, UseKind useKind)
     case FinalObjectUse:
         out.print("FinalObject");
         return;
+    case RegExpObjectUse:
+        out.print("RegExpObject");
+        return;
     case ObjectOrOtherUse:
         out.print("ObjectOrOther");
         return;
index 9b5143b..816c19e 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2013-2015 Apple Inc. All rights reserved.
+ * Copyright (C) 2013-2016 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -55,6 +55,7 @@ enum UseKind {
     ObjectUse,
     FunctionUse,
     FinalObjectUse,
+    RegExpObjectUse,
     ObjectOrOtherUse,
     StringIdentUse,
     StringUse,
@@ -117,6 +118,8 @@ inline SpeculatedType typeFilterFor(UseKind useKind)
         return SpecFunction;
     case FinalObjectUse:
         return SpecFinalObject;
+    case RegExpObjectUse:
+        return SpecRegExpObject;
     case ObjectOrOtherUse:
         return SpecObject | SpecOther;
     case StringIdentUse:
@@ -208,6 +211,7 @@ inline bool isCell(UseKind kind)
     case ObjectUse:
     case FunctionUse:
     case FinalObjectUse:
+    case RegExpObjectUse:
     case StringIdentUse:
     case StringUse:
     case KnownStringUse:
index d715693..e49b11e 100644 (file)
@@ -223,6 +223,7 @@ inline CapabilityLevel canCompile(Node* node)
     case RegExpExec:
     case RegExpTest:
     case NewRegexp:
+    case StringReplace:
         // These are OK.
         break;
 
@@ -465,6 +466,7 @@ CapabilityLevel canCompile(Graph& graph)
                 case StringOrStringObjectUse:
                 case SymbolUse:
                 case FinalObjectUse:
+                case RegExpObjectUse:
                 case NotCellUse:
                 case OtherUse:
                 case MiscUse:
index dd76f26..5f89d2c 100644 (file)
@@ -923,6 +923,9 @@ private:
         case NewRegexp:
             compileNewRegexp();
             break;
+        case StringReplace:
+            compileStringReplace();
+            break;
 
         case PhantomLocal:
         case LoopHint:
@@ -6459,6 +6462,33 @@ private:
         setJSValue(result);
     }
 
+    void compileStringReplace()
+    {
+        if (m_node->child1().useKind() == StringUse
+            && m_node->child2().useKind() == RegExpObjectUse
+            && m_node->child3().useKind() == StringUse) {
+            
+            LValue string = lowString(m_node->child1());
+            LValue regExp = lowCell(m_node->child2());
+            speculateRegExpObject(m_node->child2(), regExp);
+            LValue replace = lowString(m_node->child3());
+
+            LValue result = vmCall(
+                Int64, m_out.operation(operationStringProtoFuncReplaceRegExpString),
+                m_callFrame, string, regExp, replace);
+
+            setJSValue(result);
+            return;
+        }
+        
+        LValue result = vmCall(
+            Int64, m_out.operation(operationStringProtoFuncReplaceGeneric), m_callFrame,
+            lowJSValue(m_node->child1()), lowJSValue(m_node->child2()),
+            lowJSValue(m_node->child3()));
+
+        setJSValue(result);
+    }
+
     LValue didOverflowStack()
     {
         // This does a very simple leaf function analysis. The invariant of FTL call
@@ -9285,6 +9315,9 @@ private:
         case FinalObjectUse:
             speculateFinalObject(edge);
             break;
+        case RegExpObjectUse:
+            speculateRegExpObject(edge);
+            break;
         case StringUse:
             speculateString(edge);
             break;
@@ -9561,6 +9594,17 @@ private:
         speculateFinalObject(edge, lowCell(edge));
     }
     
+    void speculateRegExpObject(Edge edge, LValue cell)
+    {
+        FTL_TYPE_CHECK(
+            jsValueValue(cell), edge, SpecRegExpObject, isNotType(cell, RegExpObjectType));
+    }
+    
+    void speculateRegExpObject(Edge edge)
+    {
+        speculateRegExpObject(edge, lowCell(edge));
+    }
+    
     void speculateString(Edge edge, LValue cell)
     {
         FTL_TYPE_CHECK(jsValueValue(cell), edge, SpecString | ~SpecCell, isNotString(cell));
index 71bb0c5..8cbe0e4 100644 (file)
@@ -254,6 +254,7 @@ typedef char* JIT_OPERATION (*P_JITOperation_EZZ)(ExecState*, int32_t, int32_t);
 typedef SlowPathReturnType JIT_OPERATION (*Sprt_JITOperation_ECli)(ExecState*, CallLinkInfo*);
 typedef StringImpl* JIT_OPERATION (*T_JITOperation_EJss)(ExecState*, JSString*);
 typedef JSString* JIT_OPERATION (*Jss_JITOperation_EZ)(ExecState*, int32_t);
+typedef JSString* JIT_OPERATION (*Jss_JITOperation_EJJJ)(ExecState*, EncodedJSValue, EncodedJSValue, EncodedJSValue);
 
 // This method is used to lookup an exception hander, keyed by faultLocation, which is
 // the return location from one of the calls out to one of the helper operations above.
index d6ccc1b..218d2ef 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2011 Apple Inc. All rights reserved.
+ * Copyright (C) 2011, 2016 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -52,6 +52,7 @@ enum Intrinsic {
     RegExpExecIntrinsic,
     RegExpTestIntrinsic,
     StringPrototypeValueOfIntrinsic,
+    StringPrototypeReplaceIntrinsic,
     IMulIntrinsic,
     RandomIntrinsic,
     FRoundIntrinsic,
index 6442dde..9954a63 100644 (file)
@@ -1,5 +1,5 @@
 /*
- *  Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011, 2015 Apple Inc. All rights reserved.
+ *  Copyright (C) 2006-2011, 2015-2016 Apple Inc. All rights reserved.
  *
  *  This library is free software; you can redistribute it and/or
  *  modify it under the terms of the GNU Library General Public
@@ -77,7 +77,7 @@ enum JSType : uint8_t {
 
     GlobalObjectType,
     ClosureObjectType,
-
+    RegExpObjectType,
     ProxyObjectType,
 
     LastJSCObjectType = ProxyObjectType,
index a1f571d..4901de0 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *  Copyright (C) 1999-2000 Harri Porten (porten@kde.org)
- *  Copyright (C) 2003, 2007, 2008, 2012 Apple Inc. All Rights Reserved.
+ *  Copyright (C) 2003, 2007, 2008, 2012, 2016 Apple Inc. All Rights Reserved.
  *
  *  This library is free software; you can redistribute it and/or
  *  modify it under the terms of the GNU Lesser General Public
@@ -71,7 +71,7 @@ public:
 
     static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
     {
-        return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info());
+        return Structure::create(vm, globalObject, prototype, TypeInfo(RegExpObjectType, StructureFlags), info());
     }
 
 protected:
index d830255..22d2682 100644 (file)
@@ -135,7 +135,7 @@ void StringPrototype::finishCreation(VM& vm, JSGlobalObject* globalObject, JSStr
     JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION("lastIndexOf", stringProtoFuncLastIndexOf, DontEnum, 1);
     JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION("match", stringProtoFuncMatch, DontEnum, 1);
     JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION("repeat", stringProtoFuncRepeat, DontEnum, 1);
-    JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION("replace", stringProtoFuncReplace, DontEnum, 2);
+    JSC_NATIVE_INTRINSIC_FUNCTION_WITHOUT_TRANSITION("replace", stringProtoFuncReplace, DontEnum, 2, StringPrototypeReplaceIntrinsic);
     JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION("slice", stringProtoFuncSlice, DontEnum, 2);
     JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION("split", stringProtoFuncSplit, DontEnum, 2);
     JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION("substr", stringProtoFuncSubstr, DontEnum, 2);
@@ -484,18 +484,10 @@ static NEVER_INLINE EncodedJSValue removeUsingRegExpSearch(ExecState* exec, JSSt
     return JSValue::encode(jsSpliceSubstrings(exec, string, source, sourceRanges.data(), sourceRanges.size()));
 }
 
-static NEVER_INLINE EncodedJSValue replaceUsingRegExpSearch(ExecState* exec, JSString* string, JSValue searchValue)
+static ALWAYS_INLINE EncodedJSValue replaceUsingRegExpSearch(
+    ExecState* exec, JSString* string, JSValue searchValue, CallData& callData, CallType callType,
+    String& replacementString, JSValue replaceValue)
 {
-    JSValue replaceValue = exec->argument(1);
-    String replacementString;
-    CallData callData;
-    CallType callType = getCallData(replaceValue, callData);
-    if (callType == CallTypeNone) {
-        replacementString = replaceValue.toString(exec)->value(exec);
-        if (exec->hadException())
-            return JSValue::encode(jsUndefined());
-    }
-
     const String& source = string->value(exec);
     unsigned sourceLen = source.length();
     if (exec->hadException())
@@ -672,7 +664,31 @@ static NEVER_INLINE EncodedJSValue replaceUsingRegExpSearch(ExecState* exec, JSS
     return JSValue::encode(jsSpliceSubstringsWithSeparators(exec, string, source, sourceRanges.data(), sourceRanges.size(), replacements.data(), replacements.size()));
 }
 
-static inline EncodedJSValue replaceUsingStringSearch(ExecState* exec, JSString* jsString, JSValue searchValue)
+EncodedJSValue JIT_OPERATION operationStringProtoFuncReplaceRegExpString(
+    ExecState* exec, JSString* thisValue, RegExpObject* searchValue, JSString* replaceString)
+{
+    CallData callData;
+    String replacementString = replaceString->value(exec);
+    return replaceUsingRegExpSearch(
+        exec, thisValue, searchValue, callData, CallTypeNone, replacementString, replaceString);
+}
+
+static ALWAYS_INLINE EncodedJSValue replaceUsingRegExpSearch(ExecState* exec, JSString* string, JSValue searchValue, JSValue replaceValue)
+{
+    String replacementString;
+    CallData callData;
+    CallType callType = getCallData(replaceValue, callData);
+    if (callType == CallTypeNone) {
+        replacementString = replaceValue.toString(exec)->value(exec);
+        if (exec->hadException())
+            return JSValue::encode(jsUndefined());
+    }
+
+    return replaceUsingRegExpSearch(
+        exec, string, searchValue, callData, callType, replacementString, replaceValue);
+}
+
+static ALWAYS_INLINE EncodedJSValue replaceUsingStringSearch(ExecState* exec, JSString* jsString, JSValue searchValue, JSValue replaceValue)
 {
     const String& string = jsString->value(exec);
     String searchString = searchValue.toString(exec)->value(exec);
@@ -684,7 +700,6 @@ static inline EncodedJSValue replaceUsingStringSearch(ExecState* exec, JSString*
     if (matchStart == notFound)
         return JSValue::encode(jsString);
 
-    JSValue replaceValue = exec->argument(1);
     CallData callData;
     CallType callType = getCallData(replaceValue, callData);
     if (callType != CallTypeNone) {
@@ -787,17 +802,37 @@ EncodedJSValue JSC_HOST_CALL stringProtoFuncRepeat(ExecState* exec)
     return JSValue::encode(ropeBuilder.release());
 }
 
-EncodedJSValue JSC_HOST_CALL stringProtoFuncReplace(ExecState* exec)
+ALWAYS_INLINE EncodedJSValue replace(
+    ExecState* exec, JSString* string, JSValue searchValue, JSValue replaceValue)
+{
+    if (searchValue.inherits(RegExpObject::info()))
+        return replaceUsingRegExpSearch(exec, string, searchValue, replaceValue);
+    return replaceUsingStringSearch(exec, string, searchValue, replaceValue);
+}
+
+ALWAYS_INLINE EncodedJSValue replace(
+    ExecState* exec, JSValue thisValue, JSValue searchValue, JSValue replaceValue)
 {
-    JSValue thisValue = exec->thisValue();
     if (!checkObjectCoercible(thisValue))
         return throwVMTypeError(exec);
     JSString* string = thisValue.toString(exec);
-    JSValue searchValue = exec->argument(0);
+    if (exec->hadException())
+        return JSValue::encode(jsUndefined());
+    return replace(exec, string, searchValue, replaceValue);
+}
 
-    if (searchValue.inherits(RegExpObject::info()))
-        return replaceUsingRegExpSearch(exec, string, searchValue);
-    return replaceUsingStringSearch(exec, string, searchValue);
+EncodedJSValue JSC_HOST_CALL stringProtoFuncReplace(ExecState* exec)
+{
+    return replace(exec, exec->thisValue(), exec->argument(0), exec->argument(1));
+}
+
+EncodedJSValue JIT_OPERATION operationStringProtoFuncReplaceGeneric(
+    ExecState* exec, EncodedJSValue thisValue, EncodedJSValue searchValue,
+    EncodedJSValue replaceValue)
+{
+    return replace(
+        exec, JSValue::decode(thisValue), JSValue::decode(searchValue),
+        JSValue::decode(replaceValue));
 }
 
 EncodedJSValue JSC_HOST_CALL stringProtoFuncToString(ExecState* exec)
index 54a78d9..b94da81 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *  Copyright (C) 1999-2000 Harri Porten (porten@kde.org)
- *  Copyright (C) 2007, 2008, 2013 Apple Inc. All rights reserved.
+ *  Copyright (C) 2007, 2008, 2013, 2016 Apple Inc. All rights reserved.
  *
  *  This library is free software; you can redistribute it and/or
  *  modify it under the terms of the GNU Lesser General Public
 #ifndef StringPrototype_h
 #define StringPrototype_h
 
+#include "JITOperations.h"
 #include "StringObject.h"
 
 namespace JSC {
 
 class ObjectPrototype;
+class RegExpObject;
 
 class StringPrototype : public StringObject {
 private:
@@ -51,6 +53,13 @@ private:
     static bool getOwnPropertySlot(JSObject*, ExecState*, PropertyName, PropertySlot&);
 };
 
+EncodedJSValue JIT_OPERATION operationStringProtoFuncReplaceGeneric(
+    ExecState* exec, EncodedJSValue thisValue, EncodedJSValue searchValue,
+    EncodedJSValue replaceValue);
+
+EncodedJSValue JIT_OPERATION operationStringProtoFuncReplaceRegExpString(
+    ExecState* exec, JSString* thisValue, RegExpObject* searchValue, JSString* replaceValue);
+
 } // namespace JSC
 
 #endif // StringPrototype_h