2019-01-08 17:09:47 +00:00
|
|
|
use crate::{
|
2019-01-18 18:54:16 +00:00
|
|
|
error::{LinkError, LinkResult},
|
2019-01-11 03:59:57 +00:00
|
|
|
export::{Context, Export},
|
2019-01-28 19:55:44 +00:00
|
|
|
global::Global,
|
2019-01-21 22:43:04 +00:00
|
|
|
import::ImportObject,
|
2019-02-05 07:07:58 +00:00
|
|
|
memory::Memory,
|
2019-03-04 05:26:34 +00:00
|
|
|
module::{ImportName, ModuleInfo, ModuleInner},
|
2019-02-07 00:26:45 +00:00
|
|
|
sig_registry::SigRegistry,
|
2019-01-16 18:26:10 +00:00
|
|
|
structures::{BoxedMap, Map, SliceMap, TypedIndex},
|
2019-01-29 18:16:39 +00:00
|
|
|
table::Table,
|
2019-01-16 18:26:10 +00:00
|
|
|
types::{
|
2019-01-29 18:16:39 +00:00
|
|
|
ImportedFuncIndex, ImportedGlobalIndex, ImportedMemoryIndex, ImportedTableIndex,
|
2019-03-08 23:15:16 +00:00
|
|
|
Initializer, LocalFuncIndex, LocalGlobalIndex, LocalMemoryIndex, LocalOrImport,
|
|
|
|
LocalTableIndex, SigIndex, Value,
|
2019-01-16 18:26:10 +00:00
|
|
|
},
|
2019-01-08 17:09:47 +00:00
|
|
|
vm,
|
|
|
|
};
|
2019-05-16 17:15:05 +00:00
|
|
|
use std::{fmt::Debug, slice};
|
2019-05-16 17:10:21 +00:00
|
|
|
|
|
|
|
pub const INTERNALS_SIZE: usize = 256;
|
|
|
|
|
|
|
|
pub(crate) struct Internals(pub(crate) [u64; INTERNALS_SIZE]);
|
|
|
|
|
|
|
|
impl Debug for Internals {
|
|
|
|
fn fmt(&self, formatter: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
|
|
|
|
write!(formatter, "Internals({:?})", &self.0[..])
|
|
|
|
}
|
|
|
|
}
|
2019-01-08 17:09:47 +00:00
|
|
|
|
2019-05-13 18:18:57 +00:00
|
|
|
/// The `LocalBacking` "owns" the memory used by all the local resources of an Instance.
|
2019-03-13 21:58:44 +00:00
|
|
|
/// That is, local memories, tables, and globals (as well as some additional
|
|
|
|
/// data for the virtual call machinery).
|
2019-01-08 17:09:47 +00:00
|
|
|
#[derive(Debug)]
|
|
|
|
pub struct LocalBacking {
|
2019-03-13 21:58:44 +00:00
|
|
|
/// This is a map from the local resource index to actual memory,
|
|
|
|
/// table, and globals.
|
2019-02-05 07:07:58 +00:00
|
|
|
pub(crate) memories: BoxedMap<LocalMemoryIndex, Memory>,
|
2019-01-29 18:16:39 +00:00
|
|
|
pub(crate) tables: BoxedMap<LocalTableIndex, Table>,
|
2019-01-28 19:55:44 +00:00
|
|
|
pub(crate) globals: BoxedMap<LocalGlobalIndex, Global>,
|
2019-01-08 17:09:47 +00:00
|
|
|
|
2019-03-13 21:58:44 +00:00
|
|
|
/// This own the memory containing the pointers to the local memories.
|
|
|
|
/// While simplifying implementation, this adds indirection and may hurt
|
|
|
|
/// performance, especially on cache-starved systems.
|
2019-01-25 23:28:54 +00:00
|
|
|
pub(crate) vm_memories: BoxedMap<LocalMemoryIndex, *mut vm::LocalMemory>,
|
2019-01-29 18:16:39 +00:00
|
|
|
pub(crate) vm_tables: BoxedMap<LocalTableIndex, *mut vm::LocalTable>,
|
2019-01-28 19:55:44 +00:00
|
|
|
pub(crate) vm_globals: BoxedMap<LocalGlobalIndex, *mut vm::LocalGlobal>,
|
2019-03-04 05:26:34 +00:00
|
|
|
|
2019-03-13 21:58:44 +00:00
|
|
|
/// The dynamic sigindices are used to efficiently support caching and
|
|
|
|
/// the `call_indirect` wasm instruction. This field (and local_functions
|
|
|
|
/// as well) are subject to change.
|
2019-03-04 05:26:34 +00:00
|
|
|
pub(crate) dynamic_sigindices: BoxedMap<SigIndex, vm::SigId>,
|
2019-03-08 23:15:16 +00:00
|
|
|
pub(crate) local_functions: BoxedMap<LocalFuncIndex, *const vm::Func>,
|
2019-05-16 17:10:21 +00:00
|
|
|
|
|
|
|
pub(crate) internals: Internals,
|
2019-01-08 17:09:47 +00:00
|
|
|
}
|
|
|
|
|
2019-01-13 03:02:19 +00:00
|
|
|
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);
|
2019-01-28 19:55:44 +00:00
|
|
|
let mut globals = Self::generate_globals(module, imports);
|
2019-01-08 17:09:47 +00:00
|
|
|
|
2019-01-16 18:26:10 +00:00
|
|
|
let vm_memories = Self::finalize_memories(module, imports, &mut memories);
|
|
|
|
let vm_tables = Self::finalize_tables(module, imports, &mut tables, vmctx);
|
2019-01-28 19:55:44 +00:00
|
|
|
let vm_globals = Self::finalize_globals(&mut globals);
|
2019-01-08 17:09:47 +00:00
|
|
|
|
2019-03-04 05:26:34 +00:00
|
|
|
let dynamic_sigindices = Self::generate_sigindices(&module.info);
|
2019-03-08 23:15:16 +00:00
|
|
|
let local_functions = Self::generate_local_functions(module);
|
2019-03-04 05:26:34 +00:00
|
|
|
|
2019-01-08 17:09:47 +00:00
|
|
|
Self {
|
|
|
|
memories,
|
|
|
|
tables,
|
2019-01-28 19:55:44 +00:00
|
|
|
globals,
|
2019-01-08 17:09:47 +00:00
|
|
|
|
|
|
|
vm_memories,
|
|
|
|
vm_tables,
|
|
|
|
vm_globals,
|
2019-03-04 05:26:34 +00:00
|
|
|
|
|
|
|
dynamic_sigindices,
|
2019-03-08 23:15:16 +00:00
|
|
|
local_functions,
|
2019-05-16 17:10:21 +00:00
|
|
|
|
2019-05-16 17:33:33 +00:00
|
|
|
internals: Internals([0; INTERNALS_SIZE]),
|
2019-01-08 17:09:47 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-03-08 23:15:16 +00:00
|
|
|
fn generate_local_functions(module: &ModuleInner) -> BoxedMap<LocalFuncIndex, *const vm::Func> {
|
|
|
|
(0..module.info.func_assoc.len() - module.info.imported_functions.len())
|
|
|
|
.map(|index| {
|
|
|
|
module
|
2019-04-12 01:01:54 +00:00
|
|
|
.runnable_module
|
|
|
|
.get_func(&module.info, LocalFuncIndex::new(index))
|
2019-03-08 23:15:16 +00:00
|
|
|
.unwrap()
|
|
|
|
.as_ptr() as *const _
|
|
|
|
})
|
|
|
|
.collect::<Map<_, _>>()
|
|
|
|
.into_boxed_map()
|
|
|
|
}
|
|
|
|
|
2019-03-04 05:26:34 +00:00
|
|
|
fn generate_sigindices(info: &ModuleInfo) -> BoxedMap<SigIndex, vm::SigId> {
|
|
|
|
info.signatures
|
|
|
|
.iter()
|
|
|
|
.map(|(_, signature)| {
|
|
|
|
let signature = SigRegistry.lookup_signature_ref(signature);
|
|
|
|
let sig_index = SigRegistry.lookup_sig_index(signature);
|
|
|
|
vm::SigId(sig_index.index() as u32)
|
|
|
|
})
|
|
|
|
.collect::<Map<_, _>>()
|
|
|
|
.into_boxed_map()
|
|
|
|
}
|
|
|
|
|
2019-02-05 07:07:58 +00:00
|
|
|
fn generate_memories(module: &ModuleInner) -> BoxedMap<LocalMemoryIndex, Memory> {
|
2019-02-07 00:26:45 +00:00
|
|
|
let mut memories = Map::with_capacity(module.info.memories.len());
|
|
|
|
for (_, &desc) in &module.info.memories {
|
2019-02-05 07:07:58 +00:00
|
|
|
memories.push(Memory::new(desc).expect("unable to create memory"));
|
2019-01-08 17:09:47 +00:00
|
|
|
}
|
|
|
|
|
2019-01-16 18:26:10 +00:00
|
|
|
memories.into_boxed_map()
|
2019-01-08 17:09:47 +00:00
|
|
|
}
|
|
|
|
|
2019-05-13 18:18:57 +00:00
|
|
|
/// Initialize each locally-defined memory in the Module.
|
2019-03-13 21:58:44 +00:00
|
|
|
///
|
|
|
|
/// This involves copying in the data initializers.
|
2019-01-13 03:02:19 +00:00
|
|
|
fn finalize_memories(
|
|
|
|
module: &ModuleInner,
|
2019-01-16 18:26:10 +00:00
|
|
|
imports: &ImportBacking,
|
2019-02-05 07:07:58 +00:00
|
|
|
memories: &mut SliceMap<LocalMemoryIndex, Memory>,
|
2019-01-25 23:28:54 +00:00
|
|
|
) -> BoxedMap<LocalMemoryIndex, *mut vm::LocalMemory> {
|
2019-01-16 18:26:10 +00:00
|
|
|
// For each init that has some data...
|
|
|
|
for init in module
|
2019-02-07 00:26:45 +00:00
|
|
|
.info
|
2019-01-16 18:26:10 +00:00
|
|
|
.data_initializers
|
|
|
|
.iter()
|
|
|
|
.filter(|init| init.data.len() > 0)
|
|
|
|
{
|
2019-01-17 01:59:12 +00:00
|
|
|
let init_base = match init.base {
|
|
|
|
Initializer::Const(Value::I32(offset)) => offset as u32,
|
|
|
|
Initializer::Const(_) => panic!("a const initializer must be the i32 type"),
|
2019-01-28 19:55:44 +00:00
|
|
|
Initializer::GetGlobal(import_global_index) => {
|
|
|
|
if let Value::I32(x) = imports.globals[import_global_index].get() {
|
|
|
|
x as u32
|
2019-01-17 01:59:12 +00:00
|
|
|
} else {
|
2019-06-18 22:15:49 +00:00
|
|
|
panic!("unsupported global type for initializer")
|
2019-01-17 01:59:12 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
} as usize;
|
2019-01-16 18:26:10 +00:00
|
|
|
|
2019-02-09 23:53:40 +00:00
|
|
|
match init.memory_index.local_or_import(&module.info) {
|
2019-01-16 18:26:10 +00:00
|
|
|
LocalOrImport::Local(local_memory_index) => {
|
2019-02-07 00:26:45 +00:00
|
|
|
let memory_desc = module.info.memories[local_memory_index];
|
2019-01-17 01:59:12 +00:00
|
|
|
let data_top = init_base + init.data.len();
|
2019-01-29 23:44:15 +00:00
|
|
|
assert!(memory_desc.minimum.bytes().0 >= data_top);
|
2019-01-25 23:28:54 +00:00
|
|
|
|
2019-01-28 18:59:05 +00:00
|
|
|
let mem = &memories[local_memory_index];
|
2019-02-05 18:20:04 +00:00
|
|
|
for (mem_byte, data_byte) in mem.view()[init_base..init_base + init.data.len()]
|
2019-02-05 07:07:58 +00:00
|
|
|
.iter()
|
|
|
|
.zip(init.data.iter())
|
|
|
|
{
|
|
|
|
mem_byte.set(*data_byte);
|
2019-02-04 23:07:32 +00:00
|
|
|
}
|
2019-01-16 18:26:10 +00:00
|
|
|
}
|
|
|
|
LocalOrImport::Import(imported_memory_index) => {
|
2019-01-25 23:28:54 +00:00
|
|
|
// Write the initialization data to the memory that
|
|
|
|
// we think the imported memory is.
|
2019-01-17 21:09:05 +00:00
|
|
|
unsafe {
|
2019-01-25 23:28:54 +00:00
|
|
|
let local_memory = &*imports.vm_memories[imported_memory_index];
|
2019-01-17 21:09:05 +00:00
|
|
|
let memory_slice =
|
2019-01-25 23:28:54 +00:00
|
|
|
slice::from_raw_parts_mut(local_memory.base, local_memory.bound);
|
2019-01-17 21:09:05 +00:00
|
|
|
|
|
|
|
let mem_init_view =
|
|
|
|
&mut memory_slice[init_base..init_base + init.data.len()];
|
|
|
|
mem_init_view.copy_from_slice(&init.data);
|
|
|
|
}
|
2019-01-16 18:26:10 +00:00
|
|
|
}
|
|
|
|
}
|
2019-01-08 17:09:47 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
memories
|
|
|
|
.iter_mut()
|
2019-02-05 07:07:58 +00:00
|
|
|
.map(|(_, mem)| mem.vm_local_memory())
|
2019-01-16 18:26:10 +00:00
|
|
|
.collect::<Map<_, _>>()
|
|
|
|
.into_boxed_map()
|
2019-01-08 17:09:47 +00:00
|
|
|
}
|
|
|
|
|
2019-01-29 18:16:39 +00:00
|
|
|
fn generate_tables(module: &ModuleInner) -> BoxedMap<LocalTableIndex, Table> {
|
2019-02-07 00:26:45 +00:00
|
|
|
let mut tables = Map::with_capacity(module.info.tables.len());
|
2019-01-08 17:09:47 +00:00
|
|
|
|
2019-02-07 00:26:45 +00:00
|
|
|
for (_, &table_desc) in module.info.tables.iter() {
|
2019-01-29 18:16:39 +00:00
|
|
|
let table = Table::new(table_desc).unwrap();
|
|
|
|
tables.push(table);
|
2019-01-08 17:09:47 +00:00
|
|
|
}
|
|
|
|
|
2019-01-16 18:26:10 +00:00
|
|
|
tables.into_boxed_map()
|
2019-01-08 17:09:47 +00:00
|
|
|
}
|
|
|
|
|
2019-05-13 18:18:57 +00:00
|
|
|
/// This initializes all of the locally-defined tables in the Module, e.g.
|
2019-03-13 21:58:44 +00:00
|
|
|
/// putting all the table elements (function pointers)
|
|
|
|
/// in the right places.
|
2019-01-18 06:33:46 +00:00
|
|
|
#[allow(clippy::cast_ptr_alignment)]
|
2019-01-08 17:09:47 +00:00
|
|
|
fn finalize_tables(
|
2019-01-13 03:02:19 +00:00
|
|
|
module: &ModuleInner,
|
2019-01-08 17:09:47 +00:00
|
|
|
imports: &ImportBacking,
|
2019-01-29 18:16:39 +00:00
|
|
|
tables: &mut SliceMap<LocalTableIndex, Table>,
|
2019-01-11 03:59:57 +00:00
|
|
|
vmctx: *mut vm::Ctx,
|
2019-01-29 18:16:39 +00:00
|
|
|
) -> BoxedMap<LocalTableIndex, *mut vm::LocalTable> {
|
2019-02-07 00:26:45 +00:00
|
|
|
for init in &module.info.elem_initializers {
|
2019-01-16 18:26:10 +00:00
|
|
|
let init_base = match init.base {
|
|
|
|
Initializer::Const(Value::I32(offset)) => offset as u32,
|
|
|
|
Initializer::Const(_) => panic!("a const initializer must be the i32 type"),
|
2019-01-28 19:55:44 +00:00
|
|
|
Initializer::GetGlobal(import_global_index) => {
|
|
|
|
if let Value::I32(x) = imports.globals[import_global_index].get() {
|
|
|
|
x as u32
|
2019-01-16 18:26:10 +00:00
|
|
|
} else {
|
2019-06-18 22:15:49 +00:00
|
|
|
panic!("unsupported global type for initializer")
|
2019-01-16 18:26:10 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
} as usize;
|
|
|
|
|
2019-02-09 23:53:40 +00:00
|
|
|
match init.table_index.local_or_import(&module.info) {
|
2019-01-16 18:26:10 +00:00
|
|
|
LocalOrImport::Local(local_table_index) => {
|
2019-01-29 18:16:39 +00:00
|
|
|
let table = &tables[local_table_index];
|
|
|
|
|
2019-01-29 23:44:15 +00:00
|
|
|
if (table.size() as usize) < init_base + init.elements.len() {
|
|
|
|
let delta = (init_base + init.elements.len()) - table.size() as usize;
|
2019-01-29 18:16:39 +00:00
|
|
|
// Grow the table if it's too small.
|
|
|
|
table.grow(delta as u32).expect("couldn't grow table");
|
2019-01-16 18:26:10 +00:00
|
|
|
}
|
2019-01-17 21:09:05 +00:00
|
|
|
|
2019-01-29 18:16:39 +00:00
|
|
|
table.anyfunc_direct_access_mut(|elements| {
|
|
|
|
for (i, &func_index) in init.elements.iter().enumerate() {
|
2019-02-07 00:26:45 +00:00
|
|
|
let sig_index = module.info.func_assoc[func_index];
|
2019-02-08 22:19:58 +00:00
|
|
|
// let signature = &module.info.signatures[sig_index];
|
|
|
|
let signature = SigRegistry
|
|
|
|
.lookup_signature_ref(&module.info.signatures[sig_index]);
|
|
|
|
let sig_id =
|
|
|
|
vm::SigId(SigRegistry.lookup_sig_index(signature).index() as u32);
|
2019-01-29 18:16:39 +00:00
|
|
|
|
2019-02-09 23:53:40 +00:00
|
|
|
let (func, ctx) = match func_index.local_or_import(&module.info) {
|
2019-01-29 18:16:39 +00:00
|
|
|
LocalOrImport::Local(local_func_index) => (
|
|
|
|
module
|
2019-04-12 01:01:54 +00:00
|
|
|
.runnable_module
|
|
|
|
.get_func(&module.info, local_func_index)
|
2019-01-29 18:16:39 +00:00
|
|
|
.unwrap()
|
|
|
|
.as_ptr()
|
|
|
|
as *const vm::Func,
|
|
|
|
vmctx,
|
|
|
|
),
|
|
|
|
LocalOrImport::Import(imported_func_index) => {
|
|
|
|
let vm::ImportedFunc { func, vmctx } =
|
|
|
|
imports.vm_functions[imported_func_index];
|
|
|
|
(func, vmctx)
|
2019-01-17 21:09:05 +00:00
|
|
|
}
|
2019-01-29 18:16:39 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
elements[init_base + i] = vm::Anyfunc { func, ctx, sig_id };
|
2019-01-16 18:26:10 +00:00
|
|
|
}
|
2019-01-29 18:16:39 +00:00
|
|
|
});
|
|
|
|
}
|
|
|
|
LocalOrImport::Import(import_table_index) => {
|
|
|
|
let table = &imports.tables[import_table_index];
|
|
|
|
|
2019-01-29 23:44:15 +00:00
|
|
|
if (table.size() as usize) < init_base + init.elements.len() {
|
|
|
|
let delta = (init_base + init.elements.len()) - table.size() as usize;
|
2019-01-29 18:16:39 +00:00
|
|
|
// Grow the table if it's too small.
|
|
|
|
table.grow(delta as u32).expect("couldn't grow table");
|
2019-01-08 17:09:47 +00:00
|
|
|
}
|
2019-01-29 18:16:39 +00:00
|
|
|
|
|
|
|
table.anyfunc_direct_access_mut(|elements| {
|
|
|
|
for (i, &func_index) in init.elements.iter().enumerate() {
|
2019-02-07 00:26:45 +00:00
|
|
|
let sig_index = module.info.func_assoc[func_index];
|
2019-02-08 22:19:58 +00:00
|
|
|
let signature = SigRegistry
|
|
|
|
.lookup_signature_ref(&module.info.signatures[sig_index]);
|
|
|
|
// let signature = &module.info.signatures[sig_index];
|
|
|
|
let sig_id =
|
|
|
|
vm::SigId(SigRegistry.lookup_sig_index(signature).index() as u32);
|
2019-01-29 18:16:39 +00:00
|
|
|
|
2019-02-09 23:53:40 +00:00
|
|
|
let (func, ctx) = match func_index.local_or_import(&module.info) {
|
2019-01-29 18:16:39 +00:00
|
|
|
LocalOrImport::Local(local_func_index) => (
|
|
|
|
module
|
2019-04-12 01:01:54 +00:00
|
|
|
.runnable_module
|
|
|
|
.get_func(&module.info, local_func_index)
|
2019-01-29 18:16:39 +00:00
|
|
|
.unwrap()
|
|
|
|
.as_ptr()
|
|
|
|
as *const vm::Func,
|
|
|
|
vmctx,
|
|
|
|
),
|
|
|
|
LocalOrImport::Import(imported_func_index) => {
|
|
|
|
let vm::ImportedFunc { func, vmctx } =
|
|
|
|
imports.vm_functions[imported_func_index];
|
|
|
|
(func, vmctx)
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
elements[init_base + i] = vm::Anyfunc { func, ctx, sig_id };
|
|
|
|
}
|
|
|
|
});
|
2019-01-08 17:09:47 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
tables
|
|
|
|
.iter_mut()
|
2019-01-29 18:16:39 +00:00
|
|
|
.map(|(_, table)| table.vm_local_table())
|
2019-01-16 18:26:10 +00:00
|
|
|
.collect::<Map<_, _>>()
|
|
|
|
.into_boxed_map()
|
2019-01-08 17:09:47 +00:00
|
|
|
}
|
|
|
|
|
2019-01-28 19:55:44 +00:00
|
|
|
fn generate_globals(
|
|
|
|
module: &ModuleInner,
|
|
|
|
imports: &ImportBacking,
|
|
|
|
) -> BoxedMap<LocalGlobalIndex, Global> {
|
2019-02-07 00:26:45 +00:00
|
|
|
let mut globals = Map::with_capacity(module.info.globals.len());
|
2019-01-16 18:26:10 +00:00
|
|
|
|
2019-02-07 00:26:45 +00:00
|
|
|
for (_, global_init) in module.info.globals.iter() {
|
2019-01-28 19:55:44 +00:00
|
|
|
let value = match &global_init.init {
|
|
|
|
Initializer::Const(value) => value.clone(),
|
|
|
|
Initializer::GetGlobal(import_global_index) => {
|
|
|
|
imports.globals[*import_global_index].get()
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
let global = if global_init.desc.mutable {
|
|
|
|
Global::new_mutable(value)
|
|
|
|
} else {
|
|
|
|
Global::new(value)
|
|
|
|
};
|
|
|
|
|
|
|
|
globals.push(global);
|
|
|
|
}
|
2019-01-08 17:09:47 +00:00
|
|
|
|
2019-01-16 18:26:10 +00:00
|
|
|
globals.into_boxed_map()
|
2019-01-08 17:09:47 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
fn finalize_globals(
|
2019-01-28 19:55:44 +00:00
|
|
|
globals: &mut SliceMap<LocalGlobalIndex, Global>,
|
|
|
|
) -> BoxedMap<LocalGlobalIndex, *mut vm::LocalGlobal> {
|
2019-01-08 17:09:47 +00:00
|
|
|
globals
|
2019-01-28 19:55:44 +00:00
|
|
|
.iter_mut()
|
|
|
|
.map(|(_, global)| global.vm_local_global())
|
|
|
|
.collect::<Map<_, _>>()
|
|
|
|
.into_boxed_map()
|
2019-01-08 17:09:47 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Debug)]
|
|
|
|
pub struct ImportBacking {
|
2019-02-05 07:07:58 +00:00
|
|
|
pub(crate) memories: BoxedMap<ImportedMemoryIndex, Memory>,
|
2019-01-29 18:16:39 +00:00
|
|
|
pub(crate) tables: BoxedMap<ImportedTableIndex, Table>,
|
2019-01-28 19:55:44 +00:00
|
|
|
pub(crate) globals: BoxedMap<ImportedGlobalIndex, Global>,
|
2019-01-25 23:28:54 +00:00
|
|
|
|
|
|
|
pub(crate) vm_functions: BoxedMap<ImportedFuncIndex, vm::ImportedFunc>,
|
|
|
|
pub(crate) vm_memories: BoxedMap<ImportedMemoryIndex, *mut vm::LocalMemory>,
|
2019-01-29 18:16:39 +00:00
|
|
|
pub(crate) vm_tables: BoxedMap<ImportedTableIndex, *mut vm::LocalTable>,
|
2019-01-28 19:55:44 +00:00
|
|
|
pub(crate) vm_globals: BoxedMap<ImportedGlobalIndex, *mut vm::LocalGlobal>,
|
2019-01-08 17:09:47 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
impl ImportBacking {
|
2019-01-11 03:59:57 +00:00
|
|
|
pub fn new(
|
2019-01-13 03:02:19 +00:00
|
|
|
module: &ModuleInner,
|
2019-02-02 23:58:33 +00:00
|
|
|
imports: &ImportObject,
|
2019-01-11 03:59:57 +00:00
|
|
|
vmctx: *mut vm::Ctx,
|
2019-01-18 18:54:16 +00:00
|
|
|
) -> LinkResult<Self> {
|
2019-01-18 22:18:06 +00:00
|
|
|
let mut failed = false;
|
2019-01-18 21:44:44 +00:00
|
|
|
let mut link_errors = vec![];
|
|
|
|
|
2019-01-25 23:28:54 +00:00
|
|
|
let vm_functions = import_functions(module, imports, vmctx).unwrap_or_else(|le| {
|
2019-01-18 22:18:06 +00:00
|
|
|
failed = true;
|
2019-01-18 21:44:44 +00:00
|
|
|
link_errors.extend(le);
|
|
|
|
Map::new().into_boxed_map()
|
|
|
|
});
|
|
|
|
|
2019-01-28 19:55:44 +00:00
|
|
|
let (memories, vm_memories) = import_memories(module, imports).unwrap_or_else(|le| {
|
2019-01-18 22:18:06 +00:00
|
|
|
failed = true;
|
2019-01-18 21:44:44 +00:00
|
|
|
link_errors.extend(le);
|
2019-01-25 23:28:54 +00:00
|
|
|
(Map::new().into_boxed_map(), Map::new().into_boxed_map())
|
2019-01-18 21:44:44 +00:00
|
|
|
});
|
|
|
|
|
2019-01-29 18:16:39 +00:00
|
|
|
let (tables, vm_tables) = import_tables(module, imports).unwrap_or_else(|le| {
|
2019-01-18 22:18:06 +00:00
|
|
|
failed = true;
|
2019-01-18 21:44:44 +00:00
|
|
|
link_errors.extend(le);
|
2019-01-29 18:16:39 +00:00
|
|
|
(Map::new().into_boxed_map(), Map::new().into_boxed_map())
|
2019-01-18 21:44:44 +00:00
|
|
|
});
|
|
|
|
|
2019-01-28 19:55:44 +00:00
|
|
|
let (globals, vm_globals) = import_globals(module, imports).unwrap_or_else(|le| {
|
2019-01-18 22:18:06 +00:00
|
|
|
failed = true;
|
2019-01-18 21:44:44 +00:00
|
|
|
link_errors.extend(le);
|
2019-01-28 19:55:44 +00:00
|
|
|
(Map::new().into_boxed_map(), Map::new().into_boxed_map())
|
2019-01-18 21:44:44 +00:00
|
|
|
});
|
|
|
|
|
2019-01-18 22:18:06 +00:00
|
|
|
if failed {
|
2019-01-18 21:44:44 +00:00
|
|
|
Err(link_errors)
|
|
|
|
} else {
|
|
|
|
Ok(ImportBacking {
|
|
|
|
memories,
|
2019-01-29 18:16:39 +00:00
|
|
|
tables,
|
2019-01-28 19:55:44 +00:00
|
|
|
globals,
|
2019-01-25 23:28:54 +00:00
|
|
|
|
|
|
|
vm_functions,
|
|
|
|
vm_memories,
|
|
|
|
vm_tables,
|
|
|
|
vm_globals,
|
2019-01-18 21:44:44 +00:00
|
|
|
})
|
|
|
|
}
|
2019-01-10 17:20:23 +00:00
|
|
|
}
|
2019-01-17 21:09:05 +00:00
|
|
|
|
2019-01-25 23:28:54 +00:00
|
|
|
pub fn imported_func(&self, index: ImportedFuncIndex) -> vm::ImportedFunc {
|
|
|
|
self.vm_functions[index].clone()
|
2019-01-17 21:09:05 +00:00
|
|
|
}
|
2019-01-10 17:20:23 +00:00
|
|
|
}
|
|
|
|
|
2019-01-16 18:26:10 +00:00
|
|
|
fn import_functions(
|
2019-01-13 03:02:19 +00:00
|
|
|
module: &ModuleInner,
|
2019-02-02 23:58:33 +00:00
|
|
|
imports: &ImportObject,
|
2019-01-12 20:34:23 +00:00
|
|
|
vmctx: *mut vm::Ctx,
|
2019-01-18 18:54:16 +00:00
|
|
|
) -> LinkResult<BoxedMap<ImportedFuncIndex, vm::ImportedFunc>> {
|
2019-01-18 21:44:44 +00:00
|
|
|
let mut link_errors = vec![];
|
2019-02-07 00:26:45 +00:00
|
|
|
let mut functions = Map::with_capacity(module.info.imported_functions.len());
|
|
|
|
for (
|
|
|
|
index,
|
|
|
|
ImportName {
|
|
|
|
namespace_index,
|
|
|
|
name_index,
|
|
|
|
},
|
|
|
|
) in &module.info.imported_functions
|
|
|
|
{
|
2019-02-09 23:53:40 +00:00
|
|
|
let sig_index = module.info.func_assoc[index.convert_up(&module.info)];
|
2019-02-07 00:26:45 +00:00
|
|
|
let expected_sig = &module.info.signatures[sig_index];
|
|
|
|
|
|
|
|
let namespace = module.info.namespace_table.get(*namespace_index);
|
|
|
|
let name = module.info.name_table.get(*name_index);
|
|
|
|
|
2019-01-16 18:26:10 +00:00
|
|
|
let import = imports
|
2019-01-13 03:02:19 +00:00
|
|
|
.get_namespace(namespace)
|
|
|
|
.and_then(|namespace| namespace.get_export(name));
|
2019-01-16 18:26:10 +00:00
|
|
|
match import {
|
|
|
|
Some(Export::Function {
|
|
|
|
func,
|
2019-01-12 20:34:23 +00:00
|
|
|
ctx,
|
2019-01-16 18:26:10 +00:00
|
|
|
signature,
|
2019-01-12 20:34:23 +00:00
|
|
|
}) => {
|
2019-02-08 22:19:58 +00:00
|
|
|
if *expected_sig == *signature {
|
2019-01-16 18:26:10 +00:00
|
|
|
functions.push(vm::ImportedFunc {
|
|
|
|
func: func.inner(),
|
2019-01-12 21:45:32 +00:00
|
|
|
vmctx: match ctx {
|
|
|
|
Context::External(ctx) => ctx,
|
|
|
|
Context::Internal => vmctx,
|
|
|
|
},
|
|
|
|
});
|
|
|
|
} else {
|
2019-01-18 21:44:44 +00:00
|
|
|
link_errors.push(LinkError::IncorrectImportSignature {
|
2019-02-07 00:26:45 +00:00
|
|
|
namespace: namespace.to_string(),
|
|
|
|
name: name.to_string(),
|
2019-02-08 22:19:58 +00:00
|
|
|
expected: (*expected_sig).clone(),
|
|
|
|
found: (*signature).clone(),
|
2019-01-18 21:44:44 +00:00
|
|
|
});
|
2019-01-12 21:45:32 +00:00
|
|
|
}
|
2019-01-12 20:34:23 +00:00
|
|
|
}
|
2019-01-18 18:54:16 +00:00
|
|
|
Some(export_type) => {
|
|
|
|
let export_type_name = match export_type {
|
|
|
|
Export::Function { .. } => "function",
|
|
|
|
Export::Memory { .. } => "memory",
|
|
|
|
Export::Table { .. } => "table",
|
|
|
|
Export::Global { .. } => "global",
|
|
|
|
}
|
|
|
|
.to_string();
|
2019-01-18 21:44:44 +00:00
|
|
|
link_errors.push(LinkError::IncorrectImportType {
|
2019-02-07 00:26:45 +00:00
|
|
|
namespace: namespace.to_string(),
|
|
|
|
name: name.to_string(),
|
2019-01-18 18:54:16 +00:00
|
|
|
expected: "function".to_string(),
|
|
|
|
found: export_type_name,
|
2019-01-18 21:44:44 +00:00
|
|
|
});
|
|
|
|
}
|
|
|
|
None => {
|
2019-05-04 15:28:13 +00:00
|
|
|
if imports.allow_missing_functions {
|
|
|
|
functions.push(vm::ImportedFunc {
|
|
|
|
func: ::std::ptr::null(),
|
|
|
|
vmctx: ::std::ptr::null_mut(),
|
|
|
|
});
|
|
|
|
} else {
|
|
|
|
link_errors.push(LinkError::ImportNotFound {
|
|
|
|
namespace: namespace.to_string(),
|
|
|
|
name: name.to_string(),
|
|
|
|
});
|
|
|
|
}
|
2019-01-12 20:34:23 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2019-01-18 21:44:44 +00:00
|
|
|
|
|
|
|
if link_errors.len() > 0 {
|
|
|
|
Err(link_errors)
|
|
|
|
} else {
|
|
|
|
Ok(functions.into_boxed_map())
|
|
|
|
}
|
2019-01-12 20:34:23 +00:00
|
|
|
}
|
2019-01-10 17:20:23 +00:00
|
|
|
|
2019-01-16 18:26:10 +00:00
|
|
|
fn import_memories(
|
2019-01-13 16:46:04 +00:00
|
|
|
module: &ModuleInner,
|
2019-02-02 23:58:33 +00:00
|
|
|
imports: &ImportObject,
|
2019-01-25 23:28:54 +00:00
|
|
|
) -> LinkResult<(
|
2019-02-05 07:07:58 +00:00
|
|
|
BoxedMap<ImportedMemoryIndex, Memory>,
|
2019-01-28 19:55:44 +00:00
|
|
|
BoxedMap<ImportedMemoryIndex, *mut vm::LocalMemory>,
|
2019-01-25 23:28:54 +00:00
|
|
|
)> {
|
2019-01-18 21:44:44 +00:00
|
|
|
let mut link_errors = vec![];
|
2019-02-07 00:26:45 +00:00
|
|
|
let mut memories = Map::with_capacity(module.info.imported_memories.len());
|
|
|
|
let mut vm_memories = Map::with_capacity(module.info.imported_memories.len());
|
|
|
|
for (
|
|
|
|
_index,
|
|
|
|
(
|
|
|
|
ImportName {
|
|
|
|
namespace_index,
|
|
|
|
name_index,
|
|
|
|
},
|
|
|
|
expected_memory_desc,
|
|
|
|
),
|
|
|
|
) in &module.info.imported_memories
|
2019-01-16 18:26:10 +00:00
|
|
|
{
|
2019-02-07 00:26:45 +00:00
|
|
|
let namespace = module.info.namespace_table.get(*namespace_index);
|
|
|
|
let name = module.info.name_table.get(*name_index);
|
|
|
|
|
2019-01-16 18:26:10 +00:00
|
|
|
let memory_import = imports
|
2019-01-25 23:28:54 +00:00
|
|
|
.get_namespace(&namespace)
|
|
|
|
.and_then(|namespace| namespace.get_export(&name));
|
2019-01-16 18:26:10 +00:00
|
|
|
match memory_import {
|
2019-02-05 07:07:58 +00:00
|
|
|
Some(Export::Memory(memory)) => {
|
|
|
|
if expected_memory_desc.fits_in_imported(memory.descriptor()) {
|
2019-01-25 23:28:54 +00:00
|
|
|
memories.push(memory.clone());
|
2019-02-05 07:07:58 +00:00
|
|
|
vm_memories.push(memory.vm_local_memory());
|
2019-01-13 21:52:25 +00:00
|
|
|
} else {
|
2019-01-29 21:04:42 +00:00
|
|
|
link_errors.push(LinkError::IncorrectMemoryDescriptor {
|
2019-02-07 00:26:45 +00:00
|
|
|
namespace: namespace.to_string(),
|
|
|
|
name: name.to_string(),
|
2019-01-25 23:28:54 +00:00
|
|
|
expected: *expected_memory_desc,
|
2019-02-05 07:07:58 +00:00
|
|
|
found: memory.descriptor(),
|
2019-01-18 21:44:44 +00:00
|
|
|
});
|
2019-01-13 16:46:04 +00:00
|
|
|
}
|
|
|
|
}
|
2019-01-18 18:54:16 +00:00
|
|
|
Some(export_type) => {
|
|
|
|
let export_type_name = match export_type {
|
|
|
|
Export::Function { .. } => "function",
|
|
|
|
Export::Memory { .. } => "memory",
|
|
|
|
Export::Table { .. } => "table",
|
|
|
|
Export::Global { .. } => "global",
|
|
|
|
}
|
|
|
|
.to_string();
|
2019-01-18 21:44:44 +00:00
|
|
|
link_errors.push(LinkError::IncorrectImportType {
|
2019-02-07 00:26:45 +00:00
|
|
|
namespace: namespace.to_string(),
|
|
|
|
name: name.to_string(),
|
2019-01-18 18:54:16 +00:00
|
|
|
expected: "memory".to_string(),
|
|
|
|
found: export_type_name,
|
2019-01-18 21:44:44 +00:00
|
|
|
});
|
|
|
|
}
|
|
|
|
None => {
|
|
|
|
link_errors.push(LinkError::ImportNotFound {
|
2019-02-07 00:26:45 +00:00
|
|
|
namespace: namespace.to_string(),
|
|
|
|
name: name.to_string(),
|
2019-01-18 21:44:44 +00:00
|
|
|
});
|
2019-01-13 21:52:25 +00:00
|
|
|
}
|
2019-01-13 16:46:04 +00:00
|
|
|
}
|
2019-01-13 21:52:25 +00:00
|
|
|
}
|
2019-01-18 21:44:44 +00:00
|
|
|
|
|
|
|
if link_errors.len() > 0 {
|
|
|
|
Err(link_errors)
|
|
|
|
} else {
|
2019-01-28 19:55:44 +00:00
|
|
|
Ok((memories.into_boxed_map(), vm_memories.into_boxed_map()))
|
2019-01-18 21:44:44 +00:00
|
|
|
}
|
2019-01-13 16:46:04 +00:00
|
|
|
}
|
|
|
|
|
2019-01-16 18:26:10 +00:00
|
|
|
fn import_tables(
|
2019-01-13 03:02:19 +00:00
|
|
|
module: &ModuleInner,
|
2019-02-02 23:58:33 +00:00
|
|
|
imports: &ImportObject,
|
2019-01-29 18:16:39 +00:00
|
|
|
) -> LinkResult<(
|
|
|
|
BoxedMap<ImportedTableIndex, Table>,
|
|
|
|
BoxedMap<ImportedTableIndex, *mut vm::LocalTable>,
|
|
|
|
)> {
|
2019-01-18 21:44:44 +00:00
|
|
|
let mut link_errors = vec![];
|
2019-02-07 00:26:45 +00:00
|
|
|
let mut tables = Map::with_capacity(module.info.imported_tables.len());
|
|
|
|
let mut vm_tables = Map::with_capacity(module.info.imported_tables.len());
|
|
|
|
for (
|
|
|
|
_index,
|
|
|
|
(
|
|
|
|
ImportName {
|
|
|
|
namespace_index,
|
|
|
|
name_index,
|
|
|
|
},
|
|
|
|
expected_table_desc,
|
|
|
|
),
|
|
|
|
) in &module.info.imported_tables
|
|
|
|
{
|
|
|
|
let namespace = module.info.namespace_table.get(*namespace_index);
|
|
|
|
let name = module.info.name_table.get(*name_index);
|
|
|
|
|
2019-01-16 18:26:10 +00:00
|
|
|
let table_import = imports
|
2019-01-25 23:28:54 +00:00
|
|
|
.get_namespace(&namespace)
|
|
|
|
.and_then(|namespace| namespace.get_export(&name));
|
2019-01-16 18:26:10 +00:00
|
|
|
match table_import {
|
2019-01-29 18:16:39 +00:00
|
|
|
Some(Export::Table(mut table)) => {
|
2019-01-29 21:04:42 +00:00
|
|
|
if expected_table_desc.fits_in_imported(table.descriptor()) {
|
2019-01-29 18:16:39 +00:00
|
|
|
vm_tables.push(table.vm_local_table());
|
|
|
|
tables.push(table);
|
2019-01-10 17:20:23 +00:00
|
|
|
} else {
|
2019-01-29 21:04:42 +00:00
|
|
|
link_errors.push(LinkError::IncorrectTableDescriptor {
|
2019-02-07 00:26:45 +00:00
|
|
|
namespace: namespace.to_string(),
|
|
|
|
name: name.to_string(),
|
2019-01-29 18:16:39 +00:00
|
|
|
expected: *expected_table_desc,
|
2019-01-29 21:04:42 +00:00
|
|
|
found: table.descriptor(),
|
2019-01-18 21:44:44 +00:00
|
|
|
});
|
2019-01-08 17:09:47 +00:00
|
|
|
}
|
2019-01-10 17:20:23 +00:00
|
|
|
}
|
2019-01-18 18:54:16 +00:00
|
|
|
Some(export_type) => {
|
|
|
|
let export_type_name = match export_type {
|
|
|
|
Export::Function { .. } => "function",
|
|
|
|
Export::Memory { .. } => "memory",
|
|
|
|
Export::Table { .. } => "table",
|
|
|
|
Export::Global { .. } => "global",
|
|
|
|
}
|
|
|
|
.to_string();
|
2019-01-18 21:44:44 +00:00
|
|
|
link_errors.push(LinkError::IncorrectImportType {
|
2019-02-07 00:26:45 +00:00
|
|
|
namespace: namespace.to_string(),
|
|
|
|
name: name.to_string(),
|
2019-01-18 18:54:16 +00:00
|
|
|
expected: "table".to_string(),
|
|
|
|
found: export_type_name,
|
2019-01-18 21:44:44 +00:00
|
|
|
});
|
|
|
|
}
|
|
|
|
None => {
|
|
|
|
link_errors.push(LinkError::ImportNotFound {
|
2019-02-07 00:26:45 +00:00
|
|
|
namespace: namespace.to_string(),
|
|
|
|
name: name.to_string(),
|
2019-01-18 21:44:44 +00:00
|
|
|
});
|
2019-01-08 17:09:47 +00:00
|
|
|
}
|
|
|
|
}
|
2019-01-10 17:20:23 +00:00
|
|
|
}
|
2019-01-18 21:44:44 +00:00
|
|
|
|
|
|
|
if link_errors.len() > 0 {
|
|
|
|
Err(link_errors)
|
|
|
|
} else {
|
2019-01-29 18:16:39 +00:00
|
|
|
Ok((tables.into_boxed_map(), vm_tables.into_boxed_map()))
|
2019-01-18 21:44:44 +00:00
|
|
|
}
|
2019-01-10 17:20:23 +00:00
|
|
|
}
|
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,
|
2019-02-02 23:58:33 +00:00
|
|
|
imports: &ImportObject,
|
2019-01-28 19:55:44 +00:00
|
|
|
) -> LinkResult<(
|
|
|
|
BoxedMap<ImportedGlobalIndex, Global>,
|
|
|
|
BoxedMap<ImportedGlobalIndex, *mut vm::LocalGlobal>,
|
|
|
|
)> {
|
2019-01-18 21:44:44 +00:00
|
|
|
let mut link_errors = vec![];
|
2019-02-07 00:26:45 +00:00
|
|
|
let mut globals = Map::with_capacity(module.info.imported_globals.len());
|
|
|
|
let mut vm_globals = Map::with_capacity(module.info.imported_globals.len());
|
|
|
|
for (
|
|
|
|
_,
|
|
|
|
(
|
|
|
|
ImportName {
|
|
|
|
namespace_index,
|
|
|
|
name_index,
|
|
|
|
},
|
|
|
|
imported_global_desc,
|
|
|
|
),
|
|
|
|
) in &module.info.imported_globals
|
|
|
|
{
|
|
|
|
let namespace = module.info.namespace_table.get(*namespace_index);
|
|
|
|
let name = module.info.name_table.get(*name_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-28 19:55:44 +00:00
|
|
|
Some(Export::Global(mut global)) => {
|
2019-01-29 21:04:42 +00:00
|
|
|
if global.descriptor() == *imported_global_desc {
|
2019-01-28 19:55:44 +00:00
|
|
|
vm_globals.push(global.vm_local_global());
|
|
|
|
globals.push(global);
|
2019-01-10 17:20:23 +00:00
|
|
|
} else {
|
2019-01-29 21:04:42 +00:00
|
|
|
link_errors.push(LinkError::IncorrectGlobalDescriptor {
|
2019-02-07 00:26:45 +00:00
|
|
|
namespace: namespace.to_string(),
|
|
|
|
name: name.to_string(),
|
2019-01-28 19:55:44 +00:00
|
|
|
expected: *imported_global_desc,
|
2019-01-29 21:04:42 +00:00
|
|
|
found: global.descriptor(),
|
2019-01-18 21:44:44 +00:00
|
|
|
});
|
2019-01-08 17:09:47 +00:00
|
|
|
}
|
2019-01-10 17:20:23 +00:00
|
|
|
}
|
2019-01-18 18:54:16 +00:00
|
|
|
Some(export_type) => {
|
|
|
|
let export_type_name = match export_type {
|
|
|
|
Export::Function { .. } => "function",
|
|
|
|
Export::Memory { .. } => "memory",
|
|
|
|
Export::Table { .. } => "table",
|
|
|
|
Export::Global { .. } => "global",
|
|
|
|
}
|
|
|
|
.to_string();
|
2019-01-18 21:44:44 +00:00
|
|
|
link_errors.push(LinkError::IncorrectImportType {
|
2019-02-07 00:26:45 +00:00
|
|
|
namespace: namespace.to_string(),
|
|
|
|
name: name.to_string(),
|
2019-01-18 18:54:16 +00:00
|
|
|
expected: "global".to_string(),
|
|
|
|
found: export_type_name,
|
2019-01-18 21:44:44 +00:00
|
|
|
});
|
|
|
|
}
|
|
|
|
None => {
|
|
|
|
link_errors.push(LinkError::ImportNotFound {
|
2019-02-07 00:26:45 +00:00
|
|
|
namespace: namespace.to_string(),
|
|
|
|
name: name.to_string(),
|
2019-01-18 21:44:44 +00:00
|
|
|
});
|
2019-01-08 17:09:47 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2019-01-18 21:44:44 +00:00
|
|
|
|
|
|
|
if link_errors.len() > 0 {
|
|
|
|
Err(link_errors)
|
|
|
|
} else {
|
2019-01-28 19:55:44 +00:00
|
|
|
Ok((globals.into_boxed_map(), vm_globals.into_boxed_map()))
|
2019-01-18 21:44:44 +00:00
|
|
|
}
|
2019-01-08 17:09:47 +00:00
|
|
|
}
|