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.
git-svn-id: http://svn.webkit.org/repository/webkit/trunk@197408 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/Source/JavaScriptCore/ChangeLog b/Source/JavaScriptCore/ChangeLog
index 2d80557..b1d1c1d 100644
--- a/Source/JavaScriptCore/ChangeLog
+++ b/Source/JavaScriptCore/ChangeLog
@@ -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.
diff --git a/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj b/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj
index 307e52e..e1b98b3 100644
--- a/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj
+++ b/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj
@@ -154,7 +154,7 @@
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 */; };
@@ -403,7 +403,7 @@
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, ); }; };
diff --git a/Source/JavaScriptCore/bytecode/SpeculatedType.cpp b/Source/JavaScriptCore/bytecode/SpeculatedType.cpp
index ca9514c..af67f45 100644
--- a/Source/JavaScriptCore/bytecode/SpeculatedType.cpp
+++ b/Source/JavaScriptCore/bytecode/SpeculatedType.cpp
@@ -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 @@
myOut.print("Stringobject");
else
isTop = false;
+
+ if (value & SpecRegExpObject)
+ myOut.print("Regexpobject");
+ else
+ isTop = false;
}
if ((value & SpecString) == SpecString)
@@ -257,6 +262,8 @@
return "<ScopedArguments>";
if (isStringObjectSpeculation(prediction))
return "<StringObject>";
+ if (isRegExpObjectSpeculation(prediction))
+ return "<RegExpObject>";
if (isStringOrStringObjectSpeculation(prediction))
return "<StringOrStringObject>";
if (isObjectSpeculation(prediction))
@@ -336,6 +343,9 @@
if (classInfo == StringObject::info())
return SpecStringObject;
+
+ if (classInfo == RegExpObject::info())
+ return SpecRegExpObject;
if (classInfo->isSubClassOf(JSFunction::info()))
return SpecFunction;
diff --git a/Source/JavaScriptCore/bytecode/SpeculatedType.h b/Source/JavaScriptCore/bytecode/SpeculatedType.h
index 1abb643..3326ed8 100644
--- a/Source/JavaScriptCore/bytecode/SpeculatedType.h
+++ b/Source/JavaScriptCore/bytecode/SpeculatedType.h
@@ -55,25 +55,26 @@
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 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 @@
return !!value && !(value & ~(SpecString | SpecStringObject));
}
+inline bool isRegExpObjectSpeculation(SpeculatedType value)
+{
+ return value == SpecRegExpObject;
+}
+
inline bool isBoolInt32Speculation(SpeculatedType value)
{
return value == SpecBoolInt32;
diff --git a/Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h b/Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h
index a541ef2..338a903 100644
--- a/Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h
+++ b/Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h
@@ -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 @@
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 @@
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;
diff --git a/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp b/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp
index bbc0521..2f3f12d 100644
--- a/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp
+++ b/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp
@@ -2188,6 +2188,23 @@
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: {
diff --git a/Source/JavaScriptCore/dfg/DFGClobberize.h b/Source/JavaScriptCore/dfg/DFGClobberize.h
index 458086e..4612177 100644
--- a/Source/JavaScriptCore/dfg/DFGClobberize.h
+++ b/Source/JavaScriptCore/dfg/DFGClobberize.h
@@ -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 @@
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);
diff --git a/Source/JavaScriptCore/dfg/DFGDoesGC.cpp b/Source/JavaScriptCore/dfg/DFGDoesGC.cpp
index 4521adb..eec32fe 100644
--- a/Source/JavaScriptCore/dfg/DFGDoesGC.cpp
+++ b/Source/JavaScriptCore/dfg/DFGDoesGC.cpp
@@ -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 @@
case MaterializeNewObject:
case MaterializeCreateActivation:
case StrCat:
+ case StringReplace:
return true;
case MultiPutByOffset:
diff --git a/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp b/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp
index f01c146..af86a46 100644
--- a/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp
+++ b/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp
@@ -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 @@
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()) {
diff --git a/Source/JavaScriptCore/dfg/DFGNode.h b/Source/JavaScriptCore/dfg/DFGNode.h
index 5499deb..7b77132 100644
--- a/Source/JavaScriptCore/dfg/DFGNode.h
+++ b/Source/JavaScriptCore/dfg/DFGNode.h
@@ -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 @@
case RegExpTest:
case GetGlobalVar:
case GetGlobalLexicalVariable:
+ case StringReplace:
return true;
default:
return false;
@@ -1966,6 +1967,11 @@
return isStringOrStringObjectSpeculation(prediction());
}
+ bool shouldSpeculateRegExpObject()
+ {
+ return isRegExpObjectSpeculation(prediction());
+ }
+
bool shouldSpeculateSymbol()
{
return isSymbolSpeculation(prediction());
diff --git a/Source/JavaScriptCore/dfg/DFGNodeType.h b/Source/JavaScriptCore/dfg/DFGNodeType.h
index 71c075a..4035dd9 100644
--- a/Source/JavaScriptCore/dfg/DFGNodeType.h
+++ b/Source/JavaScriptCore/dfg/DFGNodeType.h
@@ -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 @@
/* Optimizations for regular expression matching. */\
macro(RegExpExec, NodeResultJS | NodeMustGenerate) \
macro(RegExpTest, NodeResultJS | NodeMustGenerate) \
+ macro(StringReplace, NodeResultJS | NodeMustGenerate) \
\
/* Optimizations for string access */ \
macro(StringCharCodeAt, NodeResultInt32) \
diff --git a/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp b/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp
index 4596053..9283ae3 100644
--- a/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp
+++ b/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp
@@ -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 @@
case ArrayPush:
case RegExpExec:
case RegExpTest:
+ case StringReplace:
case GetById:
case GetByIdFlush:
case GetByOffset:
@@ -572,7 +573,11 @@
break;
}
- case NewRegexp:
+ case NewRegexp: {
+ changed |= setPrediction(SpecRegExpObject);
+ break;
+ }
+
case CreateActivation: {
changed |= setPrediction(SpecObjectOther);
break;
diff --git a/Source/JavaScriptCore/dfg/DFGSafeToExecute.h b/Source/JavaScriptCore/dfg/DFGSafeToExecute.h
index 98592c7..1924978 100644
--- a/Source/JavaScriptCore/dfg/DFGSafeToExecute.h
+++ b/Source/JavaScriptCore/dfg/DFGSafeToExecute.h
@@ -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 @@
case ObjectUse:
case FunctionUse:
case FinalObjectUse:
+ case RegExpObjectUse:
case ObjectOrOtherUse:
case StringIdentUse:
case StringUse:
@@ -330,6 +331,7 @@
case GetMyArgumentByVal:
case ForwardVarargs:
case CopyRest:
+ case StringReplace:
return true;
case BottomValue:
diff --git a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp
index f03af97..ed82a04 100644
--- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp
+++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp
@@ -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 @@
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 @@
case FinalObjectUse:
speculateFinalObject(edge);
break;
+ case RegExpObjectUse:
+ speculateRegExpObject(edge);
+ break;
case ObjectOrOtherUse:
speculateObjectOrOther(edge);
break;
diff --git a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h
index 5d6fba4d..20036fa 100644
--- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h
+++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h
@@ -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 @@
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);
diff --git a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp
index 2009a02..e39237b 100644
--- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp
+++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp
@@ -4828,6 +4828,7 @@
case KillStack:
case GetStack:
case GetMyArgumentByVal:
+ case StringReplace:
DFG_CRASH(m_jit.graph(), node, "unexpected node in DFG backend");
break;
}
diff --git a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp
index 38cb2cd..06b4008 100644
--- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp
+++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp
@@ -4882,6 +4882,7 @@
case PutStack:
case KillStack:
case GetStack:
+ case StringReplace:
DFG_CRASH(m_jit.graph(), node, "Unexpected node");
break;
}
diff --git a/Source/JavaScriptCore/dfg/DFGUseKind.cpp b/Source/JavaScriptCore/dfg/DFGUseKind.cpp
index 86a1bda..3b9ad74 100644
--- a/Source/JavaScriptCore/dfg/DFGUseKind.cpp
+++ b/Source/JavaScriptCore/dfg/DFGUseKind.cpp
@@ -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 @@
case FinalObjectUse:
out.print("FinalObject");
return;
+ case RegExpObjectUse:
+ out.print("RegExpObject");
+ return;
case ObjectOrOtherUse:
out.print("ObjectOrOther");
return;
diff --git a/Source/JavaScriptCore/dfg/DFGUseKind.h b/Source/JavaScriptCore/dfg/DFGUseKind.h
index 9b5143b..816c19e 100644
--- a/Source/JavaScriptCore/dfg/DFGUseKind.h
+++ b/Source/JavaScriptCore/dfg/DFGUseKind.h
@@ -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 @@
ObjectUse,
FunctionUse,
FinalObjectUse,
+ RegExpObjectUse,
ObjectOrOtherUse,
StringIdentUse,
StringUse,
@@ -117,6 +118,8 @@
return SpecFunction;
case FinalObjectUse:
return SpecFinalObject;
+ case RegExpObjectUse:
+ return SpecRegExpObject;
case ObjectOrOtherUse:
return SpecObject | SpecOther;
case StringIdentUse:
@@ -208,6 +211,7 @@
case ObjectUse:
case FunctionUse:
case FinalObjectUse:
+ case RegExpObjectUse:
case StringIdentUse:
case StringUse:
case KnownStringUse:
diff --git a/Source/JavaScriptCore/ftl/FTLCapabilities.cpp b/Source/JavaScriptCore/ftl/FTLCapabilities.cpp
index d715693..e49b11e 100644
--- a/Source/JavaScriptCore/ftl/FTLCapabilities.cpp
+++ b/Source/JavaScriptCore/ftl/FTLCapabilities.cpp
@@ -223,6 +223,7 @@
case RegExpExec:
case RegExpTest:
case NewRegexp:
+ case StringReplace:
// These are OK.
break;
@@ -465,6 +466,7 @@
case StringOrStringObjectUse:
case SymbolUse:
case FinalObjectUse:
+ case RegExpObjectUse:
case NotCellUse:
case OtherUse:
case MiscUse:
diff --git a/Source/JavaScriptCore/ftl/FTLLowerDFGToB3.cpp b/Source/JavaScriptCore/ftl/FTLLowerDFGToB3.cpp
index dd76f26..5f89d2c 100644
--- a/Source/JavaScriptCore/ftl/FTLLowerDFGToB3.cpp
+++ b/Source/JavaScriptCore/ftl/FTLLowerDFGToB3.cpp
@@ -923,6 +923,9 @@
case NewRegexp:
compileNewRegexp();
break;
+ case StringReplace:
+ compileStringReplace();
+ break;
case PhantomLocal:
case LoopHint:
@@ -6459,6 +6462,33 @@
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 @@
case FinalObjectUse:
speculateFinalObject(edge);
break;
+ case RegExpObjectUse:
+ speculateRegExpObject(edge);
+ break;
case StringUse:
speculateString(edge);
break;
@@ -9561,6 +9594,17 @@
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));
diff --git a/Source/JavaScriptCore/jit/JITOperations.h b/Source/JavaScriptCore/jit/JITOperations.h
index 71bb0c5..8cbe0e4 100644
--- a/Source/JavaScriptCore/jit/JITOperations.h
+++ b/Source/JavaScriptCore/jit/JITOperations.h
@@ -254,6 +254,7 @@
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.
diff --git a/Source/JavaScriptCore/runtime/Intrinsic.h b/Source/JavaScriptCore/runtime/Intrinsic.h
index d6ccc1b..218d2ef 100644
--- a/Source/JavaScriptCore/runtime/Intrinsic.h
+++ b/Source/JavaScriptCore/runtime/Intrinsic.h
@@ -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 @@
RegExpExecIntrinsic,
RegExpTestIntrinsic,
StringPrototypeValueOfIntrinsic,
+ StringPrototypeReplaceIntrinsic,
IMulIntrinsic,
RandomIntrinsic,
FRoundIntrinsic,
diff --git a/Source/JavaScriptCore/runtime/JSType.h b/Source/JavaScriptCore/runtime/JSType.h
index 6442dde..9954a63 100644
--- a/Source/JavaScriptCore/runtime/JSType.h
+++ b/Source/JavaScriptCore/runtime/JSType.h
@@ -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 @@
GlobalObjectType,
ClosureObjectType,
-
+ RegExpObjectType,
ProxyObjectType,
LastJSCObjectType = ProxyObjectType,
diff --git a/Source/JavaScriptCore/runtime/RegExpObject.h b/Source/JavaScriptCore/runtime/RegExpObject.h
index a1f571d..4901de0 100644
--- a/Source/JavaScriptCore/runtime/RegExpObject.h
+++ b/Source/JavaScriptCore/runtime/RegExpObject.h
@@ -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 @@
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:
diff --git a/Source/JavaScriptCore/runtime/StringPrototype.cpp b/Source/JavaScriptCore/runtime/StringPrototype.cpp
index d830255..22d2682 100644
--- a/Source/JavaScriptCore/runtime/StringPrototype.cpp
+++ b/Source/JavaScriptCore/runtime/StringPrototype.cpp
@@ -135,7 +135,7 @@
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 @@
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 @@
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 @@
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 @@
return JSValue::encode(ropeBuilder.release());
}
-EncodedJSValue JSC_HOST_CALL stringProtoFuncReplace(ExecState* exec)
+ALWAYS_INLINE EncodedJSValue replace(
+ ExecState* exec, JSString* string, JSValue searchValue, JSValue replaceValue)
{
- JSValue thisValue = exec->thisValue();
+ 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)
+{
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)
diff --git a/Source/JavaScriptCore/runtime/StringPrototype.h b/Source/JavaScriptCore/runtime/StringPrototype.h
index 54a78d9..b94da81 100644
--- a/Source/JavaScriptCore/runtime/StringPrototype.h
+++ b/Source/JavaScriptCore/runtime/StringPrototype.h
@@ -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
@@ -21,11 +21,13 @@
#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 @@
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