Web Inspector: Canvas: replace WTF::Vector with std::initializer_list in CallTracer...
authordrousso@apple.com <drousso@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 9 Jul 2019 21:07:53 +0000 (21:07 +0000)
committerdrousso@apple.com <drousso@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 9 Jul 2019 21:07:53 +0000 (21:07 +0000)
https://bugs.webkit.org/show_bug.cgi?id=199611

Reviewed by Joseph Pecoraro.

Source/WebCore:

The number of arguments for each member function is known at build time, so there's no need
to dynamically allocate a `WTF::Vector` when capturing the arguments. One downside to using
a `std::initializer_list` is that we can no longer "flatten" `WTF::Variant` arguments into
a `RecordCanvasActionVariant`, but this is acceptable because `WTF::Variant` supports having
yet another `WTF::Variant` as one of it's types, which the `InspectorCanvas` can then figure
out when it finally gets the data. The same applies to `nullptr`/`Optional` checks as well.

* bindings/scripts/CodeGeneratorJS.pm:
(GenerateAttributeSetterBodyDefinition):
(GenerateImplementationFunctionCall):
(GenerateCallTracer):
(GenerateCallTracerParameter): Deleted.
* bindings/scripts/test/JS/JSTestCallTracer.cpp:

* bindings/js/CallTracerTypes.h:
* bindings/js/CallTracer.h:
* bindings/js/CallTracer.cpp:
(WebCore::CallTracer::recordCanvasAction):

* inspector/InspectorInstrumentation.h:
(WebCore::InspectorInstrumentation::recordCanvasAction):
* inspector/InspectorInstrumentation.cpp:
(WebCore::InspectorInstrumentation::recordCanvasActionImpl):

* inspector/agents/InspectorCanvasAgent.h:
* inspector/agents/InspectorCanvasAgent.cpp:
(WebCore::InspectorCanvasAgent::recordCanvasAction):

* inspector/InspectorCanvas.h:
* inspector/InspectorCanvas.cpp:
(WebCore::InspectorCanvas::recordAction):
(WebCore::InspectorCanvas::buildAction):
Drive-by: handle the situation where a parameter is an array of deduplicated strings, which
          would otherwise be treated as an array of numbers.

Source/WebInspectorUI:

* UserInterface/Models/Recording.js:
(WI.Recording.prototype.async swizzle):
Drive-by: handle the situation where a parameter is an array of deduplicated strings, which
          would otherwise be treated as an array of numbers.

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@247278 268f45cc-cd09-0410-ab3c-d52691b4dbfc

14 files changed:
Source/WebCore/ChangeLog
Source/WebCore/bindings/js/CallTracer.cpp
Source/WebCore/bindings/js/CallTracer.h
Source/WebCore/bindings/js/CallTracerTypes.h
Source/WebCore/bindings/scripts/CodeGeneratorJS.pm
Source/WebCore/bindings/scripts/test/JS/JSTestCallTracer.cpp
Source/WebCore/inspector/InspectorCanvas.cpp
Source/WebCore/inspector/InspectorCanvas.h
Source/WebCore/inspector/InspectorInstrumentation.cpp
Source/WebCore/inspector/InspectorInstrumentation.h
Source/WebCore/inspector/agents/InspectorCanvasAgent.cpp
Source/WebCore/inspector/agents/InspectorCanvasAgent.h
Source/WebInspectorUI/ChangeLog
Source/WebInspectorUI/UserInterface/Models/Recording.js

index f1606c9..1fb517c 100644 (file)
@@ -1,3 +1,45 @@
+2019-07-09  Devin Rousso  <drousso@apple.com>
+
+        Web Inspector: Canvas: replace WTF::Vector with std::initializer_list in CallTracer to avoid dynamic allocations
+        https://bugs.webkit.org/show_bug.cgi?id=199611
+
+        Reviewed by Joseph Pecoraro.
+
+        The number of arguments for each member function is known at build time, so there's no need
+        to dynamically allocate a `WTF::Vector` when capturing the arguments. One downside to using
+        a `std::initializer_list` is that we can no longer "flatten" `WTF::Variant` arguments into
+        a `RecordCanvasActionVariant`, but this is acceptable because `WTF::Variant` supports having
+        yet another `WTF::Variant` as one of it's types, which the `InspectorCanvas` can then figure
+        out when it finally gets the data. The same applies to `nullptr`/`Optional` checks as well.
+
+        * bindings/scripts/CodeGeneratorJS.pm:
+        (GenerateAttributeSetterBodyDefinition):
+        (GenerateImplementationFunctionCall):
+        (GenerateCallTracer):
+        (GenerateCallTracerParameter): Deleted.
+        * bindings/scripts/test/JS/JSTestCallTracer.cpp:
+
+        * bindings/js/CallTracerTypes.h:
+        * bindings/js/CallTracer.h:
+        * bindings/js/CallTracer.cpp:
+        (WebCore::CallTracer::recordCanvasAction):
+
+        * inspector/InspectorInstrumentation.h:
+        (WebCore::InspectorInstrumentation::recordCanvasAction):
+        * inspector/InspectorInstrumentation.cpp:
+        (WebCore::InspectorInstrumentation::recordCanvasActionImpl):
+
+        * inspector/agents/InspectorCanvasAgent.h:
+        * inspector/agents/InspectorCanvasAgent.cpp:
+        (WebCore::InspectorCanvasAgent::recordCanvasAction):
+
+        * inspector/InspectorCanvas.h:
+        * inspector/InspectorCanvas.cpp:
+        (WebCore::InspectorCanvas::recordAction):
+        (WebCore::InspectorCanvas::buildAction):
+        Drive-by: handle the situation where a parameter is an array of deduplicated strings, which
+                  would otherwise be treated as an array of numbers.
+
 2019-07-09  Chris Dumez  <cdumez@apple.com>
 
         Fix non thread-safe use of WeakPtr in DisplayRefreshMonitorMac::displayLinkFired()
