From 84adbfa467ec235fd7caeadfe1c669e69a6f5452 Mon Sep 17 00:00:00 2001 From: Mike Rolig Date: Mon, 26 Feb 2024 10:46:04 -0800 Subject: [PATCH 1/3] [Emval] Update co_await to move promise 'val' when possible --- system/include/emscripten/val.h | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/system/include/emscripten/val.h b/system/include/emscripten/val.h index 9721f66f7999e..30377ee91ce1a 100644 --- a/system/include/emscripten/val.h +++ b/system/include/emscripten/val.h @@ -629,7 +629,8 @@ class val { #if __cplusplus >= 202002L class awaiter; - awaiter operator co_await() const; + awaiter operator co_await() const&; + awaiter operator co_await() &&; class promise_type; #endif @@ -717,6 +718,8 @@ class val::awaiter { constexpr static std::size_t STATE_RESULT = 2; public: + awaiter(val&& promise) + : state(std::in_place_index, std::move(promise)) {} awaiter(const val& promise) : state(std::in_place_index, promise) {} @@ -746,7 +749,11 @@ class val::awaiter { val await_resume() { return std::move(std::get(state)); } }; -inline val::awaiter val::operator co_await() const { +inline val::awaiter val::operator co_await() && { + return {std::move(*this)}; +} + +inline val::awaiter val::operator co_await() const& { return {*this}; } @@ -768,7 +775,7 @@ class val::promise_type { } // Return the stored promise as the actual return value of the coroutine. - val get_return_object() { return promise; } + val get_return_object() { return std::move(promise); } // For similarity with JS async functions, our coroutines are eagerly evaluated. auto initial_suspend() noexcept { return std::suspend_never{}; } From ae1b41c8885ce517a08c0a30364d7cf980915bdb Mon Sep 17 00:00:00 2001 From: Mike Rolig Date: Mon, 26 Feb 2024 10:57:26 -0800 Subject: [PATCH 2/3] Move in typed_awaiter. --- test/embind/test_val_coro.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/embind/test_val_coro.cpp b/test/embind/test_val_coro.cpp index 442667e2a56cd..3ba54da64c76a 100644 --- a/test/embind/test_val_coro.cpp +++ b/test/embind/test_val_coro.cpp @@ -26,14 +26,14 @@ class typed_promise: public val { public: typed_promise(val&& promise): val(std::move(promise)) {} - auto operator co_await() const { + auto operator co_await() && { struct typed_awaiter: public val::awaiter { T await_resume() { return val::awaiter::await_resume().template as(); } }; - return typed_awaiter(*this); + return typed_awaiter(std::move(*this)); } }; From 17c023b7de4ce0826b8c778758b70fe032e1f02a Mon Sep 17 00:00:00 2001 From: Mike Rolig Date: Mon, 26 Feb 2024 11:10:26 -0800 Subject: [PATCH 3/3] Explicitly test the copy code path for co_await. --- test/embind/test_val_coro.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/test/embind/test_val_coro.cpp b/test/embind/test_val_coro.cpp index 3ba54da64c76a..9dc5c59425d78 100644 --- a/test/embind/test_val_coro.cpp +++ b/test/embind/test_val_coro.cpp @@ -46,6 +46,12 @@ val asyncCoro() { // check that awaiting a subclassed promise works and returns the correct type int x = co_await typed_promise(promise_sleep(1, 23)); assert(x == 23); + // check awaiting the same promise twice using copy-path of co_await. + val twice = promise_sleep(1, 30); + val first = co_await twice; + val second = co_await twice; + assert(first.as() == 30); + assert(second.as() == 30); // check that returning value works (checked by JS in tests) co_return 34; }