use std::sync::Arc;
use crate::canon::{IrHeap, IrVal};
use crate::module::handler::HandlerSpan;
use crate::module::inner::ModuleInner;
use crate::module::op::{BigMemArg, BranchTarget, Op, TypeIdx};
#[derive(Copy, Clone, Debug, Default, serde::Serialize, serde::Deserialize)]
pub(crate) struct Span {
pub start: u32,
pub len: u32,
}
impl Span {
#[inline]
pub(crate) fn range(self) -> std::ops::Range<usize> {
self.start as usize..self.start.saturating_add(self.len) as usize
}
#[inline]
fn of<T>(self, arena: &[T]) -> crate::Result<&[T]> {
arena.get(self.range()).ok_or_else(span_error)
}
}
#[cold]
fn span_error() -> crate::Error {
crate::error::InternalError::Compiler("code span out of range").into()
}
#[derive(Debug, Default, serde::Serialize, serde::Deserialize)]
pub(crate) struct CodeArenas {
pub ops: Vec<Op>,
pub local_types: Vec<IrVal>,
pub handlers: Vec<HandlerSpan>,
pub br_tables: Vec<BranchTarget>,
pub big_memargs: Vec<BigMemArg>,
pub offsets: Vec<u32>,
pub v128s: Vec<[u8; 16]>,
pub cast_heaps: Vec<IrHeap>,
}
#[derive(Copy, Clone, Debug, serde::Serialize, serde::Deserialize)]
pub(crate) struct CompiledFunc {
pub ops: Span,
pub type_idx: TypeIdx,
pub n_params: u32,
pub n_results: u32,
pub local_types: Span,
pub max_operands: u32,
pub handlers: Span,
pub br_tables: Span,
pub big_memargs: Span,
pub offsets: Span,
}
#[derive(Debug, Clone)]
pub(crate) struct Code {
pub module: Arc<ModuleInner>,
pub index: u32,
}
#[allow(clippy::indexing_slicing)]
impl Code {
#[inline]
pub(crate) fn key(&self) -> usize {
Arc::as_ptr(&self.module).addr()
}
#[inline]
fn f(&self) -> &CompiledFunc {
&self.module.functions[self.index as usize]
}
#[inline]
pub(crate) fn func(&self) -> CompiledFunc {
*self.f()
}
#[inline]
pub(crate) fn enter_defined(&mut self, index: u32) -> Option<u32> {
if index as usize >= self.module.functions.len() {
return None;
}
let func_index = index.checked_add(self.module.num_imported_funcs)?;
self.index = index;
Some(func_index)
}
#[inline]
pub(crate) fn ops_in(&self, span: Span) -> crate::Result<&[Op]> {
span.of(&self.module.code.ops)
}
#[inline]
pub(crate) fn local_types_of(&self, f: &CompiledFunc) -> crate::Result<&[IrVal]> {
f.local_types.of(&self.module.code.local_types)
}
#[inline]
pub(crate) fn handlers(&self) -> crate::Result<&[HandlerSpan]> {
self.f().handlers.of(&self.module.code.handlers)
}
#[inline]
pub(crate) fn br_tables(&self) -> crate::Result<&[BranchTarget]> {
self.f().br_tables.of(&self.module.code.br_tables)
}
#[inline]
pub(crate) fn big_memargs(&self) -> crate::Result<&[BigMemArg]> {
self.f().big_memargs.of(&self.module.code.big_memargs)
}
#[inline]
pub(crate) fn offsets(&self) -> Option<&[u32]> {
let span = self.f().offsets;
if span.len == 0 {
return None;
}
span.of(&self.module.code.offsets).ok()
}
pub(crate) fn cast_heap(&self, index: u32) -> crate::Result<&IrHeap> {
self.module
.code
.cast_heaps
.get(index as usize)
.ok_or_else(|| {
crate::error::InternalError::Compiler("cast heap index out of range").into()
})
}
pub(crate) fn v128(&self, index: u32) -> crate::Result<[u8; 16]> {
self.module
.code
.v128s
.get(index as usize)
.copied()
.ok_or_else(|| {
crate::error::InternalError::Compiler("SIMD immediate index out of range").into()
})
}
#[inline]
pub(crate) fn type_idx(&self) -> TypeIdx {
self.f().type_idx
}
#[inline]
pub(crate) fn n_params(&self) -> u32 {
self.f().n_params
}
#[inline]
pub(crate) fn n_results(&self) -> u32 {
self.f().n_results
}
#[inline]
pub(crate) fn max_operands(&self) -> u32 {
self.f().max_operands
}
}