mirror of
https://github.com/fluencelabs/wasmer
synced 2025-06-27 23:51:33 +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,12 +62,9 @@ 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())
|
||||
}
|
||||
@ -169,4 +173,4 @@ impl wasmer_runtime::FuncResolver for FuncResolver {
|
||||
#[inline]
|
||||
fn round_up(n: usize, multiple: usize) -> usize {
|
||||
(n + multiple - 1) & !(multiple - 1)
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user