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::{
|
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`.
|
||||||
|
@ -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
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
_ => (),
|
_ => (),
|
||||||
}
|
}
|
||||||
|
@ -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())
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
}
|
}
|
Binary file not shown.
@ -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));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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 {
|
||||||
|
@ -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)
|
||||||
}
|
}
|
@ -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()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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);
|
||||||
|
|
||||||
|
@ -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,
|
||||||
|
@ -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()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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,
|
||||||
|
@ -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)
|
||||||
|
Reference in New Issue
Block a user