@@ -114,7 +114,7 @@ pub(super) fn compile(module: &mut Module<'_>, adapter: &AdapterData) {
114114 )
115115 }
116116
117- let start_adapter = |module : & mut Module , param_globals| {
117+ let async_start_adapter = |module : & mut Module , param_globals| {
118118 let sig = module. types . async_start_signature ( & adapter. lift ) ;
119119 let ty = module. core_types . function ( & sig. params , & sig. results ) ;
120120 let result = module. funcs . push ( Function :: new (
@@ -131,7 +131,7 @@ pub(super) fn compile(module: &mut Module<'_>, adapter: &AdapterData) {
131131 result
132132 } ;
133133
134- let return_adapter = |module : & mut Module , result_globals| {
134+ let async_return_adapter = |module : & mut Module , result_globals| {
135135 let sig = module. types . async_return_signature ( & adapter. lift ) ;
136136 let ty = module. core_types . function ( & sig. params , & sig. results ) ;
137137 let result = module. funcs . push ( Function :: new (
@@ -150,12 +150,29 @@ pub(super) fn compile(module: &mut Module<'_>, adapter: &AdapterData) {
150150
151151 match ( adapter. lower . options . async_ , adapter. lift . options . async_ ) {
152152 ( false , false ) => {
153+ // We can adapt sync->sync case with only minimal use of intrinsics,
154+ // e.g. resource enter and exit calls as needed.
153155 let ( compiler, lower_sig, lift_sig) = compiler ( module, adapter) ;
154156 compiler. compile_sync_to_sync_adapter ( adapter, & lower_sig, & lift_sig)
155157 }
156158 ( true , true ) => {
157- let start = start_adapter ( module, None ) ;
158- let return_ = return_adapter ( module, None ) ;
159+ // In the async->async case, we must compile a couple of helper functions:
160+ //
161+ // - `async-start`: copies the parameters from the caller to the callee
162+ // - `async-return`: copies the result from the callee to the caller
163+ //
164+ // Unlike synchronous calls, the above operations are asynchronous
165+ // and subject to backpressure. If the callee is not yet ready to
166+ // handle a new call, the `async-start` function will not be called
167+ // immediately. Instead, control will return to the caller,
168+ // allowing it to do other work while waiting for this call to make
169+ // progress. Once the callee indicates it is ready, `async-start`
170+ // will be called, and sometime later (possibly after various task
171+ // switch events), when the callee has produced a result, it will
172+ // call `async-return` via the `task.return` intrinsic, at which
173+ // point a `STATUS_RETURNED` event will be delivered to the caller.
174+ let start = async_start_adapter ( module, None ) ;
175+ let return_ = async_return_adapter ( module, None ) ;
159176 let ( compiler, _, lift_sig) = compiler ( module, adapter) ;
160177 compiler. compile_async_to_async_adapter (
161178 adapter,
@@ -165,6 +182,18 @@ pub(super) fn compile(module: &mut Module<'_>, adapter: &AdapterData) {
165182 ) ;
166183 }
167184 ( false , true ) => {
185+ // Like the async->async case above, for the sync->async case we
186+ // also need `async-start` and `async-return` helper functions to
187+ // allow the callee to asynchronously "pull" the parameters and
188+ // "push" the results when it is ready.
189+ //
190+ // However, since the caller is using the synchronous ABI, the
191+ // parameters may have been passed via the stack rather than linear
192+ // memory. In that case, we use global variables to store them such
193+ // that they can be retrieved by the `async-start` function.
194+ // Similarly, the `async-return` function may write its result to
195+ // global variables from which the adapter function can read and
196+ // return them via the stack to the caller.
168197 let lower_sig = module. types . signature ( & adapter. lower , Context :: Lower ) ;
169198 let param_globals = if lower_sig. params_indirect {
170199 None
@@ -196,8 +225,8 @@ pub(super) fn compile(module: &mut Module<'_>, adapter: &AdapterData) {
196225 )
197226 } ;
198227
199- let start = start_adapter ( module, param_globals. as_deref ( ) ) ;
200- let return_ = return_adapter ( module, result_globals. as_deref ( ) ) ;
228+ let start = async_start_adapter ( module, param_globals. as_deref ( ) ) ;
229+ let return_ = async_return_adapter ( module, result_globals. as_deref ( ) ) ;
201230 let ( compiler, _, lift_sig) = compiler ( module, adapter) ;
202231 compiler. compile_sync_to_async_adapter (
203232 adapter,
@@ -209,9 +238,28 @@ pub(super) fn compile(module: &mut Module<'_>, adapter: &AdapterData) {
209238 ) ;
210239 }
211240 ( true , false ) => {
241+ // As with the async->async and sync->async cases above, for the
242+ // async->sync case we use `async-start` and `async-return` helper
243+ // functions. Here, those functions allow the host to enforce
244+ // backpressure in the case where the callee instance already has
245+ // another synchronous call in progress, in which case we can't
246+ // start a new one until the current one (and any others already
247+ // waiting in line behind it) has completed.
248+ //
249+ // In the case of backpressure, we'll return control to the caller
250+ // immediately so it can do other work. Later, once the callee is
251+ // ready, the host will call the `async-start` function to retrieve
252+ // the parameters and pass them to the callee. At that point, the
253+ // callee may block on a host call, at which point the host will
254+ // suspend the fiber it is running on and allow the caller (or any
255+ // other ready instance) to run concurrently with the blocked
256+ // callee. Once the callee finally returns, the host will call the
257+ // `async-return` function to write the result to the caller's
258+ // linear memory and deliver a `STATUS_RETURNED` event to the
259+ // caller.
212260 let lift_sig = module. types . signature ( & adapter. lift , Context :: Lift ) ;
213- let start = start_adapter ( module, None ) ;
214- let return_ = return_adapter ( module, None ) ;
261+ let start = async_start_adapter ( module, None ) ;
262+ let return_ = async_return_adapter ( module, None ) ;
215263 let ( compiler, ..) = compiler ( module, adapter) ;
216264 compiler. compile_async_to_sync_adapter (
217265 adapter,
0 commit comments