WHLSL Metal code generation unnecessarily does string copies by passing partial resul...
authorweinig@apple.com <weinig@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 6 Aug 2019 19:04:00 +0000 (19:04 +0000)
committerweinig@apple.com <weinig@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 6 Aug 2019 19:04:00 +0000 (19:04 +0000)
https://bugs.webkit.org/show_bug.cgi?id=200471

Reviewed by Saam Barati.

Avoid string copies by passing a single StringBuilder all the way through Metal code
generation and only converting to a String when passing the constructed shader to Metal
API.

Where possible, use StringView in lieu of String for temporary strings being passed to
the StringBuilder to avoid the allocation overhead of StringImpl.

* Modules/webgpu/WHLSL/AST/WHLSLAddressSpace.h:
(WebCore::WHLSL::AST::toString):
Switch to StringView.

* Modules/webgpu/WHLSL/AST/WHLSLBuiltInSemantic.h:
(WebCore::WHLSL::AST::BuiltInSemantic::toString const):
Switch to StringView.

* Modules/webgpu/WHLSL/AST/WHLSLEntryPointType.h:
(WebCore::WHLSL::AST::toString):
Switch to StringView.

* Modules/webgpu/WHLSL/AST/WHLSLPointerType.h:
Remove unnecessary "private:".

* Modules/webgpu/WHLSL/AST/WHLSLResourceSemantic.h:
(WebCore::WHLSL::AST::ResourceSemantic::toString):
Switch to StringView.

* Modules/webgpu/WHLSL/Metal/WHLSLEntryPointScaffolding.cpp:
(WebCore::WHLSL::Metal::EntryPointScaffolding::emitResourceHelperTypes):
(WebCore::WHLSL::Metal::EntryPointScaffolding::emitResourceSignature):
(WebCore::WHLSL::Metal::EntryPointScaffolding::emitBuiltInsSignature):
(WebCore::WHLSL::Metal::EntryPointScaffolding::emitMangledInputPath):
(WebCore::WHLSL::Metal::EntryPointScaffolding::emitMangledOutputPath):
(WebCore::WHLSL::Metal::EntryPointScaffolding::emitUnpackResourcesAndNamedBuiltIns):
(WebCore::WHLSL::Metal::VertexEntryPointScaffolding::emitHelperTypes):
(WebCore::WHLSL::Metal::VertexEntryPointScaffolding::emitSignature):
(WebCore::WHLSL::Metal::VertexEntryPointScaffolding::emitUnpack):
(WebCore::WHLSL::Metal::VertexEntryPointScaffolding::emitPack):
(WebCore::WHLSL::Metal::FragmentEntryPointScaffolding::emitHelperTypes):
(WebCore::WHLSL::Metal::FragmentEntryPointScaffolding::emitSignature):
(WebCore::WHLSL::Metal::FragmentEntryPointScaffolding::emitUnpack):
(WebCore::WHLSL::Metal::FragmentEntryPointScaffolding::emitPack):
(WebCore::WHLSL::Metal::ComputeEntryPointScaffolding::emitHelperTypes):
(WebCore::WHLSL::Metal::ComputeEntryPointScaffolding::emitSignature):
(WebCore::WHLSL::Metal::ComputeEntryPointScaffolding::emitUnpack):
(WebCore::WHLSL::Metal::ComputeEntryPointScaffolding::emitPack):
(WebCore::WHLSL::Metal::EntryPointScaffolding::resourceHelperTypes): Deleted.
(WebCore::WHLSL::Metal::EntryPointScaffolding::resourceSignature): Deleted.
(WebCore::WHLSL::Metal::EntryPointScaffolding::builtInsSignature): Deleted.
(WebCore::WHLSL::Metal::EntryPointScaffolding::mangledInputPath): Deleted.
(WebCore::WHLSL::Metal::EntryPointScaffolding::mangledOutputPath): Deleted.
(WebCore::WHLSL::Metal::EntryPointScaffolding::unpackResourcesAndNamedBuiltIns): Deleted.
(WebCore::WHLSL::Metal::VertexEntryPointScaffolding::helperTypes): Deleted.
(WebCore::WHLSL::Metal::VertexEntryPointScaffolding::signature): Deleted.
(WebCore::WHLSL::Metal::VertexEntryPointScaffolding::unpack): Deleted.
(WebCore::WHLSL::Metal::VertexEntryPointScaffolding::pack): Deleted.
(WebCore::WHLSL::Metal::FragmentEntryPointScaffolding::helperTypes): Deleted.
(WebCore::WHLSL::Metal::FragmentEntryPointScaffolding::signature): Deleted.
(WebCore::WHLSL::Metal::FragmentEntryPointScaffolding::unpack): Deleted.
(WebCore::WHLSL::Metal::FragmentEntryPointScaffolding::pack): Deleted.
(WebCore::WHLSL::Metal::ComputeEntryPointScaffolding::helperTypes): Deleted.
(WebCore::WHLSL::Metal::ComputeEntryPointScaffolding::signature): Deleted.
(WebCore::WHLSL::Metal::ComputeEntryPointScaffolding::unpack): Deleted.
(WebCore::WHLSL::Metal::ComputeEntryPointScaffolding::pack): Deleted.
* Modules/webgpu/WHLSL/Metal/WHLSLEntryPointScaffolding.h:
Rather than have scaffolding return strings, pass in StringBuilders everywhere.

* Modules/webgpu/WHLSL/Metal/WHLSLFunctionWriter.cpp:
(WebCore::WHLSL::Metal::FunctionDefinitionWriter::FunctionDefinitionWriter):
(WebCore::WHLSL::Metal::FunctionDefinitionWriter::visit):
(WebCore::WHLSL::Metal::FunctionDefinitionWriter::emitConstantExpressionString):
(WebCore::WHLSL::Metal::generateMetalFunctionsMapping):
(WebCore::WHLSL::Metal::emitSharedMetalFunctions):
(WebCore::WHLSL::Metal::emitMetalFunctions):
(WebCore::WHLSL::Metal::FunctionDeclarationWriter::FunctionDeclarationWriter): Deleted.
(WebCore::WHLSL::Metal::FunctionDeclarationWriter::toString): Deleted.
(WebCore::WHLSL::Metal::FunctionDefinitionWriter::toString): Deleted.
(WebCore::WHLSL::Metal::FunctionDefinitionWriter::constantExpressionString): Deleted.
(WebCore::WHLSL::Metal::RenderFunctionDefinitionWriter::RenderFunctionDefinitionWriter): Deleted.
(WebCore::WHLSL::Metal::ComputeFunctionDefinitionWriter::ComputeFunctionDefinitionWriter): Deleted.
(WebCore::WHLSL::Metal::sharedMetalFunctions): Deleted.
(WebCore::WHLSL::Metal::metalFunctions): Deleted.
* Modules/webgpu/WHLSL/Metal/WHLSLFunctionWriter.h:
Rather than returning Strings from function generation functions, pass in StringBuilders everywhere.

* Modules/webgpu/WHLSL/Metal/WHLSLMetalCodeGenerator.cpp:
(WebCore::WHLSL::Metal::metalCodeProlog):
(WebCore::WHLSL::Metal::dumpMetalCodeIfNeeded):
(WebCore::WHLSL::Metal::generateMetalCode):
(WebCore::WHLSL::Metal::generateMetalCodeShared): Deleted.
* Modules/webgpu/WHLSL/Metal/WHLSLMetalCodeGenerator.h:
Switch RenderMetalCode and ComputeMetalCode to contain StringBuilders to allow
delaying conversion to String to the latest point possible.

* Modules/webgpu/WHLSL/Metal/WHLSLTypeNamer.cpp:
(WebCore::WHLSL::Metal::TypeNamer::emitMetalTypeDeclarations):
(WebCore::WHLSL::Metal::TypeNamer::emitUnnamedTypeDefinition):
(WebCore::WHLSL::Metal::TypeNamer::emitNamedTypeDefinition):
(WebCore::WHLSL::Metal::TypeNamer::emitAllUnnamedTypeDefinitions):
(WebCore::WHLSL::Metal::TypeNamer::emitMetalTypeDefinitions):
(WebCore::WHLSL::Metal::TypeNamer::emitMetalTypes):
(WebCore::WHLSL::Metal::MetalTypeDeclarationWriter::MetalTypeDeclarationWriter): Deleted.
(WebCore::WHLSL::Metal::MetalTypeDeclarationWriter::toString): Deleted.
(WebCore::WHLSL::Metal::MetalTypeDeclarationWriter::visit): Deleted.
(WebCore::WHLSL::Metal::TypeNamer::metalTypeDeclarations): Deleted.
(WebCore::WHLSL::Metal::TypeNamer::metalTypeDefinitions): Deleted.
(WebCore::WHLSL::Metal::TypeNamer::metalTypes): Deleted.
* Modules/webgpu/WHLSL/Metal/WHLSLTypeNamer.h:
Rather than returning Strings from function generation functions, pass in StringBuilders everywhere.

* Modules/webgpu/WHLSL/WHLSLParser.cpp:
(WebCore::WHLSL::Parser::parseResourceSemantic):
Remove use of _str, which allocates a String, and just use a StringView directly.

* Modules/webgpu/WHLSL/WHLSLPrepare.h:
Switch RenderPrepareResult and ComputePrepareResult to contain StringBuilders to allow
delaying conversion to String to the latest point possible.

* platform/graphics/gpu/cocoa/GPUComputePipelineMetal.mm:
(WebCore::trySetFunctions):
* platform/graphics/gpu/cocoa/GPURenderPipelineMetal.mm:
(WebCore::trySetFunctions):
Convert StringBuilders to String at the last moment necessary. Adds a FIXME to improve
in the future by adding direct conversion from StringBuilder to NSString to avoid another
copy.

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

18 files changed:
Source/WebCore/ChangeLog
Source/WebCore/Modules/webgpu/WHLSL/AST/WHLSLAddressSpace.h
Source/WebCore/Modules/webgpu/WHLSL/AST/WHLSLBuiltInSemantic.h
Source/WebCore/Modules/webgpu/WHLSL/AST/WHLSLEntryPointType.h
Source/WebCore/Modules/webgpu/WHLSL/AST/WHLSLPointerType.h
Source/WebCore/Modules/webgpu/WHLSL/AST/WHLSLResourceSemantic.h
Source/WebCore/Modules/webgpu/WHLSL/Metal/WHLSLEntryPointScaffolding.cpp
Source/WebCore/Modules/webgpu/WHLSL/Metal/WHLSLEntryPointScaffolding.h
Source/WebCore/Modules/webgpu/WHLSL/Metal/WHLSLFunctionWriter.cpp
Source/WebCore/Modules/webgpu/WHLSL/Metal/WHLSLFunctionWriter.h
Source/WebCore/Modules/webgpu/WHLSL/Metal/WHLSLMetalCodeGenerator.cpp
Source/WebCore/Modules/webgpu/WHLSL/Metal/WHLSLMetalCodeGenerator.h
Source/WebCore/Modules/webgpu/WHLSL/Metal/WHLSLTypeNamer.cpp
Source/WebCore/Modules/webgpu/WHLSL/Metal/WHLSLTypeNamer.h
Source/WebCore/Modules/webgpu/WHLSL/WHLSLParser.cpp
Source/WebCore/Modules/webgpu/WHLSL/WHLSLPrepare.h
Source/WebCore/platform/graphics/gpu/cocoa/GPUComputePipelineMetal.mm
Source/WebCore/platform/graphics/gpu/cocoa/GPURenderPipelineMetal.mm

index b456d8f..ab2958a 100644 (file)
@@ -1,3 +1,135 @@
+2019-08-06  Sam Weinig  <weinig@apple.com>
+
+        WHLSL Metal code generation unnecessarily does string copies by passing partial results as Strings
+        https://bugs.webkit.org/show_bug.cgi?id=200471
+
+        Reviewed by Saam Barati.
+
+        Avoid string copies by passing a single StringBuilder all the way through Metal code
+        generation and only converting to a String when passing the constructed shader to Metal
+        API.
+        
+        Where possible, use StringView in lieu of String for temporary strings being passed to
+        the StringBuilder to avoid the allocation overhead of StringImpl. 
+
+        * Modules/webgpu/WHLSL/AST/WHLSLAddressSpace.h:
+        (WebCore::WHLSL::AST::toString):
+        Switch to StringView.
+
+        * Modules/webgpu/WHLSL/AST/WHLSLBuiltInSemantic.h:
+        (WebCore::WHLSL::AST::BuiltInSemantic::toString const):
+        Switch to StringView.
+
+        * Modules/webgpu/WHLSL/AST/WHLSLEntryPointType.h:
+        (WebCore::WHLSL::AST::toString):
+        Switch to StringView.
+
+        * Modules/webgpu/WHLSL/AST/WHLSLPointerType.h:
+        Remove unnecessary "private:".
+    
+        * Modules/webgpu/WHLSL/AST/WHLSLResourceSemantic.h:
+        (WebCore::WHLSL::AST::ResourceSemantic::toString):
+        Switch to StringView.
+
+        * Modules/webgpu/WHLSL/Metal/WHLSLEntryPointScaffolding.cpp:
+        (WebCore::WHLSL::Metal::EntryPointScaffolding::emitResourceHelperTypes):
+        (WebCore::WHLSL::Metal::EntryPointScaffolding::emitResourceSignature):
+        (WebCore::WHLSL::Metal::EntryPointScaffolding::emitBuiltInsSignature):
+        (WebCore::WHLSL::Metal::EntryPointScaffolding::emitMangledInputPath):
+        (WebCore::WHLSL::Metal::EntryPointScaffolding::emitMangledOutputPath):
+        (WebCore::WHLSL::Metal::EntryPointScaffolding::emitUnpackResourcesAndNamedBuiltIns):
+        (WebCore::WHLSL::Metal::VertexEntryPointScaffolding::emitHelperTypes):
+        (WebCore::WHLSL::Metal::VertexEntryPointScaffolding::emitSignature):
+        (WebCore::WHLSL::Metal::VertexEntryPointScaffolding::emitUnpack):
+        (WebCore::WHLSL::Metal::VertexEntryPointScaffolding::emitPack):
+        (WebCore::WHLSL::Metal::FragmentEntryPointScaffolding::emitHelperTypes):
+        (WebCore::WHLSL::Metal::FragmentEntryPointScaffolding::emitSignature):
+        (WebCore::WHLSL::Metal::FragmentEntryPointScaffolding::emitUnpack):
+        (WebCore::WHLSL::Metal::FragmentEntryPointScaffolding::emitPack):
+        (WebCore::WHLSL::Metal::ComputeEntryPointScaffolding::emitHelperTypes):
+        (WebCore::WHLSL::Metal::ComputeEntryPointScaffolding::emitSignature):
+        (WebCore::WHLSL::Metal::ComputeEntryPointScaffolding::emitUnpack):
+        (WebCore::WHLSL::Metal::ComputeEntryPointScaffolding::emitPack):
+        (WebCore::WHLSL::Metal::EntryPointScaffolding::resourceHelperTypes): Deleted.
+        (WebCore::WHLSL::Metal::EntryPointScaffolding::resourceSignature): Deleted.
+        (WebCore::WHLSL::Metal::EntryPointScaffolding::builtInsSignature): Deleted.
+        (WebCore::WHLSL::Metal::EntryPointScaffolding::mangledInputPath): Deleted.
+        (WebCore::WHLSL::Metal::EntryPointScaffolding::mangledOutputPath): Deleted.
+        (WebCore::WHLSL::Metal::EntryPointScaffolding::unpackResourcesAndNamedBuiltIns): Deleted.
+        (WebCore::WHLSL::Metal::VertexEntryPointScaffolding::helperTypes): Deleted.
+        (WebCore::WHLSL::Metal::VertexEntryPointScaffolding::signature): Deleted.
+        (WebCore::WHLSL::Metal::VertexEntryPointScaffolding::unpack): Deleted.
+        (WebCore::WHLSL::Metal::VertexEntryPointScaffolding::pack): Deleted.
+        (WebCore::WHLSL::Metal::FragmentEntryPointScaffolding::helperTypes): Deleted.
+        (WebCore::WHLSL::Metal::FragmentEntryPointScaffolding::signature): Deleted.
+        (WebCore::WHLSL::Metal::FragmentEntryPointScaffolding::unpack): Deleted.
+        (WebCore::WHLSL::Metal::FragmentEntryPointScaffolding::pack): Deleted.
+        (WebCore::WHLSL::Metal::ComputeEntryPointScaffolding::helperTypes): Deleted.
+        (WebCore::WHLSL::Metal::ComputeEntryPointScaffolding::signature): Deleted.
+        (WebCore::WHLSL::Metal::ComputeEntryPointScaffolding::unpack): Deleted.
+        (WebCore::WHLSL::Metal::ComputeEntryPointScaffolding::pack): Deleted.
+        * Modules/webgpu/WHLSL/Metal/WHLSLEntryPointScaffolding.h:
+        Rather than have scaffolding return strings, pass in StringBuilders everywhere. 
+
+        * Modules/webgpu/WHLSL/Metal/WHLSLFunctionWriter.cpp:
+        (WebCore::WHLSL::Metal::FunctionDefinitionWriter::FunctionDefinitionWriter):
+        (WebCore::WHLSL::Metal::FunctionDefinitionWriter::visit):
+        (WebCore::WHLSL::Metal::FunctionDefinitionWriter::emitConstantExpressionString):
+        (WebCore::WHLSL::Metal::generateMetalFunctionsMapping):
+        (WebCore::WHLSL::Metal::emitSharedMetalFunctions):
+        (WebCore::WHLSL::Metal::emitMetalFunctions):
+        (WebCore::WHLSL::Metal::FunctionDeclarationWriter::FunctionDeclarationWriter): Deleted.
+        (WebCore::WHLSL::Metal::FunctionDeclarationWriter::toString): Deleted.
+        (WebCore::WHLSL::Metal::FunctionDefinitionWriter::toString): Deleted.
+        (WebCore::WHLSL::Metal::FunctionDefinitionWriter::constantExpressionString): Deleted.
+        (WebCore::WHLSL::Metal::RenderFunctionDefinitionWriter::RenderFunctionDefinitionWriter): Deleted.
+        (WebCore::WHLSL::Metal::ComputeFunctionDefinitionWriter::ComputeFunctionDefinitionWriter): Deleted.
+        (WebCore::WHLSL::Metal::sharedMetalFunctions): Deleted.
+        (WebCore::WHLSL::Metal::metalFunctions): Deleted.
+        * Modules/webgpu/WHLSL/Metal/WHLSLFunctionWriter.h:
+        Rather than returning Strings from function generation functions, pass in StringBuilders everywhere.
+
+        * Modules/webgpu/WHLSL/Metal/WHLSLMetalCodeGenerator.cpp:
+        (WebCore::WHLSL::Metal::metalCodeProlog):
+        (WebCore::WHLSL::Metal::dumpMetalCodeIfNeeded):
+        (WebCore::WHLSL::Metal::generateMetalCode):
+        (WebCore::WHLSL::Metal::generateMetalCodeShared): Deleted.
+        * Modules/webgpu/WHLSL/Metal/WHLSLMetalCodeGenerator.h:
+        Switch RenderMetalCode and ComputeMetalCode to contain StringBuilders to allow
+        delaying conversion to String to the latest point possible.
+        
+        * Modules/webgpu/WHLSL/Metal/WHLSLTypeNamer.cpp:
+        (WebCore::WHLSL::Metal::TypeNamer::emitMetalTypeDeclarations):
+        (WebCore::WHLSL::Metal::TypeNamer::emitUnnamedTypeDefinition):
+        (WebCore::WHLSL::Metal::TypeNamer::emitNamedTypeDefinition):
+        (WebCore::WHLSL::Metal::TypeNamer::emitAllUnnamedTypeDefinitions):
+        (WebCore::WHLSL::Metal::TypeNamer::emitMetalTypeDefinitions):
+        (WebCore::WHLSL::Metal::TypeNamer::emitMetalTypes):
+        (WebCore::WHLSL::Metal::MetalTypeDeclarationWriter::MetalTypeDeclarationWriter): Deleted.
+        (WebCore::WHLSL::Metal::MetalTypeDeclarationWriter::toString): Deleted.
+        (WebCore::WHLSL::Metal::MetalTypeDeclarationWriter::visit): Deleted.
+        (WebCore::WHLSL::Metal::TypeNamer::metalTypeDeclarations): Deleted.
+        (WebCore::WHLSL::Metal::TypeNamer::metalTypeDefinitions): Deleted.
+        (WebCore::WHLSL::Metal::TypeNamer::metalTypes): Deleted.
+        * Modules/webgpu/WHLSL/Metal/WHLSLTypeNamer.h:
+        Rather than returning Strings from function generation functions, pass in StringBuilders everywhere.
+
+        * Modules/webgpu/WHLSL/WHLSLParser.cpp:
+        (WebCore::WHLSL::Parser::parseResourceSemantic):
+        Remove use of _str, which allocates a String, and just use a StringView directly.
+
+        * Modules/webgpu/WHLSL/WHLSLPrepare.h:
+        Switch RenderPrepareResult and ComputePrepareResult to contain StringBuilders to allow
+        delaying conversion to String to the latest point possible.
+
+        * platform/graphics/gpu/cocoa/GPUComputePipelineMetal.mm:
+        (WebCore::trySetFunctions):
+        * platform/graphics/gpu/cocoa/GPURenderPipelineMetal.mm:
+        (WebCore::trySetFunctions):
+        Convert StringBuilders to String at the last moment necessary. Adds a FIXME to improve
+        in the future by adding direct conversion from StringBuilder to NSString to avoid another
+        copy.
+
 2019-08-06  Saam Barati  <sbarati@apple.com>
 
         [WHLSL] Reduce the number of variables that make it into the global struct by skipping stdlib functions and internal uses of MakePointerExpression/MakeArrayReference
index 00771e1..bff15eb 100644 (file)
@@ -44,18 +44,18 @@ enum class AddressSpace : uint8_t {
     Thread
 };
 
