WIP.
This commit is contained in:
parent
a73dacd5df
commit
86454940af
120
src/frontend.rs
120
src/frontend.rs
|
@ -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 });
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
||||
|
|
|
@ -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) => {
|
||||
|
|
118
src/ir/module.rs
118
src/ir/module.rs
|
@ -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> {
|
||||
|
|
Loading…
Reference in a new issue