use crate::error::Error;
use crate::ir::id::{GlobalID, ImportsID};
use crate::ir::module::module_imports::ModuleImports;
use crate::ir::module::{GetID, Iter, LocalOrImport, ReIndexable};
use crate::InitExpr;
use std::vec::IntoIter;
use wasmparser::{GlobalType, TypeRef};
type Result<T> = std::result::Result<T, Error>;
#[derive(Clone, Debug)]
pub enum GlobalKind {
Local(LocalGlobal),
Import(ImportedGlobal),
}
#[derive(Clone, Debug)]
pub struct LocalGlobal {
pub global_id: GlobalID,
pub ty: GlobalType,
pub init_expr: InitExpr,
}
#[derive(Clone, Debug)]
pub struct ImportedGlobal {
pub import_id: ImportsID, pub(crate) import_global_id: GlobalID, pub ty: GlobalType,
}
impl ImportedGlobal {
pub(crate) fn new(import_id: ImportsID, import_global_id: GlobalID, ty: GlobalType) -> Self {
Self {
import_id,
import_global_id,
ty,
}
}
}
#[derive(Debug, Clone)]
pub struct Global {
pub(crate) kind: GlobalKind,
pub(crate) deleted: bool,
}
impl GetID for Global {
fn get_id(&self) -> u32 {
match &self.kind {
GlobalKind::Local(LocalGlobal { global_id, .. })
| GlobalKind::Import(ImportedGlobal {
import_global_id: global_id,
..
}) => **global_id,
}
}
}
impl LocalOrImport for Global {
fn is_local(&self) -> bool {
matches!(&self.kind, GlobalKind::Local(_))
}
fn is_import(&self) -> bool {
matches!(&self.kind, GlobalKind::Import(_))
}
fn is_deleted(&self) -> bool {
self.deleted
}
}
impl Global {
pub fn new(kind: GlobalKind) -> Self {
Self {
kind,
deleted: false,
}
}
pub(crate) fn from_wasmparser(global: wasmparser::Global) -> Result<Global> {
let ty = global.ty;
let init_expr = InitExpr::eval(&global.init_expr);
Ok(Global {
kind: GlobalKind::Local(LocalGlobal {
global_id: GlobalID(0),
ty,
init_expr,
}),
deleted: false,
})
}
pub(crate) fn set_id(&mut self, id: GlobalID) {
match &mut self.kind {
GlobalKind::Local(LocalGlobal { global_id, .. })
| GlobalKind::Import(ImportedGlobal {
import_global_id: global_id,
..
}) => {
*global_id = id;
}
}
}
fn delete(&mut self) {
self.deleted = true;
}
}
#[derive(Clone, Debug, Default)]
pub struct ModuleGlobals {
globals: Vec<Global>,
pub(crate) recalculate_ids: bool,
}
impl Iter<Global> for ModuleGlobals {
fn iter(&self) -> std::slice::Iter<'_, Global> {
self.globals.iter()
}
fn get_into_iter(&self) -> IntoIter<Global> {
self.globals.clone().into_iter()
}
}
impl ReIndexable<Global> for ModuleGlobals {
fn len(&self) -> usize {
self.globals.len()
}
fn remove(&mut self, global_id: u32) -> Global {
self.globals.remove(global_id as usize)
}
fn insert(&mut self, global_id: u32, global: Global) {
self.globals.insert(global_id as usize, global);
}
fn push(&mut self, global: Global) {
self.globals.push(global);
}
}
impl ModuleGlobals {
pub fn new(imports: &ModuleImports, local_globals: Vec<Global>) -> Self {
let mut result = ModuleGlobals::default();
let mut curr_global_id: u32 = 0;
for (id, import) in imports.iter().enumerate() {
if let TypeRef::Global(ty) = import.ty {
curr_global_id += 1;
result.add(Global {
kind: GlobalKind::Import(ImportedGlobal {
import_id: ImportsID(id as u32),
import_global_id: GlobalID(curr_global_id),
ty,
}),
deleted: false,
});
};
}
for global in local_globals.iter() {
let mut owned = global.to_owned();
owned.set_id(GlobalID(curr_global_id));
curr_global_id += 1;
result.add(owned);
}
result
}
pub fn get_kind(&self, global_id: GlobalID) -> &GlobalKind {
&self.globals[*global_id as usize].kind
}
pub fn iter(&self) -> std::slice::Iter<'_, Global> {
self.globals.iter()
}
pub fn len(&self) -> usize {
self.globals.len()
}
pub fn is_empty(&self) -> bool {
self.globals.is_empty()
}
pub(crate) fn delete(&mut self, id: GlobalID) {
self.recalculate_ids = true;
if *id < self.globals.len() as u32 {
self.globals[*id as usize].delete();
}
}
pub(crate) fn add(&mut self, mut global: Global) -> GlobalID {
let id = GlobalID(self.globals.len() as u32);
global.set_id(id);
self.globals.push(global);
id
}
}