Replace byte slices with str

This commit is contained in:
Brian Carroll 2022-05-22 19:25:39 +01:00
parent c16a5ad8ae
commit 84a3ac2ef6
No known key found for this signature in database
GPG key ID: 9CF4E3BF9C4722C7
7 changed files with 68 additions and 63 deletions

View file

@ -1,5 +1,4 @@
use bumpalo::{self, collections::Vec}; use bumpalo::collections::{String, Vec};
use std::fmt::Write;
use code_builder::Align; use code_builder::Align;
use roc_builtins::bitcode::{FloatWidth, IntWidth}; 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 // 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! // 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 let data_end_idx = app_exports
.iter() .iter()
.find(|ex| ex.name == data_end_name) .find(|ex| ex.name == "__data_end")
.map(|ex| ex.index) .map(|ex| ex.index)
.unwrap_or_else(|| { .unwrap_or_else(|| {
internal_error!("Preloaded Wasm binary must export global constant `__data_end`") internal_error!("Preloaded Wasm binary must export global constant `__data_end`")
}); });
// TODO: move this to module parsing // TODO: move this to module parsing
let next_constant_addr = module.global.parse_u32_at_index(data_end_idx).unwrap_or_else(|e| { let next_constant_addr = module
internal_error!("Failed to parse __data_end from object file: {:?}", e); .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; module.export.exports = app_exports;
@ -145,6 +146,7 @@ impl<'a> WasmBackend<'a> {
.layout_ids .layout_ids
.get_toplevel(symbol, &layout) .get_toplevel(symbol, &layout)
.to_symbol_string(symbol, self.interns); .to_symbol_string(symbol, self.interns);
let name = String::from_str_in(&name, self.env.arena).into_bump_str();
self.proc_lookup.push(ProcLookupData { self.proc_lookup.push(ProcLookupData {
name: symbol, name: symbol,
@ -302,10 +304,8 @@ impl<'a> WasmBackend<'a> {
.unwrap(); .unwrap();
let wasm_fn_index = self.fn_index_offset + proc_index as u32; 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); let name = String::from_str_in(sym.as_str(self.interns), self.env.arena).into_bump_str();
write!(debug_name, "{:?}", sym).unwrap(); self.module.names.append_function(wasm_fn_index, name);
let name_bytes = debug_name.into_bytes().into_bump_slice();
self.module.names.append_function(wasm_fn_index, name_bytes);
} }
/// Build a wrapper around a Roc procedure so that it can be called from our higher-order Zig builtins. /// 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 .layout_ids
.get(sym, &Layout::Builtin(Builtin::Str)) .get(sym, &Layout::Builtin(Builtin::Str))
.to_symbol_string(sym, self.interns); .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 { let linker_symbol = SymInfo::Data(DataSymbol::Defined {
flags: 0, flags: 0,
name: name.clone(), name,
segment_index, segment_index,
segment_offset: 4, segment_offset: 4,
size: bytes.len() as u32, size: bytes.len() as u32,
@ -1102,7 +1103,7 @@ impl<'a> WasmBackend<'a> {
num_wasm_args: usize, num_wasm_args: usize,
has_return_val: bool, 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); self.called_preload_fns.push(fn_index);
let linker_symbol_index = u32::MAX; let linker_symbol_index = u32::MAX;

View file

@ -8,7 +8,8 @@ pub mod wasm_module;
pub mod wasm32_result; pub mod wasm32_result;
pub mod wasm32_sized; 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_collections::all::{MutMap, MutSet};
use roc_module::low_level::LowLevelWrapperType; use roc_module::low_level::LowLevelWrapperType;
@ -58,7 +59,7 @@ pub fn build_module<'a>(
interns: &'a mut Interns, interns: &'a mut Interns,
preload_bytes: &[u8], preload_bytes: &[u8],
procedures: MutMap<(Symbol, ProcLayout<'a>), Proc<'a>>, procedures: MutMap<(Symbol, ProcLayout<'a>), Proc<'a>>,
) -> Result<std::vec::Vec<u8>, String> { ) -> Result<std::vec::Vec<u8>, std::string::String> {
let (mut wasm_module, called_preload_fns, _) = let (mut wasm_module, called_preload_fns, _) =
build_module_unserialized(env, interns, preload_bytes, procedures) build_module_unserialized(env, interns, preload_bytes, procedures)
.map_err(|e| format!("{:?}", e))?; .map_err(|e| format!("{:?}", e))?;
@ -102,17 +103,18 @@ pub fn build_module_unserialized<'a>(
let fn_name = layout_ids let fn_name = layout_ids
.get_toplevel(sym, &proc_layout) .get_toplevel(sym, &proc_layout)
.to_symbol_string(sym, interns); .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) { if env.exposed_to_host.contains(&sym) {
maybe_main_fn_index = Some(fn_index); maybe_main_fn_index = Some(fn_index);
exports.push(Export { exports.push(Export {
name: env.arena.alloc_slice_copy(fn_name.as_bytes()), name,
ty: ExportType::Func, ty: ExportType::Func,
index: fn_index, 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; 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! // linker_sym_index is redundant for these procs from user code, but needed for generated helpers!

View file

@ -22,7 +22,7 @@ pub trait Wasm32Result {
fn insert_wrapper<'a>( fn insert_wrapper<'a>(
arena: &'a Bump, arena: &'a Bump,
module: &mut WasmModule<'a>, module: &mut WasmModule<'a>,
wrapper_name: &str, wrapper_name: &'static str,
main_function_index: u32, main_function_index: u32,
) { ) {
insert_wrapper_metadata(arena, module, wrapper_name); insert_wrapper_metadata(arena, module, wrapper_name);
@ -38,7 +38,7 @@ pub trait Wasm32Result {
pub fn insert_wrapper_for_layout<'a>( pub fn insert_wrapper_for_layout<'a>(
arena: &'a Bump, arena: &'a Bump,
module: &mut WasmModule<'a>, module: &mut WasmModule<'a>,
wrapper_name: &str, wrapper_name: &'static str,
main_fn_index: u32, main_fn_index: u32,
layout: &Layout<'a>, 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 let index = module.import.function_count
+ module.code.preloaded_count + module.code.preloaded_count
+ module.code.code_builders.len() as u32; + 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 { module.export.append(Export {
name: arena.alloc_slice_copy(wrapper_name.as_bytes()), name: wrapper_name,
ty: ExportType::Func, ty: ExportType::Func,
index, 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 { let linker_symbol = SymInfo::Function(WasmObjectSymbol::Defined {
flags: 0, flags: 0,
index, index,
name: wrapper_name.to_string(), name: wrapper_name,
}); });
module.linking.symbol_table.push(linker_symbol); module.linking.symbol_table.push(linker_symbol);
} }

View file

@ -175,13 +175,13 @@ impl<'a> Serialize for RelocationSection<'a> {
/// Linking metadata for data segments /// Linking metadata for data segments
#[derive(Debug)] #[derive(Debug)]
pub struct LinkingSegment { pub struct LinkingSegment<'a> {
pub name: String, pub name: &'a str,
pub alignment: Align, pub alignment: Align,
pub flags: u32, pub flags: u32,
} }
impl Serialize for LinkingSegment { impl<'a> Serialize for LinkingSegment<'a> {
fn serialize<T: SerialBuffer>(&self, buffer: &mut T) { fn serialize<T: SerialBuffer>(&self, buffer: &mut T) {
buffer.encode_u32(self.name.len() as u32); buffer.encode_u32(self.name.len() as u32);
buffer.append_slice(self.name.as_bytes()); buffer.append_slice(self.name.as_bytes());
@ -238,7 +238,7 @@ impl Serialize for ComdatSym {
#[allow(dead_code)] #[allow(dead_code)]
#[derive(Debug)] #[derive(Debug)]
pub struct LinkingComdat<'a> { pub struct LinkingComdat<'a> {
name: String, name: &'a str,
flags: u32, flags: u32,
syms: Vec<'a, ComdatSym>, 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; pub const WASM_SYM_NO_STRIP: u32 = 0x80;
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub enum WasmObjectSymbol { pub enum WasmObjectSymbol<'a> {
Defined { Defined {
flags: u32, flags: u32,
index: u32, index: u32,
name: String, name: &'a str,
}, },
Imported { Imported {
flags: u32, flags: u32,
@ -304,7 +304,7 @@ pub enum WasmObjectSymbol {
}, },
} }
impl Serialize for WasmObjectSymbol { impl<'a> Serialize for WasmObjectSymbol<'a> {
fn serialize<T: SerialBuffer>(&self, buffer: &mut T) { fn serialize<T: SerialBuffer>(&self, buffer: &mut T) {
match self { match self {
Self::Defined { flags, index, name } => { Self::Defined { flags, index, name } => {
@ -322,21 +322,21 @@ impl Serialize for WasmObjectSymbol {
} }
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub enum DataSymbol { pub enum DataSymbol<'a> {
Defined { Defined {
flags: u32, flags: u32,
name: String, name: &'a str,
segment_index: u32, segment_index: u32,
segment_offset: u32, segment_offset: u32,
size: u32, size: u32,
}, },
Imported { Imported {
flags: u32, flags: u32,
name: String, name: &'a str,
}, },
} }
impl Serialize for DataSymbol { impl<'a> Serialize for DataSymbol<'a> {
fn serialize<T: SerialBuffer>(&self, buffer: &mut T) { fn serialize<T: SerialBuffer>(&self, buffer: &mut T) {
match self { match self {
Self::Defined { Self::Defined {
@ -377,17 +377,17 @@ impl Serialize for SectionSymbol {
} }
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub enum SymInfo { pub enum SymInfo<'a> {
Function(WasmObjectSymbol), Function(WasmObjectSymbol<'a>),
Data(DataSymbol), Data(DataSymbol<'a>),
Global(WasmObjectSymbol), Global(WasmObjectSymbol<'a>),
Section(SectionSymbol), Section(SectionSymbol),
Event(WasmObjectSymbol), Event(WasmObjectSymbol<'a>),
Table(WasmObjectSymbol), Table(WasmObjectSymbol<'a>),
} }
impl SymInfo { impl<'a> SymInfo<'a> {
pub fn for_function(wasm_function_index: u32, name: String) -> Self { pub fn for_function(wasm_function_index: u32, name: &'a str) -> Self {
SymInfo::Function(WasmObjectSymbol::Defined { SymInfo::Function(WasmObjectSymbol::Defined {
flags: 0, flags: 0,
index: wasm_function_index, index: wasm_function_index,
@ -396,7 +396,7 @@ impl SymInfo {
} }
} }
impl Serialize for SymInfo { impl<'a> Serialize for SymInfo<'a> {
fn serialize<T: SerialBuffer>(&self, buffer: &mut T) { fn serialize<T: SerialBuffer>(&self, buffer: &mut T) {
buffer.append_u8(match self { buffer.append_u8(match self {
Self::Function(_) => 0, 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. /// No point writing code to "find" the symbol table, when we know there's exactly one.
#[derive(Debug)] #[derive(Debug)]
pub struct LinkingSection<'a> { pub struct LinkingSection<'a> {
pub symbol_table: Vec<'a, SymInfo>, pub symbol_table: Vec<'a, SymInfo<'a>>,
pub segment_info: Vec<'a, LinkingSegment>, pub segment_info: Vec<'a, LinkingSegment<'a>>,
pub init_funcs: Vec<'a, LinkingInitFunc>, pub init_funcs: Vec<'a, LinkingInitFunc>,
pub comdat_info: Vec<'a, LinkingComdat<'a>>, pub comdat_info: Vec<'a, LinkingComdat<'a>>,
} }

View file

@ -52,15 +52,15 @@ impl Parse<()> for u32 {
} }
} }
// Parse string bytes without utf8 validation impl<'a> Parse<&'a Bump> for &'a str {
impl<'a> Parse<&'a Bump> for &'a [u8] {
fn parse(arena: &'a Bump, bytes: &[u8], cursor: &mut usize) -> Result<Self, ParseError> { fn parse(arena: &'a Bump, bytes: &[u8], cursor: &mut usize) -> Result<Self, ParseError> {
let len = u32::parse((), bytes, cursor)?; let len = u32::parse((), bytes, cursor)?;
let end = *cursor + len as usize; let end = *cursor + len as usize;
let bytes: &[u8] = &bytes[*cursor..end]; let bytes: &[u8] = &bytes[*cursor..end];
let copy = arena.alloc_slice_copy(bytes); let copy = arena.alloc_slice_copy(bytes);
let s = unsafe { std::str::from_utf8_unchecked(copy) };
*cursor = end; *cursor = end;
Ok(copy) Ok(s)
} }
} }

View file

@ -787,14 +787,14 @@ impl From<u8> for ExportType {
#[derive(Debug)] #[derive(Debug)]
pub struct Export<'a> { pub struct Export<'a> {
pub name: &'a [u8], pub name: &'a str,
pub ty: ExportType, pub ty: ExportType,
pub index: u32, pub index: u32,
} }
impl<'a> Export<'a> { impl<'a> Export<'a> {
fn parse(arena: &'a Bump, bytes: &[u8], cursor: &mut usize) -> Self { 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]); let ty = ExportType::from(bytes[*cursor]);
*cursor += 1; *cursor += 1;
@ -1257,7 +1257,7 @@ enum NameSubSections {
pub struct NameSection<'a> { pub struct NameSection<'a> {
pub bytes: Vec<'a, u8>, pub bytes: Vec<'a, u8>,
pub functions: MutMap<&'a [u8], u32>, pub functions: MutMap<&'a str, u32>,
} }
impl<'a> NameSection<'a> { impl<'a> NameSection<'a> {
@ -1268,7 +1268,7 @@ impl<'a> NameSection<'a> {
self.bytes.len() 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); index.serialize(&mut self.bytes);
name.serialize(&mut self.bytes); name.serialize(&mut self.bytes);
self.functions.insert(name, index); self.functions.insert(name, index);
@ -1315,12 +1315,12 @@ impl<'a> NameSection<'a> {
cursor: &mut usize, cursor: &mut usize,
section_end: usize, section_end: usize,
) { ) {
let section_name = <&'a [u8]>::parse(arena, module_bytes, cursor).unwrap(); let section_name = <&'a str>::parse(arena, module_bytes, cursor).unwrap();
if section_name != Self::NAME.as_bytes() { if section_name != Self::NAME {
internal_error!( internal_error!(
"Expected Custom section {:?}, found {:?}", "Expected Custom section {:?}, found {:?}",
Self::NAME, Self::NAME,
std::str::from_utf8(section_name) section_name
); );
} }
@ -1348,9 +1348,8 @@ impl<'a> NameSection<'a> {
let fn_names_start = *cursor; let fn_names_start = *cursor;
for _ in 0..num_entries { for _ in 0..num_entries {
let fn_index = u32::parse((), module_bytes, cursor).unwrap(); let fn_index = u32::parse((), module_bytes, cursor).unwrap();
let name_bytes = <&'a [u8]>::parse(arena, module_bytes, cursor).unwrap(); let name_bytes = <&'a str>::parse(arena, module_bytes, cursor).unwrap();
self.functions self.functions.insert(name_bytes, fn_index);
.insert(arena.alloc_slice_copy(name_bytes), fn_index);
} }
// Copy only the bytes for the function names segment // Copy only the bytes for the function names segment
@ -1395,8 +1394,7 @@ impl<'a> Debug for NameSection<'a> {
by_index.sort_unstable(); by_index.sort_unstable();
for (index, name) in by_index.iter() { for (index, name) in by_index.iter() {
let name_str = unsafe { std::str::from_utf8_unchecked(name) }; writeln!(f, " {:4}: {}", index, name)?;
writeln!(f, " {:4}: {}", index, name_str)?;
} }
Ok(()) Ok(())

View file

@ -120,15 +120,15 @@ fn compile_roc_to_wasm_bytes<'a, T: Wasm32Result>(
}; };
let (mut module, called_preload_fns, main_fn_index) = 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); T::insert_wrapper(arena, &mut module, TEST_WRAPPER_NAME, main_fn_index);
// Export the initialiser function for refcount tests // 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_NAME];
let init_refcount_idx = module.names.functions[init_refcount_bytes];
module.export.append(Export { module.export.append(Export {
name: arena.alloc_slice_copy(init_refcount_bytes), name: INIT_REFCOUNT_NAME,
ty: ExportType::Func, ty: ExportType::Func,
index: init_refcount_idx, index: init_refcount_idx,
}); });