-ALWAYS_INLINE String toString(AddressSpace addressSpace)
+ALWAYS_INLINE StringView toString(AddressSpace addressSpace)
 {
     switch (addressSpace) {
     case AddressSpace::Constant:
-        return "constant"_str;
+        return "constant";
     case AddressSpace::Device:
-        return "device"_str;
+        return "device";
     case AddressSpace::Threadgroup:
-        return "threadgroup"_str;
+        return "threadgroup";
     default:
         ASSERT(addressSpace == AddressSpace::Thread);
-        return "thread"_str;
+        return "thread";
     }
 }
 
index 45a2008..f9f0d16 100644 (file)
@@ -83,7 +83,7 @@ public:
         return !(*this == other);
     }
 
-    String toString() const
+    StringView toString() const
     {
         switch (m_variable) {
         case Variable::SVInstanceID:
index b45424f..f69c376 100644 (file)
@@ -41,7 +41,7 @@ enum class EntryPointType : uint8_t {
     Compute,
 };
 
-ALWAYS_INLINE String toString(EntryPointType type)
+ALWAYS_INLINE StringView toString(EntryPointType type)
 {
     switch (type) {
     case EntryPointType::Vertex:
index 7df06d0..f30ca58 100644 (file)
@@ -49,8 +49,8 @@ class PointerType final : public ReferenceType {
         : Base(location, addressSpace, WTFMove(elementType))
     {
     }
-public:
 
+public:
     static Ref<PointerType> create(CodeLocation location, AddressSpace addressSpace, Ref<UnnamedType> elementType)
     {
         return adoptRef(*new PointerType(location, addressSpace, WTFMove(elementType)));
@@ -78,8 +78,6 @@ public:
     {
         return makeString(elementType().toString(), '*');
     }
-
-private:
 };
 
 } // namespace AST
index 560232d..822c58e 100644 (file)
@@ -60,7 +60,7 @@ public:
     ResourceSemantic(const ResourceSemantic&) = delete;
     ResourceSemantic(ResourceSemantic&&) = default;
 
-    String toString()
+    StringView toString()
     {
         switch (m_mode) {
         case Mode::UnorderedAccessView:
index a142ec9..b39f42b 100644 (file)
@@ -139,9 +139,8 @@ EntryPointScaffolding::EntryPointScaffolding(AST::FunctionDefinition& functionDe
         m_parameterVariables.uncheckedAppend(m_generateNextVariableName());
 }
 
-String EntryPointScaffolding::resourceHelperTypes()
+void EntryPointScaffolding::emitResourceHelperTypes(StringBuilder& stringBuilder)
 {
-    StringBuilder stringBuilder;
     for (size_t i = 0; i < m_layout.size(); ++i) {
         stringBuilder.flexibleAppend("struct ", m_namedBindGroups[i].structName, " {\n");
         Vector<std::pair<unsigned, String>> structItems;
@@ -174,22 +173,23 @@ String EntryPointScaffolding::resourceHelperTypes()
             stringBuilder.flexibleAppend("    ", structItem.second, '\n');
         stringBuilder.append("};\n\n");
     }
-    return stringBuilder.toString();
 }
 
-Optional<String> EntryPointScaffolding::resourceSignature()
+bool EntryPointScaffolding::emitResourceSignature(StringBuilder& stringBuilder, IncludePrecedingComma includePrecedingComma)
 {
     if (!m_layout.size())
-        return WTF::nullopt;
+        return false;
+
+    if (includePrecedingComma == IncludePrecedingComma::Yes)
+        stringBuilder.append(", ");
 
-    StringBuilder stringBuilder;
     for (size_t i = 0; i < m_layout.size(); ++i) {
         if (i)
             stringBuilder.append(", ");
         auto& namedBindGroup = m_namedBindGroups[i];
         stringBuilder.flexibleAppend("device ", namedBindGroup.structName, "& ", namedBindGroup.variableName, " [[buffer(", namedBindGroup.argumentBufferIndex, ")]]");
     }
-    return stringBuilder.toString();
+    return true;
 }
 
 static StringView internalTypeForSemantic(const AST::BuiltInSemantic& builtInSemantic)
@@ -227,12 +227,14 @@ static StringView internalTypeForSemantic(const AST::BuiltInSemantic& builtInSem
     }
 }
 
-Optional<String> EntryPointScaffolding::builtInsSignature()
+bool EntryPointScaffolding::emitBuiltInsSignature(StringBuilder& stringBuilder, IncludePrecedingComma includePrecedingComma)
 {
     if (!m_namedBuiltIns.size())
-        return WTF::nullopt;
+        return false;
+
+    if (includePrecedingComma == IncludePrecedingComma::Yes)
+        stringBuilder.append(", ");
 
-    StringBuilder stringBuilder;
     for (size_t i = 0; i < m_namedBuiltIns.size(); ++i) {
         if (i)
             stringBuilder.append(", ");
@@ -246,13 +248,12 @@ Optional<String> EntryPointScaffolding::builtInsSignature()
             stringBuilder.flexibleAppend(m_typeNamer.mangledNameForType(*item.unnamedType));
         stringBuilder.flexibleAppend(' ', namedBuiltIn.variableName, ' ', attributeForSemantic(builtInSemantic));
     }
-    return stringBuilder.toString();
+    return true;
 }
 
-String EntryPointScaffolding::mangledInputPath(Vector<String>& path)
+void EntryPointScaffolding::emitMangledInputPath(StringBuilder& stringBuilder, Vector<String>& path)
 {
     ASSERT(!path.isEmpty());
-    StringBuilder stringBuilder;
     bool found = false;
     AST::StructureDefinition* structureDefinition = nullptr;
     for (size_t i = 0; i < m_functionDefinition.parameters().size(); ++i) {
@@ -282,14 +283,10 @@ String EntryPointScaffolding::mangledInputPath(Vector<String>& path)
                 structureDefinition = &downcast<AST::StructureDefinition>(namedType);
         }
     }
-
-    return stringBuilder.toString();
 }
 
-String EntryPointScaffolding::mangledOutputPath(Vector<String>& path)
+void EntryPointScaffolding::emitMangledOutputPath(StringBuilder& stringBuilder, Vector<String>& path)
 {
-    StringBuilder stringBuilder;
-
     AST::StructureDefinition* structureDefinition = nullptr;
     auto& unifyNode = m_functionDefinition.type().unifyNode();
     structureDefinition = &downcast<AST::StructureDefinition>(downcast<AST::NamedType>(unifyNode));
@@ -306,13 +303,10 @@ String EntryPointScaffolding::mangledOutputPath(Vector<String>& path)
                 structureDefinition = &downcast<AST::StructureDefinition>(namedType);
         }
     }
-
-    return stringBuilder.toString();
 }
 
-String EntryPointScaffolding::unpackResourcesAndNamedBuiltIns()
+void EntryPointScaffolding::emitUnpackResourcesAndNamedBuiltIns(StringBuilder& stringBuilder)
 {
-    StringBuilder stringBuilder;
     for (size_t i = 0; i < m_functionDefinition.parameters().size(); ++i)
         stringBuilder.flexibleAppend(m_typeNamer.mangledNameForType(*m_functionDefinition.parameters()[i]->type()), ' ', m_parameterVariables[i], ";\n");
 
@@ -336,13 +330,19 @@ String EntryPointScaffolding::unpackResourcesAndNamedBuiltIns()
                     lengthTemporaryName, " = ", lengthTemporaryName, " << 32;\n",
                     lengthTemporaryName, " = ", lengthTemporaryName, " | ", variableName, '.', lengthElementName, ".x;\n",
                     lengthTemporaryName, " = ", lengthTemporaryName, " / sizeof(", mangledTypeName, ");\n",
-                    "if (", lengthTemporaryName, " > 0xFFFFFFFF) ", lengthTemporaryName, " = 0xFFFFFFFF;\n",
-                    mangledInputPath(path), " = { ", variableName, '.', elementName, ", static_cast<uint32_t>(", lengthTemporaryName, ") };\n"
+                    "if (", lengthTemporaryName, " > 0xFFFFFFFF) ", lengthTemporaryName, " = 0xFFFFFFFF;\n"
+                );
+                    
+                emitMangledInputPath(stringBuilder, path);
+                stringBuilder.flexibleAppend(
+                    " = { ", variableName, '.', elementName, ", static_cast<uint32_t>(", lengthTemporaryName, ") };\n"
                 );
             } else {
                 auto& path = m_entryPointItems.inputs[iterator->value].path;
                 auto elementName = m_namedBindGroups[i].namedBindings[j].elementName;
-                stringBuilder.flexibleAppend(mangledInputPath(path), " = ", variableName, '.', elementName, ";\n");
+                
+                emitMangledInputPath(stringBuilder, path);
+                stringBuilder.flexibleAppend(" = ", variableName, '.', elementName, ";\n");
             }
         }
     }
@@ -352,9 +352,10 @@ String EntryPointScaffolding::unpackResourcesAndNamedBuiltIns()
         auto& path = item.path;
         auto& variableName = namedBuiltIn.variableName;
         auto mangledTypeName = m_typeNamer.mangledNameForType(*item.unnamedType);
-        stringBuilder.flexibleAppend(mangledInputPath(path), " = ", mangledTypeName, '(', variableName, ");\n");
+
+        emitMangledInputPath(stringBuilder, path);
+        stringBuilder.flexibleAppend(" = ", mangledTypeName, '(', variableName, ");\n");
     }
-    return stringBuilder.toString();
 }
 
 VertexEntryPointScaffolding::VertexEntryPointScaffolding(AST::FunctionDefinition& functionDefinition, Intrinsics& intrinsics, TypeNamer& typeNamer, EntryPointItems& entryPointItems, HashMap<Binding*, size_t>& resourceMap, Layout& layout, std::function<MangledVariableName()>&& generateNextVariableName, HashMap<VertexAttribute*, size_t>& matchedVertexAttributes)
@@ -389,10 +390,8 @@ VertexEntryPointScaffolding::VertexEntryPointScaffolding(AST::FunctionDefinition
     }
 }
 
