Make the wire Client own ObjectAllocators and CommandSerializer

This moves ownership of ObjectAllocators and CommandSerializers
from the Device to the Client. There may be also be multiple
Devices, so New() now takes the Device the object belongs to.
Device allocation specializes New() to take the owning Client so
that we can get a pointer to the Client from any Dawn API object.

Bug: dawn:88
Change-Id: Ie4274d46313884c44a857159e95d236dc1141c0c
Reviewed-on: https://dawn-review.googlesource.com/c/4001
Commit-Queue: Austin Eng <enga@chromium.org>
Reviewed-by: Kai Ninomiya <kainino@chromium.org>
diff --git a/BUILD.gn b/BUILD.gn
index 4171f62..e3ebd1d 100644
--- a/BUILD.gn
+++ b/BUILD.gn
@@ -763,9 +763,9 @@
     "dawn_wire/client/ApiObjects_autogen.h",
     "dawn_wire/client/ApiProcs_autogen.cpp",
     "dawn_wire/client/ApiProcs_autogen.h",
+    "dawn_wire/client/ClientBase_autogen.h",
     "dawn_wire/client/ClientHandlers_autogen.cpp",
     "dawn_wire/client/ClientPrototypes_autogen.inl",
-    "dawn_wire/client/Device_autogen.h",
     "dawn_wire/server/ServerBase_autogen.h",
     "dawn_wire/server/ServerCallbacks_autogen.cpp",
     "dawn_wire/server/ServerHandlers_autogen.cpp",
@@ -795,6 +795,8 @@
     "src/dawn_wire/client/Client.cpp",
     "src/dawn_wire/client/Client.h",
     "src/dawn_wire/client/ClientHandlers.cpp",
+    "src/dawn_wire/client/Device.cpp",
+    "src/dawn_wire/client/Device.h",
     "src/dawn_wire/client/Fence.cpp",
     "src/dawn_wire/client/Fence.h",
     "src/dawn_wire/client/ObjectAllocator.h",
diff --git a/generator/main.py b/generator/main.py
index ab4c6c7..bbc0869 100644
--- a/generator/main.py
+++ b/generator/main.py
@@ -387,9 +387,9 @@
         renders.append(FileRender('dawn_wire/client/ApiObjects.h', 'dawn_wire/client/ApiObjects_autogen.h', wire_params))
         renders.append(FileRender('dawn_wire/client/ApiProcs.cpp', 'dawn_wire/client/ApiProcs_autogen.cpp', wire_params))
         renders.append(FileRender('dawn_wire/client/ApiProcs.h', 'dawn_wire/client/ApiProcs_autogen.h', wire_params))
+        renders.append(FileRender('dawn_wire/client/ClientBase.h', 'dawn_wire/client/ClientBase_autogen.h', wire_params))
         renders.append(FileRender('dawn_wire/client/ClientHandlers.cpp', 'dawn_wire/client/ClientHandlers_autogen.cpp', wire_params))
         renders.append(FileRender('dawn_wire/client/ClientPrototypes.inl', 'dawn_wire/client/ClientPrototypes_autogen.inl', wire_params))
-        renders.append(FileRender('dawn_wire/client/Device.h', 'dawn_wire/client/Device_autogen.h', wire_params))
         renders.append(FileRender('dawn_wire/server/ServerBase.h', 'dawn_wire/server/ServerBase_autogen.h', wire_params))
         renders.append(FileRender('dawn_wire/server/ServerCallbacks.cpp', 'dawn_wire/server/ServerCallbacks_autogen.cpp', wire_params))
         renders.append(FileRender('dawn_wire/server/ServerHandlers.cpp', 'dawn_wire/server/ServerHandlers_autogen.cpp', wire_params))
diff --git a/generator/templates/dawn_wire/client/ApiProcs.cpp b/generator/templates/dawn_wire/client/ApiProcs.cpp
index 9544e93..a5c6282 100644
--- a/generator/templates/dawn_wire/client/ApiProcs.cpp
+++ b/generator/templates/dawn_wire/client/ApiProcs.cpp
@@ -15,7 +15,6 @@
 #include "dawn_wire/client/ApiObjects.h"
 #include "dawn_wire/client/ApiProcs_autogen.h"
 #include "dawn_wire/client/Client.h"
