Implement GPUCompilationInfo

Implements the GPUCompilationInfo and GPUCompilationMessage interfaces,
adds the GPUCompilationMessageType enum, and adds the compilationInfo
method to GPUShaderModule.

BUG: dawn:746
Change-Id: Ied70cbbfedbf4890916ec076993714e5042f70e4
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/46600
Commit-Queue: Brandon Jones <bajones@chromium.org>
Reviewed-by: Austin Eng <enga@chromium.org>
diff --git a/dawn.json b/dawn.json
index a2aa130..9eecdf6 100644
--- a/dawn.json
+++ b/dawn.json
@@ -501,6 +501,49 @@
             {"value": 8, "name": "always"}
         ]
     },
+    "compilation info": {
+        "category": "structure",
+        "extensible": false,
+        "members": [
+            {"name": "message count", "type": "uint32_t"},
+            {"name": "messages", "type": "compilation message", "annotation": "const*", "length": "message count"}
+        ]
+    },
+    "compilation info callback": {
+        "category": "callback",
+        "args": [
+            {"name": "status", "type": "compilation info request status"},
+            {"name": "compilation info", "type": "compilation info", "annotation": "const*"},
+            {"name": "userdata", "type": "void", "annotation": "*"}
+        ]
+    },
+    "compilation info request status": {
+        "category": "enum",
+        "values": [
+            {"value": 0, "name": "success"},
+            {"value": 1, "name": "error"},
+            {"value": 2, "name": "device lost"},
+            {"value": 3, "name": "unknown"}
+        ]
+    },
+    "compilation message": {
+        "category": "structure",
+        "extensible": false,
+        "members": [
+            {"name": "message", "type": "char", "annotation": "const*", "length": "strlen", "optional": true},
+            {"name": "type", "type": "compilation message type"},
+            {"name": "line num", "type": "uint64_t"},
+            {"name": "line pos", "type": "uint64_t"}
+        ]
+    },
+    "compilation message type": {
+        "category": "enum",
+        "values": [
+            {"value": 0, "name": "error"},
+            {"value": 1, "name": "warning"},
+            {"value": 2, "name": "info"}
+        ]
+    },
     "compute pass descriptor": {
         "category": "structure",
         "extensible": true,
@@ -1731,7 +1774,16 @@
         ]
     },
     "shader module": {
-        "category": "object"
+        "category": "object",
+        "methods": [
+            {
+                "name": "get compilation info",
+                "args": [
+                    {"name": "callback", "type": "compilation info callback"},
+                    {"name": "userdata", "type": "void", "annotation": "*"}
+                ]
+            }
+        ]
     },
     "shader module descriptor": {
         "category": "structure",
diff --git a/dawn_wire.json b/dawn_wire.json
index 1732781..a6e39ed 100644
--- a/dawn_wire.json
+++ b/dawn_wire.json
@@ -83,6 +83,10 @@
             {"name": "data size", "type": "uint64_t"},
             {"name": "data layout", "type": "texture data layout", "annotation": "const*"},
             {"name": "writeSize", "type": "extent 3D", "annotation": "const*"}
+        ],
+        "shader module get compilation info": [
+            { "name": "shader module id", "type": "ObjectId" },
+            { "name": "request serial", "type": "uint64_t" }
         ]
     },
     "return commands": {
@@ -133,6 +137,12 @@
             { "name": "queue", "type": "ObjectHandle", "handle_type": "queue" },
             { "name": "request serial", "type": "uint64_t" },
             { "name": "status", "type": "queue work done status" }
+        ],
+        "shader module get compilation info callback": [
+            { "name": "shader module", "type": "ObjectHandle", "handle_type": "shader module" },
+            { "name": "request serial", "type": "uint64_t" },
+            { "name": "status", "type": "compilation info request status" },
+            { "name": "info", "type": "compilation info", "annotation": "const*", "optional": true }
         ]
     },
     "special items": {
@@ -153,6 +163,7 @@
             "DeviceSetUncapturedErrorCallback",
             "FenceGetCompletedValue",
             "FenceOnCompletion",
+            "ShaderModuleGetCompilationInfo",
             "QueueOnSubmittedWorkDone",
             "QueueWriteBuffer",
             "QueueWriteTexture"
@@ -171,7 +182,8 @@
             "Buffer",
             "Device",
             "Fence",
-            "Queue"
+            "Queue",
+            "ShaderModule"
         ],
         "server_custom_pre_handler_commands": [
             "BufferDestroy",
diff --git a/generator/dawn_json_generator.py b/generator/dawn_json_generator.py
index 8af2272..84a2b99 100644
--- a/generator/dawn_json_generator.py
+++ b/generator/dawn_json_generator.py
@@ -593,7 +593,7 @@
 def as_wireType(typ):
     if typ.category == 'object':
         return typ.name.CamelCase() + '*'
-    elif typ.category in ['bitmask', 'enum']:
+    elif typ.category in ['bitmask', 'enum', 'structure']:
         return 'WGPU' + typ.name.CamelCase()
     else:
         return as_cppType(typ.name)
diff --git a/src/dawn_native/BUILD.gn b/src/dawn_native/BUILD.gn
index 284e61f..803ee30 100644
--- a/src/dawn_native/BUILD.gn
+++ b/src/dawn_native/BUILD.gn
@@ -194,6 +194,8 @@
     "CommandValidation.h",
     "Commands.cpp",
     "Commands.h",
+    "CompilationMessages.cpp",
+    "CompilationMessages.h",
     "ComputePassEncoder.cpp",
     "ComputePassEncoder.h",
     "ComputePipeline.cpp",
diff --git a/src/dawn_native/CMakeLists.txt b/src/dawn_native/CMakeLists.txt
index e6039b3..ab80577 100644
--- a/src/dawn_native/CMakeLists.txt
+++ b/src/dawn_native/CMakeLists.txt
@@ -62,6 +62,8 @@
     "CommandValidation.h"
     "Commands.cpp"
     "Commands.h"
+    "CompilationMessages.cpp",
+    "CompilationMessages.h",
     "ComputePassEncoder.cpp"
     "ComputePassEncoder.h"
     "ComputePipeline.cpp"
diff --git a/src/dawn_native/CompilationMessages.cpp b/src/dawn_native/CompilationMessages.cpp
new file mode 100644
index 0000000..310b794
--- /dev/null
+++ b/src/dawn_native/CompilationMessages.cpp
@@ -0,0 +1,98 @@
+// Copyright 2021 The Dawn Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "dawn_native/CompilationMessages.h"
+
+#include "common/Assert.h"
+#include "dawn_native/dawn_platform.h"
+
+#include <tint/tint.h>
+
+namespace dawn_native {
+
+    namespace {
+
+        WGPUCompilationMessageType tintSeverityToMessageType(tint::diag::Severity severity) {
+            switch (severity) {
+                case tint::diag::Severity::Note:
+                    return WGPUCompilationMessageType_Info;
+                case tint::diag::Severity::Warning:
+                    return WGPUCompilationMessageType_Warning;
+                default:
+                    return WGPUCompilationMessageType_Error;
+            }
+        }
+
+    }  // anonymous namespace
+
+    OwnedCompilationMessages::OwnedCompilationMessages() {
+        mCompilationInfo.messageCount = 0;
+        mCompilationInfo.messages = nullptr;
+    }
+
+    void OwnedCompilationMessages::AddMessage(std::string message,
+                                              wgpu::CompilationMessageType type,
+                                              uint64_t lineNum,
+                                              uint64_t linePos) {
+        // Cannot add messages after GetCompilationInfo has been called.
+        ASSERT(mCompilationInfo.messages == nullptr);
+
+        mMessageStrings.push_back(message);
+        mMessages.push_back(
+            {nullptr, static_cast<WGPUCompilationMessageType>(type), lineNum, linePos});
+    }
+
+    void OwnedCompilationMessages::AddMessage(const tint::diag::Diagnostic& diagnostic) {
+        // Cannot add messages after GetCompilationInfo has been called.
+        ASSERT(mCompilationInfo.messages == nullptr);
+
+        mMessageStrings.push_back(diagnostic.message);
+        mMessages.push_back({nullptr, tintSeverityToMessageType(diagnostic.severity),
+                             diagnostic.source.range.begin.line,
+                             diagnostic.source.range.begin.column});
+    }
+
+    void OwnedCompilationMessages::AddMessages(const tint::diag::List& diagnostics) {
+        // Cannot add messages after GetCompilationInfo has been called.
+        ASSERT(mCompilationInfo.messages == nullptr);
+
+        for (const auto& diag : diagnostics) {
+            AddMessage(diag);
+        }
+    }
+
+    void OwnedCompilationMessages::ClearMessages() {
+        // Cannot clear messages after GetCompilationInfo has been called.
+        ASSERT(mCompilationInfo.messages == nullptr);
+
+        mMessageStrings.clear();
+        mMessages.clear();
+    }
+
+    const WGPUCompilationInfo* 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;
+    }
+
+}  // namespace dawn_native
diff --git a/src/dawn_native/CompilationMessages.h b/src/dawn_native/CompilationMessages.h
new file mode 100644
index 0000000..02c449d
--- /dev/null
+++ b/src/dawn_native/CompilationMessages.h
@@ -0,0 +1,55 @@
+// Copyright 2021 The Dawn Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef DAWNNATIVE_COMPILATIONMESSAGES_H_
+#define DAWNNATIVE_COMPILATIONMESSAGES_H_
+
+#include "dawn_native/dawn_platform.h"
+
+#include "common/NonCopyable.h"
+
+#include <string>
+#include <vector>
+
+namespace tint { namespace diag {
+    class Diagnostic;
+    class List;
+}}  // namespace tint::diag
+
+namespace dawn_native {
+
+    class OwnedCompilationMessages : public NonCopyable {
+      public:
+        OwnedCompilationMessages();
+        ~OwnedCompilationMessages() = default;
+
+        void AddMessage(std::string message,
+                        wgpu::CompilationMessageType type = wgpu::CompilationMessageType::Info,
+                        uint64_t lineNum = 0,
+                        uint64_t linePos = 0);
+        void AddMessage(const tint::diag::Diagnostic& diagnostic);
+        void AddMessages(const tint::diag::List& diagnostics);
+        void ClearMessages();
+
+        const WGPUCompilationInfo* GetCompilationInfo();
+
+      private:
+        WGPUCompilationInfo mCompilationInfo;
+        std::vector<std::string> mMessageStrings;
+        std::vector<WGPUCompilationMessage> mMessages;
+    };
+
+}  // namespace dawn_native
+
+#endif  // DAWNNATIVE_COMPILATIONMESSAGES_H_
\ No newline at end of file
diff --git a/src/dawn_native/ShaderModule.cpp b/src/dawn_native/ShaderModule.cpp
index de290db..f8b2980 100644
--- a/src/dawn_native/ShaderModule.cpp
+++ b/src/dawn_native/ShaderModule.cpp
@@ -16,6 +16,7 @@
 
 #include "common/VertexFormatUtils.h"
 #include "dawn_native/BindGroupLayout.h"
