- Revision
- 197416
- Author
- fpi...@apple.com
- Date
- 2016-03-01 15:35:05 -0800 (Tue, 01 Mar 2016)
Log Message
FTL should simplify StringReplace with an empty replacement string
https://bugs.webkit.org/show_bug.cgi?id=154871
Reviewed by Michael Saboff.
This is a simple and hugely profitable change. If we do a string.replace(/things/, ""), then
this calls directly into StringPrototype's replace-with-empty-string logic instead of going
through stuff that does checks before reaching that same conclusion.
This speeds up Octane/regexp by about 6-10%. It also speeds up the attached microbenchmark by
about 7%.
* ftl/FTLLowerDFGToB3.cpp:
(JSC::FTL::DFG::LowerDFGToB3::compileStringReplace):
* runtime/StringPrototype.cpp:
(JSC::jsSpliceSubstringsWithSeparators):
(JSC::removeUsingRegExpSearch):
(JSC::replaceUsingRegExpSearch):
(JSC::operationStringProtoFuncReplaceRegExpEmptyStr):
(JSC::operationStringProtoFuncReplaceRegExpString):
* runtime/StringPrototype.h:
Modified Paths
Diff
Modified: trunk/LayoutTests/js/regress/script-tests/string-replace.js (197415 => 197416)
--- trunk/LayoutTests/js/regress/script-tests/string-replace.js 2016-03-01 23:33:36 UTC (rev 197415)
+++ trunk/LayoutTests/js/regress/script-tests/string-replace.js 2016-03-01 23:35:05 UTC (rev 197416)
@@ -1,7 +1,7 @@
(function() {
var result;
for (var i = 0; i < 400000; ++i) {
- result = "foo".replace(/f/, "b");
+ result = "foo".replace(/f/g, "b");
}
if (result != "boo")
throw "Error: bad result: "+ result;
Modified: trunk/Source/_javascript_Core/ChangeLog (197415 => 197416)
--- trunk/Source/_javascript_Core/ChangeLog 2016-03-01 23:33:36 UTC (rev 197415)
+++ trunk/Source/_javascript_Core/ChangeLog 2016-03-01 23:35:05 UTC (rev 197416)
@@ -1,3 +1,27 @@
+2016-03-01 Filip Pizlo <fpi...@apple.com>
+
+ FTL should simplify StringReplace with an empty replacement string
+ https://bugs.webkit.org/show_bug.cgi?id=154871
+
+ Reviewed by Michael Saboff.
+
+ This is a simple and hugely profitable change. If we do a string.replace(/things/, ""), then
+ this calls directly into StringPrototype's replace-with-empty-string logic instead of going
+ through stuff that does checks before reaching that same conclusion.
+
+ This speeds up Octane/regexp by about 6-10%. It also speeds up the attached microbenchmark by
+ about 7%.
+
+ * ftl/FTLLowerDFGToB3.cpp:
+ (JSC::FTL::DFG::LowerDFGToB3::compileStringReplace):
+ * runtime/StringPrototype.cpp:
+ (JSC::jsSpliceSubstringsWithSeparators):
+ (JSC::removeUsingRegExpSearch):
+ (JSC::replaceUsingRegExpSearch):
+ (JSC::operationStringProtoFuncReplaceRegExpEmptyStr):
+ (JSC::operationStringProtoFuncReplaceRegExpString):
+ * runtime/StringPrototype.h:
+
2016-03-01 Alex Christensen <achristen...@webkit.org>
Reduce size of internal windows build output
Modified: trunk/Source/_javascript_Core/ftl/FTLLowerDFGToB3.cpp (197415 => 197416)
--- trunk/Source/_javascript_Core/ftl/FTLLowerDFGToB3.cpp 2016-03-01 23:33:36 UTC (rev 197415)
+++ trunk/Source/_javascript_Core/ftl/FTLLowerDFGToB3.cpp 2016-03-01 23:35:05 UTC (rev 197416)
@@ -6467,6 +6467,21 @@
if (m_node->child1().useKind() == StringUse
&& m_node->child2().useKind() == RegExpObjectUse
&& m_node->child3().useKind() == StringUse) {
+
+ if (JSString* replace = m_node->child3()->dynamicCastConstant<JSString*>()) {
+ if (!replace->length()) {
+ LValue string = lowString(m_node->child1());
+ LValue regExp = lowCell(m_node->child2());
+ speculateRegExpObject(m_node->child2(), regExp);
+
+ LValue result = vmCall(
+ Int64, m_out.operation(operationStringProtoFuncReplaceRegExpEmptyStr),
+ m_callFrame, string, regExp);
+
+ setJSValue(result);
+ return;
+ }
+ }
LValue string = lowString(m_node->child1());
LValue regExp = lowCell(m_node->child2());
Modified: trunk/Source/_javascript_Core/runtime/StringPrototype.cpp (197415 => 197416)
--- trunk/Source/_javascript_Core/runtime/StringPrototype.cpp 2016-03-01 23:33:36 UTC (rev 197415)
+++ trunk/Source/_javascript_Core/runtime/StringPrototype.cpp 2016-03-01 23:35:05 UTC (rev 197416)
@@ -446,7 +446,7 @@
return jsString(exec, impl.release());
}
-static NEVER_INLINE EncodedJSValue removeUsingRegExpSearch(ExecState* exec, JSString* string, const String& source, RegExp* regExp)
+static ALWAYS_INLINE EncodedJSValue removeUsingRegExpSearch(ExecState* exec, JSString* string, const String& source, RegExp* regExp)
{
size_t lastIndex = 0;
unsigned startPosition = 0;
@@ -506,6 +506,8 @@
return removeUsingRegExpSearch(exec, string, source, regExp);
}
+ // FIXME: This is wrong because we may be called directly from the FTL.
+ // https://bugs.webkit.org/show_bug.cgi?id=154874
RegExpConstructor* regExpConstructor = exec->lexicalGlobalObject()->regExpConstructor();
size_t lastIndex = 0;
@@ -664,6 +666,24 @@
return JSValue::encode(jsSpliceSubstringsWithSeparators(exec, string, source, sourceRanges.data(), sourceRanges.size(), replacements.data(), replacements.size()));
}
+EncodedJSValue JIT_OPERATION operationStringProtoFuncReplaceRegExpEmptyStr(
+ ExecState* exec, JSString* thisValue, RegExpObject* searchValue)
+{
+ RegExp* regExp = searchValue->regExp();
+ if (regExp->global()) {
+ // ES5.1 15.5.4.10 step 8.a.
+ searchValue->setLastIndex(exec, 0);
+ if (exec->hadException())
+ return JSValue::encode(jsUndefined());
+ return removeUsingRegExpSearch(exec, thisValue, thisValue->value(exec), regExp);
+ }
+
+ CallData callData;
+ String replacementString = emptyString();
+ return replaceUsingRegExpSearch(
+ exec, thisValue, searchValue, callData, CallTypeNone, replacementString, JSValue());
+}
+
EncodedJSValue JIT_OPERATION operationStringProtoFuncReplaceRegExpString(
ExecState* exec, JSString* thisValue, RegExpObject* searchValue, JSString* replaceString)
{
Modified: trunk/Source/_javascript_Core/runtime/StringPrototype.h (197415 => 197416)
--- trunk/Source/_javascript_Core/runtime/StringPrototype.h 2016-03-01 23:33:36 UTC (rev 197415)
+++ trunk/Source/_javascript_Core/runtime/StringPrototype.h 2016-03-01 23:35:05 UTC (rev 197416)
@@ -54,11 +54,13 @@
};
EncodedJSValue JIT_OPERATION operationStringProtoFuncReplaceGeneric(
- ExecState* exec, EncodedJSValue thisValue, EncodedJSValue searchValue,
- EncodedJSValue replaceValue);
+ ExecState*, EncodedJSValue thisValue, EncodedJSValue searchValue, EncodedJSValue replaceValue);
+EncodedJSValue JIT_OPERATION operationStringProtoFuncReplaceRegExpEmptyStr(
+ ExecState*, JSString* thisValue, RegExpObject* searchValue);
+
EncodedJSValue JIT_OPERATION operationStringProtoFuncReplaceRegExpString(
- ExecState* exec, JSString* thisValue, RegExpObject* searchValue, JSString* replaceValue);
+ ExecState*, JSString* thisValue, RegExpObject* searchValue, JSString* replaceValue);
} // namespace JSC