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 std::convert::TryFrom;
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<'_>> {
@ -33,46 +34,60 @@ fn handle_payload<'a>(
) -> Result<()> {
trace!("Wasm parser item: {:?}", payload);
match payload {
Payload::TypeSection(mut reader) => {
for _ in 0..reader.get_count() {
let ty = reader.read()?;
Payload::TypeSection(reader) => {
for ty in reader {
let ty = ty?;
if let TypeDef::Func(fty) = ty {
module.frontend_add_signature(fty.into());
}
}
}
Payload::ImportSection(mut reader) => {
for _ in 0..reader.get_count() {
match reader.read()?.ty {
Payload::ImportSection(reader) => {
for import in reader {
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) => {
module.frontend_add_func(FuncDecl::Import(Signature::from(sig_idx)));
let func =
module.frontend_add_func(FuncDecl::Import(Signature::from(sig_idx)));
*next_func += 1;
Some(ImportKind::Func(func))
}
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) => {
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) => {
for _ in 0..reader.get_count() {
let global = reader.read()?;
Payload::GlobalSection(reader) => {
for global in reader {
let global = global?;
module.frontend_add_global(global.ty.content_type.into());
}
}
Payload::TableSection(mut reader) => {
for _ in 0..reader.get_count() {
let table = reader.read()?;
Payload::TableSection(reader) => {
for table in reader {
let table = table?;
module.frontend_add_table(table.element_type.into());
}
}
Payload::FunctionSection(mut reader) => {
for _ in 0..reader.get_count() {
let sig_idx = Signature::from(reader.read()?);
Payload::FunctionSection(reader) => {
for sig_idx in reader {
let sig_idx = Signature::from(sig_idx?);
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();
*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() {
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() {
match func_decl {
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::frontend;
use anyhow::Result;
use fxhash::FxHashSet;
#[derive(Clone, Debug, Default)]
#[derive(Clone, Debug)]
pub struct Module<'a> {
orig_bytes: &'a [u8],
funcs: EntityVec<Func, FuncDecl>,
signatures: EntityVec<Signature, SignatureData>,
globals: EntityVec<Global, Type>,
tables: EntityVec<Table, Type>,
imports: Vec<Import>,
exports: Vec<Export>,
memories: EntityVec<Memory, MemoryData>,
dirty_funcs: FxHashSet<Func>,
}
@ -21,6 +24,19 @@ pub struct SignatureData {
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 {
fn from(fty: &wasmparser::FuncType) -> 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> {
pub(crate) fn with_orig_bytes(orig_bytes: &'a [u8]) -> Module<'a> {
let mut m = Module::default();
m.orig_bytes = orig_bytes;
m
Module {
orig_bytes,
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 {
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) {
self.signatures.push(ty);
}
pub(crate) fn frontend_add_func(&mut self, body: FuncDecl) {
self.funcs.push(body);
pub(crate) fn frontend_add_func(&mut self, body: FuncDecl) -> Func {
self.funcs.push(body)
}
pub(crate) fn frontend_add_table(&mut self, ty: Type) {
self.tables.push(ty);
pub(crate) fn frontend_add_table(&mut self, ty: Type) -> Table {
self.tables.push(ty)
}
pub(crate) fn frontend_add_global(&mut self, ty: Type) {
self.globals.push(ty);
pub(crate) fn frontend_add_global(&mut self, ty: Type) -> Global {
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> {