use crate::Engine;
use crate::Module;
use crate::Result;
use crate::module::ModuleRegistry;
use crate::vm::ModuleMemoryImageSource;
use crate::{code_memory::CodeMemory, type_registry::TypeCollection};
#[cfg(feature = "debug")]
use alloc::boxed::Box;
use alloc::sync::Arc;
use core::ops::{Add, Range, Sub};
use wasmtime_environ::DefinedFuncIndex;
use wasmtime_environ::ModuleTypes;
#[cfg(feature = "component-model")]
use wasmtime_environ::component::ComponentTypes;
macro_rules! define_pc_kind {
($ty:ident) => {
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct $ty(usize);
impl Add<usize> for $ty {
type Output = $ty;
fn add(self, other: usize) -> $ty {
$ty(self.0.wrapping_add(other))
}
}
impl Sub<usize> for $ty {
type Output = $ty;
fn sub(self, other: usize) -> $ty {
$ty(self.0.wrapping_sub(other))
}
}
impl $ty {
pub fn offset_of(range: Range<$ty>, pc: usize) -> Option<usize> {
if pc >= range.start.0 && pc < range.end.0 {
Some(pc.wrapping_sub(range.start.0))
} else {
None
}
}
pub fn raw(&self) -> usize {
self.0
}
}
};
}
define_pc_kind!(EngineCodePC);
define_pc_kind!(StoreCodePC);
impl StoreCodePC {
pub fn from_raw(pc: usize) -> StoreCodePC {
StoreCodePC(pc)
}
}
pub struct EngineCode {
original_code: Arc<CodeMemory>,
signatures: TypeCollection,
types: Types,
}
impl EngineCode {
pub fn new(mmap: Arc<CodeMemory>, signatures: TypeCollection, types: Types) -> EngineCode {
crate::module::register_code(&mmap, mmap.raw_addr_range());
EngineCode {
original_code: mmap,
signatures,
types,
}
}
#[cfg(feature = "component-model")]
pub fn types(&self) -> &Types {
&self.types
}
pub fn module_types(&self) -> &ModuleTypes {
self.types.module_types()
}
pub fn signatures(&self) -> &TypeCollection {
&self.signatures
}
pub fn text_size(&self) -> usize {
self.original_code.text().len()
}
pub fn text_range(&self) -> Range<EngineCodePC> {
let raw = self.original_code.raw_addr_range();
EngineCodePC(raw.start)..EngineCodePC(raw.end)
}
pub(crate) fn raw_wasm_to_array_trampoline_data(&self, range: Range<usize>) -> &[u8] {
&self.original_code.text()[range]
}
pub fn address_map_data(&self) -> &[u8] {
self.original_code.address_map_data()
}
pub fn stack_map_data(&self) -> &[u8] {
self.original_code.stack_map_data()
}
pub fn exception_tables(&self) -> &[u8] {
self.original_code.exception_tables()
}
pub fn frame_tables(&self) -> &[u8] {
self.original_code.frame_tables()
}
#[inline]
pub fn func_name_data(&self) -> &[u8] {
self.original_code.func_name_data()
}
#[inline]
pub fn wasm_dwarf(&self) -> &[u8] {
self.original_code.wasm_dwarf()
}
pub fn image(&self) -> &[u8] {
&self.original_code.mmap()[..]
}
pub fn text(&self) -> &[u8] {
&self.original_code.text()
}
#[inline]
pub fn wasm_data(&self) -> &[u8] {
self.original_code.wasm_data()
}
pub(crate) fn module_memory_image_source(&self) -> &Arc<impl ModuleMemoryImageSource> {
&self.original_code
}
}
impl Drop for EngineCode {
fn drop(&mut self) {
crate::module::unregister_code(self.original_code.raw_addr_range());
}
}
pub enum Types {
Module(ModuleTypes),
#[cfg(feature = "component-model")]
Component(Arc<ComponentTypes>),
}
impl Types {
fn module_types(&self) -> &ModuleTypes {
match self {
Types::Module(m) => m,
#[cfg(feature = "component-model")]
Types::Component(c) => c.module_types(),
}
}
}
impl From<ModuleTypes> for Types {
fn from(types: ModuleTypes) -> Types {
Types::Module(types)
}
}
#[cfg(feature = "component-model")]
impl From<Arc<ComponentTypes>> for Types {
fn from(types: Arc<ComponentTypes>) -> Types {
Types::Component(types)
}
}
pub struct StoreCode(StoreCodeStorage);
enum StoreCodeStorage {
Shared(Arc<CodeMemory>),
#[cfg(feature = "debug")]
Private(Box<CodeMemory>),
}
impl StoreCode {
pub fn new(engine: &Engine, engine_code: &Arc<EngineCode>) -> Result<Self> {
#[cfg(feature = "debug")]
let code = if engine.tunables().debug_guest {
let mut private_copy = engine_code.original_code.deep_clone(engine)?;
private_copy.publish()?;
crate::module::register_code(&engine_code.original_code, private_copy.raw_addr_range());
StoreCodeStorage::Private(Box::new(private_copy))
} else {
StoreCodeStorage::Shared(engine_code.original_code.clone())
};
#[cfg(not(feature = "debug"))]
let code = StoreCodeStorage::Shared(engine_code.original_code.clone());
let _ = engine;
Ok(StoreCode(code))
}
pub fn code_memory(&self) -> &CodeMemory {
match &self.0 {
StoreCodeStorage::Shared(m) => m,
#[cfg(feature = "debug")]
StoreCodeStorage::Private(m) => m,
}
}
#[cfg(feature = "debug")]
pub fn code_memory_mut(&mut self) -> Option<&mut CodeMemory> {
match &mut self.0 {
StoreCodeStorage::Shared(_) => None,
StoreCodeStorage::Private(m) => Some(m),
}
}
pub fn text_range(&self) -> Range<StoreCodePC> {
let raw = self.code_memory().raw_addr_range();
StoreCodePC(raw.start)..StoreCodePC(raw.end)
}
pub fn text(&self) -> &[u8] {
self.code_memory().text()
}
}
impl Drop for StoreCode {
fn drop(&mut self) {
match &self.0 {
StoreCodeStorage::Shared(_) => {
}
#[cfg(feature = "debug")]
StoreCodeStorage::Private(mem) => {
crate::module::unregister_code(mem.raw_addr_range());
}
}
}
}
pub struct ModuleWithCode<'a> {
module: &'a Module,
store_code: &'a StoreCode,
}
impl<'a> ModuleWithCode<'a> {
pub fn in_store(
registry: &'a ModuleRegistry,
module: &'a Module,
) -> Option<ModuleWithCode<'a>> {
let store_code = registry.store_code(module.engine_code())?;
Some(ModuleWithCode { module, store_code })
}
pub(crate) fn from_raw(module: &'a Module, store_code: &'a StoreCode) -> ModuleWithCode<'a> {
ModuleWithCode { module, store_code }
}
pub fn module(&self) -> &'a Module {
self.module
}
pub fn store_code(&self) -> &'a StoreCode {
self.store_code
}
#[inline]
pub fn finished_functions(
&self,
) -> impl ExactSizeIterator<Item = (DefinedFuncIndex, &[u8])> + '_ {
self.module
.env_module()
.defined_func_indices()
.map(|i| (i, self.finished_function(i)))
}
#[inline]
pub fn finished_function(&self, def_func_index: DefinedFuncIndex) -> &[u8] {
let range = self
.module
.compiled_module()
.finished_function_range(def_func_index);
&self.store_code.text()[range]
}
pub fn array_to_wasm_trampoline(&self, def_func_index: DefinedFuncIndex) -> Option<&[u8]> {
let range = self
.module
.compiled_module()
.array_to_wasm_trampoline_range(def_func_index)?;
Some(&self.store_code.text()[range])
}
#[cfg(feature = "gc")]
pub(crate) fn text_offset(&self, pc: usize) -> Option<u32> {
StoreCodePC::offset_of(self.store_code.text_range(), pc)
.map(|offset| u32::try_from(offset).expect("Module larger than 4GiB"))
}
#[cfg(feature = "gc")]
pub(crate) fn lookup_stack_map(&self, pc: usize) -> Option<wasmtime_environ::StackMap<'_>> {
let text_offset = self.text_offset(pc)?;
let info = self.module.engine_code().stack_map_data();
wasmtime_environ::StackMap::lookup(text_offset, info)
}
}