mirror of
https://github.com/fluencelabs/wasmer
synced 2025-06-22 13:11:32 +00:00
Support imported functions
This commit is contained in:
@ -1,18 +1,4 @@
|
||||
use wasmer_runtime::{
|
||||
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 crate::resolver::FuncResolverBuilder;
|
||||
use cranelift_codegen::cursor::FuncCursor;
|
||||
use cranelift_codegen::ir::immediates::{Offset32, Uimm64};
|
||||
use cranelift_codegen::ir::types::{self, *};
|
||||
@ -29,7 +15,18 @@ use cranelift_wasm::{
|
||||
};
|
||||
use hashbrown::HashMap;
|
||||
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
|
||||
/// to a Wasmer module.
|
||||
@ -72,8 +69,17 @@ pub mod converter {
|
||||
func_assoc.push(WasmerSignatureIndex::new(signature_index.index()));
|
||||
}
|
||||
|
||||
let function_bodies: Vec<_> = cranelift_module.function_bodies.into_iter().map(|(_, v)| v.clone()).collect();
|
||||
let func_resolver_builder = FuncResolverBuilder::new(&*crate::get_isa(), function_bodies).unwrap();
|
||||
let function_bodies: Vec<_> = cranelift_module
|
||||
.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.
|
||||
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`.
|
||||
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.
|
||||
pub memories: Vec<Memory>,
|
||||
|
||||
@ -271,7 +274,6 @@ impl CraneliftModule {
|
||||
memories_base: None,
|
||||
current_memory_extfunc: None,
|
||||
grow_memory_extfunc: None,
|
||||
func_resolver: None,
|
||||
memories: Vec::new(),
|
||||
globals: Vec::new(),
|
||||
tables: Vec::new(),
|
||||
@ -286,8 +288,7 @@ impl CraneliftModule {
|
||||
};
|
||||
|
||||
// Translate wasm to cranelift IR.
|
||||
translate_module(&buffer_source, &mut cranelift_module)
|
||||
.map_err(|e| e.to_string())?;
|
||||
translate_module(&buffer_source, &mut cranelift_module).map_err(|e| e.to_string())?;
|
||||
|
||||
// Return translated module.
|
||||
Ok(cranelift_module)
|
||||
@ -560,12 +561,68 @@ impl<'environment> FuncEnvironmentTrait for FuncEnvironment<'environment> {
|
||||
fn translate_call(
|
||||
&mut self,
|
||||
mut pos: FuncCursor,
|
||||
_callee_index: FuncIndex,
|
||||
callee_index: FuncIndex,
|
||||
callee: ir::FuncRef,
|
||||
call_args: &[ir::Value],
|
||||
) -> WasmResult<ir::Inst> {
|
||||
// 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`.
|
||||
|
@ -3,13 +3,16 @@ mod libcalls;
|
||||
mod relocation;
|
||||
mod resolver;
|
||||
|
||||
use wasmer_runtime::{Compiler, Module};
|
||||
use cranelift_codegen::{settings::{self, Configurable}, isa};
|
||||
use cranelift_codegen::{
|
||||
isa,
|
||||
settings::{self, Configurable},
|
||||
};
|
||||
use target_lexicon::Triple;
|
||||
use wasmer_runtime::{Compiler, Module};
|
||||
use wasmparser::{self, WasmDecoder};
|
||||
|
||||
use self::codegen::CraneliftModule;
|
||||
use self::codegen::converter;
|
||||
use self::codegen::CraneliftModule;
|
||||
|
||||
pub struct CraneliftCompiler {}
|
||||
|
||||
@ -59,10 +62,7 @@ fn validate(bytes: &[u8]) -> Result<(), String> {
|
||||
match *state {
|
||||
wasmparser::ParserState::EndWasm => return Ok(()),
|
||||
wasmparser::ParserState::Error(err) => {
|
||||
return Err(format!(
|
||||
"Validation error: {}",
|
||||
err.message
|
||||
));
|
||||
return Err(format!("Validation error: {}", err.message));
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
|
@ -1,19 +1,14 @@
|
||||
use cranelift_codegen::{
|
||||
ir,
|
||||
isa,
|
||||
Context,
|
||||
};
|
||||
use crate::libcalls;
|
||||
use crate::relocation::{Reloc, RelocSink, Relocation, RelocationType, TrapSink};
|
||||
use cranelift_codegen::{ir, isa, Context};
|
||||
use std::mem;
|
||||
use std::ptr::{write_unaligned, NonNull};
|
||||
use wasmer_runtime::{
|
||||
self,
|
||||
types::{Map, MapIndex, FuncIndex},
|
||||
mmap::{Mmap, Protect},
|
||||
vm,
|
||||
vmcalls,
|
||||
types::{FuncIndex, Map, MapIndex},
|
||||
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)]
|
||||
pub struct FuncResolverBuilder {
|
||||
@ -23,7 +18,11 @@ pub struct 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 relocations = 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 trap_sink = TrapSink::new();
|
||||
|
||||
ctx
|
||||
.compile_and_emit(isa, &mut code_buf, &mut reloc_sink, &mut trap_sink)
|
||||
.map_err(|e| {
|
||||
format!("compile error: {}", e.to_string())
|
||||
})?;
|
||||
ctx.compile_and_emit(isa, &mut code_buf, &mut reloc_sink, &mut trap_sink)
|
||||
.map_err(|e| format!("compile error: {}", e.to_string()))?;
|
||||
ctx.clear();
|
||||
// Round up each function's size to pointer alignment.
|
||||
total_size += round_up(code_buf.len(), mem::size_of::<usize>());
|
||||
@ -62,7 +58,8 @@ impl FuncResolverBuilder {
|
||||
for compiled in compiled_functions.iter() {
|
||||
let new_end = previous_end + round_up(compiled.len(), mem::size_of::<usize>());
|
||||
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);
|
||||
previous_end = new_end;
|
||||
@ -70,6 +67,7 @@ impl FuncResolverBuilder {
|
||||
|
||||
Ok(Self {
|
||||
resolver: FuncResolver {
|
||||
num_imported_funcs,
|
||||
map,
|
||||
memory,
|
||||
},
|
||||
@ -86,7 +84,10 @@ impl FuncResolverBuilder {
|
||||
// This will always be an internal function
|
||||
// because imported functions are not
|
||||
// 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::GrowMemory => vmcalls::memory_grow_static as isize,
|
||||
@ -135,7 +136,9 @@ impl FuncResolverBuilder {
|
||||
}
|
||||
|
||||
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)
|
||||
@ -144,16 +147,17 @@ impl FuncResolverBuilder {
|
||||
|
||||
/// Resolves a function index to a function address.
|
||||
pub struct FuncResolver {
|
||||
num_imported_funcs: usize,
|
||||
map: Map<FuncIndex, usize>,
|
||||
memory: Mmap,
|
||||
}
|
||||
|
||||
impl FuncResolver {
|
||||
fn lookup(&self, index: FuncIndex) -> Option<NonNull<vm::Func>> {
|
||||
let offset = *self.map.get(index)?;
|
||||
let ptr = unsafe {
|
||||
self.memory.as_ptr().add(offset)
|
||||
};
|
||||
let offset = *self
|
||||
.map
|
||||
.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())
|
||||
}
|
||||
|
@ -1,13 +1,38 @@
|
||||
use wasmer_runtime as runtime;
|
||||
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");
|
||||
|
||||
fn main() {
|
||||
let compiler = CraneliftCompiler::new();
|
||||
let module = runtime::compile(EXAMPLE_WASM, &compiler).unwrap();
|
||||
let imports = runtime::Imports::new();
|
||||
let mut instance = module.instantiate(&imports).unwrap();
|
||||
let ret = instance.call("main", &[runtime::types::Value::I32(42)]);
|
||||
fn main() -> Result<(), String> {
|
||||
let module = runtime::compile(EXAMPLE_WASM, &CraneliftCompiler::new())?;
|
||||
|
||||
let mut imports = Imports::new();
|
||||
imports.add(
|
||||
"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);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
extern "C" fn print_num(n: i32, _vmctx: *mut vm::Ctx) -> i32 {
|
||||
println!("print_num({})", n);
|
||||
n + 1
|
||||
}
|
Binary file not shown.
@ -108,7 +108,6 @@ impl LocalBacking {
|
||||
match table.elements {
|
||||
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);
|
||||
|
||||
@ -263,7 +262,8 @@ impl ImportBacking {
|
||||
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);
|
||||
if let Some(&Import::Func(func, ref signature)) = import {
|
||||
match import {
|
||||
Some(&Import::Func(func, ref signature)) => {
|
||||
if expected_sig == signature {
|
||||
functions.push(vm::ImportedFunc {
|
||||
func,
|
||||
@ -275,8 +275,16 @@ impl ImportBacking {
|
||||
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
|
||||
{
|
||||
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 {
|
||||
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 as u64,
|
||||
Value::F64(n) => n,
|
||||
Value::I32(n) => *n as u64,
|
||||
Value::I64(n) => *n as u64,
|
||||
Value::F32(n) => *n as u64,
|
||||
Value::F64(n) => *n,
|
||||
},
|
||||
},
|
||||
});
|
||||
@ -311,8 +320,16 @@ impl ImportBacking {
|
||||
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));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -19,7 +19,10 @@ pub struct 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 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
|
||||
// wasm function is running.
|
||||
let mut vmctx = vm::Ctx::new(
|
||||
&mut self.backing,
|
||||
&mut self.import_backing,
|
||||
);
|
||||
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
|
||||
@ -102,15 +102,19 @@ impl Instance {
|
||||
.chain(iter::once(libffi_arg(&vmctx_ptr)))
|
||||
.collect();
|
||||
|
||||
let func_ptr = CodePtr::from_ptr(self.module
|
||||
let func_ptr = CodePtr::from_ptr(
|
||||
self.module
|
||||
.func_resolver
|
||||
.get(&self.module, func_index)
|
||||
.expect("broken invariant, func resolver not synced with module.exports")
|
||||
.cast()
|
||||
.as_ptr());
|
||||
.as_ptr(),
|
||||
);
|
||||
|
||||
call_protected(|| {
|
||||
self.module.sig_registry.lookup_func_sig(sig_index)
|
||||
self.module
|
||||
.sig_registry
|
||||
.lookup_func_sig(sig_index)
|
||||
.returns
|
||||
.first()
|
||||
.map(|ty| match ty {
|
||||
|
@ -4,26 +4,23 @@ mod backend;
|
||||
mod backing;
|
||||
mod instance;
|
||||
mod memory;
|
||||
mod sig_registry;
|
||||
mod table;
|
||||
mod recovery;
|
||||
mod sighandler;
|
||||
pub mod mmap;
|
||||
pub mod module;
|
||||
mod recovery;
|
||||
mod sig_registry;
|
||||
mod sighandler;
|
||||
mod table;
|
||||
pub mod types;
|
||||
pub mod vm;
|
||||
pub mod vmcalls;
|
||||
|
||||
pub use self::backend::{Compiler, FuncResolver};
|
||||
pub use self::instance::{Import, ImportResolver, Imports, Instance};
|
||||
pub use self::memory::LinearMemory;
|
||||
pub use self::module::{Module, ModuleInner};
|
||||
pub use self::sig_registry::SigRegistry;
|
||||
pub use self::memory::LinearMemory;
|
||||
|
||||
/// Compile a webassembly module using the provided compiler.
|
||||
pub fn compile(
|
||||
wasm: &[u8],
|
||||
compiler: &dyn Compiler,
|
||||
) -> Result<Module, String> {
|
||||
pub fn compile(wasm: &[u8], compiler: &dyn Compiler) -> Result<Module, String> {
|
||||
compiler.compile(wasm)
|
||||
}
|
@ -5,7 +5,11 @@
|
||||
//! mutable from both Rust and WebAssembly.
|
||||
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.
|
||||
#[derive(Debug)]
|
||||
@ -69,7 +73,10 @@ impl LinearMemory {
|
||||
// map initial pages as readwrite since the inital mmap is mapped as not accessible.
|
||||
if initial_pages != 0 {
|
||||
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");
|
||||
}
|
||||
}
|
||||
@ -191,7 +198,9 @@ impl LinearMemory {
|
||||
let new_bytes = (new_pages * Self::PAGE_SIZE) as usize;
|
||||
|
||||
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;
|
||||
@ -210,16 +219,12 @@ impl PartialEq for LinearMemory {
|
||||
impl Deref for LinearMemory {
|
||||
type Target = [u8];
|
||||
fn deref(&self) -> &[u8] {
|
||||
unsafe {
|
||||
self.mmap.as_slice()
|
||||
}
|
||||
unsafe { self.mmap.as_slice() }
|
||||
}
|
||||
}
|
||||
|
||||
impl DerefMut for LinearMemory {
|
||||
fn deref_mut(&mut self) -> &mut [u8] {
|
||||
unsafe {
|
||||
self.mmap.as_slice_mut()
|
||||
}
|
||||
unsafe { self.mmap.as_slice_mut() }
|
||||
}
|
||||
}
|
||||
|
@ -1,8 +1,8 @@
|
||||
use std::{slice, ptr};
|
||||
use std::ops::Range;
|
||||
use errno;
|
||||
use nix::libc;
|
||||
use page_size;
|
||||
use errno;
|
||||
use std::ops::Range;
|
||||
use std::{ptr, slice};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Mmap {
|
||||
@ -44,7 +44,9 @@ impl Mmap {
|
||||
|
||||
pub unsafe fn protect(&mut self, range: Range<usize>, protect: Protect) -> Result<(), String> {
|
||||
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);
|
||||
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`.
|
||||
fn round_down_to_page_size(size: usize, page_size: usize) -> usize {
|
||||
size & !(page_size-1)
|
||||
size & !(page_size - 1)
|
||||
}
|
@ -1,16 +1,15 @@
|
||||
use crate::{
|
||||
backend::FuncResolver,
|
||||
types::{
|
||||
FuncIndex, Global, GlobalDesc, GlobalIndex, Map, MapIndex, Memory, MemoryIndex,
|
||||
SigIndex, Table, TableIndex,
|
||||
},
|
||||
sig_registry::SigRegistry,
|
||||
ImportResolver,
|
||||
Instance,
|
||||
types::{
|
||||
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 std::ops::Deref;
|
||||
use std::sync::Arc;
|
||||
|
||||
/// This is used to instantiate a new webassembly module.
|
||||
pub struct ModuleInner {
|
||||
@ -62,7 +61,6 @@ impl Deref for Module {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct ImportName {
|
||||
pub module: String,
|
||||
|
@ -1,5 +1,5 @@
|
||||
use crate::{
|
||||
types::{FuncSig, Map, SigIndex, MapIndex},
|
||||
types::{FuncSig, Map, MapIndex, SigIndex},
|
||||
vm,
|
||||
};
|
||||
use hashbrown::HashMap;
|
||||
@ -20,9 +20,9 @@ impl SigRegistry {
|
||||
pub fn register(&mut self, func_sig: FuncSig) -> SigIndex {
|
||||
let func_table = &mut self.func_table;
|
||||
let sig_assoc = &mut self.sig_assoc;
|
||||
*func_table.entry(func_sig.clone()).or_insert_with(|| {
|
||||
sig_assoc.push(func_sig)
|
||||
})
|
||||
*func_table
|
||||
.entry(func_sig.clone())
|
||||
.or_insert_with(|| sig_assoc.push(func_sig))
|
||||
}
|
||||
|
||||
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]> {
|
||||
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()
|
||||
}
|
||||
}
|
||||
|
@ -17,7 +17,7 @@ pub enum Type {
|
||||
F64,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub enum Value {
|
||||
/// The `i32` type.
|
||||
I32(i32),
|
||||
@ -83,7 +83,7 @@ pub struct Table {
|
||||
/// A global value initializer.
|
||||
/// Overtime, this will be able to represent more and more
|
||||
/// complex expressions.
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub enum Initializer {
|
||||
/// Corresponds to a `const.*` instruction.
|
||||
Const(Value),
|
||||
@ -98,7 +98,7 @@ pub struct GlobalDesc {
|
||||
}
|
||||
|
||||
/// A wasm global.
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Global {
|
||||
pub desc: GlobalDesc,
|
||||
pub init: Initializer,
|
||||
|
@ -33,10 +33,7 @@ pub struct Ctx {
|
||||
}
|
||||
|
||||
impl Ctx {
|
||||
pub fn new(
|
||||
local_backing: &mut LocalBacking,
|
||||
import_backing: &mut ImportBacking,
|
||||
) -> Self {
|
||||
pub 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(),
|
||||
@ -101,6 +98,10 @@ impl ImportedFunc {
|
||||
pub fn offset_func() -> 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)
|
||||
|
Reference in New Issue
Block a user