[ES] Implement RegExp.prototype.@@replace and use it for String.prototype.replace
authormsaboff@apple.com <msaboff@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 27 Apr 2016 01:28:03 +0000 (01:28 +0000)
committermsaboff@apple.com <msaboff@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 27 Apr 2016 01:28:03 +0000 (01:28 +0000)
commit260a7b2ef10b2f817abe04aefd6fc930ee47edb7
treef76d1328ec5a52799dc44867efccca6c9092ec95
parenta09f7f1c5848c4ad61b04f3fe0b869bb41ccb5b0
[ES] Implement RegExp.prototype.@@replace and use it for String.prototype.replace
https://bugs.webkit.org/show_bug.cgi?id=156562

Reviewed by Filip Pizlo.

Source/JavaScriptCore:

Added builtins for String.prototype.replace as well as RegExp.prototype[Symbol.replace].

The String.prototype.replace also has an intrinsic, StringPrototypeReplaceIntrinsic.
This original intrinsic was copied to make StringPrototypeReplaceRegExpIntrinsic.
The difference between the two intrinsics is that StringPrototypeReplaceIntrinsic has
the same checks found in the new builtin hasObservableSideEffectsForStringReplace.
We implement these primordial checks for StringPrototypeReplaceIntrinsic in two places.
First, we do a trial check during ByteCode parsing time to see if the current
RegExp.prototype properties have changed from the original.  If they have, we don't
inline the intrinsic.  Later, in the fixup phase, we add nodes to the IR to emit the
checks at runtime.

The new intrinsic StringPrototypeReplaceRegExpIntrinsic is only available via the
private @replaceUsingRegExp, which is called in the String.prototype.replace builtin.
It is only called after hasObservableSideEffectsForStringReplace has been called

Both of these intrinsics are needed, because the JS code containing String.replace() calls
runs initially in the LLint and then the baseline JIT.  Even after the function tiers up
to the DFG JIT, the inlining budget may not allow StringPrototypeReplaceIntrinsic to be inlined.
Having StringPrototypeReplaceRegExpIntrinsic allows for the String.prototype.replace builtin to
get reasonable performance before the other intrinsic is inlined or when it can't.

* builtins/RegExpPrototype.js:
(match):
(getSubstitution):
(replace):
(search):
(split):
* builtins/StringPrototype.js:
(repeat):
(hasObservableSideEffectsForStringReplace):
(intrinsic.StringPrototypeReplaceIntrinsic.replace):
(localeCompare):
New builtins for String.prototype.replace and RegExp.prototype[Symbol.replace].

* bytecode/BytecodeIntrinsicRegistry.cpp:
* bytecode/BytecodeIntrinsicRegistry.h:
* 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):
(JSC::DFG::FixupPhase::fixupGetAndSetLocalsInBlock):
(JSC::DFG::FixupPhase::tryAddStringReplacePrimordialChecks):
(JSC::DFG::FixupPhase::checkArray):
* dfg/DFGGraph.cpp:
(JSC::DFG::Graph::getRegExpPrototypeProperty):
* dfg/DFGGraph.h:
(JSC::DFG::Graph::getRegExpPrototypeProperty):
* dfg/DFGNode.h:
(JSC::DFG::Node::hasHeapPrediction):
* dfg/DFGNodeType.h:
* dfg/DFGPredictionPropagationPhase.cpp:
* dfg/DFGSafeToExecute.h:
(JSC::DFG::safeToExecute):
* dfg/DFGSpeculativeJIT32_64.cpp:
(JSC::DFG::SpeculativeJIT::compile):
* dfg/DFGSpeculativeJIT64.cpp:
(JSC::DFG::SpeculativeJIT::compile):
* dfg/DFGStrengthReductionPhase.cpp:
(JSC::DFG::StrengthReductionPhase::handleNode):
* ftl/FTLCapabilities.cpp:
(JSC::FTL::canCompile):
* ftl/FTLLowerDFGToB3.cpp:
(JSC::FTL::DFG::LowerDFGToB3::compileNode):
* runtime/CommonIdentifiers.h:
* runtime/Intrinsic.h:
* runtime/RegExpPrototype.cpp:
(JSC::RegExpPrototype::finishCreation):
* runtime/StringPrototype.cpp:
(JSC::StringPrototype::finishCreation):
(JSC::replace):
(JSC::stringProtoFuncReplaceUsingRegExp):
(JSC::stringProtoFuncReplaceUsingStringSearch):
(JSC::operationStringProtoFuncReplaceGeneric):
(JSC::stringProtoFuncReplace): Deleted.
Added StringReplaceRegExp intrinsic.  Added checks for RegExp profiled arguments to StringReplace
that mirror what is in hasObservableSideEffectsForStringReplace().  If we aren't able to add the
checks, we OSR exit.  Add Graph::getPrimordialRegExpPrototypeProperty() as a helper to get the
primordial values from RegExp.prototype.