index 807116d..9b05c39 100644 (file)
 
 namespace WebCore {
 
-void CallTracer::recordCanvasAction(const HTMLCanvasElement& canvasElement, const String& name, Vector<RecordCanvasActionVariant>&& parameters)
+void CallTracer::recordCanvasAction(const HTMLCanvasElement& canvasElement, const String& name, std::initializer_list<RecordCanvasActionVariant>&& parameters)
 {
     if (auto* canvasRenderingContext = canvasElement.renderingContext())
         InspectorInstrumentation::recordCanvasAction(*canvasRenderingContext, name, WTFMove(parameters));
 }
 
-void CallTracer::recordCanvasAction(CanvasRenderingContext& canvasRenderingContext, const String& name, Vector<RecordCanvasActionVariant>&& parameters)
+void CallTracer::recordCanvasAction(CanvasRenderingContext& canvasRenderingContext, const String& name, std::initializer_list<RecordCanvasActionVariant>&& parameters)
 {
     InspectorInstrumentation::recordCanvasAction(canvasRenderingContext, name, WTFMove(parameters));
 }
index db264f3..fd571f9 100644 (file)
@@ -26,7 +26,7 @@
 #pragma once
 
 #include "CallTracerTypes.h"
-#include <wtf/Vector.h>
+#include <initializer_list>
 #include <wtf/text/WTFString.h>
 
 namespace WebCore {
@@ -36,8 +36,8 @@ class HTMLCanvasElement;
 
 class CallTracer {
 public:
-    static void recordCanvasAction(const HTMLCanvasElement&, const String&, Vector<RecordCanvasActionVariant>&& = { });
-    static void recordCanvasAction(CanvasRenderingContext&, const String&, Vector<RecordCanvasActionVariant>&& = { });
+    static void recordCanvasAction(const HTMLCanvasElement&, const String&, std::initializer_list<RecordCanvasActionVariant>&& = { });
+    static void recordCanvasAction(CanvasRenderingContext&, const String&, std::initializer_list<RecordCanvasActionVariant>&& = { });
 };
 
 } // namespace WebCore
index 7bc5406..e730a76 100644 (file)
@@ -42,6 +42,7 @@
 #include <JavaScriptCore/Float32Array.h>
 #include <JavaScriptCore/Int32Array.h>
 #include <JavaScriptCore/Uint32Array.h>
+#include <wtf/Optional.h>
 #include <wtf/RefPtr.h>
 #include <wtf/Variant.h>
 #include <wtf/Vector.h>
@@ -53,6 +54,7 @@
 #include "WebGLProgram.h"
 #include "WebGLQuery.h"
 #include "WebGLRenderbuffer.h"
+#include "WebGLRenderingContextBase.h"
 #include "WebGLSampler.h"
 #include "WebGLShader.h"
 #include "WebGLSync.h"
 #include "WebGLVertexArrayObject.h"
 #endif
 
+#if ENABLE(WEBGL2)
+#include "WebGL2RenderingContext.h"
+#endif
+
 namespace WebCore {
 
 using RecordCanvasActionVariant = Variant<
+    // enum
     CanvasDirection,
     CanvasFillRule,
     CanvasLineCap,
     CanvasLineJoin,
     CanvasTextAlign,
     CanvasTextBaseline,
+    ImageSmoothingQuality,
+
+    // struct
     DOMMatrix2DInit,
+
+    // pointer
     Element*,
     HTMLImageElement*,
     ImageBitmap*,
     ImageData*,
-    ImageSmoothingQuality,
     Path2D*,
 #if ENABLE(WEBGL)
     WebGLBuffer*,
@@ -109,13 +120,35 @@ using RecordCanvasActionVariant = Variant<
     RefPtr<ImageData>,
     RefPtr<Int32Array>,
     RefPtr<Uint32Array>,
+
+    // variant
+    CanvasImageSource,
+    CanvasRenderingContext2DBase::Style,
+#if ENABLE(WEBGL)
+    WebGLRenderingContextBase::BufferDataSource,
+    Optional<WebGLRenderingContextBase::BufferDataSource>,
+    WebGLRenderingContextBase::TexImageSource,
+    Optional<WebGLRenderingContextBase::TexImageSource>,
+#endif
+
+    // array
     Vector<String>,
     Vector<float>,
     Vector<uint32_t>,
     Vector<int32_t>,
+#if ENABLE(WEBGL)
+    WebGLRenderingContextBase::Float32List::VariantType,
+    WebGLRenderingContextBase::Int32List::VariantType,
+#endif
+#if ENABLE(WEBGL2)
+    WebGL2RenderingContext::Uint32List::VariantType,
+#endif
+
+    // basic
     String,
     double,
     float,
+    Optional<float>,
     uint64_t,
     int64_t,
     uint32_t,
index d0982de..0b6332b 100644 (file)
@@ -5063,8 +5063,7 @@ sub GenerateAttributeSetterBodyDefinition
         my $callTracingCallback = $attribute->extendedAttributes->{CallTracingCallback} || $interface->extendedAttributes->{CallTracingCallback};
         if ($callTracingCallback) {
             my $indent = "    ";
-            my @callTracerArguments = ();
-            push(@callTracerArguments, GenerateCallTracerParameter("nativeValue", $attribute->type, 0, $indent));
+            my @callTracerArguments = ("nativeValue");
             GenerateCallTracer($outputArray, $callTracingCallback, $attribute->name, \@callTracerArguments, $indent);
         }
 
@@ -6262,10 +6261,7 @@ sub GenerateImplementationFunctionCall
 
     my $callTracingCallback = $operation->extendedAttributes->{CallTracingCallback} || $interface->extendedAttributes->{CallTracingCallback};
     if ($callTracingCallback) {
-        my @callTracerArguments = ();
-        foreach my $argument (@{$operation->arguments}) {
-            push(@callTracerArguments, GenerateCallTracerParameter($argument->name, $argument->type, $argument->isOptional && !defined($argument->default), $indent));
-        }
+        my @callTracerArguments = map { $_->name } @{$operation->arguments};
         GenerateCallTracer($outputArray, $callTracingCallback, $operation->name, \@callTracerArguments, $indent);
     }
 
@@ -7505,57 +7501,18 @@ sub AddJSBuiltinIncludesIfNeeded()
     }
 }
 
