diff --git a/compiler/gen_wasm/src/wasm_module/linking.rs b/compiler/gen_wasm/src/wasm_module/linking.rs index ea877cfee7..09c5520334 100644 --- a/compiler/gen_wasm/src/wasm_module/linking.rs +++ b/compiler/gen_wasm/src/wasm_module/linking.rs @@ -4,6 +4,7 @@ use bumpalo::Bump; use super::sections::{update_section_size, write_custom_section_header}; use super::serialize::{SerialBuffer, Serialize}; use super::Align; +use crate::wasm_module::{Parse, ParseError}; /******************************************************************* * @@ -136,6 +137,43 @@ impl Serialize for RelocationEntry { } } +impl Parse<()> for RelocationEntry { + fn parse(_: (), bytes: &[u8], cursor: &mut usize) -> Result { + use IndexRelocType::*; + + let type_id = bytes[*cursor]; + *cursor += 1; + let offset = u32::parse((), bytes, cursor)?; + let symbol_index = u32::parse((), bytes, cursor)?; + + if type_id == (FunctionIndexLeb as u8) + || type_id == (TableIndexSleb as u8) + || type_id == (TableIndexI32 as u8) + || type_id == (TypeIndexLeb as u8) + || type_id == (GlobalIndexLeb as u8) + || type_id == (EventIndexLeb as u8) + || type_id == (GlobalIndexI32 as u8) + || type_id == (TableIndexSleb64 as u8) + || type_id == (TableIndexI64 as u8) + || type_id == (TableNumberLeb as u8) + { + Ok(RelocationEntry::Index { + type_id: unsafe { std::mem::transmute(type_id) }, + offset, + symbol_index, + }) + } else { + let addend = i32::parse((), bytes, cursor)?; + Ok(RelocationEntry::Offset { + type_id: unsafe { std::mem::transmute(type_id) }, + offset, + symbol_index, + addend, + }) + } + } +} + #[derive(Debug)] pub struct RelocationSection<'a> { pub name: &'a str, @@ -165,6 +203,13 @@ impl<'a> Serialize for RelocationSection<'a> { } } +impl<'a> Parse<&'a Bump> for RelocationSection<'a> { + fn parse(arena: &'a Bump, bytes: &[u8], cursor: &mut usize) -> Result { + let name = <&'a str>::parse(arena, bytes, cursor)?; + todo!() + } +} + /******************************************************************* * * Linking section @@ -191,6 +236,12 @@ impl<'a> Serialize for LinkingSegment<'a> { } } +impl<'a> Parse<&'a Bump> for LinkingSegment<'a> { + fn parse(arena: &'a Bump, bytes: &[u8], cursor: &mut usize) -> Result { + todo!() + } +} + /// Linking metadata for init (start) functions #[derive(Debug)] pub struct LinkingInitFunc { @@ -204,6 +255,12 @@ impl Serialize for LinkingInitFunc { } } +impl Parse<()> for LinkingInitFunc { + fn parse(_: (), bytes: &[u8], cursor: &mut usize) -> Result { + todo!() + } +} + //------------------------------------------------ // Common data //------------------------------------------------ @@ -231,6 +288,12 @@ impl Serialize for ComdatSym { } } +impl Parse<()> for ComdatSym { + fn parse(_: (), bytes: &[u8], cursor: &mut usize) -> Result { + todo!() + } +} + /// Linking metadata for common data /// A COMDAT group may contain one or more functions, data segments, and/or custom sections. /// The linker will include all of these elements with a given group name from one object file, @@ -249,6 +312,12 @@ impl<'a> Serialize for LinkingComdat<'a> { } } +impl<'a> Parse<&'a Bump> for LinkingComdat<'a> { + fn parse(arena: &'a Bump, bytes: &[u8], cursor: &mut usize) -> Result { + todo!() + } +} + //------------------------------------------------ // Symbol table //------------------------------------------------ @@ -321,6 +390,12 @@ impl<'a> Serialize for WasmObjectSymbol<'a> { } } +impl<'a> Parse<&'a Bump> for WasmObjectSymbol<'a> { + fn parse(arena: &'a Bump, bytes: &[u8], cursor: &mut usize) -> Result { + todo!() + } +} + #[derive(Clone, Debug)] pub enum DataSymbol<'a> { Defined { @@ -362,6 +437,12 @@ impl<'a> Serialize for DataSymbol<'a> { } } +impl<'a> Parse<&'a Bump> for DataSymbol<'a> { + fn parse(arena: &'a Bump, bytes: &[u8], cursor: &mut usize) -> Result { + todo!() + } +} + /// section index (not section id!) #[derive(Clone, Debug)] pub struct SectionSymbol { @@ -376,6 +457,12 @@ impl Serialize for SectionSymbol { } } +impl Parse<()> for SectionSymbol { + fn parse(_: (), bytes: &[u8], cursor: &mut usize) -> Result { + todo!() + } +} + #[derive(Clone, Debug)] pub enum SymInfo<'a> { Function(WasmObjectSymbol<'a>), @@ -417,6 +504,12 @@ impl<'a> Serialize for SymInfo<'a> { } } +impl<'a> Parse<&'a Bump> for SymInfo<'a> { + fn parse(arena: &'a Bump, bytes: &[u8], cursor: &mut usize) -> Result { + todo!() + } +} + //---------------------------------------------------------------- // Linking subsections //---------------------------------------------------------------- @@ -489,3 +582,9 @@ impl<'a> Serialize for LinkingSection<'a> { update_section_size(buffer, header_indices); } } + +impl<'a> Parse<&'a Bump> for LinkingSection<'a> { + fn parse(arena: &'a Bump, bytes: &[u8], cursor: &mut usize) -> Result { + todo!() + } +} diff --git a/compiler/gen_wasm/src/wasm_module/parse.rs b/compiler/gen_wasm/src/wasm_module/parse.rs index 3768cbddca..eff8c08140 100644 --- a/compiler/gen_wasm/src/wasm_module/parse.rs +++ b/compiler/gen_wasm/src/wasm_module/parse.rs @@ -1,4 +1,5 @@ use super::serialize::MAX_SIZE_ENCODED_U32; +use bumpalo::collections::vec::Vec; use bumpalo::Bump; /// Parse serialized bytes into a data structure @@ -46,6 +47,43 @@ impl Parse<()> for u32 { } } +/// Decode a signed 32-bit integer from the provided buffer in LEB-128 format +/// Return the integer itself and the offset after it ends +fn decode_i32(bytes: &[u8]) -> Result<(i32, usize), ()> { + let mut value = 0; + let mut shift = 0; + for (i, byte) in bytes.iter().take(MAX_SIZE_ENCODED_U32).enumerate() { + value |= ((byte & 0x7f) as i32) << shift; + if (byte & 0x80) == 0 { + let is_negative = byte & 0x40 != 0; + if shift < MAX_SIZE_ENCODED_U32 && is_negative { + value |= -1 << shift; + } + return Ok((value, i + 1)); + } + shift += 7; + } + Err(()) +} + +impl Parse<()> for i32 { + fn parse(_ctx: (), bytes: &[u8], cursor: &mut usize) -> Result { + match decode_i32(&bytes[*cursor..]) { + Ok((value, len)) => { + *cursor += len; + Ok(value) + } + Err(()) => Err(ParseError { + offset: *cursor, + message: format!( + "Failed to decode i32 as LEB-128 from bytes: {:2x?}", + &bytes[*cursor..][..MAX_SIZE_ENCODED_U32] + ), + }), + } + } +} + 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)?; @@ -58,6 +96,40 @@ impl<'a> Parse<&'a Bump> for &'a str { } } +pub fn parse_variable_size_items<'a, T>( + arena: &'a Bump, + bytes: &[u8], + cursor: &mut usize, +) -> Result, ParseError> +where + T: Parse<&'a Bump>, +{ + let len = u32::parse((), bytes, cursor)?; + let mut vector: Vec<'a, T> = Vec::with_capacity_in(len as usize, arena); + for _ in 0..len { + let item = T::parse(arena, bytes, cursor)?; + vector.push(item); + } + Ok(vector) +} + +pub fn parse_fixed_size_items<'a, T>( + arena: &'a Bump, + bytes: &[u8], + cursor: &mut usize, +) -> Result, ParseError> +where + T: Parse<()>, +{ + let len = u32::parse((), bytes, cursor)?; + let mut vector: Vec<'a, T> = Vec::with_capacity_in(len as usize, arena); + for _ in 0..len { + let item = T::parse((), bytes, cursor)?; + vector.push(item); + } + Ok(vector) +} + /// Skip over serialized bytes for a type /// This may, or may not, require looking at the byte values pub trait SkipBytes: Sized {