Use more efficient makeString() instead of StringBuilder
https://bugs.webkit.org/show_bug.cgi?id=213708

Reviewed by Sam Weinig.

Source/WebCore:

This patch refactors throwRequiredMemberTypeError() and throwArgument*Error()
methods, replacing all StringBuilder usages with more efficient makeString().

Extracts makeArgumentTypeErrorMessage(), similiar to existing helpers,
which can be reused if neccessary.

No new tests, no behavior change.

* bindings/js/JSDOMExceptionHandling.cpp:
(WebCore::makeArgumentTypeErrorMessage):
(WebCore::throwArgumentMustBeEnumError):
(WebCore::throwArgumentMustBeFunctionError):
(WebCore::throwArgumentMustBeObjectError):
(WebCore::throwArgumentTypeError):
(WebCore::throwRequiredMemberTypeError):
(WebCore::appendArgumentMustBe): Deleted.

Source/WTF:

Introduces StringTypeAdapter<std::tuple> overload, which enables using
makeString() instead of StringBuilder in more cases.

* wtf/text/StringConcatenate.h:
(WTF::StringTypeAdapter<std::tuple<StringTypes...>, void>): Added.


git-svn-id: http://svn.webkit.org/repository/webkit/trunk@263795 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/Source/WTF/ChangeLog b/Source/WTF/ChangeLog
index 891ce31..13ddb98 100644
--- a/Source/WTF/ChangeLog
+++ b/Source/WTF/ChangeLog
@@ -1,3 +1,16 @@
+2020-07-01  Alexey Shvayka  <shvaikalesh@gmail.com>
+
+        Use more efficient makeString() instead of StringBuilder
+        https://bugs.webkit.org/show_bug.cgi?id=213708
+
+        Reviewed by Sam Weinig.
+
+        Introduces StringTypeAdapter<std::tuple> overload, which enables using
+        makeString() instead of StringBuilder in more cases.
+
+        * wtf/text/StringConcatenate.h:
+        (WTF::StringTypeAdapter<std::tuple<StringTypes...>, void>): Added.
+
 2020-06-30  Geoffrey Garen  <ggaren@apple.com>
 
         [Cocoa] [GTK] RunLoop::Timer::isActive() is incorrect for timers while they are firing
diff --git a/Source/WTF/wtf/text/StringConcatenate.h b/Source/WTF/wtf/text/StringConcatenate.h
index 37c2850..26902e0 100644
--- a/Source/WTF/wtf/text/StringConcatenate.h
+++ b/Source/WTF/wtf/text/StringConcatenate.h
@@ -197,6 +197,44 @@
     }
 };
 
