Skip to content

Commit 9074e03

Browse files
refactor(bindgen): resource lift handling
1 parent 17485b2 commit 9074e03

1 file changed

Lines changed: 125 additions & 72 deletions

File tree

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

Lines changed: 125 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -1980,77 +1980,104 @@ impl Bindgen for FunctionBindgen<'_> {
19801980
.intrinsic(Intrinsic::Resource(ResourceIntrinsic::ResourceTableRemove));
19811981
let rsc_flag = self
19821982
.intrinsic(Intrinsic::Resource(ResourceIntrinsic::ResourceTableFlag));
1983-
if !imported {
1984-
let symbol_resource_handle =
1985-
self.intrinsic(Intrinsic::SymbolResourceHandle);
1986-
1987-
uwriteln!(
1988-
self.src,
1989-
"var {rsc} = new.target === {local_name} ? this : Object.create({local_name}.prototype);"
1990-
);
1983+
let symbol_resource_handle =
1984+
self.intrinsic(Intrinsic::SymbolResourceHandle);
1985+
let empty_func =
1986+
self.intrinsic(Intrinsic::JsHelper(JsHelperIntrinsic::EmptyFunc));
19911987

1992-
if is_own {
1993-
// Sending an own handle out to JS as a return value - set up finalizer and disposal.
1994-
let empty_func = self
1995-
.intrinsic(Intrinsic::JsHelper(JsHelperIntrinsic::EmptyFunc));
1996-
uwriteln!(self.src,
1997-
"Object.defineProperty({rsc}, {symbol_resource_handle}, {{ writable: true, value: {handle} }});
1998-
finalizationRegistry{tid}.register({rsc}, {handle}, {rsc});");
1999-
if let Some(dtor) = dtor_name {
1988+
match (imported, is_own) {
1989+
// Non-imported owned resource
1990+
(_imported @ false, _owned @ true) => {
1991+
let dtor_setup_js = if let Some(dtor) = dtor_name {
20001992
// The Symbol.dispose function gets disabled on drop, so we can rely on the own handle remaining valid.
2001-
uwriteln!(
2002-
self.src,
2003-
"Object.defineProperty({rsc}, {symbol_dispose}, {{ writable: true, value: function () {{
1993+
format!(
1994+
r#",
1995+
Object.defineProperty({rsc}, {symbol_dispose}, {{ writable: true, value: function () {{
20041996
finalizationRegistry{tid}.unregister({rsc});
20051997
{rsc_table_remove}(handleTable{tid}, {handle});
20061998
{rsc}[{symbol_dispose}] = {empty_func};
20071999
{rsc}[{symbol_resource_handle}] = undefined;
20082000
{dtor}(handleTable{tid}[({handle} << 1) + 1] & ~{rsc_flag});
2009-
}}}});"
2010-
);
2001+
}}}});
2002+
"#
2003+
)
20112004
} else {
20122005
// Set up Symbol.dispose for borrows to allow its call, even though it does nothing.
2013-
uwriteln!(
2014-
self.src,
2015-
"Object.defineProperty({rsc}, {symbol_dispose}, {{ writable: true, value: {empty_func} }});",
2016-
);
2017-
}
2018-
} else {
2006+
format!(
2007+
"Object.defineProperty({rsc}, {symbol_dispose}, {{ writable: true, value: {empty_func} }});"
2008+
)
2009+
};
2010+
2011+
// Sending an own handle out to JS as a return value - set up finalizer and disposal.
2012+
uwriteln!(
2013+
self.src,
2014+
r#"
2015+
var {rsc} = new.target === {local_name} ? this : Object.create({local_name}.prototype);
2016+
Object.defineProperty({rsc}, {symbol_resource_handle}, {{ writable: true, value: {handle} }});
2017+
finalizationRegistry{tid}.register({rsc}, {handle}, {rsc});
2018+
{dtor_setup_js}
2019+
"#
2020+
);
2021+
}
2022+
2023+
// Non-imported borrowed resource
2024+
(_imported @ false, _owned @ false) => {
20192025
// Borrow handles of local resources have rep handles, which we carry through here.
20202026
uwriteln!(
20212027
self.src,
20222028
"Object.defineProperty({rsc}, {symbol_resource_handle}, {{ writable: true, value: {handle} }});"
20232029
);
20242030
}
2025-
} else {
2026-
let rep = format!("rep{}", self.tmp());
2027-
// Imported handles either lift as instance capture from a previous lowering,
2028-
// or we create a new JS class to represent it.
2029-
let symbol_resource_rep = self.intrinsic(Intrinsic::SymbolResourceRep);
2030-
let symbol_resource_handle =
2031-
self.intrinsic(Intrinsic::SymbolResourceHandle);
20322031

2033-
uwriteln!(
2034-
self.src,
2035-
r#"
2032+
// Imported owned resource
2033+
(_imported @ true, _owned @ true) => {
2034+
let rep = format!("rep{}", self.tmp());
2035+
// Imported handles either lift as instance capture from a previous lowering,
2036+
// or we create a new JS class to represent it.
2037+
let symbol_resource_rep =
2038+
self.intrinsic(Intrinsic::SymbolResourceRep);
2039+
let symbol_resource_handle =
2040+
self.intrinsic(Intrinsic::SymbolResourceHandle);
2041+
2042+
uwriteln!(
2043+
self.src,
2044+
r#"
20362045
var {rep} = handleTable{tid}[({handle} << 1) + 1] & ~{rsc_flag};
20372046
var {rsc} = captureTable{rid}.get({rep});
20382047
if (!{rsc}) {{
20392048
{rsc} = Object.create({local_name}.prototype);
20402049
Object.defineProperty({rsc}, {symbol_resource_handle}, {{ writable: true, value: {handle} }});
20412050
Object.defineProperty({rsc}, {symbol_resource_rep}, {{ writable: true, value: {rep} }});
2051+
}} else {{
2052+
captureTable{rid}.delete({rep});
20422053
}}
2054+
// NOTE: owned lifting is a transfer to JS, so existing own handle must be dropped
2055+
{rsc_table_remove}(handleTable{tid}, {handle});
20432056
"#,
2044-
);
2057+
);
2058+
}
2059+
2060+
// Imported borrowed resource
2061+
(_imported @ true, _owned @ false) => {
2062+
let rep = format!("rep{}", self.tmp());
2063+
// Imported handles either lift as instance capture from a previous lowering,
2064+
// or we create a new JS class to represent it.
2065+
let symbol_resource_rep =
2066+
self.intrinsic(Intrinsic::SymbolResourceRep);
2067+
let symbol_resource_handle =
2068+
self.intrinsic(Intrinsic::SymbolResourceHandle);
20452069

2046-
if is_own {
2047-
// An own lifting is a transfer to JS, so existing own handle is implicitly dropped.
20482070
uwriteln!(
20492071
self.src,
2050-
"else {{
2051-
captureTable{rid}.delete({rep});
2052-
}}
2053-
{rsc_table_remove}(handleTable{tid}, {handle});"
2072+
r#"
2073+
var {rep} = handleTable{tid}[({handle} << 1) + 1] & ~{rsc_flag};
2074+
var {rsc} = captureTable{rid}.get({rep});
2075+
if (!{rsc}) {{
2076+
{rsc} = Object.create({local_name}.prototype);
2077+
Object.defineProperty({rsc}, {symbol_resource_handle}, {{ writable: true, value: {handle} }});
2078+
Object.defineProperty({rsc}, {symbol_resource_rep}, {{ writable: true, value: {rep} }});
2079+
}}
2080+
"#,
20542081
);
20552082
}
20562083
}
@@ -2080,52 +2107,78 @@ impl Bindgen for FunctionBindgen<'_> {
20802107
let prefix = prefix.as_deref().unwrap_or("");
20812108
let lower_camel = resource_name.to_lower_camel_case();
20822109