-String VertexEntryPointScaffolding::helperTypes()
+void VertexEntryPointScaffolding::emitHelperTypes(StringBuilder& stringBuilder)
 {
-    StringBuilder stringBuilder;
-
     stringBuilder.flexibleAppend("struct ", m_stageInStructName, " {\n");
     for (auto& namedStageIn : m_namedStageIns) {
         auto mangledTypeName = m_typeNamer.mangledNameForType(*m_entryPointItems.inputs[namedStageIn.indexInEntryPointItems].unnamedType);
@@ -411,60 +410,49 @@ String VertexEntryPointScaffolding::helperTypes()
         auto attribute = attributeForSemantic(*outputItem.semantic);
         stringBuilder.flexibleAppend("    ", internalTypeName, ' ', elementName, ' ', attribute, ";\n");
     }
-    stringBuilder.flexibleAppend(
-        "};\n\n",
-        resourceHelperTypes()
+    stringBuilder.append(
+        "};\n\n"
     );
-
-    return stringBuilder.toString();
+    
+    emitResourceHelperTypes(stringBuilder);
 }
 
-String VertexEntryPointScaffolding::signature(MangledFunctionName functionName)
+void VertexEntryPointScaffolding::emitSignature(StringBuilder& stringBuilder, MangledFunctionName functionName)
 {
-    StringBuilder stringBuilder;
-
     stringBuilder.flexibleAppend("vertex ", m_returnStructName, ' ', functionName, '(', m_stageInStructName, ' ', m_stageInParameterName, " [[stage_in]]");
-    if (auto resourceSignature = this->resourceSignature())
-        stringBuilder.flexibleAppend(", ", *resourceSignature);
-    if (auto builtInsSignature = this->builtInsSignature())
-        stringBuilder.flexibleAppend(", ", *builtInsSignature);
+    emitResourceSignature(stringBuilder, IncludePrecedingComma::Yes);
+    emitBuiltInsSignature(stringBuilder, IncludePrecedingComma::Yes);
     stringBuilder.append(')');
-
-    return stringBuilder.toString();
 }
 
-String VertexEntryPointScaffolding::unpack()
+void VertexEntryPointScaffolding::emitUnpack(StringBuilder& stringBuilder)
 {
-    StringBuilder stringBuilder;
-
-    stringBuilder.append(unpackResourcesAndNamedBuiltIns());
+    emitUnpackResourcesAndNamedBuiltIns(stringBuilder);
 
     for (auto& namedStageIn : m_namedStageIns) {
         auto& path = m_entryPointItems.inputs[namedStageIn.indexInEntryPointItems].path;
         auto& elementName = namedStageIn.elementName;
-        stringBuilder.flexibleAppend(mangledInputPath(path), " = ", m_stageInParameterName, '.', elementName, ";\n");
+        emitMangledInputPath(stringBuilder, path);
+        stringBuilder.flexibleAppend(" = ", m_stageInParameterName, '.', elementName, ";\n");
     }
-
-    return stringBuilder.toString();
 }
 
-String VertexEntryPointScaffolding::pack(MangledVariableName inputVariableName, MangledVariableName outputVariableName)
+void VertexEntryPointScaffolding::emitPack(StringBuilder& stringBuilder, MangledVariableName inputVariableName, MangledVariableName outputVariableName)
 {
-    StringBuilder stringBuilder;
-
     stringBuilder.flexibleAppend(m_returnStructName, ' ', outputVariableName, ";\n");
     if (m_entryPointItems.outputs.size() == 1 && !m_entryPointItems.outputs[0].path.size()) {
         auto& elementName = m_namedOutputs[0].elementName;
         stringBuilder.flexibleAppend(outputVariableName, '.', elementName, " = ", inputVariableName, ";\n");
-        return stringBuilder.toString();
+        return;
     }
     for (size_t i = 0; i < m_entryPointItems.outputs.size(); ++i) {
         auto& elementName = m_namedOutputs[i].elementName;
         auto& internalTypeName = m_namedOutputs[i].internalTypeName;
         auto& path = m_entryPointItems.outputs[i].path;
-        stringBuilder.flexibleAppend(outputVariableName, '.', elementName, " = ", internalTypeName, '(', inputVariableName, mangledOutputPath(path), ");\n");
+        stringBuilder.flexibleAppend(outputVariableName, '.', elementName, " = ", internalTypeName, '(', inputVariableName);
+        emitMangledOutputPath(stringBuilder, path);
+        stringBuilder.flexibleAppend(");\n");
     }
-    return stringBuilder.toString();
 }
 
 FragmentEntryPointScaffolding::FragmentEntryPointScaffolding(AST::FunctionDefinition& functionDefinition, Intrinsics& intrinsics, TypeNamer& typeNamer, EntryPointItems& entryPointItems, HashMap<Binding*, size_t>& resourceMap, Layout& layout, std::function<MangledVariableName()>&& generateNextVariableName, HashMap<AttachmentDescriptor*, size_t>&)
@@ -501,10 +489,8 @@ FragmentEntryPointScaffolding::FragmentEntryPointScaffolding(AST::FunctionDefini
     }
 }
 
