Revert "[dawn] Removes old non-overridden non-Future entry."

This reverts commit fa07f3046419775df4d2f8fb5b0a9c5078399d4e.

Reason for revert: Breaking Dawn->Chromium roll, need to update MLDrift.

Original change's description:
> [dawn] Removes old non-overridden non-Future entry.
>
> - Removes/Renames the following entry points and their
>   corresponding old Callbacks and CallbackInfos:
>     - ShaderModule::GetCompilationInfo
>     - Device::Create*PipelineAsync
>     - Device::PopErrorScope
>     - Buffer::MapAsync
>     - Queue::OnSubmittedWorkDone
>  - Note that "overridden" entry points will be removed in
>    multi-CL changes since those refer to entry points
>    where users may be manually overriding the C proc table.
>
> Bug: 369445924
> Change-Id: I074cac71587b64555288e44c9f483d9426c7abd0
> Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/216314
> Reviewed-by: Kai Ninomiya <kainino@chromium.org>
> Commit-Queue: Loko Kung <lokokung@google.com>

Bug: 369445924
Change-Id: Ia93ea22936c5a37ba9d86fb9a34d10b1c5ebcbff
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/220294
Commit-Queue: Loko Kung <lokokung@google.com>
Reviewed-by: Jiawei Shao <jiawei.shao@intel.com>
Reviewed-by: Loko Kung <lokokung@google.com>
Auto-Submit: Loko Kung <lokokung@google.com>
diff --git a/generator/templates/mock_api.cpp b/generator/templates/mock_api.cpp
index e976aef..dc5c9e1 100644
--- a/generator/templates/mock_api.cpp
+++ b/generator/templates/mock_api.cpp
@@ -98,7 +98,10 @@
                     object->m{{Suffix}}Userdata = userdata;
                 {% endfor %}
 
