This commit is contained in:
Chris Fallin 2022-11-02 20:29:30 -07:00
parent a73dacd5df
commit 86454940af
3 changed files with 237 additions and 31 deletions

View file

@ -11,7 +11,8 @@ use fxhash::{FxHashMap, FxHashSet};
use log::trace; use log::trace;
use std::convert::TryFrom; use std::convert::TryFrom;
use wasmparser::{ use wasmparser::{
Ieee32, Ieee64, ImportSectionEntryType, Parser, Payload, TypeDef, TypeOrFuncType, DataKind, ExternalKind, Ieee32, Ieee64, ImportSectionEntryType, Parser, Payload, TypeDef,
TypeOrFuncType,
}; };
pub fn wasm_to_ir(bytes: &[u8]) -> Result<Module<'_>> { pub fn wasm_to_ir(bytes: &[u8]) -> Result<Module<'_>> {
@ -33,46 +34,60 @@ fn handle_payload<'a>(
) -> Result<()> { ) -> Result<()> {
trace!("Wasm parser item: {:?}", payload); trace!("Wasm parser item: {:?}", payload);
match payload { match payload {
Payload::TypeSection(mut reader) => { Payload::TypeSection(reader) => {
for _ in 0..reader.get_count() { for ty in reader {
let ty = reader.read()?; let ty = ty?;
if let TypeDef::Func(fty) = ty { if let TypeDef::Func(fty) = ty {
module.frontend_add_signature(fty.into()); module.frontend_add_signature(fty.into());
} }
} }
} }
Payload::ImportSection(mut reader) => { Payload::ImportSection(reader) => {
for _ in 0..reader.get_count() { for import in reader {
match reader.read()?.ty { let import = import?;
let module_name = import.module.to_owned();
let name = import.field.unwrap_or("").to_owned();
let kind = match import.ty {
ImportSectionEntryType::Function(sig_idx) => { ImportSectionEntryType::Function(sig_idx) => {
let func =
module.frontend_add_func(FuncDecl::Import(Signature::from(sig_idx))); module.frontend_add_func(FuncDecl::Import(Signature::from(sig_idx)));
*next_func += 1; *next_func += 1;
Some(ImportKind::Func(func))
} }
ImportSectionEntryType::Global(ty) => { ImportSectionEntryType::Global(ty) => {
module.frontend_add_global(ty.content_type.into()); let global = module.frontend_add_global(ty.content_type.into());
Some(ImportKind::Global(global))
} }
ImportSectionEntryType::Table(ty) => { ImportSectionEntryType::Table(ty) => {
module.frontend_add_table(ty.element_type.into()); let table = module.frontend_add_table(ty.element_type.into());
Some(ImportKind::Table(table))
} }
_ => {} _ => None,
};
if let Some(kind) = kind {
module.frontend_add_import(Import {
module: module_name,
name,
kind,
});
} }
} }
} }
Payload::GlobalSection(mut reader) => { Payload::GlobalSection(reader) => {
for _ in 0..reader.get_count() { for global in reader {
let global = reader.read()?; let global = global?;
module.frontend_add_global(global.ty.content_type.into()); module.frontend_add_global(global.ty.content_type.into());
} }
} }
Payload::TableSection(mut reader) => { Payload::TableSection(reader) => {
for _ in 0..reader.get_count() { for table in reader {
let table = reader.read()?; let table = table?;
module.frontend_add_table(table.element_type.into()); module.frontend_add_table(table.element_type.into());
} }
} }
Payload::FunctionSection(mut reader) => { Payload::FunctionSection(reader) => {
for _ in 0..reader.get_count() { for sig_idx in reader {
let sig_idx = Signature::from(reader.read()?); let sig_idx = Signature::from(sig_idx?);
module.frontend_add_func(FuncDecl::Body(sig_idx, FunctionBody::default())); module.frontend_add_func(FuncDecl::Body(sig_idx, FunctionBody::default()));
} }
} }
@ -86,6 +101,71 @@ fn handle_payload<'a>(
let existing_body = module.func_mut(func_idx).body_mut().unwrap(); let existing_body = module.func_mut(func_idx).body_mut().unwrap();
*existing_body = body; *existing_body = body;
} }
Payload::ExportSection(reader) => {
for export in reader {
let export = export?;
let name = export.field.to_owned();
let kind = match export.kind {
ExternalKind::Function => Some(ExportKind::Func(Func::from(export.index))),
ExternalKind::Table => Some(ExportKind::Table(Table::from(export.index))),
ExternalKind::Global => Some(ExportKind::Global(Global::from(export.index))),
ExternalKind::Memory => Some(ExportKind::Memory(Memory::from(export.index))),
_ => None,
};
if let Some(kind) = kind {
module.frontend_add_export(Export { name, kind });
}
}
}
Payload::MemorySection(reader) => {
for memory in reader {
let memory = memory?;
module.frontend_add_memory(MemoryData {
initial_pages: memory.initial as usize,
maximum_pages: memory.maximum.map(|max| max as usize),
segments: vec![],
});
}
}
Payload::DataSection(reader) => {
for segment in reader {
let segment = segment?;
match &segment.kind {
DataKind::Passive => {}
DataKind::Active {
memory_index,
init_expr,
} => {
let data = segment.data.to_vec();
let memory = Memory::from(*memory_index);
let operators = init_expr
.get_operators_reader()
.into_iter()
.collect::<Result<Vec<wasmparser::Operator>, _>>()?;
if operators.len() != 2
|| !matches!(&operators[1], &wasmparser::Operator::End)
{
anyhow::bail!(
"Unsupported operator seq in base-address expr: {:?}",
operators
);
}
let offset = match &operators[0] {
&wasmparser::Operator::I32Const { value } => value as usize,
&wasmparser::Operator::I64Const { value } => value as usize,
op => anyhow::bail!(
"Unsupported data segment base-address operator: {:?}",
op
),
};
module
.frontend_memory_mut(memory)
.segments
.push(MemorySegment { offset, data });
}
}
}
}
_ => {} _ => {}
} }