* runtime/JSGlobalObject.cpp:
(JSC::JSGlobalObject::init): Added @regExpPrototypeSymbolReplace and
@hasObservableSideEffectsForStringReplace here instead og String.prototype so that we reduce the
number of objects we have to traverse.

* tests/es6.yaml: Changed expectations for the various replace related tests to passing.

* tests/stress/regexp-replace-proxy.js:
(assert):
(let.getProxyNullExec.new.Proxy):
(let.getSetProxyNullExec.new.Proxy):
(get resetTracking):
(let.getSetProxyMatches_comma.new.Proxy):
(set get getSetProxyNullExec):
(let.getSetProxyReplace_phoneNumber.new.Proxy):
(set get getSetProxyMatches_comma):
(let.getSetProxyReplaceUnicode_digit_nonGreedy.new.Proxy):
(set get resetTracking):
* tests/stress/string-replace-proxy.js:
(assert):
(let.getSetProxyReplace.new.Proxy.replace):
New tests.

LayoutTests:

Updated tests.  Needed to update js/regress-141098.js test, because builtins are
only compilied when called.  This test checks behavior at or near running out of
stack space.  It turns out that String.replace is used by the -pre.js test harness
and I was running out of stack space when compiling the String.prototype.replace
builting.  Therefore, I added a call to testPassed() to precompile String.replace.

* js/Object-getOwnPropertyNames-expected.txt:
* js/regress-141098-expected.txt:
* js/script-tests/Object-getOwnPropertyNames.js:
* js/script-tests/regress-141098.js:
(probeAndRecurse):
* fast/profiler/nested-start-and-stop-profiler-expected.txt:
* js/Object-getOwnPropertyNames-expected.txt:
* js/dom/string-prototype-properties-expected.txt:
* js/regress-141098-expected.txt:
* js/script-tests/Object-getOwnPropertyNames.js:
* js/script-tests/regress-141098.js:
(probeAndRecurse):
* sputnik/Conformance/15_Native_Objects/15.5_String/15.5.4/15.5.4.11_String.prototype.replace/S15.5.4.11_A1_T3-expected.txt:

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@200117 268f45cc-cd09-0410-ab3c-d52691b4dbfc
38 files changed:
LayoutTests/ChangeLog
LayoutTests/fast/profiler/nested-start-and-stop-profiler-expected.txt
LayoutTests/js/Object-getOwnPropertyNames-expected.txt
LayoutTests/js/dom/string-prototype-properties-expected.txt
LayoutTests/js/regress-141098-expected.txt
LayoutTests/js/script-tests/Object-getOwnPropertyNames.js
LayoutTests/js/script-tests/regress-141098.js
LayoutTests/sputnik/Conformance/15_Native_Objects/15.5_String/15.5.4/15.5.4.11_String.prototype.replace/S15.5.4.11_A1_T3-expected.txt
Source/JavaScriptCore/ChangeLog
Source/JavaScriptCore/builtins/RegExpPrototype.js
Source/JavaScriptCore/builtins/StringPrototype.js
Source/JavaScriptCore/bytecode/BytecodeIntrinsicRegistry.cpp
Source/JavaScriptCore/bytecode/BytecodeIntrinsicRegistry.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/DFGGraph.cpp
Source/JavaScriptCore/dfg/DFGGraph.h
Source/JavaScriptCore/dfg/DFGNode.h
Source/JavaScriptCore/dfg/DFGNodeType.h
Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp
Source/JavaScriptCore/dfg/DFGSafeToExecute.h
Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp
Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp
Source/JavaScriptCore/dfg/DFGStrengthReductionPhase.cpp
Source/JavaScriptCore/ftl/FTLCapabilities.cpp
Source/JavaScriptCore/ftl/FTLLowerDFGToB3.cpp
Source/JavaScriptCore/runtime/CommonIdentifiers.h
Source/JavaScriptCore/runtime/Intrinsic.h
Source/JavaScriptCore/runtime/JSGlobalObject.cpp
Source/JavaScriptCore/runtime/JSGlobalObject.h
Source/JavaScriptCore/runtime/RegExpPrototype.cpp
Source/JavaScriptCore/runtime/StringPrototype.cpp
Source/JavaScriptCore/tests/es6.yaml
Source/JavaScriptCore/tests/stress/regexp-replace-proxy.js [new file with mode: 0644]
Source/JavaScriptCore/tests/stress/string-replace-proxy.js [new file with mode: 0644]