-sub GenerateCallTracerParameter()
-{
-    my ($name, $type, $optional, $indent) = @_;
-
-    my $result = "";
-
-    if ($optional || $type->isNullable) {
-        $result .= $indent . "    if (" . $name . ")\n";
-        $result .= "    ";
-    }
-
-    $result .= $indent . "    ";
-
-    if ($type->isUnion) {
-        $result .= "WTF::visit([&] (auto& value) { callTracerParameters.append(value); }, ";
-    } else {
-        $result .= "callTracerParameters.append(";
-    }
-
-    if ($optional || ($type->isUnion && $type->isNullable)) {
-        $result .= "*";
-    }
-
-    $result .= $name . ");";
-
-    return $result;
-}
-
 sub GenerateCallTracer()
 {
     my ($outputArray, $callTracingCallback, $name, $arguments, $indent) = @_;
 
     AddToImplIncludes("CallTracer.h");
 
-    my $count = scalar(@$arguments);
-
-    push(@$outputArray, $indent . "if (UNLIKELY(impl.callTracingActive()))");
-    if ($count) {
-        push(@$outputArray, " {\n");
-        push(@$outputArray, $indent . "    Vector<" . $codeGenerator->WK_ucfirst($callTracingCallback) . "Variant> callTracerParameters;\n");
-        push(@$outputArray, join("\n", @$arguments));
-    }
-    push(@$outputArray, "\n");
+    push(@$outputArray, $indent . "if (UNLIKELY(impl.callTracingActive()))\n");
     push(@$outputArray, $indent . "    CallTracer::" . $callTracingCallback . "(impl, \"" . $name . "\"_s");
-    if ($count) {
-        push(@$outputArray, ", WTFMove(callTracerParameters)");
+    if (scalar(@$arguments)) {
+        push(@$outputArray, ", { " . join(", ", @$arguments) . " }");
     }
     push(@$outputArray, ");\n");
-    if ($count) {
-        push(@$outputArray, $indent . "}\n")
-    }
 }
 
 sub GenerateCustomElementReactionsStackIfNeeded
index 6b81bff..1b266af 100644 (file)
@@ -242,11 +242,8 @@ static inline bool setJSTestCallTracerTestAttributeInterfaceSetter(ExecState& st
     auto& impl = thisObject.wrapped();
     auto nativeValue = convert<IDLBoolean>(state, value);
     RETURN_IF_EXCEPTION(throwScope, false);
-    if (UNLIKELY(impl.callTracingActive())) {
-        Vector<TestCallTracerInterfaceVariant> callTracerParameters;
-        callTracerParameters.append(nativeValue);
-        CallTracer::testCallTracerInterface(impl, "testAttributeInterface"_s, WTFMove(callTracerParameters));
-    }
+    if (UNLIKELY(impl.callTracingActive()))
+        CallTracer::testCallTracerInterface(impl, "testAttributeInterface"_s, { nativeValue });
     AttributeSetter::call(state, throwScope, [&] {
         return impl.setTestAttributeInterface(WTFMove(nativeValue));
     });
@@ -280,11 +277,8 @@ static inline bool setJSTestCallTracerTestAttributeSpecifiedSetter(ExecState& st
     auto& impl = thisObject.wrapped();
     auto nativeValue = convert<IDLBoolean>(state, value);
     RETURN_IF_EXCEPTION(throwScope, false);
-    if (UNLIKELY(impl.callTracingActive())) {
-        Vector<TestCallTracerAttributeVariant> callTracerParameters;
-        callTracerParameters.append(nativeValue);
-        CallTracer::testCallTracerAttribute(impl, "testAttributeSpecified"_s, WTFMove(callTracerParameters));
-    }
+    if (UNLIKELY(impl.callTracingActive()))
+        CallTracer::testCallTracerAttribute(impl, "testAttributeSpecified"_s, { nativeValue });
     AttributeSetter::call(state, throwScope, [&] {
         return impl.setTestAttributeSpecified(WTFMove(nativeValue));
     });
@@ -318,11 +312,8 @@ static inline bool setJSTestCallTracerTestAttributeWithVariantSetter(ExecState&
     auto& impl = thisObject.wrapped();
     auto nativeValue = convert<IDLUnion<IDLBoolean, IDLFloat, IDLDOMString>>(state, value);
     RETURN_IF_EXCEPTION(throwScope, false);
-    if (UNLIKELY(impl.callTracingActive())) {
-        Vector<TestCallTracerInterfaceVariant> callTracerParameters;
-        WTF::visit([&] (auto& value) { callTracerParameters.append(value); }, nativeValue);
-        CallTracer::testCallTracerInterface(impl, "testAttributeWithVariant"_s, WTFMove(callTracerParameters));
-    }
+    if (UNLIKELY(impl.callTracingActive()))
+        CallTracer::testCallTracerInterface(impl, "testAttributeWithVariant"_s, { nativeValue });
     AttributeSetter::call(state, throwScope, [&] {
         return impl.setTestAttributeWithVariant(WTFMove(nativeValue));
     });
@@ -393,13 +384,8 @@ static inline JSC::EncodedJSValue jsTestCallTracerPrototypeFunctionTestOperation
     RETURN_IF_EXCEPTION(throwScope, encodedJSValue());
     auto c = convert<IDLDOMString>(*state, state->uncheckedArgument(2));
     RETURN_IF_EXCEPTION(throwScope, encodedJSValue());
-    if (UNLIKELY(impl.callTracingActive())) {
-        Vector<TestCallTracerInterfaceVariant> callTracerParameters;
-        callTracerParameters.append(a);
-        callTracerParameters.append(b);
-        callTracerParameters.append(c);
-        CallTracer::testCallTracerInterface(impl, "testOperationWithArguments"_s, WTFMove(callTracerParameters));
-    }
+    if (UNLIKELY(impl.callTracingActive()))
+        CallTracer::testCallTracerInterface(impl, "testOperationWithArguments"_s, { a, b, c });
     impl.testOperationWithArguments(WTFMove(a), WTFMove(b), WTFMove(c));
     return JSValue::encode(jsUndefined());
 }
@@ -418,12 +404,8 @@ static inline JSC::EncodedJSValue jsTestCallTracerPrototypeFunctionTestOperation
         return throwVMError(state, throwScope, createNotEnoughArgumentsError(state));
     auto nodeNullableArg = convert<IDLNullable<IDLInterface<Node>>>(*state, state->uncheckedArgument(0), [](JSC::ExecState& state, JSC::ThrowScope& scope) { throwArgumentTypeError(state, scope, 0, "nodeNullableArg", "TestCallTracer", "testOperationWithNullableArgument", "Node"); });
     RETURN_IF_EXCEPTION(throwScope, encodedJSValue());
-    if (UNLIKELY(impl.callTracingActive())) {
-        Vector<TestCallTracerInterfaceVariant> callTracerParameters;
-        if (nodeNullableArg)
-            callTracerParameters.append(nodeNullableArg);
-        CallTracer::testCallTracerInterface(impl, "testOperationWithNullableArgument"_s, WTFMove(callTracerParameters));
-    }
+    if (UNLIKELY(impl.callTracingActive()))
+        CallTracer::testCallTracerInterface(impl, "testOperationWithNullableArgument"_s, { nodeNullableArg });
     impl.testOperationWithNullableArgument(WTFMove(nodeNullableArg));
     return JSValue::encode(jsUndefined());
 }
@@ -442,11 +424,8 @@ static inline JSC::EncodedJSValue jsTestCallTracerPrototypeFunctionTestOperation
         return throwVMError(state, throwScope, createNotEnoughArgumentsError(state));
     auto variantArg = convert<IDLUnion<IDLBoolean, IDLFloat, IDLDOMString>>(*state, state->uncheckedArgument(0));
     RETURN_IF_EXCEPTION(throwScope, encodedJSValue());
-    if (UNLIKELY(impl.callTracingActive())) {
-        Vector<TestCallTracerInterfaceVariant> callTracerParameters;
-        WTF::visit([&] (auto& value) { callTracerParameters.append(value); }, variantArg);
-        CallTracer::testCallTracerInterface(impl, "testOperationWithVariantArgument"_s, WTFMove(callTracerParameters));
-    }
+    if (UNLIKELY(impl.callTracingActive()))
+        CallTracer::testCallTracerInterface(impl, "testOperationWithVariantArgument"_s, { variantArg });
     impl.testOperationWithVariantArgument(WTFMove(variantArg));
     return JSValue::encode(jsUndefined());
 }
@@ -465,12 +444,8 @@ static inline JSC::EncodedJSValue jsTestCallTracerPrototypeFunctionTestOperation
         return throwVMError(state, throwScope, createNotEnoughArgumentsError(state));
     auto variantNullableArg = convert<IDLNullable<IDLUnion<IDLBoolean, IDLFloat, IDLDOMString>>>(*state, state->uncheckedArgument(0));
     RETURN_IF_EXCEPTION(throwScope, encodedJSValue());
-    if (UNLIKELY(impl.callTracingActive())) {
-        Vector<TestCallTracerInterfaceVariant> callTracerParameters;
-        if (variantNullableArg)
-            WTF::visit([&] (auto& value) { callTracerParameters.append(value); }, *variantNullableArg);
-        CallTracer::testCallTracerInterface(impl, "testOperationWithNullableVariantArgument"_s, WTFMove(callTracerParameters));
-    }
+    if (UNLIKELY(impl.callTracingActive()))
+        CallTracer::testCallTracerInterface(impl, "testOperationWithNullableVariantArgument"_s, { variantNullableArg });
     impl.testOperationWithNullableVariantArgument(WTFMove(variantNullableArg));
     return JSValue::encode(jsUndefined());
 }