View file

@ -158,6 +158,36 @@ impl<'a> Display for ModuleDisplay<'a> {
for (table, table_ty) in self.0.tables() { for (table, table_ty) in self.0.tables() {
writeln!(f, " {}: {}", table, table_ty)?; writeln!(f, " {}: {}", table, table_ty)?;
} }
for (memory, memory_data) in self.0.memories() {
writeln!(
f,
" {}: initial {} max {:?}",
memory, memory_data.initial_pages, memory_data.maximum_pages
)?;
for seg in &memory_data.segments {
writeln!(
f,
" {} offset {}: [{}]",
memory,
seg.offset,
seg.data
.iter()
.map(|&byte| format!("0x{:02x}", byte))
.collect::<Vec<_>>()
.join(", ")
)?;
}
}
for import in self.0.imports() {
writeln!(
f,
" import \"{}\".\"{}\": {}",
import.module, import.name, import.kind
)?;
}
for export in self.0.exports() {
writeln!(f, " export \"{}\": {}", export.name, export.kind)?;
}
for (func, func_decl) in self.0.funcs() { for (func, func_decl) in self.0.funcs() {
match func_decl { match func_decl {
FuncDecl::Body(sig, body) => { FuncDecl::Body(sig, body) => {

View file

@ -1,16 +1,19 @@
use super::{Func, FuncDecl, Global, ModuleDisplay, Signature, Table, Type}; use super::{Func, FuncDecl, Global, Memory, ModuleDisplay, Signature, Table, Type};
use crate::entity::EntityVec; use crate::entity::EntityVec;
use crate::frontend; use crate::frontend;
use anyhow::Result; use anyhow::Result;
use fxhash::FxHashSet; use fxhash::FxHashSet;
#[derive(Clone, Debug, Default)] #[derive(Clone, Debug)]
pub struct Module<'a> { pub struct Module<'a> {
orig_bytes: &'a [u8], orig_bytes: &'a [u8],
funcs: EntityVec<Func, FuncDecl>, funcs: EntityVec<Func, FuncDecl>,
signatures: EntityVec<Signature, SignatureData>, signatures: EntityVec<Signature, SignatureData>,
globals: EntityVec<Global, Type>, globals: EntityVec<Global, Type>,
tables: EntityVec<Table, Type>, tables: EntityVec<Table, Type>,
imports: Vec<Import>,
exports: Vec<Export>,
memories: EntityVec<Memory, MemoryData>,
dirty_funcs: FxHashSet<Func>, dirty_funcs: FxHashSet<Func>,
} }
@ -21,6 +24,19 @@ pub struct SignatureData {
pub returns: Vec<Type>, pub returns: Vec<Type>,
} }
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct MemoryData {
pub initial_pages: usize,
pub maximum_pages: Option<usize>,
pub segments: Vec<MemorySegment>,
}
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct MemorySegment {
pub offset: usize,
pub data: Vec<u8>,
}
impl From<&wasmparser::FuncType> for SignatureData { impl From<&wasmparser::FuncType> for SignatureData {
fn from(fty: &wasmparser::FuncType) -> Self { fn from(fty: &wasmparser::FuncType) -> Self {
Self { Self {
@ -43,11 +59,70 @@ impl From<wasmparser::FuncType> for SignatureData {
} }
} }
#[derive(Clone, Debug)]
pub struct Import {
pub module: String,
pub name: String,
pub kind: ImportKind,
}
#[derive(Clone, Debug)]
pub enum ImportKind {
Table(Table),
Func(Func),
Global(Global),
}
impl std::fmt::Display for ImportKind {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
match self {
ImportKind::Table(table) => write!(f, "{}", table)?,
ImportKind::Func(func) => write!(f, "{}", func)?,
ImportKind::Global(global) => write!(f, "{}", global)?,
}
Ok(())
}
}
#[derive(Clone, Debug)]
pub struct Export {
pub name: String,
pub kind: ExportKind,
}
#[derive(Clone, Debug)]
pub enum ExportKind {
Table(Table),
Func(Func),
Global(Global),
Memory(Memory),
}
impl std::fmt::Display for ExportKind {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
match self {
ExportKind::Table(table) => write!(f, "{}", table)?,
ExportKind::Func(func) => write!(f, "{}", func)?,
ExportKind::Global(global) => write!(f, "{}", global)?,
ExportKind::Memory(memory) => write!(f, "{}", memory)?,
}
Ok(())
}
}
impl<'a> Module<'a> { impl<'a> Module<'a> {
pub(crate) fn with_orig_bytes(orig_bytes: &'a [u8]) -> Module<'a> { pub(crate) fn with_orig_bytes(orig_bytes: &'a [u8]) -> Module<'a> {
let mut m = Module::default(); Module {
m.orig_bytes = orig_bytes; orig_bytes,
m funcs: EntityVec::default(),
signatures: EntityVec::default(),
globals: EntityVec::default(),
tables: EntityVec::default(),
imports: vec![],
exports: vec![],
memories: EntityVec::default(),
dirty_funcs: FxHashSet::default(),
}
} }
} }
@ -80,18 +155,39 @@ impl<'a> Module<'a> {
pub fn tables<'b>(&'b self) -> impl Iterator<Item = (Table, Type)> + 'b { pub fn tables<'b>(&'b self) -> impl Iterator<Item = (Table, Type)> + 'b {
self.tables.entries().map(|(id, ty)| (id, *ty)) self.tables.entries().map(|(id, ty)| (id, *ty))
} }
pub fn memories<'b>(&'b self) -> impl Iterator<Item = (Memory, &'b MemoryData)> + 'b {
self.memories.entries()
}
pub fn imports<'b>(&'b self) -> impl Iterator<Item = &'b Import> + 'b {
self.imports.iter()
}
pub fn exports<'b>(&'b self) -> impl Iterator<Item = &'b Export> + 'b {
self.exports.iter()
}
pub(crate) fn frontend_add_signature(&mut self, ty: SignatureData) { pub(crate) fn frontend_add_signature(&mut self, ty: SignatureData) {
self.signatures.push(ty); self.signatures.push(ty);
} }
pub(crate) fn frontend_add_func(&mut self, body: FuncDecl) { pub(crate) fn frontend_add_func(&mut self, body: FuncDecl) -> Func {
self.funcs.push(body); self.funcs.push(body)
} }
pub(crate) fn frontend_add_table(&mut self, ty: Type) { pub(crate) fn frontend_add_table(&mut self, ty: Type) -> Table {
self.tables.push(ty); self.tables.push(ty)
} }
pub(crate) fn frontend_add_global(&mut self, ty: Type) { pub(crate) fn frontend_add_global(&mut self, ty: Type) -> Global {
self.globals.push(ty); self.globals.push(ty)
}
pub(crate) fn frontend_add_import(&mut self, import: Import) {
self.imports.push(import);
}
pub(crate) fn frontend_add_export(&mut self, export: Export) {
self.exports.push(export);
}
pub(crate) fn frontend_add_memory(&mut self, memory: MemoryData) -> Memory {
self.memories.push(memory)
}
pub(crate) fn frontend_memory_mut<'b>(&'b mut self, memory: Memory) -> &'b mut MemoryData {
&mut self.memories[memory]
} }
pub fn from_wasm_bytes(bytes: &'a [u8]) -> Result<Self> { pub fn from_wasm_bytes(bytes: &'a [u8]) -> Result<Self> {