mirror of
https://github.com/roc-lang/roc.git
synced 2025-08-04 12:18:19 +00:00
wasm_module: create WasmModule::new for testing
This commit is contained in:
parent
2ca74e5070
commit
26cce05bbe
5 changed files with 133 additions and 6 deletions
|
@ -50,6 +50,26 @@ pub struct WasmModule<'a> {
|
|||
impl<'a> WasmModule<'a> {
|
||||
pub const WASM_VERSION: u32 = 1;
|
||||
|
||||
pub fn new(arena: &'a Bump) -> Self {
|
||||
WasmModule {
|
||||
types: TypeSection::new(arena),
|
||||
import: ImportSection::new(arena),
|
||||
function: FunctionSection::new(arena),
|
||||
table: TableSection::new(),
|
||||
memory: MemorySection::new(arena, 0),
|
||||
global: GlobalSection::new(arena),
|
||||
export: ExportSection::new(arena),
|
||||
start: OpaqueSection::new(),
|
||||
element: ElementSection::new(arena),
|
||||
code: CodeSection::new(arena),
|
||||
data: DataSection::new(arena),
|
||||
linking: LinkingSection::new(arena),
|
||||
reloc_code: RelocationSection::new(arena, "reloc.CODE"),
|
||||
reloc_data: RelocationSection::new(arena, "reloc.DATA"),
|
||||
names: NameSection::new(arena),
|
||||
}
|
||||
}
|
||||
|
||||
/// Create entries in the Type and Function sections for a function signature
|
||||
pub fn add_function_signature(&mut self, signature: Signature<'a>) {
|
||||
let index = self.types.insert(signature);
|
||||
|
|
|
@ -158,7 +158,7 @@ pub struct RelocationSection<'a> {
|
|||
}
|
||||
|
||||
impl<'a> RelocationSection<'a> {
|
||||
fn new(arena: &'a Bump, name: &'a str) -> Self {
|
||||
pub(crate) fn new(arena: &'a Bump, name: &'a str) -> Self {
|
||||
RelocationSection {
|
||||
name,
|
||||
target_section_index: 0,
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use super::serialize::MAX_SIZE_ENCODED_U32;
|
||||
use super::serialize::{MAX_SIZE_ENCODED_U32, MAX_SIZE_ENCODED_U64};
|
||||
use bumpalo::collections::vec::Vec;
|
||||
use bumpalo::Bump;
|
||||
|
||||
|
@ -92,6 +92,43 @@ impl Parse<()> for i32 {
|
|||
}
|
||||
}
|
||||
|
||||
/// Decode a signed 64-bit integer from the provided buffer in LEB-128 format
|
||||
/// Return the integer itself and the offset after it ends
|
||||
fn decode_i64(bytes: &[u8]) -> Result<(i64, usize), ()> {
|
||||
let mut value = 0;
|
||||
let mut shift = 0;
|
||||
for (i, byte) in bytes.iter().take(MAX_SIZE_ENCODED_U64).enumerate() {
|
||||
value |= ((byte & 0x7f) as i64) << shift;
|
||||
if (byte & 0x80) == 0 {
|
||||
let is_negative = byte & 0x40 != 0;
|
||||
if shift < MAX_SIZE_ENCODED_U64 && is_negative {
|
||||
value |= -1 << shift;
|
||||
}
|
||||
return Ok((value, i + 1));
|
||||
}
|
||||
shift += 7;
|
||||
}
|
||||
Err(())
|
||||
}
|
||||
|
||||
impl Parse<()> for i64 {
|
||||
fn parse(_ctx: (), bytes: &[u8], cursor: &mut usize) -> Result<Self, ParseError> {
|
||||
match decode_i64(&bytes[*cursor..]) {
|
||||
Ok((value, len)) => {
|
||||
*cursor += len;
|
||||
Ok(value)
|
||||
}
|
||||
Err(()) => Err(ParseError {
|
||||
offset: *cursor,
|
||||
message: format!(
|
||||
"Failed to decode i64 as LEB-128 from bytes: {:2x?}",
|
||||
&bytes[*cursor..][..MAX_SIZE_ENCODED_U64]
|
||||
),
|
||||
}),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Parse<&'a Bump> for &'a str {
|
||||
fn parse(arena: &'a Bump, bytes: &[u8], cursor: &mut usize) -> Result<Self, ParseError> {
|
||||
let len = u32::parse((), bytes, cursor)?;
|
||||
|
|
|
@ -220,6 +220,14 @@ pub struct TypeSection<'a> {
|
|||
}
|
||||
|
||||
impl<'a> TypeSection<'a> {
|
||||
pub fn new(arena: &'a Bump) -> Self {
|
||||
TypeSection {
|
||||
arena,
|
||||
bytes: Vec::new_in(arena),
|
||||
offsets: Vec::new_in(arena),
|
||||
}
|
||||
}
|
||||
|
||||
/// Find a matching signature or insert a new one. Return the index.
|
||||
pub fn insert(&mut self, signature: Signature<'a>) -> u32 {
|
||||
let mut sig_bytes = Vec::with_capacity_in(signature.param_types.len() + 4, self.arena);
|
||||
|
@ -425,6 +433,12 @@ pub struct ImportSection<'a> {
|
|||
impl<'a> ImportSection<'a> {
|
||||
const ID: SectionId = SectionId::Import;
|
||||
|
||||
pub fn new(arena: &'a Bump) -> Self {
|
||||
ImportSection {
|
||||
imports: Vec::new_in(arena),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn size(&self) -> usize {
|
||||
self.imports.iter().map(|imp| imp.size()).sum()
|
||||
}
|
||||
|
@ -488,6 +502,12 @@ pub struct FunctionSection<'a> {
|
|||
}
|
||||
|
||||
impl<'a> FunctionSection<'a> {
|
||||
pub fn new(arena: &'a Bump) -> Self {
|
||||
FunctionSection {
|
||||
signatures: Vec::new_in(arena),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn add_sig(&mut self, sig_id: u32) {
|
||||
self.signatures.push(sig_id);
|
||||
}
|
||||
|
@ -590,6 +610,15 @@ pub struct TableSection {
|
|||
impl TableSection {
|
||||
const ID: SectionId = SectionId::Table;
|
||||
|
||||
pub fn new() -> Self {
|
||||
TableSection {
|
||||
function_table: TableType {
|
||||
ref_type: RefType::Func,
|
||||
limits: Limits::Min(0),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
pub fn size(&self) -> usize {
|
||||
let section_id_bytes = 1;
|
||||
let section_length_bytes = 1;
|
||||
|
@ -880,6 +909,13 @@ pub struct GlobalSection<'a> {
|
|||
}
|
||||
|
||||
impl<'a> GlobalSection<'a> {
|
||||
pub fn new(arena: &'a Bump) -> Self {
|
||||
GlobalSection {
|
||||
count: 0,
|
||||
bytes: Vec::new_in(arena),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn parse_u32_at_index(&self, index: u32) -> Result<u32, ParseError> {
|
||||
let mut cursor = 0;
|
||||
for _ in 0..index {
|
||||
|
@ -961,6 +997,12 @@ pub struct ExportSection<'a> {
|
|||
impl<'a> ExportSection<'a> {
|
||||
const ID: SectionId = SectionId::Export;
|
||||
|
||||
pub fn new(arena: &'a Bump) -> Self {
|
||||
ExportSection {
|
||||
exports: Vec::new_in(arena),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn append(&mut self, export: Export<'a>) {
|
||||
self.exports.push(export);
|
||||
}
|
||||
|
@ -1086,6 +1128,12 @@ pub struct ElementSection<'a> {
|
|||
impl<'a> ElementSection<'a> {
|
||||
const ID: SectionId = SectionId::Element;
|
||||
|
||||
pub fn new(arena: &'a Bump) -> Self {
|
||||
ElementSection {
|
||||
segments: Vec::new_in(arena),
|
||||
}
|
||||
}
|
||||
|
||||
/// Get a table index for a function (equivalent to a function pointer)
|
||||
/// The function will be inserted into the table if it's not already there.
|
||||
/// This index is what the call_indirect instruction expects.
|
||||
|
@ -1179,6 +1227,15 @@ pub struct CodeSection<'a> {
|
|||
}
|
||||
|
||||
impl<'a> CodeSection<'a> {
|
||||
pub fn new(arena: &'a Bump) -> Self {
|
||||
CodeSection {
|
||||
function_count: 0,
|
||||
bytes: Vec::new_in(arena),
|
||||
function_offsets: Vec::new_in(arena),
|
||||
dead_import_dummy_count: 0,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn size(&self) -> usize {
|
||||
MAX_SIZE_SECTION_HEADER + self.bytes.len()
|
||||
}
|
||||
|
@ -1329,6 +1386,14 @@ pub struct DataSection<'a> {
|
|||
impl<'a> DataSection<'a> {
|
||||
const ID: SectionId = SectionId::Data;
|
||||
|
||||
pub fn new(arena: &'a Bump) -> Self {
|
||||
DataSection {
|
||||
end_addr: 0,
|
||||
count: 0,
|
||||
bytes: Vec::new_in(arena),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn size(&self) -> usize {
|
||||
MAX_SIZE_SECTION_HEADER + self.bytes.len()
|
||||
}
|
||||
|
@ -1394,6 +1459,10 @@ pub struct OpaqueSection<'a> {
|
|||
}
|
||||
|
||||
impl<'a> OpaqueSection<'a> {
|
||||
pub fn new() -> Self {
|
||||
OpaqueSection { bytes: &[] }
|
||||
}
|
||||
|
||||
pub fn size(&self) -> usize {
|
||||
self.bytes.len()
|
||||
}
|
||||
|
@ -1464,7 +1533,7 @@ impl<'a> NameSection<'a> {
|
|||
self.function_names.push((index, name));
|
||||
}
|
||||
|
||||
pub fn empty(arena: &'a Bump) -> Self {
|
||||
pub fn new(arena: &'a Bump) -> Self {
|
||||
NameSection {
|
||||
function_names: bumpalo::vec![in arena],
|
||||
}
|
||||
|
@ -1502,12 +1571,12 @@ impl<'a> Parse<&'a Bump> for NameSection<'a> {
|
|||
|
||||
// If we're already past the end of the preloaded file then there is no Name section
|
||||
if *cursor >= module_bytes.len() {
|
||||
return Ok(Self::empty(arena));
|
||||
return Ok(Self::new(arena));
|
||||
}
|
||||
|
||||
// Custom section ID
|
||||
if module_bytes[*cursor] != Self::ID as u8 {
|
||||
return Ok(Self::empty(arena));
|
||||
return Ok(Self::new(arena));
|
||||
}
|
||||
*cursor += 1;
|
||||
|
||||
|
@ -1520,7 +1589,7 @@ impl<'a> Parse<&'a Bump> for NameSection<'a> {
|
|||
// This is a different Custom section. This host has no debug info.
|
||||
// Not a parse error, just an empty section.
|
||||
*cursor = cursor_start;
|
||||
return Ok(Self::empty(arena));
|
||||
return Ok(Self::new(arena));
|
||||
}
|
||||
|
||||
// Find function names subsection
|
||||
|
|
|
@ -6,6 +6,7 @@ use std::fmt::Debug;
|
|||
/// In practice, this saves space, since small numbers used more often than large numbers.
|
||||
/// Of course there is a price for this - an encoded U32 can be up to 5 bytes wide.
|
||||
pub const MAX_SIZE_ENCODED_U32: usize = 5;
|
||||
pub const MAX_SIZE_ENCODED_U64: usize = 10;
|
||||
|
||||
pub trait Serialize {
|
||||
fn serialize<T: SerialBuffer>(&self, buffer: &mut T);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue