//! `environment` holds the state of the compiler. 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> { // Output dir pub output_file: &'b Path, // Inkwell code generator pub context: &'a Context, pub module: &'b Module<'a>, pub builder: Builder<'a>, // Set of primitive types of inkwell pub inkwell_types: InkwellTypes<'a>, pub inkwell_insts: InkwellInsts<'a>, // List of all signatures pub function_signature_list: Vec>, // List of functions pub function_list: Vec>, pub function_list_signature: Vec, pub function_list_name: Vec, // Stack for Wasm binary pub stack: Vec>, // Global variables pub global: Vec>, pub import_section_size: u32, pub function_section_size: u32, pub current_function_idx: u32, // ControlFrame pub control_frames: Vec>, pub wasker_init_block: Option>, pub wasker_main_block: Option>, pub linear_memory_offset_global: Option>, // Caution: Can only used in wasker_init pub linear_memory_offset_int: Option>, pub start_function_idx: Option, pub unreachable_depth: u32, pub unreachable_reason: UnreachableReason, // Table pub global_table: Option>, // Memory pub global_memory_size: Option>, pub fn_memory_grow: Option>, } 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, } } /// Restore the stack to the specified size. pub fn reset_stack(&mut self, stack_size: usize) { self.stack.truncate(stack_size); } /// Pop the stack and load the value if it is a pointer. 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 } } /// Get the control frame immediately outside the current control frame. 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] } /// Pop two values from the stack. 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) } /// Peek values from the stack. 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..]) } }