@@ -487,12 +462,8 @@ static inline JSC::EncodedJSValue jsTestCallTracerPrototypeFunctionTestOperation
     auto& impl = castedThis->wrapped();
     auto variantOptionalArg = state->argument(0).isUndefined() ? Optional<Converter<IDLUnion<IDLBoolean, IDLFloat, IDLDOMString>>::ReturnType>() : Optional<Converter<IDLUnion<IDLBoolean, IDLFloat, IDLDOMString>>::ReturnType>(convert<IDLUnion<IDLBoolean, IDLFloat, IDLDOMString>>(*state, state->uncheckedArgument(0)));
     RETURN_IF_EXCEPTION(throwScope, encodedJSValue());
-    if (UNLIKELY(impl.callTracingActive())) {
-        Vector<TestCallTracerInterfaceVariant> callTracerParameters;
-        if (variantOptionalArg)
-            WTF::visit([&] (auto& value) { callTracerParameters.append(value); }, *variantOptionalArg);
-        CallTracer::testCallTracerInterface(impl, "testOperationWithOptionalVariantArgument"_s, WTFMove(callTracerParameters));
-    }
+    if (UNLIKELY(impl.callTracingActive()))
+        CallTracer::testCallTracerInterface(impl, "testOperationWithOptionalVariantArgument"_s, { variantOptionalArg });
     impl.testOperationWithOptionalVariantArgument(WTFMove(variantOptionalArg));
     return JSValue::encode(jsUndefined());
 }
@@ -509,11 +480,8 @@ static inline JSC::EncodedJSValue jsTestCallTracerPrototypeFunctionTestOperation
     auto& impl = castedThis->wrapped();
     auto variantDefaultArg = state->argument(0).isUndefined() ? "" : convert<IDLUnion<IDLBoolean, IDLFloat, IDLDOMString>>(*state, state->uncheckedArgument(0));
     RETURN_IF_EXCEPTION(throwScope, encodedJSValue());
-    if (UNLIKELY(impl.callTracingActive())) {
-        Vector<TestCallTracerInterfaceVariant> callTracerParameters;
-        WTF::visit([&] (auto& value) { callTracerParameters.append(value); }, variantDefaultArg);
-        CallTracer::testCallTracerInterface(impl, "testOperationWithDefaultVariantArgument"_s, WTFMove(callTracerParameters));
-    }
+    if (UNLIKELY(impl.callTracingActive()))
+        CallTracer::testCallTracerInterface(impl, "testOperationWithDefaultVariantArgument"_s, { variantDefaultArg });
     impl.testOperationWithDefaultVariantArgument(WTFMove(variantDefaultArg));
     return JSValue::encode(jsUndefined());
 }
index 4b22d5d..29be2a0 100644 (file)
@@ -71,6 +71,7 @@
 #endif
 #include <JavaScriptCore/IdentifiersFactory.h>
 #include <JavaScriptCore/ScriptCallStackFactory.h>
+#include <wtf/Function.h>
 
 namespace WebCore {
 
@@ -158,7 +159,7 @@ static bool shouldSnapshotWebGL2Action(const String& name)
 }
 #endif
 