2083-
if !imported {
2084-
if is_own {
2085-
uwriteln!(
2086-
self.src,
2087-
"var {rsc} = repTable.get($resource_{prefix}rep${lower_camel}({handle})).rep;"
2088-
);
2110+
match (imported, is_own) {
2111+
// Non-imported, owned guest resource
2112+
(_imported @ false, _owned @ true) => {
20892113
uwrite!(
20902114
self.src,
20912115
r#"
2116+
const {rsc} = repTable.get($resource_{prefix}rep${lower_camel}({handle})).rep;
20922117
repTable.delete({handle});
20932118
delete {rsc}[{symbol_resource_handle}];
20942119
finalizationRegistry_export${prefix}{lower_camel}.unregister({rsc});
20952120
"#
20962121
);
2097-
} else {
2098-
uwriteln!(self.src, "var {rsc} = repTable.get({handle}).rep;");
20992122
}
2100-
} else {
2101-
let upper_camel = resource_name.to_upper_camel_case();
21022123

2103-
uwrite!(
2104-
self.src,
2105-
r#"
2106-
var {rsc} = new.target === import_{prefix}{upper_camel} ? this : Object.create(import_{prefix}{upper_camel}.prototype);
2107-
Object.defineProperty({rsc}, {symbol_resource_handle}, {{ writable: true, value: {handle} }});
2108-
"#
2109-
);
2124+
// Non-imported, borrowed guest resource
2125+
(_imported @ false, _owned @ false) => {
2126+
uwriteln!(self.src, "const {rsc} = repTable.get({handle}).rep;");
2127+
}
21102128

2111-
uwriteln!(
2112-
self.src,
2113-
"finalizationRegistry_import${prefix}{lower_camel}.register({rsc}, {handle}, {rsc});",
2114-
);
2129+
// Imported, owned guest resource
2130+
(_imported @ true, _owned @ true) => {
2131+
let upper_camel = resource_name.to_upper_camel_case();
21152132

2116-
if !is_own {
2117-
let cur_resource_borrows = self.intrinsic(Intrinsic::Resource(
2118-
ResourceIntrinsic::CurResourceBorrows,
2119-
));
2120-
uwriteln!(
2133+
uwrite!(
2134+
self.src,
2135+
r#"
2136+
let {rsc};
2137+
if (new.target === import_{prefix}{upper_camel}) {{
2138+
{rsc} = this;
2139+
}} else {{
2140+
{rsc} = Object.create(import_{prefix}{upper_camel}.prototype);
2141+
}}
2142+
Object.defineProperty({rsc}, {symbol_resource_handle}, {{ writable: true, value: {handle} }});
2143+
finalizationRegistry_import${prefix}{lower_camel}.register({rsc}, {handle}, {rsc});
2144+
"#
2145+
);
2146+
}
2147+
2148+
// Imported, borrowed guest resource
2149+
(_imported @ true, _owned @ false) => {
2150+
let upper_camel = resource_name.to_upper_camel_case();
2151+
2152+
uwrite!(
21212153
self.src,
2122-
"{cur_resource_borrows}.push({{ rsc: {rsc}, drop: $resource_import${prefix}drop${lower_camel} }});"
2154+
r#"
2155+
let {rsc};
2156+
if (new.target === import_{prefix}{upper_camel}) {{
2157+
{rsc} = this;
2158+
}} else {{
2159+
{rsc} = Object.create(import_{prefix}{upper_camel}.prototype);
2160+
}}
2161+
Object.defineProperty({rsc}, {symbol_resource_handle}, {{ writable: true, value: {handle} }});
2162+
finalizationRegistry_import${prefix}{lower_camel}.register({rsc}, {handle}, {rsc});
2163+
"#
21232164
);
2124-
self.clear_resource_borrows = true;
2165+
2166+
// TODO(fix): should this be similar to host and *not* be here, but apply no matter what?
2167+
if !is_own {
2168+
let cur_resource_borrows = self.intrinsic(Intrinsic::Resource(
2169+
ResourceIntrinsic::CurResourceBorrows,
2170+
));
2171+
uwriteln!(
2172+
self.src,
2173+
"{cur_resource_borrows}.push({{ rsc: {rsc}, drop: $resource_import${prefix}drop${lower_camel} }});"
2174+
);
2175+
self.clear_resource_borrows = true;
2176+
}
21252177
}
21262178
}
21272179
}
21282180
}
2181+
21292182
results.push(rsc);
21302183
}
21312184

0 commit comments

Comments
 (0)