Skip to content

Commit

Permalink
feat: experimental JSPI async option for jco transpile (#561)
Browse files Browse the repository at this point in the history
  • Loading branch information
calvinrp authored Jan 31, 2025
1 parent 3ed579b commit 5f06630
Show file tree
Hide file tree
Showing 21 changed files with 1,430 additions and 182 deletions.
13 changes: 13 additions & 0 deletions crates/js-component-bindgen-component/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,17 @@ impl From<BindingsMode> for js_component_bindgen::BindingsMode {
}
}

impl From<AsyncMode> for js_component_bindgen::AsyncMode {
fn from(value: AsyncMode) -> Self {
match value {
AsyncMode::Sync => js_component_bindgen::AsyncMode::Sync,
AsyncMode::Jspi(AsyncImportsExports { imports, exports }) => {
js_component_bindgen::AsyncMode::JavaScriptPromiseIntegration { imports, exports }
}
}
}
}

struct JsComponentBindgenComponent;

export!(JsComponentBindgenComponent);
Expand All @@ -76,6 +87,7 @@ impl Guest for JsComponentBindgenComponent {
multi_memory: options.multi_memory.unwrap_or(false),
import_bindings: options.import_bindings.map(Into::into),
guest: options.guest.unwrap_or(false),
async_mode: options.async_mode.map(Into::into),
};

let js_component_bindgen::Transpiled {
Expand Down Expand Up @@ -162,6 +174,7 @@ impl Guest for JsComponentBindgenComponent {
multi_memory: false,
import_bindings: None,
guest: opts.guest.unwrap_or(false),
async_mode: opts.async_mode.map(Into::into),
};

let files = generate_types(name, resolve, world, opts).map_err(|e| e.to_string())?;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,13 +58,29 @@ world js-component-bindgen {
/// Whether to generate namespaced exports like `foo as "local:package/foo"`.
/// These exports can break typescript builds.
no-namespaced-exports: option<bool>,

/// Whether to generate module declarations like `declare module "local:package/foo" {...`.
guest: option<bool>,

/// Whether to output core Wasm utilizing multi-memory or to polyfill
/// this handling.
multi-memory: option<bool>,

/// Configure whether to use `async` imports or exports with
/// JavaScript Promise Integration (JSPI).
async-mode: option<async-mode>,
}

record async-imports-exports {
imports: list<string>,
exports: list<string>,
}

variant async-mode {
/// default to sync mode
sync,
/// use JavaScript Promise Integration (JSPI)
jspi(async-imports-exports),
}

variant wit {
Expand Down Expand Up @@ -96,6 +112,9 @@ world js-component-bindgen {
features: option<enabled-feature-set>,
/// Whether to generate module declarations like `declare module "local:package/foo" {...`.
guest: option<bool>,
/// Configure whether to use `async` imports or exports with
/// JavaScript Promise Integration (JSPI).
async-mode: option<async-mode>,
}

enum export-type {
Expand Down
18 changes: 15 additions & 3 deletions crates/js-component-bindgen/src/function_bindgen.rs
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ pub struct FunctionBindgen<'a> {
pub callee: &'a str,
pub callee_resource_dynamic: bool,
pub resolve: &'a Resolve,
pub is_async: bool,
}

impl FunctionBindgen<'_> {
Expand Down Expand Up @@ -1048,7 +1049,13 @@ impl Bindgen for FunctionBindgen<'_> {
Instruction::CallWasm { sig, .. } => {
let sig_results_length = sig.results.len();
self.bind_results(sig_results_length, results);
uwriteln!(self.src, "{}({});", self.callee, operands.join(", "));
let maybe_async_await = if self.is_async { "await " } else { "" };
uwriteln!(
self.src,
"{maybe_async_await}{}({});",
self.callee,
operands.join(", ")
);

if let Some(prefix) = self.tracing_prefix {
let to_result_string = self.intrinsic(Intrinsic::ToResultString);
Expand All @@ -1066,15 +1073,20 @@ impl Bindgen for FunctionBindgen<'_> {

Instruction::CallInterface { func } => {
let results_length = func.results.len();
let maybe_async_await = if self.is_async { "await " } else { "" };
let call = if self.callee_resource_dynamic {
format!(
"{}.{}({})",
"{maybe_async_await}{}.{}({})",
operands[0],
self.callee,
operands[1..].join(", ")
)
} else {
format!("{}({})", self.callee, operands.join(", "))
format!(
"{maybe_async_await}{}({})",
self.callee,
operands.join(", ")
)
};
if self.err == ErrHandling::ResultCatchHandler {
// result<_, string> allows JS error coercion only, while
Expand Down
1 change: 1 addition & 0 deletions crates/js-component-bindgen/src/intrinsics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -671,6 +671,7 @@ impl Intrinsic {
"hasOwnProperty",
"i32ToF32",
"i64ToF64",
"imports",
"instantiateCore",
"isLE",
"resourceCallBorrows",
Expand Down
2 changes: 1 addition & 1 deletion crates/js-component-bindgen/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ pub mod function_bindgen;
pub mod intrinsics;
pub mod names;
pub mod source;
pub use transpile_bindgen::{BindingsMode, InstantiationMode, TranspileOpts};
pub use transpile_bindgen::{AsyncMode, BindingsMode, InstantiationMode, TranspileOpts};

use anyhow::Result;
use transpile_bindgen::transpile_bindgen;
Expand Down
Loading

0 comments on commit 5f06630

Please sign in to comment.