Rewrite exports and imports

This commit is contained in:
Lachlan Sneff
2019-01-10 22:59:57 -05:00
parent 1a5ef3aea2
commit 230e43a894
81 changed files with 75027 additions and 16753 deletions

View File

@ -1,8 +1,8 @@
use crate::{module::Module, types::FuncIndex, vm};
use std::ptr::NonNull;
pub use crate::sig_registry::SigRegistry;
pub use crate::mmap::{Mmap, Protect};
pub use crate::sig_registry::SigRegistry;
pub trait Compiler {
/// Compiles a `Module` from WebAssembly binary format

View File

@ -1,5 +1,6 @@
use crate::{
instance::{Import, ImportResolver},
export::{Context, Export},
import::ImportResolver,
memory::LinearMemory,
module::{ImportName, Module},
table::{TableBacking, TableElements},
@ -18,13 +19,13 @@ pub struct LocalBacking {
}
impl LocalBacking {
pub fn new(module: &Module, imports: &ImportBacking) -> Self {
pub fn new(module: &Module, imports: &ImportBacking, vmctx: *mut vm::Ctx) -> Self {
let mut memories = Self::generate_memories(module);
let mut tables = Self::generate_tables(module);
let globals = Self::generate_globals(module);
let vm_memories = Self::finalize_memories(module, &mut memories[..]);
let vm_tables = Self::finalize_tables(module, imports, &mut tables[..]);
let vm_tables = Self::finalize_tables(module, imports, &mut tables[..], vmctx);
let vm_globals = Self::finalize_globals(module, imports, globals);
Self {
@ -61,9 +62,7 @@ impl LocalBacking {
fn finalize_memories(module: &Module, memories: &mut [LinearMemory]) -> Box<[vm::LocalMemory]> {
for init in &module.data_initializers {
assert!(init.base.is_none(), "global base not supported yet");
assert!(
init.offset + init.data.len() <= memories[init.memory_index.index()].size()
);
assert!(init.offset + init.data.len() <= memories[init.memory_index.index()].size());
let offset = init.offset;
let mem: &mut LinearMemory = &mut memories[init.memory_index.index()];
// let end_of_init = offset + init.data.len();
@ -98,6 +97,7 @@ impl LocalBacking {
module: &Module,
imports: &ImportBacking,
tables: &mut [TableBacking],
vmctx: *mut vm::Ctx,
) -> Box<[vm::LocalTable]> {
for init in &module.table_initializers {
assert!(init.base.is_none(), "global base not supported yet");
@ -106,7 +106,8 @@ impl LocalBacking {
TableElements::Anyfunc(ref mut elements) => {
for (i, &func_index) in init.elements.iter().enumerate() {
let sig_index = module.func_assoc[func_index];
let vm_sig_id = vm::SigId(sig_index.index() as u32);
let sig_id = vm::SigId(sig_index.index() as u32);
let func_data = if module.is_imported_function(func_index) {
imports.functions[func_index.index()].clone()
} else {
@ -116,13 +117,13 @@ impl LocalBacking {
.get(module, func_index)
.unwrap()
.as_ptr(),
vmctx,
}
};
elements[init.offset + i] = vm::Anyfunc {
func_data,
sig_id: vm_sig_id,
};
println!("func_data: {:#?}", func_data);
elements[init.offset + i] = vm::Anyfunc { func_data, sig_id };
}
}
}
@ -152,7 +153,9 @@ impl LocalBacking {
Initializer::Const(Value::I64(x)) => x as u64,
Initializer::Const(Value::F32(x)) => x.to_bits() as u64,
Initializer::Const(Value::F64(x)) => x.to_bits(),
Initializer::GetGlobal(index) => (imports.globals[index.index()].global).data,
Initializer::GetGlobal(index) => unsafe {
(*imports.globals[index.index()].global).data
},
};
}
@ -169,7 +172,11 @@ pub struct ImportBacking {
}
impl ImportBacking {
pub fn new(module: &Module, imports: &dyn ImportResolver) -> Result<Self, String> {
pub fn new(
module: &Module,
imports: &dyn ImportResolver,
vmctx: *mut vm::Ctx,
) -> Result<Self, String> {
assert!(
module.imported_memories.len() == 0,
"imported memories not yet supported"
@ -180,7 +187,7 @@ impl ImportBacking {
);
Ok(ImportBacking {
functions: import_functions(module, imports)?,
functions: import_functions(module, imports, vmctx)?,
memories: vec![].into_boxed_slice(),
tables: vec![].into_boxed_slice(),
globals: import_globals(module, imports)?,
@ -192,89 +199,71 @@ impl ImportBacking {
// }
fn import_functions(module: &Module, imports: &dyn ImportResolver) -> Result<Box<[vm::ImportedFunc]>, String> {
fn import_functions(
module: &Module,
imports: &dyn ImportResolver,
vmctx: *mut vm::Ctx,
) -> Result<Box<[vm::ImportedFunc]>, String> {
let mut functions = Vec::with_capacity(module.imported_functions.len());
for (
index,
ImportName {
module: mod_name,
name: item_name,
},
) in &module.imported_functions
{
for (index, ImportName { namespace, name }) in &module.imported_functions {
let sig_index = module.func_assoc[index];
let expected_sig = module.sig_registry.lookup_func_sig(sig_index);
let import = imports.get(mod_name, item_name);
let import = imports.get(namespace, name);
match import {
Some(&Import::Func(ref func, ref signature)) => {
if expected_sig == signature {
Some(Export::Function {
func,
ctx,
signature,
}) => {
if expected_sig == &signature {
functions.push(vm::ImportedFunc {
func: func.inner(),
// vmctx: ptr::null_mut(),
vmctx: match ctx {
Context::External(ctx) => ctx,
Context::Internal => vmctx,
},
});
} else {
return Err(format!(
"unexpected signature for {:?}:{:?}",
mod_name, item_name
namespace, name
));
}
}
Some(_) => {
return Err(format!(
"incorrect import type for {}:{}",
mod_name, item_name
));
return Err(format!("incorrect import type for {}:{}", namespace, name));
}
None => {
return Err(format!("import not found: {}:{}", mod_name, item_name));
return Err(format!("import not found: {}:{}", namespace, name));
}
}
}
Ok(functions.into_boxed_slice())
}
fn import_globals(module: &Module, imports: &dyn ImportResolver) -> Result<Box<[vm::ImportedGlobal]>, String> {
fn import_globals(
module: &Module,
imports: &dyn ImportResolver,
) -> Result<Box<[vm::ImportedGlobal]>, String> {
let mut globals = Vec::with_capacity(module.imported_globals.len());
for (
_,
(
ImportName {
module: mod_name,
name: item_name,
},
global_desc,
),
) in &module.imported_globals
{
let import = imports.get(mod_name, item_name);
for (_, (ImportName { namespace, name }, global_desc)) in &module.imported_globals {
let import = imports.get(namespace, name);
match import {
Some(Import::Global(val)) => {
if val.ty() == global_desc.ty {
globals.push(vm::ImportedGlobal {
global: vm::LocalGlobal {
data: match val {
Value::I32(n) => *n as u64,
Value::I64(n) => *n as u64,
Value::F32(n) => (*n).to_bits() as u64,
Value::F64(n) => (*n).to_bits(),
},
},
});
Some(Export::Global { local, global }) => {
if &global == global_desc {
globals.push(vm::ImportedGlobal { global: local });
} else {
return Err(format!(
"unexpected global type for {:?}:{:?}",
mod_name, item_name
"unexpected global description for {:?}:{:?}",
namespace, name
));
}
}
Some(_) => {
return Err(format!(
"incorrect import type for {}:{}",
mod_name, item_name
));
return Err(format!("incorrect import type for {}:{}", namespace, name));
}
None => {
return Err(format!("import not found: {}:{}", mod_name, item_name));
return Err(format!("import not found: {}:{}", namespace, name));
}
}
}

34
lib/runtime/src/export.rs Normal file
View File

@ -0,0 +1,34 @@
use crate::{
instance::FuncRef,
types::{FuncSig, GlobalDesc, Memory, Table},
vm,
};
#[derive(Debug, Clone)]
pub enum Context {
External(*mut vm::Ctx),
Internal,
}
#[derive(Debug, Clone)]
pub enum Export {
Function {
func: FuncRef,
ctx: Context,
signature: FuncSig,
},
Memory {
local: *mut vm::LocalMemory,
ctx: Context,
memory: Memory,
},
Table {
local: *mut vm::LocalTable,
ctx: Context,
table: Table,
},
Global {
local: *mut vm::LocalGlobal,
global: GlobalDesc,
},
}

58
lib/runtime/src/import.rs Normal file
View File

@ -0,0 +1,58 @@
use crate::{export::Export, Instance};
use hashbrown::{hash_map::Entry, HashMap};
pub trait ImportResolver {
fn get(&self, namespace: &str, name: &str) -> Option<Export>;
}
enum Namespace {
Instance(Box<Instance>),
UserSupplied(HashMap<String, Export>),
}
pub struct Imports {
map: HashMap<String, Namespace>,
}
impl Imports {
pub fn new() -> Self {
Self {
map: HashMap::new(),
}
}
pub fn register_instance(&mut self, namespace: impl Into<String>, instance: Box<Instance>) {
match self.map.entry(namespace.into()) {
Entry::Vacant(empty) => empty.insert(Namespace::Instance(instance)),
Entry::Occupied(_) => {
panic!("cannot register an instance in a namespace that already exists")
}
};
}
pub fn register_export(
&mut self,
namespace: impl Into<String>,
name: impl Into<String>,
export: Export,
) {
let namespace_item = self
.map
.entry(namespace.into())
.or_insert_with(|| Namespace::UserSupplied(HashMap::new()));
match namespace_item {
Namespace::UserSupplied(ref mut map) => map.insert(name.into(), export),
Namespace::Instance(_) => panic!("cannot register an export in a namespace that has already been used to register an instance"),
};
}
}
impl ImportResolver for Imports {
fn get(&self, namespace: &str, name: &str) -> Option<Export> {
match self.map.get(namespace)? {
Namespace::UserSupplied(map) => map.get(name).cloned(),
Namespace::Instance(instance) => instance.get_export(name).ok(),
}
}
}

View File

@ -1,40 +1,54 @@
use crate::recovery::call_protected;
use crate::{
backing::{ImportBacking, LocalBacking},
memory::LinearMemory,
module::{Export, Module},
table::TableBacking,
types::{FuncIndex, FuncSig, Memory, Table, Type, Value, MapIndex},
export::{Context, Export},
import::ImportResolver,
module::{ExportIndex, Module},
types::{FuncIndex, FuncSig, MapIndex, Type, Value},
vm,
};
use hashbrown::HashMap;
use hashbrown::hash_map;
use libffi::high::{arg as libffi_arg, call as libffi_call, CodePtr};
use std::iter;
use std::sync::Arc;
use std::rc::Rc;
use std::{iter, mem};
pub struct Instance {
pub(crate) backing: LocalBacking,
import_backing: ImportBacking,
pub module: Module,
#[allow(dead_code)]
pub(crate) backing: LocalBacking,
#[allow(dead_code)]
imports: Rc<dyn ImportResolver>,
import_backing: ImportBacking,
vmctx: Box<vm::Ctx>,
}
impl Instance {
pub(crate) fn new(
module: Module,
imports: &dyn ImportResolver,
imports: Rc<dyn ImportResolver>,
) -> Result<Box<Instance>, String> {
let import_backing = ImportBacking::new(&module, imports)?;
let backing = LocalBacking::new(&module, &import_backing);
// We need the backing and import_backing to create a vm::Ctx, but we need
// a vm::Ctx to create a backing and an import_backing. The solution is to create an
// uninitialized vm::Ctx and then initialize it in-place.
let mut vmctx = unsafe { Box::new(mem::uninitialized()) };
let start_func = module.start_func;
let import_backing = ImportBacking::new(&module, &*imports, &mut *vmctx)?;
let backing = LocalBacking::new(&module, &import_backing, &mut *vmctx);
// When Pin is stablized, this will use `Box::pinned` instead of `Box::new`.
let mut instance = Box::new(Instance {
backing,
import_backing,
module,
backing,
imports,
import_backing,
vmctx,
});
if let Some(start_index) = start_func {
// Initialize the vm::Ctx in-place after the import_backing
// has been boxed.
*instance.vmctx = vm::Ctx::new(&mut instance.backing, &mut instance.import_backing);
if let Some(start_index) = instance.module.start_func {
instance.call_with_index(start_index, &[])?;
}
@ -48,15 +62,17 @@ impl Instance {
/// This will eventually return `Result<Option<Vec<Value>>, String>` in
/// order to support multi-value returns.
pub fn call(&mut self, name: &str, args: &[Value]) -> Result<Option<Value>, String> {
let func_index = *self
let export_index = self
.module
.exports
.get(name)
.ok_or_else(|| "there is no export with that name".to_string())
.and_then(|export| match export {
Export::Func(func_index) => Ok(func_index),
_ => Err("that export is not a function".to_string()),
})?;
.ok_or_else(|| format!("there is no export with that name: {}", name))?;
let func_index = if let ExportIndex::Func(func_index) = export_index {
*func_index
} else {
return Err("that export is not a function".to_string());
};
self.call_with_index(func_index, args)
}
@ -66,31 +82,25 @@ impl Instance {
func_index: FuncIndex,
args: &[Value],
) -> Result<Option<Value>, String> {
// Check the function signature.
let sig_index = *self
.module
.func_assoc
.get(func_index)
.expect("broken invariant, incorrect func index");
{
let signature = self.module.sig_registry.lookup_func_sig(sig_index);
let (func_ref, ctx, signature) = self.get_func_from_index(func_index);
assert!(
signature.returns.len() <= 1,
"multi-value returns not yet supported"
);
println!("func_ref: {:?}", func_ref);
if !signature.check_sig(args) {
return Err("incorrect signature".to_string());
}
let func_ptr = CodePtr::from_ptr(func_ref.inner() as _);
let vmctx_ptr = match ctx {
Context::External(vmctx) => vmctx,
Context::Internal => &mut *self.vmctx,
};
assert!(
signature.returns.len() <= 1,
"multi-value returns not yet supported"
);
if !signature.check_sig(args) {
return Err("incorrect signature".to_string());
}
// the vmctx will be located at the same place on the stack the entire time that this
// wasm function is running.
let mut vmctx = vm::Ctx::new(&mut self.backing, &mut self.import_backing);
let vmctx_ptr = &mut vmctx as *mut vm::Ctx;
let libffi_args: Vec<_> = args
.iter()
.map(|val| match val {
@ -102,22 +112,8 @@ impl Instance {
.chain(iter::once(libffi_arg(&vmctx_ptr)))
.collect();
let func_ptr = CodePtr::from_ptr(if self.module.is_imported_function(func_index) {
let imported_func = &self.import_backing.functions[func_index.index()];
imported_func.func as *const _
} else {
self.module
.func_resolver
.get(&self.module, func_index)
.expect("broken invariant, func resolver not synced with module.exports")
.cast()
.as_ptr()
});
call_protected(|| {
self.module
.sig_registry
.lookup_func_sig(sig_index)
signature
.returns
.first()
.map(|ty| match ty {
@ -135,9 +131,75 @@ impl Instance {
})
})
}
pub fn get_export(&self, name: &str) -> Result<Export, String> {
let export_index = self
.module
.exports
.get(name)
.ok_or_else(|| format!("there is no export with that name: {}", name))?;
Ok(self.get_export_from_index(export_index))
}
pub fn exports(&self) -> ExportIter {
ExportIter::new(self)
}
fn get_export_from_index(&self, export_index: &ExportIndex) -> Export {
match export_index {
ExportIndex::Func(func_index) => {
let (func, ctx, signature) = self.get_func_from_index(*func_index);
Export::Function {
func,
ctx: match ctx {
Context::Internal => {
Context::External(&*self.vmctx as *const vm::Ctx as *mut vm::Ctx)
}
ctx @ Context::External(_) => ctx,
},
signature,
}
}
ExportIndex::Memory(_memory_index) => unimplemented!(),
ExportIndex::Global(_global_index) => unimplemented!(),
ExportIndex::Table(_table_index) => unimplemented!(),
}
}
fn get_func_from_index(&self, func_index: FuncIndex) -> (FuncRef, Context, FuncSig) {
let sig_index = *self
.module
.func_assoc
.get(func_index)
.expect("broken invariant, incorrect func index");
let (func_ptr, ctx) = if self.module.is_imported_function(func_index) {
let imported_func = &self.import_backing.functions[func_index.index()];
(
imported_func.func as *const _,
Context::External(imported_func.vmctx),
)
} else {
(
self.module
.func_resolver
.get(&self.module, func_index)
.expect("broken invariant, func resolver not synced with module.exports")
.cast()
.as_ptr() as *const _,
Context::Internal,
)
};
let signature = self.module.sig_registry.lookup_func_sig(sig_index).clone();
(FuncRef(func_ptr), ctx, signature)
}
}
#[derive(Debug)]
#[derive(Debug, Clone)]
pub struct FuncRef(*const vm::Func);
impl FuncRef {
@ -153,47 +215,31 @@ impl FuncRef {
}
}
#[derive(Debug)]
pub enum Import {
Func(FuncRef, FuncSig),
Table(Arc<TableBacking>, Table),
Memory(Arc<LinearMemory>, Memory),
Global(Value),
pub struct ExportIter<'a> {
instance: &'a Instance,
iter: hash_map::Iter<'a, String, ExportIndex>,
}
pub struct Imports {
map: HashMap<String, HashMap<String, Import>>,
}
impl Imports {
pub fn new() -> Self {
impl<'a> ExportIter<'a> {
fn new(instance: &'a Instance) -> Self {
Self {
map: HashMap::new(),
instance,
iter: instance.module.exports.iter(),
}
}
pub fn add(&mut self, module: impl Into<String>, name: impl Into<String>, import: Import) {
self.map
.entry(module.into())
.or_insert_with(|| HashMap::new())
.insert(name.into(), import);
}
pub fn get(&self, module: &str, name: &str) -> Option<&Import> {
self.map.get(module).and_then(|m| m.get(name))
}
}
impl ImportResolver for Imports {
fn get(&self, module: &str, name: &str) -> Option<&Import> {
self.get(module, name)
impl<'a> Iterator for ExportIter<'a> {
type Item = (String, Export);
fn next(&mut self) -> Option<(String, Export)> {
let (name, export_index) = self.iter.next()?;
Some((
name.clone(),
self.instance.get_export_from_index(export_index),
))
}
}
pub trait ImportResolver {
fn get(&self, module: &str, name: &str) -> Option<&Import>;
}
// TODO Remove this later, only needed for compilation till emscripten is updated
impl Instance {
pub fn memory_offset_addr(&self, _index: usize, _offset: usize) -> *const usize {

View File

@ -4,21 +4,23 @@ extern crate field_offset;
#[macro_use]
mod macros;
pub mod backend;
mod backing;
pub mod export;
pub mod import;
mod instance;
mod memory;
mod recovery;
mod sighandler;
mod sig_registry;
mod mmap;
pub mod module;
pub mod backend;
mod recovery;
mod sig_registry;
mod sighandler;
pub mod table;
pub mod types;
pub mod vm;
pub mod vmcalls;
pub use self::instance::{Import, ImportResolver, Imports, FuncRef, Instance};
pub use self::instance::{FuncRef, Instance};
pub use self::memory::LinearMemory;
/// Compile a webassembly module using the provided compiler.

View File

@ -52,21 +52,22 @@ impl LinearMemory {
assert!(mem.max.is_none() || mem.max.unwrap() <= Self::MAX_PAGES);
debug!("Instantiate LinearMemory(mem: {:?})", mem);
let (mmap_size, initial_pages, offset_guard_size, requires_signal_catch) =
if /*mem.is_static_heap()*/ true {
(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 (mmap_size, initial_pages, offset_guard_size, requires_signal_catch) = if
/*mem.is_static_heap()*/
true {
(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.");
(
mem.min as usize * Self::PAGE_SIZE as usize,
mem.min,
0,
false,
)
};
(
mem.min as usize * Self::PAGE_SIZE as usize,
mem.min,
0,
false,
)
};
let mut mmap = Mmap::with_size(mmap_size).unwrap();

View File

@ -1,15 +1,16 @@
use crate::{
backend::FuncResolver,
import::ImportResolver,
sig_registry::SigRegistry,
types::{
FuncIndex, Global, GlobalDesc, GlobalIndex, Map, MapIndex, Memory, MemoryIndex, SigIndex,
Table, TableIndex,
},
ImportResolver, Instance,
Instance,
};
use hashbrown::HashMap;
use std::ops::Deref;
use std::sync::Arc;
use std::rc::Rc;
/// This is used to instantiate a new webassembly module.
pub struct ModuleInner {
@ -23,7 +24,7 @@ pub struct ModuleInner {
pub imported_tables: Map<TableIndex, (ImportName, Table)>,
pub imported_globals: Map<GlobalIndex, (ImportName, GlobalDesc)>,
pub exports: HashMap<String, Export>,
pub exports: HashMap<String, ExportIndex>,
pub data_initializers: Vec<DataInitializer>,
pub table_initializers: Vec<TableInitializer>,
@ -33,17 +34,17 @@ pub struct ModuleInner {
pub sig_registry: SigRegistry,
}
pub struct Module(Arc<ModuleInner>);
pub struct Module(Rc<ModuleInner>);
impl Module {
#[inline]
pub fn new(inner: ModuleInner) -> Self {
Module(Arc::new(inner))
Module(Rc::new(inner))
}
/// Instantiate a webassembly module with the provided imports.
pub fn instantiate(&self, imports: &dyn ImportResolver) -> Result<Box<Instance>, String> {
Instance::new(Module(Arc::clone(&self.0)), imports)
pub fn instantiate(&self, imports: Rc<dyn ImportResolver>) -> Result<Box<Instance>, String> {
Instance::new(Module(Rc::clone(&self.0)), imports)
}
}
@ -63,21 +64,21 @@ impl Deref for Module {
#[derive(Debug, Clone)]
pub struct ImportName {
pub module: String,
pub namespace: String,
pub name: String,
}
impl From<(String, String)> for ImportName {
fn from(n: (String, String)) -> Self {
ImportName {
module: n.0,
namespace: n.0,
name: n.1,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Export {
pub enum ExportIndex {
Func(FuncIndex),
Memory(MemoryIndex),
Global(GlobalIndex),

View File

@ -1,6 +1,4 @@
use crate::{
types::{FuncSig, Map, SigIndex},
};
use crate::types::{FuncSig, Map, SigIndex};
use hashbrown::HashMap;
#[derive(Debug)]

View File

@ -1,9 +1,8 @@
use std::marker::PhantomData;
use std::{
iter,
iter, mem,
ops::{Index, IndexMut},
slice,
mem,
};
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
@ -354,7 +353,7 @@ impl<T> MonoVec<T> {
0 | 1 => Self::new(),
_ => Self {
inner: MonoVecInner::Heap(Vec::with_capacity(capacity)),
}
},
}
}
@ -362,16 +361,12 @@ impl<T> MonoVec<T> {
let uninit = unsafe { mem::uninitialized() };
let prev = mem::replace(&mut self.inner, uninit);
let next = match prev {
MonoVecInner::None => {
MonoVecInner::Inline(item)
},
MonoVecInner::Inline(previous_item) => {
MonoVecInner::Heap(vec![previous_item, item])
},
MonoVecInner::None => MonoVecInner::Inline(item),
MonoVecInner::Inline(previous_item) => MonoVecInner::Heap(vec![previous_item, item]),
MonoVecInner::Heap(mut v) => {
v.push(item);
MonoVecInner::Heap(v)
},
}
};
let uninit = mem::replace(&mut self.inner, next);
mem::forget(uninit);
@ -379,51 +374,35 @@ impl<T> MonoVec<T> {
pub fn pop(&mut self) -> Option<T> {
match self.inner {
MonoVecInner::None => {
None
},
MonoVecInner::None => None,
MonoVecInner::Inline(ref mut item) => {
let uninit = unsafe { mem::uninitialized() };
let item = mem::replace(item, uninit);
let uninit = mem::replace(&mut self.inner, MonoVecInner::None);
mem::forget(uninit);
Some(item)
},
MonoVecInner::Heap(ref mut v) => {
v.pop()
},
}
MonoVecInner::Heap(ref mut v) => v.pop(),
}
}
pub fn as_slice(&self) -> &[T] {
match self.inner {
MonoVecInner::None => {
unsafe {
slice::from_raw_parts(mem::align_of::<T>() as *const T, 0)
}
},
MonoVecInner::Inline(ref item) => {
slice::from_ref(item)
},
MonoVecInner::Heap(ref v) => {
&v[..]
MonoVecInner::None => unsafe {
slice::from_raw_parts(mem::align_of::<T>() as *const T, 0)
},
MonoVecInner::Inline(ref item) => slice::from_ref(item),
MonoVecInner::Heap(ref v) => &v[..],
}
}
pub fn as_slice_mut(&mut self) -> &mut [T] {
match self.inner {
MonoVecInner::None => {
unsafe {
slice::from_raw_parts_mut(mem::align_of::<T>() as *mut T, 0)
}
},
MonoVecInner::Inline(ref mut item) => {
slice::from_mut(item)
},
MonoVecInner::Heap(ref mut v) => {
&mut v[..]
MonoVecInner::None => unsafe {
slice::from_raw_parts_mut(mem::align_of::<T>() as *mut T, 0)
},
MonoVecInner::Inline(ref mut item) => slice::from_mut(item),
MonoVecInner::Heap(ref mut v) => &mut v[..],
}
}
}
}

View File

@ -40,7 +40,7 @@ impl Ctx {
imported_tables: import_backing.tables.as_mut_ptr(),
imported_globals: import_backing.globals.as_mut_ptr(),
imported_funcs: import_backing.functions.as_mut_ptr(),
local_backing,
}
}
@ -88,6 +88,7 @@ pub enum Func {}
#[repr(C)]
pub struct ImportedFunc {
pub func: *const Func,
pub vmctx: *mut Ctx,
}
impl ImportedFunc {
@ -95,6 +96,10 @@ impl ImportedFunc {
0 * (mem::size_of::<usize>() as u8)
}
pub fn offset_vmctx() -> u8 {
1 * (mem::size_of::<usize>() as u8)
}
pub fn size() -> u8 {
mem::size_of::<Self>() as u8
}
@ -164,12 +169,17 @@ impl LocalMemory {
pub struct ImportedMemory {
/// A pointer to the memory definition.
pub memory: *mut LocalMemory,
pub vmctx: *mut Ctx,
}
impl ImportedMemory {
pub fn offset_memory() -> u8 {
0 * (mem::size_of::<usize>() as u8)
}
pub fn offset_vmctx() -> u8 {
1 * (mem::size_of::<usize>() as u8)
}
}
/// Definition of a global used by the VM.
@ -192,11 +202,11 @@ impl LocalGlobal {
#[derive(Debug, Clone)]
#[repr(C)]
pub struct ImportedGlobal {
pub global: LocalGlobal,
pub global: *mut LocalGlobal,
}
impl ImportedGlobal {
pub fn offset_data() -> u8 {
pub fn offset_global() -> u8 {
0 * (mem::size_of::<usize>() as u8)
}
}
@ -216,7 +226,10 @@ pub struct Anyfunc {
impl Anyfunc {
pub fn null() -> Self {
Self {
func_data: ImportedFunc { func: ptr::null() },
func_data: ImportedFunc {
func: ptr::null(),
vmctx: ptr::null_mut(),
},
sig_id: SigId(u32::max_value()),
}
}
@ -225,12 +238,12 @@ impl Anyfunc {
0 * (mem::size_of::<usize>() as u8)
}
// pub fn offset_vmctx() -> u8 {
// 1 * (mem::size_of::<usize>() as u8)
// }
pub fn offset_vmctx() -> u8 {
1 * (mem::size_of::<usize>() as u8)
}
pub fn offset_sig_id() -> u8 {
1 * (mem::size_of::<usize>() as u8)
2 * (mem::size_of::<usize>() as u8)
}
}
@ -286,10 +299,10 @@ mod vm_offset_tests {
offset_of!(ImportedFunc => func).get_byte_offset(),
);
// assert_eq!(
// ImportedFunc::offset_vmctx() as usize,
// offset_of!(ImportedFunc => vmctx).get_byte_offset(),
// );
assert_eq!(
ImportedFunc::offset_vmctx() as usize,
offset_of!(ImportedFunc => vmctx).get_byte_offset(),
);
}
#[test]
@ -337,6 +350,11 @@ mod vm_offset_tests {
ImportedMemory::offset_memory() as usize,
offset_of!(ImportedMemory => memory).get_byte_offset(),
);
assert_eq!(
ImportedMemory::offset_vmctx() as usize,
offset_of!(ImportedMemory => vmctx).get_byte_offset(),
);
}
#[test]
@ -350,8 +368,8 @@ mod vm_offset_tests {
#[test]
fn imported_global() {
assert_eq!(
ImportedGlobal::offset_data() as usize,
offset_of!(ImportedGlobal => global: LocalGlobal => data).get_byte_offset(),
ImportedGlobal::offset_global() as usize,
offset_of!(ImportedGlobal => global).get_byte_offset(),
);
}
@ -362,10 +380,10 @@ mod vm_offset_tests {
offset_of!(Anyfunc => func_data: ImportedFunc => func).get_byte_offset(),
);
// assert_eq!(
// Anyfunc::offset_vmctx() as usize,
// offset_of!(Anyfunc => func_data: ImportedFunc => vmctx).get_byte_offset(),
// );
assert_eq!(
Anyfunc::offset_vmctx() as usize,
offset_of!(Anyfunc => func_data: ImportedFunc => vmctx).get_byte_offset(),
);
assert_eq!(
Anyfunc::offset_sig_id() as usize,

View File

@ -25,7 +25,8 @@ pub unsafe extern "C" fn memory_grow_dynamic(
by_pages: u32,
ctx: *mut vm::Ctx,
) -> i32 {
if let Some(old) = (*(*ctx).local_backing).memories[memory_index as usize].grow_dynamic(by_pages)
if let Some(old) =
(*(*ctx).local_backing).memories[memory_index as usize].grow_dynamic(by_pages)
{
// Store the new size back into the vmctx.
(*(*ctx).memories.add(memory_index as usize)).size =
@ -34,4 +35,4 @@ pub unsafe extern "C" fn memory_grow_dynamic(
} else {
-1
}
}
}