wasmer/lib/runtime/src/backing.rs

484 lines
19 KiB
Rust
Raw Normal View History

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-16 18:26:10 +00:00
structures::{BoxedMap, Map, SliceMap, TypedIndex},
2019-01-08 17:09:47 +00:00
table::{TableBacking, TableElements},
2019-01-16 18:26:10 +00:00
types::{
ElementType, ImportedFuncIndex, ImportedGlobalIndex, ImportedMemoryIndex,
ImportedTableIndex, Initializer, LocalGlobalIndex, LocalMemoryIndex, LocalOrImport,
LocalTableIndex, Type, Value,
},
2019-01-08 17:09:47 +00:00
vm,
};
2019-01-17 21:09:05 +00:00
use std::{mem, slice};
2019-01-08 17:09:47 +00:00
#[derive(Debug)]
pub struct LocalBacking {
2019-01-16 18:26:10 +00:00
pub(crate) memories: BoxedMap<LocalMemoryIndex, LinearMemory>,
pub(crate) tables: BoxedMap<LocalTableIndex, TableBacking>,
2019-01-08 17:09:47 +00:00
2019-01-16 18:26:10 +00:00
pub(crate) vm_memories: BoxedMap<LocalMemoryIndex, vm::LocalMemory>,
pub(crate) vm_tables: BoxedMap<LocalTableIndex, vm::LocalTable>,
pub(crate) vm_globals: BoxedMap<LocalGlobalIndex, vm::LocalGlobal>,
2019-01-08 17:09:47 +00:00
}
impl LocalBacking {
2019-01-16 18:26:10 +00:00
pub fn memory(&mut self, local_memory_index: LocalMemoryIndex) -> &mut LinearMemory {
&mut self.memories[local_memory_index]
2019-01-13 03:02:19 +00:00
}
2019-01-16 18:26:10 +00:00
pub fn table(&mut self, local_table_index: LocalTableIndex) -> &mut TableBacking {
&mut self.tables[local_table_index]
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);
let globals = Self::generate_globals(module);
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-17 01:59:12 +00:00
let vm_globals = Self::finalize_globals(module, imports, globals);
2019-01-08 17:09:47 +00:00
Self {
memories,
tables,
vm_memories,
vm_tables,
vm_globals,
}
}
2019-01-16 18:26:10 +00:00
fn generate_memories(module: &ModuleInner) -> BoxedMap<LocalMemoryIndex, LinearMemory> {
let mut memories = Map::with_capacity(module.memories.len());
2019-01-08 17:09:47 +00:00
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);
}
2019-01-16 18:26:10 +00:00
memories.into_boxed_map()
2019-01-08 17:09:47 +00:00
}
2019-01-13 03:02:19 +00:00
fn finalize_memories(
module: &ModuleInner,
2019-01-16 18:26:10 +00:00
imports: &ImportBacking,
memories: &mut SliceMap<LocalMemoryIndex, LinearMemory>,
) -> BoxedMap<LocalMemoryIndex, vm::LocalMemory> {
// For each init that has some data...
for init in module
.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"),
Initializer::GetGlobal(imported_global_index) => {
if module.imported_globals[imported_global_index].1.ty == Type::I32 {
unsafe { (*imports.globals[imported_global_index].global).data as u32 }
} else {
panic!("unsupported global type for initialzer")
}
}
} as usize;
2019-01-16 18:26:10 +00:00
match init.memory_index.local_or_import(module) {
LocalOrImport::Local(local_memory_index) => {
let memory_desc = &module.memories[local_memory_index];
2019-01-17 01:59:12 +00:00
let data_top = init_base + init.data.len();
println!("data_top: {}", data_top);
assert!((memory_desc.min * LinearMemory::PAGE_SIZE) as usize >= data_top);
2019-01-16 18:26:10 +00:00
let mem: &mut LinearMemory = &mut memories[local_memory_index];
2019-01-17 21:09:05 +00:00
let mem_init_view = &mut mem[init_base..init_base + init.data.len()];
mem_init_view.copy_from_slice(&init.data);
2019-01-16 18:26:10 +00:00
}
LocalOrImport::Import(imported_memory_index) => {
2019-01-17 21:09:05 +00:00
let vm_imported_memory = imports.imported_memory(imported_memory_index);
unsafe {
let local_memory = &(*vm_imported_memory.memory);
let memory_slice =
slice::from_raw_parts_mut(local_memory.base, local_memory.size);
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-01-17 21:09:05 +00:00
.map(|(index, mem)| mem.into_vm_memory(index))
2019-01-16 18:26:10 +00:00
.collect::<Map<_, _>>()
.into_boxed_map()
2019-01-08 17:09:47 +00:00
}
2019-01-16 18:26:10 +00:00
fn generate_tables(module: &ModuleInner) -> BoxedMap<LocalTableIndex, TableBacking> {
let mut tables = Map::with_capacity(module.tables.len());
2019-01-08 17:09:47 +00:00
for (_, table) in &module.tables {
let table_backing = TableBacking::new(table);
tables.push(table_backing);
}
2019-01-16 18:26:10 +00:00
tables.into_boxed_map()
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-16 18:26:10 +00:00
tables: &mut SliceMap<LocalTableIndex, TableBacking>,
2019-01-11 03:59:57 +00:00
vmctx: *mut vm::Ctx,
2019-01-16 18:26:10 +00:00
) -> BoxedMap<LocalTableIndex, vm::LocalTable> {
2019-01-17 01:59:12 +00:00
for init in &module.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"),
Initializer::GetGlobal(imported_global_index) => {
2019-01-17 01:59:12 +00:00
if module.imported_globals[imported_global_index].1.ty == Type::I32 {
2019-01-16 18:26:10 +00:00
unsafe { (*imports.globals[imported_global_index].global).data as u32 }
} else {
panic!("unsupported global type for initialzer")
}
}
} as usize;
match init.table_index.local_or_import(module) {
LocalOrImport::Local(local_table_index) => {
let table = &mut tables[local_table_index];
match table.elements {
TableElements::Anyfunc(ref mut elements) => {
2019-01-17 21:09:05 +00:00
if elements.len() < init_base + init.elements.len() {
// Grow the table if it's too small.
elements
.resize(init_base + init.elements.len(), vm::Anyfunc::null());
}
2019-01-16 18:26:10 +00:00
for (i, &func_index) in init.elements.iter().enumerate() {
let sig_index = module.func_assoc[func_index];
let sig_id = vm::SigId(sig_index.index() as u32);
let func_data = match func_index.local_or_import(module) {
LocalOrImport::Local(local_func_index) => vm::ImportedFunc {
func: module
.func_resolver
.get(module, local_func_index)
.unwrap()
.as_ptr(),
vmctx,
},
LocalOrImport::Import(imported_func_index) => {
imports.functions[imported_func_index].clone()
}
};
elements[init_base + i] = vm::Anyfunc { func_data, sig_id };
2019-01-08 17:09:47 +00:00
}
2019-01-16 18:26:10 +00:00
}
}
}
LocalOrImport::Import(imported_table_index) => {
let (_, table_description) = module.imported_tables[imported_table_index];
match table_description.ty {
ElementType::Anyfunc => {
2019-01-17 21:09:05 +00:00
let imported_table = &imports.tables[imported_table_index];
let imported_local_table = (*imported_table).table;
let mut elements = unsafe {
Vec::from_raw_parts(
(*imported_local_table).base as *mut vm::Anyfunc,
(*imported_local_table).current_elements,
(*imported_local_table).capacity,
)
};
if elements.len() < init_base + init.elements.len() {
// Grow the table if it's too small.
elements
.resize(init_base + init.elements.len(), vm::Anyfunc::null());
// Since the vector may have changed location after reallocating,
// we must fix the base, current_elements, and capacity fields.
unsafe {
(*imported_local_table).base = elements.as_mut_ptr() as *mut u8;
(*imported_local_table).current_elements = elements.len();
(*imported_local_table).capacity = elements.capacity();
}
}
2019-01-16 18:26:10 +00:00
for (i, &func_index) in init.elements.iter().enumerate() {
let sig_index = module.func_assoc[func_index];
let sig_id = vm::SigId(sig_index.index() as u32);
2019-01-08 17:09:47 +00:00
2019-01-16 18:26:10 +00:00
let func_data = match func_index.local_or_import(module) {
LocalOrImport::Local(local_func_index) => vm::ImportedFunc {
func: module
.func_resolver
.get(module, local_func_index)
.unwrap()
.as_ptr(),
vmctx,
},
LocalOrImport::Import(imported_func_index) => {
imports.functions[imported_func_index].clone()
}
};
2019-01-17 21:09:05 +00:00
elements[init_base + i] = vm::Anyfunc { func_data, sig_id };
2019-01-16 18:26:10 +00:00
}
2019-01-17 21:09:05 +00:00
// println!("imported elements: {:#?}", elements);
// THIS IS EXTREMELY IMPORTANT.
mem::forget(elements);
2019-01-16 18:26:10 +00:00
}
2019-01-08 17:09:47 +00:00
}
}
}
}
tables
.iter_mut()
2019-01-16 18:26:10 +00:00
.map(|(_, table)| table.into_vm_table())
.collect::<Map<_, _>>()
.into_boxed_map()
2019-01-08 17:09:47 +00:00
}
2019-01-16 18:26:10 +00:00
fn generate_globals(module: &ModuleInner) -> BoxedMap<LocalGlobalIndex, vm::LocalGlobal> {
let mut globals = Map::with_capacity(module.globals.len());
globals.resize(module.globals.len(), vm::LocalGlobal::null());
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-13 03:02:19 +00:00
module: &ModuleInner,
2019-01-17 01:59:12 +00:00
imports: &ImportBacking,
2019-01-16 18:26:10 +00:00
mut globals: BoxedMap<LocalGlobalIndex, vm::LocalGlobal>,
) -> BoxedMap<LocalGlobalIndex, vm::LocalGlobal> {
2019-01-17 01:59:12 +00:00
for ((_, to), (_, from)) in globals.iter_mut().zip(module.globals.iter()) {
2019-01-08 17:09:47 +00:00
to.data = match from.init {
2019-01-17 01:59:12 +00:00
Initializer::Const(ref value) => match value {
Value::I32(x) => *x as u64,
Value::I64(x) => *x as u64,
Value::F32(x) => x.to_bits() as u64,
Value::F64(x) => x.to_bits(),
},
Initializer::GetGlobal(imported_global_index) => unsafe {
(*imports.globals[imported_global_index].global).data
},
2019-01-08 17:09:47 +00:00
};
}
globals
}
}
#[derive(Debug)]
pub struct ImportBacking {
2019-01-17 21:09:05 +00:00
pub(crate) functions: BoxedMap<ImportedFuncIndex, vm::ImportedFunc>,
pub(crate) memories: BoxedMap<ImportedMemoryIndex, vm::ImportedMemory>,
pub(crate) tables: BoxedMap<ImportedTableIndex, vm::ImportedTable>,
pub(crate) globals: BoxedMap<ImportedGlobalIndex, vm::ImportedGlobal>,
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-01-13 21:44:14 +00:00
imports: &mut Imports,
2019-01-11 03:59:57 +00:00
vmctx: *mut vm::Ctx,
) -> Result<Self, String> {
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)?,
globals: import_globals(module, imports)?,
})
}
2019-01-17 21:09:05 +00:00
pub fn imported_memory(&self, memory_index: ImportedMemoryIndex) -> vm::ImportedMemory {
self.memories[memory_index].clone()
}
}
2019-01-16 18:26:10 +00:00
fn import_functions(
2019-01-13 03:02:19 +00:00
module: &ModuleInner,
2019-01-13 21:44:14 +00:00
imports: &mut Imports,
2019-01-12 20:34:23 +00:00
vmctx: *mut vm::Ctx,
2019-01-16 18:26:10 +00:00
) -> Result<BoxedMap<ImportedFuncIndex, vm::ImportedFunc>, String> {
let mut functions = Map::with_capacity(module.imported_functions.len());
for (index, ImportName { namespace, name }) in &module.imported_functions {
let sig_index = module.func_assoc[index.convert_up(module)];
let expected_sig = module.sig_registry.lookup_func_sig(sig_index);
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-01-16 18:26:10 +00:00
if expected_sig == &signature {
functions.push(vm::ImportedFunc {
func: func.inner(),
vmctx: match ctx {
Context::External(ctx) => ctx,
Context::Internal => vmctx,
},
});
} else {
return Err(format!(
2019-01-16 18:26:10 +00:00
"unexpected signature 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 => {
return Err(format!("import not found: {}:{}", namespace, name));
2019-01-12 20:34:23 +00:00
}
}
}
2019-01-16 18:26:10 +00:00
Ok(functions.into_boxed_map())
2019-01-12 20:34: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-01-13 21:52:25 +00:00
imports: &mut Imports,
2019-01-13 16:46:04 +00:00
vmctx: *mut vm::Ctx,
2019-01-16 18:26:10 +00:00
) -> Result<BoxedMap<ImportedMemoryIndex, vm::ImportedMemory>, String> {
let mut memories = Map::with_capacity(module.imported_memories.len());
for (_index, (ImportName { namespace, name }, expected_memory_desc)) in
&module.imported_memories
{
let memory_import = imports
2019-01-13 21:52:25 +00:00
.get_namespace(namespace)
.and_then(|namespace| namespace.get_export(name));
2019-01-16 18:26:10 +00:00
match memory_import {
Some(Export::Memory {
2019-01-13 21:52:25 +00:00
local,
ctx,
2019-01-16 18:26:10 +00:00
memory: memory_desc,
2019-01-13 21:52:25 +00:00
}) => {
2019-01-16 18:26:10 +00:00
if expected_memory_desc.fits_in_imported(&memory_desc) {
memories.push(vm::ImportedMemory {
memory: local.inner(),
2019-01-13 21:52:25 +00:00
vmctx: match ctx {
Context::External(ctx) => ctx,
Context::Internal => vmctx,
},
});
} else {
return Err(format!(
2019-01-16 18:26:10 +00:00
"incorrect memory description for {}:{}",
2019-01-13 21:52:25 +00:00
namespace, name,
));
2019-01-13 16:46:04 +00:00
}
}
2019-01-13 21:52:25 +00:00
Some(_) => {
return Err(format!("incorrect import type for {}:{}", namespace, name));
}
None => {
return Err(format!("import not found: {}:{}", namespace, name));
}
2019-01-13 16:46:04 +00:00
}
2019-01-13 21:52:25 +00:00
}
2019-01-16 18:26:10 +00:00
Ok(memories.into_boxed_map())
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-01-13 21:44:14 +00:00
imports: &mut Imports,
2019-01-11 03:59:57 +00:00
vmctx: *mut vm::Ctx,
2019-01-16 18:26:10 +00:00
) -> Result<BoxedMap<ImportedTableIndex, vm::ImportedTable>, String> {
let mut tables = Map::with_capacity(module.imported_tables.len());
for (_index, (ImportName { namespace, name }, expected_table_desc)) in &module.imported_tables {
let table_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 table_import {
Some(Export::Table {
local,
2019-01-11 03:59:57 +00:00
ctx,
2019-01-16 18:26:10 +00:00
table: table_desc,
2019-01-11 03:59:57 +00:00
}) => {
2019-01-16 18:26:10 +00:00
if expected_table_desc.fits_in_imported(&table_desc) {
tables.push(vm::ImportedTable {
table: local.inner(),
2019-01-11 03:59:57 +00:00
vmctx: match ctx {
Context::External(ctx) => ctx,
Context::Internal => vmctx,
},
});
} else {
2019-01-08 17:09:47 +00:00
return Err(format!(
2019-01-16 18:26:10 +00:00
"incorrect table description for {}:{}",
namespace, name,
2019-01-08 17:09:47 +00:00
));
}
}
Some(_) => {
2019-01-11 03:59:57 +00:00
return Err(format!("incorrect import type for {}:{}", namespace, name));
}
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-16 18:26:10 +00:00
Ok(tables.into_boxed_map())
}
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-01-13 21:44:14 +00:00
imports: &mut Imports,
2019-01-16 18:26:10 +00:00
) -> Result<BoxedMap<ImportedGlobalIndex, vm::ImportedGlobal>, String> {
let mut globals = Map::with_capacity(module.imported_globals.len());
2019-01-17 01:59:12 +00:00
for (_, (ImportName { namespace, name }, imported_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));
match import {
2019-01-11 03:59:57 +00:00
Some(Export::Global { local, global }) => {
2019-01-17 01:59:12 +00:00
if global == *imported_global_desc {
2019-01-12 22:53:17 +00:00
globals.push(vm::ImportedGlobal {
global: local.inner(),
});
} 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
));
}
}
Some(_) => {
2019-01-11 03:59:57 +00:00
return Err(format!("incorrect import type for {}:{}", namespace, name));
}
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-16 18:26:10 +00:00
Ok(globals.into_boxed_map())
2019-01-08 17:09:47 +00:00
}