Support imported functions

This commit is contained in:
Lachlan Sneff
2019-01-08 21:57:28 -05:00
parent 55b7cae523
commit bba168e61e
14 changed files with 265 additions and 151 deletions

View File

@ -1,18 +1,4 @@
use wasmer_runtime::{ use crate::resolver::FuncResolverBuilder;
FuncResolver,
LinearMemory,
ModuleInner as WasmerModule,
SigRegistry,
module::{DataInitializer, Export, ImportName, TableInitializer},
types::{
ElementType as WasmerElementType, FuncIndex as WasmerFuncIndex, FuncSig as WasmerSignature,
Global as WasmerGlobal, GlobalDesc as WasmerGlobalDesc, GlobalIndex as WasmerGlobalIndex,
Initializer as WasmerInitializer, Map, MapIndex, Memory as WasmerMemory,
MemoryIndex as WasmerMemoryIndex, SigIndex as WasmerSignatureIndex, Table as WasmerTable,
TableIndex as WasmerTableIndex, Type as WasmerType,
},
vm::Ctx as WasmerVMContext,
};
use cranelift_codegen::cursor::FuncCursor; use cranelift_codegen::cursor::FuncCursor;
use cranelift_codegen::ir::immediates::{Offset32, Uimm64}; use cranelift_codegen::ir::immediates::{Offset32, Uimm64};
use cranelift_codegen::ir::types::{self, *}; use cranelift_codegen::ir::types::{self, *};
@ -29,7 +15,18 @@ use cranelift_wasm::{
}; };
use hashbrown::HashMap; use hashbrown::HashMap;
use target_lexicon; use target_lexicon;
use crate::resolver::{FuncResolverBuilder}; use wasmer_runtime::{
module::{DataInitializer, Export, ImportName, TableInitializer},
types::{
ElementType as WasmerElementType, FuncIndex as WasmerFuncIndex, FuncSig as WasmerSignature,
Global as WasmerGlobal, GlobalDesc as WasmerGlobalDesc, GlobalIndex as WasmerGlobalIndex,
Initializer as WasmerInitializer, Map, MapIndex, Memory as WasmerMemory,
MemoryIndex as WasmerMemoryIndex, SigIndex as WasmerSignatureIndex, Table as WasmerTable,
TableIndex as WasmerTableIndex, Type as WasmerType,
},
vm::{self, Ctx as WasmerVMContext},
LinearMemory, ModuleInner as WasmerModule, SigRegistry,
};
/// The converter namespace contains functions for converting a Cranelift module /// The converter namespace contains functions for converting a Cranelift module
/// to a Wasmer module. /// to a Wasmer module.
@ -72,8 +69,17 @@ pub mod converter {
func_assoc.push(WasmerSignatureIndex::new(signature_index.index())); func_assoc.push(WasmerSignatureIndex::new(signature_index.index()));
} }
let function_bodies: Vec<_> = cranelift_module.function_bodies.into_iter().map(|(_, v)| v.clone()).collect(); let function_bodies: Vec<_> = cranelift_module
let func_resolver_builder = FuncResolverBuilder::new(&*crate::get_isa(), function_bodies).unwrap(); .function_bodies
.into_iter()
.map(|(_, v)| v.clone())
.collect();
let func_resolver_builder = FuncResolverBuilder::new(
&*crate::get_isa(),
function_bodies,
cranelift_module.imported_functions.len(),
)
.unwrap();
// Create func_resolver. // Create func_resolver.
let func_resolver = Box::new(func_resolver_builder.finalize().unwrap()); let func_resolver = Box::new(func_resolver_builder.finalize().unwrap());
@ -217,9 +223,6 @@ pub struct CraneliftModule {
/// The external function declaration for implementing wasm's `grow_memory`. /// The external function declaration for implementing wasm's `grow_memory`.
pub grow_memory_extfunc: Option<FuncRef>, pub grow_memory_extfunc: Option<FuncRef>,
/// A function that takes a Wasmer module and resolves a function index to a vm::Func.
pub func_resolver: Option<Box<dyn FuncResolver>>,
// An array holding information about the wasm instance memories. // An array holding information about the wasm instance memories.
pub memories: Vec<Memory>, pub memories: Vec<Memory>,
@ -271,7 +274,6 @@ impl CraneliftModule {
memories_base: None, memories_base: None,
current_memory_extfunc: None, current_memory_extfunc: None,
grow_memory_extfunc: None, grow_memory_extfunc: None,
func_resolver: None,
memories: Vec::new(), memories: Vec::new(),
globals: Vec::new(), globals: Vec::new(),
tables: Vec::new(), tables: Vec::new(),
@ -286,8 +288,7 @@ impl CraneliftModule {
}; };
// Translate wasm to cranelift IR. // Translate wasm to cranelift IR.
translate_module(&buffer_source, &mut cranelift_module) translate_module(&buffer_source, &mut cranelift_module).map_err(|e| e.to_string())?;
.map_err(|e| e.to_string())?;
// Return translated module. // Return translated module.
Ok(cranelift_module) Ok(cranelift_module)
@ -560,12 +561,68 @@ impl<'environment> FuncEnvironmentTrait for FuncEnvironment<'environment> {
fn translate_call( fn translate_call(
&mut self, &mut self,
mut pos: FuncCursor, mut pos: FuncCursor,
_callee_index: FuncIndex, callee_index: FuncIndex,
callee: ir::FuncRef, callee: ir::FuncRef,
call_args: &[ir::Value], call_args: &[ir::Value],
) -> WasmResult<ir::Inst> { ) -> WasmResult<ir::Inst> {
// Insert call instructions for `callee`. // Insert call instructions for `callee`.
Ok(pos.ins().call(callee, call_args))
if callee_index.index() < self.module.imported_functions.len() {
// this is an imported function
let vmctx = pos.func.create_global_value(ir::GlobalValueData::VMContext);
let imported_funcs = pos.func.create_global_value(ir::GlobalValueData::Load {
base: vmctx,
offset: (WasmerVMContext::offset_imported_funcs() as i32).into(),
global_type: self.pointer_type(),
readonly: true,
});
let imported_func_struct_addr =
pos.func.create_global_value(ir::GlobalValueData::IAddImm {
base: imported_funcs,
offset: (callee_index.index() as i64 * vm::ImportedFunc::size() as i64).into(),
global_type: self.pointer_type(),
});
let imported_func_addr = pos.func.create_global_value(ir::GlobalValueData::Load {
base: imported_func_struct_addr,
offset: (vm::ImportedFunc::offset_func() as i32).into(),
global_type: self.pointer_type(),
readonly: true,
});
let imported_func_addr = pos
.ins()
.global_value(self.pointer_type(), imported_func_addr);
let sig_ref = pos.func.dfg.ext_funcs[callee].signature;
let vmctx = pos
.func
.special_param(ir::ArgumentPurpose::VMContext)
.expect("missing vmctx parameter");
let mut args = Vec::with_capacity(call_args.len() + 1);
args.extend(call_args.iter().cloned());
args.push(vmctx);
Ok(pos
.ins()
.call_indirect(sig_ref, imported_func_addr, &args[..]))
} else {
// this is an internal function
let vmctx = pos
.func
.special_param(ir::ArgumentPurpose::VMContext)
.expect("missing vmctx parameter");
let mut args = Vec::with_capacity(call_args.len() + 1);
args.extend(call_args.iter().cloned());
args.push(vmctx);
Ok(pos.ins().call(callee, &args[..]))
}
} }
/// Generates code corresponding to wasm `memory.grow`. /// Generates code corresponding to wasm `memory.grow`.

View File

@ -3,13 +3,16 @@ mod libcalls;
mod relocation; mod relocation;
mod resolver; mod resolver;
use wasmer_runtime::{Compiler, Module}; use cranelift_codegen::{
use cranelift_codegen::{settings::{self, Configurable}, isa}; isa,
settings::{self, Configurable},
};
use target_lexicon::Triple; use target_lexicon::Triple;
use wasmer_runtime::{Compiler, Module};
use wasmparser::{self, WasmDecoder}; use wasmparser::{self, WasmDecoder};
use self::codegen::CraneliftModule;
use self::codegen::converter; use self::codegen::converter;
use self::codegen::CraneliftModule;
pub struct CraneliftCompiler {} pub struct CraneliftCompiler {}
@ -59,10 +62,7 @@ fn validate(bytes: &[u8]) -> Result<(), String> {
match *state { match *state {
wasmparser::ParserState::EndWasm => return Ok(()), wasmparser::ParserState::EndWasm => return Ok(()),
wasmparser::ParserState::Error(err) => { wasmparser::ParserState::Error(err) => {
return Err(format!( return Err(format!("Validation error: {}", err.message));
"Validation error: {}",
err.message
));
} }
_ => (), _ => (),
} }

View File

@ -1,19 +1,14 @@
use cranelift_codegen::{ use crate::libcalls;
ir, use crate::relocation::{Reloc, RelocSink, Relocation, RelocationType, TrapSink};
isa, use cranelift_codegen::{ir, isa, Context};
Context, use std::mem;
}; use std::ptr::{write_unaligned, NonNull};
use wasmer_runtime::{ use wasmer_runtime::{
self, self,
types::{Map, MapIndex, FuncIndex},
mmap::{Mmap, Protect}, mmap::{Mmap, Protect},
vm, types::{FuncIndex, Map, MapIndex},
vmcalls, vm, vmcalls,
}; };
use crate::relocation::{Reloc, RelocSink, Relocation, RelocationType, TrapSink};
use crate::libcalls;
use std::ptr::{write_unaligned, NonNull};
use std::mem;
#[allow(dead_code)] #[allow(dead_code)]
pub struct FuncResolverBuilder { pub struct FuncResolverBuilder {
@ -23,7 +18,11 @@ pub struct FuncResolverBuilder {
} }
impl FuncResolverBuilder { impl FuncResolverBuilder {
pub fn new(isa: &isa::TargetIsa, function_bodies: Vec<ir::Function>) -> Result<Self, String> { pub fn new(
isa: &isa::TargetIsa,
function_bodies: Vec<ir::Function>,
num_imported_funcs: usize,
) -> Result<Self, String> {
let mut compiled_functions: Vec<Vec<u8>> = Vec::with_capacity(function_bodies.len()); let mut compiled_functions: Vec<Vec<u8>> = Vec::with_capacity(function_bodies.len());
let mut relocations = Map::with_capacity(function_bodies.len()); let mut relocations = Map::with_capacity(function_bodies.len());
let mut trap_sinks = Map::with_capacity(function_bodies.len()); let mut trap_sinks = Map::with_capacity(function_bodies.len());
@ -37,11 +36,8 @@ impl FuncResolverBuilder {
let mut reloc_sink = RelocSink::new(); let mut reloc_sink = RelocSink::new();
let mut trap_sink = TrapSink::new(); let mut trap_sink = TrapSink::new();
ctx ctx.compile_and_emit(isa, &mut code_buf, &mut reloc_sink, &mut trap_sink)
.compile_and_emit(isa, &mut code_buf, &mut reloc_sink, &mut trap_sink) .map_err(|e| format!("compile error: {}", e.to_string()))?;
.map_err(|e| {
format!("compile error: {}", e.to_string())
})?;
ctx.clear(); ctx.clear();
// Round up each function's size to pointer alignment. // Round up each function's size to pointer alignment.
total_size += round_up(code_buf.len(), mem::size_of::<usize>()); total_size += round_up(code_buf.len(), mem::size_of::<usize>());
@ -62,7 +58,8 @@ impl FuncResolverBuilder {
for compiled in compiled_functions.iter() { for compiled in compiled_functions.iter() {
let new_end = previous_end + round_up(compiled.len(), mem::size_of::<usize>()); let new_end = previous_end + round_up(compiled.len(), mem::size_of::<usize>());
unsafe { unsafe {
memory.as_slice_mut()[previous_end..previous_end + compiled.len()].copy_from_slice(&compiled[..]); memory.as_slice_mut()[previous_end..previous_end + compiled.len()]
.copy_from_slice(&compiled[..]);
} }
map.push(previous_end); map.push(previous_end);
previous_end = new_end; previous_end = new_end;
@ -70,6 +67,7 @@ impl FuncResolverBuilder {
Ok(Self { Ok(Self {
resolver: FuncResolver { resolver: FuncResolver {
num_imported_funcs,
map, map,
memory, memory,
}, },
@ -86,7 +84,10 @@ impl FuncResolverBuilder {
// This will always be an internal function // This will always be an internal function
// because imported functions are not // because imported functions are not
// called in this way. // called in this way.
self.resolver.lookup(FuncIndex::new(func_index as _)).unwrap().as_ptr() as isize self.resolver
.lookup(FuncIndex::new(func_index as _))
.unwrap()
.as_ptr() as isize
} }
RelocationType::CurrentMemory => vmcalls::memory_size as isize, RelocationType::CurrentMemory => vmcalls::memory_size as isize,
RelocationType::GrowMemory => vmcalls::memory_grow_static as isize, RelocationType::GrowMemory => vmcalls::memory_grow_static as isize,
@ -135,7 +136,9 @@ impl FuncResolverBuilder {
} }
unsafe { unsafe {
self.resolver.memory.protect(0..self.resolver.memory.size(), Protect::ReadExec)?; self.resolver
.memory
.protect(0..self.resolver.memory.size(), Protect::ReadExec)?;
} }
Ok(self.resolver) Ok(self.resolver)
@ -144,16 +147,17 @@ impl FuncResolverBuilder {
/// Resolves a function index to a function address. /// Resolves a function index to a function address.
pub struct FuncResolver { pub struct FuncResolver {
num_imported_funcs: usize,
map: Map<FuncIndex, usize>, map: Map<FuncIndex, usize>,
memory: Mmap, memory: Mmap,
} }
impl FuncResolver { impl FuncResolver {
fn lookup(&self, index: FuncIndex) -> Option<NonNull<vm::Func>> { fn lookup(&self, index: FuncIndex) -> Option<NonNull<vm::Func>> {
let offset = *self.map.get(index)?; let offset = *self
let ptr = unsafe { .map
self.memory.as_ptr().add(offset) .get(FuncIndex::new(index.index() - self.num_imported_funcs))?;
}; let ptr = unsafe { self.memory.as_ptr().add(offset) };
NonNull::new(ptr).map(|nonnull| nonnull.cast()) NonNull::new(ptr).map(|nonnull| nonnull.cast())
} }

View File

@ -1,13 +1,38 @@
use wasmer_runtime as runtime;
use wasmer_clif_backend::CraneliftCompiler; use wasmer_clif_backend::CraneliftCompiler;
use wasmer_runtime::{
self as runtime,
types::{FuncSig, Type, Value},
vm, Import, Imports,
};
static EXAMPLE_WASM: &'static [u8] = include_bytes!("simple.wasm"); static EXAMPLE_WASM: &'static [u8] = include_bytes!("simple.wasm");
fn main() { fn main() -> Result<(), String> {
let compiler = CraneliftCompiler::new(); let module = runtime::compile(EXAMPLE_WASM, &CraneliftCompiler::new())?;
let module = runtime::compile(EXAMPLE_WASM, &compiler).unwrap();
let imports = runtime::Imports::new(); let mut imports = Imports::new();
let mut instance = module.instantiate(&imports).unwrap(); imports.add(
let ret = instance.call("main", &[runtime::types::Value::I32(42)]); "env".to_string(),
"print_num".to_string(),
Import::Func(
print_num as _,
FuncSig {
params: vec![Type::I32],
returns: vec![Type::I32],
},
),
);
let mut instance = module.instantiate(&imports)?;
let ret = instance.call("main", &[Value::I32(42)])?;
println!("ret: {:?}", ret); println!("ret: {:?}", ret);
Ok(())
}
extern "C" fn print_num(n: i32, _vmctx: *mut vm::Ctx) -> i32 {
println!("print_num({})", n);
n + 1
} }

View File

@ -108,7 +108,6 @@ impl LocalBacking {
match table.elements { match table.elements {
TableElements::Anyfunc(ref mut elements) => { TableElements::Anyfunc(ref mut elements) => {
for (i, &func_index) in init.elements.iter().enumerate() { for (i, &func_index) in init.elements.iter().enumerate() {
let sig_index = module.func_assoc[func_index]; let sig_index = module.func_assoc[func_index];
let vm_sig_id = vm::SigId(sig_index.index() as u32); let vm_sig_id = vm::SigId(sig_index.index() as u32);
@ -263,7 +262,8 @@ impl ImportBacking {
let sig_index = module.func_assoc[index]; let sig_index = module.func_assoc[index];
let expected_sig = module.sig_registry.lookup_func_sig(sig_index); let expected_sig = module.sig_registry.lookup_func_sig(sig_index);
let import = imports.get(mod_name, item_name); let import = imports.get(mod_name, item_name);
if let Some(&Import::Func(func, ref signature)) = import { match import {
Some(&Import::Func(func, ref signature)) => {
if expected_sig == signature { if expected_sig == signature {
functions.push(vm::ImportedFunc { functions.push(vm::ImportedFunc {
func, func,
@ -275,8 +275,16 @@ impl ImportBacking {
mod_name, item_name mod_name, item_name
)); ));
} }
} else { }
return Err(format!("incorrect type for {:?}:{:?}", mod_name, item_name)); Some(_) => {
return Err(format!(
"incorrect import type for {}:{}",
mod_name, item_name
));
}
None => {
return Err(format!("import not found: {}:{}", mod_name, item_name));
}
} }
} }
@ -293,15 +301,16 @@ impl ImportBacking {
) in &module.imported_globals ) in &module.imported_globals
{ {
let import = imports.get(mod_name, item_name); let import = imports.get(mod_name, item_name);
if let Some(&Import::Global(val)) = import { match import {
Some(Import::Global(val)) => {
if val.ty() == global_desc.ty { if val.ty() == global_desc.ty {
globals.push(vm::ImportedGlobal { globals.push(vm::ImportedGlobal {
global: vm::LocalGlobal { global: vm::LocalGlobal {
data: match val { data: match val {
Value::I32(n) => n as u64, Value::I32(n) => *n as u64,
Value::I64(n) => n as u64, Value::I64(n) => *n as u64,
Value::F32(n) => n as u64, Value::F32(n) => *n as u64,
Value::F64(n) => n, Value::F64(n) => *n,
}, },
}, },
}); });
@ -311,8 +320,16 @@ impl ImportBacking {
mod_name, item_name mod_name, item_name
)); ));
} }
} else { }
return Err(format!("incorrect type for {:?}:{:?}", mod_name, item_name)); Some(_) => {
return Err(format!(
"incorrect import type for {}:{}",
mod_name, item_name
));
}
None => {
return Err(format!("import not found: {}:{}", mod_name, item_name));
}
} }
} }

View File

@ -19,7 +19,10 @@ pub struct Instance {
} }
impl Instance { impl Instance {
pub(crate) fn new(module: Module, imports: &dyn ImportResolver) -> Result<Box<Instance>, String> { pub(crate) fn new(
module: Module,
imports: &dyn ImportResolver,
) -> Result<Box<Instance>, String> {
let import_backing = ImportBacking::new(&module, imports)?; let import_backing = ImportBacking::new(&module, imports)?;
let backing = LocalBacking::new(&module, &import_backing); let backing = LocalBacking::new(&module, &import_backing);
@ -85,10 +88,7 @@ impl Instance {
// the vmctx will be located at the same place on the stack the entire time that this // the vmctx will be located at the same place on the stack the entire time that this
// wasm function is running. // wasm function is running.
let mut vmctx = vm::Ctx::new( let mut vmctx = vm::Ctx::new(&mut self.backing, &mut self.import_backing);
&mut self.backing,
&mut self.import_backing,
);
let vmctx_ptr = &mut vmctx as *mut vm::Ctx; let vmctx_ptr = &mut vmctx as *mut vm::Ctx;
let libffi_args: Vec<_> = args let libffi_args: Vec<_> = args
@ -102,15 +102,19 @@ impl Instance {
.chain(iter::once(libffi_arg(&vmctx_ptr))) .chain(iter::once(libffi_arg(&vmctx_ptr)))
.collect(); .collect();
let func_ptr = CodePtr::from_ptr(self.module let func_ptr = CodePtr::from_ptr(
self.module
.func_resolver .func_resolver
.get(&self.module, func_index) .get(&self.module, func_index)
.expect("broken invariant, func resolver not synced with module.exports") .expect("broken invariant, func resolver not synced with module.exports")
.cast() .cast()
.as_ptr()); .as_ptr(),
);
call_protected(|| { call_protected(|| {
self.module.sig_registry.lookup_func_sig(sig_index) self.module
.sig_registry
.lookup_func_sig(sig_index)
.returns .returns
.first() .first()
.map(|ty| match ty { .map(|ty| match ty {

View File

@ -4,26 +4,23 @@ mod backend;
mod backing; mod backing;
mod instance; mod instance;
mod memory; mod memory;
mod sig_registry;
mod table;
mod recovery;
mod sighandler;
pub mod mmap; pub mod mmap;
pub mod module; pub mod module;
mod recovery;
mod sig_registry;
mod sighandler;
mod table;
pub mod types; pub mod types;
pub mod vm; pub mod vm;
pub mod vmcalls; pub mod vmcalls;
pub use self::backend::{Compiler, FuncResolver}; pub use self::backend::{Compiler, FuncResolver};
pub use self::instance::{Import, ImportResolver, Imports, Instance}; pub use self::instance::{Import, ImportResolver, Imports, Instance};
pub use self::memory::LinearMemory;
pub use self::module::{Module, ModuleInner}; pub use self::module::{Module, ModuleInner};
pub use self::sig_registry::SigRegistry; pub use self::sig_registry::SigRegistry;
pub use self::memory::LinearMemory;
/// Compile a webassembly module using the provided compiler. /// Compile a webassembly module using the provided compiler.
pub fn compile( pub fn compile(wasm: &[u8], compiler: &dyn Compiler) -> Result<Module, String> {
wasm: &[u8],
compiler: &dyn Compiler,
) -> Result<Module, String> {
compiler.compile(wasm) compiler.compile(wasm)
} }

View File

@ -5,7 +5,11 @@
//! mutable from both Rust and WebAssembly. //! mutable from both Rust and WebAssembly.
use std::ops::{Deref, DerefMut}; use std::ops::{Deref, DerefMut};
use crate::{types::Memory, vm::LocalMemory, mmap::{Mmap, Protect}}; use crate::{
mmap::{Mmap, Protect},
types::Memory,
vm::LocalMemory,
};
/// A linear memory instance. /// A linear memory instance.
#[derive(Debug)] #[derive(Debug)]
@ -69,7 +73,10 @@ impl LinearMemory {
// map initial pages as readwrite since the inital mmap is mapped as not accessible. // map initial pages as readwrite since the inital mmap is mapped as not accessible.
if initial_pages != 0 { if initial_pages != 0 {
unsafe { unsafe {
mmap.protect(0..(initial_pages as usize * Self::PAGE_SIZE as usize), Protect::ReadWrite) mmap.protect(
0..(initial_pages as usize * Self::PAGE_SIZE as usize),
Protect::ReadWrite,
)
.expect("unable to make memory accessible"); .expect("unable to make memory accessible");
} }
} }
@ -191,7 +198,9 @@ impl LinearMemory {
let new_bytes = (new_pages * Self::PAGE_SIZE) as usize; let new_bytes = (new_pages * Self::PAGE_SIZE) as usize;
unsafe { unsafe {
self.mmap.protect(prev_bytes..new_bytes, Protect::ReadWrite).ok()?; self.mmap
.protect(prev_bytes..new_bytes, Protect::ReadWrite)
.ok()?;
} }
self.current = new_pages; self.current = new_pages;
@ -210,16 +219,12 @@ impl PartialEq for LinearMemory {
impl Deref for LinearMemory { impl Deref for LinearMemory {
type Target = [u8]; type Target = [u8];
fn deref(&self) -> &[u8] { fn deref(&self) -> &[u8] {
unsafe { unsafe { self.mmap.as_slice() }
self.mmap.as_slice()
}
} }
} }
impl DerefMut for LinearMemory { impl DerefMut for LinearMemory {
fn deref_mut(&mut self) -> &mut [u8] { fn deref_mut(&mut self) -> &mut [u8] {
unsafe { unsafe { self.mmap.as_slice_mut() }
self.mmap.as_slice_mut()
}
} }
} }

View File

@ -1,8 +1,8 @@
use std::{slice, ptr}; use errno;
use std::ops::Range;
use nix::libc; use nix::libc;
use page_size; use page_size;
use errno; use std::ops::Range;
use std::{ptr, slice};
#[derive(Debug)] #[derive(Debug)]
pub struct Mmap { pub struct Mmap {
@ -44,7 +44,9 @@ impl Mmap {
pub unsafe fn protect(&mut self, range: Range<usize>, protect: Protect) -> Result<(), String> { pub unsafe fn protect(&mut self, range: Range<usize>, protect: Protect) -> Result<(), String> {
let page_size = page_size::get(); let page_size = page_size::get();
let start = self.ptr.add(round_down_to_page_size(range.start, page_size)); let start = self
.ptr
.add(round_down_to_page_size(range.start, page_size));
let size = round_up_to_page_size(range.end - range.start, page_size); let size = round_up_to_page_size(range.end - range.start, page_size);
assert!(size <= self.size); assert!(size <= self.size);
@ -100,5 +102,5 @@ fn round_up_to_page_size(size: usize, page_size: usize) -> usize {
/// Round `size` down to the nearest multiple of `page_size`. /// Round `size` down to the nearest multiple of `page_size`.
fn round_down_to_page_size(size: usize, page_size: usize) -> usize { fn round_down_to_page_size(size: usize, page_size: usize) -> usize {
size & !(page_size-1) size & !(page_size - 1)
} }

View File

@ -1,16 +1,15 @@
use crate::{ use crate::{
backend::FuncResolver, backend::FuncResolver,
types::{
FuncIndex, Global, GlobalDesc, GlobalIndex, Map, MapIndex, Memory, MemoryIndex,
SigIndex, Table, TableIndex,
},
sig_registry::SigRegistry, sig_registry::SigRegistry,
ImportResolver, types::{
Instance, FuncIndex, Global, GlobalDesc, GlobalIndex, Map, MapIndex, Memory, MemoryIndex, SigIndex,
Table, TableIndex,
},
ImportResolver, Instance,
}; };
use std::sync::Arc;
use std::ops::Deref;
use hashbrown::HashMap; use hashbrown::HashMap;
use std::ops::Deref;
use std::sync::Arc;
/// This is used to instantiate a new webassembly module. /// This is used to instantiate a new webassembly module.
pub struct ModuleInner { pub struct ModuleInner {
@ -62,7 +61,6 @@ impl Deref for Module {
} }
} }
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct ImportName { pub struct ImportName {
pub module: String, pub module: String,

View File

@ -1,5 +1,5 @@
use crate::{ use crate::{
types::{FuncSig, Map, SigIndex, MapIndex}, types::{FuncSig, Map, MapIndex, SigIndex},
vm, vm,
}; };
use hashbrown::HashMap; use hashbrown::HashMap;
@ -20,9 +20,9 @@ impl SigRegistry {
pub fn register(&mut self, func_sig: FuncSig) -> SigIndex { pub fn register(&mut self, func_sig: FuncSig) -> SigIndex {
let func_table = &mut self.func_table; let func_table = &mut self.func_table;
let sig_assoc = &mut self.sig_assoc; let sig_assoc = &mut self.sig_assoc;
*func_table.entry(func_sig.clone()).or_insert_with(|| { *func_table
sig_assoc.push(func_sig) .entry(func_sig.clone())
}) .or_insert_with(|| sig_assoc.push(func_sig))
} }
pub fn lookup_func_sig(&self, sig_index: SigIndex) -> &FuncSig { pub fn lookup_func_sig(&self, sig_index: SigIndex) -> &FuncSig {
@ -30,7 +30,11 @@ impl SigRegistry {
} }
pub(crate) fn into_vm_sigid(&self) -> Box<[vm::SigId]> { pub(crate) fn into_vm_sigid(&self) -> Box<[vm::SigId]> {
let v: Vec<_> = self.sig_assoc.iter().map(|(sig_index, _)| vm::SigId(sig_index.index() as u32)).collect(); let v: Vec<_> = self
.sig_assoc
.iter()
.map(|(sig_index, _)| vm::SigId(sig_index.index() as u32))
.collect();
v.into_boxed_slice() v.into_boxed_slice()
} }
} }

View File

@ -17,7 +17,7 @@ pub enum Type {
F64, F64,
} }
#[derive(Debug, Clone, Copy, PartialEq, Eq)] #[derive(Debug, Clone, PartialEq, Eq)]
pub enum Value { pub enum Value {
/// The `i32` type. /// The `i32` type.
I32(i32), I32(i32),
@ -83,7 +83,7 @@ pub struct Table {
/// A global value initializer. /// A global value initializer.
/// Overtime, this will be able to represent more and more /// Overtime, this will be able to represent more and more
/// complex expressions. /// complex expressions.
#[derive(Debug, Clone, Copy, PartialEq, Eq)] #[derive(Debug, Clone, PartialEq, Eq)]
pub enum Initializer { pub enum Initializer {
/// Corresponds to a `const.*` instruction. /// Corresponds to a `const.*` instruction.
Const(Value), Const(Value),
@ -98,7 +98,7 @@ pub struct GlobalDesc {
} }
/// A wasm global. /// A wasm global.
#[derive(Debug, Clone, Copy)] #[derive(Debug, Clone)]
pub struct Global { pub struct Global {
pub desc: GlobalDesc, pub desc: GlobalDesc,
pub init: Initializer, pub init: Initializer,

View File

@ -33,10 +33,7 @@ pub struct Ctx {
} }
impl Ctx { impl Ctx {
pub fn new( pub fn new(local_backing: &mut LocalBacking, import_backing: &mut ImportBacking) -> Self {
local_backing: &mut LocalBacking,
import_backing: &mut ImportBacking,
) -> Self {
Self { Self {
memories: local_backing.vm_memories.as_mut_ptr(), memories: local_backing.vm_memories.as_mut_ptr(),
tables: local_backing.vm_tables.as_mut_ptr(), tables: local_backing.vm_tables.as_mut_ptr(),
@ -101,6 +98,10 @@ impl ImportedFunc {
pub fn offset_func() -> u8 { pub fn offset_func() -> u8 {
0 * (mem::size_of::<usize>() as u8) 0 * (mem::size_of::<usize>() as u8)
} }
pub fn size() -> u8 {
mem::size_of::<Self>() as u8
}
} }
/// Definition of a table used by the VM. (obviously) /// Definition of a table used by the VM. (obviously)