2019-01-08 17:09:47 +00:00
|
|
|
use crate::{
|
2019-01-11 03:59:57 +00:00
|
|
|
export::{Context, Export},
|
2019-01-13 03:02:19 +00:00
|
|
|
import::Imports,
|
2019-01-08 17:09:47 +00:00
|
|
|
memory::LinearMemory,
|
2019-01-13 03:02:19 +00:00
|
|
|
module::{ImportName, ModuleInner},
|
2019-01-08 17:09:47 +00:00
|
|
|
table::{TableBacking, TableElements},
|
|
|
|
types::{Initializer, MapIndex, Value},
|
|
|
|
vm,
|
|
|
|
};
|
|
|
|
|
|
|
|
#[derive(Debug)]
|
|
|
|
pub struct LocalBacking {
|
2019-01-13 03:02:19 +00:00
|
|
|
pub(crate) memories: Box<[LinearMemory]>,
|
|
|
|
pub(crate) tables: Box<[TableBacking]>,
|
2019-01-08 17:09:47 +00:00
|
|
|
|
2019-01-13 03:02:19 +00:00
|
|
|
pub(crate) vm_memories: Box<[vm::LocalMemory]>,
|
|
|
|
pub(crate) vm_tables: Box<[vm::LocalTable]>,
|
|
|
|
pub(crate) vm_globals: Box<[vm::LocalGlobal]>,
|
2019-01-08 17:09:47 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
impl LocalBacking {
|
2019-01-13 03:02:19 +00:00
|
|
|
pub fn memory(&mut self, index: u32) -> &mut LinearMemory {
|
|
|
|
&mut self.memories[index as usize]
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn table(&mut self, index: u32) -> &mut TableBacking {
|
|
|
|
&mut self.tables[index as usize]
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl LocalBacking {
|
|
|
|
pub(crate) fn new(module: &ModuleInner, imports: &ImportBacking, vmctx: *mut vm::Ctx) -> Self {
|
2019-01-08 17:09:47 +00:00
|
|
|
let mut memories = Self::generate_memories(module);
|
|
|
|
let mut tables = Self::generate_tables(module);
|
|
|
|
let globals = Self::generate_globals(module);
|
|
|
|
|
|
|
|
let vm_memories = Self::finalize_memories(module, &mut memories[..]);
|
2019-01-11 03:59:57 +00:00
|
|
|
let vm_tables = Self::finalize_tables(module, imports, &mut tables[..], vmctx);
|
2019-01-08 17:09:47 +00:00
|
|
|
let vm_globals = Self::finalize_globals(module, imports, globals);
|
|
|
|
|
|
|
|
Self {
|
|
|
|
memories,
|
|
|
|
tables,
|
|
|
|
|
|
|
|
vm_memories,
|
|
|
|
vm_tables,
|
|
|
|
vm_globals,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-01-13 03:02:19 +00:00
|
|
|
fn generate_memories(module: &ModuleInner) -> Box<[LinearMemory]> {
|
2019-01-08 17:09:47 +00:00
|
|
|
let mut memories = Vec::with_capacity(module.memories.len());
|
|
|
|
|
|
|
|
for (_, mem) in &module.memories {
|
|
|
|
// If we use emscripten, we set a fixed initial and maximum
|
|
|
|
debug!("Instance - init memory ({}, {:?})", mem.min, mem.max);
|
|
|
|
// let memory = if options.abi == InstanceABI::Emscripten {
|
|
|
|
// // We use MAX_PAGES, so at the end the result is:
|
|
|
|
// // (initial * LinearMemory::PAGE_SIZE) == LinearMemory::DEFAULT_HEAP_SIZE
|
|
|
|
// // However, it should be: (initial * LinearMemory::PAGE_SIZE) == 16777216
|
|
|
|
// LinearMemory::new(LinearMemory::MAX_PAGES, None)
|
|
|
|
// } else {
|
|
|
|
// LinearMemory::new(memory.minimum, memory.maximum.map(|m| m as u32))
|
|
|
|
// };
|
|
|
|
let memory = LinearMemory::new(mem);
|
|
|
|
memories.push(memory);
|
|
|
|
}
|
|
|
|
|
|
|
|
memories.into_boxed_slice()
|
|
|
|
}
|
|
|
|
|
2019-01-13 03:02:19 +00:00
|
|
|
fn finalize_memories(
|
|
|
|
module: &ModuleInner,
|
|
|
|
memories: &mut [LinearMemory],
|
|
|
|
) -> Box<[vm::LocalMemory]> {
|
2019-01-08 17:09:47 +00:00
|
|
|
for init in &module.data_initializers {
|
|
|
|
assert!(init.base.is_none(), "global base not supported yet");
|
2019-01-11 03:59:57 +00:00
|
|
|
assert!(init.offset + init.data.len() <= memories[init.memory_index.index()].size());
|
2019-01-08 17:09:47 +00:00
|
|
|
let offset = init.offset;
|
|
|
|
let mem: &mut LinearMemory = &mut memories[init.memory_index.index()];
|
|
|
|
// let end_of_init = offset + init.data.len();
|
|
|
|
// if end_of_init > mem.current_size() {
|
|
|
|
// let grow_pages = (end_of_init / LinearMemory::PAGE_SIZE as usize) + 1;
|
|
|
|
// mem.grow(grow_pages as u32)
|
|
|
|
// .expect("failed to grow memory for data initializers");
|
|
|
|
// }
|
|
|
|
let to_init = &mut mem[offset..offset + init.data.len()];
|
|
|
|
to_init.copy_from_slice(&init.data);
|
|
|
|
}
|
|
|
|
|
|
|
|
memories
|
|
|
|
.iter_mut()
|
|
|
|
.map(|mem| mem.into_vm_memory())
|
|
|
|
.collect::<Vec<_>>()
|
|
|
|
.into_boxed_slice()
|
|
|
|
}
|
|
|
|
|
2019-01-13 03:02:19 +00:00
|
|
|
fn generate_tables(module: &ModuleInner) -> Box<[TableBacking]> {
|
2019-01-08 17:09:47 +00:00
|
|
|
let mut tables = Vec::with_capacity(module.tables.len());
|
|
|
|
|
|
|
|
for (_, table) in &module.tables {
|
|
|
|
let table_backing = TableBacking::new(table);
|
|
|
|
tables.push(table_backing);
|
|
|
|
}
|
|
|
|
|
|
|
|
tables.into_boxed_slice()
|
|
|
|
}
|
|
|
|
|
|
|
|
fn finalize_tables(
|
2019-01-13 03:02:19 +00:00
|
|
|
module: &ModuleInner,
|
2019-01-08 17:09:47 +00:00
|
|
|
imports: &ImportBacking,
|
|
|
|
tables: &mut [TableBacking],
|
2019-01-11 03:59:57 +00:00
|
|
|
vmctx: *mut vm::Ctx,
|
2019-01-08 17:09:47 +00:00
|
|
|
) -> Box<[vm::LocalTable]> {
|
|
|
|
for init in &module.table_initializers {
|
|
|
|
assert!(init.base.is_none(), "global base not supported yet");
|
|
|
|
let table = &mut tables[init.table_index.index()];
|
|
|
|
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];
|
2019-01-11 03:59:57 +00:00
|
|
|
let sig_id = vm::SigId(sig_index.index() as u32);
|
|
|
|
|
2019-01-08 17:09:47 +00:00
|
|
|
let func_data = if module.is_imported_function(func_index) {
|
|
|
|
imports.functions[func_index.index()].clone()
|
|
|
|
} else {
|
|
|
|
vm::ImportedFunc {
|
|
|
|
func: module
|
|
|
|
.func_resolver
|
|
|
|
.get(module, func_index)
|
|
|
|
.unwrap()
|
|
|
|
.as_ptr(),
|
2019-01-11 03:59:57 +00:00
|
|
|
vmctx,
|
2019-01-08 17:09:47 +00:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2019-01-11 03:59:57 +00:00
|
|
|
elements[init.offset + i] = vm::Anyfunc { func_data, sig_id };
|
2019-01-08 17:09:47 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
tables
|
|
|
|
.iter_mut()
|
|
|
|
.map(|table| table.into_vm_table())
|
|
|
|
.collect::<Vec<_>>()
|
|
|
|
.into_boxed_slice()
|
|
|
|
}
|
|
|
|
|
2019-01-13 03:02:19 +00:00
|
|
|
fn generate_globals(module: &ModuleInner) -> Box<[vm::LocalGlobal]> {
|
2019-01-08 17:09:47 +00:00
|
|
|
let globals = vec![vm::LocalGlobal::null(); module.globals.len()];
|
|
|
|
|
|
|
|
globals.into_boxed_slice()
|
|
|
|
}
|
|
|
|
|
|
|
|
fn finalize_globals(
|
2019-01-13 03:02:19 +00:00
|
|
|
module: &ModuleInner,
|
2019-01-08 17:09:47 +00:00
|
|
|
imports: &ImportBacking,
|
|
|
|
mut globals: Box<[vm::LocalGlobal]>,
|
|
|
|
) -> Box<[vm::LocalGlobal]> {
|
|
|
|
for (to, (_, from)) in globals.iter_mut().zip(module.globals.into_iter()) {
|
|
|
|
to.data = match from.init {
|
|
|
|
Initializer::Const(Value::I32(x)) => x as u64,
|
|
|
|
Initializer::Const(Value::I64(x)) => x as u64,
|
2019-01-10 01:32:02 +00:00
|
|
|
Initializer::Const(Value::F32(x)) => x.to_bits() as u64,
|
|
|
|
Initializer::Const(Value::F64(x)) => x.to_bits(),
|
2019-01-11 03:59:57 +00:00
|
|
|
Initializer::GetGlobal(index) => unsafe {
|
|
|
|
(*imports.globals[index.index()].global).data
|
|
|
|
},
|
2019-01-08 17:09:47 +00:00
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
globals
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Debug)]
|
|
|
|
pub struct ImportBacking {
|
|
|
|
pub functions: Box<[vm::ImportedFunc]>,
|
|
|
|
pub memories: Box<[vm::ImportedMemory]>,
|
|
|
|
pub tables: Box<[vm::ImportedTable]>,
|
|
|
|
pub globals: Box<[vm::ImportedGlobal]>,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl ImportBacking {
|
2019-01-11 03:59:57 +00:00
|
|
|
pub fn new(
|
2019-01-13 03:02:19 +00:00
|
|
|
module: &ModuleInner,
|
|
|
|
imports: &Imports,
|
2019-01-11 03:59:57 +00:00
|
|
|
vmctx: *mut vm::Ctx,
|
|
|
|
) -> Result<Self, String> {
|
2019-01-08 17:09:47 +00:00
|
|
|
|
2019-01-10 17:20:23 +00:00
|
|
|
Ok(ImportBacking {
|
2019-01-11 03:59:57 +00:00
|
|
|
functions: import_functions(module, imports, vmctx)?,
|
2019-01-12 20:34:23 +00:00
|
|
|
memories: import_memories(module, imports, vmctx)?,
|
2019-01-13 16:46:04 +00:00
|
|
|
tables: import_tables(module, imports, vmctx)?,
|
2019-01-10 17:20:23 +00:00
|
|
|
globals: import_globals(module, imports)?,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-01-12 20:34:23 +00:00
|
|
|
fn import_memories(
|
2019-01-13 03:02:19 +00:00
|
|
|
module: &ModuleInner,
|
|
|
|
imports: &Imports,
|
2019-01-12 20:34:23 +00:00
|
|
|
vmctx: *mut vm::Ctx,
|
|
|
|
) -> Result<Box<[vm::ImportedMemory]>, String> {
|
|
|
|
let mut memories = Vec::with_capacity(module.imported_memories.len());
|
2019-01-12 22:53:17 +00:00
|
|
|
for (_index, (ImportName { namespace, name }, expected_memory_desc)) in
|
|
|
|
&module.imported_memories
|
|
|
|
{
|
2019-01-13 03:02:19 +00:00
|
|
|
let memory_import = imports
|
|
|
|
.get_namespace(namespace)
|
|
|
|
.and_then(|namespace| namespace.get_export(name));
|
2019-01-12 20:34:23 +00:00
|
|
|
match memory_import {
|
|
|
|
Some(Export::Memory {
|
|
|
|
local,
|
|
|
|
ctx,
|
2019-01-12 21:45:32 +00:00
|
|
|
memory: memory_desc,
|
2019-01-12 20:34:23 +00:00
|
|
|
}) => {
|
2019-01-12 21:45:32 +00:00
|
|
|
if expected_memory_desc.fits_in_imported(&memory_desc) {
|
|
|
|
memories.push(vm::ImportedMemory {
|
2019-01-12 22:52:14 +00:00
|
|
|
memory: local.inner(),
|
2019-01-12 21:45:32 +00:00
|
|
|
vmctx: match ctx {
|
|
|
|
Context::External(ctx) => ctx,
|
|
|
|
Context::Internal => vmctx,
|
|
|
|
},
|
|
|
|
});
|
|
|
|
} else {
|
|
|
|
return Err(format!(
|
|
|
|
"incorrect memory description for {}:{}",
|
|
|
|
namespace, name,
|
|
|
|
));
|
|
|
|
}
|
2019-01-12 20:34:23 +00:00
|
|
|
}
|
|
|
|
Some(_) => {
|
2019-01-12 22:53:17 +00:00
|
|
|
return Err(format!("incorrect import type for {}:{}", namespace, name));
|
2019-01-12 20:34:23 +00:00
|
|
|
}
|
|
|
|
None => {
|
2019-01-12 21:45:32 +00:00
|
|
|
return Err(format!("import not found: {}:{}", namespace, name));
|
2019-01-12 20:34:23 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Ok(memories.into_boxed_slice())
|
|
|
|
}
|
2019-01-10 17:20:23 +00:00
|
|
|
|
2019-01-13 16:46:04 +00:00
|
|
|
fn import_tables(
|
|
|
|
module: &ModuleInner,
|
|
|
|
imports: &Imports,
|
|
|
|
vmctx: *mut vm::Ctx,
|
|
|
|
) -> Result<Box<[vm::ImportedTable]>, String> {
|
|
|
|
let mut tables = Vec::with_capacity(module.imported_tables.len());
|
|
|
|
for (_index, (ImportName { namespace, name }, expected_table_desc)) in
|
|
|
|
&module.imported_tables
|
|
|
|
{
|
|
|
|
let table_import = imports
|
|
|
|
.get_namespace(namespace)
|
|
|
|
.and_then(|namespace| namespace.get_export(name));
|
|
|
|
match table_import {
|
|
|
|
Some(Export::Table {
|
|
|
|
local,
|
|
|
|
ctx,
|
|
|
|
table: table_desc,
|
|
|
|
}) => {
|
|
|
|
if expected_table_desc.fits_in_imported(&table_desc) {
|
|
|
|
tables.push(vm::ImportedTable {
|
|
|
|
table: local.inner(),
|
|
|
|
vmctx: match ctx {
|
|
|
|
Context::External(ctx) => ctx,
|
|
|
|
Context::Internal => vmctx,
|
|
|
|
},
|
|
|
|
});
|
|
|
|
} else {
|
|
|
|
return Err(format!(
|
|
|
|
"incorrect table description for {}:{}",
|
|
|
|
namespace, name,
|
|
|
|
));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Some(_) => {
|
|
|
|
return Err(format!("incorrect import type for {}:{}", namespace, name));
|
|
|
|
}
|
|
|
|
None => {
|
|
|
|
return Err(format!("import not found: {}:{}", namespace, name));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Ok(tables.into_boxed_slice())
|
|
|
|
}
|
|
|
|
|
2019-01-11 03:59:57 +00:00
|
|
|
fn import_functions(
|
2019-01-13 03:02:19 +00:00
|
|
|
module: &ModuleInner,
|
|
|
|
imports: &Imports,
|
2019-01-11 03:59:57 +00:00
|
|
|
vmctx: *mut vm::Ctx,
|
|
|
|
) -> Result<Box<[vm::ImportedFunc]>, String> {
|
2019-01-10 17:20:23 +00:00
|
|
|
let mut functions = Vec::with_capacity(module.imported_functions.len());
|
2019-01-11 03:59:57 +00:00
|
|
|
for (index, ImportName { namespace, name }) in &module.imported_functions {
|
2019-01-10 17:20:23 +00:00
|
|
|
let sig_index = module.func_assoc[index];
|
|
|
|
let expected_sig = module.sig_registry.lookup_func_sig(sig_index);
|
2019-01-13 03:02:19 +00:00
|
|
|
let import = imports
|
|
|
|
.get_namespace(namespace)
|
|
|
|
.and_then(|namespace| namespace.get_export(name));
|
2019-01-10 17:20:23 +00:00
|
|
|
match import {
|
2019-01-11 03:59:57 +00:00
|
|
|
Some(Export::Function {
|
|
|
|
func,
|
|
|
|
ctx,
|
|
|
|
signature,
|
|
|
|
}) => {
|
|
|
|
if expected_sig == &signature {
|
2019-01-10 17:20:23 +00:00
|
|
|
functions.push(vm::ImportedFunc {
|
|
|
|
func: func.inner(),
|
2019-01-11 03:59:57 +00:00
|
|
|
vmctx: match ctx {
|
|
|
|
Context::External(ctx) => ctx,
|
|
|
|
Context::Internal => vmctx,
|
|
|
|
},
|
2019-01-10 17:20:23 +00:00
|
|
|
});
|
|
|
|
} else {
|
2019-01-08 17:09:47 +00:00
|
|
|
return Err(format!(
|
2019-01-10 17:20:23 +00:00
|
|
|
"unexpected signature for {:?}:{:?}",
|
2019-01-11 03:59:57 +00:00
|
|
|
namespace, name
|
2019-01-08 17:09:47 +00:00
|
|
|
));
|
|
|
|
}
|
2019-01-10 17:20:23 +00:00
|
|
|
}
|
|
|
|
Some(_) => {
|
2019-01-11 03:59:57 +00:00
|
|
|
return Err(format!("incorrect import type for {}:{}", namespace, name));
|
2019-01-10 17:20:23 +00:00
|
|
|
}
|
|
|
|
None => {
|
2019-01-11 03:59:57 +00:00
|
|
|
return Err(format!("import not found: {}:{}", namespace, name));
|
2019-01-08 17:09:47 +00:00
|
|
|
}
|
|
|
|
}
|
2019-01-10 17:20:23 +00:00
|
|
|
}
|
|
|
|
Ok(functions.into_boxed_slice())
|
|
|
|
}
|
2019-01-08 17:09:47 +00:00
|
|
|
|
2019-01-11 03:59:57 +00:00
|
|
|
fn import_globals(
|
2019-01-13 03:02:19 +00:00
|
|
|
module: &ModuleInner,
|
|
|
|
imports: &Imports,
|
2019-01-11 03:59:57 +00:00
|
|
|
) -> Result<Box<[vm::ImportedGlobal]>, String> {
|
2019-01-10 17:20:23 +00:00
|
|
|
let mut globals = Vec::with_capacity(module.imported_globals.len());
|
2019-01-11 03:59:57 +00:00
|
|
|
for (_, (ImportName { namespace, name }, global_desc)) in &module.imported_globals {
|
2019-01-13 03:02:19 +00:00
|
|
|
let import = imports
|
|
|
|
.get_namespace(namespace)
|
|
|
|
.and_then(|namespace| namespace.get_export(name));
|
2019-01-10 17:20:23 +00:00
|
|
|
match import {
|
2019-01-11 03:59:57 +00:00
|
|
|
Some(Export::Global { local, global }) => {
|
|
|
|
if &global == global_desc {
|
2019-01-12 22:53:17 +00:00
|
|
|
globals.push(vm::ImportedGlobal {
|
|
|
|
global: local.inner(),
|
|
|
|
});
|
2019-01-10 17:20:23 +00:00
|
|
|
} else {
|
2019-01-08 17:09:47 +00:00
|
|
|
return Err(format!(
|
2019-01-11 03:59:57 +00:00
|
|
|
"unexpected global description for {:?}:{:?}",
|
|
|
|
namespace, name
|
2019-01-08 17:09:47 +00:00
|
|
|
));
|
|
|
|
}
|
2019-01-10 17:20:23 +00:00
|
|
|
}
|
|
|
|
Some(_) => {
|
2019-01-11 03:59:57 +00:00
|
|
|
return Err(format!("incorrect import type for {}:{}", namespace, name));
|
2019-01-10 17:20:23 +00:00
|
|
|
}
|
|
|
|
None => {
|
2019-01-11 03:59:57 +00:00
|
|
|
return Err(format!("import not found: {}:{}", namespace, name));
|
2019-01-08 17:09:47 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2019-01-10 17:20:23 +00:00
|
|
|
Ok(globals.into_boxed_slice())
|
2019-01-08 17:09:47 +00:00
|
|
|
}
|