mirror of
https://github.com/fluencelabs/wasmer
synced 2025-06-14 17:31:20 +00:00
Rework imports
This commit is contained in:
@ -1,4 +1,4 @@
|
||||
use crate::{module::Module, types::FuncIndex, vm};
|
||||
use crate::{module::ModuleInner, types::FuncIndex, vm};
|
||||
use std::ptr::NonNull;
|
||||
|
||||
pub use crate::mmap::{Mmap, Protect};
|
||||
@ -6,9 +6,9 @@ pub use crate::sig_registry::SigRegistry;
|
||||
|
||||
pub trait Compiler {
|
||||
/// Compiles a `Module` from WebAssembly binary format
|
||||
fn compile(&self, wasm: &[u8]) -> Result<Module, String>;
|
||||
fn compile(&self, wasm: &[u8]) -> Result<ModuleInner, String>;
|
||||
}
|
||||
|
||||
pub trait FuncResolver {
|
||||
fn get(&self, module: &Module, index: FuncIndex) -> Option<NonNull<vm::Func>>;
|
||||
fn get(&self, module: &ModuleInner, index: FuncIndex) -> Option<NonNull<vm::Func>>;
|
||||
}
|
||||
|
@ -1,8 +1,8 @@
|
||||
use crate::{
|
||||
export::{Context, Export},
|
||||
import::ImportResolver,
|
||||
import::Imports,
|
||||
memory::LinearMemory,
|
||||
module::{ImportName, Module},
|
||||
module::{ImportName, ModuleInner},
|
||||
table::{TableBacking, TableElements},
|
||||
types::{Initializer, MapIndex, Value},
|
||||
vm,
|
||||
@ -10,16 +10,26 @@ use crate::{
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct LocalBacking {
|
||||
pub memories: Box<[LinearMemory]>,
|
||||
pub tables: Box<[TableBacking]>,
|
||||
pub(crate) memories: Box<[LinearMemory]>,
|
||||
pub(crate) tables: Box<[TableBacking]>,
|
||||
|
||||
pub vm_memories: Box<[vm::LocalMemory]>,
|
||||
pub vm_tables: Box<[vm::LocalTable]>,
|
||||
pub vm_globals: Box<[vm::LocalGlobal]>,
|
||||
pub(crate) vm_memories: Box<[vm::LocalMemory]>,
|
||||
pub(crate) vm_tables: Box<[vm::LocalTable]>,
|
||||
pub(crate) vm_globals: Box<[vm::LocalGlobal]>,
|
||||
}
|
||||
|
||||
impl LocalBacking {
|
||||
pub fn new(module: &Module, imports: &ImportBacking, vmctx: *mut vm::Ctx) -> Self {
|
||||
pub fn memory(&mut self, index: u32) -> &mut LinearMemory {
|
||||
&mut self.memories[index as usize]
|
||||
}
|
||||
|
||||
pub fn table(&mut self, index: u32) -> &mut TableBacking {
|
||||
&mut self.tables[index as usize]
|
||||
}
|
||||
}
|
||||
|
||||
impl LocalBacking {
|
||||
pub(crate) fn new(module: &ModuleInner, 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);
|
||||
@ -38,7 +48,7 @@ impl LocalBacking {
|
||||
}
|
||||
}
|
||||
|
||||
fn generate_memories(module: &Module) -> Box<[LinearMemory]> {
|
||||
fn generate_memories(module: &ModuleInner) -> Box<[LinearMemory]> {
|
||||
let mut memories = Vec::with_capacity(module.memories.len());
|
||||
|
||||
for (_, mem) in &module.memories {
|
||||
@ -59,7 +69,10 @@ impl LocalBacking {
|
||||
memories.into_boxed_slice()
|
||||
}
|
||||
|
||||
fn finalize_memories(module: &Module, memories: &mut [LinearMemory]) -> Box<[vm::LocalMemory]> {
|
||||
fn finalize_memories(
|
||||
module: &ModuleInner,
|
||||
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());
|
||||
@ -82,7 +95,7 @@ impl LocalBacking {
|
||||
.into_boxed_slice()
|
||||
}
|
||||
|
||||
fn generate_tables(module: &Module) -> Box<[TableBacking]> {
|
||||
fn generate_tables(module: &ModuleInner) -> Box<[TableBacking]> {
|
||||
let mut tables = Vec::with_capacity(module.tables.len());
|
||||
|
||||
for (_, table) in &module.tables {
|
||||
@ -94,7 +107,7 @@ impl LocalBacking {
|
||||
}
|
||||
|
||||
fn finalize_tables(
|
||||
module: &Module,
|
||||
module: &ModuleInner,
|
||||
imports: &ImportBacking,
|
||||
tables: &mut [TableBacking],
|
||||
vmctx: *mut vm::Ctx,
|
||||
@ -134,14 +147,14 @@ impl LocalBacking {
|
||||
.into_boxed_slice()
|
||||
}
|
||||
|
||||
fn generate_globals(module: &Module) -> Box<[vm::LocalGlobal]> {
|
||||
fn generate_globals(module: &ModuleInner) -> Box<[vm::LocalGlobal]> {
|
||||
let globals = vec![vm::LocalGlobal::null(); module.globals.len()];
|
||||
|
||||
globals.into_boxed_slice()
|
||||
}
|
||||
|
||||
fn finalize_globals(
|
||||
module: &Module,
|
||||
module: &ModuleInner,
|
||||
imports: &ImportBacking,
|
||||
mut globals: Box<[vm::LocalGlobal]>,
|
||||
) -> Box<[vm::LocalGlobal]> {
|
||||
@ -171,8 +184,8 @@ pub struct ImportBacking {
|
||||
|
||||
impl ImportBacking {
|
||||
pub fn new(
|
||||
module: &Module,
|
||||
imports: &dyn ImportResolver,
|
||||
module: &ModuleInner,
|
||||
imports: &Imports,
|
||||
vmctx: *mut vm::Ctx,
|
||||
) -> Result<Self, String> {
|
||||
assert!(
|
||||
@ -190,15 +203,17 @@ impl ImportBacking {
|
||||
}
|
||||
|
||||
fn import_memories(
|
||||
module: &Module,
|
||||
imports: &dyn ImportResolver,
|
||||
module: &ModuleInner,
|
||||
imports: &Imports,
|
||||
vmctx: *mut vm::Ctx,
|
||||
) -> Result<Box<[vm::ImportedMemory]>, String> {
|
||||
let mut memories = Vec::with_capacity(module.imported_memories.len());
|
||||
for (_index, (ImportName { namespace, name }, expected_memory_desc)) in
|
||||
&module.imported_memories
|
||||
{
|
||||
let memory_import = imports.get(namespace, name);
|
||||
let memory_import = imports
|
||||
.get_namespace(namespace)
|
||||
.and_then(|namespace| namespace.get_export(name));
|
||||
match memory_import {
|
||||
Some(Export::Memory {
|
||||
local,
|
||||
@ -232,15 +247,17 @@ fn import_memories(
|
||||
}
|
||||
|
||||
fn import_functions(
|
||||
module: &Module,
|
||||
imports: &dyn ImportResolver,
|
||||
module: &ModuleInner,
|
||||
imports: &Imports,
|
||||
vmctx: *mut vm::Ctx,
|
||||
) -> Result<Box<[vm::ImportedFunc]>, String> {
|
||||
let mut functions = Vec::with_capacity(module.imported_functions.len());
|
||||
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(namespace, name);
|
||||
let import = imports
|
||||
.get_namespace(namespace)
|
||||
.and_then(|namespace| namespace.get_export(name));
|
||||
match import {
|
||||
Some(Export::Function {
|
||||
func,
|
||||
@ -274,12 +291,14 @@ fn import_functions(
|
||||
}
|
||||
|
||||
fn import_globals(
|
||||
module: &Module,
|
||||
imports: &dyn ImportResolver,
|
||||
module: &ModuleInner,
|
||||
imports: &Imports,
|
||||
) -> Result<Box<[vm::ImportedGlobal]>, String> {
|
||||
let mut globals = Vec::with_capacity(module.imported_globals.len());
|
||||
for (_, (ImportName { namespace, name }, global_desc)) in &module.imported_globals {
|
||||
let import = imports.get(namespace, name);
|
||||
let import = imports
|
||||
.get_namespace(namespace)
|
||||
.and_then(|namespace| namespace.get_export(name));
|
||||
match import {
|
||||
Some(Export::Global { local, global }) => {
|
||||
if &global == global_desc {
|
||||
|
@ -1,10 +1,6 @@
|
||||
use crate::export::Export;
|
||||
use hashbrown::{hash_map::Entry, HashMap};
|
||||
|
||||
pub trait ImportResolver {
|
||||
fn get(&self, namespace: &str, name: &str) -> Option<Export>;
|
||||
}
|
||||
|
||||
pub trait Namespace {
|
||||
fn get_export(&self, name: &str) -> Option<Export>;
|
||||
}
|
||||
@ -31,11 +27,11 @@ impl Imports {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn register(
|
||||
&mut self,
|
||||
name: impl Into<String>,
|
||||
namespace: impl Namespace + 'static,
|
||||
) -> Option<Box<dyn Namespace>> {
|
||||
pub fn register<S, N>(&mut self, name: S, namespace: N) -> Option<Box<dyn Namespace>>
|
||||
where
|
||||
S: Into<String>,
|
||||
N: Namespace + 'static,
|
||||
{
|
||||
match self.map.entry(name.into()) {
|
||||
Entry::Vacant(empty) => {
|
||||
empty.insert(Box::new(namespace));
|
||||
@ -45,36 +41,7 @@ impl Imports {
|
||||
}
|
||||
}
|
||||
|
||||
// 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_name: &str, name: &str) -> Option<Export> {
|
||||
let namespace = self.map.get(namespace_name)?;
|
||||
namespace.get_export(name)
|
||||
pub fn get_namespace(&self, namespace: &str) -> Option<&dyn Namespace> {
|
||||
self.map.get(namespace).map(|namespace| &**namespace)
|
||||
}
|
||||
}
|
||||
|
@ -2,8 +2,8 @@ use crate::recovery::call_protected;
|
||||
use crate::{
|
||||
backing::{ImportBacking, LocalBacking},
|
||||
export::{Context, Export, ExportIter, FuncPointer, MemoryPointer},
|
||||
import::{ImportResolver, Namespace},
|
||||
module::{ExportIndex, Module},
|
||||
import::{Imports, Namespace},
|
||||
module::{ExportIndex, Module, ModuleInner},
|
||||
types::{FuncIndex, FuncSig, MapIndex, Memory, MemoryIndex, Type, Value},
|
||||
vm,
|
||||
};
|
||||
@ -14,19 +14,17 @@ use std::{iter, mem};
|
||||
struct InstanceInner {
|
||||
#[allow(dead_code)]
|
||||
pub(crate) backing: LocalBacking,
|
||||
#[allow(dead_code)]
|
||||
imports: Rc<dyn ImportResolver>,
|
||||
import_backing: ImportBacking,
|
||||
vmctx: Box<vm::Ctx>,
|
||||
}
|
||||
|
||||
pub struct Instance {
|
||||
pub module: Module,
|
||||
pub(crate) module: Rc<ModuleInner>,
|
||||
inner: Box<InstanceInner>,
|
||||
}
|
||||
|
||||
impl Instance {
|
||||
pub(crate) fn new(module: Module, imports: Rc<dyn ImportResolver>) -> Result<Instance, String> {
|
||||
pub(crate) fn new(module: Rc<ModuleInner>, imports: &Imports) -> Result<Instance, String> {
|
||||
// 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.
|
||||
@ -38,16 +36,13 @@ impl Instance {
|
||||
// When Pin is stablized, this will use `Box::pinned` instead of `Box::new`.
|
||||
let mut inner = Box::new(InstanceInner {
|
||||
backing,
|
||||
imports,
|
||||
import_backing,
|
||||
vmctx,
|
||||
});
|
||||
|
||||
// Initialize the vm::Ctx in-place after the backing
|
||||
// has been boxed.
|
||||
*inner.vmctx = unsafe {
|
||||
vm::Ctx::new(&mut inner.backing, &mut inner.import_backing)
|
||||
};
|
||||
*inner.vmctx = unsafe { vm::Ctx::new(&mut inner.backing, &mut inner.import_backing) };
|
||||
|
||||
let mut instance = Instance { module, inner };
|
||||
|
||||
@ -83,6 +78,10 @@ impl Instance {
|
||||
pub fn exports(&self) -> ExportIter {
|
||||
ExportIter::new(self)
|
||||
}
|
||||
|
||||
pub fn module(&self) -> Module {
|
||||
Module::new(Rc::clone(&self.module))
|
||||
}
|
||||
}
|
||||
|
||||
impl Instance {
|
||||
|
@ -4,6 +4,7 @@ extern crate field_offset;
|
||||
|
||||
#[macro_use]
|
||||
mod macros;
|
||||
#[doc(hidden)]
|
||||
pub mod backend;
|
||||
mod backing;
|
||||
pub mod export;
|
||||
@ -18,11 +19,17 @@ mod sighandler;
|
||||
pub mod table;
|
||||
pub mod types;
|
||||
pub mod vm;
|
||||
#[doc(hidden)]
|
||||
pub mod vmcalls;
|
||||
|
||||
pub use self::instance::Instance;
|
||||
#[doc(inline)]
|
||||
pub use self::module::Module;
|
||||
use std::rc::Rc;
|
||||
|
||||
/// Compile a webassembly module using the provided compiler.
|
||||
pub fn compile(wasm: &[u8], compiler: &dyn backend::Compiler) -> Result<module::Module, String> {
|
||||
compiler.compile(wasm)
|
||||
compiler
|
||||
.compile(wasm)
|
||||
.map(|inner| module::Module::new(Rc::new(inner)))
|
||||
}
|
||||
|
@ -1,8 +1,3 @@
|
||||
//! The webassembly::Memory() constructor creates a new Memory object which is
|
||||
//! a structure that holds the raw bytes of memory accessed by a
|
||||
//! webassembly::Instance.
|
||||
//! A memory created by Rust or in WebAssembly code will be accessible and
|
||||
//! mutable from both Rust and WebAssembly.
|
||||
use std::ops::{Deref, DerefMut};
|
||||
|
||||
use crate::{
|
||||
@ -40,7 +35,9 @@ pub struct LinearMemory {
|
||||
impl LinearMemory {
|
||||
pub(crate) const PAGE_SIZE: u32 = 65_536;
|
||||
pub(crate) const MAX_PAGES: u32 = 65_536;
|
||||
#[doc(hidden)]
|
||||
pub const DEFAULT_HEAP_SIZE: usize = 1 << 32; // 4 GiB
|
||||
#[doc(hidden)]
|
||||
pub const DEFAULT_GUARD_SIZE: usize = 1 << 31; // 2 GiB
|
||||
pub(crate) const DEFAULT_SIZE: usize = Self::DEFAULT_HEAP_SIZE + Self::DEFAULT_GUARD_SIZE; // 6 GiB
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
use crate::{
|
||||
backend::FuncResolver,
|
||||
import::ImportResolver,
|
||||
import::Imports,
|
||||
sig_registry::SigRegistry,
|
||||
types::{
|
||||
FuncIndex, Global, GlobalDesc, GlobalIndex, Map, MapIndex, Memory, MemoryIndex, SigIndex,
|
||||
@ -9,10 +9,10 @@ use crate::{
|
||||
Instance,
|
||||
};
|
||||
use hashbrown::HashMap;
|
||||
use std::ops::Deref;
|
||||
use std::rc::Rc;
|
||||
|
||||
/// This is used to instantiate a new webassembly module.
|
||||
#[doc(hidden)]
|
||||
pub struct ModuleInner {
|
||||
pub func_resolver: Box<dyn FuncResolver>,
|
||||
pub memories: Map<MemoryIndex, Memory>,
|
||||
@ -37,14 +37,13 @@ pub struct ModuleInner {
|
||||
pub struct Module(Rc<ModuleInner>);
|
||||
|
||||
impl Module {
|
||||
#[inline]
|
||||
pub fn new(inner: ModuleInner) -> Self {
|
||||
Module(Rc::new(inner))
|
||||
pub(crate) fn new(inner: Rc<ModuleInner>) -> Self {
|
||||
Module(inner)
|
||||
}
|
||||
|
||||
/// Instantiate a webassembly module with the provided imports.
|
||||
pub fn instantiate(&self, imports: Rc<dyn ImportResolver>) -> Result<Instance, String> {
|
||||
Instance::new(Module(Rc::clone(&self.0)), imports)
|
||||
pub fn instantiate(&self, imports: &Imports) -> Result<Instance, String> {
|
||||
Instance::new(Rc::clone(&self.0), imports)
|
||||
}
|
||||
}
|
||||
|
||||
@ -58,14 +57,7 @@ impl ModuleInner {
|
||||
}
|
||||
}
|
||||
|
||||
impl Deref for Module {
|
||||
type Target = ModuleInner;
|
||||
|
||||
fn deref(&self) -> &ModuleInner {
|
||||
&*self.0
|
||||
}
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct ImportName {
|
||||
pub namespace: String,
|
||||
|
@ -1,36 +1,40 @@
|
||||
use crate::backing::{ImportBacking, LocalBacking};
|
||||
use crate::backing::ImportBacking;
|
||||
pub use crate::backing::LocalBacking;
|
||||
use std::{mem, ptr};
|
||||
|
||||
#[derive(Debug)]
|
||||
#[repr(C)]
|
||||
pub struct Ctx {
|
||||
/// A pointer to an array of locally-defined memories, indexed by `MemoryIndex`.
|
||||
pub memories: *mut LocalMemory,
|
||||
pub(crate) memories: *mut LocalMemory,
|
||||
|
||||
/// A pointer to an array of locally-defined tables, indexed by `TableIndex`.
|
||||
pub tables: *mut LocalTable,
|
||||
pub(crate) tables: *mut LocalTable,
|
||||
|
||||
/// A pointer to an array of locally-defined globals, indexed by `GlobalIndex`.
|
||||
pub globals: *mut LocalGlobal,
|
||||
pub(crate) globals: *mut LocalGlobal,
|
||||
|
||||
/// A pointer to an array of imported memories, indexed by `MemoryIndex,
|
||||
pub imported_memories: *mut ImportedMemory,
|
||||
pub(crate) imported_memories: *mut ImportedMemory,
|
||||
|
||||
/// A pointer to an array of imported tables, indexed by `TableIndex`.
|
||||
pub imported_tables: *mut ImportedTable,
|
||||
pub(crate) imported_tables: *mut ImportedTable,
|
||||
|
||||
/// A pointer to an array of imported globals, indexed by `GlobalIndex`.
|
||||
pub imported_globals: *mut ImportedGlobal,
|
||||
pub(crate) imported_globals: *mut ImportedGlobal,
|
||||
|
||||
/// A pointer to an array of imported functions, indexed by `FuncIndex`.
|
||||
pub imported_funcs: *mut ImportedFunc,
|
||||
pub(crate) imported_funcs: *mut ImportedFunc,
|
||||
|
||||
/// The parent instance.
|
||||
pub local_backing: *mut LocalBacking,
|
||||
}
|
||||
|
||||
impl Ctx {
|
||||
pub unsafe fn new(local_backing: &mut LocalBacking, import_backing: &mut ImportBacking) -> Self {
|
||||
pub unsafe fn new(
|
||||
local_backing: &mut LocalBacking,
|
||||
import_backing: &mut ImportBacking,
|
||||
) -> Self {
|
||||
Self {
|
||||
memories: local_backing.vm_memories.as_mut_ptr(),
|
||||
tables: local_backing.vm_tables.as_mut_ptr(),
|
||||
|
@ -5,7 +5,9 @@ pub unsafe extern "C" fn memory_grow_static(
|
||||
by_pages: u32,
|
||||
ctx: *mut vm::Ctx,
|
||||
) -> i32 {
|
||||
if let Some(old) = (*(*ctx).local_backing).memories[memory_index as usize].grow_static(by_pages)
|
||||
if let Some(old) = (*(*ctx).local_backing)
|
||||
.memory(memory_index)
|
||||
.grow_static(by_pages)
|
||||
{
|
||||
// Store the new size back into the vmctx.
|
||||
(*(*ctx).memories.add(memory_index as usize)).size =
|
||||
@ -17,7 +19,7 @@ pub unsafe extern "C" fn memory_grow_static(
|
||||
}
|
||||
|
||||
pub unsafe extern "C" fn memory_size(memory_index: u32, ctx: *mut vm::Ctx) -> u32 {
|
||||
(*(*ctx).local_backing).memories[memory_index as usize].pages()
|
||||
(*(*ctx).local_backing).memory(memory_index).pages()
|
||||
}
|
||||
|
||||
pub unsafe extern "C" fn memory_grow_dynamic(
|
||||
@ -25,8 +27,9 @@ 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)
|
||||
.memory(memory_index)
|
||||
.grow_dynamic(by_pages)
|
||||
{
|
||||
// Store the new size back into the vmctx.
|
||||
(*(*ctx).memories.add(memory_index as usize)).size =
|
||||
|
Reference in New Issue
Block a user