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-channel = "0.3.31"
|
||||||
futures-util = { version = "0.3", default-features = false }
|
futures-util = { version = "0.3", default-features = false }
|
||||||
rustc-hash = "2.1.1"
|
rustc-hash = "2.1.1"
|
||||||
wasm-bindgen = "0.2.100"
|
wasm-bindgen = "0.2.105"
|
||||||
wasm-bindgen-futures = "0.4.50"
|
wasm-bindgen-futures = "0.4.50"
|
||||||
js-sys = "0.3"
|
js-sys = "0.3"
|
||||||
web-sys = { version = "0.3.77", default-features = false }
|
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
|
// `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.
|
// 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
|
// 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.
|
// its ifunc table, and then resolve directly to the index in that table.
|
||||||
for (import_id, ifunc_index) in got_funcs {
|
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()) {
|
if let Some(table_idx) = name_to_ifunc_old.get(import.name.as_str()) {
|
||||||
new.imports.delete(env_func_import);
|
new.imports.delete(env_func_import);
|
||||||
convert_import_to_ifunc_call(
|
convert_func_to_ifunc_call(
|
||||||
&mut new,
|
&mut new,
|
||||||
ifunc_table_initializer,
|
ifunc_table_initializer,
|
||||||
func_id,
|
func_id,
|
||||||
*table_idx,
|
*table_idx,
|
||||||
name.clone(),
|
name.clone(),
|
||||||
);
|
);
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if name_is_bindgen_symbol(&name) {
|
if name_is_bindgen_symbol(&name) {
|
||||||
new.imports.delete(env_func_import);
|
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
|
// 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) {
|
if name_is_bindgen_symbol(&import.name) {
|
||||||
let name = import.name.as_str().to_string();
|
let name = import.name.as_str().to_string();
|
||||||
new.imports.delete(import_id);
|
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 ifunc_count = name_to_ifunc_new.len() as u64;
|
||||||
let mut map = AddressMap::default();
|
let mut map = AddressMap::default();
|
||||||
for (name, idx) in name_to_ifunc_new.iter() {
|
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) {
|
if let Some(old_idx) = name_to_ifunc_old.get(*name) {
|
||||||
map.insert(*old_idx as u64, *idx as u64);
|
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,
|
new: &mut Module,
|
||||||
ifunc_table_initializer: TableId,
|
ifunc_table_initializer: TableId,
|
||||||
func_id: FunctionId,
|
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..describe..WasmDescribe")
|
||||||
|| name.contains("wasm_bindgen..closure..WasmClosure$GT$8describe")
|
|| name.contains("wasm_bindgen..closure..WasmClosure$GT$8describe")
|
||||||
|| name.contains("wasm_bindgen7closure16Closure$LT$T$GT$4wrap8describe")
|
|| name.contains("wasm_bindgen7closure16Closure$LT$T$GT$4wrap8describe")
|
||||||
|| name.contains("wasm_bindgen4__rt8wbg_")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Manually parse the data section from a wasm module
|
/// Manually parse the data section from a wasm module
|
||||||
|
|||||||
@@ -8,5 +8,7 @@ publish = false
|
|||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
dioxus = { path = "../../dioxus", features = ["web"] }
|
dioxus = { path = "../../dioxus", features = ["web"] }
|
||||||
|
wasm-bindgen = { version = "0.2.100" }
|
||||||
|
web-sys = { version = "*", features = ["MouseEvent"] }
|
||||||
|
|
||||||
[workspace]
|
[workspace]
|
||||||
@@ -6,6 +6,11 @@ const IMAGE: Asset = asset!("/assets/toasts.png");
|
|||||||
fn app() -> Element {
|
fn app() -> Element {
|
||||||
let mut num = use_signal(|| 0);
|
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! {
|
rsx! {
|
||||||
document::Link {
|
document::Link {
|
||||||
href: CSS,
|
href: CSS,
|
||||||
|
|||||||
Reference in new issue
Block a user