diff --git a/compiler/gen_wasm/src/backend.rs b/compiler/gen_wasm/src/backend.rs index 64605f6409..d420df2ef0 100644 --- a/compiler/gen_wasm/src/backend.rs +++ b/compiler/gen_wasm/src/backend.rs @@ -1,5 +1,4 @@ -use bumpalo::{self, collections::Vec}; -use std::fmt::Write; +use bumpalo::collections::{String, Vec}; use code_builder::Align; use roc_builtins::bitcode::{FloatWidth, IntWidth}; @@ -90,18 +89,20 @@ impl<'a> WasmBackend<'a> { // The preloaded binary has a global to tell us where its data section ends // Note: We need this to account for zero data (.bss), which doesn't have an explicit DataSegment! - let data_end_name = "__data_end".as_bytes(); let data_end_idx = app_exports .iter() - .find(|ex| ex.name == data_end_name) + .find(|ex| ex.name == "__data_end") .map(|ex| ex.index) .unwrap_or_else(|| { internal_error!("Preloaded Wasm binary must export global constant `__data_end`") }); // TODO: move this to module parsing - let next_constant_addr = module.global.parse_u32_at_index(data_end_idx).unwrap_or_else(|e| { - internal_error!("Failed to parse __data_end from object file: {:?}", e); - }); + let next_constant_addr = module + .global + .parse_u32_at_index(data_end_idx) + .unwrap_or_else(|e| { + internal_error!("Failed to parse __data_end from object file: {:?}", e); + }); module.export.exports = app_exports; @@ -145,6 +146,7 @@ impl<'a> WasmBackend<'a> { .layout_ids .get_toplevel(symbol, &layout) .to_symbol_string(symbol, self.interns); + let name = String::from_str_in(&name, self.env.arena).into_bump_str(); self.proc_lookup.push(ProcLookupData { name: symbol, @@ -302,10 +304,8 @@ impl<'a> WasmBackend<'a> { .unwrap(); let wasm_fn_index = self.fn_index_offset + proc_index as u32; - let mut debug_name = bumpalo::collections::String::with_capacity_in(64, self.env.arena); - write!(debug_name, "{:?}", sym).unwrap(); - let name_bytes = debug_name.into_bytes().into_bump_slice(); - self.module.names.append_function(wasm_fn_index, name_bytes); + let name = String::from_str_in(sym.as_str(self.interns), self.env.arena).into_bump_str(); + self.module.names.append_function(wasm_fn_index, name); } /// Build a wrapper around a Roc procedure so that it can be called from our higher-order Zig builtins. @@ -952,10 +952,11 @@ impl<'a> WasmBackend<'a> { .layout_ids .get(sym, &Layout::Builtin(Builtin::Str)) .to_symbol_string(sym, self.interns); + let name = String::from_str_in(&name, self.env.arena).into_bump_str(); let linker_symbol = SymInfo::Data(DataSymbol::Defined { flags: 0, - name: name.clone(), + name, segment_index, segment_offset: 4, size: bytes.len() as u32, @@ -1102,7 +1103,7 @@ impl<'a> WasmBackend<'a> { num_wasm_args: usize, has_return_val: bool, ) { - let fn_index = self.module.names.functions[name.as_bytes()]; + let fn_index = self.module.names.functions[name]; self.called_preload_fns.push(fn_index); let linker_symbol_index = u32::MAX; diff --git a/compiler/gen_wasm/src/lib.rs b/compiler/gen_wasm/src/lib.rs index 9d73f8a182..fe10b9d8b9 100644 --- a/compiler/gen_wasm/src/lib.rs +++ b/compiler/gen_wasm/src/lib.rs @@ -8,7 +8,8 @@ pub mod wasm_module; pub mod wasm32_result; pub mod wasm32_sized; -use bumpalo::{self, collections::Vec, Bump}; +use bumpalo::collections::{String, Vec}; +use bumpalo::{self, Bump}; use roc_collections::all::{MutMap, MutSet}; use roc_module::low_level::LowLevelWrapperType; @@ -58,7 +59,7 @@ pub fn build_module<'a>( interns: &'a mut Interns, preload_bytes: &[u8], procedures: MutMap<(Symbol, ProcLayout<'a>), Proc<'a>>, -) -> Result, String> { +) -> Result, std::string::String> { let (mut wasm_module, called_preload_fns, _) = build_module_unserialized(env, interns, preload_bytes, procedures) .map_err(|e| format!("{:?}", e))?; @@ -102,17 +103,18 @@ pub fn build_module_unserialized<'a>( let fn_name = layout_ids .get_toplevel(sym, &proc_layout) .to_symbol_string(sym, interns); + let name = String::from_str_in(&fn_name, env.arena).into_bump_str(); if env.exposed_to_host.contains(&sym) { maybe_main_fn_index = Some(fn_index); exports.push(Export { - name: env.arena.alloc_slice_copy(fn_name.as_bytes()), + name, ty: ExportType::Func, index: fn_index, }); } - let linker_sym = SymInfo::for_function(fn_index, fn_name); + let linker_sym = SymInfo::for_function(fn_index, name); let linker_sym_index = linker_symbols.len() as u32; // linker_sym_index is redundant for these procs from user code, but needed for generated helpers! diff --git a/compiler/gen_wasm/src/wasm32_result.rs b/compiler/gen_wasm/src/wasm32_result.rs index 79d7f56596..56bb3a8f04 100644 --- a/compiler/gen_wasm/src/wasm32_result.rs +++ b/compiler/gen_wasm/src/wasm32_result.rs @@ -22,7 +22,7 @@ pub trait Wasm32Result { fn insert_wrapper<'a>( arena: &'a Bump, module: &mut WasmModule<'a>, - wrapper_name: &str, + wrapper_name: &'static str, main_function_index: u32, ) { insert_wrapper_metadata(arena, module, wrapper_name); @@ -38,7 +38,7 @@ pub trait Wasm32Result { pub fn insert_wrapper_for_layout<'a>( arena: &'a Bump, module: &mut WasmModule<'a>, - wrapper_name: &str, + wrapper_name: &'static str, main_fn_index: u32, layout: &Layout<'a>, ) { @@ -84,7 +84,11 @@ pub fn insert_wrapper_for_layout<'a>( } } -fn insert_wrapper_metadata<'a>(arena: &'a Bump, module: &mut WasmModule<'a>, wrapper_name: &str) { +fn insert_wrapper_metadata<'a>( + arena: &'a Bump, + module: &mut WasmModule<'a>, + wrapper_name: &'static str, +) { let index = module.import.function_count + module.code.preloaded_count + module.code.code_builders.len() as u32; @@ -95,7 +99,7 @@ fn insert_wrapper_metadata<'a>(arena: &'a Bump, module: &mut WasmModule<'a>, wra }); module.export.append(Export { - name: arena.alloc_slice_copy(wrapper_name.as_bytes()), + name: wrapper_name, ty: ExportType::Func, index, }); @@ -103,7 +107,7 @@ fn insert_wrapper_metadata<'a>(arena: &'a Bump, module: &mut WasmModule<'a>, wra let linker_symbol = SymInfo::Function(WasmObjectSymbol::Defined { flags: 0, index, - name: wrapper_name.to_string(), + name: wrapper_name, }); module.linking.symbol_table.push(linker_symbol); } diff --git a/compiler/gen_wasm/src/wasm_module/linking.rs b/compiler/gen_wasm/src/wasm_module/linking.rs index 048ede0418..ea877cfee7 100644 --- a/compiler/gen_wasm/src/wasm_module/linking.rs +++ b/compiler/gen_wasm/src/wasm_module/linking.rs @@ -175,13 +175,13 @@ impl<'a> Serialize for RelocationSection<'a> { /// Linking metadata for data segments #[derive(Debug)] -pub struct LinkingSegment { - pub name: String, +pub struct LinkingSegment<'a> { + pub name: &'a str, pub alignment: Align, pub flags: u32, } -impl Serialize for LinkingSegment { +impl<'a> Serialize for LinkingSegment<'a> { fn serialize(&self, buffer: &mut T) { buffer.encode_u32(self.name.len() as u32); buffer.append_slice(self.name.as_bytes()); @@ -238,7 +238,7 @@ impl Serialize for ComdatSym { #[allow(dead_code)] #[derive(Debug)] pub struct LinkingComdat<'a> { - name: String, + name: &'a str, flags: u32, syms: Vec<'a, ComdatSym>, } @@ -292,11 +292,11 @@ pub const WASM_SYM_EXPLICIT_NAME: u32 = 0x40; // use the name from the symbol ta pub const WASM_SYM_NO_STRIP: u32 = 0x80; #[derive(Clone, Debug)] -pub enum WasmObjectSymbol { +pub enum WasmObjectSymbol<'a> { Defined { flags: u32, index: u32, - name: String, + name: &'a str, }, Imported { flags: u32, @@ -304,7 +304,7 @@ pub enum WasmObjectSymbol { }, } -impl Serialize for WasmObjectSymbol { +impl<'a> Serialize for WasmObjectSymbol<'a> { fn serialize(&self, buffer: &mut T) { match self { Self::Defined { flags, index, name } => { @@ -322,21 +322,21 @@ impl Serialize for WasmObjectSymbol { } #[derive(Clone, Debug)] -pub enum DataSymbol { +pub enum DataSymbol<'a> { Defined { flags: u32, - name: String, + name: &'a str, segment_index: u32, segment_offset: u32, size: u32, }, Imported { flags: u32, - name: String, + name: &'a str, }, } -impl Serialize for DataSymbol { +impl<'a> Serialize for DataSymbol<'a> { fn serialize(&self, buffer: &mut T) { match self { Self::Defined { @@ -377,17 +377,17 @@ impl Serialize for SectionSymbol { } #[derive(Clone, Debug)] -pub enum SymInfo { - Function(WasmObjectSymbol), - Data(DataSymbol), - Global(WasmObjectSymbol), +pub enum SymInfo<'a> { + Function(WasmObjectSymbol<'a>), + Data(DataSymbol<'a>), + Global(WasmObjectSymbol<'a>), Section(SectionSymbol), - Event(WasmObjectSymbol), - Table(WasmObjectSymbol), + Event(WasmObjectSymbol<'a>), + Table(WasmObjectSymbol<'a>), } -impl SymInfo { - pub fn for_function(wasm_function_index: u32, name: String) -> Self { +impl<'a> SymInfo<'a> { + pub fn for_function(wasm_function_index: u32, name: &'a str) -> Self { SymInfo::Function(WasmObjectSymbol::Defined { flags: 0, index: wasm_function_index, @@ -396,7 +396,7 @@ impl SymInfo { } } -impl Serialize for SymInfo { +impl<'a> Serialize for SymInfo<'a> { fn serialize(&self, buffer: &mut T) { buffer.append_u8(match self { Self::Function(_) => 0, @@ -459,8 +459,8 @@ const LINKING_VERSION: u8 = 2; /// No point writing code to "find" the symbol table, when we know there's exactly one. #[derive(Debug)] pub struct LinkingSection<'a> { - pub symbol_table: Vec<'a, SymInfo>, - pub segment_info: Vec<'a, LinkingSegment>, + pub symbol_table: Vec<'a, SymInfo<'a>>, + pub segment_info: Vec<'a, LinkingSegment<'a>>, pub init_funcs: Vec<'a, LinkingInitFunc>, pub comdat_info: Vec<'a, LinkingComdat<'a>>, } diff --git a/compiler/gen_wasm/src/wasm_module/parse.rs b/compiler/gen_wasm/src/wasm_module/parse.rs index 99fb2c28ec..4827c1929f 100644 --- a/compiler/gen_wasm/src/wasm_module/parse.rs +++ b/compiler/gen_wasm/src/wasm_module/parse.rs @@ -52,15 +52,15 @@ impl Parse<()> for u32 { } } -// Parse string bytes without utf8 validation -impl<'a> Parse<&'a Bump> for &'a [u8] { +impl<'a> Parse<&'a Bump> for &'a str { fn parse(arena: &'a Bump, bytes: &[u8], cursor: &mut usize) -> Result { let len = u32::parse((), bytes, cursor)?; let end = *cursor + len as usize; let bytes: &[u8] = &bytes[*cursor..end]; let copy = arena.alloc_slice_copy(bytes); + let s = unsafe { std::str::from_utf8_unchecked(copy) }; *cursor = end; - Ok(copy) + Ok(s) } } diff --git a/compiler/gen_wasm/src/wasm_module/sections.rs b/compiler/gen_wasm/src/wasm_module/sections.rs index 401f28f267..3b9d8e8cfc 100644 --- a/compiler/gen_wasm/src/wasm_module/sections.rs +++ b/compiler/gen_wasm/src/wasm_module/sections.rs @@ -787,14 +787,14 @@ impl From for ExportType { #[derive(Debug)] pub struct Export<'a> { - pub name: &'a [u8], + pub name: &'a str, pub ty: ExportType, pub index: u32, } impl<'a> Export<'a> { fn parse(arena: &'a Bump, bytes: &[u8], cursor: &mut usize) -> Self { - let name = <&'a [u8]>::parse(arena, bytes, cursor).unwrap(); + let name = <&'a str>::parse(arena, bytes, cursor).unwrap(); let ty = ExportType::from(bytes[*cursor]); *cursor += 1; @@ -1257,7 +1257,7 @@ enum NameSubSections { pub struct NameSection<'a> { pub bytes: Vec<'a, u8>, - pub functions: MutMap<&'a [u8], u32>, + pub functions: MutMap<&'a str, u32>, } impl<'a> NameSection<'a> { @@ -1268,7 +1268,7 @@ impl<'a> NameSection<'a> { self.bytes.len() } - pub fn append_function(&mut self, index: u32, name: &'a [u8]) { + pub fn append_function(&mut self, index: u32, name: &'a str) { index.serialize(&mut self.bytes); name.serialize(&mut self.bytes); self.functions.insert(name, index); @@ -1315,12 +1315,12 @@ impl<'a> NameSection<'a> { cursor: &mut usize, section_end: usize, ) { - let section_name = <&'a [u8]>::parse(arena, module_bytes, cursor).unwrap(); - if section_name != Self::NAME.as_bytes() { + let section_name = <&'a str>::parse(arena, module_bytes, cursor).unwrap(); + if section_name != Self::NAME { internal_error!( "Expected Custom section {:?}, found {:?}", Self::NAME, - std::str::from_utf8(section_name) + section_name ); } @@ -1348,9 +1348,8 @@ impl<'a> NameSection<'a> { let fn_names_start = *cursor; for _ in 0..num_entries { let fn_index = u32::parse((), module_bytes, cursor).unwrap(); - let name_bytes = <&'a [u8]>::parse(arena, module_bytes, cursor).unwrap(); - self.functions - .insert(arena.alloc_slice_copy(name_bytes), fn_index); + let name_bytes = <&'a str>::parse(arena, module_bytes, cursor).unwrap(); + self.functions.insert(name_bytes, fn_index); } // Copy only the bytes for the function names segment @@ -1395,8 +1394,7 @@ impl<'a> Debug for NameSection<'a> { by_index.sort_unstable(); for (index, name) in by_index.iter() { - let name_str = unsafe { std::str::from_utf8_unchecked(name) }; - writeln!(f, " {:4}: {}", index, name_str)?; + writeln!(f, " {:4}: {}", index, name)?; } Ok(()) diff --git a/compiler/test_gen/src/helpers/wasm.rs b/compiler/test_gen/src/helpers/wasm.rs index 44cfa8ab88..298b990b8f 100644 --- a/compiler/test_gen/src/helpers/wasm.rs +++ b/compiler/test_gen/src/helpers/wasm.rs @@ -120,15 +120,15 @@ fn compile_roc_to_wasm_bytes<'a, T: Wasm32Result>( }; let (mut module, called_preload_fns, main_fn_index) = - roc_gen_wasm::build_module_unserialized(&env, &mut interns, preload_bytes, procedures).unwrap(); + roc_gen_wasm::build_module_unserialized(&env, &mut interns, preload_bytes, procedures) + .unwrap(); T::insert_wrapper(arena, &mut module, TEST_WRAPPER_NAME, main_fn_index); // Export the initialiser function for refcount tests - let init_refcount_bytes = INIT_REFCOUNT_NAME.as_bytes(); - let init_refcount_idx = module.names.functions[init_refcount_bytes]; + let init_refcount_idx = module.names.functions[INIT_REFCOUNT_NAME]; module.export.append(Export { - name: arena.alloc_slice_copy(init_refcount_bytes), + name: INIT_REFCOUNT_NAME, ty: ExportType::Func, index: init_refcount_idx, });