Skip to content

Commit 59f1b55

Browse files
authored
feat: JS resource method dynamic dispatch (#390)
1 parent d28833e commit 59f1b55

File tree

2 files changed

+67
-47
lines changed

2 files changed

+67
-47
lines changed

crates/js-component-bindgen/src/function_bindgen.rs

+15-7
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,7 @@ pub struct FunctionBindgen<'a> {
8181
pub tracing_prefix: Option<&'a String>,
8282
pub encoding: StringEncoding,
8383
pub callee: &'a str,
84+
pub callee_resource_dynamic: bool,
8485
pub resolve: &'a Resolve,
8586
}
8687

@@ -1070,24 +1071,31 @@ impl Bindgen for FunctionBindgen<'_> {
10701071

10711072
Instruction::CallInterface { func } => {
10721073
let results_length = func.results.len();
1074+
let call = if self.callee_resource_dynamic {
1075+
format!(
1076+
"{}.{}({})",
1077+
operands[0],
1078+
self.callee,
1079+
operands[1..].join(", ")
1080+
)
1081+
} else {
1082+
format!("{}({})", self.callee, operands.join(", "))
1083+
};
10731084
if self.err == ErrHandling::ResultCatchHandler {
10741085
let err_payload = self.intrinsic(Intrinsic::GetErrorPayload);
10751086
uwriteln!(
10761087
self.src,
10771088
"let ret;
10781089
try {{
1079-
ret = {{ tag: 'ok', val: {}({}) }};
1090+
ret = {{ tag: 'ok', val: {call} }};
10801091
}} catch (e) {{
1081-
ret = {{ tag: 'err', val: {}(e) }};
1082-
}}",
1083-
self.callee,
1084-
operands.join(", "),
1085-
err_payload,
1092+
ret = {{ tag: 'err', val: {err_payload}(e) }};
1093+
}}"
10861094
);
10871095
results.push("ret".to_string());
10881096
} else {
10891097
self.bind_results(results_length, results);
1090-
uwriteln!(self.src, "{}({});", self.callee, operands.join(", "));
1098+
uwriteln!(self.src, "{call};");
10911099
}
10921100

10931101
if let Some(prefix) = self.tracing_prefix {

crates/js-component-bindgen/src/transpile_bindgen.rs

+52-40
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,16 @@ pub enum InstantiationMode {
8383
Sync,
8484
}
8585

86+
/// Internal Bindgen calling convention
87+
enum CallType {
88+
/// Standard calls - inner function is called directly with parameters
89+
Standard,
90+
/// Exported resource method calls - this is passed as the first argument
91+
FirstArgIsThis,
92+
/// Imported resource method calls - callee is a member of the parameter
93+
CalleeResourceDispatch,
94+
}
95+
8696
struct JsBindgen<'a> {
8797
local_names: LocalNames,
8898

@@ -959,10 +969,9 @@ impl<'a> Instantiator<'a, '_> {
959969
WorldItem::Type(_) => unreachable!(),
960970
};
961971