+#include "dawn_native/CompilationMessages.h"
 #include "dawn_native/Device.h"
 #include "dawn_native/ObjectContentHasher.h"
 #include "dawn_native/Pipeline.h"
@@ -1195,7 +1196,9 @@
     // ShaderModuleBase
 
     ShaderModuleBase::ShaderModuleBase(DeviceBase* device, const ShaderModuleDescriptor* descriptor)
-        : CachedObject(device), mType(Type::Undefined) {
+        : CachedObject(device),
+          mType(Type::Undefined),
+          mCompilationMessages(std::make_unique<OwnedCompilationMessages>()) {
         ASSERT(descriptor->nextInChain != nullptr);
         switch (descriptor->nextInChain->sType) {
             case wgpu::SType::ShaderModuleSPIRVDescriptor: {
@@ -1218,7 +1221,9 @@
     }
 
     ShaderModuleBase::ShaderModuleBase(DeviceBase* device, ObjectBase::ErrorTag tag)
-        : CachedObject(device, tag), mType(Type::Undefined) {
+        : CachedObject(device, tag),
+          mType(Type::Undefined),
+          mCompilationMessages(std::make_unique<OwnedCompilationMessages>()) {
     }
 
     ShaderModuleBase::~ShaderModuleBase() {
@@ -1265,6 +1270,16 @@
         return mTintProgram.get();
     }
 
+    void ShaderModuleBase::APIGetCompilationInfo(wgpu::CompilationInfoCallback callback,
+                                                 void* userdata) {
+        if (callback == nullptr) {
+            return;
+        }
+
+        callback(WGPUCompilationInfoRequestStatus_Success,
+                 mCompilationMessages->GetCompilationInfo(), userdata);
+    }
+
     ResultOrError<std::vector<uint32_t>> ShaderModuleBase::GeneratePullingSpirv(
         const std::vector<uint32_t>& spirv,
         const VertexState& vertexState,
diff --git a/src/dawn_native/ShaderModule.h b/src/dawn_native/ShaderModule.h
index 2f00962..059dee9 100644
--- a/src/dawn_native/ShaderModule.h
+++ b/src/dawn_native/ShaderModule.h
@@ -48,6 +48,7 @@
 
 namespace dawn_native {
 
+    class OwnedCompilationMessages;
     struct EntryPointMetadata;
 
     // A map from name to EntryPointMetadata.
@@ -143,6 +144,8 @@
         const std::vector<uint32_t>& GetSpirv() const;
         const tint::Program* GetTintProgram() const;
 
+        void APIGetCompilationInfo(wgpu::CompilationInfoCallback callback, void* userdata);
+
         ResultOrError<std::vector<uint32_t>> GeneratePullingSpirv(
             const std::vector<uint32_t>& spirv,
             const VertexState& vertexState,
@@ -155,6 +158,10 @@
             const std::string& entryPoint,
             BindGroupIndex pullingBufferBindingSet) const;
 
+        OwnedCompilationMessages* CompilationMessages() {
+            return mCompilationMessages.get();
+        }
+
       protected:
         MaybeError InitializeBase(ShaderModuleParseResult* parseResult);
         static ResultOrError<EntryPointMetadataTable> ReflectShaderUsingSPIRVCross(
@@ -175,6 +182,8 @@
         EntryPointMetadataTable mEntryPoints;
         std::vector<uint32_t> mSpirv;
         std::unique_ptr<tint::Program> mTintProgram;
+
+        std::unique_ptr<OwnedCompilationMessages> mCompilationMessages;
     };
 
 }  // namespace dawn_native
diff --git a/src/dawn_wire/BUILD.gn b/src/dawn_wire/BUILD.gn
index ad72394..4a3f127 100644
--- a/src/dawn_wire/BUILD.gn
+++ b/src/dawn_wire/BUILD.gn
@@ -85,6 +85,8 @@
     "client/ObjectAllocator.h",
     "client/Queue.cpp",
     "client/Queue.h",
+    "client/ShaderModule.cpp",
+    "client/ShaderModule.h",
     "server/ObjectStorage.h",
     "server/Server.cpp",
     "server/Server.h",
@@ -93,6 +95,7 @@
     "server/ServerFence.cpp",
     "server/ServerInlineMemoryTransferService.cpp",
     "server/ServerQueue.cpp",
+    "server/ServerShaderModule.cpp",
   ]
 
   # Make headers publicly visible
diff --git a/src/dawn_wire/CMakeLists.txt b/src/dawn_wire/CMakeLists.txt
index 77e96c0..b1f9ba4 100644
--- a/src/dawn_wire/CMakeLists.txt
+++ b/src/dawn_wire/CMakeLists.txt
@@ -57,6 +57,8 @@
     "client/ObjectAllocator.h"
     "client/Queue.cpp"
     "client/Queue.h"
+    "client/ShaderModule.cpp"
+    "client/ShaderModule.h"
     "server/ObjectStorage.h"
     "server/Server.cpp"
     "server/Server.h"
@@ -65,6 +67,7 @@
     "server/ServerFence.cpp"
     "server/ServerInlineMemoryTransferService.cpp"
     "server/ServerQueue.cpp"
+    "server/ServerShaderModule.cpp"
 )
 target_link_libraries(dawn_wire
     PUBLIC dawn_headers
diff --git a/src/dawn_wire/client/ApiObjects.h b/src/dawn_wire/client/ApiObjects.h
index f842d53..8ec482a 100644
--- a/src/dawn_wire/client/ApiObjects.h
+++ b/src/dawn_wire/client/ApiObjects.h
@@ -21,6 +21,7 @@
 #include "dawn_wire/client/Device.h"
 #include "dawn_wire/client/Fence.h"
 #include "dawn_wire/client/Queue.h"
+#include "dawn_wire/client/ShaderModule.h"
 
 #include "dawn_wire/client/ApiObjects_autogen.h"
 
diff --git a/src/dawn_wire/client/ClientDoers.cpp b/src/dawn_wire/client/ClientDoers.cpp
index 2c6e23f..4073baa 100644
--- a/src/dawn_wire/client/ClientDoers.cpp
+++ b/src/dawn_wire/client/ClientDoers.cpp
@@ -122,4 +122,15 @@
         return device->OnCreateRenderPipelineAsyncCallback(requestSerial, status, message);
     }
 
+    bool Client::DoShaderModuleGetCompilationInfoCallback(ShaderModule* shaderModule,
+                                                          uint64_t requestSerial,
+                                                          WGPUCompilationInfoRequestStatus status,
+                                                          const WGPUCompilationInfo* info) {
+        // The shader module might have been deleted or recreated so this isn't an error.
+        if (shaderModule == nullptr) {
+            return true;
+        }
+        return shaderModule->GetCompilationInfoCallback(requestSerial, status, info);
+    }
+
 }}  // namespace dawn_wire::client
diff --git a/src/dawn_wire/client/ShaderModule.cpp b/src/dawn_wire/client/ShaderModule.cpp
new file mode 100644
index 0000000..97e0204
--- /dev/null
+++ b/src/dawn_wire/client/ShaderModule.cpp
@@ -0,0 +1,66 @@
+// Copyright 2021 The Dawn Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "dawn_wire/client/ShaderModule.h"
+
+#include "dawn_wire/client/Client.h"
+
+namespace dawn_wire { namespace client {
+
+    ShaderModule::~ShaderModule() {
+        // Callbacks need to be fired in all cases, as they can handle freeing resources. So we call
+        // them with "Unknown" status.
+        for (auto& it : mCompilationInfoRequests) {
+            if (it.second.callback) {
+                it.second.callback(WGPUCompilationInfoRequestStatus_Unknown, nullptr,
+                                   it.second.userdata);
+            }
+        }
+        mCompilationInfoRequests.clear();
+    }
+
+    void ShaderModule::GetCompilationInfo(WGPUCompilationInfoCallback callback, void* userdata) {
+        if (client->IsDisconnected()) {
+            callback(WGPUCompilationInfoRequestStatus_DeviceLost, nullptr, userdata);
+            return;
+        }
+
+        uint64_t serial = mCompilationInfoRequestSerial++;
+        ShaderModuleGetCompilationInfoCmd cmd;
+        cmd.shaderModuleId = this->id;
+        cmd.requestSerial = serial;
+
+        mCompilationInfoRequests[serial] = {callback, userdata};
+
+        client->SerializeCommand(cmd);
+    }
+
+    bool ShaderModule::GetCompilationInfoCallback(uint64_t requestSerial,
+                                                  WGPUCompilationInfoRequestStatus status,
+                                                  const WGPUCompilationInfo* info) {
+        auto requestIt = mCompilationInfoRequests.find(requestSerial);
+        if (requestIt == mCompilationInfoRequests.end()) {
+            return false;
+        }
+
+        // Remove the request data so that the callback cannot be called again.
+        // ex.) inside the callback: if the shader module is deleted, all callbacks reject.
+        CompilationInfoRequest request = std::move(requestIt->second);
+        mCompilationInfoRequests.erase(requestIt);
+
+        request.callback(status, info, request.userdata);
+        return true;
+    }
+
+}}  // namespace dawn_wire::client
diff --git a/src/dawn_wire/client/ShaderModule.h b/src/dawn_wire/client/ShaderModule.h
new file mode 100644
index 0000000..add5b97
--- /dev/null
+++ b/src/dawn_wire/client/ShaderModule.h
@@ -0,0 +1,46 @@
+// Copyright 2021 The Dawn Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef DAWNWIRE_CLIENT_SHADER_MODULE_H_
+#define DAWNWIRE_CLIENT_SHADER_MODULE_H_
+
+#include <dawn/webgpu.h>
+
+#include "common/SerialMap.h"
+#include "dawn_wire/client/ObjectBase.h"
+
+namespace dawn_wire { namespace client {
+
+    class ShaderModule final : public ObjectBase {
+      public:
+        using ObjectBase::ObjectBase;
+        ~ShaderModule();
+
+        void GetCompilationInfo(WGPUCompilationInfoCallback callback, void* userdata);
+        bool GetCompilationInfoCallback(uint64_t requestSerial,
+                                        WGPUCompilationInfoRequestStatus status,
+                                        const WGPUCompilationInfo* info);
+
+      private:
+        struct CompilationInfoRequest {
+            WGPUCompilationInfoCallback callback = nullptr;
+            void* userdata = nullptr;
+        };
+        uint64_t mCompilationInfoRequestSerial = 0;
+        std::map<uint64_t, CompilationInfoRequest> mCompilationInfoRequests;
+    };
+
+}}  // namespace dawn_wire::client
+
+#endif  // DAWNWIRE_CLIENT_SHADER_MODULE_H_
diff --git a/src/dawn_wire/server/Server.h b/src/dawn_wire/server/Server.h
index 1124cba..5baea19 100644
--- a/src/dawn_wire/server/Server.h
+++ b/src/dawn_wire/server/Server.h
@@ -141,6 +141,13 @@
         uint64_t requestSerial;
     };
 
