From 8f33b67404160ce8cf35a22c0d0993112b5abe9c Mon Sep 17 00:00:00 2001 From: Henry Gressmann Date: Mon, 18 Dec 2023 15:01:30 +0100 Subject: feat: global parsing, improve testsuite Signed-off-by: Henry Gressmann --- crates/parser/src/conversion.rs | 49 ++++++++++++++++++++++++++++++++++++++++- crates/parser/src/lib.rs | 3 +++ crates/parser/src/module.rs | 18 +++++++-------- 3 files changed, 60 insertions(+), 10 deletions(-) (limited to 'crates/parser/src') diff --git a/crates/parser/src/conversion.rs b/crates/parser/src/conversion.rs index 269bb66..9f4930a 100644 --- a/crates/parser/src/conversion.rs +++ b/crates/parser/src/conversion.rs @@ -1,10 +1,43 @@ use alloc::{boxed::Box, format, string::ToString, vec::Vec}; use log::info; -use tinywasm_types::{BlockArgs, Export, ExternalKind, FuncType, Instruction, MemArg, ValType}; +use tinywasm_types::{ + BlockArgs, ConstInstruction, Export, ExternalKind, FuncType, Global, Instruction, MemArg, ValType, +}; use wasmparser::{FuncValidator, ValidatorResources}; use crate::{module::CodeSection, Result}; +pub(crate) fn convert_module_globals<'a, T: IntoIterator>>>( + globals: T, +) -> Result> { + let globals = globals + .into_iter() + .map(|global| { + let global = global?; + let ty = convert_valtype(&global.ty.content_type); + + let ops = global + .init_expr + .get_operators_reader() + .into_iter() + .collect::>>()?; + + // In practice, the len can never be something other than 2, + // but we'll keep this here since it's part of the spec + // Invalid modules will be rejected by the validator anyway (there are also tests for this in the testsuite) + assert!(ops.len() >= 2); + assert!(matches!(ops[ops.len() - 1], wasmparser::Operator::End)); + + Ok(Global { + ty, + init: process_const_operator(ops[ops.len() - 2].clone())?, + mutable: global.ty.mutable, + }) + }) + .collect::>>()?; + Ok(globals) +} + pub(crate) fn convert_module_export(export: wasmparser::Export) -> Result { let kind = match export.kind { wasmparser::ExternalKind::Func => ExternalKind::Func, @@ -105,6 +138,20 @@ pub(crate) fn convert_memarg(memarg: wasmparser::MemArg) -> MemArg { } } +pub fn process_const_operator(op: wasmparser::Operator) -> Result { + match op { + wasmparser::Operator::I32Const { value } => Ok(ConstInstruction::I32Const(value)), + wasmparser::Operator::I64Const { value } => Ok(ConstInstruction::I64Const(value)), + wasmparser::Operator::F32Const { value } => Ok(ConstInstruction::F32Const(f32::from_bits(value.bits()))), // TODO: check if this is correct + wasmparser::Operator::F64Const { value } => Ok(ConstInstruction::F64Const(f64::from_bits(value.bits()))), // TODO: check if this is correct + wasmparser::Operator::GlobalGet { global_index } => Ok(ConstInstruction::GlobalGet(global_index)), + op => Err(crate::ParseError::UnsupportedOperator(format!( + "Unsupported instruction: {:?}", + op + ))), + } +} + pub fn process_operators<'a>( mut offset: usize, ops: impl Iterator, wasmparser::BinaryReaderError>>, diff --git a/crates/parser/src/lib.rs b/crates/parser/src/lib.rs index 0719c96..bcaef76 100644 --- a/crates/parser/src/lib.rs +++ b/crates/parser/src/lib.rs @@ -114,12 +114,15 @@ impl TryFrom for TinyWasmModule { }) .collect::>(); + let globals = reader.global_section; + Ok(TinyWasmModule { version: reader.version, start_func: reader.start_func, types: reader.type_section.into_boxed_slice(), funcs: funcs.into_boxed_slice(), exports: reader.export_section.into_boxed_slice(), + globals: globals.into_boxed_slice(), }) } } diff --git a/crates/parser/src/module.rs b/crates/parser/src/module.rs index 69bb894..6f823de 100644 --- a/crates/parser/src/module.rs +++ b/crates/parser/src/module.rs @@ -1,7 +1,7 @@ use crate::log::debug; use alloc::{boxed::Box, format, vec::Vec}; use core::fmt::Debug; -use tinywasm_types::{Export, FuncType, Instruction, ValType}; +use tinywasm_types::{Export, FuncType, Global, Instruction, ValType}; use wasmparser::{Payload, Validator}; use crate::{conversion, ParseError, Result}; @@ -21,10 +21,10 @@ pub struct ModuleReader { pub function_section: Vec, pub export_section: Vec, pub code_section: Vec, + pub global_section: Vec, // pub table_section: Option>, // pub memory_section: Option>, - // pub global_section: Option>, // pub element_section: Option>, // pub data_section: Option>, // pub import_section: Option>, @@ -39,9 +39,9 @@ impl Debug for ModuleReader { .field("function_section", &self.function_section) .field("code_section", &self.code_section) .field("export_section", &self.export_section) + .field("global_section", &self.global_section) // .field("table_section", &self.table_section) // .field("memory_section", &self.memory_section) - // .field("global_section", &self.global_section) // .field("element_section", &self.element_section) // .field("data_section", &self.data_section) // .field("import_section", &self.import_section) @@ -84,6 +84,11 @@ impl ModuleReader { validator.function_section(&reader)?; self.function_section = reader.into_iter().map(|f| Ok(f?)).collect::>>()?; } + GlobalSection(reader) => { + debug!("Found global section"); + validator.global_section(&reader)?; + self.global_section = conversion::convert_module_globals(reader)?; + } TableSection(_reader) => { return Err(ParseError::UnsupportedSection("Table section".into())); // debug!("Found table section"); @@ -96,12 +101,7 @@ impl ModuleReader { // validator.memory_section(&reader)?; // self.memory_section = Some(reader); } - GlobalSection(_reader) => { - return Err(ParseError::UnsupportedSection("Global section".into())); - // debug!("Found global section"); - // validator.global_section(&reader)?; - // self.global_section = Some(reader); - } + ElementSection(_reader) => { return Err(ParseError::UnsupportedSection("Element section".into())); // debug!("Found element section"); -- cgit v1.3.1