962-
let callee_name = match func.kind {
963-
FunctionKind::Freestanding => {
964-
let callee_name = self
965-
.gen
972+
let (callee_name, call_type) = match func.kind {
973+
FunctionKind::Freestanding => (
974+
self.gen
966975
.local_names
967976
.get_or_create(
968977
&format!(
@@ -974,40 +983,39 @@ impl<'a> Instantiator<'a, '_> {
974983
&func.name,
975984
)
976985
.0
977-
.to_string();
978-
callee_name
979-
}
980-
FunctionKind::Method(ty) => format!(
981-
"{}.prototype.{}.call",
982-
match &self.imports_resource_map[&ty].data {
983-
ResourceData::Host { local_name, .. } => {
984-
self.gen.esm_bindgen.ensure_import_binding(local_name);
985-
local_name
986-
}
987-
ResourceData::Guest { .. } => unreachable!(),
988-
},
989-
func.item_name().to_lower_camel_case()
986+
.to_string(),
987+
CallType::Standard,
990988
),
991-
FunctionKind::Static(ty) => format!(
992-
"{}.{}",
993-
match &self.imports_resource_map[&ty].data {
994-
ResourceData::Host { local_name, .. } => {
995-
self.gen.esm_bindgen.ensure_import_binding(local_name);
996-
local_name
997-
}
998-
ResourceData::Guest { .. } => unreachable!(),
999-
},
1000-
func.item_name().to_lower_camel_case()
989+
FunctionKind::Method(_) => (
990+
func.item_name().to_lower_camel_case(),
991+
CallType::CalleeResourceDispatch,
1001992
),
1002-
FunctionKind::Constructor(ty) => format!(
1003-
"new {}",
1004-
match &self.imports_resource_map[&ty].data {
1005-
ResourceData::Host { local_name, .. } => {
1006-
self.gen.esm_bindgen.ensure_import_binding(local_name);
1007-
local_name
1008-
}
1009-
ResourceData::Guest { .. } => unreachable!(),
1010-
},
993+
FunctionKind::Static(ty) => (
994+
format!(
995+
"{}.{}",
996+
match &self.imports_resource_map[&ty].data {
997+
ResourceData::Host { local_name, .. } => {
998+
self.gen.esm_bindgen.ensure_import_binding(local_name);
999+
local_name
1000+
}
1001+
ResourceData::Guest { .. } => unreachable!(),
1002+
},
1003+
func.item_name().to_lower_camel_case()
1004+
),
1005+
CallType::Standard,
1006+
),
1007+
FunctionKind::Constructor(ty) => (
1008+
format!(
1009+
"new {}",
1010+
match &self.imports_resource_map[&ty].data {
1011+
ResourceData::Host { local_name, .. } => {
1012+
self.gen.esm_bindgen.ensure_import_binding(local_name);
1013+
local_name
1014+
}
1015+
ResourceData::Guest { .. } => unreachable!(),
1016+
},
1017+
),
1018+
CallType::Standard,
10111019
),
10121020
};
10131021

@@ -1020,7 +1028,7 @@ impl<'a> Instantiator<'a, '_> {
10201028
uwrite!(self.src.js, "\nfunction trampoline{}", trampoline.as_u32());
10211029
self.bindgen(
10221030
nparams,
1023-
false,
1031+
call_type,
10241032
if import_name.is_empty() {
10251033
None
10261034
} else {
@@ -1290,7 +1298,7 @@ impl<'a> Instantiator<'a, '_> {
12901298
fn bindgen(
12911299
&mut self,
12921300
nparams: usize,
1293-
this_ref: bool,
1301+
call_type: CallType,
12941302
module_name: Option<&str>,
12951303
callee: &str,
12961304
opts: &CanonicalOptions,
@@ -1308,7 +1316,7 @@ impl<'a> Instantiator<'a, '_> {
13081316
let mut params = Vec::new();
13091317
let mut first = true;
13101318
for i in 0..nparams {
1311-
if i == 0 && this_ref {
1319+
if i == 0 && matches!(call_type, CallType::FirstArgIsThis) {
13121320
params.push("this".into());
13131321
continue;
13141322
}
@@ -1377,6 +1385,7 @@ impl<'a> Instantiator<'a, '_> {
13771385
block_storage: Vec::new(),
13781386
blocks: Vec::new(),
13791387
callee,
1388+
callee_resource_dynamic: matches!(call_type, CallType::CalleeResourceDispatch),
13801389
memory: memory.as_ref(),
13811390
realloc: realloc.as_ref(),
13821391
tmp: 0,
@@ -1706,7 +1715,10 @@ impl<'a> Instantiator<'a, '_> {
17061715
let callee = self.core_def(def);
17071716
self.bindgen(
17081717
func.params.len(),
1709-
matches!(func.kind, FunctionKind::Method(_)),
1718+
match func.kind {
1719+
FunctionKind::Method(_) => CallType::FirstArgIsThis,
1720+
_ => CallType::Standard,
1721+
},
17101722
if export_name.is_empty() {
17111723
None
17121724
} else {

0 commit comments

Comments
 (0)