Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 3 additions & 4 deletions crates/core/src/abi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1329,7 +1329,9 @@ impl<'a, B: Bindgen> Generator<'a, B> {
// (statically) and then write the result into that
// memory, returning the pointer at the end.
(_lower_to_memory @ true, _, variant) => match variant {
AbiVariant::GuestExport | AbiVariant::GuestExportAsync => {
AbiVariant::GuestExport
| AbiVariant::GuestExportAsync
| AbiVariant::GuestExportAsyncStackful => {
let ElementInfo { size, align } =
self.bindgen.sizes().params(&func.result);
let ptr = self.bindgen.return_pointer(size, align);
Expand All @@ -1347,9 +1349,6 @@ impl<'a, B: Bindgen> Generator<'a, B> {
func_name = func.name,
)
}
AbiVariant::GuestExportAsyncStackful => {
todo!("stackful exports are not yet supported")
}
},
}

Expand Down
70 changes: 52 additions & 18 deletions crates/go/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,16 @@ pub struct Opts {
#[cfg_attr(feature = "clap", clap(long))]
pub print_remote_pkg_version: bool,

/// If true, async exports are stackful (`[async-lift-stackful]`) instead of
/// callback-based.
///
/// A stackful export runs on its own stack and may block on a waitable
/// set. The generated code does not export a `[callback]` function. This
/// needs a runtime that can block a thread, such as TinyGo with
/// cooperative threads.
#[cfg_attr(feature = "clap", clap(long))]
pub stackful_exports: bool,

/// When generating Go package names, include the WIT package version even
/// if only one version of that package is referenced by the specified
/// world.
Expand Down Expand Up @@ -1313,7 +1323,14 @@ func {camel}({go_params}) {go_results} {{

let async_ = self.opts.async_.is_async(resolve, interface, func, false);

let (variant, prefix) = if async_ {
let stackful = async_ && self.opts.stackful_exports;

let (variant, prefix) = if stackful {
(
AbiVariant::GuestExportAsyncStackful,
"[async-lift-stackful]",
)
} else if async_ {
(AbiVariant::GuestExportAsync, "[async-lift]")
} else {
(AbiVariant::GuestExport, "")
Expand Down Expand Up @@ -1398,30 +1415,47 @@ func {camel}({go_params}) {go_results} {{
.collect::<Vec<_>>()
.join(", ");

(
if abi::guest_export_needs_post_return(resolve, func) {
format!(
"{PINNER} := &runtime.Pinner{{}}
defer {PINNER}.Unpin()"
)
} else {
String::new()
},
let pinner = if abi::guest_export_needs_post_return(resolve, func) {
format!(
"
"{PINNER} := &runtime.Pinner{{}}
defer {PINNER}.Unpin()"
)
} else {
String::new()
};
let task_return = format!(
"//go:wasmimport [export]{module} [task-return]{function}
func wasm_export_task_return_{name}({task_return_params})
"
);
if stackful {
(
pinner,
format!(
"

{task_return}"
),
"witAsync.Run(func() {",
"})",
)
} else {
(
pinner,
format!(
"

//go:wasmexport [callback]{prefix}{export_name}
func wasm_export_callback_{name}(event0 uint32, event1 uint32, event2 uint32) uint32 {{
return witAsync.Callback(event0, event1, event2)
}}

//go:wasmimport [export]{module} [task-return]{function}
func wasm_export_task_return_{name}({task_return_params})
"
),
"return int32(witAsync.Run(func() {",
"}))",
)
{task_return}"
),
"return int32(witAsync.Run(func() {",
"}))",
)
}
} else if abi::guest_export_needs_post_return(resolve, func) {
(
format!("{PINNER} := &{SYNC_EXPORT_PINNER}"),
Expand Down
Loading