Add preliminary support for imports

This commit is contained in:
Lachlan Sneff 2018-12-24 23:05:04 -05:00
parent 93ef1e4220
commit c06c65e7c6
11 changed files with 191 additions and 80 deletions

11
Cargo.lock generated
View File

@ -329,6 +329,15 @@ name = "glob"
version = "0.2.11" version = "0.2.11"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "hashbrown"
version = "0.1.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"byteorder 1.2.7 (registry+https://github.com/rust-lang/crates.io-index)",
"scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]] [[package]]
name = "indicatif" name = "indicatif"
version = "0.10.3" version = "0.10.3"
@ -894,6 +903,7 @@ dependencies = [
"errno 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", "errno 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)",
"error-chain 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)", "error-chain 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)",
"field-offset 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "field-offset 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"hashbrown 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
"indicatif 0.10.3 (registry+https://github.com/rust-lang/crates.io-index)", "indicatif 0.10.3 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.44 (git+https://github.com/rust-lang/libc)", "libc 0.2.44 (git+https://github.com/rust-lang/libc)",
"log 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)",
@ -978,6 +988,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
"checksum fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7" "checksum fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7"
"checksum gcc 0.3.55 (registry+https://github.com/rust-lang/crates.io-index)" = "8f5f3913fa0bfe7ee1fd8248b6b9f42a5af4b9d65ec2dd2c3c26132b950ecfc2" "checksum gcc 0.3.55 (registry+https://github.com/rust-lang/crates.io-index)" = "8f5f3913fa0bfe7ee1fd8248b6b9f42a5af4b9d65ec2dd2c3c26132b950ecfc2"
"checksum glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "8be18de09a56b60ed0edf84bc9df007e30040691af7acd1c41874faac5895bfb" "checksum glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "8be18de09a56b60ed0edf84bc9df007e30040691af7acd1c41874faac5895bfb"
"checksum hashbrown 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "64b7d419d0622ae02fe5da6b9a5e1964b610a65bb37923b976aeebb6dbb8f86e"
"checksum indicatif 0.10.3 (registry+https://github.com/rust-lang/crates.io-index)" = "40ecd1e2ee08e6c255ce890f5a99d17000850e664e7acf119fb03b25b0575bfe" "checksum indicatif 0.10.3 (registry+https://github.com/rust-lang/crates.io-index)" = "40ecd1e2ee08e6c255ce890f5a99d17000850e664e7acf119fb03b25b0575bfe"
"checksum itoa 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "1306f3464951f30e30d12373d31c79fbd52d236e5e896fd92f96ec7babbbe60b" "checksum itoa 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "1306f3464951f30e30d12373d31c79fbd52d236e5e896fd92f96ec7babbbe60b"
"checksum lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a374c89b9db55895453a74c1e38861d9deec0b01b405a82516e9d5de4820dea1" "checksum lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a374c89b9db55895453a74c1e38861d9deec0b01b405a82516e9d5de4820dea1"

View File

@ -50,6 +50,7 @@ byteorder = "1"
indicatif = "0.10" indicatif = "0.10"
console = "0.7.1" console = "0.7.1"
field-offset = "0.1.1" field-offset = "0.1.1"
hashbrown = "0.1"
[build-dependencies] [build-dependencies]
wabt = "0.7.2" wabt = "0.7.2"

View File

@ -5,11 +5,12 @@ use crate::runtime::{
module::Module, module::Module,
types::FuncIndex, types::FuncIndex,
}; };
use std::sync::Arc;
pub trait Compiler { pub trait Compiler {
fn compile(wasm: &[u8]) -> Box<Module>; fn compile(&self, wasm: &[u8]) -> Result<Arc<Module>, String>;
} }
pub trait FuncResolver { pub trait FuncResolver {
pub fn resolve(&self, index: FuncIndex) -> *const vm::Func; pub fn resolve(&self, index: FuncIndex) -> Option<*const vm::Func>;
} }

View File

@ -1,16 +1,12 @@
use super::vm;
use crate::module::Module;
use super::table::{TableBacking, TableScheme};
use super::memory::LinearMemory;
use super::instance::{InstanceOptions, InstanceABI};
use std::mem;
use crate::runtime::{ use crate::runtime::{
vm, vm,
module::Module, module::Module,
table::TableBacking, table::TableBacking,
types::{Val, GlobalInit}, types::{Val, GlobalInit},
memory::LinearMemory,
instance::{Imports, Import},
}; };
use std::{ptr, mem};
#[derive(Debug)] #[derive(Debug)]
@ -24,9 +20,9 @@ pub struct LocalBacking {
} }
impl LocalBacking { impl LocalBacking {
pub fn new(module: &Module, imports: &ImportBacking, options: &InstanceOptions) -> Self { pub fn new(module: &Module, imports: &ImportBacking) -> Self {
let mut memories = Self::generate_memories(module, options); let mut memories = Self::generate_memories(module);
let mut tables = Self::generate_tables(module, options); let mut tables = Self::generate_tables(module);
let globals = Self::generate_globals(module); let globals = Self::generate_globals(module);
Self { Self {
@ -39,7 +35,7 @@ impl LocalBacking {
} }
} }
fn generate_memories(module: &Module, options: &InstanceOptions) -> Box<[LinearMemory]> { fn generate_memories(module: &Module) -> Box<[LinearMemory]> {
let mut memories = Vec::with_capacity(module.memories.len()); let mut memories = Vec::with_capacity(module.memories.len());
for (_, mem) in &module.memories { for (_, mem) in &module.memories {
@ -63,7 +59,7 @@ impl LocalBacking {
memories.into_boxed_slice() memories.into_boxed_slice()
} }
fn finalize_memories(module: &Module, memories: &mut [LinearMemory], options: &InstanceOptions) -> Box<[vm::LocalMemory]> { fn finalize_memories(module: &Module, memories: &mut [LinearMemory]) -> Box<[vm::LocalMemory]> {
for init in &module.data_initializers { for init in &module.data_initializers {
debug_assert!(init.base.is_none(), "globalvar base not supported yet"); debug_assert!(init.base.is_none(), "globalvar base not supported yet");
let offset = init.offset; let offset = init.offset;
@ -78,16 +74,10 @@ impl LocalBacking {
to_init.copy_from_slice(&init.data); to_init.copy_from_slice(&init.data);
} }
if options.abi == InstanceABI::Emscripten {
debug!("emscripten::setup memory");
crate::apis::emscripten::emscripten_set_up_memory(&mut memories[0]);
debug!("emscripten::finish setup memory");
}
memories.iter_mut().map(|mem| mem.into_vm_memory()).collect::<Vec<_>>().into_boxed_slice() memories.iter_mut().map(|mem| mem.into_vm_memory()).collect::<Vec<_>>().into_boxed_slice()
} }
fn generate_tables(module: &Module, options: &InstanceOptions) -> Box<[TableBacking]> { fn generate_tables(module: &Module) -> Box<[TableBacking]> {
let mut tables = Vec::with_capacity(module.tables.len()); let mut tables = Vec::with_capacity(module.tables.len());
for table in &module.tables { for table in &module.tables {
@ -98,7 +88,7 @@ impl LocalBacking {
tables.into_boxed_slice() tables.into_boxed_slice()
} }
fn finalize_tables(module: &Module, tables: &[TableBacking], options: &InstanceOptions) -> Box<[vm::LocalTable]> { fn finalize_tables(module: &Module, tables: &[TableBacking]) -> Box<[vm::LocalTable]> {
tables.iter().map(|table| table.into_vm_table()).collect::<Vec<_>>().into_boxed_slice() tables.iter().map(|table| table.into_vm_table()).collect::<Vec<_>>().into_boxed_slice()
} }
@ -197,3 +187,58 @@ pub struct ImportBacking {
tables: Box<[vm::ImportedTable]>, tables: Box<[vm::ImportedTable]>,
globals: Box<[vm::ImportedGlobal]>, globals: Box<[vm::ImportedGlobal]>,
} }
impl ImportBacking {
pub fn new(module: &Module, imports: &Imports) -> Result<Self, String> {
assert!(module.imported_memories.len() == 0, "imported memories not yet supported");
assert!(module.imported_tables.len() == 0, "imported tables not yet supported");
let mut functions = Vec::with_capacity(module.imported_functions.len());
for (index, (mod_name, item_name)) in &module.imported_functions {
let expected_sig = module.signatures[index];
let import = imports.get(mod_name, item_name);
if let Import::Func(func, signature) = import {
if expected_sig == signature {
functions.push(vm::ImportedFunc {
func,
vmctx: ptr::null_mut(),
});
} else {
return Err(format!("unexpected signature for {}:{}", mod_name, item_name));
}
} else {
return Err(format!("incorrect type for {}:{}", mod_name, item_name));
}
}
let mut globals = Vec::with_capacity(module.imported_globals.len());
for (_, ((mod_name, item_name), global_desc)) in &module.imported_globals {
let import = imports.get(mod_name, item_name);
if let Import::Global(val) = import {
if val.ty() == global_desc.ty {
globals.push(vm::ImportedGlobal {
global: vm::LocalGlobal {
data: match val {
Val::I32(n) => n as u64,
Val::I64(n) => n as u64,
Val::F32(n) => n as u64,
Val::F64(n) => n,
},
},
});
} else {
return Err(format!("unexpected global type for {}:{}", mod_name, item_name));
}
} else {
return Err(format!("incorrect type for {}:{}", mod_name, item_name));
}
}
Ok(ImportBacking {
functions: functions.into_boxed_slice(),
memories: vec![].into_boxed_slice(),
tables: vec![].into_boxed_slice(),
globals: globals.into_boxed_slice(),
})
}
}

View File

@ -1,26 +1,63 @@
use crate::runtime::{ use crate::runtime::{
vm, vm,
backing::{LocalBacking, ImportBacking}, backing::{LocalBacking, ImportBacking},
module::{ModuleName, ItemName},
types::{Val, Memory, Table, Global, FuncSig},
table::TableBacking,
memory::LinearMemory,
}; };
use std::sync::Arc; use std::sync::Arc;
use hashbrown::{HashMap, Entry};
pub struct Instance { pub struct Instance {
pub vmctx: vm::Ctx, pub vmctx: vm::Ctx,
pub finalized_funcs: Box<[*const vm::Func]>, backing: LocalBacking,
imports: ImportBacking,
pub backing: LocalBacking,
pub imports: ImportBacking,
pub module: Arc<Module>, pub module: Arc<Module>,
} }
impl Instance { impl Instance {
pub fn new(module: Arc<Module>) -> Box<Instance> { pub fn new(module: Arc<Module>, imports: &Imports) -> Result<Box<Instance>, String> {
let mut import_backing = ImportBacking::new(&*module, imports)?;
let mut backing = LocalBacking::new(&*module, &import_backing);
Box::new(Instance { let vmctx = vm::Ctx::new(&mut backing, &mut imports);
Ok(Box::new(Instance {
vmctx, vmctx,
finalized_funcs backing,
}) import_backing,
module,
}))
}
}
#[derive(Debug, PartialEq, Eq)]
pub enum Import {
Func(*const vm::Func, FuncSig),
Table(Arc<TableBacking>, Table),
Memory(Arc<LinearMemory>, Memory),
Global(Val),
}
pub struct Imports {
map: HashMap<ModuleName, HashMap<ItemName, Import>>,
}
impl Imports {
pub fn new() -> Self {
Self {
map: HashMap::new(),
}
}
pub fn add(&mut self, module: ModuleName, name: ItemName, import: Import) {
self.map.entry(module).or_insert(HashMap::new()).insert(name, import)
}
pub fn get(&self, module: ModuleName, name: ItemName) -> Option<&Import> {
self.map.get().and_then(|m| m.get(name))
} }
} }

View File

@ -239,8 +239,3 @@ impl DerefMut for LinearMemory {
} }
} }
} }
fn round_up_to_page_size(size: usize) -> usize {
let page_size = region::page::size();
(size + (page_size - 1)) & !(page_size - 1)
}

View File

@ -1,9 +1,20 @@
pub mod vm; pub mod vm;
pub mod backing; mod backing;
pub mod types; mod types;
pub mod memory; mod memory;
pub mod backend; mod backend;
pub mod module; mod module;
pub mod instance; mod instance;
pub mod table; mod table;
mod sig_registry;
pub use backend::Compiler;
pub use instance::{Instance, Imports, Import};
pub use module::{ModuleName, ItemName, Module};
/// Compile a webassembly module using the provided compiler and linked with the provided imports.
pub fn compile(compiler: &dyn Compiler, wasm: &[u8], imports: &Imports) -> Result<Box<Instance>, String> {
let module = compiler.compile(wasm)?;
Instance::new(module, imports)
}

View File

@ -1,7 +1,7 @@
use crate::runtime::types::{ use crate::runtime::types::{
Map, Map,
FuncIndex, MemoryIndex, TableIndex, GlobalIndex, FuncIndex, MemoryIndex, TableIndex, GlobalIndex,
Memory, Globals, GlobalDesc, Func, Table, Memory, Globals, GlobalDesc, FuncSig, Table,
}; };
use crate::runtime::backend::FuncResolver; use crate::runtime::backend::FuncResolver;
@ -13,7 +13,7 @@ pub struct Module {
pub globals: Map<Global, GlobalIndex>, pub globals: Map<Global, GlobalIndex>,
pub tables: Map<Table, TableIndex>, pub tables: Map<Table, TableIndex>,
pub imported_functions: Map<(ImportName, Func), FuncIndex>, pub imported_functions: Map<ImportName, FuncIndex>,
pub imported_memories: Map<(ImportName, Memory), MemoryIndex>, pub imported_memories: Map<(ImportName, Memory), MemoryIndex>,
pub imported_tables: Map<(ImportName, Table), TableIndex>, pub imported_tables: Map<(ImportName, Table), TableIndex>,
pub imported_globals: Map<(ImportName, GlobalDesc), GlobalIndex>, pub imported_globals: Map<(ImportName, GlobalDesc), GlobalIndex>,
@ -23,7 +23,7 @@ pub struct Module {
pub data_initializers: Vec<DataInitializer>, pub data_initializers: Vec<DataInitializer>,
pub start_func: FuncIndex, pub start_func: FuncIndex,
pub signatures: Map<Func, FuncIndex>, pub signatures: Map<FuncSig, FuncIndex>,
} }
pub type ModuleName = Vec<u8>; pub type ModuleName = Vec<u8>;

View File

@ -0,0 +1,5 @@
pub struct SignatureRegistry {
}

View File

@ -25,6 +25,17 @@ pub enum Val {
F64(u64), F64(u64),
} }
impl Val {
pub fn ty(&self) -> Type {
match self {
Val::I32(_) => Type::I32,
Val::I64(_) => Type::I64,
Val::F32(_) => Type::F32,
Val::F64(_) => Type::F64,
}
}
}
impl From<i32> for Val { impl From<i32> for Val {
fn from(n: i32) -> Self { fn from(n: i32) -> Self {
Self::I32(n) Self::I32(n)
@ -105,8 +116,8 @@ impl Memory {
} }
/// A wasm func. /// A wasm func.
#[derive(Debug)] #[derive(Debug, PartialEq, Eq)]
pub struct Func { pub struct FuncSig {
pub params: Vec<Type>, pub params: Vec<Type>,
pub returns: Vec<Type>, pub returns: Vec<Type>,
} }

View File

@ -1,19 +1,22 @@
use std::{ptr, mem}; use std::{ptr, mem};
use crate::runtime::types::{ use crate::runtime::{
MemoryIndex, TableIndex, GlobalIndex, FuncIndex, types::{
SignatureIndex, MemoryIndex, TableIndex, GlobalIndex, FuncIndex,
SignatureIndex,
},
backing::{LocalBacking, ImportBacking},
}; };
#[derive(Debug)] #[derive(Debug)]
#[repr(C)] #[repr(C)]
pub struct Ctx<'a> { pub struct Ctx<'a> {
/// A pointer to an array of locally-defined memories, indexed by `DefinedMemoryIndex`. /// A pointer to an array of locally-defined memories, indexed by `MemoryIndex`.
pub memories: *mut LocalMemory, pub memories: *mut LocalMemory,
/// A pointer to an array of locally-defined tables, indexed by `DefinedTableIndex`. /// A pointer to an array of locally-defined tables, indexed by `TableIndex`.
pub tables: *mut LocalTable, pub tables: *mut LocalTable,
/// A pointer to an array of locally-defined globals, indexed by `DefinedGlobalIndex`. /// A pointer to an array of locally-defined globals, indexed by `GlobalIndex`.
pub globals: *mut LocalGlobal, pub globals: *mut LocalGlobal,
/// A pointer to an array of imported memories, indexed by `MemoryIndex, /// A pointer to an array of imported memories, indexed by `MemoryIndex,
@ -34,23 +37,19 @@ pub struct Ctx<'a> {
impl Ctx { impl Ctx {
pub fn new( pub fn new(
memories: *mut LocalMemory, local_backing: &mut LocalBacking,
tables: *mut LocalTable, import_backing: &mut ImportBacking,
globals: *mut LocalGlobal,
imported_memories: *mut ImportedMemory,
imported_tables: *mut ImportedTable,
imported_globals: *mut ImportedGlobal,
imported_funcs: *mut ImportedFunc,
sig_ids: *mut SigId, sig_ids: *mut SigId,
) -> Self { ) -> Self {
Self { Self {
memories, memories: local_backing.vm_memories.as_mut_ptr(),
tables, tables: local_backing.vm_tables.as_mut_ptr(),
globals, globals: local_backing.vm_globals.as_mut_ptr(),
imported_memories,
imported_tables, imported_memories: import_backing.memories.as_mut_ptr(),
imported_globals, imported_tables: import_backing.tables.as_mut_ptr(),
imported_funcs, imported_funcs: import_backing.functions.as_mut_ptr(),
sig_ids, sig_ids,
} }
} }
@ -98,17 +97,12 @@ pub enum Func {}
#[repr(C)] #[repr(C)]
pub struct ImportedFunc { pub struct ImportedFunc {
pub func: *const Func, pub func: *const Func,
pub vmctx: *mut Ctx,
} }
impl ImportedFunc { 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 offset_vmctx() -> u8 {
1 * (mem::size_of::<usize>() as u8)
}
} }
/// Definition of a table used by the VM. (obviously) /// Definition of a table used by the VM. (obviously)
@ -205,11 +199,11 @@ impl LocalGlobal {
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
#[repr(C)] #[repr(C)]
pub struct ImportedGlobal { pub struct ImportedGlobal {
pub global: *mut LocalGlobal, pub global: LocalGlobal,
} }
impl ImportedGlobal { impl ImportedGlobal {
pub fn offset_global() -> u8 { pub fn offset_data() -> u8 {
0 * (mem::size_of::<usize>() as u8) 0 * (mem::size_of::<usize>() as u8)
} }
} }
@ -314,10 +308,10 @@ mod vm_offset_tests {
offset_of!(ImportedFunc => func).get_byte_offset(), offset_of!(ImportedFunc => func).get_byte_offset(),
); );
assert_eq!( // assert_eq!(
ImportedFunc::offset_vmctx() as usize, // ImportedFunc::offset_vmctx() as usize,
offset_of!(ImportedFunc => vmctx).get_byte_offset(), // offset_of!(ImportedFunc => vmctx).get_byte_offset(),
); // );
} }
#[test] #[test]
@ -378,8 +372,8 @@ mod vm_offset_tests {
#[test] #[test]
fn imported_global() { fn imported_global() {
assert_eq!( assert_eq!(
ImportedGlobal::offset_global() as usize, ImportedGlobal::offset_data() as usize,
offset_of!(ImportedGlobal => global).get_byte_offset(), offset_of!(ImportedGlobal => global: LocalGlobal => data).get_byte_offset(),
); );
} }