-void InspectorCanvas::recordAction(const String& name, Vector<RecordCanvasActionVariant>&& parameters)
+void InspectorCanvas::recordAction(const String& name, std::initializer_list<RecordCanvasActionVariant>&& parameters)
 {
     if (!m_initialState) {
         // We should only construct the initial state for the first action of the recording.
@@ -655,7 +656,7 @@ Ref<Inspector::Protocol::Recording::InitialState> InspectorCanvas::buildInitialS
     return initialStatePayload;
 }
 
-Ref<JSON::ArrayOf<JSON::Value>> InspectorCanvas::buildAction(const String& name, Vector<RecordCanvasActionVariant>&& parameters)
+Ref<JSON::ArrayOf<JSON::Value>> InspectorCanvas::buildAction(const String& name, std::initializer_list<RecordCanvasActionVariant>&& parameters)
 {
     auto action = JSON::ArrayOf<JSON::Value>::create();
     action->addItem(indexForData(name));
@@ -668,14 +669,17 @@ Ref<JSON::ArrayOf<JSON::Value>> InspectorCanvas::buildAction(const String& name,
         swizzleTypes->addItem(static_cast<int>(swizzleType));
     };
 
-    for (auto& item : parameters) {
-        WTF::switchOn(item,
+    // Declared before it's initialized so it can be used recursively.
+    Function<void(const RecordCanvasActionVariant&)> parseParameter;
+    parseParameter = [&] (const auto& parameter) {
+        WTF::switchOn(parameter,
             [&] (CanvasDirection value) { addParameter(indexForData(convertEnumerationToString(value)), RecordingSwizzleTypes::String); },
             [&] (CanvasFillRule value) { addParameter(indexForData(convertEnumerationToString(value)), RecordingSwizzleTypes::String); },
             [&] (CanvasLineCap value) { addParameter(indexForData(convertEnumerationToString(value)), RecordingSwizzleTypes::String); },
             [&] (CanvasLineJoin value) { addParameter(indexForData(convertEnumerationToString(value)), RecordingSwizzleTypes::String); },
             [&] (CanvasTextAlign value) { addParameter(indexForData(convertEnumerationToString(value)), RecordingSwizzleTypes::String); },
             [&] (CanvasTextBaseline value) { addParameter(indexForData(convertEnumerationToString(value)), RecordingSwizzleTypes::String); },
+            [&] (ImageSmoothingQuality value) { addParameter(indexForData(convertEnumerationToString(value)), RecordingSwizzleTypes::String); },
             [&] (const DOMMatrix2DInit& value) {
                 auto array = JSON::ArrayOf<double>::create();
                 array->addItem(value.a.valueOr(1));
@@ -686,53 +690,159 @@ Ref<JSON::ArrayOf<JSON::Value>> InspectorCanvas::buildAction(const String& name,
                 array->addItem(value.f.valueOr(0));
                 addParameter(array.ptr(), RecordingSwizzleTypes::DOMMatrix);
             },
-            [&] (const Element*) {
-                // Elements are not serializable, so add a string as a placeholder since the actual
-                // element cannot be reconstructed in the frontend.
-                addParameter(indexForData("Element"), RecordingSwizzleTypes::None);
+            [&] (const Element* value) {
+                if (value) {
+                    // Elements are not serializable, so add a string as a placeholder since the actual
+                    // element cannot be reconstructed in the frontend.
+                    addParameter(indexForData("Element"), RecordingSwizzleTypes::None);
+                }
             },
-            [&] (HTMLImageElement* value) { addParameter(indexForData(value), RecordingSwizzleTypes::Image); },
-            [&] (ImageBitmap* value) { addParameter(indexForData(value), RecordingSwizzleTypes::ImageBitmap); },
-            [&] (ImageData* value) { addParameter(indexForData(value), RecordingSwizzleTypes::ImageData); },
-            [&] (ImageSmoothingQuality value) { addParameter(indexForData(convertEnumerationToString(value)), RecordingSwizzleTypes::String); },
-            [&] (const Path2D* value) { addParameter(indexForData(buildStringFromPath(value->path())), RecordingSwizzleTypes::Path2D); },
+            [&] (HTMLImageElement* value) {
+                if (value)
+                    addParameter(indexForData(value), RecordingSwizzleTypes::Image); },
+            [&] (ImageBitmap* value) {
+                if (value)
+                    addParameter(indexForData(value), RecordingSwizzleTypes::ImageBitmap); },
+            [&] (ImageData* value) {
+                if (value)
+                    addParameter(indexForData(value), RecordingSwizzleTypes::ImageData); },
+            [&] (const Path2D* value) {
+                if (value)
+                    addParameter(indexForData(buildStringFromPath(value->path())), RecordingSwizzleTypes::Path2D); },
 #if ENABLE(WEBGL)
             // FIXME: <https://webkit.org/b/176009> Web Inspector: send data for WebGL objects during a recording instead of a placeholder string
-            [&] (const WebGLBuffer*) { addParameter(0, RecordingSwizzleTypes::WebGLBuffer); },
-            [&] (const WebGLFramebuffer*) { addParameter(0, RecordingSwizzleTypes::WebGLFramebuffer); },
-            [&] (const WebGLProgram*) { addParameter(0, RecordingSwizzleTypes::WebGLProgram); },
-            [&] (const WebGLQuery*) { addParameter(0, RecordingSwizzleTypes::WebGLQuery); },
-            [&] (const WebGLRenderbuffer*) { addParameter(0, RecordingSwizzleTypes::WebGLRenderbuffer); },
-            [&] (const WebGLSampler*) { addParameter(0, RecordingSwizzleTypes::WebGLSampler); },
-            [&] (const WebGLShader*) { addParameter(0, RecordingSwizzleTypes::WebGLShader); },
-            [&] (const WebGLSync*) { addParameter(0, RecordingSwizzleTypes::WebGLSync); },
-            [&] (const WebGLTexture*) { addParameter(0, RecordingSwizzleTypes::WebGLTexture); },
-            [&] (const WebGLTransformFeedback*) { addParameter(0, RecordingSwizzleTypes::WebGLTransformFeedback); },
-            [&] (const WebGLUniformLocation*) { addParameter(0, RecordingSwizzleTypes::WebGLUniformLocation); },
-            [&] (const WebGLVertexArrayObject*) { addParameter(0, RecordingSwizzleTypes::WebGLVertexArrayObject); },
+            [&] (const WebGLBuffer* value) {
+                if (value)
+                    addParameter(0, RecordingSwizzleTypes::WebGLBuffer);
+            },
+            [&] (const WebGLFramebuffer* value) {
+                if (value)
+                    addParameter(0, RecordingSwizzleTypes::WebGLFramebuffer);
+            },
+            [&] (const WebGLProgram* value) {
+                if (value)
+                    addParameter(0, RecordingSwizzleTypes::WebGLProgram);
+            },
+            [&] (const WebGLQuery* value) {
+                if (value)
+                    addParameter(0, RecordingSwizzleTypes::WebGLQuery);
+            },
+            [&] (const WebGLRenderbuffer* value) {
+                if (value)
+                    addParameter(0, RecordingSwizzleTypes::WebGLRenderbuffer);
+            },
+            [&] (const WebGLSampler* value) {
+                if (value)
+                    addParameter(0, RecordingSwizzleTypes::WebGLSampler);
+            },
+            [&] (const WebGLShader* value) {
+                if (value)
+                    addParameter(0, RecordingSwizzleTypes::WebGLShader);
+            },
+            [&] (const WebGLSync* value) {
+                if (value)
+                    addParameter(0, RecordingSwizzleTypes::WebGLSync);
+            },
+            [&] (const WebGLTexture* value) {
+                if (value)
+                    addParameter(0, RecordingSwizzleTypes::WebGLTexture);
+            },
+            [&] (const WebGLTransformFeedback* value) {
+                if (value)
+                    addParameter(0, RecordingSwizzleTypes::WebGLTransformFeedback);
+            },
+            [&] (const WebGLUniformLocation* value) {
+                if (value)
+                    addParameter(0, RecordingSwizzleTypes::WebGLUniformLocation);
+            },
+            [&] (const WebGLVertexArrayObject* value) {
+                if (value)
+                    addParameter(0, RecordingSwizzleTypes::WebGLVertexArrayObject);
+            },
 #endif
-            [&] (const RefPtr<ArrayBuffer>&) { addParameter(0, RecordingSwizzleTypes::TypedArray); },
-            [&] (const RefPtr<ArrayBufferView>&) { addParameter(0, RecordingSwizzleTypes::TypedArray); },
-            [&] (const RefPtr<CanvasGradient>& value) { addParameter(indexForData(value), RecordingSwizzleTypes::CanvasGradient); },
-            [&] (const RefPtr<CanvasPattern>& value) { addParameter(indexForData(value), RecordingSwizzleTypes::CanvasPattern); },
-            [&] (const RefPtr<Float32Array>&) { addParameter(0, RecordingSwizzleTypes::TypedArray); },
-            [&] (const RefPtr<HTMLCanvasElement>& value) { addParameter(indexForData(value), RecordingSwizzleTypes::Image); },
-            [&] (const RefPtr<HTMLImageElement>& value) { addParameter(indexForData(value), RecordingSwizzleTypes::Image); },
+            [&] (const RefPtr<ArrayBuffer>& value) {
+                if (value)
+                    addParameter(0, RecordingSwizzleTypes::TypedArray);
+            },
+            [&] (const RefPtr<ArrayBufferView>& value) {
+                if (value)
+                    addParameter(0, RecordingSwizzleTypes::TypedArray);
+            },
+            [&] (const RefPtr<CanvasGradient>& value) {
+                if (value)
+                    addParameter(indexForData(value), RecordingSwizzleTypes::CanvasGradient);
+            },
+            [&] (const RefPtr<CanvasPattern>& value) {
+                if (value)
+                    addParameter(indexForData(value), RecordingSwizzleTypes::CanvasPattern);
+            },
+            [&] (const RefPtr<Float32Array>& value) {
+                if (value)
+                    addParameter(0, RecordingSwizzleTypes::TypedArray);
+            },
+            [&] (const RefPtr<HTMLCanvasElement>& value) {
+                if (value)
+                    addParameter(indexForData(value), RecordingSwizzleTypes::Image);
+            },
+            [&] (const RefPtr<HTMLImageElement>& value) {
+                if (value)
+                    addParameter(indexForData(value), RecordingSwizzleTypes::Image);
+            },
 #if ENABLE(VIDEO)
-            [&] (const RefPtr<HTMLVideoElement>& value) { addParameter(indexForData(value), RecordingSwizzleTypes::Image); },
+            [&] (const RefPtr<HTMLVideoElement>& value) {
+                if (value)
+                    addParameter(indexForData(value), RecordingSwizzleTypes::Image);
+            },
 #endif
 #if ENABLE(CSS_TYPED_OM)
-            [&] (const RefPtr<TypedOMCSSImageValue>& value) { addParameter(indexForData(value), RecordingSwizzleTypes::Image); },
+            [&] (const RefPtr<TypedOMCSSImageValue>& value) {
+                if (value)
+                    addParameter(indexForData(value), RecordingSwizzleTypes::Image);
+            },
+#endif
+            [&] (const RefPtr<ImageBitmap>& value) {
+                if (value)
+                    addParameter(indexForData(value), RecordingSwizzleTypes::ImageBitmap);
+            },
+            [&] (const RefPtr<ImageData>& value) {
+                if (value)
+                    addParameter(indexForData(value), RecordingSwizzleTypes::ImageData);
+            },
+            [&] (const RefPtr<Int32Array>& value) {
+                if (value)
+                    addParameter(0, RecordingSwizzleTypes::TypedArray);
+            },
+            [&] (const RefPtr<Uint32Array>& value) {
+                if (value)
+                    addParameter(0, RecordingSwizzleTypes::TypedArray);
+            },
+            [&] (const CanvasImageSource& value) {
+                WTF::visit(parseParameter, value);
+            },
+            [&] (const CanvasRenderingContext2DBase::Style& value) {
+                WTF::visit(parseParameter, value);
+            },
+#if ENABLE(WEBGL)
+            [&] (const WebGLRenderingContextBase::BufferDataSource& value) {
+                WTF::visit(parseParameter, value);
+            },
+            [&] (const Optional<WebGLRenderingContextBase::BufferDataSource>& value) {
+                if (value)
+                    parseParameter(value.value());
+            },
+            [&] (const WebGLRenderingContextBase::TexImageSource& value) {
+                WTF::visit(parseParameter, value);
+            },
+            [&] (const Optional<WebGLRenderingContextBase::TexImageSource>& value) {
+                if (value)
+                    parseParameter(value.value());
+            },
 #endif
-            [&] (const RefPtr<ImageBitmap>& value) { addParameter(indexForData(value), RecordingSwizzleTypes::ImageBitmap); },
-            [&] (const RefPtr<ImageData>& value) { addParameter(indexForData(value), RecordingSwizzleTypes::ImageData); },
-            [&] (const RefPtr<Int32Array>&) { addParameter(0, RecordingSwizzleTypes::TypedArray); },
-            [&] (const RefPtr<Uint32Array>&) { addParameter(0, RecordingSwizzleTypes::TypedArray); },
             [&] (const Vector<String>& value) {
                 auto deduplicated = value.map([&] (const String& item) {
                     return indexForData(item);
                 });
-                addParameter(buildArrayForVector(deduplicated).ptr(), RecordingSwizzleTypes::Array);
+                addParameter(buildArrayForVector(deduplicated).ptr(), RecordingSwizzleTypes::String);
             },
             [&] (const Vector<float>& value) { addParameter(buildArrayForVector(value).ptr(), RecordingSwizzleTypes::Array); },
             [&] (const Vector<uint32_t>& value) {
@@ -742,9 +852,26 @@ Ref<JSON::ArrayOf<JSON::Value>> InspectorCanvas::buildAction(const String& name,
                 addParameter(buildArrayForVector(mapped).ptr(), RecordingSwizzleTypes::Array);
             },
             [&] (const Vector<int32_t>& value) { addParameter(buildArrayForVector(value).ptr(), RecordingSwizzleTypes::Array); },
+#if ENABLE(WEBGL)
+            [&] (const WebGLRenderingContextBase::Float32List::VariantType& value) {
+                WTF::visit(parseParameter, value);
+            },
+            [&] (const WebGLRenderingContextBase::Int32List::VariantType& value) {
+                WTF::visit(parseParameter, value);
+            },
+#endif
+#if ENABLE(WEBGL2)
+            [&] (const WebGL2RenderingContext::Uint32List::VariantType& value) {
+                WTF::visit(parseParameter, value);
+            },
+#endif
             [&] (const String& value) { addParameter(indexForData(value), RecordingSwizzleTypes::String); },
             [&] (double value) { addParameter(value, RecordingSwizzleTypes::Number); },
             [&] (float value) { addParameter(value, RecordingSwizzleTypes::Number); },
+            [&] (const Optional<float>& value) {
+                if (value)
+                    parseParameter(value.value());
+            },
             [&] (uint64_t value) { addParameter(static_cast<double>(value), RecordingSwizzleTypes::Number); },
             [&] (int64_t value) { addParameter(static_cast<double>(value), RecordingSwizzleTypes::Number); },
             [&] (uint32_t value) { addParameter(static_cast<double>(value), RecordingSwizzleTypes::Number); },
@@ -752,7 +879,9 @@ Ref<JSON::ArrayOf<JSON::Value>> InspectorCanvas::buildAction(const String& name,
             [&] (uint8_t value) { addParameter(static_cast<int>(value), RecordingSwizzleTypes::Number); },
             [&] (bool value) { addParameter(value, RecordingSwizzleTypes::Boolean); }
         );
-    }
+    };
+    for (auto& parameter : parameters)
+        parseParameter(parameter);
 
     action->addItem(WTFMove(parametersData));
     action->addItem(WTFMove(swizzleTypes));
index 6886e62..38542fb 100644 (file)
@@ -29,6 +29,7 @@
 #include <JavaScriptCore/InspectorProtocolObjects.h>
 #include <JavaScriptCore/ScriptCallFrame.h>
 #include <JavaScriptCore/ScriptCallStack.h>
+#include <initializer_list>
 #include <wtf/Variant.h>
 #include <wtf/Vector.h>
 #include <wtf/text/WTFString.h>
@@ -63,7 +64,7 @@ public:
     void resetRecordingData();
     bool hasRecordingData() const;
     bool currentFrameHasData() const;
-    void recordAction(const String&, Vector<RecordCanvasActionVariant>&& = { });
+    void recordAction(const String&, std::initializer_list<RecordCanvasActionVariant>&& = { });
 
     Ref<JSON::ArrayOf<Inspector::Protocol::Recording::Frame>> releaseFrames() { return m_frames.releaseNonNull(); }
 
@@ -109,7 +110,7 @@ private:
     int indexForData(DuplicateDataVariant);
     String stringIndexForKey(const String&);
     Ref<Inspector::Protocol::Recording::InitialState> buildInitialState();
-    Ref<JSON::ArrayOf<JSON::Value>> buildAction(const String&, Vector<RecordCanvasActionVariant>&& = { });
+    Ref<JSON::ArrayOf<JSON::Value>> buildAction(const String&, std::initializer_list<RecordCanvasActionVariant>&& = { });
     Ref<JSON::ArrayOf<JSON::Value>> buildArrayForCanvasGradient(const CanvasGradient&);
     Ref<JSON::ArrayOf<JSON::Value>> buildArrayForCanvasPattern(const CanvasPattern&);
     Ref<JSON::ArrayOf<JSON::Value>> buildArrayForImageData(const ImageData&);
index fbb8af4..a904c03 100644 (file)
@@ -1036,7 +1036,7 @@ void InspectorInstrumentation::didChangeCanvasMemoryImpl(InstrumentingAgents& in
         canvasAgent->didChangeCanvasMemory(context);
 }
 
-void InspectorInstrumentation::recordCanvasActionImpl(InstrumentingAgents& instrumentingAgents, CanvasRenderingContext& canvasRenderingContext, const String& name, Vector<RecordCanvasActionVariant>&& parameters)
+void InspectorInstrumentation::recordCanvasActionImpl(InstrumentingAgents& instrumentingAgents, CanvasRenderingContext& canvasRenderingContext, const String& name, std::initializer_list<RecordCanvasActionVariant>&& parameters)
 {
     if (InspectorCanvasAgent* canvasAgent = instrumentingAgents.inspectorCanvasAgent())
         canvasAgent->recordCanvasAction(canvasRenderingContext, name, WTFMove(parameters));
index 9791a86..9cadfb1 100644 (file)
@@ -50,6 +50,7 @@
 #include "WorkerGlobalScope.h"
 #include "WorkerInspectorController.h"
 #include <JavaScriptCore/JSCInlines.h>
+#include <initializer_list>
 #include <wtf/MemoryPressureHandler.h>
 #include <wtf/RefPtr.h>
 
@@ -269,7 +270,7 @@ public:
     static void didChangeCSSCanvasClientNodes(CanvasBase&);
     static void didCreateCanvasRenderingContext(CanvasRenderingContext&);
     static void didChangeCanvasMemory(CanvasRenderingContext&);
-    static void recordCanvasAction(CanvasRenderingContext&, const String&, Vector<RecordCanvasActionVariant>&& = { });
+    static void recordCanvasAction(CanvasRenderingContext&, const String&, std::initializer_list<RecordCanvasActionVariant>&& = { });
     static void didFinishRecordingCanvasFrame(CanvasRenderingContext&, bool forceDispatch = false);
 #if ENABLE(WEBGL)
     static void didEnableExtension(WebGLRenderingContextBase&, const String&);
@@ -452,7 +453,7 @@ private:
     static void didChangeCSSCanvasClientNodesImpl(InstrumentingAgents&, CanvasBase&);
     static void didCreateCanvasRenderingContextImpl(InstrumentingAgents&, CanvasRenderingContext&);
     static void didChangeCanvasMemoryImpl(InstrumentingAgents&, CanvasRenderingContext&);
-    static void recordCanvasActionImpl(InstrumentingAgents&, CanvasRenderingContext&, const String&, Vector<RecordCanvasActionVariant>&& = { });
+    static void recordCanvasActionImpl(InstrumentingAgents&, CanvasRenderingContext&, const String&, std::initializer_list<RecordCanvasActionVariant>&& = { });
     static void didFinishRecordingCanvasFrameImpl(InstrumentingAgents&, CanvasRenderingContext&, bool forceDispatch = false);
 #if ENABLE(WEBGL)
     static void didEnableExtensionImpl(InstrumentingAgents&, WebGLRenderingContextBase&, const String&);
@@ -1311,7 +1312,7 @@ inline void InspectorInstrumentation::didChangeCanvasMemory(CanvasRenderingConte
         didChangeCanvasMemoryImpl(*instrumentingAgents, context);
 }
 
-inline void InspectorInstrumentation::recordCanvasAction(CanvasRenderingContext& context, const String& name, Vector<RecordCanvasActionVariant>&& parameters)
+inline void InspectorInstrumentation::recordCanvasAction(CanvasRenderingContext& context, const String& name, std::initializer_list<RecordCanvasActionVariant>&& parameters)
 {
     FAST_RETURN_IF_NO_FRONTENDS(void());
     if (InstrumentingAgents* instrumentingAgents = instrumentingAgentsForContext(context.canvasBase().scriptExecutionContext()))
index a33b603..9be0611 100644 (file)
@@ -420,7 +420,7 @@ void InspectorCanvasAgent::didChangeCanvasMemory(CanvasRenderingContext& context
         m_frontendDispatcher->canvasMemoryChanged(inspectorCanvas->identifier(), node->memoryCost());
 }
 
-void InspectorCanvasAgent::recordCanvasAction(CanvasRenderingContext& canvasRenderingContext, const String& name, Vector<RecordCanvasActionVariant>&& parameters)
+void InspectorCanvasAgent::recordCanvasAction(CanvasRenderingContext& canvasRenderingContext, const String& name, std::initializer_list<RecordCanvasActionVariant>&& parameters)
 {
     auto inspectorCanvas = findInspectorCanvas(canvasRenderingContext);
     ASSERT(inspectorCanvas);
index 59a2250..fa0f6cc 100644 (file)
@@ -32,6 +32,7 @@
 #include "Timer.h"
 #include <JavaScriptCore/InspectorBackendDispatchers.h>
 #include <JavaScriptCore/InspectorFrontendDispatchers.h>
+#include <initializer_list>
 #include <wtf/HashMap.h>
 #include <wtf/RefPtr.h>
 #include <wtf/Vector.h>
@@ -87,7 +88,7 @@ public:
     void didCreateCanvasRenderingContext(CanvasRenderingContext&);
     void willDestroyCanvasRenderingContext(CanvasRenderingContext&);
     void didChangeCanvasMemory(CanvasRenderingContext&);
-    void recordCanvasAction(CanvasRenderingContext&, const String&, Vector<RecordCanvasActionVariant>&& = { });
+    void recordCanvasAction(CanvasRenderingContext&, const String&, std::initializer_list<RecordCanvasActionVariant>&& = { });
     void didFinishRecordingCanvasFrame(CanvasRenderingContext&, bool forceDispatch = false);
     void consoleStartRecordingCanvas(CanvasRenderingContext&, JSC::ExecState&, JSC::JSObject* options);
 #if ENABLE(WEBGL)
index 926e5fe..682145d 100644 (file)
@@ -1,3 +1,15 @@
+2019-07-09  Devin Rousso  <drousso@apple.com>
+
+        Web Inspector: Canvas: replace WTF::Vector with std::initializer_list in CallTracer to avoid dynamic allocations
+        https://bugs.webkit.org/show_bug.cgi?id=199611
+
+        Reviewed by Joseph Pecoraro.
+
+        * UserInterface/Models/Recording.js:
+        (WI.Recording.prototype.async swizzle):
+        Drive-by: handle the situation where a parameter is an array of deduplicated strings, which
+                  would otherwise be treated as an array of numbers.
+
 2019-07-09  Joseph Pecoraro  <pecoraro@apple.com>
 
         Web Inspector: Add another Protocol Version (iOS 13.0)
index c9b7434..3847ce6 100644 (file)
@@ -352,7 +352,10 @@ WI.Recording = class Recording extends WI.Object
                     break;
 
                 case WI.Recording.Swizzle.String:
-                    this._swizzle[index][type] = String(data);
+                    if (Array.isArray(data))
+                        this._swizzle[index][type] = await Promise.all(data.map((item) => this.swizzle(item, WI.Recording.Swizzle.String)));
+                    else
+                        this._swizzle[index][type] = String(data);
                     break;
 
                 case WI.Recording.Swizzle.Image: