mirror of
https://github.com/fluencelabs/wasmer
synced 2025-06-27 07:31:33 +00:00
Support imported functions
This commit is contained in:
@ -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,20 +262,29 @@ 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 {
|
||||
if expected_sig == signature {
|
||||
functions.push(vm::ImportedFunc {
|
||||
func,
|
||||
// vmctx: ptr::null_mut(),
|
||||
});
|
||||
} else {
|
||||
match import {
|
||||
Some(&Import::Func(func, ref signature)) => {
|
||||
if expected_sig == signature {
|
||||
functions.push(vm::ImportedFunc {
|
||||
func,
|
||||
// vmctx: ptr::null_mut(),
|
||||
});
|
||||
} else {
|
||||
return Err(format!(
|
||||
"unexpected signature for {:?}:{:?}",
|
||||
mod_name, item_name
|
||||
));
|
||||
}
|
||||
}
|
||||
Some(_) => {
|
||||
return Err(format!(
|
||||
"unexpected signature for {:?}:{:?}",
|
||||
"incorrect import type for {}:{}",
|
||||
mod_name, item_name
|
||||
));
|
||||
}
|
||||
} else {
|
||||
return Err(format!("incorrect type for {:?}:{:?}", mod_name, item_name));
|
||||
None => {
|
||||
return Err(format!("import not found: {}:{}", mod_name, item_name));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -293,26 +301,35 @@ impl ImportBacking {
|
||||
) in &module.imported_globals
|
||||
{
|
||||
let import = imports.get(mod_name, item_name);
|
||||
if let Some(&Import::Global(val)) = import {
|
||||
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,
|
||||
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,
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
} else {
|
||||
});
|
||||
} else {
|
||||
return Err(format!(
|
||||
"unexpected global type for {:?}:{:?}",
|
||||
mod_name, item_name
|
||||
));
|
||||
}
|
||||
}
|
||||
Some(_) => {
|
||||
return Err(format!(
|
||||
"unexpected global type for {:?}:{:?}",
|
||||
"incorrect import type for {}:{}",
|
||||
mod_name, item_name
|
||||
));
|
||||
}
|
||||
} else {
|
||||
return Err(format!("incorrect 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,8 +73,11 @@ 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)
|
||||
.expect("unable to make memory accessible");
|
||||
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 {
|
||||
@ -56,13 +55,12 @@ impl ModuleInner {
|
||||
|
||||
impl Deref for Module {
|
||||
type Target = ModuleInner;
|
||||
|
||||
|
||||
fn deref(&self) -> &ModuleInner {
|
||||
&*self.0
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#[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;
|
||||
@ -16,13 +16,13 @@ impl SigRegistry {
|
||||
sig_assoc: Map::new(),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
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