use anyhow::{bail, Result};
use inkwell::{
basic_block::BasicBlock,
builder::Builder,
context::Context,
module::Module,
types::{BasicTypeEnum, FunctionType},
values::{BasicValueEnum, FunctionValue, GlobalValue, IntValue},
};
use std::path::Path;
use crate::inkwell::{InkwellInsts, InkwellTypes};
use crate::insts::control::{ControlFrame, UnreachableReason};
pub enum Global<'a> {
Mut {
ptr_to_value: GlobalValue<'a>,
ty: BasicTypeEnum<'a>,
},
Const {
value: BasicValueEnum<'a>,
},
}
pub struct Environment<'a, 'b> {
pub output_file: &'b Path,
pub context: &'a Context,
pub module: &'b Module<'a>,
pub builder: Builder<'a>,
pub inkwell_types: InkwellTypes<'a>,
pub inkwell_insts: InkwellInsts<'a>,
pub function_signature_list: Vec<FunctionType<'a>>,
pub function_list: Vec<FunctionValue<'a>>,
pub function_list_signature: Vec<u32>,
pub function_list_name: Vec<String>,
pub stack: Vec<BasicValueEnum<'a>>,
pub global: Vec<Global<'a>>,
pub import_section_size: u32,
pub function_section_size: u32,
pub current_function_idx: u32,
pub control_frames: Vec<ControlFrame<'a>>,
pub wasker_init_block: Option<BasicBlock<'a>>,
pub wasker_main_block: Option<BasicBlock<'a>>,
pub linear_memory_offset_global: Option<GlobalValue<'a>>,
pub linear_memory_offset_int: Option<IntValue<'a>>,
pub start_function_idx: Option<u32>,
pub unreachable_depth: u32,
pub unreachable_reason: UnreachableReason,
pub global_table: Option<GlobalValue<'a>>,
pub global_memory_size: Option<GlobalValue<'a>>,
pub fn_memory_grow: Option<FunctionValue<'a>>,
}
impl<'a, 'b> Environment<'a, 'b> {
pub fn new(
output_file: &'b Path,
context: &'a Context,
module: &'b Module<'a>,
builder: Builder<'a>,
inkwell_types: InkwellTypes<'a>,
inkwell_insts: InkwellInsts<'a>,
) -> Self {
Self {
output_file,
context,
module,
builder,
inkwell_types,
inkwell_insts,
function_signature_list: Vec::new(),
function_list: Vec::new(),
function_list_signature: Vec::new(),
function_list_name: Vec::new(),
stack: Vec::new(),
global: Vec::new(),
import_section_size: 0,
function_section_size: 0,
current_function_idx: u32::MAX,
control_frames: Vec::new(),
wasker_init_block: None,
wasker_main_block: None,
linear_memory_offset_global: None,
linear_memory_offset_int: None,
start_function_idx: None,
unreachable_depth: 0,
unreachable_reason: UnreachableReason::Reachable,
global_table: None,
global_memory_size: None,
fn_memory_grow: None,
}
}
pub fn reset_stack(&mut self, stack_size: usize) {
self.stack.truncate(stack_size);
}
pub fn pop_and_load(&mut self) -> BasicValueEnum<'a> {
let pop = self.stack.pop().expect("stack empty");
if pop.is_pointer_value() {
self.builder.build_load(
self.inkwell_types.i64_type,
pop.into_pointer_value(),
"from_stack",
)
} else {
pop
}
}
pub fn ref_outer_frame(&self) -> &ControlFrame<'a> {
let frame_len = self.control_frames.len();
assert_ne!(frame_len, 0);
&self.control_frames[frame_len - 1]
}
pub fn pop2(&mut self) -> (BasicValueEnum<'a>, BasicValueEnum<'a>) {
let v2 = self.stack.pop().expect("stack empty");
let v1 = self.stack.pop().expect("stack empty");
(v1, v2)
}
pub fn peekn(&self, n: usize) -> Result<&[BasicValueEnum<'a>]> {
if self.stack.len() < n {
bail!("stack length too short {} vs {}", self.stack.len(), n);
}
let index = self.stack.len() - n;
Ok(&self.stack[index..])
}
}