Reland "[dawn][webgpu.h] Use wgpu::StringView for strings in output structs."

This is a reland of commit 980e48de901e70a01ca96fcc30032492bfc1468f

Original change's description:
> [dawn][webgpu.h] Use wgpu::StringView for strings in output structs.
>
> These are wgpu::AdapterInfo and wgpu::CompilationMessage.
>
>  - Adds a deprecation #define for a few code changes in Skia and
>    Chromium.
>  - Fixup the FreeMembers logic for StringView that 1) doesn't need a
>    FreeMembers method itself, 2) should have .data checked when deciding
>    whether to auto-free members in the C++ header.
>  - For convenience, add StringView support to webgpu_cpp_print.h
>  - During conversion of dawn::native, try to simplify the handling of
>    allocation and returning of output strings in Adapter and
>    CompilationMessages.
>  - Likewise for dawn::wire.
>  - Simplify GPUCompilationMessages in dawn.node to compute all members
>    in its constructor.
>  - Fixup various other files for compilation errors after the change.
>
> Bug: 42241188
> Change-Id: I6db839a6b8862b4a55c1ea9911ed3725b465c2f3
> Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/208534
> Commit-Queue: Corentin Wallez <cwallez@chromium.org>
> Reviewed-by: Kai Ninomiya <kainino@chromium.org>

Bug: 42241188
Change-Id: I535d2f4f41143be623b00aa6d999af8c8f747119
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/210435
Reviewed-by: Loko Kung <lokokung@google.com>
Reviewed-by: Kai Ninomiya <kainino@chromium.org>
Commit-Queue: Corentin Wallez <cwallez@chromium.org>
diff --git a/generator/dawn_json_generator.py b/generator/dawn_json_generator.py
index ef21844..45be92d 100644
--- a/generator/dawn_json_generator.py
+++ b/generator/dawn_json_generator.py
@@ -339,7 +339,8 @@
         if not self.output:
             return False
         for m in self.members:
-            if m.annotation != 'value':
+            if m.annotation != 'value' \
+                or m.type.name.canonical_case() == 'string view':
                 return True
         return False
 
diff --git a/generator/templates/api.h b/generator/templates/api.h
index df298b0..05f8575 100644
--- a/generator/templates/api.h
+++ b/generator/templates/api.h
@@ -38,6 +38,7 @@
 #define {{metadata.api.upper()}}_H_
 
 #define WGPU_BREAKING_CHANGE_STRING_VIEW_LABELS
+#define WGPU_BREAKING_CHANGE_STRING_VIEW_OUTPUT_STRUCTS
 
 {% set API = metadata.c_prefix %}
 #if defined({{API}}_SHARED_LIBRARY)
diff --git a/generator/templates/api_cpp.h b/generator/templates/api_cpp.h
index be78c15..fe78b71 100644
--- a/generator/templates/api_cpp.h
+++ b/generator/templates/api_cpp.h
@@ -755,12 +755,14 @@
 
         {% if type.has_free_members_function %}
             void {{CppType}}::FreeMembers() {
-                if (
-                    {%- for member in type.members if member.annotation != 'value' %}
-                        {% if not loop.first %} || {% endif -%}
-                        this->{{member.name.camelCase()}} != nullptr
-                    {%- endfor -%}
-                ) {
+                bool needsFreeing = false;
+                {%- for member in type.members if member.annotation != 'value' %}
+                    if (this->{{member.name.camelCase()}} != nullptr) { needsFreeing = true; }
+                {%- endfor -%}
+                {%- for member in type.members if member.type.name.canonical_case() == 'string view' %}
+                    if (this->{{member.name.camelCase()}}.data != nullptr) { needsFreeing = true; }
+                {%- endfor -%}
+                if (needsFreeing) {
                     {{as_cMethodNamespaced(type.name, Name("free members"), c_namespace)}}(
                         *reinterpret_cast<{{CType}}*>(this));
                 }
diff --git a/generator/templates/api_cpp_print.h b/generator/templates/api_cpp_print.h
index 4c7c84a..e2c9961 100644
--- a/generator/templates/api_cpp_print.h
+++ b/generator/templates/api_cpp_print.h
@@ -100,6 +100,12 @@
       }
   {% endfor %}
 
+  template <typename CharT, typename Traits>
+  std::basic_ostream<CharT, Traits>& operator<<(std::basic_ostream<CharT, Traits>& o, StringView value) {
+      o << std::string_view(value);
+      return o;
+  }
+
 }  // namespace {{metadata.namespace}}
 
 #endif // {{API}}_CPP_PRINT_H_
diff --git a/generator/templates/dawn/cpp_macros.tmpl b/generator/templates/dawn/cpp_macros.tmpl
index a63acd1..2b0fb20 100644
--- a/generator/templates/dawn/cpp_macros.tmpl
+++ b/generator/templates/dawn/cpp_macros.tmpl
@@ -40,6 +40,12 @@
         this->length = WGPU_STRLEN;  // use strlen
     }
 
+    // NOLINTNEXTLINE(runtime/explicit) allow implicit construction
+    inline constexpr {{CppType}}(WGPUStringView s) {
+        this->data = s.data;
+        this->length = s.length;
+    }
+
     inline constexpr {{CppType}}(const char* data, size_t length) {
         this->data = data;
         this->length = length;
diff --git a/generator/templates/dawn/native/api_structs.cpp b/generator/templates/dawn/native/api_structs.cpp
index 8b8c9c8..64e373b 100644
--- a/generator/templates/dawn/native/api_structs.cpp
+++ b/generator/templates/dawn/native/api_structs.cpp
@@ -157,12 +157,14 @@
         }
 
         void {{as_cppType(type.name)}}::FreeMembers() {
-            if (
-                {%- for member in type.members if member.annotation != 'value' %}
-                    {% if not loop.first %} || {% endif -%}
-                    this->{{member.name.camelCase()}} != nullptr
-                {%- endfor -%}
-            ) {
+            bool needsFreeing = false;
+            {%- for member in type.members if member.annotation != 'value' %}
+                if (this->{{member.name.camelCase()}} != nullptr) { needsFreeing = true; }
+            {%- endfor -%}
+            {%- for member in type.members if member.type.name.canonical_case() == 'string view' %}
+                if (this->{{member.name.camelCase()}}.data != nullptr) { needsFreeing = true; }
+            {%- endfor -%}
+            if (needsFreeing) {
                 API{{as_MethodSuffix(type.name, Name("free members"))}}(*reinterpret_cast<{{as_cType(type.name)}}*>(this));
             }
         }
diff --git a/src/dawn/common/BUILD.gn b/src/dawn/common/BUILD.gn
index 63d20a8..64ab821 100644
--- a/src/dawn/common/BUILD.gn
+++ b/src/dawn/common/BUILD.gn
@@ -303,6 +303,8 @@
       "SlabAllocator.cpp",
       "SlabAllocator.h",
       "StackAllocated.h",
+      "StringViewUtils.cpp",
+      "StringViewUtils.h",
       "SystemUtils.cpp",
       "SystemUtils.h",
       "TypeTraits.h",
diff --git a/src/dawn/common/CMakeLists.txt b/src/dawn/common/CMakeLists.txt
index aa0e401..8fe3b95 100644
--- a/src/dawn/common/CMakeLists.txt
+++ b/src/dawn/common/CMakeLists.txt
@@ -90,6 +90,7 @@
     "SerialStorage.h"
     "SlabAllocator.h"
     "StackAllocated.h"
+    "StringViewUtils.h"
     "SystemUtils.h"
     "TypedInteger.h"
     "TypeTraits.h"
@@ -114,6 +115,7 @@
     "RefCounted.cpp"
     "Result.cpp"
     "SlabAllocator.cpp"
+    "StringViewUtils.cpp"
     "SystemUtils.cpp"
     "WeakRefSupport.cpp"
 )
