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"
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]]
name = "indicatif"
version = "0.10.3"
@ -894,6 +903,7 @@ dependencies = [
"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)",
"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)",
"libc 0.2.44 (git+https://github.com/rust-lang/libc)",
"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 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 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 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"

View File

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

View File

@ -5,11 +5,12 @@ use crate::runtime::{
module::Module,
types::FuncIndex,
};
use std::sync::Arc;
pub trait Compiler {
fn compile(wasm: &[u8]) -> Box<Module>;
fn compile(&self, wasm: &[u8]) -> Result<Arc<Module>, String>;
}
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::{
vm,
module::Module,
table::TableBacking,
types::{Val, GlobalInit},
memory::LinearMemory,
instance::{Imports, Import},
};
use std::{ptr, mem};
#[derive(Debug)]
@ -24,9 +20,9 @@ pub struct LocalBacking {
}
impl LocalBacking {
pub fn new(module: &Module, imports: &ImportBacking, options: &InstanceOptions) -> Self {
let mut memories = Self::generate_memories(module, options);
let mut tables = Self::generate_tables(module, options);
pub fn new(module: &Module, imports: &ImportBacking) -> Self {
let mut memories = Self::generate_memories(module);
let mut tables = Self::generate_tables(module);
let globals = Self::generate_globals(module);
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());
for (_, mem) in &module.memories {
@ -63,7 +59,7 @@ impl LocalBacking {
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 {
debug_assert!(init.base.is_none(), "globalvar base not supported yet");
let offset = init.offset;
@ -78,16 +74,10 @@ impl LocalBacking {
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()
}
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());
for table in &module.tables {
@ -98,7 +88,7 @@ impl LocalBacking {
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()
}
@ -196,4 +186,59 @@ pub struct ImportBacking {
memories: Box<[vm::ImportedMemory]>,
tables: Box<[vm::ImportedTable]>,
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::{
vm,
backing::{LocalBacking, ImportBacking},
module::{ModuleName, ItemName},
types::{Val, Memory, Table, Global, FuncSig},
table::TableBacking,
memory::LinearMemory,
};
use std::sync::Arc;
use hashbrown::{HashMap, Entry};
pub struct Instance {
pub vmctx: vm::Ctx,
pub finalized_funcs: Box<[*const vm::Func]>,
pub backing: LocalBacking,
pub imports: ImportBacking,
backing: LocalBacking,
imports: ImportBacking,
pub module: Arc<Module>,
}
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);
let vmctx = vm::Ctx::new(&mut backing, &mut imports);
Box::new(Instance {
Ok(Box::new(Instance {
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

@ -238,9 +238,4 @@ 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 backing;
pub mod types;
pub mod memory;
pub mod backend;
pub mod module;
pub mod instance;
pub mod table;
mod backing;
mod types;
mod memory;
mod backend;
mod module;
mod instance;
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::{
Map,
FuncIndex, MemoryIndex, TableIndex, GlobalIndex,
Memory, Globals, GlobalDesc, Func, Table,
Memory, Globals, GlobalDesc, FuncSig, Table,
};
use crate::runtime::backend::FuncResolver;
@ -13,7 +13,7 @@ pub struct Module {
pub globals: Map<Global, GlobalIndex>,
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_tables: Map<(ImportName, Table), TableIndex>,
pub imported_globals: Map<(ImportName, GlobalDesc), GlobalIndex>,
@ -23,7 +23,7 @@ pub struct Module {
pub data_initializers: Vec<DataInitializer>,
pub start_func: FuncIndex,
pub signatures: Map<Func, FuncIndex>,
pub signatures: Map<FuncSig, FuncIndex>,
}
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),
}
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 {
fn from(n: i32) -> Self {
Self::I32(n)
@ -105,8 +116,8 @@ impl Memory {
}
/// A wasm func.
#[derive(Debug)]
pub struct Func {
#[derive(Debug, PartialEq, Eq)]
pub struct FuncSig {
pub params: Vec<Type>,
pub returns: Vec<Type>,
}

View File

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