wasm: use a BitVec for called host functions

This commit is contained in:
Brian Carroll 2022-06-15 21:31:10 +01:00
parent 52f209b2f9
commit 6e30811b0c
No known key found for this signature in database
GPG key ID: 9CF4E3BF9C4722C7
6 changed files with 18 additions and 20 deletions

View file

@ -1,3 +1,4 @@
use bitvec::vec::BitVec;
use bumpalo::collections::{String, Vec}; use bumpalo::collections::{String, Vec};
use code_builder::Align; use code_builder::Align;
@ -53,7 +54,7 @@ pub struct WasmBackend<'a> {
module: WasmModule<'a>, module: WasmModule<'a>,
layout_ids: LayoutIds<'a>, layout_ids: LayoutIds<'a>,
pub fn_index_offset: u32, pub fn_index_offset: u32,
called_preload_fns: Vec<'a, u32>, called_preload_fns: BitVec<usize>,
pub proc_lookup: Vec<'a, ProcLookupData<'a>>, pub proc_lookup: Vec<'a, ProcLookupData<'a>>,
host_lookup: Vec<'a, (&'a str, u32)>, host_lookup: Vec<'a, (&'a str, u32)>,
helper_proc_gen: CodeGenHelp<'a>, helper_proc_gen: CodeGenHelp<'a>,
@ -125,7 +126,7 @@ impl<'a> WasmBackend<'a> {
layout_ids, layout_ids,
fn_index_offset, fn_index_offset,
called_preload_fns: Vec::with_capacity_in(2, env.arena), called_preload_fns: BitVec::repeat(false, host_lookup.len()),
proc_lookup, proc_lookup,
host_lookup, host_lookup,
helper_proc_gen, helper_proc_gen,
@ -273,7 +274,7 @@ impl<'a> WasmBackend<'a> {
wasm_fn_index wasm_fn_index
} }
pub fn finalize(mut self) -> (WasmModule<'a>, Vec<'a, u32>) { pub fn finalize(mut self) -> (WasmModule<'a>, BitVec<usize>) {
self.maybe_call_host_main(); self.maybe_call_host_main();
let fn_table_size = 1 + self.module.element.max_table_index(); let fn_table_size = 1 + self.module.element.max_table_index();
self.module.table.function_table.limits = Limits::MinMax(fn_table_size, fn_table_size); self.module.table.function_table.limits = Limits::MinMax(fn_table_size, fn_table_size);
@ -328,7 +329,7 @@ impl<'a> WasmBackend<'a> {
self.code_builder.build_fn_header_and_footer(&[], 0, None); self.code_builder.build_fn_header_and_footer(&[], 0, None);
self.reset(); self.reset();
self.called_preload_fns.push(main_fn_index); self.called_preload_fns.set(main_fn_index as usize, true);
} }
/// Register the debug names of Symbols in a global lookup table /// Register the debug names of Symbols in a global lookup table
@ -1250,7 +1251,7 @@ impl<'a> WasmBackend<'a> {
.find(|(fn_name, _)| *fn_name == name) .find(|(fn_name, _)| *fn_name == name)
.unwrap_or_else(|| panic!("The Roc app tries to call `{}` but I can't find it!", name)); .unwrap_or_else(|| panic!("The Roc app tries to call `{}` but I can't find it!", name));
self.called_preload_fns.push(*fn_index); self.called_preload_fns.set(*fn_index as usize, true);
self.code_builder self.code_builder
.call(*fn_index, num_wasm_args, has_return_val); .call(*fn_index, num_wasm_args, has_return_val);
} }

View file