diff --git a/src/dawn/common/StringViewUtils.cpp b/src/dawn/common/StringViewUtils.cpp
new file mode 100644
index 0000000..63a4a51
--- /dev/null
+++ b/src/dawn/common/StringViewUtils.cpp
@@ -0,0 +1,64 @@
+// Copyright 2024 The Dawn & Tint Authors
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// 1. Redistributions of source code must retain the above copyright notice, this
+//    list of conditions and the following disclaimer.
+//
+// 2. Redistributions in binary form must reproduce the above copyright notice,
+//    this list of conditions and the following disclaimer in the documentation
+//    and/or other materials provided with the distribution.
+//
+// 3. Neither the name of the copyright holder nor the names of its
+//    contributors may be used to endorse or promote products derived from
+//    this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "dawn/common/StringViewUtils.h"
+
+bool operator==(WGPUStringView a, WGPUStringView b) {
+    return wgpu::StringView(a) == wgpu::StringView(b);
+}
+
+namespace wgpu {
+bool operator==(StringView a, StringView b) {
+    return std::string_view(a) == std::string_view(b);
+}
+}  // namespace wgpu
+
+namespace dawn {
+
+WGPUStringView ToOutputStringView(const std::string& s) {
+    return {s.data(), s.size()};
+}
+
+WGPUStringView ToOutputStringView(const std::string_view& s) {
+    return {s.data(), s.size()};
+}
+
+WGPUStringView ToOutputStringView(const char* s) {
+    return {s, std::strlen(s)};
+}
+
+std::string ToString(WGPUStringView s) {
+    if (s.length == WGPU_STRLEN) {
+        if (s.data == nullptr) {
+            return {};
+        }
+        return {s.data};
+    }
+    return {s.data, s.length};
+}
+
+}  // namespace dawn
diff --git a/src/dawn/common/StringViewUtils.h b/src/dawn/common/StringViewUtils.h
new file mode 100644
index 0000000..4b38506
--- /dev/null
+++ b/src/dawn/common/StringViewUtils.h
@@ -0,0 +1,59 @@
+// Copyright 2024 The Dawn & Tint Authors
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// 1. Redistributions of source code must retain the above copyright notice, this
+//    list of conditions and the following disclaimer.
+//
+// 2. Redistributions in binary form must reproduce the above copyright notice,
+//    this list of conditions and the following disclaimer in the documentation
+//    and/or other materials provided with the distribution.
+//
+// 3. Neither the name of the copyright holder nor the names of its
+//    contributors may be used to endorse or promote products derived from
+//    this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef SRC_DAWN_COMMON_STRINGVIEWUTILS_H_
+#define SRC_DAWN_COMMON_STRINGVIEWUTILS_H_
+
+#include <webgpu/webgpu_cpp.h>
+
+#include <string>
+#include <string_view>
+
+// A comparison operators for use in tests that assumes that the nil string is the same as "".
+bool operator==(WGPUStringView a, WGPUStringView b);
+namespace wgpu {
+bool operator==(StringView a, StringView b);
+}  // namespace wgpu
+
+namespace dawn {
+
+// Helper functions to work with the C WGPUStringView in tests, since it doesn't have all the
+// niceties of wgpu::StringView.
+WGPUStringView ToOutputStringView(const std::string& s);
+WGPUStringView ToOutputStringView(const std::string_view& s);
+template <size_t N>
+constexpr WGPUStringView ToOutputStringView(const char (&s)[N]) {
+    return {s, N - 1};
+}
+
+constexpr WGPUStringView kEmptyOutputStringView = {nullptr, 0};
+
+std::string ToString(WGPUStringView s);
+
+}  // namespace dawn
+
+#endif  // SRC_DAWN_COMMON_STRINGVIEWUTILS_H_
diff --git a/src/dawn/dawn.json b/src/dawn/dawn.json
index 34a84e0..2a9da95 100644
--- a/src/dawn/dawn.json
+++ b/src/dawn/dawn.json
@@ -212,10 +212,10 @@
         "category": "structure",
         "extensible": "out",
         "members": [
-            {"name": "vendor", "type": "char", "annotation": "const*", "length": "strlen", "default": "nullptr"},
-            {"name": "architecture", "type": "char", "annotation": "const*", "length": "strlen", "default": "nullptr"},
-            {"name": "device", "type": "char", "annotation": "const*", "length": "strlen", "default": "nullptr"},
-            {"name": "description", "type": "char", "annotation": "const*", "length": "strlen", "default": "nullptr"},
+            {"name": "vendor", "type": "string view"},
+            {"name": "architecture", "type": "string view"},
+            {"name": "device", "type": "string view"},
+            {"name": "description", "type": "string view"},
             {"name": "backend type", "type": "backend type"},
             {"name": "adapter type", "type": "adapter type"},
             {"name": "vendor ID", "type": "uint32_t"},
@@ -1094,7 +1094,7 @@
         "category": "structure",
         "extensible": "in",
         "members": [
-            {"name": "message", "type": "char", "annotation": "const*", "length": "strlen", "optional": true},
+            {"name": "message", "type": "string view"},
             {"name": "type", "type": "compilation message type"},
             {"name": "line num", "type": "uint64_t"},
             {"name": "line pos", "type": "uint64_t"},
diff --git a/src/dawn/native/Adapter.cpp b/src/dawn/native/Adapter.cpp
index eebd22c..3e79c840 100644
--- a/src/dawn/native/Adapter.cpp
+++ b/src/dawn/native/Adapter.cpp
@@ -177,30 +177,25 @@
 
     mPhysicalDevice->PopulateBackendProperties(unpacked);
 
-    // Get lengths, with null terminators.
-    size_t vendorCLen = mPhysicalDevice->GetVendorName().length() + 1;
-    size_t architectureCLen = mPhysicalDevice->GetArchitectureName().length() + 1;
-    size_t deviceCLen = mPhysicalDevice->GetName().length() + 1;
-    size_t descriptionCLen = mPhysicalDevice->GetDriverDescription().length() + 1;
-
     // Allocate space for all strings.
-    char* ptr = new char[vendorCLen + architectureCLen + deviceCLen + descriptionCLen];
+    size_t allocSize = mPhysicalDevice->GetVendorName().length() +
+                       mPhysicalDevice->GetArchitectureName().length() +
+                       mPhysicalDevice->GetName().length() +
+                       mPhysicalDevice->GetDriverDescription().length();
+    absl::Span<char> outBuffer{new char[allocSize], allocSize};
 
-    info->vendor = ptr;
-    memcpy(ptr, mPhysicalDevice->GetVendorName().c_str(), vendorCLen);
-    ptr += vendorCLen;
+    auto AddString = [&](const std::string& in, StringView* out) {
+        DAWN_ASSERT(in.length() <= outBuffer.length());
+        memcpy(outBuffer.data(), in.data(), in.length());
+        *out = {outBuffer.data(), in.length()};
+        outBuffer = outBuffer.subspan(in.length());
+    };
 
-    info->architecture = ptr;
-    memcpy(ptr, mPhysicalDevice->GetArchitectureName().c_str(), architectureCLen);
-    ptr += architectureCLen;
-
-    info->device = ptr;
-    memcpy(ptr, mPhysicalDevice->GetName().c_str(), deviceCLen);
-    ptr += deviceCLen;
-
-    info->description = ptr;
-    memcpy(ptr, mPhysicalDevice->GetDriverDescription().c_str(), descriptionCLen);
-    ptr += descriptionCLen;
+    AddString(mPhysicalDevice->GetVendorName(), &info->vendor);
+    AddString(mPhysicalDevice->GetArchitectureName(), &info->architecture);
+    AddString(mPhysicalDevice->GetName(), &info->device);
+    AddString(mPhysicalDevice->GetDriverDescription(), &info->description);
+    DAWN_ASSERT(outBuffer.empty());
 
     info->backendType = mPhysicalDevice->GetBackendType();
     info->adapterType = mPhysicalDevice->GetAdapterType();
@@ -213,7 +208,7 @@
 
 void APIAdapterInfoFreeMembers(WGPUAdapterInfo info) {
     // This single delete is enough because everything is a single allocation.
-    delete[] info.vendor;
+    delete[] info.vendor.data;
 }
 
 void APIAdapterPropertiesMemoryHeapsFreeMembers(
diff --git a/src/dawn/native/CompilationMessages.cpp b/src/dawn/native/CompilationMessages.cpp
index 3fed812..91c3b59 100644
--- a/src/dawn/native/CompilationMessages.cpp
+++ b/src/dawn/native/CompilationMessages.cpp
@@ -28,6 +28,7 @@
 #include "dawn/native/CompilationMessages.h"
 
 #include "dawn/common/Assert.h"
+#include "dawn/common/StringViewUtils.h"
 #include "dawn/native/dawn_platform.h"
 
 #include "tint/tint.h"
@@ -36,14 +37,14 @@
 
 namespace {
 
-WGPUCompilationMessageType tintSeverityToMessageType(tint::diag::Severity severity) {
+wgpu::CompilationMessageType TintSeverityToMessageType(tint::diag::Severity severity) {
     switch (severity) {
         case tint::diag::Severity::Note:
-            return WGPUCompilationMessageType_Info;
+            return wgpu::CompilationMessageType::Info;
         case tint::diag::Severity::Warning:
-            return WGPUCompilationMessageType_Warning;
+            return wgpu::CompilationMessageType::Warning;
         default:
-            return WGPUCompilationMessageType_Error;
+            return wgpu::CompilationMessageType::Error;
     }
 }
 
@@ -92,8 +93,11 @@
 
 void OwnedCompilationMessages::AddUnanchoredMessage(std::string_view message,
                                                     wgpu::CompilationMessageType type) {
-    AddMessage(message, {nullptr, nullptr, static_cast<WGPUCompilationMessageType>(type), 0, 0, 0,
-                         0, 0, 0, 0});
+    CompilationMessage m = {};
+    m.message = message;
+    m.type = type;
+
+    AddMessage(m);
 }
 
 void OwnedCompilationMessages::AddMessageForTesting(std::string_view message,
@@ -102,8 +106,18 @@
                                                     uint64_t linePos,
                                                     uint64_t offset,
                                                     uint64_t length) {
-    AddMessage(message, {nullptr, nullptr, static_cast<WGPUCompilationMessageType>(type), lineNum,
-                         linePos, offset, length, linePos, offset, length});
+    CompilationMessage m = {};
+    m.message = message;
+    m.type = type;
+    m.lineNum = lineNum;
+    m.linePos = linePos;
+    m.offset = offset;
+    m.length = length;
+    m.utf16LinePos = linePos;
+    m.utf16Offset = offset;
+    m.utf16Length = length;
+
+    AddMessage(m);
 }
 
 MaybeError OwnedCompilationMessages::AddMessage(const tint::diag::Diagnostic& diagnostic) {
@@ -160,25 +174,36 @@
                                            fileStart + offsetInBytes, lengthInBytes)));
     }
 
-    AddMessage(
-        diagnostic.message.Plain(),
-        {nullptr, nullptr, tintSeverityToMessageType(diagnostic.severity), lineNum, linePosInBytes,
-         offsetInBytes, lengthInBytes, linePosInUTF16, offsetInUTF16, lengthInUTF16});
+    std::string plainMessage = diagnostic.message.Plain();
 
+    CompilationMessage m = {};
+    m.message = std::string_view(plainMessage);
+    m.type = TintSeverityToMessageType(diagnostic.severity);
+    m.lineNum = lineNum;
+    m.linePos = linePosInBytes;
+    m.offset = offsetInBytes;
+    m.length = lengthInBytes;
+    m.utf16LinePos = linePosInUTF16;
+    m.utf16Offset = offsetInUTF16;
+    m.utf16Length = lengthInUTF16;
+
+    AddMessage(m);
     return {};
 }
 
-void OwnedCompilationMessages::AddMessage(std::string_view messageString,
-                                          const WGPUCompilationMessage& message) {
+void OwnedCompilationMessages::AddMessage(const CompilationMessage& message) {
     // Cannot add messages after GetCompilationInfo has been called.
     DAWN_ASSERT(mCompilationInfo.messages == nullptr);
 
     DAWN_ASSERT(message.nextInChain == nullptr);
-    // The message string won't be populated until GetCompilationInfo.
-    DAWN_ASSERT(message.message == nullptr);
 
-    mMessageStrings.push_back(std::string(messageString));
     mMessages.push_back(message);
+
+    // Own the contents of the message as it might be freed afterwards.
+    // Note that we use make_unique here as moving strings doesn't guarantee that the data pointer
+    // stays the same, for example if there's some small string optimization.
+    mMessageStrings.push_back(std::make_unique<std::string>(message.message));
+    mMessages.back().message = ToOutputStringView(*mMessageStrings.back());
 }
 
 MaybeError OwnedCompilationMessages::AddMessages(const tint::diag::List& diagnostics) {
@@ -202,18 +227,10 @@
     mMessages.clear();
 }
 
-const WGPUCompilationInfo* OwnedCompilationMessages::GetCompilationInfo() {
+const CompilationInfo* OwnedCompilationMessages::GetCompilationInfo() {
     mCompilationInfo.messageCount = mMessages.size();
     mCompilationInfo.messages = mMessages.data();
 
-    // Ensure every message points at the correct message string. Cannot do this earlier, since
-    // vector reallocations may move the pointers around.
-    for (size_t i = 0; i < mCompilationInfo.messageCount; ++i) {
-        WGPUCompilationMessage& message = mMessages[i];
-        std::string& messageString = mMessageStrings[i];
-        message.message = messageString.c_str();
-    }
-
     return &mCompilationInfo;
 }
 
@@ -223,8 +240,8 @@
 
 bool OwnedCompilationMessages::HasWarningsOrErrors() const {
     for (const auto& message : mMessages) {
-        if (message.type == WGPUCompilationMessageType_Error ||
-            message.type == WGPUCompilationMessageType_Warning) {
+        if (message.type == wgpu::CompilationMessageType::Error ||
+            message.type == wgpu::CompilationMessageType::Warning) {
             return true;
         }
     }
diff --git a/src/dawn/native/CompilationMessages.h b/src/dawn/native/CompilationMessages.h
index 55c7c8b..8a0280d 100644
--- a/src/dawn/native/CompilationMessages.h
+++ b/src/dawn/native/CompilationMessages.h
@@ -28,6 +28,7 @@
 #ifndef SRC_DAWN_NATIVE_COMPILATIONMESSAGES_H_
 #define SRC_DAWN_NATIVE_COMPILATIONMESSAGES_H_
 
+#include <memory>
 #include <string>
 #include <vector>
 
@@ -66,18 +67,18 @@
     MaybeError AddMessages(const tint::diag::List& diagnostics);
     void ClearMessages();
 
-    const WGPUCompilationInfo* GetCompilationInfo();
+    const CompilationInfo* GetCompilationInfo();
     const std::vector<std::string>& GetFormattedTintMessages() const;
     bool HasWarningsOrErrors() const;
 
   private:
     MaybeError AddMessage(const tint::diag::Diagnostic& diagnostic);
-    void AddMessage(std::string_view messageString, const WGPUCompilationMessage& message);
+    void AddMessage(const CompilationMessage& message);
     void AddFormattedTintMessages(const tint::diag::List& diagnostics);
 
-    WGPUCompilationInfo mCompilationInfo;
-    std::vector<std::string> mMessageStrings;
-    std::vector<WGPUCompilationMessage> mMessages;
+    CompilationInfo mCompilationInfo;
+    std::vector<std::unique_ptr<std::string>> mMessageStrings;
+    std::vector<CompilationMessage> mMessages;
     std::vector<std::string> mFormattedTintMessages;
 };
 
diff --git a/src/dawn/native/ShaderModule.cpp b/src/dawn/native/ShaderModule.cpp
index 46b9536..cf73dfc 100644
--- a/src/dawn/native/ShaderModule.cpp
+++ b/src/dawn/native/ShaderModule.cpp
@@ -1560,13 +1560,13 @@
         void Complete(EventCompletionType completionType) override {
             WGPUCompilationInfoRequestStatus status =
                 WGPUCompilationInfoRequestStatus_InstanceDropped;
-            const WGPUCompilationInfo* compilationInfo = nullptr;
+            const CompilationInfo* compilationInfo = nullptr;
             if (completionType == EventCompletionType::Ready) {
                 status = WGPUCompilationInfoRequestStatus_Success;
                 compilationInfo = mShaderModule->mCompilationMessages->GetCompilationInfo();
             }
 
-            mCallback(status, compilationInfo, mUserdata1.ExtractAsDangling(),
+            mCallback(status, ToAPI(compilationInfo), mUserdata1.ExtractAsDangling(),
                       mUserdata2.ExtractAsDangling());
         }
     };
diff --git a/src/dawn/node/binding/GPU.cpp b/src/dawn/node/binding/GPU.cpp
index 4903aa7..31c8e8d 100644
--- a/src/dawn/node/binding/GPU.cpp
+++ b/src/dawn/node/binding/GPU.cpp
@@ -219,10 +219,12 @@
     for (auto& a : adapters) {
         wgpu::AdapterInfo info;
         a.GetInfo(&info);
-        if (!deviceName.empty() && info.device &&
-            std::string(info.device).find(deviceName) == std::string::npos) {
+
+        if (!deviceName.empty() &&
+            std::string_view(info.device).find(deviceName) == std::string::npos) {
             continue;
         }
+
         adapter = &a;
         break;
     }
@@ -257,7 +259,7 @@
     if (flags_.Get("verbose")) {
         wgpu::AdapterInfo info;
         adapter->GetInfo(&info);
-        printf("using GPU adapter: %s\n", info.device);
+        std::cout << "using GPU adapter: " << info.device << "\n";
     }
 
     auto gpuAdapter = GPUAdapter::Create<GPUAdapter>(env, *adapter, flags_, async_);
diff --git a/src/dawn/node/binding/GPUAdapterInfo.cpp b/src/dawn/node/binding/GPUAdapterInfo.cpp
index bedffcf..80c75c9 100644
--- a/src/dawn/node/binding/GPUAdapterInfo.cpp
+++ b/src/dawn/node/binding/GPUAdapterInfo.cpp
@@ -36,7 +36,7 @@
 // wgpu::bindings::GPUAdapterInfo
 ////////////////////////////////////////////////////////////////////////////////
 
-GPUAdapterInfo::GPUAdapterInfo(WGPUAdapterInfo info)
+GPUAdapterInfo::GPUAdapterInfo(const wgpu::AdapterInfo& info)
     : vendor_(info.vendor),
       architecture_(info.architecture),
       device_(info.device),
diff --git a/src/dawn/node/binding/GPUAdapterInfo.h b/src/dawn/node/binding/GPUAdapterInfo.h
index 316e78f..965d2da 100644
--- a/src/dawn/node/binding/GPUAdapterInfo.h
+++ b/src/dawn/node/binding/GPUAdapterInfo.h
@@ -41,7 +41,7 @@
 // GPUAdapterInfo is an implementation of interop::GPUAdapterInfo.
 class GPUAdapterInfo final : public interop::GPUAdapterInfo {
   public:
-    explicit GPUAdapterInfo(WGPUAdapterInfo);
+    explicit GPUAdapterInfo(const wgpu::AdapterInfo& info);
 
     // interop::GPUAdapterInfo interface compliance
     std::string getVendor(Napi::Env) override;
diff --git a/src/dawn/node/binding/GPUShaderModule.cpp b/src/dawn/node/binding/GPUShaderModule.cpp
index 44cf937..d5f8f87 100644
--- a/src/dawn/node/binding/GPUShaderModule.cpp
+++ b/src/dawn/node/binding/GPUShaderModule.cpp
@@ -46,26 +46,40 @@
 interop::Promise<interop::Interface<interop::GPUCompilationInfo>>
 GPUShaderModule::getCompilationInfo(Napi::Env env) {
     struct GPUCompilationMessage : public interop::GPUCompilationMessage {
-        WGPUCompilationMessage message;
+        interop::GPUCompilationMessageType type;
+        uint64_t lineNum;
+        uint64_t linePos;
+        uint64_t offset;
+        uint64_t length;
+        std::string message;
 
-        explicit GPUCompilationMessage(const WGPUCompilationMessage& m) : message(m) {}
-        std::string getMessage(Napi::Env) override { return message.message; }
-        interop::GPUCompilationMessageType getType(Napi::Env) override {
-            switch (message.type) {
-                case WGPUCompilationMessageType_Error:
-                    return interop::GPUCompilationMessageType::kError;
-                case WGPUCompilationMessageType_Warning:
-                    return interop::GPUCompilationMessageType::kWarning;
-                case WGPUCompilationMessageType_Info:
-                    return interop::GPUCompilationMessageType::kInfo;
+        explicit GPUCompilationMessage(const wgpu::CompilationMessage& m)
+            : lineNum(m.lineNum),
+              linePos(m.utf16LinePos),
+              offset(m.utf16Offset),
+              length(m.utf16Length),
+              message(m.message) {
+            switch (m.type) {
+                case wgpu::CompilationMessageType::Error:
+                    type = interop::GPUCompilationMessageType::kError;
+                    break;
+                case wgpu::CompilationMessageType::Warning:
+                    type = interop::GPUCompilationMessageType::kWarning;
+                    break;
+                case wgpu::CompilationMessageType::Info:
+                    type = interop::GPUCompilationMessageType::kInfo;
+                    break;
                 default:
-                    UNREACHABLE("unrecognized handled compilation message type", message.type);
+                    UNREACHABLE("unrecognized handled compilation message type", m.type);
             }
         }
-        uint64_t getLineNum(Napi::Env) override { return message.lineNum; }
-        uint64_t getLinePos(Napi::Env) override { return message.utf16LinePos; }
-        uint64_t getOffset(Napi::Env) override { return message.utf16Offset; }
-        uint64_t getLength(Napi::Env) override { return message.utf16Length; }
+
+        std::string getMessage(Napi::Env) override { return message; }
+        interop::GPUCompilationMessageType getType(Napi::Env) override { return type; }
+        uint64_t getLineNum(Napi::Env) override { return lineNum; }
+        uint64_t getLinePos(Napi::Env) override { return linePos; }
+        uint64_t getOffset(Napi::Env) override { return offset; }
+        uint64_t getLength(Napi::Env) override { return length; }
     };
 
     using Messages = std::vector<interop::Interface<interop::GPUCompilationMessage>>;
diff --git a/src/dawn/samples/DawnInfo.cpp b/src/dawn/samples/DawnInfo.cpp
index 4ca39d9..cc5eaa6 100644
--- a/src/dawn/samples/DawnInfo.cpp
+++ b/src/dawn/samples/DawnInfo.cpp
@@ -35,6 +35,7 @@
 
 #include "dawn/dawn_proc.h"  // nogncheck
 #include "dawn/native/DawnNative.h"
+#include "dawn/webgpu_cpp_print.h"
 
 namespace {
 
diff --git a/src/dawn/samples/SampleUtils.cpp b/src/dawn/samples/SampleUtils.cpp
index 18cee4b..cb6095c 100644
--- a/src/dawn/samples/SampleUtils.cpp
+++ b/src/dawn/samples/SampleUtils.cpp
@@ -43,6 +43,7 @@
 #include "dawn/utils/CommandLineParser.h"
 #include "dawn/utils/SystemUtils.h"
 #include "dawn/utils/WGPUHelpers.h"
+#include "dawn/webgpu_cpp_print.h"
 
 #ifndef __EMSCRIPTEN__
 #include "GLFW/glfw3.h"
diff --git a/src/dawn/tests/DawnTest.cpp b/src/dawn/tests/DawnTest.cpp
index 2a7e9a6..6ba7dd0 100644
--- a/src/dawn/tests/DawnTest.cpp
+++ b/src/dawn/tests/DawnTest.cpp
@@ -746,7 +746,7 @@
                         info.deviceID == param.adapterProperties.deviceID &&
                         info.vendorID == param.adapterProperties.vendorID &&
                         info.adapterType == param.adapterProperties.adapterType &&
-                        strcmp(info.device, param.adapterProperties.name.c_str()) == 0);
+                        std::string_view(info.device) == param.adapterProperties.name);
             });
         DAWN_ASSERT(it != adapters.end());
         gCurrentTest->mBackendAdapter = *it;
diff --git a/src/dawn/tests/end2end/AdapterCreationTests.cpp b/src/dawn/tests/end2end/AdapterCreationTests.cpp
index df281cc..b0d23c0 100644
--- a/src/dawn/tests/end2end/AdapterCreationTests.cpp
+++ b/src/dawn/tests/end2end/AdapterCreationTests.cpp
@@ -33,6 +33,7 @@
 #include <utility>
 
 #include "dawn/common/GPUInfo.h"
+#include "dawn/common/StringViewUtils.h"
 #include "dawn/dawn_proc.h"
 #include "dawn/native/DawnNative.h"
 #include "dawn/tests/DawnTest.h"
@@ -323,14 +324,14 @@
     adapter.GetInfo(&info1);
     adapter.GetInfo(&info2);
 
-    EXPECT_NE(info1.vendor, info2.vendor);
-    EXPECT_STREQ(info1.vendor, info2.vendor);
-    EXPECT_NE(info1.architecture, info2.architecture);
-    EXPECT_STREQ(info1.architecture, info2.architecture);
-    EXPECT_NE(info1.device, info2.device);
-    EXPECT_STREQ(info1.device, info2.device);
-    EXPECT_NE(info1.description, info2.description);
-    EXPECT_STREQ(info1.description, info2.description);
+    EXPECT_NE(info1.vendor.data, info2.vendor.data);
+    EXPECT_EQ(info1.vendor, info2.vendor);
+    EXPECT_NE(info1.architecture.data, info2.architecture.data);
+    EXPECT_EQ(info1.architecture, info2.architecture);
+    EXPECT_NE(info1.device.data, info2.device.data);
+    EXPECT_EQ(info1.device, info2.device);
+    EXPECT_NE(info1.description.data, info2.description.data);
+    EXPECT_EQ(info1.description, info2.description);
 }
 
 // Test move assignment of the adapter info.
@@ -355,10 +356,10 @@
     adapter.GetInfo(&info1);
     adapter.GetInfo(&info2);
 
-    std::string vendor = info1.vendor;
-    std::string architecture = info1.architecture;
-    std::string device = info1.device;
-    std::string description = info1.description;
+    wgpu::StringView vendor = info1.vendor;
+    wgpu::StringView architecture = info1.architecture;
+    wgpu::StringView device = info1.device;
+    wgpu::StringView description = info1.description;
     wgpu::BackendType backendType = info1.backendType;
     wgpu::AdapterType adapterType = info1.adapterType;
     uint32_t vendorID = info1.vendorID;
@@ -368,10 +369,10 @@
     info2 = std::move(info1);
 
     // Expect info2 to have info1's old contents.
-    EXPECT_STREQ(info2.vendor, vendor.c_str());
-    EXPECT_STREQ(info2.architecture, architecture.c_str());
-    EXPECT_STREQ(info2.device, device.c_str());
-    EXPECT_STREQ(info2.description, description.c_str());
+    EXPECT_EQ(info2.vendor, vendor);
+    EXPECT_EQ(info2.architecture, architecture);
+    EXPECT_EQ(info2.device, device);
+    EXPECT_EQ(info2.description, description);
     EXPECT_EQ(info2.backendType, backendType);
     EXPECT_EQ(info2.adapterType, adapterType);
     EXPECT_EQ(info2.vendorID, vendorID);
@@ -379,10 +380,14 @@
     EXPECT_EQ(info2.compatibilityMode, compatibilityMode);
 
     // Expect info1 to be empty.
-    EXPECT_EQ(info1.vendor, nullptr);
-    EXPECT_EQ(info1.architecture, nullptr);
-    EXPECT_EQ(info1.device, nullptr);
-    EXPECT_EQ(info1.description, nullptr);
+    EXPECT_EQ(info1.vendor.data, nullptr);
+    EXPECT_EQ(info1.vendor.length, wgpu::kStrlen);
+    EXPECT_EQ(info1.architecture.data, nullptr);
+    EXPECT_EQ(info1.architecture.length, wgpu::kStrlen);
+    EXPECT_EQ(info1.device.data, nullptr);
+    EXPECT_EQ(info1.device.length, wgpu::kStrlen);
+    EXPECT_EQ(info1.description.data, nullptr);
+    EXPECT_EQ(info1.description.length, wgpu::kStrlen);
     EXPECT_EQ(info1.backendType, static_cast<wgpu::BackendType>(0));
     EXPECT_EQ(info1.adapterType, static_cast<wgpu::AdapterType>(0));
     EXPECT_EQ(info1.vendorID, 0u);
@@ -410,10 +415,10 @@
     wgpu::AdapterInfo info1;
     adapter.GetInfo(&info1);
 
-    std::string vendor = info1.vendor;
-    std::string architecture = info1.architecture;
-    std::string device = info1.device;
-    std::string description = info1.description;
+    wgpu::StringView vendor = info1.vendor;
+    wgpu::StringView architecture = info1.architecture;
+    wgpu::StringView device = info1.device;
+    wgpu::StringView description = info1.description;
     wgpu::BackendType backendType = info1.backendType;
     wgpu::AdapterType adapterType = info1.adapterType;
     uint32_t vendorID = info1.vendorID;
@@ -423,10 +428,10 @@
     wgpu::AdapterInfo info2(std::move(info1));
 
     // Expect info2 to have info1's old contents.
-    EXPECT_STREQ(info2.vendor, vendor.c_str());
-    EXPECT_STREQ(info2.architecture, architecture.c_str());
-    EXPECT_STREQ(info2.device, device.c_str());
-    EXPECT_STREQ(info2.description, description.c_str());
+    EXPECT_EQ(info2.vendor, vendor);
+    EXPECT_EQ(info2.architecture, architecture);
+    EXPECT_EQ(info2.device, device);
+    EXPECT_EQ(info2.description, description);
     EXPECT_EQ(info2.backendType, backendType);
     EXPECT_EQ(info2.adapterType, adapterType);
     EXPECT_EQ(info2.vendorID, vendorID);
@@ -434,10 +439,14 @@
     EXPECT_EQ(info2.compatibilityMode, compatibilityMode);
 
     // Expect info1 to be empty.
-    EXPECT_EQ(info1.vendor, nullptr);
-    EXPECT_EQ(info1.architecture, nullptr);
-    EXPECT_EQ(info1.device, nullptr);
-    EXPECT_EQ(info1.description, nullptr);
+    EXPECT_EQ(info1.vendor.data, nullptr);
+    EXPECT_EQ(info1.vendor.length, wgpu::kStrlen);
+    EXPECT_EQ(info1.architecture.data, nullptr);
+    EXPECT_EQ(info1.architecture.length, wgpu::kStrlen);
+    EXPECT_EQ(info1.device.data, nullptr);
+    EXPECT_EQ(info1.device.length, wgpu::kStrlen);
+    EXPECT_EQ(info1.description.data, nullptr);
+    EXPECT_EQ(info1.description.length, wgpu::kStrlen);
     EXPECT_EQ(info1.backendType, static_cast<wgpu::BackendType>(0));
     EXPECT_EQ(info1.adapterType, static_cast<wgpu::AdapterType>(0));
     EXPECT_EQ(info1.vendorID, 0u);
@@ -466,10 +475,10 @@
     adapter.GetInfo(&info);
 
     // Make a copy of the info.
-    std::string vendor = info.vendor;
-    std::string architecture = info.architecture;
-    std::string device = info.device;
-    std::string description = info.description;
+    std::string vendor{std::string_view(info.vendor)};
+    std::string architecture{std::string_view(info.architecture)};
+    std::string device{std::string_view(info.device)};
+    std::string description{std::string_view(info.description)};
 
     // Release the adapter.
     adapter = nullptr;
@@ -477,10 +486,10 @@
     // Ensure we still read the info (pointers are still valid).
     // Check the values are equal to make sure they haven't been overwritten,
     // and to make sure the compiler can't elide no-op pointer reads.
-    EXPECT_EQ(info.vendor, vendor);
-    EXPECT_EQ(info.architecture, architecture);
-    EXPECT_EQ(info.device, device);
-    EXPECT_EQ(info.description, description);
+    EXPECT_EQ(std::string_view(info.vendor), vendor);
+    EXPECT_EQ(std::string_view(info.architecture), architecture);
+    EXPECT_EQ(std::string_view(info.device), device);
+    EXPECT_EQ(std::string_view(info.description), description);
 }
 
 }  // anonymous namespace
diff --git a/src/dawn/tests/end2end/AdapterEnumerationTests.cpp b/src/dawn/tests/end2end/AdapterEnumerationTests.cpp
index a8e721b..a6206b2 100644
--- a/src/dawn/tests/end2end/AdapterEnumerationTests.cpp
+++ b/src/dawn/tests/end2end/AdapterEnumerationTests.cpp
@@ -31,6 +31,7 @@
 #include <utility>
 
 #include "dawn/common/GPUInfo.h"
+#include "dawn/common/StringViewUtils.h"
 #include "dawn/dawn_proc.h"
 #include "dawn/native/DawnNative.h"
 
@@ -154,10 +155,10 @@
         wgpu::AdapterInfo infoAgain;
         adaptersAgain[0].GetInfo(&infoAgain);
 
-        EXPECT_STREQ(info.vendor, infoAgain.vendor);
-        EXPECT_STREQ(info.architecture, infoAgain.architecture);
-        EXPECT_STREQ(info.device, infoAgain.device);
-        EXPECT_STREQ(info.description, infoAgain.description);
+        EXPECT_EQ(info.vendor, infoAgain.vendor);
+        EXPECT_EQ(info.architecture, infoAgain.architecture);
+        EXPECT_EQ(info.device, infoAgain.device);
+        EXPECT_EQ(info.description, infoAgain.description);
         EXPECT_EQ(info.backendType, infoAgain.backendType);
         EXPECT_EQ(info.adapterType, infoAgain.adapterType);
         EXPECT_EQ(info.vendorID, infoAgain.vendorID);
@@ -228,10 +229,10 @@
         wgpu::AdapterInfo infoAgain;
         adaptersAgain[0].GetInfo(&infoAgain);
 
-        EXPECT_STREQ(info.vendor, infoAgain.vendor);
-        EXPECT_STREQ(info.architecture, infoAgain.architecture);
-        EXPECT_STREQ(info.device, infoAgain.device);
-        EXPECT_STREQ(info.description, infoAgain.description);
+        EXPECT_EQ(info.vendor, infoAgain.vendor);
+        EXPECT_EQ(info.architecture, infoAgain.architecture);
+        EXPECT_EQ(info.device, infoAgain.device);
+        EXPECT_EQ(info.description, infoAgain.description);
         EXPECT_EQ(info.backendType, infoAgain.backendType);
         EXPECT_EQ(info.adapterType, infoAgain.adapterType);
         EXPECT_EQ(info.vendorID, infoAgain.vendorID);
diff --git a/src/dawn/tests/unittests/validation/ShaderModuleValidationTests.cpp b/src/dawn/tests/unittests/validation/ShaderModuleValidationTests.cpp
index 299eeff..9400eca 100644
--- a/src/dawn/tests/unittests/validation/ShaderModuleValidationTests.cpp
+++ b/src/dawn/tests/unittests/validation/ShaderModuleValidationTests.cpp
@@ -290,25 +290,25 @@
             ASSERT_EQ(4u, info->messageCount);
 
             const wgpu::CompilationMessage* message = &info->messages[0];
-            ASSERT_STREQ("Info Message", message->message);
+            ASSERT_EQ("Info Message", std::string_view(message->message));
             ASSERT_EQ(wgpu::CompilationMessageType::Info, message->type);
             ASSERT_EQ(0u, message->lineNum);
             ASSERT_EQ(0u, message->linePos);
 
             message = &info->messages[1];
-            ASSERT_STREQ("Warning Message", message->message);
+            ASSERT_EQ("Warning Message", std::string_view(message->message));
             ASSERT_EQ(wgpu::CompilationMessageType::Warning, message->type);
             ASSERT_EQ(0u, message->lineNum);
             ASSERT_EQ(0u, message->linePos);
 
             message = &info->messages[2];
-            ASSERT_STREQ("Error Message", message->message);
+            ASSERT_EQ("Error Message", std::string_view(message->message));
             ASSERT_EQ(wgpu::CompilationMessageType::Error, message->type);
             ASSERT_EQ(3u, message->lineNum);
             ASSERT_EQ(4u, message->linePos);
 
             message = &info->messages[3];
-            ASSERT_STREQ("Complete Message", message->message);
+            ASSERT_EQ("Complete Message", std::string_view(message->message));
             ASSERT_EQ(wgpu::CompilationMessageType::Info, message->type);
             ASSERT_EQ(3u, message->lineNum);
             ASSERT_EQ(4u, message->linePos);
@@ -732,7 +732,7 @@
             ASSERT_EQ(1u, info->messageCount);
 
             const wgpu::CompilationMessage* message = &info->messages[0];
-            ASSERT_STREQ("Shader compilation error", message->message);
+            ASSERT_EQ("Shader compilation error", std::string_view(message->message));
             ASSERT_EQ(wgpu::CompilationMessageType::Error, message->type);
             ASSERT_EQ(0u, message->lineNum);
             ASSERT_EQ(0u, message->linePos);
diff --git a/src/dawn/tests/unittests/wire/WireInstanceTests.cpp b/src/dawn/tests/unittests/wire/WireInstanceTests.cpp
index 8b97d85..f6865a7 100644
--- a/src/dawn/tests/unittests/wire/WireInstanceTests.cpp
+++ b/src/dawn/tests/unittests/wire/WireInstanceTests.cpp
@@ -28,6 +28,7 @@
 #include <unordered_set>
 #include <vector>
 
+#include "dawn/common/StringViewUtils.h"
 #include "dawn/tests/MockCallback.h"
 #include "dawn/tests/unittests/wire/WireFutureTest.h"
 #include "dawn/tests/unittests/wire/WireTest.h"
@@ -119,10 +120,10 @@
     InstanceRequestAdapter(instance, &options, nullptr);
 
     WGPUAdapterInfo fakeInfo = {};
-    fakeInfo.vendor = "fake-vendor";
-    fakeInfo.architecture = "fake-architecture";
-    fakeInfo.device = "fake adapter";
-    fakeInfo.description = "hello world";
+    fakeInfo.vendor = ToOutputStringView("fake-vendor");
+    fakeInfo.architecture = ToOutputStringView("fake-architecture");
+    fakeInfo.device = ToOutputStringView("fake-device");
+    fakeInfo.description = ToOutputStringView("fake-description");
     fakeInfo.backendType = WGPUBackendType_D3D12;
     fakeInfo.adapterType = WGPUAdapterType_IntegratedGPU;
     fakeInfo.vendorID = 0x134;
@@ -179,10 +180,14 @@
             .WillOnce(WithArg<1>(Invoke([&](WGPUAdapter adapter) {
                 WGPUAdapterInfo info = {};
                 wgpuAdapterGetInfo(adapter, &info);
-                EXPECT_STREQ(info.vendor, fakeInfo.vendor);
-                EXPECT_STREQ(info.architecture, fakeInfo.architecture);
-                EXPECT_STREQ(info.device, fakeInfo.device);
-                EXPECT_STREQ(info.description, fakeInfo.description);
+                EXPECT_NE(info.vendor.length, WGPU_STRLEN);
+                EXPECT_EQ(info.vendor, fakeInfo.vendor);
+                EXPECT_NE(info.architecture.length, WGPU_STRLEN);
+                EXPECT_EQ(info.architecture, fakeInfo.architecture);
+                EXPECT_NE(info.device.length, WGPU_STRLEN);
+                EXPECT_EQ(info.device, fakeInfo.device);
+                EXPECT_NE(info.description.length, WGPU_STRLEN);
+                EXPECT_EQ(info.description, fakeInfo.description);
                 EXPECT_EQ(info.backendType, fakeInfo.backendType);
                 EXPECT_EQ(info.adapterType, fakeInfo.adapterType);
                 EXPECT_EQ(info.vendorID, fakeInfo.vendorID);
@@ -249,10 +254,10 @@
 
             EXPECT_CALL(api, AdapterGetInfo(apiAdapter, NotNull()))
                 .WillOnce(WithArg<1>(Invoke([&](WGPUAdapterInfo* info) {
-                    info->vendor = "fake-vendor";
-                    info->architecture = "fake-architecture";
-                    info->device = "fake adapter";
-                    info->description = "hello world";
+                    info->vendor = ToOutputStringView("fake-vendor");
+                    info->architecture = ToOutputStringView("fake-architecture");
+                    info->device = ToOutputStringView("fake-device");
+                    info->description = ToOutputStringView("fake-description");
 
                     WGPUChainedStructOut* chain = info->nextInChain;
                     while (chain != nullptr) {
@@ -372,10 +377,10 @@
 
             EXPECT_CALL(api, AdapterGetInfo(apiAdapter, NotNull()))
                 .WillOnce(WithArg<1>(Invoke([&](WGPUAdapterInfo* info) {
-                    info->vendor = "fake-vendor";
-                    info->architecture = "fake-architecture";
-                    info->device = "fake adapter";
-                    info->description = "hello world";
+                    info->vendor = ToOutputStringView("fake-vendor");
+                    info->architecture = ToOutputStringView("fake-architecture");
+                    info->device = ToOutputStringView("fake-device");
+                    info->description = ToOutputStringView("fake-description");
                     return WGPUStatus_Success;
                 })));
 
diff --git a/src/dawn/tests/unittests/wire/WireShaderModuleTests.cpp b/src/dawn/tests/unittests/wire/WireShaderModuleTests.cpp
index f6f2cb6..3dff5f7 100644
--- a/src/dawn/tests/unittests/wire/WireShaderModuleTests.cpp
+++ b/src/dawn/tests/unittests/wire/WireShaderModuleTests.cpp
@@ -27,6 +27,7 @@
 
 #include <memory>
 
+#include "dawn/common/StringViewUtils.h"
 #include "dawn/tests/unittests/wire/WireFutureTest.h"
 #include "dawn/tests/unittests/wire/WireTest.h"
 #include "dawn/wire/WireClient.h"
@@ -66,8 +67,16 @@
     WGPUShaderModule apiShaderModule;
 
     // Default responses.
-    WGPUCompilationMessage mMessage = {
-        nullptr, "Test Message", WGPUCompilationMessageType_Info, 2, 4, 6, 8, 4, 6, 8};
+    WGPUCompilationMessage mMessage = {nullptr,
+                                       ToOutputStringView("Test Message"),
+                                       WGPUCompilationMessageType_Info,
+                                       2,
+                                       4,
+                                       6,
+                                       8,
+                                       4,
+                                       6,
+                                       8};
     WGPUCompilationInfo mCompilationInfo = {nullptr, 1, &mMessage};
 };
 
@@ -92,7 +101,8 @@
                                          return false;
                                      }
                                      const WGPUCompilationMessage* infoMessage = &info->messages[0];
-                                     return strcmp(infoMessage->message, mMessage.message) == 0 &&
+                                     EXPECT_NE(infoMessage->message.length, WGPU_STRLEN);
+                                     return infoMessage->message == mMessage.message &&
                                             infoMessage->nextInChain == mMessage.nextInChain &&
                                             infoMessage->type == mMessage.type &&
                                             infoMessage->lineNum == mMessage.lineNum &&
diff --git a/src/dawn/tests/unittests/wire/WireTest.cpp b/src/dawn/tests/unittests/wire/WireTest.cpp
index 519d212..fcfcaca 100644
--- a/src/dawn/tests/unittests/wire/WireTest.cpp
+++ b/src/dawn/tests/unittests/wire/WireTest.cpp
@@ -27,6 +27,7 @@
 
 #include "dawn/tests/unittests/wire/WireTest.h"
 
+#include "dawn/common/StringViewUtils.h"
 #include "dawn/dawn_proc.h"
 #include "dawn/tests/MockCallback.h"
 #include "dawn/utils/TerribleCommandBuffer.h"
@@ -100,10 +101,10 @@
         EXPECT_CALL(api, AdapterGetInfo(apiAdapter, NotNull()))
             .WillOnce(WithArg<1>(Invoke([&](WGPUAdapterInfo* info) {
                 *info = {};
-                info->vendor = "";
-                info->architecture = "";
-                info->device = "";
-                info->description = "";
+                info->vendor = dawn::kEmptyOutputStringView;
+                info->architecture = dawn::kEmptyOutputStringView;
+                info->device = dawn::kEmptyOutputStringView;
+                info->description = dawn::kEmptyOutputStringView;
                 return WGPUStatus_Success;
             })));
 
diff --git a/src/dawn/wire/client/Adapter.cpp b/src/dawn/wire/client/Adapter.cpp
index 9503051..3c07a4b 100644
--- a/src/dawn/wire/client/Adapter.cpp
+++ b/src/dawn/wire/client/Adapter.cpp
@@ -31,7 +31,9 @@
 #include <string>
 #include <utility>
 
+#include "absl/types/span.h"  // TODO(343500108): Use std::span when we have C++20.
 #include "dawn/common/Log.h"
+#include "dawn/common/StringViewUtils.h"
 #include "dawn/wire/client/Client.h"
 #include "dawn/wire/client/webgpu.h"
 #include "partition_alloc/pointers/raw_ptr.h"
@@ -164,15 +166,15 @@
 void Adapter::SetInfo(const WGPUAdapterInfo* info) {
     mInfo = *info;
 
-    // Deep copy the string pointed out by info.
-    mVendor = info->vendor;
-    mInfo.vendor = mVendor.c_str();
-    mArchitecture = info->architecture;
-    mInfo.architecture = mArchitecture.c_str();
-    mDeviceName = info->device;
-    mInfo.device = mDeviceName.c_str();
-    mDescription = info->description;
-    mInfo.description = mDescription.c_str();
+    // Deep copy the string pointed out by info. StringViews are all explicitly sized by the wire.
+    mVendor = ToString(info->vendor);
+    mInfo.vendor = ToOutputStringView(mVendor);
+    mArchitecture = ToString(info->architecture);
+    mInfo.architecture = ToOutputStringView(mArchitecture);
+    mDeviceName = ToString(info->device);
+    mInfo.device = ToOutputStringView(mDeviceName);
+    mDescription = ToString(info->description);
+    mInfo.description = ToOutputStringView(mDescription);
 
     mInfo.nextInChain = nullptr;
 
@@ -242,30 +244,23 @@
 
     *info = mInfo;
 
-    // Get lengths, with null terminators.
-    size_t vendorCLen = strlen(mInfo.vendor) + 1;
-    size_t architectureCLen = strlen(mInfo.architecture) + 1;
-    size_t deviceCLen = strlen(mInfo.device) + 1;
-    size_t descriptionCLen = strlen(mInfo.description) + 1;
-
     // Allocate space for all strings.
-    char* ptr = new char[vendorCLen + architectureCLen + deviceCLen + descriptionCLen];
+    size_t allocSize =
+        mVendor.length() + mArchitecture.length() + mDeviceName.length() + mDescription.length();
+    absl::Span<char> outBuffer{new char[allocSize], allocSize};
 
-    info->vendor = ptr;
-    memcpy(ptr, mInfo.vendor, vendorCLen);
-    ptr += vendorCLen;
+    auto AddString = [&](const std::string& in, WGPUStringView* out) {
+        DAWN_ASSERT(in.length() <= outBuffer.length());
+        memcpy(outBuffer.data(), in.data(), in.length());
+        *out = {outBuffer.data(), in.length()};
+        outBuffer = outBuffer.subspan(in.length());
+    };
 
-    info->architecture = ptr;
-    memcpy(ptr, mInfo.architecture, architectureCLen);
-    ptr += architectureCLen;
-
-    info->device = ptr;
-    memcpy(ptr, mInfo.device, deviceCLen);
-    ptr += deviceCLen;
-
-    info->description = ptr;
-    memcpy(ptr, mInfo.description, descriptionCLen);
-    ptr += descriptionCLen;
+    AddString(mVendor, &info->vendor);
+    AddString(mArchitecture, &info->architecture);
+    AddString(mDeviceName, &info->device);
+    AddString(mDescription, &info->description);
+    DAWN_ASSERT(outBuffer.empty());
 
     return WGPUStatus_Success;
 }
@@ -384,7 +379,7 @@
 
 DAWN_WIRE_EXPORT void wgpuDawnWireClientAdapterInfoFreeMembers(WGPUAdapterInfo info) {
     // This single delete is enough because everything is a single allocation.
-    delete[] info.vendor;
+    delete[] info.vendor.data;
 }
 
 DAWN_WIRE_EXPORT void wgpuDawnWireClientAdapterPropertiesMemoryHeapsFreeMembers(
diff --git a/src/dawn/wire/client/ShaderModule.cpp b/src/dawn/wire/client/ShaderModule.cpp
index 66951d8..614489b 100644
--- a/src/dawn/wire/client/ShaderModule.cpp
+++ b/src/dawn/wire/client/ShaderModule.cpp
@@ -30,6 +30,7 @@
 #include <memory>
 #include <utility>
 
+#include "dawn/common/StringViewUtils.h"
 #include "dawn/wire/client/Client.h"
 #include "partition_alloc/pointers/raw_ptr.h"
 
@@ -62,12 +63,15 @@
         }
 
         mStatus = status;
+
+        // Deep copy the WGPUCompilationInfo
         mShader->mMessageStrings.reserve(info->messageCount);
         mShader->mMessages.reserve(info->messageCount);
         for (size_t i = 0; i < info->messageCount; i++) {
-            mShader->mMessageStrings.push_back(info->messages[i].message);
+            DAWN_ASSERT(info->messages[i].length != WGPU_STRLEN);
+            mShader->mMessageStrings.push_back(ToString(info->messages[i].message));
             mShader->mMessages.push_back(info->messages[i]);
-            mShader->mMessages[i].message = mShader->mMessageStrings[i].c_str();
+            mShader->mMessages[i].message = ToOutputStringView(mShader->mMessageStrings[i]);
         }
         mShader->mCompilationInfo = {nullptr, mShader->mMessages.size(), mShader->mMessages.data()};