String.prototype.toLowerCase should be a DFG/FTL intrinsic
https://bugs.webkit.org/show_bug.cgi?id=162887

Reviewed by Filip Pizlo and Yusuke Suzuki.

JSTests:

* microbenchmarks/to-lower-case.js: Added.
(assert):
(foo):
(bar):
* stress/to-lower-case.js: Added.
(assert):
(foo):

Source/JavaScriptCore:

This patch makes ToLowerCase an intrinsic in the DFG/FTL. On the fast
path, the intrinsic will loop over an 8-bit string ensuring it's already
lower case, and simply return the string. In the slow path, it'll call
into C code to make a new string.

This is a 7-8% speedup on ES6SampleBench/Basic.

* 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/DFGNodeType.h:
* dfg/DFGOperations.cpp:
* dfg/DFGOperations.h:
* dfg/DFGPredictionPropagationPhase.cpp:
* dfg/DFGSafeToExecute.h:
(JSC::DFG::safeToExecute):
* dfg/DFGSpeculativeJIT.cpp:
(JSC::DFG::SpeculativeJIT::compileToLowerCase):
* dfg/DFGSpeculativeJIT.h:
(JSC::DFG::SpeculativeJIT::callOperation):
* dfg/DFGSpeculativeJIT32_64.cpp:
(JSC::DFG::SpeculativeJIT::compile):
* dfg/DFGSpeculativeJIT64.cpp:
(JSC::DFG::SpeculativeJIT::compile):
* ftl/FTLAbstractHeapRepository.h:
* ftl/FTLCapabilities.cpp:
(JSC::FTL::canCompile):
* ftl/FTLLowerDFGToB3.cpp:
(JSC::FTL::DFG::LowerDFGToB3::compileNode):
(JSC::FTL::DFG::LowerDFGToB3::compileToLowerCase):
* jit/JITOperations.h:
* runtime/Intrinsic.h:
* runtime/StringPrototype.cpp:
(JSC::StringPrototype::finishCreation):

Source/WTF:

This patch exposes a new StringImpl function called convertToLowercaseWithoutLocaleStartingAtFailingIndex8Bit
which extracts slow path for the 8-bit part of convertToLowercaseWithoutLocale
into a helper function. I decided to extract this into its own function because
it may be the case that JSCs JITs will want to continue the operation
after it has already ensured that part of an 8-bit string is lower case.

* wtf/text/StringImpl.cpp:
(WTF::StringImpl::convertToLowercaseWithoutLocale):
(WTF::StringImpl::convertToLowercaseWithoutLocaleStartingAtFailingIndex8Bit):
* wtf/text/StringImpl.h:
* wtf/text/WTFString.cpp:
(WTF::String::convertToLowercaseWithoutLocaleStartingAtFailingIndex8Bit):
* wtf/text/WTFString.h:


git-svn-id: http://svn.webkit.org/repository/webkit/trunk@206804 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/Source/JavaScriptCore/dfg/DFGOperations.cpp b/Source/JavaScriptCore/dfg/DFGOperations.cpp
index 3aed72c..c079f9a 100644
--- a/Source/JavaScriptCore/dfg/DFGOperations.cpp
+++ b/Source/JavaScriptCore/dfg/DFGOperations.cpp
@@ -1514,6 +1514,22 @@
     return string->value(exec).impl();
 }
 
+JSString* JIT_OPERATION operationToLowerCase(ExecState* exec, JSString* string, uint32_t failingIndex)
+{
+    VM& vm = exec->vm();
+    NativeCallFrameTracer tracer(&vm, exec);
+
+    auto scope = DECLARE_THROW_SCOPE(vm);
+
+    const String& inputString = string->value(exec);
+    RETURN_IF_EXCEPTION(scope, nullptr);
+    String lowercasedString = inputString.is8Bit() ? inputString.convertToLowercaseWithoutLocaleStartingAtFailingIndex8Bit(failingIndex) : inputString.convertToLowercaseWithoutLocale();
+    if (lowercasedString.impl() == inputString.impl())
+        return string;
+    scope.release();
+    return jsString(exec, lowercasedString);
+}
+
 JSString* JIT_OPERATION operationSingleCharacterString(ExecState* exec, int32_t character)
 {
     VM& vm = exec->vm();