-String FragmentEntryPointScaffolding::helperTypes()
+void FragmentEntryPointScaffolding::emitHelperTypes(StringBuilder& stringBuilder)
 {
-    StringBuilder stringBuilder;
-
     stringBuilder.flexibleAppend("struct ", m_stageInStructName, " {\n");
     for (auto& namedStageIn : m_namedStageIns) {
         auto mangledTypeName = m_typeNamer.mangledNameForType(*m_entryPointItems.inputs[namedStageIn.indexInEntryPointItems].unnamedType);
@@ -523,60 +509,49 @@ String FragmentEntryPointScaffolding::helperTypes()
         auto attribute = attributeForSemantic(*outputItem.semantic);
         stringBuilder.flexibleAppend("    ", internalTypeName, ' ', elementName, ' ', attribute, ";\n");
     }
-    stringBuilder.flexibleAppend(
-        "};\n\n",
-        resourceHelperTypes()
+    stringBuilder.append(
+        "};\n\n"
     );
 
-    return stringBuilder.toString();
+    emitResourceHelperTypes(stringBuilder);
 }
 
-String FragmentEntryPointScaffolding::signature(MangledFunctionName functionName)
+void FragmentEntryPointScaffolding::emitSignature(StringBuilder& stringBuilder, MangledFunctionName functionName)
 {
-    StringBuilder stringBuilder;
-
     stringBuilder.flexibleAppend("fragment ", m_returnStructName, ' ', functionName, '(', m_stageInStructName, ' ', m_stageInParameterName, " [[stage_in]]");
-    if (auto resourceSignature = this->resourceSignature())
-        stringBuilder.flexibleAppend(", ", *resourceSignature);
-    if (auto builtInsSignature = this->builtInsSignature())
-        stringBuilder.flexibleAppend(", ", *builtInsSignature);
+    emitResourceSignature(stringBuilder, IncludePrecedingComma::Yes);
+    emitBuiltInsSignature(stringBuilder, IncludePrecedingComma::Yes);
     stringBuilder.append(')');
-
-    return stringBuilder.toString();
 }
 
-String FragmentEntryPointScaffolding::unpack()
+void FragmentEntryPointScaffolding::emitUnpack(StringBuilder& stringBuilder)
 {
-    StringBuilder stringBuilder;
-
-    stringBuilder.append(unpackResourcesAndNamedBuiltIns());
+    emitUnpackResourcesAndNamedBuiltIns(stringBuilder);
 
     for (auto& namedStageIn : m_namedStageIns) {
         auto& path = m_entryPointItems.inputs[namedStageIn.indexInEntryPointItems].path;
         auto& elementName = namedStageIn.elementName;
-        stringBuilder.flexibleAppend(mangledInputPath(path), " = ", m_stageInParameterName, '.', elementName, ";\n");
+        emitMangledInputPath(stringBuilder, path);
+        stringBuilder.flexibleAppend(" = ", m_stageInParameterName, '.', elementName, ";\n");
     }
-
-    return stringBuilder.toString();
 }
 
-String FragmentEntryPointScaffolding::pack(MangledVariableName inputVariableName, MangledVariableName outputVariableName)
+void FragmentEntryPointScaffolding::emitPack(StringBuilder& stringBuilder, MangledVariableName inputVariableName, MangledVariableName outputVariableName)
 {
-    StringBuilder stringBuilder;
-
     stringBuilder.flexibleAppend(m_returnStructName, ' ', outputVariableName, ";\n");
     if (m_entryPointItems.outputs.size() == 1 && !m_entryPointItems.outputs[0].path.size()) {
         auto& elementName = m_namedOutputs[0].elementName;
         stringBuilder.flexibleAppend(outputVariableName, '.', elementName, " = ", inputVariableName, ";\n");
-        return stringBuilder.toString();
+        return;
     }
     for (size_t i = 0; i < m_entryPointItems.outputs.size(); ++i) {
         auto& elementName = m_namedOutputs[i].elementName;
         auto& internalTypeName = m_namedOutputs[i].internalTypeName;
         auto& path = m_entryPointItems.outputs[i].path;
-        stringBuilder.flexibleAppend(outputVariableName, '.', elementName, " = ", internalTypeName, '(', inputVariableName, mangledOutputPath(path), ");\n");
+        stringBuilder.flexibleAppend(outputVariableName, '.', elementName, " = ", internalTypeName, '(', inputVariableName);
+        emitMangledOutputPath(stringBuilder, path);
+        stringBuilder.flexibleAppend(");\n");
     }
-    return stringBuilder.toString();
 }
 
 ComputeEntryPointScaffolding::ComputeEntryPointScaffolding(AST::FunctionDefinition& functionDefinition, Intrinsics& intrinsics, TypeNamer& typeNamer, EntryPointItems& entryPointItems, HashMap<Binding*, size_t>& resourceMap, Layout& layout, std::function<MangledVariableName()>&& generateNextVariableName)
@@ -584,40 +559,27 @@ ComputeEntryPointScaffolding::ComputeEntryPointScaffolding(AST::FunctionDefiniti
 {
 }
 
-String ComputeEntryPointScaffolding::helperTypes()
+void ComputeEntryPointScaffolding::emitHelperTypes(StringBuilder& stringBuilder)
 {
-    return resourceHelperTypes();
+    emitResourceHelperTypes(stringBuilder);
 }
 
-String ComputeEntryPointScaffolding::signature(MangledFunctionName functionName)
+void ComputeEntryPointScaffolding::emitSignature(StringBuilder& stringBuilder, MangledFunctionName functionName)
 {
-    StringBuilder stringBuilder;
-
     stringBuilder.flexibleAppend("kernel void ", functionName, '(');
-    bool empty = true;
-    if (auto resourceSignature = this->resourceSignature()) {
-        empty = false;
-        stringBuilder.append(*resourceSignature);
-    }
-    if (auto builtInsSignature = this->builtInsSignature()) {
-        if (!empty)
-            stringBuilder.append(", ");
-        stringBuilder.append(*builtInsSignature);
-    }
+    bool addedToSignature = emitResourceSignature(stringBuilder, IncludePrecedingComma::No);
+    emitBuiltInsSignature(stringBuilder, addedToSignature ? IncludePrecedingComma::Yes : IncludePrecedingComma::No);
     stringBuilder.append(')');
-
-    return stringBuilder.toString();
 }
 
-String ComputeEntryPointScaffolding::unpack()
+void ComputeEntryPointScaffolding::emitUnpack(StringBuilder& stringBuilder)
 {
-    return unpackResourcesAndNamedBuiltIns();
+    emitUnpackResourcesAndNamedBuiltIns(stringBuilder);
 }
 
-String ComputeEntryPointScaffolding::pack(MangledVariableName, MangledVariableName)
+void ComputeEntryPointScaffolding::emitPack(StringBuilder&, MangledVariableName, MangledVariableName)
 {
     ASSERT_NOT_REACHED();
-    return String();
 }
 
 }
index 8f2d4d9..0e31ffb 100644 (file)
@@ -53,23 +53,28 @@ class EntryPointScaffolding {
 public:
     virtual ~EntryPointScaffolding() = default;
 
-    virtual String helperTypes() = 0;
-    virtual String signature(MangledFunctionName) = 0;
-    virtual String unpack() = 0;
-    virtual String pack(MangledVariableName existingVariableName, MangledVariableName) = 0;
+    virtual void emitHelperTypes(StringBuilder&) = 0;
+    virtual void emitSignature(StringBuilder&, MangledFunctionName) = 0;
+    virtual void emitUnpack(StringBuilder&) = 0;
+    virtual void emitPack(StringBuilder&, MangledVariableName existingVariableName, MangledVariableName) = 0;
 
     Vector<MangledVariableName>& parameterVariables() { return m_parameterVariables; }
 
 protected:
     EntryPointScaffolding(AST::FunctionDefinition&, Intrinsics&, TypeNamer&, EntryPointItems&, HashMap<Binding*, size_t>& resourceMap, Layout&, std::function<MangledVariableName()>&& generateNextVariableName);
 
-    String resourceHelperTypes();
-    Optional<String> resourceSignature();
-    Optional<String> builtInsSignature();
+    void emitResourceHelperTypes(StringBuilder&);
 
-    String mangledInputPath(Vector<String>& path);
-    String mangledOutputPath(Vector<String>& path);
-    String unpackResourcesAndNamedBuiltIns();
+    enum class IncludePrecedingComma {
+        Yes,
+        No
+    };
+    bool emitResourceSignature(StringBuilder&, IncludePrecedingComma);
+    bool emitBuiltInsSignature(StringBuilder&, IncludePrecedingComma);
+
+    void emitMangledInputPath(StringBuilder&, Vector<String>& path);
+    void emitMangledOutputPath(StringBuilder&, Vector<String>& path);
+    void emitUnpackResourcesAndNamedBuiltIns(StringBuilder&);
 
     AST::FunctionDefinition& m_functionDefinition;
     Intrinsics& m_intrinsics;
@@ -106,17 +111,17 @@ protected:
     Vector<MangledVariableName> m_parameterVariables;
 };
 
-class VertexEntryPointScaffolding : public EntryPointScaffolding {
+class VertexEntryPointScaffolding final : public EntryPointScaffolding {
 public:
     VertexEntryPointScaffolding(AST::FunctionDefinition&, Intrinsics&, TypeNamer&, EntryPointItems&, HashMap<Binding*, size_t>& resourceMap, Layout&, std::function<MangledVariableName()>&& generateNextVariableName, HashMap<VertexAttribute*, size_t>& matchedVertexAttributes);
     virtual ~VertexEntryPointScaffolding() = default;
 
-    String helperTypes() override;
-    String signature(MangledFunctionName) override;
-    String unpack() override;
-    String pack(MangledVariableName existingVariableName, MangledVariableName) override;
-
 private:
+    void emitHelperTypes(StringBuilder&) override;
+    void emitSignature(StringBuilder&, MangledFunctionName) override;
+    void emitUnpack(StringBuilder&) override;
+    void emitPack(StringBuilder&, MangledVariableName existingVariableName, MangledVariableName) override;
+
     HashMap<VertexAttribute*, size_t>& m_matchedVertexAttributes;
     MangledTypeName m_stageInStructName;
     MangledTypeName m_returnStructName;
@@ -136,17 +141,17 @@ private:
     Vector<NamedOutput> m_namedOutputs;
 };
 
-class FragmentEntryPointScaffolding : public EntryPointScaffolding {
+class FragmentEntryPointScaffolding final : public EntryPointScaffolding {
 public:
     FragmentEntryPointScaffolding(AST::FunctionDefinition&, Intrinsics&, TypeNamer&, EntryPointItems&, HashMap<Binding*, size_t>& resourceMap, Layout&, std::function<MangledVariableName()>&& generateNextVariableName, HashMap<AttachmentDescriptor*, size_t>& matchedColorAttachments);
     virtual ~FragmentEntryPointScaffolding() = default;
 
-    String helperTypes() override;
-    String signature(MangledFunctionName) override;
-    String unpack() override;
-    String pack(MangledVariableName existingVariableName, MangledVariableName) override;
-
 private:
+    void emitHelperTypes(StringBuilder&) override;
+    void emitSignature(StringBuilder&, MangledFunctionName) override;
+    void emitUnpack(StringBuilder&) override;
+    void emitPack(StringBuilder&, MangledVariableName existingVariableName, MangledVariableName) override;
+
     MangledTypeName m_stageInStructName;
     MangledTypeName m_returnStructName;
     MangledVariableName m_stageInParameterName;
@@ -165,15 +170,16 @@ private:
     Vector<NamedOutput> m_namedOutputs;
 };
 
-class ComputeEntryPointScaffolding : public EntryPointScaffolding {
+class ComputeEntryPointScaffolding final : public EntryPointScaffolding {
 public:
     ComputeEntryPointScaffolding(AST::FunctionDefinition&, Intrinsics&, TypeNamer&, EntryPointItems&, HashMap<Binding*, size_t>& resourceMap, Layout&, std::function<MangledVariableName()>&& generateNextVariableName);
     virtual ~ComputeEntryPointScaffolding() = default;
 
-    String helperTypes() override;
-    String signature(MangledFunctionName) override;
-    String unpack() override;
-    String pack(MangledVariableName existingVariableName, MangledVariableName) override;
+private:
+    void emitHelperTypes(StringBuilder&) override;
+    void emitSignature(StringBuilder&, MangledFunctionName) override;
+    void emitUnpack(StringBuilder&) override;
+    void emitPack(StringBuilder&, MangledVariableName existingVariableName, MangledVariableName) override;
 };
 
 }
index 3c7f2d3..d20ce0a 100644 (file)
@@ -47,24 +47,23 @@ namespace WHLSL {
 
 namespace Metal {
 
-class FunctionDeclarationWriter : public Visitor {
+class FunctionDeclarationWriter final : public Visitor {
 public:
-    FunctionDeclarationWriter(TypeNamer& typeNamer, HashMap<AST::FunctionDeclaration*, MangledFunctionName>& functionMapping)
+    FunctionDeclarationWriter(StringBuilder& stringBuilder, TypeNamer& typeNamer, HashMap<AST::FunctionDeclaration*, MangledFunctionName>& functionMapping)
         : m_typeNamer(typeNamer)
         , m_functionMapping(functionMapping)
+        , m_stringBuilder(stringBuilder)
     {
     }
 
     virtual ~FunctionDeclarationWriter() = default;
 
-    String toString() { return m_stringBuilder.toString(); }
-
     void visit(AST::FunctionDeclaration&) override;
 
 private:
     TypeNamer& m_typeNamer;
     HashMap<AST::FunctionDeclaration*, MangledFunctionName>& m_functionMapping;
-    StringBuilder m_stringBuilder;
+    StringBuilder& m_stringBuilder;
 };
 
 void FunctionDeclarationWriter::visit(AST::FunctionDeclaration& functionDeclaration)
@@ -85,8 +84,9 @@ void FunctionDeclarationWriter::visit(AST::FunctionDeclaration& functionDeclarat
 
 class FunctionDefinitionWriter : public Visitor {
 public:
-    FunctionDefinitionWriter(Intrinsics& intrinsics, TypeNamer& typeNamer, HashMap<AST::FunctionDeclaration*, MangledFunctionName>& functionMapping, Layout& layout)
-        : m_intrinsics(intrinsics)
+    FunctionDefinitionWriter(StringBuilder& stringBuilder, Intrinsics& intrinsics, TypeNamer& typeNamer, HashMap<AST::FunctionDeclaration*, MangledFunctionName>& functionMapping, Layout& layout)
+        : m_stringBuilder(stringBuilder)
+        , m_intrinsics(intrinsics)
         , m_typeNamer(typeNamer)
         , m_functionMapping(functionMapping)
         , m_layout(layout)
@@ -95,8 +95,6 @@ public:
 
     virtual ~FunctionDefinitionWriter() = default;
 
-    String toString() { return m_stringBuilder.toString(); }
-
     void visit(AST::NativeFunctionDeclaration&) override;
     void visit(AST::FunctionDefinition&) override;
 
@@ -148,7 +146,7 @@ protected:
     };
     void emitLoop(LoopConditionLocation, AST::Expression* conditionExpression, AST::Expression* increment, AST::Statement& body);
 
-    String constantExpressionString(AST::ConstantExpression&);
+    void emitConstantExpressionString(AST::ConstantExpression&);
 
     MangledVariableName generateNextVariableName() { return { m_variableCount++ }; }
 
@@ -215,11 +213,11 @@ protected:
 
     Optional<BreakContext> m_currentBreakContext;
 
+    StringBuilder& m_stringBuilder;
     Intrinsics& m_intrinsics;
     TypeNamer& m_typeNamer;
     HashMap<AST::FunctionDeclaration*, MangledFunctionName>& m_functionMapping;
     HashMap<AST::VariableDeclaration*, MangledVariableName> m_variableMapping;
-    StringBuilder m_stringBuilder;
 
     Vector<StackItem> m_stack;
     std::unique_ptr<EntryPointScaffolding> m_entryPointScaffolding;
@@ -242,11 +240,12 @@ void FunctionDefinitionWriter::visit(AST::FunctionDefinition& functionDefinition
         if (!entryPointScaffolding)
             return;
         m_entryPointScaffolding = WTFMove(entryPointScaffolding);
-        m_stringBuilder.flexibleAppend(
-            m_entryPointScaffolding->helperTypes(), '\n',
-            m_entryPointScaffolding->signature(iterator->value), " {\n",
-            m_entryPointScaffolding->unpack()
-        );
+        m_entryPointScaffolding->emitHelperTypes(m_stringBuilder);
+        m_stringBuilder.append('\n');
+        m_entryPointScaffolding->emitSignature(m_stringBuilder, iterator->value);
+        m_stringBuilder.append(" {\n");
+        m_entryPointScaffolding->emitUnpack(m_stringBuilder);
+    
         for (size_t i = 0; i < functionDefinition.parameters().size(); ++i) {
             auto addResult = m_variableMapping.add(&functionDefinition.parameters()[i], m_entryPointScaffolding->parameterVariables()[i]);
             ASSERT_UNUSED(addResult, addResult.isNewEntry);
@@ -406,10 +405,8 @@ void FunctionDefinitionWriter::visit(AST::Return& returnStatement)
         checkErrorAndVisit(*returnStatement.value());
         if (m_entryPointScaffolding) {
             auto variableName = generateNextVariableName();
-            m_stringBuilder.flexibleAppend(
-                m_entryPointScaffolding->pack(takeLastValue(), variableName),
-                "return ", variableName, ";\n"
-            );
+            m_entryPointScaffolding->emitPack(m_stringBuilder, takeLastValue(), variableName);
+            m_stringBuilder.flexibleAppend("return ", variableName, ";\n");
         } else
             m_stringBuilder.flexibleAppend("return ", takeLastValue(), ";\n");
     } else
@@ -428,9 +425,11 @@ void FunctionDefinitionWriter::visit(AST::SwitchStatement& switchStatement)
 
 void FunctionDefinitionWriter::visit(AST::SwitchCase& switchCase)
 {
-    if (switchCase.value())
-        m_stringBuilder.flexibleAppend("case ", constantExpressionString(*switchCase.value()), ":\n");
-    else
+    if (switchCase.value()) {
+        m_stringBuilder.flexibleAppend("case ");
+        emitConstantExpressionString(*switchCase.value());
+        m_stringBuilder.flexibleAppend(":\n");
+    } else
         m_stringBuilder.append("default:\n");
     SetForScope<Optional<BreakContext>> breakContext(m_currentBreakContext, BreakContext::Switch);
     checkErrorAndVisit(switchCase.block());
@@ -735,29 +734,39 @@ void FunctionDefinitionWriter::visit(AST::VariableReference& variableReference)
     appendLeftValue(variableReference, iterator->value, pointerName, Nullability::NotNull);
 }
 
-String FunctionDefinitionWriter::constantExpressionString(AST::ConstantExpression& constantExpression)
-{
-    return constantExpression.visit(WTF::makeVisitor([&](AST::IntegerLiteral& integerLiteral) -> String {
-        return makeString("", integerLiteral.value());
-    }, [&](AST::UnsignedIntegerLiteral& unsignedIntegerLiteral) -> String {
-        return makeString("", unsignedIntegerLiteral.value());
-    }, [&](AST::FloatLiteral& floatLiteral) -> String {
-        return makeString("", floatLiteral.value());
-    }, [&](AST::NullLiteral&) -> String {
-        return "nullptr"_str;
-    }, [&](AST::BooleanLiteral& booleanLiteral) -> String {
-        return booleanLiteral.value() ? "true"_str : "false"_str;
-    }, [&](AST::EnumerationMemberLiteral& enumerationMemberLiteral) -> String {
-        ASSERT(enumerationMemberLiteral.enumerationDefinition());
-        ASSERT(enumerationMemberLiteral.enumerationDefinition());
-        return makeString(m_typeNamer.mangledNameForType(*enumerationMemberLiteral.enumerationDefinition()), "::", m_typeNamer.mangledNameForEnumerationMember(*enumerationMemberLiteral.enumerationMember()));
-    }));
+void FunctionDefinitionWriter::emitConstantExpressionString(AST::ConstantExpression& constantExpression)
+{
+    constantExpression.visit(WTF::makeVisitor(
+        [&](AST::IntegerLiteral& integerLiteral) {
+            m_stringBuilder.flexibleAppend(integerLiteral.value());
+        },
+        [&](AST::UnsignedIntegerLiteral& unsignedIntegerLiteral) {
+            m_stringBuilder.flexibleAppend(unsignedIntegerLiteral.value());
+        },
+        [&](AST::FloatLiteral& floatLiteral) {
+            m_stringBuilder.flexibleAppend(floatLiteral.value());
+        },
+        [&](AST::NullLiteral&) {
+            m_stringBuilder.flexibleAppend("nullptr");
+        },
+        [&](AST::BooleanLiteral& booleanLiteral) {
+            if (booleanLiteral.value())
+                m_stringBuilder.flexibleAppend("true");
+            else
+                m_stringBuilder.flexibleAppend("false");
+        },
+        [&](AST::EnumerationMemberLiteral& enumerationMemberLiteral) {
+            ASSERT(enumerationMemberLiteral.enumerationDefinition());
+            ASSERT(enumerationMemberLiteral.enumerationDefinition());
+            m_stringBuilder.flexibleAppend(m_typeNamer.mangledNameForType(*enumerationMemberLiteral.enumerationDefinition()), "::", m_typeNamer.mangledNameForEnumerationMember(*enumerationMemberLiteral.enumerationMember()));
+        }
+    ));
 }
 
-class RenderFunctionDefinitionWriter : public FunctionDefinitionWriter {
+class RenderFunctionDefinitionWriter final : public FunctionDefinitionWriter {
 public:
-    RenderFunctionDefinitionWriter(Intrinsics& intrinsics, TypeNamer& typeNamer, HashMap<AST::FunctionDeclaration*, MangledFunctionName>& functionMapping, MatchedRenderSemantics&& matchedSemantics, Layout& layout)
-        : FunctionDefinitionWriter(intrinsics, typeNamer, functionMapping, layout)
+    RenderFunctionDefinitionWriter(StringBuilder& stringBuilder, Intrinsics& intrinsics, TypeNamer& typeNamer, HashMap<AST::FunctionDeclaration*, MangledFunctionName>& functionMapping, MatchedRenderSemantics&& matchedSemantics, Layout& layout)
+        : FunctionDefinitionWriter(stringBuilder, intrinsics, typeNamer, functionMapping, layout)
         , m_matchedSemantics(WTFMove(matchedSemantics))
     {
     }
@@ -780,10 +789,10 @@ std::unique_ptr<EntryPointScaffolding> RenderFunctionDefinitionWriter::createEnt
     return nullptr;
 }
 
-class ComputeFunctionDefinitionWriter : public FunctionDefinitionWriter {
+class ComputeFunctionDefinitionWriter final : public FunctionDefinitionWriter {
 public:
-    ComputeFunctionDefinitionWriter(Intrinsics& intrinsics, TypeNamer& typeNamer, HashMap<AST::FunctionDeclaration*, MangledFunctionName>& functionMapping, MatchedComputeSemantics&& matchedSemantics, Layout& layout)
-        : FunctionDefinitionWriter(intrinsics, typeNamer, functionMapping, layout)
+    ComputeFunctionDefinitionWriter(StringBuilder& stringBuilder, Intrinsics& intrinsics, TypeNamer& typeNamer, HashMap<AST::FunctionDeclaration*, MangledFunctionName>& functionMapping, MatchedComputeSemantics&& matchedSemantics, Layout& layout)
+        : FunctionDefinitionWriter(stringBuilder, intrinsics, typeNamer, functionMapping, layout)
         , m_matchedSemantics(WTFMove(matchedSemantics))
     {
     }
@@ -804,14 +813,8 @@ std::unique_ptr<EntryPointScaffolding> ComputeFunctionDefinitionWriter::createEn
     return nullptr;
 }
 
-struct SharedMetalFunctionsResult {
-    HashMap<AST::FunctionDeclaration*, MangledFunctionName> functionMapping;
-    String metalFunctions;
-};
-static SharedMetalFunctionsResult sharedMetalFunctions(Program& program, TypeNamer& typeNamer, const HashSet<AST::FunctionDeclaration*>& reachableFunctions)
+static HashMap<AST::FunctionDeclaration*, MangledFunctionName> generateMetalFunctionsMapping(Program& program)
 {
-    StringBuilder stringBuilder;
-
     unsigned numFunctions = 0;
     HashMap<AST::FunctionDeclaration*, MangledFunctionName> functionMapping;
     for (auto& functionDefinition : program.functionDefinitions()) {
@@ -819,20 +822,21 @@ static SharedMetalFunctionsResult sharedMetalFunctions(Program& program, TypeNam
         ASSERT_UNUSED(addResult, addResult.isNewEntry);
     }
 
-    {
-        FunctionDeclarationWriter functionDeclarationWriter(typeNamer, functionMapping);
-        for (auto& functionDefinition : program.functionDefinitions()) {
-            if (!functionDefinition->entryPointType() && reachableFunctions.contains(&functionDefinition))
-                functionDeclarationWriter.visit(functionDefinition);
-        }
-        stringBuilder.append(functionDeclarationWriter.toString());
+    return functionMapping;
+}
+
+static void emitSharedMetalFunctions(StringBuilder& stringBuilder, Program& program, TypeNamer& typeNamer, const HashSet<AST::FunctionDeclaration*>& reachableFunctions, HashMap<AST::FunctionDeclaration*, MangledFunctionName>& functionMapping)
+{
+    FunctionDeclarationWriter functionDeclarationWriter(stringBuilder, typeNamer, functionMapping);
+    for (auto& functionDefinition : program.functionDefinitions()) {
+        if (!functionDefinition->entryPointType() && reachableFunctions.contains(&functionDefinition))
+            functionDeclarationWriter.visit(functionDefinition);
     }
 
     stringBuilder.append('\n');
-    return { WTFMove(functionMapping), stringBuilder.toString() };
 }
 
-class ReachableFunctionsGatherer : public Visitor {
+class ReachableFunctionsGatherer final : public Visitor {
 public:
     void visit(AST::FunctionDeclaration& functionDeclaration) override
     {
@@ -855,7 +859,7 @@ private:
     HashSet<AST::FunctionDeclaration*> m_reachableFunctions;
 };
 
-RenderMetalFunctions metalFunctions(Program& program, TypeNamer& typeNamer, MatchedRenderSemantics&& matchedSemantics, Layout& layout)
+RenderMetalFunctionEntryPoints emitMetalFunctions(StringBuilder& stringBuilder, Program& program, TypeNamer& typeNamer, MatchedRenderSemantics&& matchedSemantics, Layout& layout)
 {
     auto& vertexShaderEntryPoint = *matchedSemantics.vertexShader;
     auto& fragmentShaderEntryPoint = *matchedSemantics.fragmentShader;
@@ -865,26 +869,20 @@ RenderMetalFunctions metalFunctions(Program& program, TypeNamer& typeNamer, Matc
     reachableFunctionsGatherer.Visitor::visit(fragmentShaderEntryPoint);
     auto reachableFunctions = reachableFunctionsGatherer.takeReachableFunctions();
 
-    auto sharedMetalFunctions = Metal::sharedMetalFunctions(program, typeNamer, reachableFunctions);
+    auto functionMapping = generateMetalFunctionsMapping(program);
+    
+    emitSharedMetalFunctions(stringBuilder, program, typeNamer, reachableFunctions, functionMapping);
 
-    StringBuilder stringBuilder;
-    stringBuilder.append(sharedMetalFunctions.metalFunctions);
-
-    RenderFunctionDefinitionWriter functionDefinitionWriter(program.intrinsics(), typeNamer, sharedMetalFunctions.functionMapping, WTFMove(matchedSemantics), layout);
+    RenderFunctionDefinitionWriter functionDefinitionWriter(stringBuilder, program.intrinsics(), typeNamer, functionMapping, WTFMove(matchedSemantics), layout);
     for (auto& functionDefinition : program.functionDefinitions()) {
         if (reachableFunctions.contains(&functionDefinition))
             functionDefinitionWriter.visit(functionDefinition);
     }
-    stringBuilder.append(functionDefinitionWriter.toString());
 
-    RenderMetalFunctions result;
-    result.metalSource = stringBuilder.toString();
-    result.mangledVertexEntryPointName = sharedMetalFunctions.functionMapping.get(&vertexShaderEntryPoint);
-    result.mangledFragmentEntryPointName = sharedMetalFunctions.functionMapping.get(&fragmentShaderEntryPoint);
-    return result;
+    return { functionMapping.get(&vertexShaderEntryPoint), functionMapping.get(&fragmentShaderEntryPoint) };
 }
 
-ComputeMetalFunctions metalFunctions(Program& program, TypeNamer& typeNamer, MatchedComputeSemantics&& matchedSemantics, Layout& layout)
+ComputeMetalFunctionEntryPoints emitMetalFunctions(StringBuilder& stringBuilder, Program& program, TypeNamer& typeNamer, MatchedComputeSemantics&& matchedSemantics, Layout& layout)
 {
     auto& entryPoint = *matchedSemantics.shader;
 
@@ -892,22 +890,16 @@ ComputeMetalFunctions metalFunctions(Program& program, TypeNamer& typeNamer, Mat
     reachableFunctionsGatherer.Visitor::visit(entryPoint);
     auto reachableFunctions = reachableFunctionsGatherer.takeReachableFunctions();
 
-    auto sharedMetalFunctions = Metal::sharedMetalFunctions(program, typeNamer, reachableFunctions);
-
-    StringBuilder stringBuilder;
-    stringBuilder.append(sharedMetalFunctions.metalFunctions);
+    auto functionMapping = generateMetalFunctionsMapping(program);
+    emitSharedMetalFunctions(stringBuilder, program, typeNamer, reachableFunctions, functionMapping);
 
-    ComputeFunctionDefinitionWriter functionDefinitionWriter(program.intrinsics(), typeNamer, sharedMetalFunctions.functionMapping, WTFMove(matchedSemantics), layout);
+    ComputeFunctionDefinitionWriter functionDefinitionWriter(stringBuilder, program.intrinsics(), typeNamer, functionMapping, WTFMove(matchedSemantics), layout);
     for (auto& functionDefinition : program.functionDefinitions()) {
         if (reachableFunctions.contains(&functionDefinition))
             functionDefinitionWriter.visit(functionDefinition);
     }
-    stringBuilder.append(functionDefinitionWriter.toString());
 
-    ComputeMetalFunctions result;
-    result.metalSource = stringBuilder.toString();
-    result.mangledEntryPointName = sharedMetalFunctions.functionMapping.get(&entryPoint);
-    return result;
+    return { functionMapping.get(&entryPoint) };
 }
 
 } // namespace Metal
index dfa23df..9783170 100644 (file)
@@ -40,18 +40,16 @@ namespace Metal {
 
 class TypeNamer;
 
-struct RenderMetalFunctions {
-    String metalSource;
+struct RenderMetalFunctionEntryPoints {
     MangledFunctionName mangledVertexEntryPointName;
     MangledFunctionName mangledFragmentEntryPointName;
 };
-RenderMetalFunctions metalFunctions(Program&, TypeNamer&, MatchedRenderSemantics&&, Layout&);
+RenderMetalFunctionEntryPoints emitMetalFunctions(StringBuilder&, Program&, TypeNamer&, MatchedRenderSemantics&&, Layout&);
 
-struct ComputeMetalFunctions {
-    String metalSource;
+struct ComputeMetalFunctionEntryPoints {
     MangledFunctionName mangledEntryPointName;
 };
-ComputeMetalFunctions metalFunctions(Program&, TypeNamer&, MatchedComputeSemantics&&, Layout&);
+ComputeMetalFunctionEntryPoints emitMetalFunctions(StringBuilder&, Program&, TypeNamer&, MatchedComputeSemantics&&, Layout&);
 
 }
 
index 88cb31b..0252c66 100644 (file)
@@ -41,9 +41,9 @@ namespace Metal {
 
 static constexpr bool dumpMetalCode = false;
 
-static String generateMetalCodeShared(String&& metalTypes, String&& metalFunctions)
+static StringView metalCodeProlog()
 {
-    auto generatedMetalCode = makeString(
+    return StringView {
         "#include <metal_stdlib>\n"
         "#include <metal_atomic>\n"
         "#include <metal_math>\n"
@@ -52,36 +52,46 @@ static String generateMetalCodeShared(String&& metalTypes, String&& metalFunctio
         "#include <metal_texture>\n"
         "\n"
         "using namespace metal;\n"
-        "\n",
-
-        WTFMove(metalTypes),
-        WTFMove(metalFunctions)
-    );
+        "\n"
+    };
+}
 
+static void dumpMetalCodeIfNeeded(StringBuilder& stringBuilder)
+{
     if (dumpMetalCode) {
         dataLogLn("Generated Metal code: ");
-        dataLogLn(generatedMetalCode);
+        dataLogLn(stringBuilder.toString());
     }
-
-    return generatedMetalCode;
 }
 
 RenderMetalCode generateMetalCode(Program& program, MatchedRenderSemantics&& matchedSemantics, Layout& layout)
 {
+    StringBuilder stringBuilder;
+    stringBuilder.append(metalCodeProlog());
+
     TypeNamer typeNamer(program);
-    auto metalTypes = typeNamer.metalTypes();
-    auto metalFunctions = Metal::metalFunctions(program, typeNamer, WTFMove(matchedSemantics), layout);
-    auto metalCode = generateMetalCodeShared(WTFMove(metalTypes), WTFMove(metalFunctions.metalSource));
-    return { WTFMove(metalCode), WTFMove(metalFunctions.mangledVertexEntryPointName), WTFMove(metalFunctions.mangledFragmentEntryPointName) };
+    typeNamer.emitMetalTypes(stringBuilder);
+    
+    auto metalFunctionEntryPoints = Metal::emitMetalFunctions(stringBuilder, program, typeNamer, WTFMove(matchedSemantics), layout);
+
+    dumpMetalCodeIfNeeded(stringBuilder);
+
+    return { WTFMove(stringBuilder), WTFMove(metalFunctionEntryPoints.mangledVertexEntryPointName), WTFMove(metalFunctionEntryPoints.mangledFragmentEntryPointName) };
 }
 
 ComputeMetalCode generateMetalCode(Program& program, MatchedComputeSemantics&& matchedSemantics, Layout& layout)
 {
+    StringBuilder stringBuilder;
+    stringBuilder.append(metalCodeProlog());
+
     TypeNamer typeNamer(program);
-    auto metalTypes = typeNamer.metalTypes();
-    auto metalFunctions = Metal::metalFunctions(program, typeNamer, WTFMove(matchedSemantics), layout);
-    auto metalCode = generateMetalCodeShared(WTFMove(metalTypes), WTFMove(metalFunctions.metalSource));
-    return { WTFMove(metalCode), WTFMove(metalFunctions.mangledEntryPointName) };
+    typeNamer.emitMetalTypes(stringBuilder);
+
+    auto metalFunctionEntryPoints = Metal::emitMetalFunctions(stringBuilder, program, typeNamer, WTFMove(matchedSemantics), layout);
+
+    dumpMetalCodeIfNeeded(stringBuilder);
+
+    return { WTFMove(stringBuilder), WTFMove(metalFunctionEntryPoints.mangledEntryPointName) };
 }
 
 }
index a22a8b9..1bd639d 100644 (file)
@@ -30,8 +30,7 @@
 #include "WHLSLMangledNames.h"
 #include "WHLSLPipelineDescriptor.h"
 #include "WHLSLSemanticMatcher.h"
-#include <wtf/Variant.h>
-#include <wtf/text/WTFString.h>
+#include <wtf/text/StringBuilder.h>
 
 namespace WebCore {
 
@@ -42,7 +41,7 @@ class Program;
 namespace Metal {
 
 struct RenderMetalCode {
-    String metalSource;
+    StringBuilder metalSource;
     MangledFunctionName mangledVertexEntryPointName;
     MangledFunctionName mangledFragmentEntryPointName;
 };
@@ -50,7 +49,7 @@ struct RenderMetalCode {
 RenderMetalCode generateMetalCode(Program&, MatchedRenderSemantics&& matchedSemantics, Layout&);
 
 struct ComputeMetalCode {
-    String metalSource;
+    StringBuilder metalSource;
     MangledFunctionName mangledEntryPointName;
 };
 // Can't fail. Any failure checks need to be done earlier, in the backend-agnostic part of the compiler.
index 8706c79..b4dc0e3 100644 (file)
@@ -351,44 +351,42 @@ BaseTypeNameNode* TypeNamer::insert(AST::UnnamedType& unnamedType, Vector<Unique
     return &*iterator;
 }
 
-class MetalTypeDeclarationWriter : public Visitor {
+class MetalTypeDeclarationWriter final : public Visitor {
     WTF_MAKE_FAST_ALLOCATED;
 public:
-    MetalTypeDeclarationWriter(std::function<MangledOrNativeTypeName(AST::NamedType&)>&& mangledNameForNamedType)
+    MetalTypeDeclarationWriter(StringBuilder& stringBuilder, std::function<MangledOrNativeTypeName(AST::NamedType&)>&& mangledNameForNamedType)
         : m_mangledNameForNamedType(WTFMove(mangledNameForNamedType))
+        , m_stringBuilder(stringBuilder)
     {
     }
 
-    String toString() { return m_stringBuilder.toString(); }
-
 private:
-    void visit(AST::StructureDefinition& structureDefinition)
+    void visit(AST::StructureDefinition& structureDefinition) override
     {
         m_stringBuilder.flexibleAppend("struct ", m_mangledNameForNamedType(structureDefinition), ";\n");
     }
 
     std::function<MangledOrNativeTypeName(AST::NamedType&)> m_mangledNameForNamedType;
-    StringBuilder m_stringBuilder;
+    StringBuilder& m_stringBuilder;
 };
 
-String TypeNamer::metalTypeDeclarations()
+void TypeNamer::emitMetalTypeDeclarations(StringBuilder& stringBuilder)
 {
-    MetalTypeDeclarationWriter metalTypeDeclarationWriter([&](AST::NamedType& namedType) -> MangledOrNativeTypeName {
+    MetalTypeDeclarationWriter metalTypeDeclarationWriter(stringBuilder, [&](AST::NamedType& namedType) -> MangledOrNativeTypeName {
         return mangledNameForType(namedType);
     });
     metalTypeDeclarationWriter.Visitor::visit(m_program);
-    return metalTypeDeclarationWriter.toString();
 }
 
-void TypeNamer::emitUnnamedTypeDefinition(BaseTypeNameNode& baseTypeNameNode, HashSet<AST::NamedType*>& emittedNamedTypes, HashSet<BaseTypeNameNode*>& emittedUnnamedTypes, StringBuilder& stringBuilder)
+void TypeNamer::emitUnnamedTypeDefinition(StringBuilder& stringBuilder, BaseTypeNameNode& baseTypeNameNode, HashSet<AST::NamedType*>& emittedNamedTypes, HashSet<BaseTypeNameNode*>& emittedUnnamedTypes)
 {
     if (emittedUnnamedTypes.contains(&baseTypeNameNode))
         return;
     if (baseTypeNameNode.parent())
-        emitUnnamedTypeDefinition(*baseTypeNameNode.parent(), emittedNamedTypes, emittedUnnamedTypes, stringBuilder);
+        emitUnnamedTypeDefinition(stringBuilder, *baseTypeNameNode.parent(), emittedNamedTypes, emittedUnnamedTypes);
     if (is<ReferenceTypeNameNode>(baseTypeNameNode)) {
         auto& namedType = downcast<ReferenceTypeNameNode>(baseTypeNameNode).namedType();
-        emitNamedTypeDefinition(namedType, emittedNamedTypes, emittedUnnamedTypes, stringBuilder);
+        emitNamedTypeDefinition(stringBuilder, namedType, emittedNamedTypes, emittedUnnamedTypes);
         stringBuilder.flexibleAppend("typedef ", mangledNameForType(namedType), ' ', baseTypeNameNode.mangledName(), ";\n");
     } else if (is<PointerTypeNameNode>(baseTypeNameNode)) {
         auto& pointerType = downcast<PointerTypeNameNode>(baseTypeNameNode);
@@ -411,14 +409,14 @@ void TypeNamer::emitUnnamedTypeDefinition(BaseTypeNameNode& baseTypeNameNode, Ha
     emittedUnnamedTypes.add(&baseTypeNameNode);
 }
 
-void TypeNamer::emitNamedTypeDefinition(AST::NamedType& namedType, HashSet<AST::NamedType*>& emittedNamedTypes, HashSet<BaseTypeNameNode*>& emittedUnnamedTypes, StringBuilder& stringBuilder)
+void TypeNamer::emitNamedTypeDefinition(StringBuilder& stringBuilder, AST::NamedType& namedType, HashSet<AST::NamedType*>& emittedNamedTypes, HashSet<BaseTypeNameNode*>& emittedUnnamedTypes)
 {
     if (emittedNamedTypes.contains(&namedType))
         return;
     auto iterator = m_dependencyGraph.find(&namedType);
     ASSERT(iterator != m_dependencyGraph.end());
     for (auto& baseTypeNameNode : iterator->value)
-        emitUnnamedTypeDefinition(baseTypeNameNode, emittedNamedTypes, emittedUnnamedTypes, stringBuilder);
+        emitUnnamedTypeDefinition(stringBuilder, baseTypeNameNode, emittedNamedTypes, emittedUnnamedTypes);
     if (is<AST::EnumerationDefinition>(namedType)) {
         auto& enumerationDefinition = downcast<AST::EnumerationDefinition>(namedType);
         auto& baseType = enumerationDefinition.type().unifyNode();
@@ -441,23 +439,21 @@ void TypeNamer::emitNamedTypeDefinition(AST::NamedType& namedType, HashSet<AST::
     emittedNamedTypes.add(&namedType);
 }
 
-void TypeNamer::emitAllUnnamedTypeDefinitions(Vector<UniqueRef<BaseTypeNameNode>>& nodes, HashSet<AST::NamedType*>& emittedNamedTypes, HashSet<BaseTypeNameNode*>& emittedUnnamedTypes, StringBuilder& stringBuilder)
+void TypeNamer::emitAllUnnamedTypeDefinitions(StringBuilder& stringBuilder, Vector<UniqueRef<BaseTypeNameNode>>& nodes, HashSet<AST::NamedType*>& emittedNamedTypes, HashSet<BaseTypeNameNode*>& emittedUnnamedTypes)
 {
     for (auto& node : nodes) {
-        emitUnnamedTypeDefinition(node, emittedNamedTypes, emittedUnnamedTypes, stringBuilder);
-        emitAllUnnamedTypeDefinitions(node->children(), emittedNamedTypes, emittedUnnamedTypes, stringBuilder);
+        emitUnnamedTypeDefinition(stringBuilder, node, emittedNamedTypes, emittedUnnamedTypes);
+        emitAllUnnamedTypeDefinitions(stringBuilder, node->children(), emittedNamedTypes, emittedUnnamedTypes);
     }
 }
 
-String TypeNamer::metalTypeDefinitions()
+void TypeNamer::emitMetalTypeDefinitions(StringBuilder& stringBuilder)
 {
     HashSet<AST::NamedType*> emittedNamedTypes;
     HashSet<BaseTypeNameNode*> emittedUnnamedTypes;
-    StringBuilder stringBuilder;
     for (auto& keyValuePair : m_dependencyGraph)
-        emitNamedTypeDefinition(*keyValuePair.key, emittedNamedTypes, emittedUnnamedTypes, stringBuilder);
-    emitAllUnnamedTypeDefinitions(m_trie, emittedNamedTypes, emittedUnnamedTypes, stringBuilder);
-    return stringBuilder.toString();
+        emitNamedTypeDefinition(stringBuilder, *keyValuePair.key, emittedNamedTypes, emittedUnnamedTypes);
+    emitAllUnnamedTypeDefinitions(stringBuilder, m_trie, emittedNamedTypes, emittedUnnamedTypes);
 }
 
 MangledTypeName TypeNamer::mangledNameForType(AST::UnnamedType& unnamedType)
@@ -489,10 +485,13 @@ MangledStructureElementName TypeNamer::mangledNameForStructureElement(AST::Struc
     return iterator->value;
 }
 
-String TypeNamer::metalTypes()
+void TypeNamer::emitMetalTypes(StringBuilder& stringBuilder)
 {
     Visitor::visit(m_program);
-    return makeString(metalTypeDeclarations(), '\n', metalTypeDefinitions());
+
+    emitMetalTypeDeclarations(stringBuilder);
+    stringBuilder.append('\n');
+    emitMetalTypeDefinitions(stringBuilder);
 }
 
 } // namespace Metal
index 6d44d6c..defa7d4 100644 (file)
@@ -59,7 +59,7 @@ public:
     TypeNamer(Program&);
     virtual ~TypeNamer();
 
-    String metalTypes();
+    void emitMetalTypes(StringBuilder&);
 
     // Must be called after calling metalTypes().
     String mangledNameForType(AST::NativeTypeDeclaration&);
@@ -82,11 +82,11 @@ private:
 
     MangledEnumerationMemberName generateNextEnumerationMemberName() { return { m_enumerationMemberCount++ }; }
 
-    void emitNamedTypeDefinition(AST::NamedType&, HashSet<AST::NamedType*>& emittedNamedTypes, HashSet<BaseTypeNameNode*>& emittedUnnamedTypes, StringBuilder&);
-    void emitUnnamedTypeDefinition(BaseTypeNameNode&, HashSet<AST::NamedType*>& emittedNamedTypes, HashSet<BaseTypeNameNode*>& emittedUnnamedTypes, StringBuilder&);
-    void emitAllUnnamedTypeDefinitions(Vector<UniqueRef<BaseTypeNameNode>>&, HashSet<AST::NamedType*>& emittedNamedTypes, HashSet<BaseTypeNameNode*>& emittedUnnamedTypes, StringBuilder&);
-    String metalTypeDeclarations();
-    String metalTypeDefinitions();
+    void emitNamedTypeDefinition(StringBuilder&, AST::NamedType&, HashSet<AST::NamedType*>& emittedNamedTypes, HashSet<BaseTypeNameNode*>& emittedUnnamedTypes);
+    void emitUnnamedTypeDefinition(StringBuilder&, BaseTypeNameNode&, HashSet<AST::NamedType*>& emittedNamedTypes, HashSet<BaseTypeNameNode*>& emittedUnnamedTypes);
+    void emitAllUnnamedTypeDefinitions(StringBuilder&, Vector<UniqueRef<BaseTypeNameNode>>&, HashSet<AST::NamedType*>& emittedNamedTypes, HashSet<BaseTypeNameNode*>& emittedUnnamedTypes);
+    void emitMetalTypeDeclarations(StringBuilder&);
+    void emitMetalTypeDefinitions(StringBuilder&);
 
     UniqueRef<BaseTypeNameNode> createNameNode(AST::UnnamedType&, BaseTypeNameNode* parent);
     BaseTypeNameNode* insert(AST::UnnamedType&, Vector<UniqueRef<BaseTypeNameNode>>&);
index 9cc7b99..8f3bcd3 100644 (file)
@@ -695,8 +695,8 @@ auto Parser::parseResourceSemantic() -> Expected<AST::ResourceSemantic, Error>
     if (tryType(Token::Type::Comma)) {
         CONSUME_TYPE(spaceToken, Identifier);
         auto spaceTokenStringView = spaceToken->stringView(m_lexer);
-        auto prefix = "space"_str;
-        if (!spaceTokenStringView.startsWith(StringView(prefix)))
+        StringView prefix { "space" };
+        if (!spaceTokenStringView.startsWith(prefix))
             return Unexpected<Error>(Error(makeString("Second argument to resource semantic ", spaceTokenStringView, " needs be of the form 'space0'")));
         if (spaceTokenStringView.length() <= prefix.length())
             return Unexpected<Error>(Error(makeString("Second argument to resource semantic ", spaceTokenStringView, " needs be of the form 'space0'")));
index 2191632..5da77f5 100644 (file)
@@ -30,6 +30,7 @@
 #include "WHLSLError.h"
 #include "WHLSLMangledNames.h"
 #include "WHLSLPipelineDescriptor.h"
+#include <wtf/text/StringBuilder.h>
 #include <wtf/text/WTFString.h>
 
 namespace WebCore {
@@ -39,7 +40,7 @@ namespace WHLSL {
 constexpr bool dumpMetalCompileTimes = false;
 
 struct RenderPrepareResult {
-    String metalSource;
+    StringBuilder metalSource;
     Metal::MangledFunctionName mangledVertexEntryPointName;
     Metal::MangledFunctionName mangledFragmentEntryPointName;
 };
@@ -52,7 +53,7 @@ struct ComputeDimensions {
 };
 
 struct ComputePrepareResult {
-    String metalSource;
+    StringBuilder metalSource;
     Metal::MangledFunctionName mangledEntryPointName;
     ComputeDimensions computeDimensions;
 };
index 667f7fb..1cefeed 100644 (file)
@@ -90,7 +90,8 @@ static Optional<WHLSL::ComputeDimensions> trySetFunctions(const GPUPipelineStage
         MonotonicTime startTime;
         if (WHLSL::dumpMetalCompileTimes)
             startTime = MonotonicTime::now();
-        computeLibrary = adoptNS([device.platformDevice() newLibraryWithSource:whlslCompileResult->metalSource options:nil error:&error]);
+        // FIXME: https://webkit.org/b/200474 Add direct StringBuilder -> NSString conversion to avoid extra copy into a WTF::String
+        computeLibrary = adoptNS([device.platformDevice() newLibraryWithSource:whlslCompileResult->metalSource.toString() options:nil error:&error]);
         if (WHLSL::dumpMetalCompileTimes)
             dataLogLn("Metal compile times: ", (MonotonicTime::now() - startTime).milliseconds(), " ms");
         END_BLOCK_OBJC_EXCEPTIONS;
index 2c37df6..86aadd8 100644 (file)
@@ -402,7 +402,8 @@ static bool trySetFunctions(const GPUPipelineStageDescriptor& vertexStage, const
         MonotonicTime startTime;
         if (WHLSL::dumpMetalCompileTimes)
             startTime = MonotonicTime::now();
-        vertexLibrary = adoptNS([device.platformDevice() newLibraryWithSource:whlslCompileResult->metalSource options:nil error:&error]);
+        // FIXME: https://webkit.org/b/200474 Add direct StringBuilder -> NSString conversion to avoid extra copy into a WTF::String
+        vertexLibrary = adoptNS([device.platformDevice() newLibraryWithSource:whlslCompileResult->metalSource.toString() options:nil error:&error]);
         if (WHLSL::dumpMetalCompileTimes)
             dataLogLn("Metal compile times: ", (MonotonicTime::now() - startTime).milliseconds(), " ms");
         END_BLOCK_OBJC_EXCEPTIONS;