mirror of
https://github.com/fluencelabs/wasmer
synced 2025-03-16 16:20:49 +00:00
new runtime module
This commit is contained in:
parent
5b920b7953
commit
93ef1e4220
@ -1,7 +1,7 @@
|
||||
use std::ops::{Index, IndexMut};
|
||||
use std::ptr::NonNull;
|
||||
use std::marker::PhantomData;
|
||||
use cranelift_entity::EntityRef;
|
||||
use crate::runtime::types::MapIndex;
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
#[repr(transparent)]
|
||||
@ -109,19 +109,32 @@ impl<'a, T> From<&'a [T]> for BoundedSlice<T> {
|
||||
|
||||
#[derive(Debug)]
|
||||
#[repr(transparent)]
|
||||
pub struct IndexedSlice<T, I> {
|
||||
pub struct IndexedSlice<'a, T, I> {
|
||||
ptr: NonNull<T>,
|
||||
_phantom: PhantomData<I>,
|
||||
}
|
||||
|
||||
impl<T, I> IndexedSlice<T, I> {
|
||||
pub fn new(ptr: *mut T) -> Self {
|
||||
impl<'a, T: 'a, I> IndexedSlice<T, I>
|
||||
where
|
||||
I: MapIndex,
|
||||
{
|
||||
pub(crate) fn new(ptr: *mut T) -> Self {
|
||||
Self {
|
||||
ptr: NonNull::new(ptr).unwrap(),
|
||||
_phantom: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
pub unsafe fn get(&self, index: I) -> &T {
|
||||
let ptr = self.as_ptr();
|
||||
&*ptr.add(index.index())
|
||||
}
|
||||
|
||||
pub unsafe fn get_mut(&mut self, index: I) -> &mut T {
|
||||
let ptr = self.as_mut_ptr();
|
||||
&mut *ptr.add(index.index())
|
||||
}
|
||||
|
||||
pub fn as_ptr(&self) -> *const T {
|
||||
self.ptr.as_ptr()
|
||||
}
|
||||
@ -129,19 +142,4 @@ impl<T, I> IndexedSlice<T, I> {
|
||||
pub fn as_mut_ptr(&mut self) -> *mut T {
|
||||
self.ptr.as_ptr()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, I: EntityRef> Index<I> for IndexedSlice<T, I> {
|
||||
type Output = T;
|
||||
fn index(&self, index: I) -> &T {
|
||||
let ptr = self.as_ptr();
|
||||
unsafe { &*ptr.add(index.index()) }
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, I: EntityRef> IndexMut<I> for IndexedSlice<T, I> {
|
||||
fn index_mut(&mut self, index: I) -> &mut T {
|
||||
let ptr = self.as_mut_ptr();
|
||||
unsafe { &mut *ptr.add(index.index()) }
|
||||
}
|
||||
}
|
@ -34,3 +34,4 @@ pub mod sighandler;
|
||||
mod spectests;
|
||||
pub mod update;
|
||||
pub mod webassembly;
|
||||
pub mod runtime;
|
||||
|
15
src/runtime/backend.rs
Normal file
15
src/runtime/backend.rs
Normal file
@ -0,0 +1,15 @@
|
||||
use crate::runtime::module::Module;
|
||||
use crate::runtime::types::FuncIndex;
|
||||
use crate::runtime::{
|
||||
vm,
|
||||
module::Module,
|
||||
types::FuncIndex,
|
||||
};
|
||||
|
||||
pub trait Compiler {
|
||||
fn compile(wasm: &[u8]) -> Box<Module>;
|
||||
}
|
||||
|
||||
pub trait FuncResolver {
|
||||
pub fn resolve(&self, index: FuncIndex) -> *const vm::Func;
|
||||
}
|
@ -1,13 +1,20 @@
|
||||
use super::vm;
|
||||
use super::module::Module;
|
||||
use crate::module::Module;
|
||||
use super::table::{TableBacking, TableScheme};
|
||||
use super::memory::LinearMemory;
|
||||
use super::instance::{InstanceOptions, InstanceABI};
|
||||
use super::ImportObject;
|
||||
use cranelift_entity::EntityRef;
|
||||
use std::mem;
|
||||
|
||||
use crate::runtime::{
|
||||
vm,
|
||||
module::Module,
|
||||
table::TableBacking,
|
||||
types::{Val, GlobalInit},
|
||||
};
|
||||
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Backing {
|
||||
pub struct LocalBacking {
|
||||
memories: Box<[LinearMemory]>,
|
||||
tables: Box<[TableBacking]>,
|
||||
|
||||
@ -16,47 +23,48 @@ pub struct Backing {
|
||||
vm_globals: Box<[vm::LocalGlobal]>,
|
||||
}
|
||||
|
||||
impl Backing {
|
||||
pub fn new(module: &Module, options: &InstanceOptions, imports: &ImportObject) -> Self {
|
||||
let memories = Backing::generate_memories(module, options);
|
||||
let tables = Backing::generate_tables(module, options);
|
||||
impl LocalBacking {
|
||||
pub fn new(module: &Module, imports: &ImportBacking, options: &InstanceOptions) -> Self {
|
||||
let mut memories = Self::generate_memories(module, options);
|
||||
let mut tables = Self::generate_tables(module, options);
|
||||
let globals = Self::generate_globals(module);
|
||||
|
||||
Backing {
|
||||
Self {
|
||||
memories,
|
||||
tables,
|
||||
|
||||
vm_memories: Backing::finalize_memories(module, &memories, options),
|
||||
vm_tables: Backing::finalize_tables(module, &tables, options, imports),
|
||||
vm_globals: Backing::generate_globals(module),
|
||||
vm_memories: Self::finalize_memories(module, &mut memories[..], options),
|
||||
vm_tables: Self::finalize_tables(module, &mut tables[..], options),
|
||||
vm_globals: Self::finalize_globals(module, imports, globals),
|
||||
}
|
||||
}
|
||||
|
||||
fn generate_memories(module: &Module, options: &InstanceOptions) -> Box<[LinearMemory]> {
|
||||
let memories = Vec::with_capacity(module.info.memories.len());
|
||||
let mut memories = Vec::with_capacity(module.memories.len());
|
||||
|
||||
for mem in &module.info.memories {
|
||||
let memory = mem.entity;
|
||||
for (_, mem) in &module.memories {
|
||||
// If we use emscripten, we set a fixed initial and maximum
|
||||
debug!(
|
||||
"Instance - init memory ({}, {:?})",
|
||||
memory.minimum, memory.maximum
|
||||
memory.min, memory.max
|
||||
);
|
||||
let memory = if options.abi == InstanceABI::Emscripten {
|
||||
// We use MAX_PAGES, so at the end the result is:
|
||||
// (initial * LinearMemory::PAGE_SIZE) == LinearMemory::DEFAULT_HEAP_SIZE
|
||||
// However, it should be: (initial * LinearMemory::PAGE_SIZE) == 16777216
|
||||
LinearMemory::new(LinearMemory::MAX_PAGES, None)
|
||||
} else {
|
||||
LinearMemory::new(memory.minimum, memory.maximum.map(|m| m as u32))
|
||||
};
|
||||
// let memory = if options.abi == InstanceABI::Emscripten {
|
||||
// // We use MAX_PAGES, so at the end the result is:
|
||||
// // (initial * LinearMemory::PAGE_SIZE) == LinearMemory::DEFAULT_HEAP_SIZE
|
||||
// // However, it should be: (initial * LinearMemory::PAGE_SIZE) == 16777216
|
||||
// LinearMemory::new(LinearMemory::MAX_PAGES, None)
|
||||
// } else {
|
||||
// LinearMemory::new(memory.minimum, memory.maximum.map(|m| m as u32))
|
||||
// };
|
||||
let memory = LinearMemory::new(mem);
|
||||
memories.push(memory);
|
||||
}
|
||||
|
||||
memories.into_boxed_slice()
|
||||
}
|
||||
|
||||
fn finalize_memories(module: &Module, memories: &[LinearMemory], options: &InstanceOptions) -> Box<[vm::LocalMemory]> {
|
||||
for init in &module.info.data_initializers {
|
||||
fn finalize_memories(module: &Module, memories: &mut [LinearMemory], options: &InstanceOptions) -> Box<[vm::LocalMemory]> {
|
||||
for init in &module.data_initializers {
|
||||
debug_assert!(init.base.is_none(), "globalvar base not supported yet");
|
||||
let offset = init.offset;
|
||||
let mem: &mut LinearMemory = &mut memories[init.memory_index.index()];
|
||||
@ -76,35 +84,44 @@ impl Backing {
|
||||
debug!("emscripten::finish setup memory");
|
||||
}
|
||||
|
||||
memories.iter().map(|mem| mem.into_vm_memory()).collect::<Vec<_>>().into_boxed_slice()
|
||||
memories.iter_mut().map(|mem| mem.into_vm_memory()).collect::<Vec<_>>().into_boxed_slice()
|
||||
}
|
||||
|
||||
fn generate_tables(module: &Module, options: &InstanceOptions) -> Box<[TableBacking]> {
|
||||
let mut tables = Vec::with_capacity(module.info.tables.len());
|
||||
let mut tables = Vec::with_capacity(module.tables.len());
|
||||
|
||||
for table in &module.info.tables {
|
||||
let scheme = TableScheme::from_table(table.entity);
|
||||
let table_backing = TableBacking::new(&scheme);
|
||||
tables.push(table_backing);
|
||||
for table in &module.tables {
|
||||
let table_backing = TableBacking::new(table);
|
||||
tables.push(table_backing);
|
||||
}
|
||||
|
||||
tables.into_boxed_slice()
|
||||
}
|
||||
|
||||
fn finalize_tables(module: &Module, tables: &[TableBacking], options: &InstanceOptions, imports: &ImportObject) -> Box<[vm::LocalTable]> {
|
||||
fn finalize_tables(module: &Module, tables: &[TableBacking], options: &InstanceOptions) -> Box<[vm::LocalTable]> {
|
||||
tables.iter().map(|table| table.into_vm_table()).collect::<Vec<_>>().into_boxed_slice()
|
||||
}
|
||||
|
||||
fn generate_globals(module: &Module) -> Box<[vm::LocalGlobal]> {
|
||||
let mut globals = Vec::with_capacity(module.info.globals.len());
|
||||
|
||||
for global in module.info.globals.iter().map(|mem| mem.entity) {
|
||||
|
||||
}
|
||||
let mut globals = vec![vm::LocalGlobal::null(); module.globals.len()];
|
||||
|
||||
globals.into_boxed_slice()
|
||||
}
|
||||
|
||||
fn finalize_globals(module: &Module, imports: &ImportBacking, globals: Box<[vm::LocalGlobal]>) -> Box<[vm::LocalGlobal]> {
|
||||
for (to, from) in globals.iter_mut().zip(module.globals.iter()) {
|
||||
*to = match from.init {
|
||||
GlobalInit::Val(Val::I32(x)) => x as u64,
|
||||
GlobalInit::Val(Val::I64(x)) => x as u64,
|
||||
GlobalInit::Val(Val::F32(x)) => x as u64,
|
||||
GlobalInit::Val(Val::F64(x)) => x,
|
||||
GlobalInit::GetGlobal(index) => unsafe { (*imports.globals[index.index()].global).data },
|
||||
};
|
||||
}
|
||||
|
||||
globals
|
||||
}
|
||||
|
||||
// fn generate_tables(module: &Module, _options: &InstanceOptions) -> (Box<[TableBacking]>, Box<[vm::LocalTable]>) {
|
||||
// let mut tables = Vec::new();
|
||||
// // Reserve space for tables
|
||||
@ -174,7 +191,7 @@ impl Backing {
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct ImportsBacking {
|
||||
pub struct ImportBacking {
|
||||
functions: Box<[vm::ImportedFunc]>,
|
||||
memories: Box<[vm::ImportedMemory]>,
|
||||
tables: Box<[vm::ImportedTable]>,
|
26
src/runtime/instance.rs
Normal file
26
src/runtime/instance.rs
Normal file
@ -0,0 +1,26 @@
|
||||
use crate::runtime::{
|
||||
vm,
|
||||
backing::{LocalBacking, ImportBacking},
|
||||
};
|
||||
use std::sync::Arc;
|
||||
|
||||
pub struct Instance {
|
||||
pub vmctx: vm::Ctx,
|
||||
|
||||
pub finalized_funcs: Box<[*const vm::Func]>,
|
||||
|
||||
pub backing: LocalBacking,
|
||||
pub imports: ImportBacking,
|
||||
|
||||
pub module: Arc<Module>,
|
||||
}
|
||||
|
||||
impl Instance {
|
||||
pub fn new(module: Arc<Module>) -> Box<Instance> {
|
||||
|
||||
Box::new(Instance {
|
||||
vmctx,
|
||||
finalized_funcs
|
||||
})
|
||||
}
|
||||
}
|
@ -8,15 +8,18 @@ use std::ops::{Deref, DerefMut};
|
||||
use std::slice;
|
||||
|
||||
use crate::common::mmap::Mmap;
|
||||
use super::vm::LocalMemory;
|
||||
use crate::runtime::{
|
||||
vm::LocalMemory,
|
||||
types::{Memory, Map, FuncIndex},
|
||||
};
|
||||
|
||||
/// A linear memory instance.
|
||||
#[derive(Debug)]
|
||||
pub struct LinearMemory {
|
||||
// The mmap allocation
|
||||
/// The actual memory allocation.
|
||||
mmap: Mmap,
|
||||
|
||||
// current number of wasm pages
|
||||
/// The current number of wasm pages.
|
||||
current: u32,
|
||||
|
||||
// The maximum size the WebAssembly Memory is allowed to grow
|
||||
@ -25,17 +28,20 @@ pub struct LinearMemory {
|
||||
// front. However, the engine may ignore or clamp this reservation
|
||||
// request. In general, most WebAssembly modules shouldn't need
|
||||
// to set a maximum.
|
||||
maximum: Option<u32>,
|
||||
max: Option<u32>,
|
||||
|
||||
// The size of the extra guard pages after the end.
|
||||
// Is used to optimize loads and stores with constant offsets.
|
||||
offset_guard_size: usize,
|
||||
|
||||
/// Requires exception catching to handle out-of-bounds accesses.
|
||||
requires_signal_catch: bool,
|
||||
}
|
||||
|
||||
/// It holds the raw bytes of memory accessed by a WebAssembly Instance
|
||||
impl LinearMemory {
|
||||
pub const PAGE_SIZE: u32 = 65536;
|
||||
pub const MAX_PAGES: u32 = 65536;
|
||||
pub const PAGE_SIZE: u32 = 65_536;
|
||||
pub const MAX_PAGES: u32 = 65_536;
|
||||
pub const DEFAULT_HEAP_SIZE: usize = 1 << 32; // 4 GiB
|
||||
pub const DEFAULT_GUARD_SIZE: usize = 1 << 31; // 2 GiB
|
||||
pub const DEFAULT_SIZE: usize = Self::DEFAULT_HEAP_SIZE + Self::DEFAULT_GUARD_SIZE; // 6 GiB
|
||||
@ -43,46 +49,41 @@ impl LinearMemory {
|
||||
/// Create a new linear memory instance with specified initial and maximum number of pages.
|
||||
///
|
||||
/// `maximum` cannot be set to more than `65536` pages.
|
||||
pub fn new(initial: u32, maximum: Option<u32>) -> Self {
|
||||
assert!(initial <= Self::MAX_PAGES);
|
||||
assert!(maximum.is_none() || maximum.unwrap() <= Self::MAX_PAGES);
|
||||
debug!(
|
||||
"Instantiate LinearMemory(initial={:?}, maximum={:?})",
|
||||
initial, maximum
|
||||
);
|
||||
pub fn new(mem: &Memory) -> Self {
|
||||
assert!(mem.min <= Self::MAX_PAGES);
|
||||
assert!(mem.max.is_none() || mem.max.unwrap() <= Self::MAX_PAGES);
|
||||
debug!("Instantiate LinearMemory(mem: {:?})", mem);
|
||||
|
||||
let mut mmap = Mmap::with_size(Self::DEFAULT_SIZE).expect("Can't create mmap");
|
||||
let (mmap_size, initial_pages, offset_guard_size, requires_signal_catch) = if mem.is_static_heap() {
|
||||
(Self::DEFAULT_SIZE, mem.min, Self::DEFAULT_GUARD_SIZE, true)
|
||||
// This is a static heap
|
||||
} else {
|
||||
// this is a dynamic heap
|
||||
assert!(!mem.shared, "shared memories must have a maximum size.");
|
||||
|
||||
let base = mmap.as_mut_ptr();
|
||||
(mem.min as usize * Self::PAGE_SIZE as usize, mem.min, 0, false)
|
||||
}
|
||||
|
||||
let mut mmap = Mmap::with_size(mmap_size).unwrap();
|
||||
|
||||
// map initial pages as readwrite since the inital mmap is mapped as not accessible.
|
||||
if initial != 0 {
|
||||
if initial_pages != 0 {
|
||||
unsafe {
|
||||
region::protect(
|
||||
base,
|
||||
initial as usize * Self::PAGE_SIZE as usize,
|
||||
mmap.as_mut_ptr(),
|
||||
initial_pages as usize * Self::PAGE_SIZE as usize,
|
||||
region::Protection::ReadWrite,
|
||||
)
|
||||
}
|
||||
.expect("unable to make memory inaccessible");
|
||||
.expect("unable to make memory accessible");
|
||||
}
|
||||
|
||||
debug!("LinearMemory instantiated");
|
||||
debug!(
|
||||
" - usable: {:#x}..{:#x}",
|
||||
base as usize,
|
||||
(base as usize) + LinearMemory::DEFAULT_HEAP_SIZE
|
||||
);
|
||||
debug!(
|
||||
" - guard: {:#x}..{:#x}",
|
||||
(base as usize) + LinearMemory::DEFAULT_HEAP_SIZE,
|
||||
(base as usize) + LinearMemory::DEFAULT_SIZE
|
||||
);
|
||||
Self {
|
||||
mmap,
|
||||
current: initial,
|
||||
offset_guard_size: LinearMemory::DEFAULT_GUARD_SIZE,
|
||||
maximum,
|
||||
current: initial_pages,
|
||||
max: mem.max,
|
||||
offset_guard_size,
|
||||
requires_signal_catch,
|
||||
}
|
||||
}
|
||||
|
||||
@ -116,8 +117,60 @@ impl LinearMemory {
|
||||
///
|
||||
/// Returns `None` if memory can't be grown by the specified amount
|
||||
/// of pages.
|
||||
pub fn grow(&mut self, add_pages: u32) -> Option<i32> {
|
||||
debug!("grow_memory called!");
|
||||
pub fn grow_dynamic(&mut self, add_pages: u32) -> Option<i32> {
|
||||
debug!("grow_memory_dynamic called!");
|
||||
assert!(self.max.is_none());
|
||||
if add_pages == 0 {
|
||||
return Some(self.current as _);
|
||||
}
|
||||
|
||||
let prev_pages = self.current;
|
||||
|
||||
let new_pages = match self.current.checked_add(add_pages) {
|
||||
Some(new_pages) => new_pages,
|
||||
None => return None,
|
||||
};
|
||||
|
||||
if let Some(val) = self.maximum {
|
||||
if new_pages > val {
|
||||
return None;
|
||||
}
|
||||
// Wasm linear memories are never allowed to grow beyond what is
|
||||
// indexable. If the memory has no maximum, enforce the greatest
|
||||
// limit here.
|
||||
} else if new_pages >= Self::MAX_PAGES {
|
||||
return None;
|
||||
}
|
||||
|
||||
let prev_bytes = (prev_pages * Self::PAGE_SIZE) as usize;
|
||||
let new_bytes = (new_pages * Self::PAGE_SIZE) as usize;
|
||||
|
||||
if new_bytes > self.mmap.len() - self.offset_guard_size {
|
||||
let mmap_size = new_bytes.checked_add(self.offset_guard_size)?;
|
||||
let mut new_mmap = Mmap::with_size(request_bytes).ok()?;
|
||||
|
||||
unsafe {
|
||||
region::protect(
|
||||
new_mmap.as_mut_ptr(),
|
||||
new_bytes,
|
||||
region::Protection::ReadWrite,
|
||||
).ok()?;
|
||||
}
|
||||
|
||||
let copy_size = self.mmap.len() - self.offset_guard_size;
|
||||
new_mmap.as_mut_slice()[..copy_size].copy_from_slice(self.mmap.as_slice()[..copy_size]);
|
||||
|
||||
self.mmap = new_mmap;
|
||||
}
|
||||
|
||||
self.current = new_pages;
|
||||
|
||||
Some(prev_pages as i32)
|
||||
}
|
||||
|
||||
pub fn grow_static(&mut self, add_pages: u32) -> Option<i32> {
|
||||
debug!("grow_memory_static called!");
|
||||
assert!(self.max.is_some());
|
||||
if add_pages == 0 {
|
||||
return Some(self.current as _);
|
||||
}
|
||||
@ -143,40 +196,13 @@ impl LinearMemory {
|
||||
let prev_bytes = (prev_pages * Self::PAGE_SIZE) as usize;
|
||||
let new_bytes = (new_pages * Self::PAGE_SIZE) as usize;
|
||||
|
||||
// if new_bytes > self.mmap.len() - self.offset_guard_size {
|
||||
unsafe {
|
||||
region::protect(
|
||||
self.mmap.as_ptr().add(prev_bytes) as _,
|
||||
new_bytes - prev_bytes,
|
||||
region::Protection::ReadWrite,
|
||||
)
|
||||
).ok()?;
|
||||
}
|
||||
.expect("unable to make memory inaccessible");
|
||||
// };
|
||||
// if new_bytes > self.mmap.len() - self.offset_guard_size {
|
||||
// // If we have no maximum, this is a "dynamic" heap, and it's allowed to move.
|
||||
// assert!(self.maximum.is_none());
|
||||
// let guard_bytes = self.offset_guard_size;
|
||||
// let request_bytes = new_bytes.checked_add(guard_bytes)?;
|
||||
|
||||
// let mut new_mmap = Mmap::with_size(request_bytes).ok()?;
|
||||
|
||||
// // Make the offset-guard pages inaccessible.
|
||||
// unsafe {
|
||||
// region::protect(
|
||||
// new_mmap.as_ptr().add(new_bytes),
|
||||
// guard_bytes,
|
||||
// region::Protection::Read | region::Protection::Write,
|
||||
// // region::Protection::None,
|
||||
// )
|
||||
// }
|
||||
// .expect("unable to make memory inaccessible");
|
||||
|
||||
// let copy_len = self.mmap.len() - self.offset_guard_size;
|
||||
// new_mmap.as_mut_slice()[..copy_len].copy_from_slice(&self.mmap.as_slice()[..copy_len]);
|
||||
|
||||
// self.mmap = new_mmap;
|
||||
// }
|
||||
|
||||
self.current = new_pages;
|
||||
|
||||
@ -213,3 +239,8 @@ impl DerefMut for LinearMemory {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn round_up_to_page_size(size: usize) -> usize {
|
||||
let page_size = region::page::size();
|
||||
(size + (page_size - 1)) & !(page_size - 1)
|
||||
}
|
9
src/runtime/mod.rs
Normal file
9
src/runtime/mod.rs
Normal file
@ -0,0 +1,9 @@
|
||||
|
||||
pub mod vm;
|
||||
pub mod backing;
|
||||
pub mod types;
|
||||
pub mod memory;
|
||||
pub mod backend;
|
||||
pub mod module;
|
||||
pub mod instance;
|
||||
pub mod table;
|
52
src/runtime/module.rs
Normal file
52
src/runtime/module.rs
Normal file
@ -0,0 +1,52 @@
|
||||
use crate::runtime::types::{
|
||||
Map,
|
||||
FuncIndex, MemoryIndex, TableIndex, GlobalIndex,
|
||||
Memory, Globals, GlobalDesc, Func, Table,
|
||||
};
|
||||
use crate::runtime::backend::FuncResolver;
|
||||
|
||||
/// This is used to instantiate a new webassembly module.
|
||||
#[derive(Debug)]
|
||||
pub struct Module {
|
||||
pub functions: Box<dyn FuncResolver>,
|
||||
pub memories: Map<Memory, MemoryIndex>,
|
||||
pub globals: Map<Global, GlobalIndex>,
|
||||
pub tables: Map<Table, TableIndex>,
|
||||
|
||||
pub imported_functions: Map<(ImportName, Func), FuncIndex>,
|
||||
pub imported_memories: Map<(ImportName, Memory), MemoryIndex>,
|
||||
pub imported_tables: Map<(ImportName, Table), TableIndex>,
|
||||
pub imported_globals: Map<(ImportName, GlobalDesc), GlobalIndex>,
|
||||
|
||||
pub exported: Vec<(ItemName, Export)>,
|
||||
|
||||
pub data_initializers: Vec<DataInitializer>,
|
||||
pub start_func: FuncIndex,
|
||||
|
||||
pub signatures: Map<Func, FuncIndex>,
|
||||
}
|
||||
|
||||
pub type ModuleName = Vec<u8>;
|
||||
pub type ItemName = Vec<u8>;
|
||||
pub type ImportName = (ModuleName, ItemName);
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub enum Export {
|
||||
Func(FuncIndex),
|
||||
Memory(MemoryIndex),
|
||||
Global(GlobalIndex),
|
||||
Table(TableIndex),
|
||||
}
|
||||
|
||||
/// A data initializer for linear memory.
|
||||
#[derive(Debug)]
|
||||
pub struct DataInitializer {
|
||||
/// The index of the memory to initialize.
|
||||
pub memory_index: MemoryIndex,
|
||||
/// Optionally a globalvalue base to initialize at.
|
||||
pub base: Option<GlobalIndex>,
|
||||
/// A constant offset to initialize at.
|
||||
pub offset: usize,
|
||||
/// The initialization data.
|
||||
pub data: Vec<u8>,
|
||||
}
|
38
src/runtime/table.rs
Normal file
38
src/runtime/table.rs
Normal file
@ -0,0 +1,38 @@
|
||||
use super::vm;
|
||||
use crate::runtime::types::{ElementType, Table};
|
||||
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
|
||||
enum TableElements {
|
||||
/// This is intended to be a caller-checked Anyfunc.
|
||||
Anyfunc(Box<[vm::Anyfunc]>),
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct TableBacking {
|
||||
pub elements: TableElements,
|
||||
pub max: Option<u32>,
|
||||
}
|
||||
|
||||
impl TableBacking {
|
||||
pub fn new(table: &Table) -> Self {
|
||||
match table.ty {
|
||||
ElementType::Anyfunc => {
|
||||
Self {
|
||||
elements: TableElements::Anyfunc(vec![vm::Anyfunc::null(); table.min].into_boxed_slice()),
|
||||
max: table.max,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn into_vm_table(&mut self) -> vm::LocalTable {
|
||||
match self.elements {
|
||||
TableElements::Anyfunc(funcs) => {
|
||||
vm::LocalTable {
|
||||
base: funcs.as_mut_ptr() as *mut u8,
|
||||
current_elements: funcs.len(),
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
270
src/runtime/types.rs
Normal file
270
src/runtime/types.rs
Normal file
@ -0,0 +1,270 @@
|
||||
use std::marker::PhantomData;
|
||||
use std::{slice, iter};
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub enum Type {
|
||||
/// The `i32` type.
|
||||
I32,
|
||||
/// The `i64` type.
|
||||
I64,
|
||||
/// The `f32` type.
|
||||
F32,
|
||||
/// The `f64` type.
|
||||
F64,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub enum Val {
|
||||
/// The `i32` type.
|
||||
I32(i32),
|
||||
/// The `i64` type.
|
||||
I64(i64),
|
||||
/// The `f32` type.
|
||||
F32(u32),
|
||||
/// The `f64` type.
|
||||
F64(u64),
|
||||
}
|
||||
|
||||
impl From<i32> for Val {
|
||||
fn from(n: i32) -> Self {
|
||||
Self::I32(n)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<i64> for Val {
|
||||
fn from(n: i64) -> Self {
|
||||
Self::I64(n)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<f32> for Val {
|
||||
fn from(n: f32) -> Self {
|
||||
Self::F32(n.to_bits())
|
||||
}
|
||||
}
|
||||
|
||||
impl From<f64> for Val {
|
||||
fn from(n: f64) -> Self {
|
||||
Self::I64(n.to_bits())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub enum ElementType {
|
||||
/// Any wasm function.
|
||||
Anyfunc,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub struct Table {
|
||||
/// Type of data stored in this table.
|
||||
pub ty: ElementType,
|
||||
/// The minimum number of elements that must be stored in this table.
|
||||
pub min: u32,
|
||||
/// The maximum number of elements in this table.
|
||||
pub max: Option<u32>,
|
||||
}
|
||||
|
||||
/// A global value initializer.
|
||||
/// Overtime, this will be able to represent more and more
|
||||
/// complex expressions.
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub enum GlobalInit {
|
||||
Val(Val),
|
||||
GetGlobal(GlobalIndex),
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub struct GlobalDesc {
|
||||
pub mutable: bool,
|
||||
pub ty: Type,
|
||||
}
|
||||
|
||||
/// A wasm global.
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub struct Global {
|
||||
pub desc: GlobalDesc,
|
||||
pub init: GlobalInit,
|
||||
}
|
||||
|
||||
/// A wasm memory.
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub struct Memory {
|
||||
/// The minimum number of allowed pages.
|
||||
pub min: u32,
|
||||
/// The maximum number of allowed pages.
|
||||
pub max: Option<u32>,
|
||||
/// This memory can be shared between wasm threads.
|
||||
pub shared: bool,
|
||||
}
|
||||
|
||||
impl Memory {
|
||||
pub fn is_static_heap(&self) -> bool {
|
||||
self.max.is_some()
|
||||
}
|
||||
}
|
||||
|
||||
/// A wasm func.
|
||||
#[derive(Debug)]
|
||||
pub struct Func {
|
||||
pub params: Vec<Type>,
|
||||
pub returns: Vec<Type>,
|
||||
}
|
||||
|
||||
pub trait MapIndex {
|
||||
fn new(index: usize) -> Self;
|
||||
fn index(&self) -> usize;
|
||||
}
|
||||
|
||||
/// Dense item map
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Map<T, I>
|
||||
where
|
||||
I: MapIndex,
|
||||
{
|
||||
elems: Vec<T>,
|
||||
_marker: PhantomData<I>,
|
||||
}
|
||||
|
||||
impl Map {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
elems: Vec::new(),
|
||||
_marker: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn with_capacity(capacity: usize) -> Self {
|
||||
Self {
|
||||
elems: Vec::with_capacity(capacity),
|
||||
_marker: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get(&self, index: I) -> Option<&T> {
|
||||
self.elems.get(index.index())
|
||||
}
|
||||
|
||||
pub fn len(&self) -> usize {
|
||||
self.elems.len()
|
||||
}
|
||||
|
||||
pub fn push(&mut self, value: T) -> I {
|
||||
let len = self.len();
|
||||
self.elems.push(value);
|
||||
I::new(len)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, I> Index<I> for Map<T, I>
|
||||
where
|
||||
I: MapIndex,
|
||||
{
|
||||
type Output = T;
|
||||
fn index(&self, index: I) -> &T {
|
||||
&self.elems[index.index()]
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, I> IndexMut<I> for Map<T, I>
|
||||
where
|
||||
I: MapIndex,
|
||||
{
|
||||
fn index_mut(&mut self, index: I) -> &mut T {
|
||||
&mut self.elems[index.index()]
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T, I> IntoIterator for &'a Map<T, I>
|
||||
where
|
||||
I: MapIndex
|
||||
{
|
||||
type Item = (I, &'a T);
|
||||
type IntoIter = Iter<'a, T, I>;
|
||||
|
||||
fn into_iter(self) -> Self::IntoIter {
|
||||
Iter::new(self.elems.iter())
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T, I> IntoIterator for &'a mut Map<T, I>
|
||||
where
|
||||
I: MapIndex
|
||||
{
|
||||
type Item = (I, &'a mut T);
|
||||
type IntoIter = IterMut<'a, T, I>;
|
||||
|
||||
fn into_iter(self) -> Self::IntoIter {
|
||||
Iter::new(self.elems.iter_mut())
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Iter<'a, T: 'a, I: MapIndex> {
|
||||
enumerated: iter::Enumerate<slice::Iter<'A, T>>,
|
||||
_marker: PhantomData,
|
||||
}
|
||||
|
||||
impl<'a, T: 'a, I: MapIndex> Iter<'a, T, I> {
|
||||
fn new(iter: slice::Iter<'a, T>) -> Self {
|
||||
Self {
|
||||
enumerated: iter.enumerate(),
|
||||
_marker: PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T: 'a, I: MapIndex> Iterator for Iter<'a, T, I> {
|
||||
type Item = (I, &'a T);
|
||||
|
||||
fn next(&mut self) -> Self::Item {
|
||||
self.enumerated.next().map(|i, v| (I::new(i), v))
|
||||
}
|
||||
}
|
||||
|
||||
pub struct IterMut<'a, T: 'a, I: MapIndex> {
|
||||
enumerated: iter::Enumerate<slice::Iter<'A, T>>,
|
||||
_marker: PhantomData,
|
||||
}
|
||||
|
||||
impl<'a, T: 'a, I: MapIndex> IterMut<'a, T, I> {
|
||||
fn new(iter: slice::Iter<'a, T>) -> Self {
|
||||
Self {
|
||||
enumerated: iter.enumerate(),
|
||||
_marker: PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T: 'a, I: MapIndex> Iterator for IterMut<'a, T, I> {
|
||||
type Item = (I, &'a mut T);
|
||||
|
||||
fn next(&mut self) -> Self::Item {
|
||||
self.enumerated.next().map(|i, v| (I::new(i), v))
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! define_map_index {
|
||||
($ty:ident) => {
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
|
||||
pub struct $ty (u32);
|
||||
impl MapIndex for $ty {
|
||||
fn new(index: usize) -> Self {
|
||||
$ty (index as _)
|
||||
}
|
||||
|
||||
fn index(&self) -> usize {
|
||||
self.0 as usize
|
||||
}
|
||||
}
|
||||
};
|
||||
($($ty:ident),*) => {
|
||||
$(
|
||||
define_map_index!($ty);
|
||||
)*
|
||||
};
|
||||
}
|
||||
|
||||
define_map_index![
|
||||
FuncIndex, MemoryIndex, GlobalIndex, TableIndex,
|
||||
SignatureIndex,
|
||||
];
|
@ -1,40 +1,38 @@
|
||||
use std::{ptr, mem};
|
||||
use crate::common::slice::IndexedSlice;
|
||||
use cranelift_wasm::{
|
||||
TableIndex, MemoryIndex, GlobalIndex, FuncIndex,
|
||||
DefinedTableIndex, DefinedMemoryIndex, DefinedGlobalIndex,
|
||||
use crate::runtime::types::{
|
||||
MemoryIndex, TableIndex, GlobalIndex, FuncIndex,
|
||||
SignatureIndex,
|
||||
};
|
||||
|
||||
#[derive(Debug)]
|
||||
#[repr(C)]
|
||||
pub struct VmCtx {
|
||||
pub struct Ctx<'a> {
|
||||
/// A pointer to an array of locally-defined memories, indexed by `DefinedMemoryIndex`.
|
||||
pub(in crate::webassembly) memories: IndexedSlice<LocalMemory, DefinedMemoryIndex>,
|
||||
pub memories: *mut LocalMemory,
|
||||
|
||||
/// A pointer to an array of locally-defined tables, indexed by `DefinedTableIndex`.
|
||||
pub(in crate::webassembly) tables: IndexedSlice<LocalTable, DefinedTableIndex>,
|
||||
pub tables: *mut LocalTable,
|
||||
|
||||
/// A pointer to an array of locally-defined globals, indexed by `DefinedGlobalIndex`.
|
||||
pub(in crate::webassembly) globals: IndexedSlice<LocalGlobal, DefinedGlobalIndex>,
|
||||
pub globals: *mut LocalGlobal,
|
||||
|
||||
/// A pointer to an array of imported memories, indexed by `MemoryIndex,
|
||||
pub(in crate::webassembly) imported_memories: IndexedSlice<ImportedMemory, MemoryIndex>,
|
||||
pub imported_memories: *mut ImportedMemory,
|
||||
|
||||
/// A pointer to an array of imported tables, indexed by `TableIndex`.
|
||||
pub(in crate::webassembly) imported_tables: IndexedSlice<ImportedTable, TableIndex>,
|
||||
pub imported_tables: *mut ImportedTable,
|
||||
|
||||
/// A pointer to an array of imported globals, indexed by `GlobalIndex`.
|
||||
pub(in crate::webassembly) imported_globals: IndexedSlice<ImportedGlobal, GlobalIndex>,
|
||||
pub imported_globals: *mut ImportedGlobal,
|
||||
|
||||
/// A pointer to an array of imported functions, indexed by `FuncIndex`.
|
||||
pub(in crate::webassembly) imported_funcs: IndexedSlice<ImportedFunc, FuncIndex>,
|
||||
pub imported_funcs: *mut ImportedFunc,
|
||||
|
||||
/// Signature identifiers for signature-checked indirect calls.
|
||||
pub(in crate::webassembly) sig_ids: IndexedSlice<SigId, SignatureIndex>,
|
||||
pub sig_ids: *mut SigId,
|
||||
}
|
||||
|
||||
impl VmCtx {
|
||||
impl Ctx {
|
||||
pub fn new(
|
||||
memories: *mut LocalMemory,
|
||||
tables: *mut LocalTable,
|
||||
@ -46,14 +44,14 @@ impl VmCtx {
|
||||
sig_ids: *mut SigId,
|
||||
) -> Self {
|
||||
Self {
|
||||
memories: IndexedSlice::new(memories),
|
||||
tables: IndexedSlice::new(tables),
|
||||
globals: IndexedSlice::new(globals),
|
||||
imported_memories: IndexedSlice::new(imported_memories),
|
||||
imported_tables: IndexedSlice::new(imported_tables),
|
||||
imported_globals: IndexedSlice::new(imported_globals),
|
||||
imported_funcs: IndexedSlice::new(imported_funcs),
|
||||
sig_ids: IndexedSlice::new(sig_ids),
|
||||
memories,
|
||||
tables,
|
||||
globals,
|
||||
imported_memories,
|
||||
imported_tables,
|
||||
imported_globals,
|
||||
imported_funcs,
|
||||
sig_ids,
|
||||
}
|
||||
}
|
||||
|
||||
@ -100,7 +98,7 @@ pub enum Func {}
|
||||
#[repr(C)]
|
||||
pub struct ImportedFunc {
|
||||
pub func: *const Func,
|
||||
pub vmctx: *mut VmCtx,
|
||||
pub vmctx: *mut Ctx,
|
||||
}
|
||||
|
||||
impl ImportedFunc {
|
||||
@ -139,7 +137,7 @@ pub struct ImportedTable {
|
||||
/// A pointer to the table definition.
|
||||
pub table: *mut LocalTable,
|
||||
/// A pointer to the vmcontext that owns this table definition.
|
||||
pub vmctx: *mut VmCtx,
|
||||
pub vmctx: *mut Ctx,
|
||||
}
|
||||
|
||||
impl ImportedTable {
|
||||
@ -156,9 +154,9 @@ impl ImportedTable {
|
||||
#[derive(Debug, Clone)]
|
||||
#[repr(C)]
|
||||
pub struct LocalMemory {
|
||||
/// Pointer to the bottom of linear memory.
|
||||
/// Pointer to the bottom of this linear memory.
|
||||
pub base: *mut u8,
|
||||
/// Current logical size of this linear memory in bytes.
|
||||
/// Current size of this linear memory in bytes.
|
||||
pub size: usize,
|
||||
}
|
||||
|
||||
@ -189,13 +187,19 @@ impl ImportedMemory {
|
||||
#[derive(Debug, Clone)]
|
||||
#[repr(C)]
|
||||
pub struct LocalGlobal {
|
||||
pub data: [u8; 8],
|
||||
pub data: u64,
|
||||
}
|
||||
|
||||
impl LocalGlobal {
|
||||
pub fn offset_data() -> u8 {
|
||||
0 * (mem::size_of::<usize>() as u8)
|
||||
}
|
||||
|
||||
pub fn null() -> Self {
|
||||
Self {
|
||||
data: 0,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
@ -217,12 +221,12 @@ pub struct SigId(u32);
|
||||
/// Caller-checked anyfunc
|
||||
#[derive(Debug, Clone)]
|
||||
#[repr(C)]
|
||||
pub struct CCAnyfunc {
|
||||
pub struct Anyfunc {
|
||||
pub func_data: ImportedFunc,
|
||||
pub sig_id: SigId,
|
||||
}
|
||||
|
||||
impl CCAnyfunc {
|
||||
impl Anyfunc {
|
||||
pub fn null() -> Self {
|
||||
Self {
|
||||
func_data: ImportedFunc {
|
||||
@ -249,7 +253,7 @@ impl CCAnyfunc {
|
||||
#[cfg(test)]
|
||||
mod vm_offset_tests {
|
||||
use super::{
|
||||
VmCtx,
|
||||
Ctx,
|
||||
ImportedFunc,
|
||||
LocalTable,
|
||||
ImportedTable,
|
||||
@ -257,49 +261,49 @@ mod vm_offset_tests {
|
||||
ImportedMemory,
|
||||
LocalGlobal,
|
||||
ImportedGlobal,
|
||||
CCAnyfunc,
|
||||
Anyfunc,
|
||||
};
|
||||
|
||||
#[test]
|
||||
fn vmctx() {
|
||||
assert_eq!(
|
||||
VmCtx::offset_memories() as usize,
|
||||
offset_of!(VmCtx => memories).get_byte_offset(),
|
||||
Ctx::offset_memories() as usize,
|
||||
offset_of!(Ctx => memories).get_byte_offset(),
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
VmCtx::offset_tables() as usize,
|
||||
offset_of!(VmCtx => tables).get_byte_offset(),
|
||||
Ctx::offset_tables() as usize,
|
||||
offset_of!(Ctx => tables).get_byte_offset(),
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
VmCtx::offset_globals() as usize,
|
||||
offset_of!(VmCtx => globals).get_byte_offset(),
|
||||
Ctx::offset_globals() as usize,
|
||||
offset_of!(Ctx => globals).get_byte_offset(),
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
VmCtx::offset_imported_memories() as usize,
|
||||
offset_of!(VmCtx => imported_memories).get_byte_offset(),
|
||||
Ctx::offset_imported_memories() as usize,
|
||||
offset_of!(Ctx => imported_memories).get_byte_offset(),
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
VmCtx::offset_imported_tables() as usize,
|
||||
offset_of!(VmCtx => imported_tables).get_byte_offset(),
|
||||
Ctx::offset_imported_tables() as usize,
|
||||
offset_of!(Ctx => imported_tables).get_byte_offset(),
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
VmCtx::offset_imported_globals() as usize,
|
||||
offset_of!(VmCtx => imported_globals).get_byte_offset(),
|
||||
Ctx::offset_imported_globals() as usize,
|
||||
offset_of!(Ctx => imported_globals).get_byte_offset(),
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
VmCtx::offset_imported_funcs() as usize,
|
||||
offset_of!(VmCtx => imported_funcs).get_byte_offset(),
|
||||
Ctx::offset_imported_funcs() as usize,
|
||||
offset_of!(Ctx => imported_funcs).get_byte_offset(),
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
VmCtx::offset_sig_ids() as usize,
|
||||
offset_of!(VmCtx => sig_ids).get_byte_offset(),
|
||||
Ctx::offset_sig_ids() as usize,
|
||||
offset_of!(Ctx => sig_ids).get_byte_offset(),
|
||||
);
|
||||
}
|
||||
|
||||
@ -382,18 +386,18 @@ mod vm_offset_tests {
|
||||
#[test]
|
||||
fn cc_anyfunc() {
|
||||
assert_eq!(
|
||||
CCAnyfunc::offset_func() as usize,
|
||||
offset_of!(CCAnyfunc => func_data: ImportedFunc => func).get_byte_offset(),
|
||||
Anyfunc::offset_func() as usize,
|
||||
offset_of!(Anyfunc => func_data: ImportedFunc => func).get_byte_offset(),
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
CCAnyfunc::offset_vmctx() as usize,
|
||||
offset_of!(CCAnyfunc => func_data: ImportedFunc => vmctx).get_byte_offset(),
|
||||
Anyfunc::offset_vmctx() as usize,
|
||||
offset_of!(Anyfunc => func_data: ImportedFunc => vmctx).get_byte_offset(),
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
CCAnyfunc::offset_sig_id() as usize,
|
||||
offset_of!(CCAnyfunc => sig_id).get_byte_offset(),
|
||||
Anyfunc::offset_sig_id() as usize,
|
||||
offset_of!(Anyfunc => sig_id).get_byte_offset(),
|
||||
);
|
||||
}
|
||||
}
|
@ -30,7 +30,7 @@ use super::memory::LinearMemory;
|
||||
use super::module::{Export, ImportableExportable, Module};
|
||||
use super::relocation::{Reloc, RelocSink, RelocationType};
|
||||
use super::vm;
|
||||
use super::backing::{Backing, ImportsBacking};
|
||||
use super::backing::{LocalBacking, ImportsBacking};
|
||||
|
||||
type TablesSlice = UncheckedSlice<BoundedSlice<usize>>;
|
||||
// TODO: this should be `type MemoriesSlice = UncheckedSlice<UncheckedSlice<u8>>;`, but that crashes for some reason.
|
||||
@ -96,13 +96,14 @@ pub enum InstanceABI {
|
||||
#[derive(Debug)]
|
||||
#[repr(C)]
|
||||
pub struct Instance {
|
||||
pub vmctx: vm::Ctx,
|
||||
// C-like pointers to data (heaps, globals, tables)
|
||||
pub data_pointers: DataPointers,
|
||||
|
||||
/// Webassembly functions
|
||||
finalized_funcs: Box<[*const vm::Func]>,
|
||||
|
||||
backing: Backing,
|
||||
backing: LocalBacking,
|
||||
|
||||
imports: ImportsBacking,
|
||||
|
||||
@ -113,6 +114,14 @@ pub struct Instance {
|
||||
pub emscripten_data: Option<EmscriptenData>,
|
||||
}
|
||||
|
||||
impl Instance {
|
||||
/// Shortcut for converting from a `vm::Ctx` pointer to a reference to the `Instance`.
|
||||
/// This works because of the `vm::Ctx` is the first field of the `Instance`.
|
||||
pub unsafe fn from_vmctx<'a>(ctx: *mut vm::Ctx) -> &'a mut Instance {
|
||||
&mut *(ctx as *mut Instance)
|
||||
}
|
||||
}
|
||||
|
||||
/// Contains pointers to data (heaps, globals, tables) needed
|
||||
/// by Cranelift.
|
||||
/// NOTE: Rearranging the fields will break the memory arrangement model
|
||||
|
@ -1,54 +0,0 @@
|
||||
use super::vm::{CCAnyfunc, LocalTable};
|
||||
use cranelift_wasm::{
|
||||
Table as ClifTable,
|
||||
TableElementType,
|
||||
};
|
||||
|
||||
pub struct TableScheme {
|
||||
table: ClifTable,
|
||||
info: TableInfo,
|
||||
}
|
||||
|
||||
impl TableScheme {
|
||||
pub fn from_table(table: ClifTable) -> Self {
|
||||
Self {
|
||||
table,
|
||||
info: match table.ty {
|
||||
TableElementType::Func => TableInfo::CallerChecks,
|
||||
TableElementType::Val(_) => unimplemented!(),
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
|
||||
pub enum TableInfo {
|
||||
CallerChecks,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct TableBacking {
|
||||
pub elements: Box<[CCAnyfunc]>,
|
||||
pub max: Option<u32>,
|
||||
}
|
||||
|
||||
impl TableBacking {
|
||||
pub fn new(scheme: &TableScheme) -> Self {
|
||||
match (scheme.table.ty, scheme.info) {
|
||||
(TableElementType::Func, TableInfo::CallerChecks) => {
|
||||
TableBacking {
|
||||
elements: vec![CCAnyfunc::null(); scheme.table.minimum as usize].into(),
|
||||
max: scheme.table.maximum,
|
||||
}
|
||||
},
|
||||
(TableElementType::Val(_), _) => unimplemented!(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn into_vm_table(&mut self) -> LocalTable {
|
||||
LocalTable {
|
||||
base: self.elements.as_mut_ptr() as *mut u8,
|
||||
current_elements: self.elements.len(),
|
||||
}
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user