+    struct ShaderModuleGetCompilationInfoUserdata : CallbackUserdata {
+        using CallbackUserdata::CallbackUserdata;
+
+        ObjectHandle shaderModule;
+        uint64_t requestSerial;
+    };
+
     struct QueueWorkDoneUserdata : CallbackUserdata {
         using CallbackUserdata::CallbackUserdata;
 
@@ -218,6 +225,9 @@
                                                  WGPURenderPipeline pipeline,
                                                  const char* message,
                                                  CreatePipelineAsyncUserData* userdata);
+        void OnShaderModuleGetCompilationInfo(WGPUCompilationInfoRequestStatus status,
+                                              const WGPUCompilationInfo* info,
+                                              ShaderModuleGetCompilationInfoUserdata* userdata);
 
 #include "dawn_wire/server/ServerPrototypes_autogen.inc"
 
diff --git a/src/dawn_wire/server/ServerShaderModule.cpp b/src/dawn_wire/server/ServerShaderModule.cpp
new file mode 100644
index 0000000..cec0dc4
--- /dev/null
+++ b/src/dawn_wire/server/ServerShaderModule.cpp
@@ -0,0 +1,51 @@
+// Copyright 2021 The Dawn Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "dawn_wire/server/Server.h"
+
+#include <memory>
+
+namespace dawn_wire { namespace server {
+
+    bool Server::DoShaderModuleGetCompilationInfo(ObjectId shaderModuleId, uint64_t requestSerial) {
+        auto* shaderModule = ShaderModuleObjects().Get(shaderModuleId);
+        if (shaderModule == nullptr) {
+            return false;
+        }
+
+        auto userdata = MakeUserdata<ShaderModuleGetCompilationInfoUserdata>();
+        userdata->shaderModule = ObjectHandle{shaderModuleId, shaderModule->generation};
+        userdata->requestSerial = requestSerial;
+
+        mProcs.shaderModuleGetCompilationInfo(
+            shaderModule->handle,
+            ForwardToServer<decltype(&Server::OnShaderModuleGetCompilationInfo)>::Func<
+                &Server::OnShaderModuleGetCompilationInfo>(),
+            userdata.release());
+        return true;
+    }
+
+    void Server::OnShaderModuleGetCompilationInfo(WGPUCompilationInfoRequestStatus status,
+                                                  const WGPUCompilationInfo* info,
+                                                  ShaderModuleGetCompilationInfoUserdata* data) {
+        ReturnShaderModuleGetCompilationInfoCallbackCmd cmd;
+        cmd.shaderModule = data->shaderModule;
+        cmd.requestSerial = data->requestSerial;
+        cmd.status = status;
+        cmd.info = info;
+
+        SerializeCommand(cmd);
+    }
+
+}}  // namespace dawn_wire::server
diff --git a/src/tests/unittests/validation/ShaderModuleValidationTests.cpp b/src/tests/unittests/validation/ShaderModuleValidationTests.cpp
index a1bea22..ceb6e18 100644
--- a/src/tests/unittests/validation/ShaderModuleValidationTests.cpp
+++ b/src/tests/unittests/validation/ShaderModuleValidationTests.cpp
@@ -14,6 +14,9 @@
 
 #include "common/Constants.h"
 
+#include "dawn_native/CompilationMessages.h"
+#include "dawn_native/ShaderModule.h"
+
 #include "tests/unittests/validation/ValidationTest.h"
 
 #include "utils/WGPUHelpers.h"
@@ -153,3 +156,53 @@
 
     ASSERT_DEVICE_ERROR(utils::CreateShaderModuleFromASM(device, shader));
 }
+
+// Tests that shader module compilation messages can be queried.
+TEST_F(ShaderModuleValidationTest, CompilationMessages) {
+    // This test works assuming ShaderModule is backed by a dawn_native::ShaderModuleBase, which
+    // is not the case on the wire.
+    DAWN_SKIP_TEST_IF(UsesWire());
+
+    std::ostringstream stream;
+    stream << R"([[location(0)]] var<out> fragColor : vec4<f32>;
+        [[stage(fragment)]] fn main() -> void {
+            fragColor = vec4<f32>(0.0, 1.0, 0.0, 1.0);
+        })";
+    wgpu::ShaderModule shaderModule = utils::CreateShaderModule(device, stream.str().c_str());
+
+    dawn_native::ShaderModuleBase* shaderModuleBase =
+        reinterpret_cast<dawn_native::ShaderModuleBase*>(shaderModule.Get());
+    shaderModuleBase->CompilationMessages()->ClearMessages();
+    shaderModuleBase->CompilationMessages()->AddMessage("Info Message");
+    shaderModuleBase->CompilationMessages()->AddMessage("Warning Message",
+                                                        wgpu::CompilationMessageType::Warning);
+    shaderModuleBase->CompilationMessages()->AddMessage("Error Message",
+                                                        wgpu::CompilationMessageType::Error, 3, 4);
+
+    auto callback = [](WGPUCompilationInfoRequestStatus status, const WGPUCompilationInfo* info,
+                       void* userdata) {
+        ASSERT_EQ(WGPUCompilationInfoRequestStatus_Success, status);
+        ASSERT_NE(nullptr, info);
+        ASSERT_EQ(3u, info->messageCount);
+
+        const WGPUCompilationMessage* message = &info->messages[0];
+        ASSERT_STREQ("Info Message", message->message);
+        ASSERT_EQ(WGPUCompilationMessageType_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(WGPUCompilationMessageType_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(WGPUCompilationMessageType_Error, message->type);
+        ASSERT_EQ(3u, message->lineNum);
+        ASSERT_EQ(4u, message->linePos);
+    };
+
+    shaderModule.GetCompilationInfo(callback, nullptr);
+}