fix: handle wbg_cast functions by rewriting patch module (#5026)
* fix: handle wbg_cast functions by rewriting patch module * clippy * dont use workspace deps
This commit is contained in:
1 parent
1d2dec1101
commit
88bc12cbb5
4 files changed
+54
-7
No files matched your search
+1
-1
@@ -249,7 +249,7 @@ futures = "0.3.31"
|
||||
futures-channel = "0.3.31"
|
||||
futures-util = { version = "0.3", default-features = false }
|
||||
rustc-hash = "2.1.1"
|
||||
wasm-bindgen = "0.2.100"
|
||||
wasm-bindgen = "0.2.105"
|
||||
wasm-bindgen-futures = "0.4.50"
|
||||
js-sys = "0.3"
|
||||
web-sys = { version = "0.3.77", default-features = false }
|
||||
|
||||
@@ -468,7 +468,7 @@ pub fn create_wasm_jump_table(patch: &Path, cache: &HotpatchModuleCache) -> Resu
|
||||
// `relocation-model=pic` synthesizes can reference the functions via the indirect function table
|
||||
// even if they are not normally synthesized in regular wasm code generation.
|
||||
//
|
||||
// Normally, the dynaic linker setup would resolve GOT.func against the same GOT.func export in
|
||||
// Normally, the dynamic linker setup would resolve GOT.func against the same GOT.func export in
|
||||
// the main module, but we don't have that. Instead, we simply re-parse the main module, aggregate
|
||||
// its ifunc table, and then resolve directly to the index in that table.
|
||||
for (import_id, ifunc_index) in got_funcs {
|
||||
@@ -584,19 +584,23 @@ pub fn create_wasm_jump_table(patch: &Path, cache: &HotpatchModuleCache) -> Resu
|
||||
|
||||
if let Some(table_idx) = name_to_ifunc_old.get(import.name.as_str()) {
|
||||
new.imports.delete(env_func_import);
|
||||
convert_import_to_ifunc_call(
|
||||
convert_func_to_ifunc_call(
|
||||
&mut new,
|
||||
ifunc_table_initializer,
|
||||
func_id,
|
||||
*table_idx,
|
||||
name.clone(),
|
||||
);
|
||||
continue;
|
||||
}
|
||||
|
||||
if name_is_bindgen_symbol(&name) {
|
||||
new.imports.delete(env_func_import);
|
||||
convert_import_to_ifunc_call(&mut new, ifunc_table_initializer, func_id, 0, name);
|
||||
convert_func_to_ifunc_call(&mut new, ifunc_table_initializer, func_id, 0, name);
|
||||
continue;
|
||||
}
|
||||
|
||||
tracing::warn!("[hotpatching]: Symbol slipped through the cracks: {}", name);
|
||||
}
|
||||
|
||||
// Wire up the preserved intrinsic functions that we saved before running wasm-bindgen to the expected
|
||||
@@ -613,7 +617,34 @@ pub fn create_wasm_jump_table(patch: &Path, cache: &HotpatchModuleCache) -> Resu
|
||||
if name_is_bindgen_symbol(&import.name) {
|
||||
let name = import.name.as_str().to_string();
|
||||
new.imports.delete(import_id);
|
||||
convert_import_to_ifunc_call(&mut new, ifunc_table_initializer, func_id, 0, name);
|
||||
convert_func_to_ifunc_call(&mut new, ifunc_table_initializer, func_id, 0, name);
|
||||
}
|
||||
}
|
||||
|
||||
// Rewrite the wbg_cast functions to call the indirect functions from the original module.
|
||||
// This is necessary because wasm-bindgen uses these calls to perform dynamic type casting through
|
||||
// the JS layer. If we don't rewrite these, they end up as calls to `breaks_if_inlined` functions
|
||||
// which are no-ops and get rewritten by the wbindgen post-processing step.
|
||||
//
|
||||
// Here, we find the corresponding wbg_cast function in the old module by name and then rewrite
|
||||
// the patch module's cast function to call the indirect function from the original module.
|
||||
//
|
||||
// See the wbg_cast implementation in wasm-bindgen for more details:
|
||||
// <https://github.com/wasm-bindgen/wasm-bindgen/blob/f61a588f674304964a2062b2307edb304aed4d16/src/rt/mod.rs#L30>
|
||||
let new_func_ids = new.funcs.iter().map(|f| f.id()).collect::<Vec<_>>();
|
||||
for func_id in new_func_ids {
|
||||
let Some(name) = new.funcs.get(func_id).name.as_deref() else {
|
||||
continue;
|
||||
};
|
||||
|
||||
if name.contains("wasm_bindgen4__rt8wbg_cast") && !name.contains("breaks_if_inline") {
|
||||
let name = name.to_string();
|
||||
let old_idx = name_to_ifunc_old
|
||||
.get(&name)
|
||||
.copied()
|
||||
.ok_or_else(|| anyhow::anyhow!("Could not find matching wbg_cast function for [{name}] - must generate new JS bindings."))?;
|
||||
|
||||
convert_func_to_ifunc_call(&mut new, ifunc_table_initializer, func_id, old_idx, name);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -642,8 +673,18 @@ pub fn create_wasm_jump_table(patch: &Path, cache: &HotpatchModuleCache) -> Resu
|
||||
let ifunc_count = name_to_ifunc_new.len() as u64;
|
||||
let mut map = AddressMap::default();
|
||||
for (name, idx) in name_to_ifunc_new.iter() {
|
||||
// Find the corresponding ifunc in the old module by name
|
||||
if let Some(old_idx) = name_to_ifunc_old.get(*name) {
|
||||
map.insert(*old_idx as u64, *idx as u64);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Warn if there might be a null entry
|
||||
if !name.contains("breaks_if_inlined") {
|
||||
tracing::warn!(
|
||||
"[hotpatching]: Failed to find ifunc entry in old module for function: {}",
|
||||
name
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -656,7 +697,7 @@ pub fn create_wasm_jump_table(patch: &Path, cache: &HotpatchModuleCache) -> Resu
|
||||
})
|
||||
}
|
||||
|
||||
fn convert_import_to_ifunc_call(
|
||||
fn convert_func_to_ifunc_call(
|
||||
new: &mut Module,
|
||||
ifunc_table_initializer: TableId,
|
||||
func_id: FunctionId,
|
||||
@@ -1309,7 +1350,6 @@ fn name_is_bindgen_symbol(name: &str) -> bool {
|
||||
|| name.contains("wasm_bindgen..describe..WasmDescribe")
|
||||
|| name.contains("wasm_bindgen..closure..WasmClosure$GT$8describe")
|
||||
|| name.contains("wasm_bindgen7closure16Closure$LT$T$GT$4wrap8describe")
|
||||
|| name.contains("wasm_bindgen4__rt8wbg_")
|
||||
}
|
||||
|
||||
/// Manually parse the data section from a wasm module
|
||||
|
||||
@@ -8,5 +8,7 @@ publish = false
|
||||
|
||||
[dependencies]
|
||||
dioxus = { path = "../../dioxus", features = ["web"] }
|
||||
wasm-bindgen = { version = "0.2.100" }
|
||||
web-sys = { version = "*", features = ["MouseEvent"] }
|
||||
|
||||
[workspace]
|
||||
@@ -6,6 +6,11 @@ const IMAGE: Asset = asset!("/assets/toasts.png");
|
||||
fn app() -> Element {
|
||||
let mut num = use_signal(|| 0);
|
||||
|
||||
// make sure to emit funky closure code in this module to test wasm-bindgen handling
|
||||
let _closures = wasm_bindgen::closure::Closure::<dyn FnMut(web_sys::MouseEvent)>::new(
|
||||
move |event: web_sys::MouseEvent| {},
|
||||
);
|
||||
|
||||
rsx! {
|
||||
document::Link {
|
||||
href: CSS,
|
||||
|
||||
Reference in new issue
Block a user