-                {% if method.name.get() not in LegacyCallbackFunctions %}
+                {% if method.name.get() == 'pop error scope' %}
+                    //* Currently special casing popErrorScope since it has an old callback type.
+                    On{{Suffix}}({{-as_varName(type.name)}}, {.nextInChain = nullptr, .mode = WGPUCallbackMode_AllowProcessEvents, .callback = nullptr, .oldCallback = oldCallback, .userdata = userdata});
+                {% elif method.name.get() not in LegacyCallbackFunctions %}
                     On{{Suffix}}(
                         {{-as_varName(type.name)}}
                         {%- for arg in method.arguments if arg.type.category != 'function pointer' and arg.type.name.get() != 'void *' -%}
diff --git a/src/dawn/dawn.json b/src/dawn/dawn.json
index e4712d5..85cacb8 100644
--- a/src/dawn/dawn.json
+++ b/src/dawn/dawn.json
@@ -600,6 +600,18 @@
         "methods": [
             {
                 "name": "map async",
+                "args": [
+                    {"name": "mode", "type": "map mode"},
+                    {"name": "offset", "type": "size_t"},
+                    {"name": "size", "type": "size_t"},
+                    {"name": "callback", "type": "buffer map callback"},
+                    {"name": "userdata", "type": "void *"}
+                ]
+            },
+            {
+                "name": "map async f",
+                "_comment": "TODO(crbug.com/dawn/2021): This is dawn/emscripten-only until we rename it to replace the old API. See bug for details.",
+                "tags": ["dawn", "emscripten"],
                 "returns": "future",
                 "args": [
                     {"name": "mode", "type": "map mode"},
@@ -609,6 +621,18 @@
                 ]
             },
             {
+                "name": "map async 2",
+                "_comment": "TODO(crbug.com/dawn/2021): This is dawn/emscripten-only until we rename it to replace the old API. See bug for details.",
+                "tags": ["dawn", "emscripten"],
+                "returns": "future",
+                "args": [
+                    {"name": "mode", "type": "map mode"},
+                    {"name": "offset", "type": "size_t"},
+                    {"name": "size", "type": "size_t"},
+                    {"name": "callback info", "type": "buffer map callback info 2"}
+                ]
+            },
+            {
                 "name": "get mapped range",
                 "returns": "void *",
                 "args": [
@@ -682,6 +706,13 @@
         ]
     },
     "buffer map callback": {
+        "category": "function pointer",
+        "args": [
+            {"name": "status", "type": "buffer map async status"},
+            {"name": "userdata", "type": "void *"}
+        ]
+    },
+    "buffer map callback 2": {
         "category": "callback function",
         "args": [
             {"name": "status", "type": "map async status"},
@@ -689,10 +720,35 @@
         ]
     },
     "buffer map callback info": {
+        "category": "structure",
+        "extensible": "in",
+        "members": [
+            {"name": "mode", "type": "callback mode"},
+            {"name": "callback", "type": "buffer map callback"},
+            {"name": "userdata", "type": "void *"}
+        ]
+    },
+    "buffer map callback info 2": {
         "category": "callback info",
         "members": [
             {"name": "mode", "type": "callback mode"},
-            {"name": "callback", "type": "buffer map callback"}
+            {"name": "callback", "type": "buffer map callback 2"}
+        ]
+    },
+    "buffer map async status": {
+        "category": "enum",
+        "emscripten_no_enum_table": true,
+        "values": [
+            {"value": 1, "name": "success"},
+            {"value": 2, "name": "instance dropped"},
+            {"value": 3, "name": "validation error"},
+            {"value": 4, "name": "unknown"},
+            {"value": 5, "name": "device lost"},
+            {"value": 6, "name": "destroyed before callback"},
+            {"value": 7, "name": "unmapped before callback"},
+            {"value": 8, "name": "mapping already pending"},
+            {"value": 9, "name": "offset out of range"},
+            {"value": 10, "name": "size out of range"}
         ]
     },
     "map async status": {
@@ -937,6 +993,14 @@
         ]
     },
     "compilation info callback": {
+        "category": "function pointer",
+        "args": [
+            {"name": "status", "type": "compilation info request status"},
+            {"name": "compilation info", "type": "compilation info", "annotation": "const*"},
+            {"name": "userdata", "type": "void *"}
+        ]
+    },
+    "compilation info callback 2": {
         "category": "callback function",
         "args": [
             {"name": "status", "type": "compilation info request status"},
@@ -944,10 +1008,19 @@
         ]
     },
     "compilation info callback info": {
+        "category": "structure",
+        "extensible": "in",
+        "members": [
+            {"name": "mode", "type": "callback mode"},
+            {"name": "callback", "type": "compilation info callback"},
+            {"name": "userdata", "type": "void *", "default": "nullptr"}
+        ]
+    },
+    "compilation info callback info 2": {
         "category": "callback info",
         "members": [
             {"name": "mode", "type": "callback mode"},
-            {"name": "callback", "type": "compilation info callback"}
+            {"name": "callback", "type": "compilation info callback 2"}
         ]
     },
     "compilation info request status": {
@@ -1137,6 +1210,15 @@
         ]
     },
     "create compute pipeline async callback": {
+        "category": "function pointer",
+        "args": [
+            {"name": "status", "type": "create pipeline async status"},
+            {"name": "pipeline", "type": "compute pipeline", "optional": true},
+            {"name": "message", "type": "string view"},
+            {"name": "userdata", "type": "void *"}
+        ]
+    },
+    "create compute pipeline async callback 2": {
         "category": "callback function",
         "args": [
             {"name": "status", "type": "create pipeline async status"},
@@ -1145,10 +1227,19 @@
         ]
     },
     "create compute pipeline async callback info": {
+        "category": "structure",
+        "extensible": "in",
+        "members": [
+            {"name": "mode", "type": "callback mode"},
+            {"name": "callback", "type": "create compute pipeline async callback"},
+            {"name": "userdata", "type": "void *"}
+        ]
+    },
+    "create compute pipeline async callback info 2": {
         "category": "callback info",
         "members": [
             {"name": "mode", "type": "callback mode"},
-            {"name": "callback", "type": "create compute pipeline async callback"}
+            {"name": "callback", "type": "create compute pipeline async callback 2"}
         ]
     },
     "create pipeline async status": {
@@ -1165,6 +1256,15 @@
         ]
     },
     "create render pipeline async callback": {
+        "category": "function pointer",
+        "args": [
+            {"name": "status", "type": "create pipeline async status"},
+            {"name": "pipeline", "type": "render pipeline", "optional": true},
+            {"name": "message", "type": "string view"},
+            {"name": "userdata", "type": "void *"}
+        ]
+    },
+    "create render pipeline async callback 2": {
         "category": "callback function",
         "args": [
             {"name": "status", "type": "create pipeline async status"},
@@ -1173,10 +1273,19 @@
         ]
     },
     "create render pipeline async callback info": {
+        "category": "structure",
+        "extensible": "in",
+        "members": [
+            {"name": "mode", "type": "callback mode"},
+            {"name": "callback", "type": "create render pipeline async callback"},
+            {"name": "userdata", "type": "void *"}
+        ]
+    },
+    "create render pipeline async callback info 2": {
         "category": "callback info",
         "members": [
             {"name": "mode", "type": "callback mode"},
-            {"name": "callback", "type": "create render pipeline async callback"}
+            {"name": "callback", "type": "create render pipeline async callback 2"}
         ]
     },
     "cull mode": {
@@ -1245,6 +1354,17 @@
             },
             {
                 "name": "create compute pipeline async",
+                "returns": "void",
+                "args": [
+                    {"name": "descriptor", "type": "compute pipeline descriptor", "annotation": "const*"},
+                    {"name": "callback", "type": "create compute pipeline async callback"},
+                    {"name": "userdata", "type": "void *"}
+                ]
+            },
+            {
+                "name": "create compute pipeline async f",
+                "_comment": "TODO(crbug.com/dawn/2021): This is dawn/emscripten-only until we rename it to replace the old API. See bug for details.",
+                "tags": ["dawn", "emscripten"],
                 "returns": "future",
                 "args": [
                     {"name": "descriptor", "type": "compute pipeline descriptor", "annotation": "const*"},
@@ -1252,6 +1372,16 @@
                 ]
             },
             {
+                "name": "create compute pipeline async 2",
+                "_comment": "TODO(crbug.com/dawn/2021): This is dawn/emscripten-only until we rename it to replace the old API. See bug for details.",
+                "tags": ["dawn", "emscripten"],
+                "returns": "future",
+                "args": [
+                    {"name": "descriptor", "type": "compute pipeline descriptor", "annotation": "const*"},
+                    {"name": "callback info", "type": "create compute pipeline async callback info 2"}
+                ]
+            },
+            {
                 "name": "create external texture",
                 "returns": "external texture",
                 "tags": ["dawn"],
@@ -1280,6 +1410,17 @@
             },
             {
                 "name": "create render pipeline async",
+                "returns": "void",
+                "args": [
+                    {"name": "descriptor", "type": "render pipeline descriptor", "annotation": "const*"},
+                    {"name": "callback", "type": "create render pipeline async callback"},
+                    {"name": "userdata", "type": "void *"}
+                ]
+            },
+            {
+                "name": "create render pipeline async f",
+                "_comment": "TODO(crbug.com/dawn/2021): This is dawn/emscripten-only until we rename it to replace the old API. See bug for details.",
+                "tags": ["dawn", "emscripten"],
                 "returns": "future",
                 "args": [
                     {"name": "descriptor", "type": "render pipeline descriptor", "annotation": "const*"},
@@ -1287,6 +1428,16 @@
                 ]
             },
             {
+                "name": "create render pipeline async 2",
+                "_comment": "TODO(crbug.com/dawn/2021): This is dawn/emscripten-only until we rename it to replace the old API. See bug for details.",
+                "tags": ["dawn", "emscripten"],
+                "returns": "future",
+                "args": [
+                    {"name": "descriptor", "type": "render pipeline descriptor", "annotation": "const*"},
+                    {"name": "callback info", "type": "create render pipeline async callback info 2"}
+                ]
+            },
+            {
                 "name": "create render bundle encoder",
                 "returns": "render bundle encoder",
                 "args": [
@@ -1456,12 +1607,30 @@
             {
                 "name": "pop error scope",
                 "no autolock": true,
+                "args": [
+                    {"name": "old callback", "type": "error callback"},
+                    {"name": "userdata", "type": "void *"}
+                ]
+            },
+            {
+                "name": "pop error scope f",
+                "_comment": "TODO(crbug.com/dawn/2021): This is dawn/emscripten-only until we rename it to replace the old API. See bug for details.",
+                "tags": ["dawn", "emscripten"],
                 "returns": "future",
                 "args": [
                     {"name": "callback info", "type": "pop error scope callback info"}
                 ]
             },
             {
+                "name": "pop error scope 2",
+                "_comment": "TODO(crbug.com/dawn/2021): This is dawn/emscripten-only until we rename it to replace the old API. See bug for details.",
+                "tags": ["dawn", "emscripten"],
+                "returns": "future",
+                "args": [
+                    {"name": "callback info", "type": "pop error scope callback info 2"}
+                ]
+            },
+            {
                 "name": "set label",
                 "returns": "void",
                 "args": [
@@ -1572,6 +1741,15 @@
         ]
     },
     "pop error scope callback": {
+        "category": "function pointer",
+        "args": [
+            {"name": "status", "type": "pop error scope status"},
+            {"name": "type", "type": "error type"},
+            {"name": "message", "type": "string view"},
+            {"name": "userdata", "type": "void *"}
+        ]
+    },
+    "pop error scope callback 2": {
         "category": "callback function",
         "args": [
             {"name": "status", "type": "pop error scope status"},
@@ -1580,10 +1758,20 @@
         ]
     },
     "pop error scope callback info": {
+        "category": "structure",
+        "extensible": "in",
+        "members": [
+            {"name": "mode", "type": "callback mode", "default": "wait any only"},
+            {"name": "callback", "type": "pop error scope callback"},
+            {"name": "old callback", "type": "error callback", "_comment": "TODO(crbug.com/dawn/2021) Deprecate this field once we have moved callers to use the new callback signature."},
+            {"name": "userdata", "type": "void *", "default": "nullptr"}
+        ]
+    },
+    "pop error scope callback info 2": {
         "category": "callback info",
         "members": [
             {"name": "mode", "type": "callback mode"},
-            {"name": "callback", "type": "pop error scope callback"}
+            {"name": "callback", "type": "pop error scope callback 2"}
         ]
     },
     "limits": {
@@ -2760,12 +2948,31 @@
             },
             {
                 "name": "on submitted work done",
+                "tags": ["dawn", "upstream"],
+                "args": [
+                    {"name": "callback", "type": "queue work done callback"},
+                    {"name": "userdata", "type": "void *"}
+                ]
+            },
+            {
+                "name": "on submitted work done f",
+                "_comment": "TODO(crbug.com/dawn/2021): This is dawn/emscripten-only until we rename it to replace the old API. See bug for details.",
+                "tags": ["dawn", "emscripten"],
                 "returns": "future",
                 "args": [
                     {"name": "callback info", "type": "queue work done callback info"}
                 ]
             },
             {
+                "name": "on submitted work done 2",
+                "_comment": "TODO(crbug.com/dawn/2021): This is dawn/emscripten-only until we rename it to replace the old API. See bug for details.",
+                "tags": ["dawn", "emscripten"],
+                "returns": "future",
+                "args": [
+                    {"name": "callback info", "type": "queue work done callback info 2"}
+                ]
+            },
+            {
                 "name": "write buffer",
                 "args": [
                     {"name": "buffer", "type": "buffer"},
@@ -2823,16 +3030,32 @@
         ]
     },
     "queue work done callback": {
+        "category": "function pointer",
+        "args": [
+            {"name": "status", "type": "queue work done status"},
+            {"name": "userdata", "type": "void *"}
+        ]
+    },
+    "queue work done callback 2": {
         "category": "callback function",
         "args": [
             {"name": "status", "type": "queue work done status"}
         ]
     },
     "queue work done callback info": {
+        "category": "structure",
+        "extensible": "in",
+        "members": [
+            {"name": "mode", "type": "callback mode"},
+            {"name": "callback", "type": "queue work done callback"},
+            {"name": "userdata", "type": "void *"}
+        ]
+    },
+    "queue work done callback info 2": {
         "category": "callback info",
         "members": [
             {"name": "mode", "type": "callback mode"},
-            {"name": "callback", "type": "queue work done callback"}
+            {"name": "callback", "type": "queue work done callback 2"}
         ]
     },
     "queue work done status": {
@@ -2842,7 +3065,8 @@
             {"value": 1, "name": "success"},
             {"value": 2, "name": "instance dropped"},
             {"value": 3, "name": "error"},
-            {"value": 4, "name": "unknown"}
+            {"value": 4, "name": "unknown"},
+            {"value": 5, "name": "device lost"}
         ]
     },
 
@@ -3472,12 +3696,30 @@
         "methods": [
             {
                 "name": "get compilation info",
+                "args": [
+                    {"name": "callback", "type": "compilation info callback"},
+                    {"name": "userdata", "type": "void *"}
+                ]
+            },
+            {
+                "name": "get compilation info f",
+                "_comment": "TODO(crbug.com/dawn/2021): This is dawn/emscripten-only until we rename it to replace the old API. See bug for details.",
+                "tags": ["dawn", "emscripten"],
                 "returns": "future",
                 "args": [
                     {"name": "callback info", "type": "compilation info callback info"}
                 ]
             },
             {
+                "name": "get compilation info 2",
+                "_comment": "TODO(crbug.com/dawn/2021): This is dawn/emscripten-only until we rename it to replace the old API. See bug for details.",
+                "tags": ["dawn", "emscripten"],
+                "returns": "future",
+                "args": [
+                    {"name": "callback info", "type": "compilation info callback info 2"}
+                ]
+            },
+            {
                 "name": "set label",
                 "returns": "void",
                 "args": [
diff --git a/src/dawn/dawn_wire.json b/src/dawn/dawn_wire.json
index cc67fcd..97b23ea 100644
--- a/src/dawn/dawn_wire.json
+++ b/src/dawn/dawn_wire.json
@@ -37,7 +37,8 @@
             { "name": "future", "type": "future" },
             { "name": "mode", "type": "map mode" },
             { "name": "offset", "type": "uint64_t"},
-            { "name": "size", "type": "uint64_t"}
+            { "name": "size", "type": "uint64_t"},
+            { "name": "userdata count", "type": "uint8_t", "_comment": "TODO(crbug.com/dawn/2509): Remove this once Chromium overrides the correct functions in the proc table."}
         ],
         "buffer update mapped data": [
             { "name": "buffer id", "type": "ObjectId", "id_type": "buffer" },
@@ -81,7 +82,8 @@
         "queue on submitted work done": [
             { "name": "queue id", "type": "ObjectId", "id_type": "queue" },
             { "name": "event manager handle", "type": "ObjectHandle" },
-            { "name": "future", "type": "future" }
+            { "name": "future", "type": "future" },
+            { "name": "userdata count", "type": "uint8_t", "_comment": "TODO(crbug.com/dawn/2509): Remove this once Chromium overrides the correct functions in the proc table."}
         ],
         "queue write buffer": [
             {"name": "queue id", "type": "ObjectId", "id_type": "queue" },
@@ -130,8 +132,10 @@
         "buffer map async callback": [
             { "name": "event manager", "type": "ObjectHandle" },
             { "name": "future", "type": "future" },
-            { "name": "status", "type": "map async status" },
+            { "name": "status", "type": "buffer map async status" },
+            { "name": "status2", "type": "map async status" },
             { "name": "message", "type": "string view" },
+            { "name": "userdata count", "type": "uint8_t", "_comment": "TODO(crbug.com/dawn/2509): Remove this once Chromium overrides the correct functions in the proc table."},
             { "name": "read data update info length", "type": "uint64_t" },
             { "name": "read data update info", "type": "uint8_t", "annotation": "const*", "length": "read data update info length", "skip_serialize": true }
         ],
@@ -224,6 +228,8 @@
             "AdapterRequestDeviceF",
             "AdapterRequestDevice2",
             "BufferMapAsync",
+            "BufferMapAsyncF",
+            "BufferMapAsync2",
             "BufferGetConstMappedRange",
             "BufferGetMappedRange",
             "BufferGetMapState",
@@ -231,7 +237,11 @@
             "BufferGetUsage",
             "DeviceCreateBuffer",
             "DeviceCreateComputePipelineAsync",
+            "DeviceCreateComputePipelineAsyncF",
+            "DeviceCreateComputePipelineAsync2",
             "DeviceCreateRenderPipelineAsync",
+            "DeviceCreateRenderPipelineAsyncF",
+            "DeviceCreateRenderPipelineAsync2",
             "DeviceGetAdapter",
             "DeviceGetAdapterInfo",
             "DeviceGetFeatures",
@@ -249,9 +259,13 @@
             "InstanceRequestAdapterF",
             "InstanceRequestAdapter2",
             "ShaderModuleGetCompilationInfo",
+            "ShaderModuleGetCompilationInfoF",
+            "ShaderModuleGetCompilationInfo2",
             "QuerySetGetType",
             "QuerySetGetCount",
             "QueueOnSubmittedWorkDone",
+            "QueueOnSubmittedWorkDoneF",
+            "QueueOnSubmittedWorkDone2",
             "QueueWriteBuffer",
             "QueueWriteTexture",
             "SurfaceGetCapabilities",
diff --git a/src/dawn/native/Buffer.cpp b/src/dawn/native/Buffer.cpp
index 0b70008..c38e2a7 100644
--- a/src/dawn/native/Buffer.cpp
+++ b/src/dawn/native/Buffer.cpp
@@ -59,6 +59,34 @@
 namespace dawn::native {
 
 namespace {
+struct MapRequestTask : TrackTaskCallback {
+    MapRequestTask(dawn::platform::Platform* platform, Ref<BufferBase> buffer, MapRequestID id)
+        : TrackTaskCallback(platform), buffer(std::move(buffer)), id(id) {}
+    ~MapRequestTask() override = default;
+
+  private:
+    void FinishImpl() override {
+        {
+            // This is called from a callback, and no lock will be held by default. Hence, we need
+            // to lock the mutex now because mSerial might be changed by another thread.
+            auto deviceLock(buffer->GetDevice()->GetScopedLock());
+            DAWN_ASSERT(mSerial != kMaxExecutionSerial);
+            TRACE_EVENT1(mPlatform, General, "Buffer::TaskInFlight::Finished", "serial",
+                         uint64_t(mSerial));
+        }
+        buffer->CallbackOnMapRequestCompleted(id, WGPUBufferMapAsyncStatus_Success);
+    }
+    void HandleDeviceLossImpl() override {
+        buffer->CallbackOnMapRequestCompleted(id, WGPUBufferMapAsyncStatus_DeviceLost);
+    }
+    void HandleShutDownImpl() override {
+        buffer->CallbackOnMapRequestCompleted(id, WGPUBufferMapAsyncStatus_DestroyedBeforeCallback);
+    }
+
+    Ref<BufferBase> buffer;
+    MapRequestID id;
+};
+
 class ErrorBuffer final : public BufferBase {
   public:
     ErrorBuffer(DeviceBase* device, const BufferDescriptor* descriptor)
@@ -155,7 +183,106 @@
 
 }  // anonymous namespace
 
-struct BufferBase::MapAsyncEvent final : public EventManager::TrackedEvent {
+struct BufferBase::MapAsyncEvent : public EventManager::TrackedEvent {
+    MapAsyncEvent(wgpu::CallbackMode mode, QueueBase* queue, ExecutionSerial serial)
+        : TrackedEvent(mode, queue, serial) {}
+    // TODO(crbug.com/42241006): Note that currently this constructor is used for errors because a
+    // dropped device can result in failure when trying to get the queue. While using this fixes the
+    // problem, it causes an unintentional side-effect where it is possible to run into a
+    // UnsupportedMixedSource error on WaitAny even if we are only using a single device with
+    // MapAsync calls. This will be fixed once we correctly implement mixed sources.
+    explicit MapAsyncEvent(wgpu::CallbackMode mode)
+        : TrackedEvent(mode, SystemEvent::CreateSignaled()) {}
+
+    virtual void UnmapEarly(wgpu::BufferMapAsyncStatus status) = 0;
+};
+
+struct BufferBase::MapAsyncEvent1 final : public BufferBase::MapAsyncEvent {
+    // MapAsyncEvent stores a raw pointer to the buffer so that it can
+    // update the buffer's map state when it completes.
+    // If the map completes early (error, unmap, destroy), then the buffer
+    // is no longer needed and we store the early status instead.
+    // The raw pointer is safe because the early status is set to destroyed
+    // before the buffer is dropped.
+    // Note: this could be an atomic + spin lock on a sentinel enum if the mutex
+    // cost is high.
+    MutexProtected<std::variant<BufferBase*, wgpu::BufferMapAsyncStatus>> mBufferOrEarlyStatus;
+
+    WGPUBufferMapCallback mCallback;
+    raw_ptr<void> mUserdata;
+
+    // Create an event backed by the given queue execution serial.
+    MapAsyncEvent1(DeviceBase* device,
+                   BufferBase* buffer,
+                   const BufferMapCallbackInfo& callbackInfo,
+                   ExecutionSerial serial)
+        : MapAsyncEvent(callbackInfo.mode, device->GetQueue(), serial),
+          mBufferOrEarlyStatus(buffer),
+          mCallback(callbackInfo.callback),
+          mUserdata(callbackInfo.userdata) {
+        TRACE_EVENT_ASYNC_BEGIN0(device->GetPlatform(), General, "Buffer::APIMapAsync",
+                                 uint64_t(serial));
+    }
+
+    // Create an event that's ready at creation (for errors, etc.)
+    MapAsyncEvent1(DeviceBase* device,
+                   const BufferMapCallbackInfo& callbackInfo,
+                   wgpu::BufferMapAsyncStatus earlyStatus)
+        : MapAsyncEvent(callbackInfo.mode, device->GetQueue(), kBeginningOfGPUTime),
+          mBufferOrEarlyStatus(earlyStatus),
+          mCallback(callbackInfo.callback),
+          mUserdata(callbackInfo.userdata) {
+        TRACE_EVENT_ASYNC_BEGIN0(device->GetPlatform(), General, "Buffer::APIMapAsync",
+                                 uint64_t(kBeginningOfGPUTime));
+    }
+
+    ~MapAsyncEvent1() override { EnsureComplete(EventCompletionType::Shutdown); }
+
+    void Complete(EventCompletionType completionType) override {
+        if (const auto* queueAndSerial = std::get_if<QueueAndSerial>(&GetCompletionData())) {
+            TRACE_EVENT_ASYNC_END0(queueAndSerial->queue->GetDevice()->GetPlatform(), General,
+                                   "Buffer::APIMapAsync",
+                                   uint64_t(queueAndSerial->completionSerial));
+        }
+
+        if (completionType == EventCompletionType::Shutdown) {
+            mCallback(ToAPI(wgpu::BufferMapAsyncStatus::InstanceDropped), mUserdata);
+            return;
+        }
+
+        wgpu::BufferMapAsyncStatus status = wgpu::BufferMapAsyncStatus::Success;
+        Ref<MapAsyncEvent> pendingMapEvent;
+
+        // Lock the buffer / early status. This may race with UnmapEarly which occurs
+        // when the buffer is unmapped or destroyed.
+        mBufferOrEarlyStatus.Use([&](auto bufferOrEarlyStatus) {
+            if (auto* earlyStatus =
+                    std::get_if<wgpu::BufferMapAsyncStatus>(&*bufferOrEarlyStatus)) {
+                // Assign the early status, if it was set.
+                status = *earlyStatus;
+            } else if (auto** buffer = std::get_if<BufferBase*>(&*bufferOrEarlyStatus)) {
+                // Set the buffer state to Mapped if this pending map succeeded.
+                // TODO(crbug.com/dawn/831): in order to be thread safe, mutation of the
+                // state and pending map event needs to be atomic w.r.t. UnmapInternal.
+                DAWN_ASSERT((*buffer)->mState == BufferState::PendingMap);
+                (*buffer)->mState = BufferState::Mapped;
+
+                pendingMapEvent = std::move((*buffer)->mPendingMapEvent);
+            }
+        });
+        mCallback(ToAPI(status), mUserdata);
+    }
+
+    // Set the buffer early status because it was unmapped early due to Unmap or Destroy.
+    // This can race with Complete such that the early status is ignored, but this is OK
+    // because we will still unmap the buffer. It will be as-if the application called
+    // Unmap/Destroy just after the map event completed.
+    void UnmapEarly(wgpu::BufferMapAsyncStatus status) override {
+        mBufferOrEarlyStatus.Use([&](auto bufferOrEarlyStatus) { *bufferOrEarlyStatus = status; });
+    }
+};
+
+struct BufferBase::MapAsyncEvent2 final : public BufferBase::MapAsyncEvent {
     // MapAsyncEvent stores a raw pointer to the buffer so that it can update the buffer's map state
     // when it completes. If the map completes early (error, unmap, destroy), then the buffer is no
     // longer needed and we store the early status instead. The raw pointer is safe because the
@@ -167,18 +294,18 @@
     };
     MutexProtected<std::variant<BufferBase*, BufferErrorData>> mBufferOrError;
 
-    WGPUBufferMapCallback mCallback;
+    WGPUBufferMapCallback2 mCallback;
     raw_ptr<void> mUserdata1;
     raw_ptr<void> mUserdata2;
 
     // Create an event backed by the given queue execution serial.
-    MapAsyncEvent(DeviceBase* device,
-                  BufferBase* buffer,
-                  const WGPUBufferMapCallbackInfo& callbackInfo,
-                  ExecutionSerial serial)
-        : TrackedEvent(static_cast<wgpu::CallbackMode>(callbackInfo.mode),
-                       device->GetQueue(),
-                       serial),
+    MapAsyncEvent2(DeviceBase* device,
+                   BufferBase* buffer,
+                   const WGPUBufferMapCallbackInfo2& callbackInfo,
+                   ExecutionSerial serial)
+        : MapAsyncEvent(static_cast<wgpu::CallbackMode>(callbackInfo.mode),
+                        device->GetQueue(),
+                        serial),
           mBufferOrError(buffer),
           mCallback(callbackInfo.callback),
           mUserdata1(callbackInfo.userdata1),
@@ -188,13 +315,16 @@
     }
 
     // Create an event that's ready at creation (for errors, etc.)
-    MapAsyncEvent(DeviceBase* device,
-                  const WGPUBufferMapCallbackInfo& callbackInfo,
-                  const std::string& message,
-                  WGPUMapAsyncStatus status)
-        : TrackedEvent(static_cast<wgpu::CallbackMode>(callbackInfo.mode),
-                       SystemEvent::CreateSignaled()),
-          mBufferOrError(BufferErrorData{status, message}),
+    MapAsyncEvent2(DeviceBase* device,
+                   const WGPUBufferMapCallbackInfo2& callbackInfo,
+                   const std::string& message,
+                   WGPUBufferMapAsyncStatus status)
+        : MapAsyncEvent(static_cast<wgpu::CallbackMode>(callbackInfo.mode)),
+          mBufferOrError(BufferErrorData{
+              status == WGPUBufferMapAsyncStatus_ValidationError ? WGPUMapAsyncStatus_Error
+              : status == WGPUBufferMapAsyncStatus_DeviceLost    ? WGPUMapAsyncStatus_Aborted
+                                                                 : WGPUMapAsyncStatus_Unknown,
+              message}),
           mCallback(callbackInfo.callback),
           mUserdata1(callbackInfo.userdata1),
           mUserdata2(callbackInfo.userdata2) {
@@ -202,7 +332,7 @@
                                  uint64_t(kBeginningOfGPUTime));
     }
 
-    ~MapAsyncEvent() override { EnsureComplete(EventCompletionType::Shutdown); }
+    ~MapAsyncEvent2() override { EnsureComplete(EventCompletionType::Shutdown); }
 
     void Complete(EventCompletionType completionType) override {
         if (const auto* queueAndSerial = std::get_if<QueueAndSerial>(&GetCompletionData())) {
@@ -255,9 +385,21 @@
     // This can race with Complete such that the early status is ignored, but this is OK
     // because we will still unmap the buffer. It will be as-if the application called
     // Unmap/Destroy just after the map event completed.
-    void UnmapEarly(WGPUMapAsyncStatus status, std::string_view message) {
+    void UnmapEarly(wgpu::BufferMapAsyncStatus status) override {
+        auto StatusToMessage = [](wgpu::BufferMapAsyncStatus status) {
+            switch (status) {
+                case wgpu::BufferMapAsyncStatus::DeviceLost:
+                    return "Device was lost.";
+                case wgpu::BufferMapAsyncStatus::DestroyedBeforeCallback:
+                    return "Buffer was destroyed before mapping was resolved.";
+                case wgpu::BufferMapAsyncStatus::UnmappedBeforeCallback:
+                    return "Buffer was unmapped before mapping was resolved.";
+                default:
+                    DAWN_UNREACHABLE();
+            }
+        };
         mBufferOrError.Use([&](auto bufferOrError) {
-            *bufferOrError = BufferErrorData{status, std::string(message)};
+            *bufferOrError = BufferErrorData{WGPUMapAsyncStatus_Aborted, StatusToMessage(status)};
         });
     }
 };
@@ -368,14 +510,12 @@
     //   is implicitly destroyed. This case is thread-safe because there are no
     //   other threads using the buffer since there are no other live refs.
     if (mState == BufferState::Mapped || mState == BufferState::PendingMap) {
-        UnmapInternal(WGPUMapAsyncStatus_Aborted,
-                      "Buffer was destroyed before mapping was resolved.");
+        UnmapInternal(WGPUBufferMapAsyncStatus_DestroyedBeforeCallback);
     } else if (mState == BufferState::MappedAtCreation) {
         if (mStagingBuffer != nullptr) {
             mStagingBuffer = nullptr;
         } else if (mSize != 0) {
-            UnmapInternal(WGPUMapAsyncStatus_Aborted,
-                          "Buffer was destroyed before mapping was resolved.");
+            UnmapInternal(WGPUBufferMapAsyncStatus_DestroyedBeforeCallback);
         }
     }
 
@@ -529,10 +669,151 @@
     DAWN_UNREACHABLE();
 }
 
-Future BufferBase::APIMapAsync(wgpu::MapMode mode,
-                               size_t offset,
-                               size_t size,
-                               const WGPUBufferMapCallbackInfo& callbackInfo) {
+std::function<void()> BufferBase::PrepareMappingCallback(MapRequestID mapID,
+                                                         WGPUBufferMapAsyncStatus status) {
+    DAWN_ASSERT(!IsError());
+
+    if (mMapCallback != nullptr && mapID == mLastMapID) {
+        auto callback = std::move(mMapCallback);
+        void* userdata = std::move(mMapUserdata);
+        WGPUBufferMapAsyncStatus actualStatus;
+        if (GetDevice()->IsLost()) {
+            actualStatus = WGPUBufferMapAsyncStatus_DeviceLost;
+        } else {
+            actualStatus = status;
+        }
+
+        // Tag the callback as fired before firing it, otherwise it could fire a second time if
+        // for example buffer.Unmap() is called before the MapRequestTask completes.
+        mMapCallback = nullptr;
+        mMapUserdata = nullptr;
+
+        return std::bind(callback, actualStatus, userdata);
+    }
+
+    return [] {};
+}
+
+void BufferBase::APIMapAsync(wgpu::MapMode mode,
+                             size_t offset,
+                             size_t size,
+                             WGPUBufferMapCallback callback,
+                             void* userdata) {
+    GetInstance()->EmitDeprecationWarning(
+        "Old MapAsync APIs are deprecated. If using C please pass a CallbackInfo "
+        "struct that has two userdatas. Otherwise, if using C++, please use templated helpers.");
+
+    // Check for an existing pending map first because it just
+    // rejects the callback and doesn't produce a validation error.
+    if (mState == BufferState::PendingMap) {
+        if (callback) {
+            GetDevice()->GetCallbackTaskManager()->AddCallbackTask(
+                callback, WGPUBufferMapAsyncStatus_MappingAlreadyPending, userdata);
+        }
+        return;
+    }
+
+    // Handle the defaulting of size required by WebGPU, even if in webgpu_cpp.h it is not
+    // possible to default the function argument (because there is the callback later in the
+    // argument list)
+    if ((size == wgpu::kWholeMapSize) && (offset <= mSize)) {
+        size = mSize - offset;
+    }
+
+    WGPUBufferMapAsyncStatus status;
+    if (GetDevice()->ConsumedError(ValidateMapAsync(mode, offset, size, &status),
+                                   "calling %s.MapAsync(%s, %u, %u, ...).", this, mode, offset,
+                                   size)) {
+        if (callback) {
+            GetDevice()->GetCallbackTaskManager()->AddCallbackTask(callback, status, userdata);
+        }
+        return;
+    }
+    DAWN_ASSERT(!IsError());
+
+    mLastMapID++;
+    mMapMode = mode;
+    mMapOffset = offset;
+    mMapSize = size;
+    mMapCallback = callback;
+    mMapUserdata = userdata;
+    mState = BufferState::PendingMap;
+
+    if (GetDevice()->ConsumedError(MapAsyncImpl(mode, offset, size))) {
+        GetDevice()->GetCallbackTaskManager()->AddCallbackTask(
+            PrepareMappingCallback(mLastMapID, WGPUBufferMapAsyncStatus_DeviceLost));
+        return;
+    }
+    std::unique_ptr<MapRequestTask> request =
+        std::make_unique<MapRequestTask>(GetDevice()->GetPlatform(), this, mLastMapID);
+    TRACE_EVENT1(GetDevice()->GetPlatform(), General, "Buffer::APIMapAsync", "serial",
+                 uint64_t(mLastUsageSerial));
+    GetDevice()->GetQueue()->TrackTask(std::move(request), mLastUsageSerial);
+}
+
+Future BufferBase::APIMapAsyncF(wgpu::MapMode mode,
+                                size_t offset,
+                                size_t size,
+                                const BufferMapCallbackInfo& callbackInfo) {
+    GetInstance()->EmitDeprecationWarning(
+        "Old MapAsync APIs are deprecated. If using C please pass a CallbackInfo "
+        "struct that has two userdatas. Otherwise, if using C++, please use templated helpers.");
+
+    // TODO(crbug.com/dawn/2052): Once we always return a future, change this to log to the instance
+    // (note, not raise a validation error to the device) and return the null future.
+    DAWN_ASSERT(callbackInfo.nextInChain == nullptr);
+
+    Ref<EventManager::TrackedEvent> event;
+    std::optional<wgpu::BufferMapAsyncStatus> earlyStatus;
+    {
+        // TODO(crbug.com/dawn/831) Manually acquire device lock instead of relying on code-gen for
+        // re-entrancy.
+        auto deviceLock(GetDevice()->GetScopedLock());
+
+        // Handle the defaulting of size required by WebGPU, even if in webgpu_cpp.h it is not
+        // possible to default the function argument (because there is the callback later in the
+        // argument list)
+        if ((size == wgpu::kWholeMapSize) && (offset <= mSize)) {
+            size = mSize - offset;
+        }
+
+        earlyStatus = [&]() -> std::optional<wgpu::BufferMapAsyncStatus> {
+            if (mState == BufferState::PendingMap) {
+                return wgpu::BufferMapAsyncStatus::MappingAlreadyPending;
+            }
+            WGPUBufferMapAsyncStatus status;
+            if (GetDevice()->ConsumedError(ValidateMapAsync(mode, offset, size, &status),
+                                           "calling %s.MapAsync(%s, %u, %u, ...).", this, mode,
+                                           offset, size)) {
+                return static_cast<wgpu::BufferMapAsyncStatus>(status);
+            }
+            if (GetDevice()->ConsumedError(MapAsyncImpl(mode, offset, size))) {
+                return wgpu::BufferMapAsyncStatus::DeviceLost;
+            }
+            return std::nullopt;
+        }();
+
+        if (earlyStatus) {
+            event = AcquireRef(new MapAsyncEvent1(GetDevice(), callbackInfo, *earlyStatus));
+        } else {
+            mMapMode = mode;
+            mMapOffset = offset;
+            mMapSize = size;
+            mState = BufferState::PendingMap;
+            mPendingMapEvent =
+                AcquireRef(new MapAsyncEvent1(GetDevice(), this, callbackInfo, mLastUsageSerial));
+            event = mPendingMapEvent;
+        }
+    }
+
+    FutureID futureID = GetInstance()->GetEventManager()->TrackEvent(std::move(event));
+    return {futureID};
+}
+
+Future BufferBase::APIMapAsync2(wgpu::MapMode mode,
+                                size_t offset,
+                                size_t size,
+                                const WGPUBufferMapCallbackInfo2& callbackInfo) {
     // TODO(crbug.com/dawn/2052): Once we always return a future, change this to log to the instance
     // (note, not raise a validation error to the device) and return the null future.
     DAWN_ASSERT(callbackInfo.nextInChain == nullptr);
@@ -550,7 +831,7 @@
             size = mSize - offset;
         }
 
-        WGPUMapAsyncStatus status = WGPUMapAsyncStatus_Error;
+        WGPUBufferMapAsyncStatus status = WGPUBufferMapAsyncStatus_ValidationError;
         MaybeError maybeError = [&]() -> MaybeError {
             DAWN_INVALID_IF(mState == BufferState::PendingMap,
                             "%s already has an outstanding map pending.", this);
@@ -562,7 +843,7 @@
         if (maybeError.IsError()) {
             auto error = maybeError.AcquireError();
             event = AcquireRef(
-                new MapAsyncEvent(GetDevice(), callbackInfo, error->GetMessage(), status));
+                new MapAsyncEvent2(GetDevice(), callbackInfo, error->GetMessage(), status));
             [[maybe_unused]] bool hadError = GetDevice()->ConsumedError(
                 std::move(error), "calling %s.MapAsync(%s, %u, %u, ...).", this, mode, offset,
                 size);
@@ -572,7 +853,7 @@
             mMapSize = size;
             mState = BufferState::PendingMap;
             mPendingMapEvent =
-                AcquireRef(new MapAsyncEvent(GetDevice(), this, callbackInfo, mLastUsageSerial));
+                AcquireRef(new MapAsyncEvent2(GetDevice(), this, callbackInfo, mLastUsageSerial));
             event = mPendingMapEvent;
         }
     }
@@ -640,18 +921,23 @@
     if (mState == BufferState::MappedAtCreation && mStagingBuffer != nullptr) {
         DAWN_TRY(CopyFromStagingBuffer());
     }
-    UnmapInternal(WGPUMapAsyncStatus_Aborted, "Buffer was unmapped before mapping was resolved.");
+    UnmapInternal(WGPUBufferMapAsyncStatus_UnmappedBeforeCallback);
     return {};
 }
 
-void BufferBase::UnmapInternal(WGPUMapAsyncStatus status, std::string_view message) {
+void BufferBase::UnmapInternal(WGPUBufferMapAsyncStatus callbackStatus) {
     // Unmaps resources on the backend.
     if (mState == BufferState::PendingMap) {
         // TODO(crbug.com/dawn/831): in order to be thread safe, mutation of the
         // state and pending map event needs to be atomic w.r.t. MapAsyncEvent::Complete.
         Ref<MapAsyncEvent> pendingMapEvent = std::move(mPendingMapEvent);
-        pendingMapEvent->UnmapEarly(status, message);
-        GetInstance()->GetEventManager()->SetFutureReady(pendingMapEvent.Get());
+        if (pendingMapEvent != nullptr) {
+            pendingMapEvent->UnmapEarly(static_cast<wgpu::BufferMapAsyncStatus>(callbackStatus));
+            GetInstance()->GetEventManager()->SetFutureReady(pendingMapEvent.Get());
+        } else {
+            GetDevice()->GetCallbackTaskManager()->AddCallbackTask(
+                PrepareMappingCallback(mLastMapID, callbackStatus));
+        }
         UnmapImpl();
     } else if (mState == BufferState::Mapped) {
         UnmapImpl();
@@ -667,11 +953,11 @@
 MaybeError BufferBase::ValidateMapAsync(wgpu::MapMode mode,
                                         size_t offset,
                                         size_t size,
-                                        WGPUMapAsyncStatus* status) const {
-    *status = WGPUMapAsyncStatus_Aborted;
+                                        WGPUBufferMapAsyncStatus* status) const {
+    *status = WGPUBufferMapAsyncStatus_DeviceLost;
     DAWN_TRY(GetDevice()->ValidateIsAlive());
 
-    *status = WGPUMapAsyncStatus_Error;
+    *status = WGPUBufferMapAsyncStatus_ValidationError;
     DAWN_TRY(GetDevice()->ValidateObject(this));
 
     DAWN_INVALID_IF(uint64_t(offset) > mSize,
@@ -716,7 +1002,7 @@
                         wgpu::BufferUsage::MapWrite);
     }
 
-    *status = WGPUMapAsyncStatus_Success;
+    *status = WGPUBufferMapAsyncStatus_Success;
     return {};
 }
 
@@ -775,6 +1061,22 @@
     return {};
 }
 
+void BufferBase::CallbackOnMapRequestCompleted(MapRequestID mapID,
+                                               WGPUBufferMapAsyncStatus status) {
+    {
+        // This is called from a callback, and no lock will be held by default. Hence, we need to
+        // lock the mutex now because this will modify the buffer's states.
+        auto deviceLock(GetDevice()->GetScopedLock());
+        if (mapID == mLastMapID && status == WGPUBufferMapAsyncStatus_Success &&
+            mState == BufferState::PendingMap) {
+            mState = BufferState::Mapped;
+        }
+    }
+
+    auto cb = PrepareMappingCallback(mapID, status);
+    cb();
+}
+
 bool BufferBase::NeedsInitialization() const {
     return !mIsDataInitialized && GetDevice()->IsToggleEnabled(Toggle::LazyClearResourceOnFirstUse);
 }
diff --git a/src/dawn/native/Buffer.h b/src/dawn/native/Buffer.h
index cc7d3d6..7f130e6 100644
--- a/src/dawn/native/Buffer.h
+++ b/src/dawn/native/Buffer.h
@@ -95,6 +95,7 @@
     wgpu::BufferUsage GetUsage() const;
 
     MaybeError MapAtCreation();
+    void CallbackOnMapRequestCompleted(MapRequestID mapID, WGPUBufferMapAsyncStatus status);
 
     MaybeError ValidateCanUseOnQueueNow() const;
 
@@ -118,10 +119,19 @@
     void DumpMemoryStatistics(dawn::native::MemoryDump* dump, const char* prefix) const;
 
     // Dawn API
-    Future APIMapAsync(wgpu::MapMode mode,
-                       size_t offset,
-                       size_t size,
-                       const WGPUBufferMapCallbackInfo& callbackInfo);
+    void APIMapAsync(wgpu::MapMode mode,
+                     size_t offset,
+                     size_t size,
+                     WGPUBufferMapCallback callback,
+                     void* userdata);
+    Future APIMapAsyncF(wgpu::MapMode mode,
+                        size_t offset,
+                        size_t size,
+                        const BufferMapCallbackInfo& callbackInfo);
+    Future APIMapAsync2(wgpu::MapMode mode,
+                        size_t offset,
+                        size_t size,
+                        const WGPUBufferMapCallbackInfo2& callbackInfo);
     void* APIGetMappedRange(size_t offset, size_t size);
     const void* APIGetConstMappedRange(size_t offset, size_t size);
     void APIUnmap();
@@ -145,6 +155,9 @@
     ExecutionSerial mLastUsageSerial = ExecutionSerial(0);
 
   private:
+    std::function<void()> PrepareMappingCallback(MapRequestID mapID,
+                                                 WGPUBufferMapAsyncStatus status);
+
     virtual MaybeError MapAtCreationImpl() = 0;
     virtual MaybeError MapAsyncImpl(wgpu::MapMode mode, size_t offset, size_t size) = 0;
     virtual void UnmapImpl() = 0;
@@ -155,10 +168,10 @@
     MaybeError ValidateMapAsync(wgpu::MapMode mode,
                                 size_t offset,
                                 size_t size,
-                                WGPUMapAsyncStatus* status) const;
+                                WGPUBufferMapAsyncStatus* status) const;
     MaybeError ValidateUnmap() const;
     bool CanGetMappedRange(bool writable, size_t offset, size_t size) const;
-    void UnmapInternal(WGPUMapAsyncStatus status, std::string_view message);
+    void UnmapInternal(WGPUBufferMapAsyncStatus callbackStatus);
 
     const uint64_t mSize = 0;
     const wgpu::BufferUsage mUsage = wgpu::BufferUsage::None;
@@ -174,11 +187,16 @@
     // i.e. buffer->mStagingBuffer->mStagingBuffer... is not possible.
     Ref<BufferBase> mStagingBuffer;
 
+    WGPUBufferMapCallback mMapCallback = nullptr;
+    raw_ptr<void> mMapUserdata = nullptr;
+    MapRequestID mLastMapID = MapRequestID(0);
     wgpu::MapMode mMapMode = wgpu::MapMode::None;
     size_t mMapOffset = 0;
     size_t mMapSize = 0;
 
     struct MapAsyncEvent;
+    struct MapAsyncEvent1;
+    struct MapAsyncEvent2;
     Ref<MapAsyncEvent> mPendingMapEvent;
 };
 
diff --git a/src/dawn/native/CreatePipelineAsyncEvent.cpp b/src/dawn/native/CreatePipelineAsyncEvent.cpp
index 4b79627..854c7ff 100644
--- a/src/dawn/native/CreatePipelineAsyncEvent.cpp
+++ b/src/dawn/native/CreatePipelineAsyncEvent.cpp
@@ -54,15 +54,15 @@
 template <>
 const char* CreatePipelineAsyncEvent<
     ComputePipelineBase,
-    WGPUCreateComputePipelineAsyncCallbackInfo>::kDawnHistogramMetricsSuccess =
+    WGPUCreateComputePipelineAsyncCallbackInfo2>::kDawnHistogramMetricsSuccess =
     "CreateComputePipelineSuccess";
 template <>
 const char*
     CreatePipelineAsyncEvent<ComputePipelineBase,
-                             WGPUCreateComputePipelineAsyncCallbackInfo>::kDawnHistogramMetricsUS =
+                             WGPUCreateComputePipelineAsyncCallbackInfo2>::kDawnHistogramMetricsUS =
         "CreateComputePipelineUS";
 template <>
-void CreatePipelineAsyncEvent<ComputePipelineBase, WGPUCreateComputePipelineAsyncCallbackInfo>::
+void CreatePipelineAsyncEvent<ComputePipelineBase, WGPUCreateComputePipelineAsyncCallbackInfo2>::
     AddOrGetCachedPipeline() {
     DeviceBase* device = mPipeline->GetDevice();
     auto deviceLock(device->GetScopedLock());
@@ -74,16 +74,16 @@
 template <>
 const char* CreatePipelineAsyncEvent<
     RenderPipelineBase,
-    WGPUCreateRenderPipelineAsyncCallbackInfo>::kDawnHistogramMetricsSuccess =
+    WGPUCreateRenderPipelineAsyncCallbackInfo2>::kDawnHistogramMetricsSuccess =
     "CreateRenderPipelineSuccess";
 template <>
 const char*
     CreatePipelineAsyncEvent<RenderPipelineBase,
-                             WGPUCreateRenderPipelineAsyncCallbackInfo>::kDawnHistogramMetricsUS =
+                             WGPUCreateRenderPipelineAsyncCallbackInfo2>::kDawnHistogramMetricsUS =
         "CreateRenderPipelineUS";
 template <>
-void CreatePipelineAsyncEvent<RenderPipelineBase,
-                              WGPUCreateRenderPipelineAsyncCallbackInfo>::AddOrGetCachedPipeline() {
+void CreatePipelineAsyncEvent<RenderPipelineBase, WGPUCreateRenderPipelineAsyncCallbackInfo2>::
+    AddOrGetCachedPipeline() {
     DeviceBase* device = mPipeline->GetDevice();
     auto deviceLock(device->GetScopedLock());
     if (device->GetState() == DeviceBase::State::Alive) {
@@ -234,8 +234,8 @@
 }
 
 template class CreatePipelineAsyncEvent<ComputePipelineBase,
-                                        WGPUCreateComputePipelineAsyncCallbackInfo>;
+                                        WGPUCreateComputePipelineAsyncCallbackInfo2>;
 template class CreatePipelineAsyncEvent<RenderPipelineBase,
-                                        WGPUCreateRenderPipelineAsyncCallbackInfo>;
+                                        WGPUCreateRenderPipelineAsyncCallbackInfo2>;
 
 }  // namespace dawn::native
diff --git a/src/dawn/native/CreatePipelineAsyncEvent.h b/src/dawn/native/CreatePipelineAsyncEvent.h
index b2fefa6..e2ae039 100644
--- a/src/dawn/native/CreatePipelineAsyncEvent.h
+++ b/src/dawn/native/CreatePipelineAsyncEvent.h
@@ -103,9 +103,9 @@
 };
 
 using CreateComputePipelineAsyncEvent =
-    CreatePipelineAsyncEvent<ComputePipelineBase, WGPUCreateComputePipelineAsyncCallbackInfo>;
+    CreatePipelineAsyncEvent<ComputePipelineBase, WGPUCreateComputePipelineAsyncCallbackInfo2>;
 using CreateRenderPipelineAsyncEvent =
-    CreatePipelineAsyncEvent<RenderPipelineBase, WGPUCreateRenderPipelineAsyncCallbackInfo>;
+    CreatePipelineAsyncEvent<RenderPipelineBase, WGPUCreateRenderPipelineAsyncCallbackInfo2>;
 
 }  // namespace dawn::native
 
diff --git a/src/dawn/native/Device.cpp b/src/dawn/native/Device.cpp
index 8c7209f..316b6b1 100644
--- a/src/dawn/native/Device.cpp
+++ b/src/dawn/native/Device.cpp
@@ -852,21 +852,45 @@
     mErrorScopeStack->Push(filter);
 }
 
-Future DeviceBase::APIPopErrorScope(const WGPUPopErrorScopeCallbackInfo& callbackInfo) {
+void DeviceBase::APIPopErrorScope(wgpu::ErrorCallback callback, void* userdata) {
+    static wgpu::ErrorCallback kDefaultCallback = [](WGPUErrorType, WGPUStringView, void*) {};
+
+    APIPopErrorScope2({nullptr, WGPUCallbackMode_AllowProcessEvents,
+                       [](WGPUPopErrorScopeStatus, WGPUErrorType type, WGPUStringView message,
+                          void* callback, void* userdata) {
+                           auto cb = reinterpret_cast<wgpu::ErrorCallback>(callback);
+                           cb(type, message, userdata);
+                       },
+                       reinterpret_cast<void*>(callback != nullptr ? callback : kDefaultCallback),
+                       userdata});
+}
+
+Future DeviceBase::APIPopErrorScopeF(const PopErrorScopeCallbackInfo& callbackInfo) {
+    return APIPopErrorScope2({ToAPI(callbackInfo.nextInChain), ToAPI(callbackInfo.mode),
+                              [](WGPUPopErrorScopeStatus status, WGPUErrorType type,
+                                 WGPUStringView message, void* callback, void* userdata) {
+                                  auto cb = reinterpret_cast<WGPUPopErrorScopeCallback>(callback);
+                                  cb(status, type, message, userdata);
+                              },
+                              reinterpret_cast<void*>(callbackInfo.callback),
+                              callbackInfo.userdata});
+}
+
+Future DeviceBase::APIPopErrorScope2(const WGPUPopErrorScopeCallbackInfo2& callbackInfo) {
     struct PopErrorScopeEvent final : public EventManager::TrackedEvent {
-        WGPUPopErrorScopeCallback mCallback;
+        WGPUPopErrorScopeCallback2 mCallback;
         raw_ptr<void> mUserdata1;
         raw_ptr<void> mUserdata2;
         std::optional<ErrorScope> mScope;
 
-        PopErrorScopeEvent(const WGPUPopErrorScopeCallbackInfo& callbackInfo,
+        PopErrorScopeEvent(const WGPUPopErrorScopeCallbackInfo2& callbackInfo,
                            std::optional<ErrorScope>&& scope)
             : TrackedEvent(static_cast<wgpu::CallbackMode>(callbackInfo.mode),
                            TrackedEvent::Completed{}),
               mCallback(callbackInfo.callback),
               mUserdata1(callbackInfo.userdata1),
               mUserdata2(callbackInfo.userdata2),
-              mScope(std::move(scope)) {}
+              mScope(scope) {}
 
         ~PopErrorScopeEvent() override { EnsureComplete(EventCompletionType::Shutdown); }
 
@@ -1326,9 +1350,42 @@
     }
     return ReturnToAPI(std::move(result));
 }
-Future DeviceBase::APICreateComputePipelineAsync(
+void DeviceBase::APICreateComputePipelineAsync(const ComputePipelineDescriptor* descriptor,
+                                               WGPUCreateComputePipelineAsyncCallback callback,
+                                               void* userdata) {
+    GetInstance()->EmitDeprecationWarning(
+        "Old CreateComputePipelineAsync APIs are deprecated. If using C please pass a CallbackInfo "
+        "struct that has two userdatas. Otherwise, if using C++, please use templated helpers.");
+
+    APICreateComputePipelineAsync2(
+        descriptor, {nullptr, WGPUCallbackMode_AllowProcessEvents,
+                     [](WGPUCreatePipelineAsyncStatus status, WGPUComputePipeline pipeline,
+                        WGPUStringView message, void* callback, void* userdata) {
+                         auto cb =
+                             reinterpret_cast<WGPUCreateComputePipelineAsyncCallback>(callback);
+                         cb(status, pipeline, message, userdata);
+                     },
+                     reinterpret_cast<void*>(callback), userdata});
+}
+Future DeviceBase::APICreateComputePipelineAsyncF(
     const ComputePipelineDescriptor* descriptor,
-    const WGPUCreateComputePipelineAsyncCallbackInfo& callbackInfo) {
+    const CreateComputePipelineAsyncCallbackInfo& callbackInfo) {
+    GetInstance()->EmitDeprecationWarning(
+        "Old CreateComputePipelineAsync APIs are deprecated. If using C please pass a CallbackInfo "
+        "struct that has two userdatas. Otherwise, if using C++, please use templated helpers.");
+    return APICreateComputePipelineAsync2(
+        descriptor, {ToAPI(callbackInfo.nextInChain), ToAPI(callbackInfo.mode),
+                     [](WGPUCreatePipelineAsyncStatus status, WGPUComputePipeline pipeline,
+                        WGPUStringView message, void* callback, void* userdata) {
+                         auto cb =
+                             reinterpret_cast<WGPUCreateComputePipelineAsyncCallback>(callback);
+                         cb(status, pipeline, message, userdata);
+                     },
+                     reinterpret_cast<void*>(callbackInfo.callback), callbackInfo.userdata});
+}
+Future DeviceBase::APICreateComputePipelineAsync2(
+    const ComputePipelineDescriptor* descriptor,
+    const WGPUCreateComputePipelineAsyncCallbackInfo2& callbackInfo) {
     utils::TraceLabel label = utils::GetLabelForTrace(descriptor->label);
     TRACE_EVENT1(GetPlatform(), General, "DeviceBase::APICreateComputePipelineAsync", "label",
                  label.label);
@@ -1395,9 +1452,42 @@
     }
     return ReturnToAPI(std::move(result));
 }
-Future DeviceBase::APICreateRenderPipelineAsync(
+void DeviceBase::APICreateRenderPipelineAsync(const RenderPipelineDescriptor* descriptor,
+                                              WGPUCreateRenderPipelineAsyncCallback callback,
+                                              void* userdata) {
+    GetInstance()->EmitDeprecationWarning(
+        "Old CreateRenderPipelineAsync APIs are deprecated. If using C please pass a CallbackInfo "
+        "struct that has two userdatas. Otherwise, if using C++, please use templated helpers.");
+
+    APICreateRenderPipelineAsync2(
+        descriptor, {nullptr, WGPUCallbackMode_AllowProcessEvents,
+                     [](WGPUCreatePipelineAsyncStatus status, WGPURenderPipeline pipeline,
+                        WGPUStringView message, void* callback, void* userdata) {
+                         auto cb =
+                             reinterpret_cast<WGPUCreateRenderPipelineAsyncCallback>(callback);
+                         cb(status, pipeline, message, userdata);
+                     },
+                     reinterpret_cast<void*>(callback), userdata});
+}
+Future DeviceBase::APICreateRenderPipelineAsyncF(
     const RenderPipelineDescriptor* descriptor,
-    const WGPUCreateRenderPipelineAsyncCallbackInfo& callbackInfo) {
+    const CreateRenderPipelineAsyncCallbackInfo& callbackInfo) {
+    GetInstance()->EmitDeprecationWarning(
+        "Old CreateRenderPipelineAsync APIs are deprecated. If using C please pass a CallbackInfo "
+        "struct that has two userdatas. Otherwise, if using C++, please use templated helpers.");
+    return APICreateRenderPipelineAsync2(
+        descriptor, {ToAPI(callbackInfo.nextInChain), ToAPI(callbackInfo.mode),
+                     [](WGPUCreatePipelineAsyncStatus status, WGPURenderPipeline pipeline,
+                        WGPUStringView message, void* callback, void* userdata) {
+                         auto cb =
+                             reinterpret_cast<WGPUCreateRenderPipelineAsyncCallback>(callback);
+                         cb(status, pipeline, message, userdata);
+                     },
+                     reinterpret_cast<void*>(callbackInfo.callback), callbackInfo.userdata});
+}
+Future DeviceBase::APICreateRenderPipelineAsync2(
+    const RenderPipelineDescriptor* descriptor,
+    const WGPUCreateRenderPipelineAsyncCallbackInfo2& callbackInfo) {
     utils::TraceLabel label = utils::GetLabelForTrace(descriptor->label);
     TRACE_EVENT1(GetPlatform(), General, "DeviceBase::APICreateRenderPipelineAsync", "label",
                  label.label);
diff --git a/src/dawn/native/Device.h b/src/dawn/native/Device.h
index b6b6d8d..f0275b1 100644
--- a/src/dawn/native/Device.h
+++ b/src/dawn/native/Device.h
@@ -242,12 +242,23 @@
     ComputePipelineBase* APICreateComputePipeline(const ComputePipelineDescriptor* descriptor);
     PipelineLayoutBase* APICreatePipelineLayout(const PipelineLayoutDescriptor* descriptor);
     QuerySetBase* APICreateQuerySet(const QuerySetDescriptor* descriptor);
-    Future APICreateComputePipelineAsync(
+    void APICreateComputePipelineAsync(const ComputePipelineDescriptor* descriptor,
+                                       WGPUCreateComputePipelineAsyncCallback callback,
+                                       void* userdata);
+    Future APICreateComputePipelineAsyncF(
         const ComputePipelineDescriptor* descriptor,
-        const WGPUCreateComputePipelineAsyncCallbackInfo& callbackInfo);
-    Future APICreateRenderPipelineAsync(
+        const CreateComputePipelineAsyncCallbackInfo& callbackInfo);
+    Future APICreateComputePipelineAsync2(
+        const ComputePipelineDescriptor* descriptor,
+        const WGPUCreateComputePipelineAsyncCallbackInfo2& callbackInfo);
+    void APICreateRenderPipelineAsync(const RenderPipelineDescriptor* descriptor,
+                                      WGPUCreateRenderPipelineAsyncCallback callback,
+                                      void* userdata);
+    Future APICreateRenderPipelineAsyncF(const RenderPipelineDescriptor* descriptor,
+                                         const CreateRenderPipelineAsyncCallbackInfo& callbackInfo);
+    Future APICreateRenderPipelineAsync2(
         const RenderPipelineDescriptor* descriptor,
-        const WGPUCreateRenderPipelineAsyncCallbackInfo& callbackInfo);
+        const WGPUCreateRenderPipelineAsyncCallbackInfo2& callbackInfo);
     RenderBundleEncoder* APICreateRenderBundleEncoder(
         const RenderBundleEncoderDescriptor* descriptor);
     RenderPipelineBase* APICreateRenderPipeline(const RenderPipelineDescriptor* descriptor);
@@ -289,7 +300,9 @@
     void APISetUncapturedErrorCallback(wgpu::ErrorCallback callback, void* userdata);
     void APISetLoggingCallback(wgpu::LoggingCallback callback, void* userdata);
     void APIPushErrorScope(wgpu::ErrorFilter filter);
-    Future APIPopErrorScope(const WGPUPopErrorScopeCallbackInfo& callbackInfo);
+    void APIPopErrorScope(wgpu::ErrorCallback callback, void* userdata);
+    Future APIPopErrorScopeF(const PopErrorScopeCallbackInfo& callbackInfo);
+    Future APIPopErrorScope2(const WGPUPopErrorScopeCallbackInfo2& callbackInfo);
 
     MaybeError ValidateIsAlive() const;
 
diff --git a/src/dawn/native/Queue.cpp b/src/dawn/native/Queue.cpp
index 5f47ca8..cc8ef36 100644
--- a/src/dawn/native/Queue.cpp
+++ b/src/dawn/native/Queue.cpp
@@ -155,6 +155,33 @@
     return uploadHandle;
 }
 
+struct SubmittedWorkDone : TrackTaskCallback {
+    SubmittedWorkDone(dawn::platform::Platform* platform,
+                      WGPUQueueWorkDoneCallback callback,
+                      void* userdata)
+        : TrackTaskCallback(platform), mCallback(callback), mUserdata(userdata) {}
+    ~SubmittedWorkDone() override = default;
+
+  private:
+    void FinishImpl() override {
+        DAWN_ASSERT(mCallback != nullptr);
+        DAWN_ASSERT(mSerial != kMaxExecutionSerial);
+        TRACE_EVENT1(mPlatform, General, "Queue::SubmittedWorkDone::Finished", "serial",
+                     uint64_t(mSerial));
+        mCallback(WGPUQueueWorkDoneStatus_Success, mUserdata.ExtractAsDangling());
+        mCallback = nullptr;
+    }
+    void HandleDeviceLossImpl() override {
+        DAWN_ASSERT(mCallback != nullptr);
+        mCallback(WGPUQueueWorkDoneStatus_DeviceLost, mUserdata.ExtractAsDangling());
+        mCallback = nullptr;
+    }
+    void HandleShutDownImpl() override { HandleDeviceLossImpl(); }
+
+    WGPUQueueWorkDoneCallback mCallback = nullptr;
+    raw_ptr<void> mUserdata;
+};
+
 class ErrorQueue : public QueueBase {
   public:
     explicit ErrorQueue(DeviceBase* device, StringView label)
@@ -230,15 +257,55 @@
         ityp::span<uint32_t, CommandBufferBase* const>(commands, commandCount));
 }
 
-Future QueueBase::APIOnSubmittedWorkDone(const WGPUQueueWorkDoneCallbackInfo& callbackInfo) {
+void QueueBase::APIOnSubmittedWorkDone(WGPUQueueWorkDoneCallback callback, void* userdata) {
+    GetInstance()->EmitDeprecationWarning(
+        "Old OnSubmittedWorkDone APIs are deprecated. If using C please pass a CallbackInfo "
+        "struct that has two userdatas. Otherwise, if using C++, please use templated helpers.");
+
+    // The error status depends on the type of error so we let the validation function choose it
+    wgpu::QueueWorkDoneStatus status;
+    if (GetDevice()->ConsumedError(ValidateOnSubmittedWorkDone(&status))) {
+        GetDevice()->GetCallbackTaskManager()->AddCallbackTask(
+            [callback, status, userdata] { callback(ToAPI(status), userdata); });
+        return;
+    }
+
+    std::unique_ptr<SubmittedWorkDone> task =
+        std::make_unique<SubmittedWorkDone>(GetDevice()->GetPlatform(), callback, userdata);
+
+    // Technically we only need to wait for previously submitted work but OnSubmittedWorkDone is
+    // also used to make sure ALL queue work is finished in tests, so we also wait for pending
+    // commands (this is non-observable outside of tests so it's ok to do deviate a bit from the
+    // spec).
+    TrackTaskAfterEventualFlush(std::move(task));
+
+    TRACE_EVENT1(GetDevice()->GetPlatform(), General, "Queue::APIOnSubmittedWorkDone", "serial",
+                 uint64_t(GetPendingCommandSerial()));
+}
+
+Future QueueBase::APIOnSubmittedWorkDoneF(const QueueWorkDoneCallbackInfo& callbackInfo) {
+    GetInstance()->EmitDeprecationWarning(
+        "Old OnSubmittedWorkDone APIs are deprecated. If using C please pass a CallbackInfo "
+        "struct that has two userdatas. Otherwise, if using C++, please use templated helpers.");
+
+    return APIOnSubmittedWorkDone2(
+        {ToAPI(callbackInfo.nextInChain), ToAPI(callbackInfo.mode),
+         [](WGPUQueueWorkDoneStatus status, void* callback, void* userdata) {
+             auto cb = reinterpret_cast<WGPUQueueWorkDoneCallback>(callback);
+             cb(status, userdata);
+         },
+         reinterpret_cast<void*>(callbackInfo.callback), callbackInfo.userdata});
+}
+
+Future QueueBase::APIOnSubmittedWorkDone2(const WGPUQueueWorkDoneCallbackInfo2& callbackInfo) {
     struct WorkDoneEvent final : public EventManager::TrackedEvent {
         std::optional<WGPUQueueWorkDoneStatus> mEarlyStatus;
-        WGPUQueueWorkDoneCallback mCallback;
+        WGPUQueueWorkDoneCallback2 mCallback;
         raw_ptr<void> mUserdata1;
         raw_ptr<void> mUserdata2;
 
         // Create an event backed by the given queue execution serial.
-        WorkDoneEvent(const WGPUQueueWorkDoneCallbackInfo& callbackInfo,
+        WorkDoneEvent(const WGPUQueueWorkDoneCallbackInfo2& callbackInfo,
                       QueueBase* queue,
                       ExecutionSerial serial)
             : TrackedEvent(static_cast<wgpu::CallbackMode>(callbackInfo.mode), queue, serial),
@@ -247,7 +314,7 @@
               mUserdata2(callbackInfo.userdata2) {}
 
         // Create an event that's ready at creation (for errors, etc.)
-        WorkDoneEvent(const WGPUQueueWorkDoneCallbackInfo& callbackInfo,
+        WorkDoneEvent(const WGPUQueueWorkDoneCallbackInfo2& callbackInfo,
                       QueueBase* queue,
                       wgpu::QueueWorkDoneStatus earlyStatus)
             : TrackedEvent(static_cast<wgpu::CallbackMode>(callbackInfo.mode),
@@ -283,8 +350,15 @@
         // re-entrancy.
         auto deviceLock(GetDevice()->GetScopedLock());
 
-        wgpu::QueueWorkDoneStatus validationEarlyStatus = wgpu::QueueWorkDoneStatus::Success;
+        wgpu::QueueWorkDoneStatus validationEarlyStatus;
         if (GetDevice()->ConsumedError(ValidateOnSubmittedWorkDone(&validationEarlyStatus))) {
+            // TODO(crbug.com/dawn/2021): This is here to pretend that things succeed when the
+            // device is lost. When the old OnSubmittedWorkDone is removed then we can update
+            // ValidateOnSubmittedWorkDone to just return the correct thing here.
+            if (validationEarlyStatus == wgpu::QueueWorkDoneStatus::DeviceLost) {
+                validationEarlyStatus = wgpu::QueueWorkDoneStatus::Success;
+            }
+
             // Note: if the callback is spontaneous, it'll get called in here.
             event = AcquireRef(new WorkDoneEvent(callbackInfo, this, validationEarlyStatus));
         } else {
@@ -567,6 +641,7 @@
 }
 
 MaybeError QueueBase::ValidateOnSubmittedWorkDone(wgpu::QueueWorkDoneStatus* status) const {
+    *status = wgpu::QueueWorkDoneStatus::DeviceLost;
     DAWN_TRY(GetDevice()->ValidateIsAlive());
 
     *status = wgpu::QueueWorkDoneStatus::Error;
diff --git a/src/dawn/native/Queue.h b/src/dawn/native/Queue.h
index 71dcdcd..36ec006 100644
--- a/src/dawn/native/Queue.h
+++ b/src/dawn/native/Queue.h
@@ -73,7 +73,9 @@
 
     // Dawn API
     void APISubmit(uint32_t commandCount, CommandBufferBase* const* commands);
-    Future APIOnSubmittedWorkDone(const WGPUQueueWorkDoneCallbackInfo& callbackInfo);
+    void APIOnSubmittedWorkDone(WGPUQueueWorkDoneCallback callback, void* userdata);
+    Future APIOnSubmittedWorkDoneF(const QueueWorkDoneCallbackInfo& callbackInfo);
+    Future APIOnSubmittedWorkDone2(const WGPUQueueWorkDoneCallbackInfo2& callbackInfo);
     void APIWriteBuffer(BufferBase* buffer, uint64_t bufferOffset, const void* data, size_t size);
     void APIWriteTexture(const ImageCopyTexture* destination,
                          const void* data,
diff --git a/src/dawn/native/ShaderModule.cpp b/src/dawn/native/ShaderModule.cpp
index 9d47730..97b3129 100644
--- a/src/dawn/native/ShaderModule.cpp
+++ b/src/dawn/native/ShaderModule.cpp
@@ -1584,17 +1584,58 @@
     return mTintData.Use([&](auto tintData) { return tintData->tintProgramRecreateCount; });
 }
 
-Future ShaderModuleBase::APIGetCompilationInfo(
-    const WGPUCompilationInfoCallbackInfo& callbackInfo) {
+namespace {
+
+void DefaultGetCompilationInfoCallback(WGPUCompilationInfoRequestStatus status,
+                                       const WGPUCompilationInfo* compilationInfo,
+                                       void* callback,
+                                       void* userdata) {
+    if (callback == nullptr) {
+        DAWN_ASSERT(userdata == nullptr);
+        return;
+    }
+    auto cb = reinterpret_cast<WGPUCompilationInfoCallback>(callback);
+    cb(status, compilationInfo, userdata);
+}
+
+}  // anonymous namespace
+
+void ShaderModuleBase::APIGetCompilationInfo(wgpu::CompilationInfoCallback callback,
+                                             void* userdata) {
+    GetInstance()->EmitDeprecationWarning(
+        "Old GetCompilationInfo APIs are deprecated. If using C please pass a CallbackInfo struct "
+        "that has two userdatas. Otherwise, if using C++, please use templated helpers.");
+
+    if (callback == nullptr) {
+        return;
+    }
+    APIGetCompilationInfo2({nullptr, WGPUCallbackMode_AllowSpontaneous,
+                            &DefaultGetCompilationInfoCallback, reinterpret_cast<void*>(callback),
+                            userdata});
+}
+
+Future ShaderModuleBase::APIGetCompilationInfoF(const CompilationInfoCallbackInfo& callbackInfo) {
+    GetInstance()->EmitDeprecationWarning(
+        "Old GetCompilationInfo APIs are deprecated. If using C please pass a CallbackInfo struct "
+        "that has two userdatas. Otherwise, if using C++, please use templated helpers.");
+
+    return APIGetCompilationInfo2({ToAPI(callbackInfo.nextInChain), ToAPI(callbackInfo.mode),
+                                   &DefaultGetCompilationInfoCallback,
+                                   reinterpret_cast<void*>(callbackInfo.callback),
+                                   callbackInfo.userdata});
+}
+
+Future ShaderModuleBase::APIGetCompilationInfo2(
+    const WGPUCompilationInfoCallbackInfo2& callbackInfo) {
     struct CompilationInfoEvent final : public EventManager::TrackedEvent {
-        WGPUCompilationInfoCallback mCallback;
+        WGPUCompilationInfoCallback2 mCallback;
         raw_ptr<void> mUserdata1;
         raw_ptr<void> mUserdata2;
         // Need to keep a Ref of the compilation messages in case the ShaderModule goes away before
         // the callback happens.
         Ref<ShaderModuleBase> mShaderModule;
 
-        CompilationInfoEvent(const WGPUCompilationInfoCallbackInfo& callbackInfo,
+        CompilationInfoEvent(const WGPUCompilationInfoCallbackInfo2& callbackInfo,
                              Ref<ShaderModuleBase> shaderModule)
             : TrackedEvent(static_cast<wgpu::CallbackMode>(callbackInfo.mode),
                            TrackedEvent::Completed{}),
diff --git a/src/dawn/native/ShaderModule.h b/src/dawn/native/ShaderModule.h
index 9ae9217..3d371c8 100644
--- a/src/dawn/native/ShaderModule.h
+++ b/src/dawn/native/ShaderModule.h
@@ -348,7 +348,9 @@
     Ref<TintProgram> GetTintProgramForTesting() const;
     int GetTintProgramRecreateCountForTesting() const;
 
-    Future APIGetCompilationInfo(const WGPUCompilationInfoCallbackInfo& callbackInfo);
+    void APIGetCompilationInfo(wgpu::CompilationInfoCallback callback, void* userdata);
+    Future APIGetCompilationInfoF(const CompilationInfoCallbackInfo& callbackInfo);
+    Future APIGetCompilationInfo2(const WGPUCompilationInfoCallbackInfo2& callbackInfo);
 
     void InjectCompilationMessages(std::unique_ptr<OwnedCompilationMessages> compilationMessages);
     OwnedCompilationMessages* GetCompilationMessages() const;
diff --git a/src/dawn/tests/end2end/BufferTests.cpp b/src/dawn/tests/end2end/BufferTests.cpp
index bfa76f1..5f79c9a 100644
--- a/src/dawn/tests/end2end/BufferTests.cpp
+++ b/src/dawn/tests/end2end/BufferTests.cpp
@@ -48,7 +48,7 @@
 using testing::MockCppCallback;
 using testing::StrictMock;
 
-using MockMapAsyncCallback = MockCppCallback<wgpu::BufferMapCallback<void>*>;
+using MockMapAsyncCallback = MockCppCallback<wgpu::BufferMapCallback2<void>*>;
 using FutureCallbackMode = wgpu::CallbackMode;
 
 DAWN_TEST_PARAM_STRUCT(BufferMappingTestParams, FutureCallbackMode);
@@ -66,7 +66,7 @@
                          wgpu::MapMode mode,
                          size_t offset,
                          size_t size,
-                         wgpu::BufferMapCallback<> cb = nullptr) {
+                         wgpu::BufferMapCallback2<> cb = nullptr) {
         wgpu::Future future;
 
         if (cb) {
diff --git a/src/dawn/tests/end2end/DeviceLostTests.cpp b/src/dawn/tests/end2end/DeviceLostTests.cpp
index 6d0b5f7..ddb6eb3 100644
--- a/src/dawn/tests/end2end/DeviceLostTests.cpp
+++ b/src/dawn/tests/end2end/DeviceLostTests.cpp
@@ -44,8 +44,10 @@
 using testing::HasSubstr;
 using testing::MockCppCallback;
 
-using MockMapAsyncCallback = MockCppCallback<wgpu::BufferMapCallback<void>*>;
-using MockQueueWorkDoneCallback = MockCppCallback<wgpu::QueueWorkDoneCallback<void>*>;
+using MockMapAsyncCallback = MockCppCallback<void (*)(wgpu::MapAsyncStatus, wgpu::StringView)>;
+using MockQueueWorkDoneCallback = MockCppCallback<void (*)(wgpu::QueueWorkDoneStatus)>;
+
+static const int fakeUserData = 0;
 
 class DeviceLostTest : public DawnTest {
   protected:
@@ -61,6 +63,11 @@
         }
     }
 
+    static void MapFailCallback(WGPUBufferMapAsyncStatus status, void* userdata) {
+        EXPECT_EQ(WGPUBufferMapAsyncStatus_DeviceLost, status);
+        EXPECT_EQ(&fakeUserData, userdata);
+    }
+
     template <typename T>
     void ExpectObjectIsError(const T& object) {
         EXPECT_TRUE(dawn::native::CheckIsErrorForTesting(object.Get()));
diff --git a/src/dawn/tests/unittests/native/AllowedErrorTests.cpp b/src/dawn/tests/unittests/native/AllowedErrorTests.cpp
index b9ac911..dbbc373 100644
--- a/src/dawn/tests/unittests/native/AllowedErrorTests.cpp
+++ b/src/dawn/tests/unittests/native/AllowedErrorTests.cpp
@@ -59,9 +59,9 @@
 using ::testing::Test;
 
 using MockComputePipelineAsyncCallback =
-    MockCppCallback<wgpu::CreateComputePipelineAsyncCallback<void>*>;
+    MockCppCallback<wgpu::CreateComputePipelineAsyncCallback2<void>*>;
 using MockRenderPipelineAsyncCallback =
-    MockCppCallback<wgpu::CreateRenderPipelineAsyncCallback<void>*>;
+    MockCppCallback<wgpu::CreateRenderPipelineAsyncCallback2<void>*>;
 
 static constexpr char kOomErrorMessage[] = "Out of memory error";
 static constexpr char kInternalErrorMessage[] = "Internal error";
diff --git a/src/dawn/tests/unittests/wire/WireBufferMappingTests.cpp b/src/dawn/tests/unittests/wire/WireBufferMappingTests.cpp
index f11b748..d301be3 100644
--- a/src/dawn/tests/unittests/wire/WireBufferMappingTests.cpp
+++ b/src/dawn/tests/unittests/wire/WireBufferMappingTests.cpp
@@ -69,7 +69,7 @@
 DAWN_WIRE_FUTURE_TEST_PARAM_STRUCT(WireBufferParam, MapMode);
 
 using WireBufferMappingTestBase =
-    WireFutureTestWithParams<wgpu::BufferMapCallback<void>*, WireBufferParam>;
+    WireFutureTestWithParams<wgpu::BufferMapCallback2<void>*, WireBufferParam>;
 
 // General mapping tests that either do not care about the specific mapping mode, or apply to both.
 class WireBufferMappingTests : public WireBufferMappingTestBase {
@@ -146,10 +146,10 @@
 
         uint32_t bufferContent = 31337;
         EXPECT_CALL(
-            api, OnBufferMapAsync(apiBuffer, static_cast<WGPUMapMode>(mapMode), 0, kBufferSize, _))
+            api, OnBufferMapAsync2(apiBuffer, static_cast<WGPUMapMode>(mapMode), 0, kBufferSize, _))
             .WillOnce(InvokeWithoutArgs([&] {
-                api.CallBufferMapAsyncCallback(apiBuffer, WGPUMapAsyncStatus_Success,
-                                               kEmptyOutputStringView);
+                api.CallBufferMapAsync2Callback(apiBuffer, WGPUMapAsyncStatus_Success,
+                                                kEmptyOutputStringView);
             }));
         ExpectMappedRangeCall(kBufferSize, &bufferContent);
         addExpectations();
@@ -188,10 +188,10 @@
         MapAsync(mapMode, 0, kBufferSize);
 
         EXPECT_CALL(
-            api, OnBufferMapAsync(apiBuffer, static_cast<WGPUMapMode>(mapMode), 0, kBufferSize, _))
+            api, OnBufferMapAsync2(apiBuffer, static_cast<WGPUMapMode>(mapMode), 0, kBufferSize, _))
             .WillOnce(InvokeWithoutArgs([&] {
-                api.CallBufferMapAsyncCallback(apiBuffer, WGPUMapAsyncStatus_Error,
-                                               ToOutputStringView("Validation error"));
+                api.CallBufferMapAsync2Callback(apiBuffer, WGPUMapAsyncStatus_Error,
+                                                ToOutputStringView("Validation error"));
             }));
 
         // Ensure that the server had a chance to respond if relevant.
@@ -232,10 +232,10 @@
 
         uint32_t bufferContent = 31337;
         EXPECT_CALL(
-            api, OnBufferMapAsync(apiBuffer, static_cast<WGPUMapMode>(mapMode), 0, kBufferSize, _))
+            api, OnBufferMapAsync2(apiBuffer, static_cast<WGPUMapMode>(mapMode), 0, kBufferSize, _))
             .WillOnce(InvokeWithoutArgs([&] {
-                api.CallBufferMapAsyncCallback(apiBuffer, WGPUMapAsyncStatus_Success,
-                                               kEmptyOutputStringView);
+                api.CallBufferMapAsync2Callback(apiBuffer, WGPUMapAsyncStatus_Success,
+                                                kEmptyOutputStringView);
             }));
         ExpectMappedRangeCall(kBufferSize, &bufferContent);
 
@@ -275,10 +275,10 @@
     MapAsync(mapMode, 0, kBufferSize);
 
     EXPECT_CALL(api,
-                OnBufferMapAsync(apiBuffer, static_cast<WGPUMapMode>(mapMode), 0, kBufferSize, _))
+                OnBufferMapAsync2(apiBuffer, static_cast<WGPUMapMode>(mapMode), 0, kBufferSize, _))
         .WillOnce(InvokeWithoutArgs([&] {
-            api.CallBufferMapAsyncCallback(apiBuffer, WGPUMapAsyncStatus_Error,
-                                           ToOutputStringView("Validation error"));
+            api.CallBufferMapAsync2Callback(apiBuffer, WGPUMapAsyncStatus_Error,
+                                            ToOutputStringView("Validation error"));
         }));
 
     FlushClient();
@@ -403,10 +403,10 @@
     MapAsync(wgpu::MapMode::Read, 0, kBufferSize);
 
     uint32_t bufferContent = 31337;
-    EXPECT_CALL(api, OnBufferMapAsync(apiBuffer, WGPUMapMode_Read, 0, kBufferSize, _))
+    EXPECT_CALL(api, OnBufferMapAsync2(apiBuffer, WGPUMapMode_Read, 0, kBufferSize, _))
         .WillOnce(InvokeWithoutArgs([&] {
-            api.CallBufferMapAsyncCallback(apiBuffer, WGPUMapAsyncStatus_Success,
-                                           kEmptyOutputStringView);
+            api.CallBufferMapAsync2Callback(apiBuffer, WGPUMapAsyncStatus_Success,
+                                            kEmptyOutputStringView);
         }));
     EXPECT_CALL(api, BufferGetConstMappedRange(apiBuffer, 0, kBufferSize))
         .WillOnce(Return(&bufferContent));
@@ -433,10 +433,10 @@
     MapAsync(wgpu::MapMode::Read, 0, kBufferSize);
 
     uint32_t bufferContent = 31337;
-    EXPECT_CALL(api, OnBufferMapAsync(apiBuffer, WGPUMapMode_Read, 0, kBufferSize, _))
+    EXPECT_CALL(api, OnBufferMapAsync2(apiBuffer, WGPUMapMode_Read, 0, kBufferSize, _))
         .WillOnce(InvokeWithoutArgs([&] {
-            api.CallBufferMapAsyncCallback(apiBuffer, WGPUMapAsyncStatus_Success,
-                                           kEmptyOutputStringView);
+            api.CallBufferMapAsync2Callback(apiBuffer, WGPUMapAsyncStatus_Success,
+                                            kEmptyOutputStringView);
         }));
     EXPECT_CALL(api, BufferGetConstMappedRange(apiBuffer, 0, kBufferSize))
         .WillOnce(Return(&bufferContent));
@@ -452,10 +452,10 @@
     // Map failure while the buffer is already mapped
     MapAsync(wgpu::MapMode::Read, 0, kBufferSize);
 
-    EXPECT_CALL(api, OnBufferMapAsync(apiBuffer, WGPUMapMode_Read, 0, kBufferSize, _))
+    EXPECT_CALL(api, OnBufferMapAsync2(apiBuffer, WGPUMapMode_Read, 0, kBufferSize, _))
         .WillOnce(InvokeWithoutArgs([&] {
-            api.CallBufferMapAsyncCallback(apiBuffer, WGPUMapAsyncStatus_Error,
-                                           ToOutputStringView("Already mapped"));
+            api.CallBufferMapAsync2Callback(apiBuffer, WGPUMapAsyncStatus_Error,
+                                            ToOutputStringView("Already mapped"));
         }));
 
     FlushClient();
@@ -489,10 +489,10 @@
     uint32_t serverBufferContent = 31337;
     uint32_t updatedContent = 4242;
 
-    EXPECT_CALL(api, OnBufferMapAsync(apiBuffer, WGPUMapMode_Write, 0, kBufferSize, _))
+    EXPECT_CALL(api, OnBufferMapAsync2(apiBuffer, WGPUMapMode_Write, 0, kBufferSize, _))
         .WillOnce(InvokeWithoutArgs([&] {
-            api.CallBufferMapAsyncCallback(apiBuffer, WGPUMapAsyncStatus_Success,
-                                           kEmptyOutputStringView);
+            api.CallBufferMapAsync2Callback(apiBuffer, WGPUMapAsyncStatus_Success,
+                                            kEmptyOutputStringView);
         }));
     EXPECT_CALL(api, BufferGetMappedRange(apiBuffer, 0, kBufferSize))
         .WillOnce(Return(&serverBufferContent));
@@ -527,10 +527,10 @@
     MapAsync(wgpu::MapMode::Write, 0, kBufferSize);
 
     uint32_t bufferContent = 31337;
-    EXPECT_CALL(api, OnBufferMapAsync(apiBuffer, WGPUMapMode_Write, 0, kBufferSize, _))
+    EXPECT_CALL(api, OnBufferMapAsync2(apiBuffer, WGPUMapMode_Write, 0, kBufferSize, _))
         .WillOnce(InvokeWithoutArgs([&] {
-            api.CallBufferMapAsyncCallback(apiBuffer, WGPUMapAsyncStatus_Success,
-                                           kEmptyOutputStringView);
+            api.CallBufferMapAsync2Callback(apiBuffer, WGPUMapAsyncStatus_Success,
+                                            kEmptyOutputStringView);
         }));
     EXPECT_CALL(api, BufferGetMappedRange(apiBuffer, 0, kBufferSize))
         .WillOnce(Return(&bufferContent));
@@ -545,10 +545,10 @@
 
     // Map failure while the buffer is already mapped
     MapAsync(wgpu::MapMode::Write, 0, kBufferSize);
-    EXPECT_CALL(api, OnBufferMapAsync(apiBuffer, WGPUMapMode_Write, 0, kBufferSize, _))
+    EXPECT_CALL(api, OnBufferMapAsync2(apiBuffer, WGPUMapMode_Write, 0, kBufferSize, _))
         .WillOnce(InvokeWithoutArgs([&] {
-            api.CallBufferMapAsyncCallback(apiBuffer, WGPUMapAsyncStatus_Error,
-                                           ToOutputStringView("Already mapped"));
+            api.CallBufferMapAsync2Callback(apiBuffer, WGPUMapAsyncStatus_Error,
+                                            ToOutputStringView("Already mapped"));
         }));
 
     FlushClient();
@@ -630,10 +630,10 @@
 
     MapAsync(wgpu::MapMode::Write, 0, kBufferSize);
 
-    EXPECT_CALL(api, OnBufferMapAsync(apiBuffer, WGPUMapMode_Write, 0, kBufferSize, _))
+    EXPECT_CALL(api, OnBufferMapAsync2(apiBuffer, WGPUMapMode_Write, 0, kBufferSize, _))
         .WillOnce(InvokeWithoutArgs([&] {
-            api.CallBufferMapAsyncCallback(apiBuffer, WGPUMapAsyncStatus_Success,
-                                           kEmptyOutputStringView);
+            api.CallBufferMapAsync2Callback(apiBuffer, WGPUMapAsyncStatus_Success,
+                                            kEmptyOutputStringView);
         }));
     EXPECT_CALL(api, BufferGetMappedRange(apiBuffer, 0, kBufferSize))
         .WillOnce(Return(&apiBufferData));
@@ -664,10 +664,10 @@
 
     // Note that the validation logic is entirely on the native side so we inject the validation
     // error here and flush the server response to mock the expected behavior.
-    EXPECT_CALL(api, OnBufferMapAsync(apiBuffer, WGPUMapMode_Write, 0, kBufferSize, _))
+    EXPECT_CALL(api, OnBufferMapAsync2(apiBuffer, WGPUMapMode_Write, 0, kBufferSize, _))
         .WillOnce(InvokeWithoutArgs([&] {
-            api.CallBufferMapAsyncCallback(apiBuffer, WGPUMapAsyncStatus_Error,
-                                           ToOutputStringView("Already mapped"));
+            api.CallBufferMapAsync2Callback(apiBuffer, WGPUMapAsyncStatus_Error,
+                                            ToOutputStringView("Already mapped"));
         }));
 
     FlushClient();
@@ -735,10 +735,10 @@
 
     uint32_t bufferContent = 0;
     EXPECT_CALL(api,
-                OnBufferMapAsync(apiBuffer, static_cast<WGPUMapMode>(mapMode), 0, kBufferSize, _))
+                OnBufferMapAsync2(apiBuffer, static_cast<WGPUMapMode>(mapMode), 0, kBufferSize, _))
         .WillOnce(InvokeWithoutArgs([&] {
-            api.CallBufferMapAsyncCallback(apiBuffer, WGPUMapAsyncStatus_Success,
-                                           kEmptyOutputStringView);
+            api.CallBufferMapAsync2Callback(apiBuffer, WGPUMapAsyncStatus_Success,
+                                            kEmptyOutputStringView);
         }));
     ExpectMappedRangeCall(kBufferSize, &bufferContent);
 
@@ -771,10 +771,10 @@
     // Calls for the first successful map.
     uint32_t bufferContent = 0;
     EXPECT_CALL(api,
-                OnBufferMapAsync(apiBuffer, static_cast<WGPUMapMode>(mapMode), 0, kBufferSize, _))
+                OnBufferMapAsync2(apiBuffer, static_cast<WGPUMapMode>(mapMode), 0, kBufferSize, _))
         .WillOnce(InvokeWithoutArgs([&] {
-            api.CallBufferMapAsyncCallback(apiBuffer, WGPUMapAsyncStatus_Success,
-                                           kEmptyOutputStringView);
+            api.CallBufferMapAsync2Callback(apiBuffer, WGPUMapAsyncStatus_Success,
+                                            kEmptyOutputStringView);
         }));
     ExpectMappedRangeCall(kBufferSize, &bufferContent);
 
@@ -823,10 +823,10 @@
         ASSERT_EQ(buffer.GetMapState(), wgpu::BufferMapState::Unmapped);
 
         EXPECT_CALL(
-            api, OnBufferMapAsync(apiBuffer, static_cast<WGPUMapMode>(mapMode), 0, kBufferSize, _))
+            api, OnBufferMapAsync2(apiBuffer, static_cast<WGPUMapMode>(mapMode), 0, kBufferSize, _))
             .WillOnce(InvokeWithoutArgs([&] {
-                api.CallBufferMapAsyncCallback(apiBuffer, WGPUMapAsyncStatus_Success,
-                                               kEmptyOutputStringView);
+                api.CallBufferMapAsync2Callback(apiBuffer, WGPUMapAsyncStatus_Success,
+                                                kEmptyOutputStringView);
             }));
         ExpectMappedRangeCall(kBufferSize, &bufferContent);
         MapAsync(mapMode, 0, kBufferSize);
@@ -861,10 +861,10 @@
     // Server-side error case
     {
         EXPECT_CALL(
-            api, OnBufferMapAsync(apiBuffer, static_cast<WGPUMapMode>(mapMode), 0, kBufferSize, _))
+            api, OnBufferMapAsync2(apiBuffer, static_cast<WGPUMapMode>(mapMode), 0, kBufferSize, _))
             .WillOnce(InvokeWithoutArgs([&] {
-                api.CallBufferMapAsyncCallback(apiBuffer, WGPUMapAsyncStatus_Error,
-                                               ToOutputStringView("Error"));
+                api.CallBufferMapAsync2Callback(apiBuffer, WGPUMapAsyncStatus_Error,
+                                                ToOutputStringView("Error"));
             }));
 
         // Map state should initially be unmapped.
@@ -901,10 +901,10 @@
 
     uint32_t bufferContent = 0;
     EXPECT_CALL(api,
-                OnBufferMapAsync(apiBuffer, static_cast<WGPUMapMode>(mapMode), 0, kBufferSize, _))
+                OnBufferMapAsync2(apiBuffer, static_cast<WGPUMapMode>(mapMode), 0, kBufferSize, _))
         .WillOnce(InvokeWithoutArgs([&] {
-            api.CallBufferMapAsyncCallback(apiBuffer, WGPUMapAsyncStatus_Success,
-                                           kEmptyOutputStringView);
+            api.CallBufferMapAsync2Callback(apiBuffer, WGPUMapAsyncStatus_Success,
+                                            kEmptyOutputStringView);
         }));
     ExpectMappedRangeCall(kBufferSize, &bufferContent);
 
@@ -932,10 +932,10 @@
 
     uint32_t bufferContent = 0;
     EXPECT_CALL(api,
-                OnBufferMapAsync(apiBuffer, static_cast<WGPUMapMode>(mapMode), 0, kBufferSize, _))
+                OnBufferMapAsync2(apiBuffer, static_cast<WGPUMapMode>(mapMode), 0, kBufferSize, _))
         .WillOnce(InvokeWithoutArgs([&] {
-            api.CallBufferMapAsyncCallback(apiBuffer, WGPUMapAsyncStatus_Success,
-                                           kEmptyOutputStringView);
+            api.CallBufferMapAsync2Callback(apiBuffer, WGPUMapAsyncStatus_Success,
+                                            kEmptyOutputStringView);
         }));
     ExpectMappedRangeCall(kBufferSize, &bufferContent);
 
diff --git a/src/dawn/tests/unittests/wire/WireCreatePipelineAsyncTests.cpp b/src/dawn/tests/unittests/wire/WireCreatePipelineAsyncTests.cpp
index 9542443..396345c 100644
--- a/src/dawn/tests/unittests/wire/WireCreatePipelineAsyncTests.cpp
+++ b/src/dawn/tests/unittests/wire/WireCreatePipelineAsyncTests.cpp
@@ -51,7 +51,7 @@
 using testing::SizedString;
 
 using WireCreateComputePipelineAsyncTestBase =
-    WireFutureTest<wgpu::CreateComputePipelineAsyncCallback<void>*>;
+    WireFutureTest<wgpu::CreateComputePipelineAsyncCallback2<void>*>;
 class WireCreateComputePipelineAsyncTest : public WireCreateComputePipelineAsyncTestBase {
   protected:
     void CreateComputePipelineAsync(wgpu::ComputePipelineDescriptor const* desc) {
@@ -95,7 +95,7 @@
 };
 
 using WireCreateRenderPipelineAsyncTestBase =
-    WireFutureTest<wgpu::CreateRenderPipelineAsyncCallback<void>*>;
+    WireFutureTest<wgpu::CreateRenderPipelineAsyncCallback2<void>*>;
 class WireCreateRenderPipelineAsyncTest : public WireCreateRenderPipelineAsyncTestBase {
   protected:
     void CreateRenderPipelineAsync(wgpu::RenderPipelineDescriptor const* desc) {
@@ -149,11 +149,11 @@
 TEST_P(WireCreateComputePipelineAsyncTest, CreateSuccess) {
     CreateComputePipelineAsync(&mDescriptor);
 
-    EXPECT_CALL(api, OnDeviceCreateComputePipelineAsync(apiDevice, _, _))
+    EXPECT_CALL(api, OnDeviceCreateComputePipelineAsync2(apiDevice, _, _))
         .WillOnce(InvokeWithoutArgs([&] {
-            api.CallDeviceCreateComputePipelineAsyncCallback(apiDevice,
-                                                             WGPUCreatePipelineAsyncStatus_Success,
-                                                             apiPipeline, kEmptyOutputStringView);
+            api.CallDeviceCreateComputePipelineAsync2Callback(apiDevice,
+                                                              WGPUCreatePipelineAsyncStatus_Success,
+                                                              apiPipeline, kEmptyOutputStringView);
         }));
 
     FlushClient();
@@ -171,11 +171,11 @@
 TEST_P(WireCreateRenderPipelineAsyncTest, CreateSuccess) {
     CreateRenderPipelineAsync(&mDescriptor);
 
-    EXPECT_CALL(api, OnDeviceCreateRenderPipelineAsync(apiDevice, _, _))
+    EXPECT_CALL(api, OnDeviceCreateRenderPipelineAsync2(apiDevice, _, _))
         .WillOnce(InvokeWithoutArgs([&] {
-            api.CallDeviceCreateRenderPipelineAsyncCallback(apiDevice,
-                                                            WGPUCreatePipelineAsyncStatus_Success,
-                                                            apiPipeline, kEmptyOutputStringView);
+            api.CallDeviceCreateRenderPipelineAsync2Callback(apiDevice,
+                                                             WGPUCreatePipelineAsyncStatus_Success,
+                                                             apiPipeline, kEmptyOutputStringView);
         }));
 
     FlushClient();
@@ -193,9 +193,9 @@
 TEST_P(WireCreateComputePipelineAsyncTest, CreateError) {
     CreateComputePipelineAsync(&mDescriptor);
 
-    EXPECT_CALL(api, OnDeviceCreateComputePipelineAsync(apiDevice, _, _))
+    EXPECT_CALL(api, OnDeviceCreateComputePipelineAsync2(apiDevice, _, _))
         .WillOnce(InvokeWithoutArgs([&] {
-            api.CallDeviceCreateComputePipelineAsyncCallback(
+            api.CallDeviceCreateComputePipelineAsync2Callback(
                 apiDevice, WGPUCreatePipelineAsyncStatus_ValidationError, nullptr,
                 ToOutputStringView("Some error message"));
         }));
@@ -215,9 +215,9 @@
 TEST_P(WireCreateRenderPipelineAsyncTest, CreateError) {
     CreateRenderPipelineAsync(&mDescriptor);
 
-    EXPECT_CALL(api, OnDeviceCreateRenderPipelineAsync(apiDevice, _, _))
+    EXPECT_CALL(api, OnDeviceCreateRenderPipelineAsync2(apiDevice, _, _))
         .WillOnce(InvokeWithoutArgs([&] {
-            api.CallDeviceCreateRenderPipelineAsyncCallback(
+            api.CallDeviceCreateRenderPipelineAsync2Callback(
                 apiDevice, WGPUCreatePipelineAsyncStatus_ValidationError, nullptr,
                 ToOutputStringView("Some error message"));
         }));
@@ -238,11 +238,11 @@
 TEST_P(WireCreateComputePipelineAsyncTest, CreateThenDisconnect) {
     CreateComputePipelineAsync(&mDescriptor);
 
-    EXPECT_CALL(api, OnDeviceCreateComputePipelineAsync(apiDevice, _, _))
+    EXPECT_CALL(api, OnDeviceCreateComputePipelineAsync2(apiDevice, _, _))
         .WillOnce(InvokeWithoutArgs([&] {
-            api.CallDeviceCreateComputePipelineAsyncCallback(apiDevice,
-                                                             WGPUCreatePipelineAsyncStatus_Success,
-                                                             apiPipeline, kEmptyOutputStringView);
+            api.CallDeviceCreateComputePipelineAsync2Callback(apiDevice,
+                                                              WGPUCreatePipelineAsyncStatus_Success,
+                                                              apiPipeline, kEmptyOutputStringView);
         }));
 
     FlushClient();
@@ -260,11 +260,11 @@
 TEST_P(WireCreateRenderPipelineAsyncTest, CreateThenDisconnect) {
     CreateRenderPipelineAsync(&mDescriptor);
 
-    EXPECT_CALL(api, OnDeviceCreateRenderPipelineAsync(apiDevice, _, _))
+    EXPECT_CALL(api, OnDeviceCreateRenderPipelineAsync2(apiDevice, _, _))
         .WillOnce(InvokeWithoutArgs([&] {
-            api.CallDeviceCreateRenderPipelineAsyncCallback(apiDevice,
-                                                            WGPUCreatePipelineAsyncStatus_Success,
-                                                            apiPipeline, kEmptyOutputStringView);
+            api.CallDeviceCreateRenderPipelineAsync2Callback(apiDevice,
+                                                             WGPUCreatePipelineAsyncStatus_Success,
+                                                             apiPipeline, kEmptyOutputStringView);
         }));
 
     FlushClient();
diff --git a/src/dawn/tests/unittests/wire/WireErrorCallbackTests.cpp b/src/dawn/tests/unittests/wire/WireErrorCallbackTests.cpp
index eb6a692..4fc1c3d 100644
--- a/src/dawn/tests/unittests/wire/WireErrorCallbackTests.cpp
+++ b/src/dawn/tests/unittests/wire/WireErrorCallbackTests.cpp
@@ -126,7 +126,7 @@
     FlushServer();
 }
 
-using WirePopErrorScopeCallbackTestBase = WireFutureTest<wgpu::PopErrorScopeCallback<void>*>;
+using WirePopErrorScopeCallbackTestBase = WireFutureTest<wgpu::PopErrorScopeCallback2<void>*>;
 class WirePopErrorScopeCallbackTests : public WirePopErrorScopeCallbackTestBase {
   protected:
     void PopErrorScope() {
@@ -153,10 +153,10 @@
     for (const auto& [type, filter] : kErrorTypeAndFilters) {
         PushErrorScope(filter);
         PopErrorScope();
-        EXPECT_CALL(api, OnDevicePopErrorScope(apiDevice, _)).WillOnce([&] {
-            api.CallDevicePopErrorScopeCallback(apiDevice, WGPUPopErrorScopeStatus_Success,
-                                                static_cast<WGPUErrorType>(type),
-                                                ToOutputStringView("Some error message"));
+        EXPECT_CALL(api, OnDevicePopErrorScope2(apiDevice, _)).WillOnce([&] {
+            api.CallDevicePopErrorScope2Callback(apiDevice, WGPUPopErrorScopeStatus_Success,
+                                                 static_cast<WGPUErrorType>(type),
+                                                 ToOutputStringView("Some error message"));
         });
 
         FlushClient();
@@ -176,7 +176,7 @@
     PushErrorScope(wgpu::ErrorFilter::Validation);
 
     PopErrorScope();
-    EXPECT_CALL(api, OnDevicePopErrorScope(apiDevice, _)).Times(1);
+    EXPECT_CALL(api, OnDevicePopErrorScope2(apiDevice, _)).Times(1);
 
     FlushClient();
     FlushFutures();
@@ -198,10 +198,10 @@
     PushErrorScope(wgpu::ErrorFilter::Validation);
     PopErrorScope();
 
-    EXPECT_CALL(api, OnDevicePopErrorScope(apiDevice, _)).WillOnce(InvokeWithoutArgs([&] {
-        api.CallDevicePopErrorScopeCallback(apiDevice, WGPUPopErrorScopeStatus_Success,
-                                            WGPUErrorType_Validation,
-                                            ToOutputStringView("Some error message"));
+    EXPECT_CALL(api, OnDevicePopErrorScope2(apiDevice, _)).WillOnce(InvokeWithoutArgs([&] {
+        api.CallDevicePopErrorScope2Callback(apiDevice, WGPUPopErrorScopeStatus_Success,
+                                             WGPUErrorType_Validation,
+                                             ToOutputStringView("Some error message"));
     }));
 
     FlushClient();
@@ -219,10 +219,10 @@
 TEST_P(WirePopErrorScopeCallbackTests, EmptyStack) {
     PopErrorScope();
 
-    EXPECT_CALL(api, OnDevicePopErrorScope(apiDevice, _)).WillOnce(InvokeWithoutArgs([&] {
-        api.CallDevicePopErrorScopeCallback(apiDevice, WGPUPopErrorScopeStatus_Success,
-                                            WGPUErrorType_NoError,
-                                            ToOutputStringView("No error scopes to pop"));
+    EXPECT_CALL(api, OnDevicePopErrorScope2(apiDevice, _)).WillOnce(InvokeWithoutArgs([&] {
+        api.CallDevicePopErrorScope2Callback(apiDevice, WGPUPopErrorScopeStatus_Success,
+                                             WGPUErrorType_NoError,
+                                             ToOutputStringView("No error scopes to pop"));
     }));
 
     FlushClient();
diff --git a/src/dawn/tests/unittests/wire/WireMemoryTransferServiceTests.cpp b/src/dawn/tests/unittests/wire/WireMemoryTransferServiceTests.cpp
index b5b962b..d80b89b 100644
--- a/src/dawn/tests/unittests/wire/WireMemoryTransferServiceTests.cpp
+++ b/src/dawn/tests/unittests/wire/WireMemoryTransferServiceTests.cpp
@@ -340,10 +340,10 @@
 
         // Mode independent expectations.
         EXPECT_CALL(api,
-                    OnBufferMapAsync(apiBuffer, static_cast<WGPUMapMode>(mode), 0, kBufferSize, _))
+                    OnBufferMapAsync2(apiBuffer, static_cast<WGPUMapMode>(mode), 0, kBufferSize, _))
             .WillOnce(InvokeWithoutArgs([&] {
-                api.CallBufferMapAsyncCallback(apiBuffer, WGPUMapAsyncStatus_Success,
-                                               kEmptyOutputStringView);
+                api.CallBufferMapAsync2Callback(apiBuffer, WGPUMapAsyncStatus_Success,
+                                                kEmptyOutputStringView);
             }));
         EXPECT_CALL(mMapAsyncCb, Call(wgpu::MapAsyncStatus::Success, _)).Times(1);
 
@@ -471,7 +471,7 @@
     uint32_t mSerializeCreateInfo = kDataGenerator++;
     static constexpr size_t kDataSize = sizeof(uint32_t);
 
-    StrictMock<MockCppCallback<wgpu::BufferMapCallback<void>*>> mMapAsyncCb;
+    StrictMock<MockCppCallback<wgpu::BufferMapCallback2<void>*>> mMapAsyncCb;
 
     StrictMock<wire::server::MockMemoryTransferService> mServerMTS;
     StrictMock<wire::client::MockMemoryTransferService> mClientMTS;
@@ -614,10 +614,11 @@
                     mMapAsyncCb.Callback());
 
     // Make the server respond to the callback with an error.
-    EXPECT_CALL(api, OnBufferMapAsync(apiBuffer, static_cast<WGPUMapMode>(mode), 0, kBufferSize, _))
+    EXPECT_CALL(api,
+                OnBufferMapAsync2(apiBuffer, static_cast<WGPUMapMode>(mode), 0, kBufferSize, _))
         .WillOnce(InvokeWithoutArgs([&] {
-            api.CallBufferMapAsyncCallback(apiBuffer, WGPUMapAsyncStatus_Error,
-                                           ToOutputStringView("Validation error"));
+            api.CallBufferMapAsync2Callback(apiBuffer, WGPUMapAsyncStatus_Error,
+                                            ToOutputStringView("Validation error"));
         }));
     FlushClient();
 
@@ -657,10 +658,11 @@
     }
 
     // Set mode independent expectations for the map async call now.
-    EXPECT_CALL(api, OnBufferMapAsync(apiBuffer, static_cast<WGPUMapMode>(mode), 0, kBufferSize, _))
+    EXPECT_CALL(api,
+                OnBufferMapAsync2(apiBuffer, static_cast<WGPUMapMode>(mode), 0, kBufferSize, _))
         .WillOnce(InvokeWithoutArgs([&] {
-            api.CallBufferMapAsyncCallback(apiBuffer, WGPUMapAsyncStatus_Success,
-                                           kEmptyOutputStringView);
+            api.CallBufferMapAsync2Callback(apiBuffer, WGPUMapAsyncStatus_Success,
+                                            kEmptyOutputStringView);
         }));
 
     switch (mode) {
diff --git a/src/dawn/tests/unittests/wire/WireQueueTests.cpp b/src/dawn/tests/unittests/wire/WireQueueTests.cpp
index b1a2477..fa3d1db 100644
--- a/src/dawn/tests/unittests/wire/WireQueueTests.cpp
+++ b/src/dawn/tests/unittests/wire/WireQueueTests.cpp
@@ -39,7 +39,7 @@
 using testing::InvokeWithoutArgs;
 using testing::Return;
 
-using WireQueueTestBase = WireFutureTest<wgpu::QueueWorkDoneCallback<void>*>;
+using WireQueueTestBase = WireFutureTest<wgpu::QueueWorkDoneCallback2<void>*>;
 class WireQueueTests : public WireQueueTestBase {
   protected:
     void OnSubmittedWorkDone() {
@@ -54,8 +54,8 @@
 TEST_P(WireQueueTests, OnSubmittedWorkDoneSuccess) {
     OnSubmittedWorkDone();
 
-    EXPECT_CALL(api, OnQueueOnSubmittedWorkDone(apiQueue, _)).WillOnce(InvokeWithoutArgs([&] {
-        api.CallQueueOnSubmittedWorkDoneCallback(apiQueue, WGPUQueueWorkDoneStatus_Success);
+    EXPECT_CALL(api, OnQueueOnSubmittedWorkDone2(apiQueue, _)).WillOnce(InvokeWithoutArgs([&] {
+        api.CallQueueOnSubmittedWorkDone2Callback(apiQueue, WGPUQueueWorkDoneStatus_Success);
     }));
     FlushClient();
     FlushFutures();
@@ -71,8 +71,8 @@
 TEST_P(WireQueueTests, OnSubmittedWorkDoneError) {
     OnSubmittedWorkDone();
 
-    EXPECT_CALL(api, OnQueueOnSubmittedWorkDone(apiQueue, _)).WillOnce(InvokeWithoutArgs([&] {
-        api.CallQueueOnSubmittedWorkDoneCallback(apiQueue, WGPUQueueWorkDoneStatus_Error);
+    EXPECT_CALL(api, OnQueueOnSubmittedWorkDone2(apiQueue, _)).WillOnce(InvokeWithoutArgs([&] {
+        api.CallQueueOnSubmittedWorkDone2Callback(apiQueue, WGPUQueueWorkDoneStatus_Error);
     }));
     FlushClient();
     FlushFutures();
@@ -93,8 +93,8 @@
 
     OnSubmittedWorkDone();
 
-    EXPECT_CALL(api, OnQueueOnSubmittedWorkDone(apiQueue, _)).WillOnce(InvokeWithoutArgs([&] {
-        api.CallQueueOnSubmittedWorkDoneCallback(apiQueue, WGPUQueueWorkDoneStatus_Error);
+    EXPECT_CALL(api, OnQueueOnSubmittedWorkDone2(apiQueue, _)).WillOnce(InvokeWithoutArgs([&] {
+        api.CallQueueOnSubmittedWorkDone2Callback(apiQueue, WGPUQueueWorkDoneStatus_Error);
     }));
     FlushClient();
     FlushFutures();
@@ -112,8 +112,8 @@
 TEST_P(WireQueueTests, OnSubmittedWorkDoneBeforeDisconnectBeforeReply) {
     OnSubmittedWorkDone();
 
-    EXPECT_CALL(api, OnQueueOnSubmittedWorkDone(apiQueue, _)).WillOnce(InvokeWithoutArgs([&] {
-        api.CallQueueOnSubmittedWorkDoneCallback(apiQueue, WGPUQueueWorkDoneStatus_Error);
+    EXPECT_CALL(api, OnQueueOnSubmittedWorkDone2(apiQueue, _)).WillOnce(InvokeWithoutArgs([&] {
+        api.CallQueueOnSubmittedWorkDone2Callback(apiQueue, WGPUQueueWorkDoneStatus_Error);
     }));
     FlushClient();
 
@@ -141,8 +141,8 @@
     static constexpr size_t kNumRequests = 10;
     OnSubmittedWorkDone();
 
-    EXPECT_CALL(api, OnQueueOnSubmittedWorkDone(apiQueue, _)).WillOnce(InvokeWithoutArgs([&] {
-        api.CallQueueOnSubmittedWorkDoneCallback(apiQueue, WGPUQueueWorkDoneStatus_Error);
+    EXPECT_CALL(api, OnQueueOnSubmittedWorkDone2(apiQueue, _)).WillOnce(InvokeWithoutArgs([&] {
+        api.CallQueueOnSubmittedWorkDone2Callback(apiQueue, WGPUQueueWorkDoneStatus_Error);
     }));
     FlushClient();
 
diff --git a/src/dawn/tests/unittests/wire/WireShaderModuleTests.cpp b/src/dawn/tests/unittests/wire/WireShaderModuleTests.cpp
index 9455b0d..dd89a96 100644
--- a/src/dawn/tests/unittests/wire/WireShaderModuleTests.cpp
+++ b/src/dawn/tests/unittests/wire/WireShaderModuleTests.cpp
@@ -40,7 +40,7 @@
 using testing::Mock;
 using testing::Return;
 
-using WireShaderModuleTestBase = WireFutureTest<wgpu::CompilationInfoCallback<void>*>;
+using WireShaderModuleTestBase = WireFutureTest<wgpu::CompilationInfoCallback2<void>*>;
 class WireShaderModuleTests : public WireShaderModuleTestBase {
   protected:
     void GetCompilationInfo() {
@@ -90,9 +90,9 @@
 TEST_P(WireShaderModuleTests, GetCompilationInfo) {
     GetCompilationInfo();
 
-    EXPECT_CALL(api, OnShaderModuleGetCompilationInfo(apiShaderModule, _))
+    EXPECT_CALL(api, OnShaderModuleGetCompilationInfo2(apiShaderModule, _))
         .WillOnce(InvokeWithoutArgs([&] {
-            api.CallShaderModuleGetCompilationInfoCallback(
+            api.CallShaderModuleGetCompilationInfo2Callback(
                 apiShaderModule, WGPUCompilationInfoRequestStatus_Success,
                 reinterpret_cast<const WGPUCompilationInfo*>(&mCompilationInfo));
         }));
@@ -127,9 +127,9 @@
 TEST_P(WireShaderModuleTests, GetCompilationInfoBeforeDisconnect) {
     GetCompilationInfo();
 
-    EXPECT_CALL(api, OnShaderModuleGetCompilationInfo(apiShaderModule, _))
+    EXPECT_CALL(api, OnShaderModuleGetCompilationInfo2(apiShaderModule, _))
         .WillOnce(InvokeWithoutArgs([&] {
-            api.CallShaderModuleGetCompilationInfoCallback(
+            api.CallShaderModuleGetCompilationInfo2Callback(
                 apiShaderModule, WGPUCompilationInfoRequestStatus_Success,
                 reinterpret_cast<const WGPUCompilationInfo*>(&mCompilationInfo));
         }));
@@ -163,9 +163,9 @@
 
     GetCompilationInfo();
 
-    EXPECT_CALL(api, OnShaderModuleGetCompilationInfo(apiShaderModule, _))
+    EXPECT_CALL(api, OnShaderModuleGetCompilationInfo2(apiShaderModule, _))
         .WillOnce(InvokeWithoutArgs([&] {
-            api.CallShaderModuleGetCompilationInfoCallback(
+            api.CallShaderModuleGetCompilationInfo2Callback(
                 apiShaderModule, WGPUCompilationInfoRequestStatus_Success,
                 reinterpret_cast<const WGPUCompilationInfo*>(&mCompilationInfo));
         }));
@@ -192,9 +192,9 @@
 
     GetCompilationInfo();
 
-    EXPECT_CALL(api, OnShaderModuleGetCompilationInfo(apiShaderModule, _))
+    EXPECT_CALL(api, OnShaderModuleGetCompilationInfo2(apiShaderModule, _))
         .WillOnce(InvokeWithoutArgs([&] {
-            api.CallShaderModuleGetCompilationInfoCallback(
+            api.CallShaderModuleGetCompilationInfo2Callback(
                 apiShaderModule, WGPUCompilationInfoRequestStatus_Success,
                 reinterpret_cast<const WGPUCompilationInfo*>(&mCompilationInfo));
         }));
diff --git a/src/dawn/wire/client/Buffer.cpp b/src/dawn/wire/client/Buffer.cpp
index a4afb34..784b039 100644
--- a/src/dawn/wire/client/Buffer.cpp
+++ b/src/dawn/wire/client/Buffer.cpp
@@ -62,6 +62,157 @@
     MapAsyncEvent(const WGPUBufferMapCallbackInfo& callbackInfo, Ref<Buffer> buffer)
         : TrackedEvent(callbackInfo.mode),
           mCallback(callbackInfo.callback),
+          mUserdata(callbackInfo.userdata),
+          mBuffer(std::move(buffer)) {
+        DAWN_ASSERT(mBuffer != nullptr);
+    }
+
+    EventType GetType() override { return kType; }
+
+    bool IsPendingRequest(FutureID futureID) {
+        return mBuffer->mPendingMapRequest && mBuffer->mPendingMapRequest->futureID == futureID;
+    }
+
+    WireResult ReadyHook(FutureID futureID,
+                         WGPUBufferMapAsyncStatus status,
+                         uint64_t readDataUpdateInfoLength = 0,
+                         const uint8_t* readDataUpdateInfo = nullptr) {
+        auto FailRequest = [this]() -> WireResult {
+            mStatus = WGPUBufferMapAsyncStatus_Unknown;
+            return WireResult::FatalError;
+        };
+
+        // Handling for different statuses.
+        switch (status) {
+            case WGPUBufferMapAsyncStatus_MappingAlreadyPending: {
+                DAWN_ASSERT(!IsPendingRequest(futureID));
+                mStatus = status;
+                break;
+            }
+
+            // For client-side rejection errors, we clear the pending request now since they always
+            // take precedence.
+            case WGPUBufferMapAsyncStatus_DestroyedBeforeCallback:
+            case WGPUBufferMapAsyncStatus_UnmappedBeforeCallback: {
+                mStatus = status;
+                mBuffer->mPendingMapRequest = std::nullopt;
+                break;
+            }
+
+            case WGPUBufferMapAsyncStatus_Success: {
+                if (!IsPendingRequest(futureID)) {
+                    // If a success occurs (which must come from the server), but it does not
+                    // correspond to the pending request, the pending request must have been
+                    // rejected early and hence the status must be set.
+                    DAWN_ASSERT(mStatus);
+                    break;
+                }
+                mStatus = status;
+                auto& pending = mBuffer->mPendingMapRequest.value();
+                if (!pending.type) {
+                    return FailRequest();
+                }
+                switch (*pending.type) {
+                    case MapRequestType::Read: {
+                        if (readDataUpdateInfoLength > std::numeric_limits<size_t>::max()) {
+                            // This is the size of data deserialized from the command stream, which
+                            // must be CPU-addressable.
+                            return FailRequest();
+                        }
+
+                        // Validate to prevent bad map request; buffer destroyed during map request
+                        if (mBuffer->mReadHandle == nullptr) {
+                            return FailRequest();
+                        }
+                        // Update user map data with server returned data
+                        if (!mBuffer->mReadHandle->DeserializeDataUpdate(
+                                readDataUpdateInfo, static_cast<size_t>(readDataUpdateInfoLength),
+                                pending.offset, pending.size)) {
+                            return FailRequest();
+                        }
+                        mBuffer->mMappedData = const_cast<void*>(mBuffer->mReadHandle->GetData());
+                        break;
+                    }
+                    case MapRequestType::Write: {
+                        if (mBuffer->mWriteHandle == nullptr) {
+                            return FailRequest();
+                        }
+                        mBuffer->mMappedData = mBuffer->mWriteHandle->GetData();
+                        break;
+                    }
+                }
+                mBuffer->mMappedOffset = pending.offset;
+                mBuffer->mMappedSize = pending.size;
+                break;
+            }
+
+            // All other statuses are server-side status.
+            default: {
+                if (!IsPendingRequest(futureID)) {
+                    break;
+                }
+                mStatus = status;
+            }
+        }
+        return WireResult::Success;
+    }
+
+  private:
+    void CompleteImpl(FutureID futureID, EventCompletionType completionType) override {
+        WGPUBufferMapAsyncStatus status = completionType == EventCompletionType::Shutdown
+                                              ? WGPUBufferMapAsyncStatus_DeviceLost
+                                              : WGPUBufferMapAsyncStatus_Success;
+        if (mStatus) {
+            status = *mStatus;
+        }
+
+        auto Callback = [this, &status]() {
+            if (mCallback) {
+                mCallback(status, mUserdata.ExtractAsDangling());
+            }
+        };
+
+        if (!IsPendingRequest(futureID)) {
+            DAWN_ASSERT(status != WGPUBufferMapAsyncStatus_Success);
+            return Callback();
+        }
+
+        // Device destruction/loss implicitly makes the map requests aborted.
+        if (!mBuffer->mDevice->IsAlive()) {
+            status = WGPUBufferMapAsyncStatus_DestroyedBeforeCallback;
+        }
+
+        if (status == WGPUBufferMapAsyncStatus_Success) {
+            DAWN_ASSERT(mBuffer->mPendingMapRequest->type);
+            switch (*mBuffer->mPendingMapRequest->type) {
+                case MapRequestType::Read:
+                    mBuffer->mMappedState = MapState::MappedForRead;
+                    break;
+                case MapRequestType::Write:
+                    mBuffer->mMappedState = MapState::MappedForWrite;
+                    break;
+            }
+        }
+        mBuffer->mPendingMapRequest = std::nullopt;
+        return Callback();
+    }
+
+    WGPUBufferMapCallback mCallback;
+    raw_ptr<void> mUserdata;
+
+    std::optional<WGPUBufferMapAsyncStatus> mStatus;
+
+    // Reference to the buffer to handle the internal states.
+    Ref<Buffer> mBuffer;
+};
+
+class Buffer::MapAsyncEvent2 : public TrackedEvent {
+  public:
+    static constexpr EventType kType = EventType::MapAsync;
+
+    MapAsyncEvent2(const WGPUBufferMapCallbackInfo2& callbackInfo, Ref<Buffer> buffer)
+        : TrackedEvent(callbackInfo.mode),
+          mCallback(callbackInfo.callback),
           mUserdata1(callbackInfo.userdata1),
           mUserdata2(callbackInfo.userdata2),
           mBuffer(buffer) {
@@ -171,7 +322,7 @@
         return Callback();
     }
 
-    WGPUBufferMapCallback mCallback;
+    WGPUBufferMapCallback2 mCallback;
     raw_ptr<void> mUserdata1;
     raw_ptr<void> mUserdata2;
 
@@ -307,30 +458,61 @@
 }
 
 void Buffer::WillDropLastExternalRef() {
-    SetFutureStatus(WGPUMapAsyncStatus_Aborted,
-                    "Buffer was destroyed before mapping was resolved.");
+    SetFutureStatus(WGPUBufferMapAsyncStatus_DestroyedBeforeCallback);
 }
 
 ObjectType Buffer::GetObjectType() const {
     return ObjectType::Buffer;
 }
 
-void Buffer::SetFutureStatus(WGPUMapAsyncStatus status, std::string_view message) {
+void Buffer::SetFutureStatus(WGPUBufferMapAsyncStatus status) {
     if (!mPendingMapRequest) {
         return;
     }
 
     FutureID futureID = mPendingMapRequest->futureID;
+    bool isNewEntryPoint = mPendingMapRequest->isNewEntryPoint;
     mPendingMapRequest = std::nullopt;
 
-    DAWN_CHECK(GetEventManager().SetFutureReady<MapAsyncEvent>(
-                   futureID, status, ToOutputStringView(message)) == WireResult::Success);
+    if (isNewEntryPoint) {
+        auto [newStatus, message] =
+            [](WGPUBufferMapAsyncStatus status) -> std::pair<WGPUMapAsyncStatus, std::string_view> {
+            switch (status) {
+                case WGPUBufferMapAsyncStatus_DestroyedBeforeCallback:
+                    return {WGPUMapAsyncStatus_Aborted,
+                            "Buffer was destroyed before mapping was resolved."};
+                case WGPUBufferMapAsyncStatus_UnmappedBeforeCallback:
+                    return {WGPUMapAsyncStatus_Aborted,
+                            "Buffer was unmapped before mapping was resolved."};
+                default:
+                    DAWN_UNREACHABLE();
+            }
+        }(status);
+
+        DAWN_CHECK(GetEventManager().SetFutureReady<MapAsyncEvent2>(
+                       futureID, newStatus, ToOutputStringView(message)) == WireResult::Success);
+    } else {
+        DAWN_CHECK(GetEventManager().SetFutureReady<MapAsyncEvent>(futureID, status) ==
+                   WireResult::Success);
+    }
 }
 
-WGPUFuture Buffer::MapAsync(WGPUMapMode mode,
-                            size_t offset,
-                            size_t size,
-                            const WGPUBufferMapCallbackInfo& callbackInfo) {
+void Buffer::MapAsync(WGPUMapMode mode,
+                      size_t offset,
+                      size_t size,
+                      WGPUBufferMapCallback callback,
+                      void* userdata) {
+    WGPUBufferMapCallbackInfo callbackInfo = {};
+    callbackInfo.mode = WGPUCallbackMode_AllowSpontaneous;
+    callbackInfo.callback = callback;
+    callbackInfo.userdata = userdata;
+    MapAsyncF(mode, offset, size, callbackInfo);
+}
+
+WGPUFuture Buffer::MapAsyncF(WGPUMapMode mode,
+                             size_t offset,
+                             size_t size,
+                             const WGPUBufferMapCallbackInfo& callbackInfo) {
     Client* client = GetClient();
     auto [futureIDInternal, tracked] =
         GetEventManager().TrackEvent(std::make_unique<MapAsyncEvent>(callbackInfo, this));
@@ -340,6 +522,52 @@
 
     if (mPendingMapRequest) {
         [[maybe_unused]] auto id = GetEventManager().SetFutureReady<MapAsyncEvent>(
+            futureIDInternal, WGPUBufferMapAsyncStatus_MappingAlreadyPending);
+        return {futureIDInternal};
+    }
+
+    // Handle the defaulting of size required by WebGPU.
+    if ((size == WGPU_WHOLE_MAP_SIZE) && (offset <= mSize)) {
+        size = mSize - offset;
+    }
+
+    // Set up the request structure that will hold information while this mapping is in flight.
+    std::optional<MapRequestType> mapMode;
+    if (mode & WGPUMapMode_Read) {
+        mapMode = MapRequestType::Read;
+    } else if (mode & WGPUMapMode_Write) {
+        mapMode = MapRequestType::Write;
+    }
+
+    mPendingMapRequest = {futureIDInternal, offset, size, mapMode, false};
+
+    // Serialize the command to send to the server.
+    BufferMapAsyncCmd cmd;
+    cmd.bufferId = GetWireId();
+    cmd.eventManagerHandle = GetEventManagerHandle();
+    cmd.future = {futureIDInternal};
+    cmd.mode = mode;
+    cmd.offset = offset;
+    cmd.size = size;
+    cmd.userdataCount = 1;
+
+    client->SerializeCommand(cmd);
+    return {futureIDInternal};
+}
+
+WGPUFuture Buffer::MapAsync2(WGPUMapMode mode,
+                             size_t offset,
+                             size_t size,
+                             const WGPUBufferMapCallbackInfo2& callbackInfo) {
+    Client* client = GetClient();
+    auto [futureIDInternal, tracked] =
+        GetEventManager().TrackEvent(std::make_unique<MapAsyncEvent2>(callbackInfo, this));
+    if (!tracked) {
+        return {futureIDInternal};
+    }
+
+    if (mPendingMapRequest) {
+        [[maybe_unused]] auto id = GetEventManager().SetFutureReady<MapAsyncEvent2>(
             futureIDInternal, WGPUMapAsyncStatus_Error,
             ToOutputStringView("Buffer already has an outstanding map pending."));
         return {futureIDInternal};
@@ -358,7 +586,7 @@
         mapMode = MapRequestType::Write;
     }
 
-    mPendingMapRequest = {futureIDInternal, offset, size, mapMode};
+    mPendingMapRequest = {futureIDInternal, offset, size, mapMode, true};
 
     // Serialize the command to send to the server.
     BufferMapAsyncCmd cmd;
@@ -368,6 +596,7 @@
     cmd.mode = mode;
     cmd.offset = offset;
     cmd.size = size;
+    cmd.userdataCount = 2;
 
     client->SerializeCommand(cmd);
     return {futureIDInternal};
@@ -375,13 +604,21 @@
 
 WireResult Client::DoBufferMapAsyncCallback(ObjectHandle eventManager,
                                             WGPUFuture future,
-                                            WGPUMapAsyncStatus status,
+                                            WGPUBufferMapAsyncStatus status,
+                                            WGPUMapAsyncStatus status2,
                                             WGPUStringView message,
+                                            uint8_t userdataCount,
                                             uint64_t readDataUpdateInfoLength,
                                             const uint8_t* readDataUpdateInfo) {
-    return GetEventManager(eventManager)
-        .SetFutureReady<Buffer::MapAsyncEvent>(future.id, status, message, readDataUpdateInfoLength,
-                                               readDataUpdateInfo);
+    if (userdataCount == 1) {
+        return GetEventManager(eventManager)
+            .SetFutureReady<Buffer::MapAsyncEvent>(future.id, status, readDataUpdateInfoLength,
+                                                   readDataUpdateInfo);
+    } else {
+        return GetEventManager(eventManager)
+            .SetFutureReady<Buffer::MapAsyncEvent2>(future.id, status2, message,
+                                                    readDataUpdateInfoLength, readDataUpdateInfo);
+    }
 }
 
 void* Buffer::GetMappedRange(size_t offset, size_t size) {
@@ -457,7 +694,7 @@
     cmd.self = ToAPI(this);
     client->SerializeCommand(cmd);
 
-    SetFutureStatus(WGPUMapAsyncStatus_Aborted, "Buffer was unmapped before mapping was resolved.");
+    SetFutureStatus(WGPUBufferMapAsyncStatus_UnmappedBeforeCallback);
 }
 
 void Buffer::Destroy() {
@@ -470,8 +707,7 @@
     cmd.self = ToAPI(this);
     client->SerializeCommand(cmd);
 
-    SetFutureStatus(WGPUMapAsyncStatus_Aborted,
-                    "Buffer was destroyed before mapping was resolved.");
+    SetFutureStatus(WGPUBufferMapAsyncStatus_DestroyedBeforeCallback);
 }
 
 WGPUBufferUsage Buffer::GetUsage() const {
diff --git a/src/dawn/wire/client/Buffer.h b/src/dawn/wire/client/Buffer.h
index f8e48f4..533635d 100644
--- a/src/dawn/wire/client/Buffer.h
+++ b/src/dawn/wire/client/Buffer.h
@@ -57,10 +57,19 @@
 
     ObjectType GetObjectType() const override;
 
-    WGPUFuture MapAsync(WGPUMapMode mode,
-                        size_t offset,
-                        size_t size,
-                        const WGPUBufferMapCallbackInfo& callbackInfo);
+    void MapAsync(WGPUMapMode mode,
+                  size_t offset,
+                  size_t size,
+                  WGPUBufferMapCallback callback,
+                  void* userdata);
+    WGPUFuture MapAsyncF(WGPUMapMode mode,
+                         size_t offset,
+                         size_t size,
+                         const WGPUBufferMapCallbackInfo& callbackInfo);
+    WGPUFuture MapAsync2(WGPUMapMode mode,
+                         size_t offset,
+                         size_t size,
+                         const WGPUBufferMapCallbackInfo2& callbackInfo);
     void* GetMappedRange(size_t offset, size_t size);
     const void* GetConstMappedRange(size_t offset, size_t size);
     void Unmap();
@@ -76,11 +85,12 @@
   private:
     friend class Client;
     class MapAsyncEvent;
+    class MapAsyncEvent2;
 
     void WillDropLastExternalRef() override;
 
     // Prepares the callbacks to be called and potentially calls them
-    void SetFutureStatus(WGPUMapAsyncStatus status, std::string_view message);
+    void SetFutureStatus(WGPUBufferMapAsyncStatus status);
 
     bool IsMappedForReading() const;
     bool IsMappedForWriting() const;
@@ -102,6 +112,9 @@
         // Because validation for request type is validated via the backend, we use an optional type
         // here. This is nullopt when an invalid request type is passed to the wire.
         std::optional<MapRequestType> type;
+        // Currently needs an additional boolean to indicate which entry point was used for the map.
+        // TODO(crbug.com/42241461): Remove this once we don't need to support both on the wire.
+        bool isNewEntryPoint = false;
     };
     enum class MapState {
         Unmapped,
diff --git a/src/dawn/wire/client/Device.cpp b/src/dawn/wire/client/Device.cpp
index 1b4960e..4677663 100644
--- a/src/dawn/wire/client/Device.cpp
+++ b/src/dawn/wire/client/Device.cpp
@@ -46,7 +46,7 @@
   public:
     static constexpr EventType kType = EventType::PopErrorScope;
 
-    explicit PopErrorScopeEvent(const WGPUPopErrorScopeCallbackInfo& callbackInfo)
+    explicit PopErrorScopeEvent(const WGPUPopErrorScopeCallbackInfo2& callbackInfo)
         : TrackedEvent(callbackInfo.mode),
           mCallback(callbackInfo.callback),
           mUserdata1(callbackInfo.userdata1),
@@ -72,7 +72,7 @@
         }
     }
 
-    WGPUPopErrorScopeCallback mCallback;
+    WGPUPopErrorScopeCallback2 mCallback;
     raw_ptr<void> mUserdata1;
     raw_ptr<void> mUserdata2;
 
@@ -145,11 +145,11 @@
 using CreateComputePipelineEvent =
     CreatePipelineEventBase<ComputePipeline,
                             EventType::CreateComputePipeline,
-                            WGPUCreateComputePipelineAsyncCallbackInfo>;
+                            WGPUCreateComputePipelineAsyncCallbackInfo2>;
 using CreateRenderPipelineEvent =
     CreatePipelineEventBase<RenderPipeline,
                             EventType::CreateRenderPipeline,
-                            WGPUCreateRenderPipelineAsyncCallbackInfo>;
+                            WGPUCreateRenderPipelineAsyncCallbackInfo2>;
 
 static constexpr WGPUUncapturedErrorCallbackInfo2 kEmptyUncapturedErrorCallbackInfo = {
     nullptr, nullptr, nullptr, nullptr};
@@ -348,7 +348,30 @@
         .SetFutureReady<Device::DeviceLostEvent>(future.id, reason, message);
 }
 
-WGPUFuture Device::PopErrorScope(const WGPUPopErrorScopeCallbackInfo& callbackInfo) {
+void Device::PopErrorScope(WGPUErrorCallback callback, void* userdata) {
+    static WGPUErrorCallback kDefaultCallback = [](WGPUErrorType, WGPUStringView, void*) {};
+
+    PopErrorScope2({nullptr, WGPUCallbackMode_AllowSpontaneous,
+                    [](WGPUPopErrorScopeStatus, WGPUErrorType type, WGPUStringView message,
+                       void* callback, void* userdata) {
+                        auto cb = reinterpret_cast<WGPUErrorCallback>(callback);
+                        cb(type, message, userdata);
+                    },
+                    reinterpret_cast<void*>(callback != nullptr ? callback : kDefaultCallback),
+                    userdata});
+}
+
+WGPUFuture Device::PopErrorScopeF(const WGPUPopErrorScopeCallbackInfo& callbackInfo) {
+    return PopErrorScope2({callbackInfo.nextInChain, callbackInfo.mode,
+                           [](WGPUPopErrorScopeStatus status, WGPUErrorType type,
+                              WGPUStringView message, void* callback, void* userdata) {
+                               auto cb = reinterpret_cast<WGPUPopErrorScopeCallback>(callback);
+                               cb(status, type, message, userdata);
+                           },
+                           reinterpret_cast<void*>(callbackInfo.callback), callbackInfo.userdata});
+}
+
+WGPUFuture Device::PopErrorScope2(const WGPUPopErrorScopeCallbackInfo2& callbackInfo) {
     Client* client = GetClient();
     auto [futureIDInternal, tracked] =
         GetEventManager().TrackEvent(std::make_unique<PopErrorScopeEvent>(callbackInfo));
@@ -415,8 +438,8 @@
 }
 
 template <typename Event, typename Cmd, typename CallbackInfo, typename Descriptor>
-WGPUFuture Device::CreatePipelineAsync(Descriptor const* descriptor,
-                                       const CallbackInfo& callbackInfo) {
+WGPUFuture Device::CreatePipelineAsyncF(Descriptor const* descriptor,
+                                        const CallbackInfo& callbackInfo) {
     using Pipeline = typename Event::Pipeline;
 
     Client* client = GetClient();
@@ -438,10 +461,38 @@
     return {futureIDInternal};
 }
 
-WGPUFuture Device::CreateComputePipelineAsync(
+void Device::CreateComputePipelineAsync(WGPUComputePipelineDescriptor const* descriptor,
+                                        WGPUCreateComputePipelineAsyncCallback callback,
+                                        void* userdata) {
+    CreateComputePipelineAsync2(
+        descriptor, {nullptr, WGPUCallbackMode_AllowSpontaneous,
+                     [](WGPUCreatePipelineAsyncStatus status, WGPUComputePipeline pipeline,
+                        WGPUStringView message, void* callback, void* userdata) {
+                         auto cb =
+                             reinterpret_cast<WGPUCreateComputePipelineAsyncCallback>(callback);
+                         cb(status, pipeline, message, userdata);
+                     },
+                     reinterpret_cast<void*>(callback), userdata});
+}
+
+WGPUFuture Device::CreateComputePipelineAsyncF(
     WGPUComputePipelineDescriptor const* descriptor,
     const WGPUCreateComputePipelineAsyncCallbackInfo& callbackInfo) {
-    return CreatePipelineAsync<CreateComputePipelineEvent, DeviceCreateComputePipelineAsyncCmd>(
+    return CreateComputePipelineAsync2(
+        descriptor, {callbackInfo.nextInChain, callbackInfo.mode,
+                     [](WGPUCreatePipelineAsyncStatus status, WGPUComputePipeline pipeline,
+                        WGPUStringView message, void* callback, void* userdata) {
+                         auto cb =
+                             reinterpret_cast<WGPUCreateComputePipelineAsyncCallback>(callback);
+                         cb(status, pipeline, message, userdata);
+                     },
+                     reinterpret_cast<void*>(callbackInfo.callback), callbackInfo.userdata});
+}
+
+WGPUFuture Device::CreateComputePipelineAsync2(
+    WGPUComputePipelineDescriptor const* descriptor,
+    const WGPUCreateComputePipelineAsyncCallbackInfo2& callbackInfo) {
+    return CreatePipelineAsyncF<CreateComputePipelineEvent, DeviceCreateComputePipelineAsyncCmd>(
         descriptor, callbackInfo);
 }
 
@@ -453,10 +504,38 @@
         .SetFutureReady<CreateComputePipelineEvent>(future.id, status, message);
 }
 
-WGPUFuture Device::CreateRenderPipelineAsync(
+void Device::CreateRenderPipelineAsync(WGPURenderPipelineDescriptor const* descriptor,
+                                       WGPUCreateRenderPipelineAsyncCallback callback,
+                                       void* userdata) {
+    CreateRenderPipelineAsync2(
+        descriptor, {nullptr, WGPUCallbackMode_AllowSpontaneous,
+                     [](WGPUCreatePipelineAsyncStatus status, WGPURenderPipeline pipeline,
+                        WGPUStringView message, void* callback, void* userdata) {
+                         auto cb =
+                             reinterpret_cast<WGPUCreateRenderPipelineAsyncCallback>(callback);
+                         cb(status, pipeline, message, userdata);
+                     },
+                     reinterpret_cast<void*>(callback), userdata});
+}
+
+WGPUFuture Device::CreateRenderPipelineAsyncF(
     WGPURenderPipelineDescriptor const* descriptor,
     const WGPUCreateRenderPipelineAsyncCallbackInfo& callbackInfo) {
-    return CreatePipelineAsync<CreateRenderPipelineEvent, DeviceCreateRenderPipelineAsyncCmd>(
+    return CreateRenderPipelineAsync2(
+        descriptor, {callbackInfo.nextInChain, callbackInfo.mode,
+                     [](WGPUCreatePipelineAsyncStatus status, WGPURenderPipeline pipeline,
+                        WGPUStringView message, void* callback, void* userdata) {
+                         auto cb =
+                             reinterpret_cast<WGPUCreateRenderPipelineAsyncCallback>(callback);
+                         cb(status, pipeline, message, userdata);
+                     },
+                     reinterpret_cast<void*>(callbackInfo.callback), callbackInfo.userdata});
+}
+
+WGPUFuture Device::CreateRenderPipelineAsync2(
+    WGPURenderPipelineDescriptor const* descriptor,
+    const WGPUCreateRenderPipelineAsyncCallbackInfo2& callbackInfo) {
+    return CreatePipelineAsyncF<CreateRenderPipelineEvent, DeviceCreateRenderPipelineAsyncCmd>(
         descriptor, callbackInfo);
 }
 
diff --git a/src/dawn/wire/client/Device.h b/src/dawn/wire/client/Device.h
index 5efef24..5f7a1a4 100644
--- a/src/dawn/wire/client/Device.h
+++ b/src/dawn/wire/client/Device.h
@@ -67,16 +67,30 @@
     // WebGPU API
     void SetLoggingCallback(WGPULoggingCallback errorCallback, void* errorUserdata);
     void InjectError(WGPUErrorType type, WGPUStringView message);
-    WGPUFuture PopErrorScope(const WGPUPopErrorScopeCallbackInfo& callbackInfo);
+    void PopErrorScope(WGPUErrorCallback callback, void* userdata);
+    WGPUFuture PopErrorScopeF(const WGPUPopErrorScopeCallbackInfo& callbackInfo);
+    WGPUFuture PopErrorScope2(const WGPUPopErrorScopeCallbackInfo2& callbackInfo);
 
     WGPUBuffer CreateBuffer(const WGPUBufferDescriptor* descriptor);
     WGPUBuffer CreateErrorBuffer(const WGPUBufferDescriptor* descriptor);
-    WGPUFuture CreateComputePipelineAsync(
+    void CreateComputePipelineAsync(WGPUComputePipelineDescriptor const* descriptor,
+                                    WGPUCreateComputePipelineAsyncCallback callback,
+                                    void* userdata);
+    WGPUFuture CreateComputePipelineAsyncF(
         WGPUComputePipelineDescriptor const* descriptor,
         const WGPUCreateComputePipelineAsyncCallbackInfo& callbackInfo);
-    WGPUFuture CreateRenderPipelineAsync(
+    WGPUFuture CreateComputePipelineAsync2(
+        WGPUComputePipelineDescriptor const* descriptor,
+        const WGPUCreateComputePipelineAsyncCallbackInfo2& callbackInfo);
+    void CreateRenderPipelineAsync(WGPURenderPipelineDescriptor const* descriptor,
+                                   WGPUCreateRenderPipelineAsyncCallback callback,
+                                   void* userdata);
+    WGPUFuture CreateRenderPipelineAsyncF(
         WGPURenderPipelineDescriptor const* descriptor,
         const WGPUCreateRenderPipelineAsyncCallbackInfo& callbackInfo);
+    WGPUFuture CreateRenderPipelineAsync2(
+        WGPURenderPipelineDescriptor const* descriptor,
+        const WGPUCreateRenderPipelineAsyncCallbackInfo2& callbackInfo);
 
     WGPUStatus GetLimits(WGPUSupportedLimits* limits) const;
     WGPUFuture GetLostFuture();
@@ -94,7 +108,7 @@
               typename Cmd,
               typename CallbackInfo = typename Event::CallbackInfo,
               typename Descriptor = decltype(std::declval<Cmd>().descriptor)>
-    WGPUFuture CreatePipelineAsync(Descriptor const* descriptor, const CallbackInfo& callbackInfo);
+    WGPUFuture CreatePipelineAsyncF(Descriptor const* descriptor, const CallbackInfo& callbackInfo);
 
     LimitsAndFeatures mLimitsAndFeatures;
 
diff --git a/src/dawn/wire/client/Queue.cpp b/src/dawn/wire/client/Queue.cpp
index e5093dc..2680e16 100644
--- a/src/dawn/wire/client/Queue.cpp
+++ b/src/dawn/wire/client/Queue.cpp
@@ -41,7 +41,7 @@
   public:
     static constexpr EventType kType = EventType::WorkDone;
 
-    explicit WorkDoneEvent(const WGPUQueueWorkDoneCallbackInfo& callbackInfo)
+    explicit WorkDoneEvent(const WGPUQueueWorkDoneCallbackInfo2& callbackInfo)
         : TrackedEvent(callbackInfo.mode),
           mCallback(callbackInfo.callback),
           mUserdata1(callbackInfo.userdata1),
@@ -59,6 +59,9 @@
         if (completionType == EventCompletionType::Shutdown) {
             mStatus = WGPUQueueWorkDoneStatus_InstanceDropped;
         }
+        if (mStatus == WGPUQueueWorkDoneStatus_DeviceLost) {
+            mStatus = WGPUQueueWorkDoneStatus_Success;
+        }
         void* userdata1 = mUserdata1.ExtractAsDangling();
         void* userdata2 = mUserdata2.ExtractAsDangling();
         if (mCallback) {
@@ -66,7 +69,7 @@
         }
     }
 
-    WGPUQueueWorkDoneCallback mCallback;
+    WGPUQueueWorkDoneCallback2 mCallback;
     raw_ptr<void> mUserdata1;
     raw_ptr<void> mUserdata2;
 
@@ -87,7 +90,41 @@
     return GetEventManager(eventManager).SetFutureReady<WorkDoneEvent>(future.id, status);
 }
 
-WGPUFuture Queue::OnSubmittedWorkDone(const WGPUQueueWorkDoneCallbackInfo& callbackInfo) {
+void Queue::OnSubmittedWorkDone(WGPUQueueWorkDoneCallback callback, void* userdata) {
+    OnSubmittedWorkDoneF({nullptr, WGPUCallbackMode_AllowSpontaneous, callback, userdata});
+}
+
+WGPUFuture Queue::OnSubmittedWorkDoneF(const WGPUQueueWorkDoneCallbackInfo& callbackInfo) {
+    // TODO(crbug.com/dawn/2052): Once we always return a future, change this to log to the instance
+    // (note, not raise a validation error to the device) and return the null future.
+    DAWN_ASSERT(callbackInfo.nextInChain == nullptr);
+
+    Client* client = GetClient();
+    auto [futureIDInternal, tracked] =
+        GetEventManager().TrackEvent(std::make_unique<WorkDoneEvent>(WGPUQueueWorkDoneCallbackInfo2{
+            callbackInfo.nextInChain, callbackInfo.mode,
+            [](WGPUQueueWorkDoneStatus status, void* callback, void* userdata) {
+                auto cb = reinterpret_cast<WGPUQueueWorkDoneCallback>(callback);
+                cb(status, userdata);
+            },
+            reinterpret_cast<void*>(callbackInfo.callback != nullptr ? callbackInfo.callback
+                                                                     : nullptr),
+            callbackInfo.userdata}));
+    if (!tracked) {
+        return {futureIDInternal};
+    }
+
+    QueueOnSubmittedWorkDoneCmd cmd;
+    cmd.queueId = GetWireId();
+    cmd.eventManagerHandle = GetEventManagerHandle();
+    cmd.future = {futureIDInternal};
+    cmd.userdataCount = 1;
+
+    client->SerializeCommand(cmd);
+    return {futureIDInternal};
+}
+
+WGPUFuture Queue::OnSubmittedWorkDone2(const WGPUQueueWorkDoneCallbackInfo2& callbackInfo) {
     // TODO(crbug.com/dawn/2052): Once we always return a future, change this to log to the instance
     // (note, not raise a validation error to the device) and return the null future.
     DAWN_ASSERT(callbackInfo.nextInChain == nullptr);
@@ -103,6 +140,7 @@
     cmd.queueId = GetWireId();
     cmd.eventManagerHandle = GetEventManagerHandle();
     cmd.future = {futureIDInternal};
+    cmd.userdataCount = 2;
 
     client->SerializeCommand(cmd);
     return {futureIDInternal};
diff --git a/src/dawn/wire/client/Queue.h b/src/dawn/wire/client/Queue.h
index 0f95a42..bec29d7 100644
--- a/src/dawn/wire/client/Queue.h
+++ b/src/dawn/wire/client/Queue.h
@@ -43,7 +43,9 @@
     ObjectType GetObjectType() const override;
 
     // Dawn API
-    WGPUFuture OnSubmittedWorkDone(const WGPUQueueWorkDoneCallbackInfo& callbackInfo);
+    void OnSubmittedWorkDone(WGPUQueueWorkDoneCallback callback, void* userdata);
+    WGPUFuture OnSubmittedWorkDoneF(const WGPUQueueWorkDoneCallbackInfo& callbackInfo);
+    WGPUFuture OnSubmittedWorkDone2(const WGPUQueueWorkDoneCallbackInfo2& callbackInfo);
     void WriteBuffer(WGPUBuffer cBuffer, uint64_t bufferOffset, const void* data, size_t size);
     void WriteTexture(const WGPUImageCopyTexture* destination,
                       const void* data,
diff --git a/src/dawn/wire/client/ShaderModule.cpp b/src/dawn/wire/client/ShaderModule.cpp
index 79fea77..614489b 100644
--- a/src/dawn/wire/client/ShaderModule.cpp
+++ b/src/dawn/wire/client/ShaderModule.cpp
@@ -40,7 +40,7 @@
   public:
     static constexpr EventType kType = EventType::CompilationInfo;
 
-    CompilationInfoEvent(const WGPUCompilationInfoCallbackInfo& callbackInfo,
+    CompilationInfoEvent(const WGPUCompilationInfoCallbackInfo2& callbackInfo,
                          Ref<ShaderModule> shader)
         : TrackedEvent(callbackInfo.mode),
           mCallback(callbackInfo.callback),
@@ -102,7 +102,7 @@
         }
     }
 
-    WGPUCompilationInfoCallback mCallback;
+    WGPUCompilationInfoCallback2 mCallback;
     raw_ptr<void> mUserdata1;
     raw_ptr<void> mUserdata2;
 
@@ -117,7 +117,39 @@
     return ObjectType::ShaderModule;
 }
 
-WGPUFuture ShaderModule::GetCompilationInfo(const WGPUCompilationInfoCallbackInfo& callbackInfo) {
+namespace {
+
+void DefaultGetCompilationInfoCallback(WGPUCompilationInfoRequestStatus status,
+                                       const WGPUCompilationInfo* compilationInfo,
+                                       void* callback,
+                                       void* userdata) {
+    if (callback == nullptr) {
+        DAWN_ASSERT(userdata == nullptr);
+        return;
+    }
+    auto cb = reinterpret_cast<WGPUCompilationInfoCallback>(callback);
+    cb(status, compilationInfo, userdata);
+}
+
+}  // anonymous namespace
+
+void ShaderModule::GetCompilationInfo(WGPUCompilationInfoCallback callback, void* userdata) {
+    if (callback == nullptr) {
+        DAWN_ASSERT(userdata == nullptr);
+        return;
+    }
+    GetCompilationInfo2({nullptr, WGPUCallbackMode_AllowSpontaneous,
+                         &DefaultGetCompilationInfoCallback, reinterpret_cast<void*>(callback),
+                         userdata});
+}
+
+WGPUFuture ShaderModule::GetCompilationInfoF(const WGPUCompilationInfoCallbackInfo& callbackInfo) {
+    return GetCompilationInfo2(
+        {callbackInfo.nextInChain, callbackInfo.mode, &DefaultGetCompilationInfoCallback,
+         reinterpret_cast<void*>(callbackInfo.callback), callbackInfo.userdata});
+}
+
+WGPUFuture ShaderModule::GetCompilationInfo2(const WGPUCompilationInfoCallbackInfo2& callbackInfo) {
     auto [futureIDInternal, tracked] =
         GetEventManager().TrackEvent(std::make_unique<CompilationInfoEvent>(callbackInfo, this));
     if (!tracked) {
diff --git a/src/dawn/wire/client/ShaderModule.h b/src/dawn/wire/client/ShaderModule.h
index a278196..d0558f6 100644
--- a/src/dawn/wire/client/ShaderModule.h
+++ b/src/dawn/wire/client/ShaderModule.h
@@ -44,7 +44,9 @@
 
     ObjectType GetObjectType() const override;
 
-    WGPUFuture GetCompilationInfo(const WGPUCompilationInfoCallbackInfo& callbackInfo);
+    void GetCompilationInfo(WGPUCompilationInfoCallback callback, void* userdata);
+    WGPUFuture GetCompilationInfoF(const WGPUCompilationInfoCallbackInfo& callbackInfo);
+    WGPUFuture GetCompilationInfo2(const WGPUCompilationInfoCallbackInfo2& callbackInfo);
 
   private:
     friend class Client;
diff --git a/src/dawn/wire/server/Server.h b/src/dawn/wire/server/Server.h
index 0241d31..4f0702f 100644
--- a/src/dawn/wire/server/Server.h
+++ b/src/dawn/wire/server/Server.h
@@ -129,6 +129,7 @@
     uint64_t offset;
     uint64_t size;
     WGPUMapMode mode;
+    uint8_t userdataCount;
 };
 
 struct ErrorScopeUserdata : CallbackUserdata {
@@ -264,9 +265,10 @@
                                WGPUPopErrorScopeStatus status,
                                WGPUErrorType type,
                                WGPUStringView message);
-    void OnBufferMapAsyncCallback(MapUserdata* userdata,
-                                  WGPUMapAsyncStatus status,
-                                  WGPUStringView message);
+    void OnBufferMapAsyncCallback(MapUserdata* userdata, WGPUBufferMapAsyncStatus status);
+    void OnBufferMapAsyncCallback2(MapUserdata* userdata,
+                                   WGPUMapAsyncStatus status,
+                                   WGPUStringView message);
     void OnQueueWorkDone(QueueWorkDoneUserdata* userdata, WGPUQueueWorkDoneStatus status);
     void OnCreateComputePipelineAsyncCallback(CreatePipelineAsyncUserData* userdata,
                                               WGPUCreatePipelineAsyncStatus status,
diff --git a/src/dawn/wire/server/ServerBuffer.cpp b/src/dawn/wire/server/ServerBuffer.cpp
index 24fe5f5..e639966 100644
--- a/src/dawn/wire/server/ServerBuffer.cpp
+++ b/src/dawn/wire/server/ServerBuffer.cpp
@@ -71,7 +71,8 @@
                                     WGPUFuture future,
                                     WGPUMapMode mode,
                                     uint64_t offset64,
-                                    uint64_t size64) {
+                                    uint64_t size64,
+                                    uint8_t userdataCount) {
     // These requests are just forwarded to the buffer, with userdata containing what the
     // client will require in the return command.
     std::unique_ptr<MapUserdata> userdata = MakeUserdata<MapUserdata>();
@@ -80,6 +81,7 @@
     userdata->bufferObj = buffer->handle;
     userdata->future = future;
     userdata->mode = mode;
+    userdata->userdataCount = userdataCount;
 
     // Make sure that the deserialized offset and size are no larger than
     // std::numeric_limits<size_t>::max() so that they are CPU-addressable, and size is not
@@ -87,13 +89,11 @@
     // client does the default size computation, we should always have a valid actual size here
     // in server. All other invalid actual size can be caught by dawn native side validation.
     if (offset64 > std::numeric_limits<size_t>::max()) {
-        static constexpr WGPUStringView kOffsetOutOfRange = {"Buffer offset was out of range.", 31};
-        OnBufferMapAsyncCallback(userdata.get(), WGPUMapAsyncStatus_Error, kOffsetOutOfRange);
+        OnBufferMapAsyncCallback(userdata.get(), WGPUBufferMapAsyncStatus_OffsetOutOfRange);
         return WireResult::Success;
     }
     if (size64 >= WGPU_WHOLE_MAP_SIZE) {
-        static constexpr WGPUStringView kSizeOutOfRange = {"Buffer size was out of range.", 29};
-        OnBufferMapAsyncCallback(userdata.get(), WGPUMapAsyncStatus_Error, kSizeOutOfRange);
+        OnBufferMapAsyncCallback(userdata.get(), WGPUBufferMapAsyncStatus_SizeOutOfRange);
         return WireResult::Success;
     }
 
@@ -103,10 +103,16 @@
     userdata->offset = offset;
     userdata->size = size;
 
-    mProcs.bufferMapAsync(
-        buffer->handle, mode, offset, size,
-        {nullptr, WGPUCallbackMode_AllowSpontaneous,
-         ForwardToServer2<&Server::OnBufferMapAsyncCallback>, userdata.release(), nullptr});
+    if (userdataCount == 1) {
+        mProcs.bufferMapAsync(buffer->handle, mode, offset, size,
+                              ForwardToServer<&Server::OnBufferMapAsyncCallback>,
+                              userdata.release());
+    } else {
+        mProcs.bufferMapAsync2(
+            buffer->handle, mode, offset, size,
+            {nullptr, WGPUCallbackMode_AllowSpontaneous,
+             ForwardToServer2<&Server::OnBufferMapAsyncCallback2>, userdata.release(), nullptr});
+    }
 
     return WireResult::Success;
 }
@@ -219,9 +225,65 @@
     return WireResult::Success;
 }
 
-void Server::OnBufferMapAsyncCallback(MapUserdata* data,
-                                      WGPUMapAsyncStatus status,
-                                      WGPUStringView message) {
+void Server::OnBufferMapAsyncCallback(MapUserdata* data, WGPUBufferMapAsyncStatus status) {
+    // Skip sending the callback if the buffer has already been destroyed.
+    Known<WGPUBuffer> buffer;
+    if (Objects<WGPUBuffer>().Get(data->buffer.id, &buffer) != WireResult::Success ||
+        buffer->generation != data->buffer.generation) {
+        return;
+    }
+
+    bool isRead = data->mode & WGPUMapMode_Read;
+    bool isSuccess = status == WGPUBufferMapAsyncStatus_Success;
+
+    ReturnBufferMapAsyncCallbackCmd cmd = {};
+    cmd.eventManager = data->eventManager;
+    cmd.future = data->future;
+    cmd.status = status;
+    cmd.message = kEmptyOutputStringView;
+    cmd.readDataUpdateInfoLength = 0;
+    cmd.readDataUpdateInfo = nullptr;
+    cmd.userdataCount = 1;
+
+    const void* readData = nullptr;
+    size_t readDataUpdateInfoLength = 0;
+    if (isSuccess) {
+        if (isRead) {
+            // Get the serialization size of the message to initialize ReadHandle data.
+            readData = mProcs.bufferGetConstMappedRange(data->bufferObj, data->offset, data->size);
+            readDataUpdateInfoLength =
+                buffer->readHandle->SizeOfSerializeDataUpdate(data->offset, data->size);
+            cmd.readDataUpdateInfoLength = readDataUpdateInfoLength;
+        } else {
+            DAWN_ASSERT(data->mode & WGPUMapMode_Write);
+            // The in-flight map request returned successfully.
+            buffer->mapWriteState = BufferMapWriteState::Mapped;
+            // Set the target of the WriteHandle to the mapped buffer data.
+            // writeHandle Target always refers to the buffer base address.
+            // but we call getMappedRange exactly with the range of data that is potentially
+            // modified (i.e. we don't want getMappedRange(0, wholeBufferSize) if only a
+            // subset of the buffer is actually mapped) in case the implementation does some
+            // range tracking.
+            buffer->writeHandle->SetTarget(static_cast<uint8_t*>(mProcs.bufferGetMappedRange(
+                                               data->bufferObj, data->offset, data->size)) -
+                                           data->offset);
+        }
+    }
+
+    SerializeCommand(cmd, CommandExtension{readDataUpdateInfoLength, [&](char* readHandleBuffer) {
+                                               if (isSuccess && isRead) {
+                                                   // The in-flight map request returned
+                                                   // successfully.
+                                                   buffer->readHandle->SerializeDataUpdate(
+                                                       readData, data->offset, data->size,
+                                                       readHandleBuffer);
+                                               }
+                                           }});
+}
+
+void Server::OnBufferMapAsyncCallback2(MapUserdata* data,
+                                       WGPUMapAsyncStatus status,
+                                       WGPUStringView message) {
     // Skip sending the callback if the buffer has already been destroyed.
     Known<WGPUBuffer> buffer;
     if (Objects<WGPUBuffer>().Get(data->buffer.id, &buffer) != WireResult::Success ||
@@ -235,10 +297,11 @@
     ReturnBufferMapAsyncCallbackCmd cmd = {};
     cmd.eventManager = data->eventManager;
     cmd.future = data->future;
-    cmd.status = status;
+    cmd.status2 = status;
     cmd.message = message;
     cmd.readDataUpdateInfoLength = 0;
     cmd.readDataUpdateInfo = nullptr;
+    cmd.userdataCount = 2;
 
     const void* readData = nullptr;
     size_t readDataUpdateInfoLength = 0;
diff --git a/src/dawn/wire/server/ServerDevice.cpp b/src/dawn/wire/server/ServerDevice.cpp
index dda48bc..f428677 100644
--- a/src/dawn/wire/server/ServerDevice.cpp
+++ b/src/dawn/wire/server/ServerDevice.cpp
@@ -72,9 +72,9 @@
     userdata->eventManager = eventManager;
     userdata->future = future;
 
-    mProcs.devicePopErrorScope(device->handle, {nullptr, WGPUCallbackMode_AllowProcessEvents,
-                                                ForwardToServer2<&Server::OnDevicePopErrorScope>,
-                                                userdata.release(), nullptr});
+    mProcs.devicePopErrorScope2(device->handle, {nullptr, WGPUCallbackMode_AllowProcessEvents,
+                                                 ForwardToServer2<&Server::OnDevicePopErrorScope>,
+                                                 userdata.release(), nullptr});
     return WireResult::Success;
 }
 
@@ -107,7 +107,7 @@
     userdata->future = future;
     userdata->pipelineObjectID = pipeline.id;
 
-    mProcs.deviceCreateComputePipelineAsync(
+    mProcs.deviceCreateComputePipelineAsync2(
         device->handle, descriptor,
         {nullptr, WGPUCallbackMode_AllowProcessEvents,
          ForwardToServer2<&Server::OnCreateComputePipelineAsyncCallback>, userdata.release(),
@@ -149,7 +149,7 @@
     userdata->future = future;
     userdata->pipelineObjectID = pipeline.id;
 
-    mProcs.deviceCreateRenderPipelineAsync(
+    mProcs.deviceCreateRenderPipelineAsync2(
         device->handle, descriptor,
         {nullptr, WGPUCallbackMode_AllowProcessEvents,
          ForwardToServer2<&Server::OnCreateRenderPipelineAsyncCallback>, userdata.release(),
diff --git a/src/dawn/wire/server/ServerQueue.cpp b/src/dawn/wire/server/ServerQueue.cpp
index 2eba81a..338a3b5 100644
--- a/src/dawn/wire/server/ServerQueue.cpp
+++ b/src/dawn/wire/server/ServerQueue.cpp
@@ -43,15 +43,22 @@
 
 WireResult Server::DoQueueOnSubmittedWorkDone(Known<WGPUQueue> queue,
                                               ObjectHandle eventManager,
-                                              WGPUFuture future) {
+                                              WGPUFuture future,
+                                              uint8_t userdataCount) {
     auto userdata = MakeUserdata<QueueWorkDoneUserdata>();
     userdata->queue = queue.AsHandle();
     userdata->eventManager = eventManager;
     userdata->future = future;
 
-    mProcs.queueOnSubmittedWorkDone(
-        queue->handle, {nullptr, WGPUCallbackMode_AllowProcessEvents,
-                        ForwardToServer2<&Server::OnQueueWorkDone>, userdata.release(), nullptr});
+    if (userdataCount == 1) {
+        mProcs.queueOnSubmittedWorkDone(queue->handle, ForwardToServer<&Server::OnQueueWorkDone>,
+                                        userdata.release());
+    } else {
+        mProcs.queueOnSubmittedWorkDone2(
+            queue->handle,
+            {nullptr, WGPUCallbackMode_AllowProcessEvents,
+             ForwardToServer2<&Server::OnQueueWorkDone>, userdata.release(), nullptr});
+    }
     return WireResult::Success;
 }
 
diff --git a/src/dawn/wire/server/ServerShaderModule.cpp b/src/dawn/wire/server/ServerShaderModule.cpp
index 969022b..effb4e0 100644
--- a/src/dawn/wire/server/ServerShaderModule.cpp
+++ b/src/dawn/wire/server/ServerShaderModule.cpp
@@ -38,7 +38,7 @@
     userdata->eventManager = eventManager;
     userdata->future = future;
 
-    mProcs.shaderModuleGetCompilationInfo(
+    mProcs.shaderModuleGetCompilationInfo2(
         shaderModule->handle,
         {nullptr, WGPUCallbackMode_AllowProcessEvents,
          ForwardToServer2<&Server::OnShaderModuleGetCompilationInfo>, userdata.release(), nullptr});
diff --git a/third_party/emdawnwebgpu/webgpu.cpp b/third_party/emdawnwebgpu/webgpu.cpp
index 8e6d041..1c44642 100644
--- a/third_party/emdawnwebgpu/webgpu.cpp
+++ b/third_party/emdawnwebgpu/webgpu.cpp
@@ -641,7 +641,7 @@
   WGPUFuture MapAsync(WGPUMapMode mode,
                       size_t offset,
                       size_t size,
-                      WGPUBufferMapCallbackInfo callbackInfo);
+                      WGPUBufferMapCallbackInfo2 callbackInfo);
   void Unmap();
 
  private:
@@ -714,7 +714,7 @@
  public:
   WGPUShaderModuleImpl(const EventSource* source);
 
-  WGPUFuture GetCompilationInfo(WGPUCompilationInfoCallbackInfo callbackInfo);
+  WGPUFuture GetCompilationInfo(WGPUCompilationInfoCallbackInfo2 callbackInfo);
 
  private:
   friend class CompilationInfoEvent;
@@ -751,7 +751,7 @@
 
   CompilationInfoEvent(InstanceID instance,
                        WGPUShaderModule shader,
-                       const WGPUCompilationInfoCallbackInfo& callbackInfo)
+                       const WGPUCompilationInfoCallbackInfo2& callbackInfo)
       : TrackedEvent(instance, callbackInfo.mode),
         mCallback(callbackInfo.callback),
         mUserdata1(callbackInfo.userdata1),
@@ -789,7 +789,7 @@
   }
 
  private:
-  WGPUCompilationInfoCallback mCallback = nullptr;
+  WGPUCompilationInfoCallback2 mCallback = nullptr;
   void* mUserdata1 = nullptr;
   void* mUserdata2 = nullptr;
 
@@ -848,11 +848,11 @@
 using CreateComputePipelineEvent =
     CreatePipelineEventBase<WGPUComputePipeline,
                             EventType::CreateComputePipeline,
-                            WGPUCreateComputePipelineAsyncCallbackInfo>;
+                            WGPUCreateComputePipelineAsyncCallbackInfo2>;
 using CreateRenderPipelineEvent =
     CreatePipelineEventBase<WGPURenderPipeline,
                             EventType::CreateRenderPipeline,
-                            WGPUCreateRenderPipelineAsyncCallbackInfo>;
+                            WGPUCreateRenderPipelineAsyncCallbackInfo2>;
 
 class DeviceLostEvent final : public TrackedEvent {
  public:
@@ -908,7 +908,7 @@
   static constexpr EventType kType = EventType::PopErrorScope;
 
   PopErrorScopeEvent(InstanceID instance,
-                     const WGPUPopErrorScopeCallbackInfo& callbackInfo)
+                     const WGPUPopErrorScopeCallbackInfo2& callbackInfo)
       : TrackedEvent(instance, callbackInfo.mode),
         mCallback(callbackInfo.callback),
         mUserdata1(callbackInfo.userdata1),
@@ -939,7 +939,7 @@
   }
 
  private:
-  WGPUPopErrorScopeCallback mCallback = nullptr;
+  WGPUPopErrorScopeCallback2 mCallback = nullptr;
   void* mUserdata1 = nullptr;
   void* mUserdata2 = nullptr;
 
@@ -954,7 +954,7 @@
 
   MapAsyncEvent(InstanceID instance,
                 WGPUBuffer buffer,
-                const WGPUBufferMapCallbackInfo& callbackInfo)
+                const WGPUBufferMapCallbackInfo2& callbackInfo)
       : TrackedEvent(instance, callbackInfo.mode),
         mCallback(callbackInfo.callback),
         mUserdata1(callbackInfo.userdata1),
@@ -1001,7 +1001,7 @@
   }
 
  private:
-  WGPUBufferMapCallback mCallback = nullptr;
+  WGPUBufferMapCallback2 mCallback = nullptr;
   void* mUserdata1 = nullptr;
   void* mUserdata2 = nullptr;
 
@@ -1109,7 +1109,7 @@
   static constexpr EventType kType = EventType::WorkDone;
 
   WorkDoneEvent(InstanceID instance,
-                const WGPUQueueWorkDoneCallbackInfo& callbackInfo)
+                const WGPUQueueWorkDoneCallbackInfo2& callbackInfo)
       : TrackedEvent(instance, callbackInfo.mode),
         mCallback(callbackInfo.callback),
         mUserdata1(callbackInfo.userdata1),
@@ -1129,7 +1129,7 @@
   }
 
  private:
-  WGPUQueueWorkDoneCallback mCallback = nullptr;
+  WGPUQueueWorkDoneCallback2 mCallback = nullptr;
   void* mUserdata1 = nullptr;
   void* mUserdata2 = nullptr;
 
@@ -1306,7 +1306,7 @@
 WGPUFuture WGPUBufferImpl::MapAsync(WGPUMapMode mode,
                                     size_t offset,
                                     size_t size,
-                                    WGPUBufferMapCallbackInfo callbackInfo) {
+                                    WGPUBufferMapCallbackInfo2 callbackInfo) {
   auto [futureId, tracked] = GetEventManager().TrackEvent(
       std::make_unique<MapAsyncEvent>(GetInstanceId(), this, callbackInfo));
   if (!tracked) {
@@ -1450,7 +1450,7 @@
     : EventSource(source) {}
 
 WGPUFuture WGPUShaderModuleImpl::GetCompilationInfo(
-    WGPUCompilationInfoCallbackInfo callbackInfo) {
+    WGPUCompilationInfoCallbackInfo2 callbackInfo) {
   auto [futureId, tracked] =
       GetEventManager().TrackEvent(std::make_unique<CompilationInfoEvent>(
           GetInstanceId(), this, callbackInfo));
@@ -1612,11 +1612,11 @@
   return buffer->GetMappedRange(offset, size);
 }
 
-WGPUFuture wgpuBufferMapAsync(WGPUBuffer buffer,
-                              WGPUMapMode mode,
-                              size_t offset,
-                              size_t size,
-                              WGPUBufferMapCallbackInfo callbackInfo) {
+WGPUFuture wgpuBufferMapAsync2(WGPUBuffer buffer,
+                               WGPUMapMode mode,
+                               size_t offset,
+                               size_t size,
+                               WGPUBufferMapCallbackInfo2 callbackInfo) {
   return buffer->MapAsync(mode, offset, size, callbackInfo);
 }
 
@@ -1651,10 +1651,29 @@
   return buffer;
 }
 
-WGPUFuture wgpuDeviceCreateComputePipelineAsync(
+void wgpuDeviceCreateComputePipelineAsync(
     WGPUDevice device,
     const WGPUComputePipelineDescriptor* descriptor,
-    WGPUCreateComputePipelineAsyncCallbackInfo callbackInfo) {
+    WGPUCreateComputePipelineAsyncCallback callback,
+    void* userdata) {
+  WGPUCreateComputePipelineAsyncCallbackInfo2 callbackInfo = {};
+  callbackInfo.mode = WGPUCallbackMode_AllowSpontaneous;
+  callbackInfo.callback =
+      [](WGPUCreatePipelineAsyncStatus status, WGPUComputePipeline pipeline,
+         WGPUStringView message, void* callback, void* userdata) {
+        auto cb =
+            reinterpret_cast<WGPUCreateComputePipelineAsyncCallback>(callback);
+        cb(status, pipeline, message, userdata);
+      };
+  callbackInfo.userdata1 = reinterpret_cast<void*>(callback);
+  callbackInfo.userdata2 = userdata;
+  wgpuDeviceCreateComputePipelineAsync2(device, descriptor, callbackInfo);
+}
+
+WGPUFuture wgpuDeviceCreateComputePipelineAsync2(
+    WGPUDevice device,
+    const WGPUComputePipelineDescriptor* descriptor,
+    WGPUCreateComputePipelineAsyncCallbackInfo2 callbackInfo) {
   auto [futureId, tracked] =
       GetEventManager().TrackEvent(std::make_unique<CreateComputePipelineEvent>(
           device->GetInstanceId(), callbackInfo));
@@ -1666,10 +1685,29 @@
   return WGPUFuture{futureId};
 }
 
-WGPUFuture wgpuDeviceCreateRenderPipelineAsync(
+void wgpuDeviceCreateRenderPipelineAsync(
     WGPUDevice device,
     const WGPURenderPipelineDescriptor* descriptor,
-    WGPUCreateRenderPipelineAsyncCallbackInfo callbackInfo) {
+    WGPUCreateRenderPipelineAsyncCallback callback,
+    void* userdata) {
+  WGPUCreateRenderPipelineAsyncCallbackInfo2 callbackInfo = {};
+  callbackInfo.mode = WGPUCallbackMode_AllowSpontaneous;
+  callbackInfo.callback = [](WGPUCreatePipelineAsyncStatus status,
+                             WGPURenderPipeline pipeline,
+                             WGPUStringView message, void* callback,
+                             void* userdata) {
+    auto cb = reinterpret_cast<WGPUCreateRenderPipelineAsyncCallback>(callback);
+    cb(status, pipeline, message, userdata);
+  };
+  callbackInfo.userdata1 = reinterpret_cast<void*>(callback);
+  callbackInfo.userdata2 = userdata;
+  wgpuDeviceCreateRenderPipelineAsync2(device, descriptor, callbackInfo);
+}
+
+WGPUFuture wgpuDeviceCreateRenderPipelineAsync2(
+    WGPUDevice device,
+    const WGPURenderPipelineDescriptor* descriptor,
+    WGPUCreateRenderPipelineAsyncCallbackInfo2 callbackInfo) {
   auto [futureId, tracked] =
       GetEventManager().TrackEvent(std::make_unique<CreateRenderPipelineEvent>(
           device->GetInstanceId(), callbackInfo));
@@ -1701,8 +1739,9 @@
   return device->GetQueue();
 }
 
-WGPUFuture wgpuDevicePopErrorScope(WGPUDevice device,
-                                   WGPUPopErrorScopeCallbackInfo callbackInfo) {
+WGPUFuture wgpuDevicePopErrorScope2(
+    WGPUDevice device,
+    WGPUPopErrorScopeCallbackInfo2 callbackInfo) {
   auto [futureId, tracked] =
       GetEventManager().TrackEvent(std::make_unique<PopErrorScopeEvent>(
           device->GetInstanceId(), callbackInfo));
@@ -1773,9 +1812,9 @@
 // Methods of Queue
 // ----------------------------------------------------------------------------
 
-WGPUFuture wgpuQueueOnSubmittedWorkDone(
+WGPUFuture wgpuQueueOnSubmittedWorkDone2(
     WGPUQueue queue,
-    WGPUQueueWorkDoneCallbackInfo callbackInfo) {
+    WGPUQueueWorkDoneCallbackInfo2 callbackInfo) {
   auto [futureId, tracked] = GetEventManager().TrackEvent(
       std::make_unique<WorkDoneEvent>(queue->GetInstanceId(), callbackInfo));
   if (!tracked) {
@@ -1810,9 +1849,9 @@
 // Methods of ShaderModule
 // ----------------------------------------------------------------------------
 
-WGPUFuture wgpuShaderModuleGetCompilationInfo(
+WGPUFuture wgpuShaderModuleGetCompilationInfo2(
     WGPUShaderModule shader,
-    WGPUCompilationInfoCallbackInfo callbackInfo) {
+    WGPUCompilationInfoCallbackInfo2 callbackInfo) {
   return shader->GetCompilationInfo(callbackInfo);
 }
 
diff --git a/tools/android/BUILD.gn b/tools/android/BUILD.gn
index de900b1..0e7abd8 100644
--- a/tools/android/BUILD.gn
+++ b/tools/android/BUILD.gn
@@ -62,8 +62,11 @@
     "java/android/dawn/BufferBindingLayout.kt",
     "java/android/dawn/BufferBindingType.kt",
     "java/android/dawn/BufferDescriptor.kt",
+    "java/android/dawn/BufferMapAsyncStatus.kt",
     "java/android/dawn/BufferMapCallback.kt",
+    "java/android/dawn/BufferMapCallback2.kt",
     "java/android/dawn/BufferMapCallbackInfo.kt",
+    "java/android/dawn/BufferMapCallbackInfo2.kt",
     "java/android/dawn/BufferMapState.kt",
     "java/android/dawn/BufferUsage.kt",
     "java/android/dawn/CallbackMode.kt",
@@ -77,7 +80,9 @@
     "java/android/dawn/CompareFunction.kt",
     "java/android/dawn/CompilationInfo.kt",
     "java/android/dawn/CompilationInfoCallback.kt",
+    "java/android/dawn/CompilationInfoCallback2.kt",
     "java/android/dawn/CompilationInfoCallbackInfo.kt",
+    "java/android/dawn/CompilationInfoCallbackInfo2.kt",
     "java/android/dawn/CompilationInfoRequestStatus.kt",
     "java/android/dawn/CompilationMessage.kt",
     "java/android/dawn/CompilationMessageType.kt",
@@ -91,10 +96,14 @@
     "java/android/dawn/ConstantEntry.kt",
     "java/android/dawn/Constants.kt",
     "java/android/dawn/CreateComputePipelineAsyncCallback.kt",
+    "java/android/dawn/CreateComputePipelineAsyncCallback2.kt",
     "java/android/dawn/CreateComputePipelineAsyncCallbackInfo.kt",
+    "java/android/dawn/CreateComputePipelineAsyncCallbackInfo2.kt",
     "java/android/dawn/CreatePipelineAsyncStatus.kt",
     "java/android/dawn/CreateRenderPipelineAsyncCallback.kt",
+    "java/android/dawn/CreateRenderPipelineAsyncCallback2.kt",
     "java/android/dawn/CreateRenderPipelineAsyncCallbackInfo.kt",
+    "java/android/dawn/CreateRenderPipelineAsyncCallbackInfo2.kt",
     "java/android/dawn/CullMode.kt",
     "java/android/dawn/DepthStencilState.kt",
     "java/android/dawn/Device.kt",
@@ -134,7 +143,9 @@
     "java/android/dawn/PipelineLayout.kt",
     "java/android/dawn/PipelineLayoutDescriptor.kt",
     "java/android/dawn/PopErrorScopeCallback.kt",
+    "java/android/dawn/PopErrorScopeCallback2.kt",
     "java/android/dawn/PopErrorScopeCallbackInfo.kt",
+    "java/android/dawn/PopErrorScopeCallbackInfo2.kt",
     "java/android/dawn/PopErrorScopeStatus.kt",
     "java/android/dawn/PowerPreference.kt",
     "java/android/dawn/PresentMode.kt",
@@ -147,7 +158,9 @@
     "java/android/dawn/Queue.kt",
     "java/android/dawn/QueueDescriptor.kt",
     "java/android/dawn/QueueWorkDoneCallback.kt",
+    "java/android/dawn/QueueWorkDoneCallback2.kt",
     "java/android/dawn/QueueWorkDoneCallbackInfo.kt",
+    "java/android/dawn/QueueWorkDoneCallbackInfo2.kt",
     "java/android/dawn/QueueWorkDoneStatus.kt",
     "java/android/dawn/RenderBundle.kt",
     "java/android/dawn/RenderBundleDescriptor.kt",
diff --git a/tools/android/webgpu/src/test/java/android/dawn/MappedNamedConstantsTest.kt b/tools/android/webgpu/src/test/java/android/dawn/MappedNamedConstantsTest.kt
index 886ca44..be7a490 100644
--- a/tools/android/webgpu/src/test/java/android/dawn/MappedNamedConstantsTest.kt
+++ b/tools/android/webgpu/src/test/java/android/dawn/MappedNamedConstantsTest.kt
@@ -21,6 +21,7 @@
         BlendFactor::class,
         BlendOperation::class,
         BufferBindingType::class,
+        BufferMapAsyncStatus::class,
         BufferMapState::class,
         BufferUsage::class,
         CallbackMode::class,