+template<typename... StringTypes> class StringTypeAdapter<std::tuple<StringTypes...>, void> {
+public:
+    StringTypeAdapter(std::tuple<StringTypes...> tuple)
+        : m_tuple { tuple }
+        , m_length { std::apply(computeLength, tuple) }
+        , m_is8Bit { std::apply(computeIs8Bit, tuple) }
+    {
+    }
+
+    unsigned length() const { return m_length; }
+    bool is8Bit() const { return m_is8Bit; }
+    template<typename CharacterType> void writeTo(CharacterType* destination) const
+    {
+        std::apply([&](StringTypes... strings) {
+            unsigned offset = 0;
+            (..., (
+                StringTypeAdapter<StringTypes>(strings).writeTo(destination + (offset * sizeof(CharacterType))),
+                offset += StringTypeAdapter<StringTypes>(strings).length()
+            ));
+        }, m_tuple);
+    }
+
+private:
+    static unsigned computeLength(StringTypes... strings)
+    {
+        return (... + StringTypeAdapter<StringTypes>(strings).length());
+    }
+
+    static bool computeIs8Bit(StringTypes... strings)
+    {
+        return (... && StringTypeAdapter<StringTypes>(strings).is8Bit());
+    }
+
+    std::tuple<StringTypes...> m_tuple;
+    unsigned m_length;
+    bool m_is8Bit;
+};
+
 template<typename UnderlyingElementType> struct PaddingSpecification {
     LChar character;
     unsigned length;
diff --git a/Source/WebCore/ChangeLog b/Source/WebCore/ChangeLog
index e960e5a..0baa142 100644
--- a/Source/WebCore/ChangeLog
+++ b/Source/WebCore/ChangeLog
@@ -1,3 +1,27 @@
+2020-07-01  Alexey Shvayka  <shvaikalesh@gmail.com>
+
+        Use more efficient makeString() instead of StringBuilder
+        https://bugs.webkit.org/show_bug.cgi?id=213708
+
+        Reviewed by Sam Weinig.
+
+        This patch refactors throwRequiredMemberTypeError() and throwArgument*Error()
+        methods, replacing all StringBuilder usages with more efficient makeString().
+
+        Extracts makeArgumentTypeErrorMessage(), similiar to existing helpers,
+        which can be reused if neccessary.
+
+        No new tests, no behavior change.
+
+        * bindings/js/JSDOMExceptionHandling.cpp:
+        (WebCore::makeArgumentTypeErrorMessage):
+        (WebCore::throwArgumentMustBeEnumError):
+        (WebCore::throwArgumentMustBeFunctionError):
+        (WebCore::throwArgumentMustBeObjectError):
+        (WebCore::throwArgumentTypeError):
+        (WebCore::throwRequiredMemberTypeError):
+        (WebCore::appendArgumentMustBe): Deleted.
+
 2020-06-29  Sergio Villar Senin  <svillar@igalia.com>
 
         [css-flexbox] Don't include scrollbar extents when computing sizes for percentage resolution
diff --git a/Source/WebCore/bindings/js/JSDOMExceptionHandling.cpp b/Source/WebCore/bindings/js/JSDOMExceptionHandling.cpp
index c240890..2392966 100644
--- a/Source/WebCore/bindings/js/JSDOMExceptionHandling.cpp
+++ b/Source/WebCore/bindings/js/JSDOMExceptionHandling.cpp
@@ -34,7 +34,6 @@
 #include <JavaScriptCore/ExceptionHelpers.h>
 #include <JavaScriptCore/ScriptCallStack.h>
 #include <JavaScriptCore/ScriptCallStackFactory.h>
-#include <wtf/text/StringBuilder.h>
 
 namespace WebCore {
 using namespace JSC;
@@ -168,14 +167,13 @@
     return throwVMTypeError(&lexicalGlobalObject, scope, errorMessage);
 }
 
-static void appendArgumentMustBe(StringBuilder& builder, unsigned argumentIndex, const char* argumentName, const char* interfaceName, const char* functionName)
+template<typename... StringTypes> static String makeArgumentTypeErrorMessage(unsigned argumentIndex, const char* argumentName, const char* interfaceName, const char* functionName, StringTypes ...strings)
 {
-    builder.append("Argument ", argumentIndex + 1, " ('", argumentName, "') to ");
-    if (!functionName)
-        builder.append("the ", interfaceName, " constructor");
-    else
-        builder.append(interfaceName, '.', functionName);
-    builder.appendLiteral(" must be ");
+    return makeString(
+        "Argument ", argumentIndex + 1, " ('", argumentName, "') to ",
+        functionName ? std::make_tuple(interfaceName, ".", functionName) : std::make_tuple("the ", interfaceName, " constructor"),
+        " must be ", strings...
+    );
 }
 
 void throwNotSupportedError(JSC::JSGlobalObject& lexicalGlobalObject, JSC::ThrowScope& scope, ASCIILiteral message)
@@ -198,34 +196,22 @@
 
 JSC::EncodedJSValue throwArgumentMustBeEnumError(JSC::JSGlobalObject& lexicalGlobalObject, JSC::ThrowScope& scope, unsigned argumentIndex, const char* argumentName, const char* functionInterfaceName, const char* functionName, const char* expectedValues)
 {
-    StringBuilder builder;
-    appendArgumentMustBe(builder, argumentIndex, argumentName, functionInterfaceName, functionName);
-    builder.append("one of: ", expectedValues);
-    return throwVMTypeError(&lexicalGlobalObject, scope, builder.toString());
+    return throwVMTypeError(&lexicalGlobalObject, scope, makeArgumentTypeErrorMessage(argumentIndex, argumentName, functionInterfaceName, functionName, "one of: ", expectedValues));
 }
 
 JSC::EncodedJSValue throwArgumentMustBeFunctionError(JSC::JSGlobalObject& lexicalGlobalObject, JSC::ThrowScope& scope, unsigned argumentIndex, const char* argumentName, const char* interfaceName, const char* functionName)
 {
-    StringBuilder builder;
-    appendArgumentMustBe(builder, argumentIndex, argumentName, interfaceName, functionName);
-    builder.appendLiteral("a function");
-    return throwVMTypeError(&lexicalGlobalObject, scope, builder.toString());
+    return throwVMTypeError(&lexicalGlobalObject, scope, makeArgumentTypeErrorMessage(argumentIndex, argumentName, interfaceName, functionName, "a function"));
 }
 
 JSC::EncodedJSValue throwArgumentMustBeObjectError(JSC::JSGlobalObject& lexicalGlobalObject, JSC::ThrowScope& scope, unsigned argumentIndex, const char* argumentName, const char* interfaceName, const char* functionName)
 {
-    StringBuilder builder;
-    appendArgumentMustBe(builder, argumentIndex, argumentName, interfaceName, functionName);
-    builder.appendLiteral("an object");
-    return throwVMTypeError(&lexicalGlobalObject, scope, builder.toString());
+    return throwVMTypeError(&lexicalGlobalObject, scope, makeArgumentTypeErrorMessage(argumentIndex, argumentName, interfaceName, functionName, "an object"));
 }
 
 JSC::EncodedJSValue throwArgumentTypeError(JSC::JSGlobalObject& lexicalGlobalObject, JSC::ThrowScope& scope, unsigned argumentIndex, const char* argumentName, const char* functionInterfaceName, const char* functionName, const char* expectedType)
 {
-    StringBuilder builder;
-    appendArgumentMustBe(builder, argumentIndex, argumentName, functionInterfaceName, functionName);
-    builder.append("an instance of ", expectedType);
-    return throwVMTypeError(&lexicalGlobalObject, scope, builder.toString());
+    return throwVMTypeError(&lexicalGlobalObject, scope, makeArgumentTypeErrorMessage(argumentIndex, argumentName, functionInterfaceName, functionName, "an instance of ", expectedType));
 }
 
 void throwAttributeTypeError(JSC::JSGlobalObject& lexicalGlobalObject, JSC::ThrowScope& scope, const char* interfaceName, const char* attributeName, const char* expectedType)
@@ -235,14 +221,7 @@
 
 JSC::EncodedJSValue throwRequiredMemberTypeError(JSC::JSGlobalObject& lexicalGlobalObject, JSC::ThrowScope& scope, const char* memberName, const char* dictionaryName, const char* expectedType)
 {
-    StringBuilder builder;
-    builder.appendLiteral("Member ");
-    builder.append(dictionaryName);
-    builder.append('.');
-    builder.append(memberName);
-    builder.appendLiteral(" is required and must be an instance of ");
-    builder.append(expectedType);
-    return throwVMTypeError(&lexicalGlobalObject, scope, builder.toString());
+    return throwVMTypeError(&lexicalGlobalObject, scope, makeString("Member ", dictionaryName, '.', memberName, " is required and must be an instance of ", expectedType));
 }
 
 JSC::EncodedJSValue throwConstructorScriptExecutionContextUnavailableError(JSC::JSGlobalObject& lexicalGlobalObject, JSC::ThrowScope& scope, const char* interfaceName)