mirror of
https://github.com/fluencelabs/wasm-bindgen
synced 2025-06-14 13:31:22 +00:00
Preserve the function table explicitly (#1970)
The main gc pass of unused items in wasm-bindgen was accidentally removing the function table because we weren't properly rooting it in the auxiliary section which has a few ways that imports can reference the function table via intrinsics and closures. Closes #1967
This commit is contained in:
@ -2889,7 +2889,7 @@ impl<'a> Context<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn export_function_table(&mut self) -> Result<String, Error> {
|
fn export_function_table(&mut self) -> Result<String, Error> {
|
||||||
match self.module.tables.main_function_table()? {
|
match self.aux.function_table {
|
||||||
Some(id) => Ok(self.export_name_of(id)),
|
Some(id) => Ok(self.export_name_of(id)),
|
||||||
None => bail!("no function table found in module"),
|
None => bail!("no function table found in module"),
|
||||||
}
|
}
|
||||||
|
@ -164,6 +164,12 @@ impl<'a> Context<'a> {
|
|||||||
// access to them while processing programs.
|
// access to them while processing programs.
|
||||||
self.descriptors.extend(descriptors);
|
self.descriptors.extend(descriptors);
|
||||||
|
|
||||||
|
// If any closures exist we need to prevent the function table from
|
||||||
|
// getting gc'd
|
||||||
|
if closure_imports.len() > 0 {
|
||||||
|
self.aux.function_table = self.module.tables.main_function_table()?;
|
||||||
|
}
|
||||||
|
|
||||||
// Register all the injected closure imports as that they're expected
|
// Register all the injected closure imports as that they're expected
|
||||||
// to manufacture a particular type of closure.
|
// to manufacture a particular type of closure.
|
||||||
//
|
//
|
||||||
@ -310,6 +316,9 @@ impl<'a> Context<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn bind_intrinsic(&mut self, id: ImportId, intrinsic: Intrinsic) -> Result<(), Error> {
|
fn bind_intrinsic(&mut self, id: ImportId, intrinsic: Intrinsic) -> Result<(), Error> {
|
||||||
|
if let Intrinsic::FunctionTable = intrinsic {
|
||||||
|
self.aux.function_table = self.module.tables.main_function_table()?;
|
||||||
|
}
|
||||||
let id = self.import_adapter(id, intrinsic.signature(), AdapterJsImportKind::Normal)?;
|
let id = self.import_adapter(id, intrinsic.signature(), AdapterJsImportKind::Normal)?;
|
||||||
self.aux
|
self.aux
|
||||||
.import_map
|
.import_map
|
||||||
|
@ -50,6 +50,7 @@ pub struct WasmBindgenAux {
|
|||||||
/// Information about various internal functions used to manage the `anyref`
|
/// Information about various internal functions used to manage the `anyref`
|
||||||
/// table, later used to process JS bindings.
|
/// table, later used to process JS bindings.
|
||||||
pub anyref_table: Option<walrus::TableId>,
|
pub anyref_table: Option<walrus::TableId>,
|
||||||
|
pub function_table: Option<walrus::TableId>,
|
||||||
pub anyref_alloc: Option<walrus::FunctionId>,
|
pub anyref_alloc: Option<walrus::FunctionId>,
|
||||||
pub anyref_drop_slice: Option<walrus::FunctionId>,
|
pub anyref_drop_slice: Option<walrus::FunctionId>,
|
||||||
|
|
||||||
@ -366,6 +367,9 @@ impl walrus::CustomSection for WasmBindgenAux {
|
|||||||
if let Some(id) = self.anyref_table {
|
if let Some(id) = self.anyref_table {
|
||||||
roots.push_table(id);
|
roots.push_table(id);
|
||||||
}
|
}
|
||||||
|
if let Some(id) = self.function_table {
|
||||||
|
roots.push_table(id);
|
||||||
|
}
|
||||||
if let Some(id) = self.anyref_alloc {
|
if let Some(id) = self.anyref_alloc {
|
||||||
roots.push_func(id);
|
roots.push_func(id);
|
||||||
}
|
}
|
||||||
|
@ -50,6 +50,7 @@ pub fn add(module: &mut Module) -> Result<(), Error> {
|
|||||||
anyref_drop_slice: _,
|
anyref_drop_slice: _,
|
||||||
exn_store: _,
|
exn_store: _,
|
||||||
shadow_stack_pointer: _,
|
shadow_stack_pointer: _,
|
||||||
|
function_table: _,
|
||||||
} = *aux;
|
} = *aux;
|
||||||
|
|
||||||
let adapter_context = |id: AdapterId| {
|
let adapter_context = |id: AdapterId| {
|
||||||
|
@ -334,3 +334,21 @@ $",
|
|||||||
)?);
|
)?);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn function_table_preserved() {
|
||||||
|
let (mut cmd, _out_dir) = Project::new("function_table_preserved")
|
||||||
|
.file(
|
||||||
|
"src/lib.rs",
|
||||||
|
r#"
|
||||||
|
use wasm_bindgen::prelude::*;
|
||||||
|
|
||||||
|
#[wasm_bindgen]
|
||||||
|
pub fn bar() {
|
||||||
|
Closure::wrap(Box::new(|| {}) as Box<dyn Fn()>);
|
||||||
|
}
|
||||||
|
"#,
|
||||||
|
)
|
||||||
|
.wasm_bindgen("");
|
||||||
|
cmd.assert().success();
|
||||||
|
}
|
||||||
|
Reference in New Issue
Block a user