-#include "dawn_wire/client/Device_autogen.h"
 
 namespace dawn_wire { namespace client {
     //* Implementation of the client API functions.
@@ -42,7 +41,7 @@
 
                     //* For object creation, store the object ID the client will use for the result.
                     {% if method.return_type.category == "object" %}
-                        auto* allocation = self->device->{{method.return_type.name.camelCase()}}.New();
+                        auto* allocation = self->device->GetClient()->{{method.return_type.name.CamelCase()}}Allocator().New(self->device);
 
                         {% if type.is_builder %}
                             //* We are in GetResult, so the callback that should be called is the
@@ -61,8 +60,8 @@
 
                     //* Allocate space to send the command and copy the value args over.
                     size_t requiredSize = cmd.GetRequiredSize();
-                    char* allocatedBuffer = static_cast<char*>(device->GetCmdSpace(requiredSize));
-                    cmd.Serialize(allocatedBuffer, *device);
+                    char* allocatedBuffer = static_cast<char*>(device->GetClient()->GetCmdSpace(requiredSize));
+                    cmd.Serialize(allocatedBuffer, *device->GetClient());
 
                     {% if method.return_type.category == "object" %}
                         return reinterpret_cast<{{as_cType(method.return_type.name)}}>(allocation->object.get());
@@ -100,10 +99,10 @@
                 cmd.objectId = obj->id;
 
                 size_t requiredSize = cmd.GetRequiredSize();
-                char* allocatedBuffer = static_cast<char*>(obj->device->GetCmdSpace(requiredSize));
+                char* allocatedBuffer = static_cast<char*>(obj->device->GetClient()->GetCmdSpace(requiredSize));
                 cmd.Serialize(allocatedBuffer);
 
-                obj->device->{{type.name.camelCase()}}.Free(obj);
+                obj->device->GetClient()->{{type.name.CamelCase()}}Allocator().Free(obj);
             }
 
             void Client{{as_MethodSuffix(type.name, Name("reference"))}}({{cType}} cObj) {
diff --git a/generator/templates/dawn_wire/client/ClientBase.h b/generator/templates/dawn_wire/client/ClientBase.h
new file mode 100644
index 0000000..fa77852
--- /dev/null
+++ b/generator/templates/dawn_wire/client/ClientBase.h
@@ -0,0 +1,62 @@
+//* Copyright 2019 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_CLIENTBASE_AUTOGEN_H_
+#define DAWNWIRE_CLIENT_CLIENTBASE_AUTOGEN_H_
+
+#include "dawn_wire/WireCmd_autogen.h"
+#include "dawn_wire/client/ApiObjects.h"
+#include "dawn_wire/client/ObjectAllocator.h"
+
+namespace dawn_wire { namespace client {
+
+    class ClientBase : public ObjectIdProvider {
+      public:
+        ClientBase() {
+        }
+
+        virtual ~ClientBase() {
+        }
+
+        {% for type in by_category["object"] %}
+            const ObjectAllocator<{{type.name.CamelCase()}}>& {{type.name.CamelCase()}}Allocator() const {
+                return m{{type.name.CamelCase()}}Allocator;
+            }
+            ObjectAllocator<{{type.name.CamelCase()}}>& {{type.name.CamelCase()}}Allocator() {
+                return m{{type.name.CamelCase()}}Allocator;
+            }
+        {% endfor %}
+
+      private:
+        // Implementation of the ObjectIdProvider interface
+        {% for type in by_category["object"] %}
+            ObjectId GetId({{as_cType(type.name)}} object) const final {
+                return object == nullptr ? 0 : reinterpret_cast<{{as_wireType(type)}}>(object)->id;
+            }
+            ObjectId GetOptionalId({{as_cType(type.name)}} object) const final {
+                if (object == nullptr) {
+                    return 0;
+                }
+                return GetId(object);
+            }
+        {% endfor %}
+
+        {% for type in by_category["object"] %}
+            ObjectAllocator<{{type.name.CamelCase()}}> m{{type.name.CamelCase()}}Allocator;
+        {% endfor %}
+    };
+
+}}  // namespace dawn_wire::client
+
+#endif  // DAWNWIRE_CLIENT_CLIENTBASE_AUTOGEN_H_
diff --git a/generator/templates/dawn_wire/client/ClientHandlers.cpp b/generator/templates/dawn_wire/client/ClientHandlers.cpp
index 31a8081..75beddc 100644
--- a/generator/templates/dawn_wire/client/ClientHandlers.cpp
+++ b/generator/templates/dawn_wire/client/ClientHandlers.cpp
@@ -14,7 +14,6 @@
 
 #include "common/Assert.h"
 #include "dawn_wire/client/Client.h"
-#include "dawn_wire/client/Device_autogen.h"
 
 #include <string>
 
@@ -31,8 +30,8 @@
 
             DAWN_ASSERT(cmd.message != nullptr);
 
-            auto* builtObject = mDevice->{{type.built_type.name.camelCase()}}.GetObject(cmd.builtObject.id);
-            uint32_t objectSerial = mDevice->{{type.built_type.name.camelCase()}}.GetSerial(cmd.builtObject.id);
+            auto* builtObject = mDevice->GetClient()->{{type.built_type.name.CamelCase()}}Allocator().GetObject(cmd.builtObject.id);
+            uint32_t objectSerial = mDevice->GetClient()->{{type.built_type.name.CamelCase()}}Allocator().GetSerial(cmd.builtObject.id);
 
             //* The object might have been deleted or a new object created with the same ID.
             if (builtObject == nullptr || objectSerial != cmd.builtObject.serial) {
diff --git a/generator/templates/dawn_wire/client/Device.h b/generator/templates/dawn_wire/client/Device.h
deleted file mode 100644
index 796383a..0000000
--- a/generator/templates/dawn_wire/client/Device.h
+++ /dev/null
@@ -1,73 +0,0 @@
-//* Copyright 2019 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_DEVICE_AUTOGEN_H_
-#define DAWNWIRE_CLIENT_DEVICE_AUTOGEN_H_
-
-#include <dawn/dawn.h>
-
-#include "dawn_wire/Wire.h"
-#include "dawn_wire/WireCmd_autogen.h"
-#include "dawn_wire/client/ApiObjects.h"
-#include "dawn_wire/client/ObjectAllocator.h"
-
-namespace dawn_wire { namespace client {
-    //* The client wire uses the global Dawn device to store its global data such as the serializer
-    //* and the object id allocators.
-    class Device : public ObjectBase, public ObjectIdProvider {
-        public:
-            Device(CommandSerializer* serializer)
-                : ObjectBase(this, 1, 1),
-                {% for type in by_category["object"] if not type.name.canonical_case() == "device" %}
-                    {{type.name.camelCase()}}(this),
-                {% endfor %}
-                mSerializer(serializer) {
-            }
-
-            void* GetCmdSpace(size_t size) {
-                return mSerializer->GetCmdSpace(size);
-            }
-
-            {% for type in by_category["object"] if not type.name.canonical_case() == "device" %}
-                ObjectAllocator<{{type.name.CamelCase()}}> {{type.name.camelCase()}};
-            {% endfor %}
-
-            // Implementation of the ObjectIdProvider interface
-            {% for type in by_category["object"] %}
-                ObjectId GetId({{as_cType(type.name)}} object) const final {
-                    return reinterpret_cast<{{as_wireType(type)}}>(object)->id;
-                }
-                ObjectId GetOptionalId({{as_cType(type.name)}} object) const final {
-                    if (object == nullptr) {
-                        return 0;
-                    }
-                    return GetId(object);
-                }
-            {% endfor %}
-
-            void HandleError(const char* message) {
-                if (errorCallback) {
-                    errorCallback(message, errorUserdata);
-                }
-            }
-
-            dawnDeviceErrorCallback errorCallback = nullptr;
-            dawnCallbackUserdata errorUserdata;
-
-        private:
-            CommandSerializer* mSerializer = nullptr;
-    };
-}}  // namespace dawn_wire::client
-
-#endif  // DAWNWIRE_CLIENT_DEVICE_AUTOGEN_H_
diff --git a/src/dawn_wire/DawnWire.cpp b/src/dawn_wire/DawnWire.cpp
index 7dca809..56792d0 100644
--- a/src/dawn_wire/DawnWire.cpp
+++ b/src/dawn_wire/DawnWire.cpp
@@ -13,19 +13,13 @@
 // limitations under the License.
 
 #include "dawn_wire/client/Client.h"
-#include "dawn_wire/client/Device_autogen.h"
 #include "dawn_wire/server/Server.h"
 
 namespace dawn_wire {
     CommandHandler* NewClientDevice(dawnProcTable* procs,
                                     dawnDevice* device,
                                     CommandSerializer* serializer) {
-        auto clientDevice = new client::Device(serializer);
-
-        *device = reinterpret_cast<dawnDeviceImpl*>(clientDevice);
-        *procs = client::GetProcs();
-
-        return new client::Client(clientDevice);
+        return new client::Client(procs, device, serializer);
     }
 
     CommandHandler* NewServerCommandHandler(dawnDevice device,
diff --git a/src/dawn_wire/client/ApiObjects.h b/src/dawn_wire/client/ApiObjects.h
index c7a52c3..b74eefe 100644
--- a/src/dawn_wire/client/ApiObjects.h
+++ b/src/dawn_wire/client/ApiObjects.h
@@ -18,6 +18,7 @@
 #include "dawn_wire/client/ObjectBase.h"
 
 #include "dawn_wire/client/Buffer.h"
+#include "dawn_wire/client/Device.h"
 #include "dawn_wire/client/Fence.h"
 
 #include "dawn_wire/client/ApiObjects_autogen.h"
diff --git a/src/dawn_wire/client/ApiProcs.cpp b/src/dawn_wire/client/ApiProcs.cpp
index 99f620a..d5a4494 100644
--- a/src/dawn_wire/client/ApiProcs.cpp
+++ b/src/dawn_wire/client/ApiProcs.cpp
@@ -12,8 +12,9 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+#include "dawn_wire/client/ApiObjects.h"
 #include "dawn_wire/client/ApiProcs_autogen.h"
-#include "dawn_wire/client/Device_autogen.h"
+#include "dawn_wire/client/Client.h"
 
 namespace dawn_wire { namespace client {
 
@@ -42,7 +43,8 @@
         cmd.isWrite = false;
 
         size_t requiredSize = cmd.GetRequiredSize();
-        char* allocatedBuffer = static_cast<char*>(buffer->device->GetCmdSpace(requiredSize));
+        char* allocatedBuffer =
+            static_cast<char*>(buffer->device->GetClient()->GetCmdSpace(requiredSize));
         cmd.Serialize(allocatedBuffer);
     }
 
@@ -71,7 +73,8 @@
         cmd.isWrite = true;
 
         size_t requiredSize = cmd.GetRequiredSize();
-        char* allocatedBuffer = static_cast<char*>(buffer->device->GetCmdSpace(requiredSize));
+        char* allocatedBuffer =
+            static_cast<char*>(buffer->device->GetClient()->GetCmdSpace(requiredSize));
         cmd.Serialize(allocatedBuffer);
     }
 
@@ -124,7 +127,7 @@
 
                 size_t requiredSize = cmd.GetRequiredSize();
                 char* allocatedBuffer =
-                    static_cast<char*>(buffer->device->GetCmdSpace(requiredSize));
+                    static_cast<char*>(buffer->device->GetClient()->GetCmdSpace(requiredSize));
                 cmd.Serialize(allocatedBuffer);
             }
 
@@ -164,9 +167,8 @@
     void ClientDeviceSetErrorCallback(dawnDevice cSelf,
                                       dawnDeviceErrorCallback callback,
                                       dawnCallbackUserdata userdata) {
-        Device* self = reinterpret_cast<Device*>(cSelf);
-        self->errorCallback = callback;
-        self->errorUserdata = userdata;
+        Device* device = reinterpret_cast<Device*>(cSelf);
+        device->SetErrorCallback(callback, userdata);
     }
 
 }}  // namespace dawn_wire::client
diff --git a/src/dawn_wire/client/Client.cpp b/src/dawn_wire/client/Client.cpp
index 6921fa9..ecd332e 100644
--- a/src/dawn_wire/client/Client.cpp
+++ b/src/dawn_wire/client/Client.cpp
@@ -13,10 +13,20 @@
 // limitations under the License.
 
 #include "dawn_wire/client/Client.h"
+#include "dawn_wire/client/Device.h"
 
 namespace dawn_wire { namespace client {
 
-    Client::Client(Device* device) : mDevice(device) {
+    Client::Client(dawnProcTable* procs, dawnDevice* device, CommandSerializer* serializer)
+        : ClientBase(),
+          mDevice(DeviceAllocator().New(this)->object.get()),
+          mSerializer(serializer) {
+        *device = reinterpret_cast<dawnDeviceImpl*>(mDevice);
+        *procs = client::GetProcs();
+    }
+
+    Client::~Client() {
+        DeviceAllocator().Free(mDevice);
     }
 
 }}  // namespace dawn_wire::client
diff --git a/src/dawn_wire/client/Client.h b/src/dawn_wire/client/Client.h
index cf975e8..3f8a703 100644
--- a/src/dawn_wire/client/Client.h
+++ b/src/dawn_wire/client/Client.h
@@ -19,20 +19,28 @@
 
 #include "dawn_wire/WireCmd_autogen.h"
 #include "dawn_wire/WireDeserializeAllocator.h"
+#include "dawn_wire/client/ClientBase_autogen.h"
 
 namespace dawn_wire { namespace client {
 
     class Device;
 
-    class Client : public CommandHandler {
+    class Client : public ClientBase, public CommandHandler {
       public:
-        Client(Device* device);
+        Client(dawnProcTable* procs, dawnDevice* device, CommandSerializer* serializer);
+        ~Client();
+
         const char* HandleCommands(const char* commands, size_t size);
 
+        void* GetCmdSpace(size_t size) {
+            return mSerializer->GetCmdSpace(size);
+        }
+
       private:
 #include "dawn_wire/client/ClientPrototypes_autogen.inl"
 
-        Device* mDevice;
+        Device* mDevice = nullptr;
+        CommandSerializer* mSerializer = nullptr;
         WireDeserializeAllocator mAllocator;
     };
 
diff --git a/src/dawn_wire/client/ClientHandlers.cpp b/src/dawn_wire/client/ClientHandlers.cpp
index dc64ec2..913b7a5 100644
--- a/src/dawn_wire/client/ClientHandlers.cpp
+++ b/src/dawn_wire/client/ClientHandlers.cpp
@@ -14,7 +14,7 @@
 
 #include "common/Assert.h"
 #include "dawn_wire/client/Client.h"
-#include "dawn_wire/client/Device_autogen.h"
+#include "dawn_wire/client/Device.h"
 
 namespace dawn_wire { namespace client {
 
@@ -40,8 +40,8 @@
             return false;
         }
 
-        auto* buffer = mDevice->buffer.GetObject(cmd.buffer.id);
-        uint32_t bufferSerial = mDevice->buffer.GetSerial(cmd.buffer.id);
+        auto* buffer = mDevice->GetClient()->BufferAllocator().GetObject(cmd.buffer.id);
+        uint32_t bufferSerial = mDevice->GetClient()->BufferAllocator().GetSerial(cmd.buffer.id);
 
         // The buffer might have been deleted or recreated so this isn't an error.
         if (buffer == nullptr || bufferSerial != cmd.buffer.serial) {
@@ -102,8 +102,8 @@
             return false;
         }
 
-        auto* buffer = mDevice->buffer.GetObject(cmd.buffer.id);
-        uint32_t bufferSerial = mDevice->buffer.GetSerial(cmd.buffer.id);
+        auto* buffer = mDevice->GetClient()->BufferAllocator().GetObject(cmd.buffer.id);
+        uint32_t bufferSerial = mDevice->GetClient()->BufferAllocator().GetSerial(cmd.buffer.id);
 
         // The buffer might have been deleted or recreated so this isn't an error.
         if (buffer == nullptr || bufferSerial != cmd.buffer.serial) {
@@ -156,8 +156,8 @@
             return false;
         }
 
-        auto* fence = mDevice->fence.GetObject(cmd.fence.id);
-        uint32_t fenceSerial = mDevice->fence.GetSerial(cmd.fence.id);
+        auto* fence = mDevice->GetClient()->FenceAllocator().GetObject(cmd.fence.id);
+        uint32_t fenceSerial = mDevice->GetClient()->FenceAllocator().GetSerial(cmd.fence.id);
 
         // The fence might have been deleted or recreated so this isn't an error.
         if (fence == nullptr || fenceSerial != cmd.fence.serial) {
diff --git a/src/dawn_wire/client/Device.cpp b/src/dawn_wire/client/Device.cpp
new file mode 100644
index 0000000..57e6e16
--- /dev/null
+++ b/src/dawn_wire/client/Device.cpp
@@ -0,0 +1,40 @@
+// Copyright 2019 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/Device.h"
+
+namespace dawn_wire { namespace client {
+
+    Device::Device(Client* client, uint32_t refcount, uint32_t id)
+        : ObjectBase(this, refcount, id), mClient(client) {
+        this->device = this;
+    }
+
+    Client* Device::GetClient() {
+        return mClient;
+    }
+
+    void Device::HandleError(const char* message) {
+        if (mErrorCallback) {
+            mErrorCallback(message, mErrorUserdata);
+        }
+    }
+
+    void Device::SetErrorCallback(dawnDeviceErrorCallback errorCallback,
+                                  dawnCallbackUserdata errorUserdata) {
+        mErrorCallback = errorCallback;
+        mErrorUserdata = errorUserdata;
+    }
+
+}}  // namespace dawn_wire::client
diff --git a/src/dawn_wire/client/Device.h b/src/dawn_wire/client/Device.h
new file mode 100644
index 0000000..f3d49d7
--- /dev/null
+++ b/src/dawn_wire/client/Device.h
@@ -0,0 +1,43 @@
+// Copyright 2019 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_DEVICE_H_
+#define DAWNWIRE_CLIENT_DEVICE_H_
+
+#include <dawn/dawn.h>
+
+#include "dawn_wire/client/ObjectBase.h"
+
+namespace dawn_wire { namespace client {
+
+    class Client;
+
+    class Device : public ObjectBase {
+      public:
+        Device(Client* client, uint32_t refcount, uint32_t id);
+
+        Client* GetClient();
+        void HandleError(const char* message);
+        void SetErrorCallback(dawnDeviceErrorCallback errorCallback,
+                              dawnCallbackUserdata errorUserdata);
+
+      private:
+        Client* mClient = nullptr;
+        dawnDeviceErrorCallback mErrorCallback = nullptr;
+        dawnCallbackUserdata mErrorUserdata;
+    };
+
+}}  // namespace dawn_wire::client
+
+#endif  // DAWNWIRE_CLIENT_DEVICE_H_
diff --git a/src/dawn_wire/client/ObjectAllocator.h b/src/dawn_wire/client/ObjectAllocator.h
index c50307c..3b1b60e 100644
--- a/src/dawn_wire/client/ObjectAllocator.h
+++ b/src/dawn_wire/client/ObjectAllocator.h
@@ -22,12 +22,16 @@
 
 namespace dawn_wire { namespace client {
 
+    class Client;
     class Device;
 
     // TODO(cwallez@chromium.org): Do something with objects before they are destroyed ?
     //  - Call still uncalled builder callbacks
     template <typename T>
     class ObjectAllocator {
+        using ObjectOwner =
+            typename std::conditional<std::is_same<T, Device>::value, Client, Device>::type;
+
       public:
         struct ObjectAndSerial {
             ObjectAndSerial(std::unique_ptr<T> object, uint32_t serial)
@@ -37,14 +41,14 @@
             uint32_t serial;
         };
 
-        ObjectAllocator(Device* device) : mDevice(device) {
+        ObjectAllocator() {
             // ID 0 is nullptr
             mObjects.emplace_back(nullptr, 0);
         }
 
-        ObjectAndSerial* New() {
+        ObjectAndSerial* New(ObjectOwner* owner) {
             uint32_t id = GetNewId();
-            T* result = new T(mDevice, 1, id);
+            T* result = new T(owner, 1, id);
             auto object = std::unique_ptr<T>(result);
 
             if (id >= mObjects.size()) {
diff --git a/src/tests/unittests/WireTests.cpp b/src/tests/unittests/WireTests.cpp
index 48db4e6..b032fc2 100644
--- a/src/tests/unittests/WireTests.cpp
+++ b/src/tests/unittests/WireTests.cpp
@@ -170,6 +170,10 @@
         void TearDown() override {
             dawnSetProcs(nullptr);
 
+            // Reset client before mocks are deleted.
+            // Incomplete callbacks will be called on deletion, so the mocks cannot be null.
+            mWireClient = nullptr;
+
             // Delete mocks so that expectations are checked
             mockDeviceErrorCallback = nullptr;
             mockBuilderErrorCallback = nullptr;