@ -8,6 +8,7 @@ pub mod wasm_module;
pub mod wasm32_result; pub mod wasm32_result;
pub mod wasm32_sized; pub mod wasm32_sized;
use bitvec::prelude::BitVec;
use bumpalo::collections::Vec; use bumpalo::collections::Vec;
use bumpalo::{self, Bump}; use bumpalo::{self, Bump};
@ -67,7 +68,7 @@ pub fn build_app_binary<'a>(
let (mut wasm_module, called_preload_fns, _) = let (mut wasm_module, called_preload_fns, _) =
build_app_module(env, interns, host_module, procedures); build_app_module(env, interns, host_module, procedures);
wasm_module.eliminate_dead_code(env.arena, &called_preload_fns); wasm_module.eliminate_dead_code(env.arena, called_preload_fns);
let mut buffer = std::vec::Vec::with_capacity(wasm_module.size()); let mut buffer = std::vec::Vec::with_capacity(wasm_module.size());
wasm_module.serialize(&mut buffer); wasm_module.serialize(&mut buffer);
@ -83,7 +84,7 @@ pub fn build_app_module<'a>(
interns: &'a mut Interns, interns: &'a mut Interns,
host_module: WasmModule<'a>, host_module: WasmModule<'a>,
procedures: MutMap<(Symbol, ProcLayout<'a>), Proc<'a>>, procedures: MutMap<(Symbol, ProcLayout<'a>), Proc<'a>>,
) -> (WasmModule<'a>, Vec<'a, u32>, u32) { ) -> (WasmModule<'a>, BitVec<usize>, u32) {
let layout_ids = LayoutIds::default(); let layout_ids = LayoutIds::default();
let mut procs = Vec::with_capacity_in(procedures.len(), env.arena); let mut procs = Vec::with_capacity_in(procedures.len(), env.arena);
let mut proc_lookup = Vec::with_capacity_in(procedures.len() * 2, env.arena); let mut proc_lookup = Vec::with_capacity_in(procedures.len() * 2, env.arena);

View file

@ -174,7 +174,7 @@ impl<'a> WasmModule<'a> {
}) })
} }
pub fn eliminate_dead_code(&mut self, arena: &'a Bump, called_host_fns: &[u32]) { pub fn eliminate_dead_code(&mut self, arena: &'a Bump, called_host_fns: BitVec<usize>) {
if DEBUG_SETTINGS.skip_dead_code_elim { if DEBUG_SETTINGS.skip_dead_code_elim {
return; return;
} }
@ -308,7 +308,7 @@ impl<'a> WasmModule<'a> {
fn trace_live_host_functions<I: Iterator<Item = u32>>( fn trace_live_host_functions<I: Iterator<Item = u32>>(
&self, &self,
arena: &'a Bump, arena: &'a Bump,
called_host_fns: &[u32], called_host_fns: BitVec<usize>,
exported_fns: I, exported_fns: I,
indirect_callees_and_signatures: Vec<'a, (u32, u32)>, indirect_callees_and_signatures: Vec<'a, (u32, u32)>,
host_fn_min: u32, host_fn_min: u32,
@ -349,14 +349,10 @@ impl<'a> WasmModule<'a> {
); );
// Loop variables for the main loop below // Loop variables for the main loop below
let capacity = host_fn_max as usize + self.code.code_builders.len(); let mut live_flags = BitVec::repeat(false, called_host_fns.len());
let mut live_flags = BitVec::repeat(false, capacity); let mut next_pass_fns = BitVec::repeat(false, called_host_fns.len());
let mut next_pass_fns = BitVec::repeat(false, capacity); let mut current_pass_fns = called_host_fns;
let mut current_pass_fns = BitVec::<usize>::repeat(false, capacity); for index in exported_fns {
// Start with everything called from Roc and everything exported to JS
// Also include everything that can be indirectly called (crude, but good enough!)
for index in called_host_fns.iter().copied().chain(exported_fns) {
current_pass_fns.set(index as usize, true); current_pass_fns.set(index as usize, true);
} }

View file

@ -151,7 +151,7 @@ fn compile_roc_to_wasm_bytes<'a, T: Wasm32Result>(
index: init_refcount_idx, index: init_refcount_idx,
}); });
module.eliminate_dead_code(env.arena, &called_preload_fns); module.eliminate_dead_code(env.arena, called_preload_fns);
let mut app_module_bytes = std::vec::Vec::with_capacity(module.size()); let mut app_module_bytes = std::vec::Vec::with_capacity(module.size());
module.serialize(&mut app_module_bytes); module.serialize(&mut app_module_bytes);

View file

@ -288,7 +288,7 @@ fn test_linking_with_dce() {
let (mut final_module, called_preload_fns, _roc_main_index) = let (mut final_module, called_preload_fns, _roc_main_index) =
roc_gen_wasm::build_app_module(&env, &mut interns, host_module, procedures); roc_gen_wasm::build_app_module(&env, &mut interns, host_module, procedures);
final_module.eliminate_dead_code(env.arena, &called_preload_fns); final_module.eliminate_dead_code(env.arena, called_preload_fns);
let mut buffer = Vec::with_capacity(final_module.size()); let mut buffer = Vec::with_capacity(final_module.size());
final_module.serialize(&mut buffer); final_module.serialize(&mut buffer);

View file

@ -227,7 +227,7 @@ pub async fn entrypoint_from_js(src: String) -> Result<String, String> {
&main_fn_layout.result, &main_fn_layout.result,
); );
module.eliminate_dead_code(env.arena, &called_preload_fns); module.eliminate_dead_code(env.arena, called_preload_fns);
let mut buffer = Vec::with_capacity_in(module.size(), arena); let mut buffer = Vec::with_capacity_in(module.size(), arena);
module.serialize(&mut buffer); module.serialize(&mut buffer);