mirror of
https://github.com/fluencelabs/wasmer
synced 2025-03-16 08:10:49 +00:00
Local/Import index differentiation
This commit is contained in:
parent
de1da689f8
commit
5872d879f9
@ -25,9 +25,9 @@ use wasmer_runtime::{
|
||||
types::{
|
||||
ElementType as WasmerElementType, FuncIndex as WasmerFuncIndex, FuncSig as WasmerSignature,
|
||||
Global as WasmerGlobal, GlobalDesc as WasmerGlobalDesc, GlobalIndex as WasmerGlobalIndex,
|
||||
Initializer as WasmerInitializer, Map, MapIndex, Memory as WasmerMemory,
|
||||
MemoryIndex as WasmerMemoryIndex, SigIndex as WasmerSignatureIndex, Table as WasmerTable,
|
||||
TableIndex as WasmerTableIndex, Type as WasmerType,
|
||||
GlobalInit as WasmerGlobalInit, Initializer as WasmerInitializer, Map,
|
||||
Memory as WasmerMemory, MemoryIndex as WasmerMemoryIndex, SigIndex as WasmerSignatureIndex,
|
||||
Table as WasmerTable, TableIndex as WasmerTableIndex, Type as WasmerType, TypedIndex,
|
||||
},
|
||||
vm::{self, Ctx as WasmerVMContext},
|
||||
};
|
||||
@ -142,14 +142,14 @@ pub mod converter {
|
||||
|
||||
// TODO: WasmerGlobal does not support `Import` as Global values.
|
||||
let init = match global.initializer {
|
||||
I32Const(val) => Const(val.into()),
|
||||
I64Const(val) => Const(val.into()),
|
||||
F32Const(val) => Const(f32::from_bits(val).into()),
|
||||
F64Const(val) => Const(f64::from_bits(val).into()),
|
||||
GlobalInit::GetGlobal(index) => {
|
||||
WasmerInitializer::GetGlobal(WasmerGlobalIndex::new(index.index()))
|
||||
},
|
||||
GlobalInit::Import => WasmerInitializer::Import
|
||||
I32Const(val) => WasmerGlobalInit::Init(Const(val.into())),
|
||||
I64Const(val) => WasmerGlobalInit::Init(Const(val.into())),
|
||||
F32Const(val) => WasmerGlobalInit::Init(Const(f32::from_bits(val).into())),
|
||||
F64Const(val) => WasmerGlobalInit::Init(Const(f64::from_bits(val).into())),
|
||||
GlobalInit::GetGlobal(index) => WasmerGlobalInit::Init(WasmerInitializer::GetGlobal(
|
||||
WasmerGlobalIndex::new(index.index()),
|
||||
)),
|
||||
GlobalInit::Import => WasmerGlobalInit::Import,
|
||||
};
|
||||
|
||||
WasmerGlobal { desc, init }
|
||||
@ -173,6 +173,7 @@ pub mod converter {
|
||||
|
||||
/// Converts a Cranelift table to a Wasmer table.
|
||||
pub fn convert_memory(memory: Memory) -> WasmerMemory {
|
||||
println!("codegen memory: {:?}", memory);
|
||||
WasmerMemory {
|
||||
shared: memory.shared,
|
||||
min: memory.minimum,
|
||||
@ -350,29 +351,71 @@ impl<'environment> FuncEnvironmentTrait for FuncEnvironment<'environment> {
|
||||
/// by `index`.
|
||||
///
|
||||
/// The index space covers both imported and locally declared globals.
|
||||
fn make_global(&mut self, func: &mut ir::Function, index: GlobalIndex) -> GlobalVariable {
|
||||
fn make_global(
|
||||
&mut self,
|
||||
func: &mut ir::Function,
|
||||
global_index: GlobalIndex,
|
||||
) -> GlobalVariable {
|
||||
// Create VMContext value.
|
||||
let vmctx = func.create_global_value(ir::GlobalValueData::VMContext);
|
||||
let ptr_size = self.pointer_bytes();
|
||||
let globals_offset = WasmerVMContext::offset_globals();
|
||||
|
||||
// Load value at (vmctx + globals_offset), i.e. the address at Ctx.globals.
|
||||
let globals_base_addr = func.create_global_value(ir::GlobalValueData::Load {
|
||||
base: vmctx,
|
||||
offset: Offset32::new(globals_offset as i32),
|
||||
global_type: self.pointer_type(),
|
||||
readonly: false,
|
||||
});
|
||||
if global_index.index() < self.module.imported_globals.len() {
|
||||
// imported global
|
||||
|
||||
// *Ctx.globals -> [ u8, u8, .. ]
|
||||
// Based on the index provided, we need to know the offset into globals array
|
||||
let offset = index.index() * ptr_size as usize;
|
||||
let imported_globals_base_addr = func.create_global_value(ir::GlobalValueData::Load {
|
||||
base: vmctx,
|
||||
offset: (vm::Ctx::offset_imported_globals() as i32).into(),
|
||||
global_type: self.pointer_type(),
|
||||
readonly: true,
|
||||
});
|
||||
|
||||
// Create global variable based on the data above.
|
||||
GlobalVariable::Memory {
|
||||
gv: globals_base_addr,
|
||||
offset: (offset as i32).into(),
|
||||
ty: self.module.get_global(index).ty,
|
||||
let offset = global_index.index() * vm::ImportedGlobal::size() as usize;
|
||||
|
||||
let imported_global_addr = func.create_global_value(ir::GlobalValueData::IAddImm {
|
||||
base: imported_globals_base_addr,
|
||||
offset: (offset as i64).into(),
|
||||
global_type: self.pointer_type(),
|
||||
});
|
||||
|
||||
let local_global_addr = func.create_global_value(ir::GlobalValueData::Load {
|
||||
base: imported_global_addr,
|
||||
offset: (vm::ImportedGlobal::offset_global() as i32).into(),
|
||||
global_type: self.pointer_type(),
|
||||
readonly: true,
|
||||
});
|
||||
|
||||
GlobalVariable::Memory {
|
||||
gv: local_global_addr,
|
||||
offset: (vm::LocalGlobal::offset_data() as i32).into(),
|
||||
ty: self.module.get_global(global_index).ty,
|
||||
}
|
||||
} else {
|
||||
// locally defined global
|
||||
|
||||
let globals_base_addr = func.create_global_value(ir::GlobalValueData::Load {
|
||||
base: vmctx,
|
||||
offset: (vm::Ctx::offset_globals() as i32).into(),
|
||||
global_type: self.pointer_type(),
|
||||
readonly: true,
|
||||
});
|
||||
|
||||
// *Ctx.globals -> [ u8, u8, .. ]
|
||||
// Based on the index provided, we need to know the offset into globals array
|
||||
let offset = (global_index.index() - self.module.imported_globals.len())
|
||||
* vm::LocalGlobal::size() as usize;
|
||||
|
||||
let local_global_addr = func.create_global_value(ir::GlobalValueData::IAddImm {
|
||||
base: globals_base_addr,
|
||||
offset: (offset as i64).into(),
|
||||
global_type: self.pointer_type(),
|
||||
});
|
||||
|
||||
// Create global variable based on the data above.
|
||||
GlobalVariable::Memory {
|
||||
gv: local_global_addr,
|
||||
offset: (vm::LocalGlobal::offset_data() as i32).into(),
|
||||
ty: self.module.get_global(global_index).ty,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -870,13 +913,18 @@ impl<'data> ModuleEnvironment<'data> for CraneliftModule {
|
||||
elements: Vec<FuncIndex>,
|
||||
) {
|
||||
// Convert Cranelift GlobalIndex to wamser GlobalIndex
|
||||
let base = base.map(|index| WasmerGlobalIndex::new(index.index()));
|
||||
// let base = base.map(|index| WasmerGlobalIndex::new(index.index()));
|
||||
let base = match base {
|
||||
Some(global_index) => {
|
||||
WasmerInitializer::GetGlobal(WasmerGlobalIndex::new(global_index.index()))
|
||||
}
|
||||
None => WasmerInitializer::Const((offset as i32).into()),
|
||||
};
|
||||
|
||||
// Add table initializer to list of table initializers
|
||||
self.table_initializers.push(TableInitializer {
|
||||
table_index: WasmerTableIndex::new(table_index.index()),
|
||||
base,
|
||||
offset,
|
||||
elements: elements
|
||||
.iter()
|
||||
.map(|index| WasmerFuncIndex::new(index.index()))
|
||||
|
@ -2,6 +2,7 @@ pub mod codegen;
|
||||
mod libcalls;
|
||||
mod relocation;
|
||||
mod resolver;
|
||||
// mod module;
|
||||
|
||||
use cranelift_codegen::{
|
||||
isa,
|
||||
|
20
lib/clif-backend/src/module.rs
Normal file
20
lib/clif-backend/src/module.rs
Normal file
@ -0,0 +1,20 @@
|
||||
use wasmer_runtime::{
|
||||
backend::SigRegistry,
|
||||
memory::LinearMemory,
|
||||
module::{
|
||||
DataInitializer, ExportIndex, ImportName, ModuleInner, TableInitializer,
|
||||
},
|
||||
types::{
|
||||
ElementType, FuncIndex, FuncSig,
|
||||
Global, GlobalDesc, GlobalIndex,
|
||||
Initializer, Map, TypedIndex, Memory,
|
||||
MemoryIndex as WasmerMemoryIndex, SigIndex as WasmerSignatureIndex, Table as WasmerTable,
|
||||
TableIndex as WasmerTableIndex, Type as WasmerType, GlobalInit as WasmerGlobalInit,
|
||||
},
|
||||
vm::{self, Ctx as WasmerVMContext},
|
||||
};
|
||||
|
||||
/// This is a wasmer module.
|
||||
pub struct Module {
|
||||
|
||||
}
|
@ -7,15 +7,15 @@ use std::ptr::{write_unaligned, NonNull};
|
||||
use wasmer_runtime::{
|
||||
self,
|
||||
backend::{self, Mmap, Protect},
|
||||
types::{FuncIndex, Map, MapIndex},
|
||||
types::{LocalFuncIndex, Map, TypedIndex},
|
||||
vm, vmcalls,
|
||||
};
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub struct FuncResolverBuilder {
|
||||
resolver: FuncResolver,
|
||||
relocations: Map<FuncIndex, Vec<Relocation>>,
|
||||
trap_sinks: Map<FuncIndex, TrapSink>,
|
||||
relocations: Map<LocalFuncIndex, Vec<Relocation>>,
|
||||
trap_sinks: Map<LocalFuncIndex, TrapSink>,
|
||||
}
|
||||
|
||||
impl FuncResolverBuilder {
|
||||
@ -158,15 +158,13 @@ impl FuncResolverBuilder {
|
||||
/// Resolves a function index to a function address.
|
||||
pub struct FuncResolver {
|
||||
num_imported_funcs: usize,
|
||||
map: Map<FuncIndex, usize>,
|
||||
map: Map<LocalFuncIndex, usize>,
|
||||
memory: Mmap,
|
||||
}
|
||||
|
||||
impl FuncResolver {
|
||||
fn lookup(&self, index: FuncIndex) -> Option<NonNull<vm::Func>> {
|
||||
let offset = *self
|
||||
.map
|
||||
.get(FuncIndex::new(index.index() - self.num_imported_funcs))?;
|
||||
fn lookup(&self, local_func_index: LocalFuncIndex) -> Option<NonNull<vm::Func>> {
|
||||
let offset = *self.map.get(local_func_index)?;
|
||||
let ptr = unsafe { self.memory.as_ptr().add(offset) };
|
||||
|
||||
NonNull::new(ptr).map(|nonnull| nonnull.cast())
|
||||
|
@ -88,8 +88,8 @@ static IMPORT_MODULE: &str = r#"
|
||||
(type $t1 (func))
|
||||
(func $print_i32 (export "print_i32") (type $t0) (param $lhs i32))
|
||||
(func $print (export "print") (type $t1))
|
||||
(table $table (export "table") 10 anyfunc)
|
||||
(memory $memory (export "memory") 1)
|
||||
(table $table (export "table") 10 20 anyfunc)
|
||||
(memory $memory (export "memory") 1 2)
|
||||
(global $global_i32 (export "global_i32") i32 (i32.const 666)))
|
||||
"#;
|
||||
|
||||
@ -350,6 +350,7 @@ fn test_module_{}() {{
|
||||
format!(
|
||||
"fn create_module_{}() -> Instance {{
|
||||
let module_str = \"{}\";
|
||||
println!(\"{{}}\", module_str);
|
||||
let wasm_binary = wat2wasm(module_str.as_bytes()).expect(\"WAST not valid or malformed\");
|
||||
let module = wasmer_runtime::compile(&wasm_binary[..], &CraneliftCompiler::new()).expect(\"WASM can't be compiled\");
|
||||
module.instantiate(&mut generate_imports()).expect(\"WASM can't be instantiated\")
|
||||
|
@ -1,4 +1,4 @@
|
||||
use crate::{module::ModuleInner, types::FuncIndex, vm};
|
||||
use crate::{module::ModuleInner, types::LocalFuncIndex, vm};
|
||||
use std::ptr::NonNull;
|
||||
|
||||
pub use crate::mmap::{Mmap, Protect};
|
||||
@ -10,5 +10,9 @@ pub trait Compiler {
|
||||
}
|
||||
|
||||
pub trait FuncResolver {
|
||||
fn get(&self, module: &ModuleInner, index: FuncIndex) -> Option<NonNull<vm::Func>>;
|
||||
fn get(
|
||||
&self,
|
||||
module: &ModuleInner,
|
||||
local_func_index: LocalFuncIndex,
|
||||
) -> Option<NonNull<vm::Func>>;
|
||||
}
|
||||
|
@ -3,28 +3,34 @@ use crate::{
|
||||
import::Imports,
|
||||
memory::LinearMemory,
|
||||
module::{ImportName, ModuleInner},
|
||||
structures::{BoxedMap, Map, SliceMap, TypedIndex},
|
||||
table::{TableBacking, TableElements},
|
||||
types::{Initializer, MapIndex, Value},
|
||||
types::{
|
||||
ElementType, ImportedFuncIndex, ImportedGlobalIndex, ImportedMemoryIndex,
|
||||
ImportedTableIndex, Initializer, LocalGlobalIndex, LocalMemoryIndex, LocalOrImport,
|
||||
LocalTableIndex, Type, Value,
|
||||
},
|
||||
vm,
|
||||
};
|
||||
use std::slice;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct LocalBacking {
|
||||
pub(crate) memories: Box<[LinearMemory]>,
|
||||
pub(crate) tables: Box<[TableBacking]>,
|
||||
pub(crate) memories: BoxedMap<LocalMemoryIndex, LinearMemory>,
|
||||
pub(crate) tables: BoxedMap<LocalTableIndex, TableBacking>,
|
||||
|
||||
pub(crate) vm_memories: Box<[vm::LocalMemory]>,
|
||||
pub(crate) vm_tables: Box<[vm::LocalTable]>,
|
||||
pub(crate) vm_globals: Box<[vm::LocalGlobal]>,
|
||||
pub(crate) vm_memories: BoxedMap<LocalMemoryIndex, vm::LocalMemory>,
|
||||
pub(crate) vm_tables: BoxedMap<LocalTableIndex, vm::LocalTable>,
|
||||
pub(crate) vm_globals: BoxedMap<LocalGlobalIndex, vm::LocalGlobal>,
|
||||
}
|
||||
|
||||
impl LocalBacking {
|
||||
pub fn memory(&mut self, index: u32) -> &mut LinearMemory {
|
||||
&mut self.memories[index as usize]
|
||||
pub fn memory(&mut self, local_memory_index: LocalMemoryIndex) -> &mut LinearMemory {
|
||||
&mut self.memories[local_memory_index]
|
||||
}
|
||||
|
||||
pub fn table(&mut self, index: u32) -> &mut TableBacking {
|
||||
&mut self.tables[index as usize]
|
||||
pub fn table(&mut self, local_table_index: LocalTableIndex) -> &mut TableBacking {
|
||||
&mut self.tables[local_table_index]
|
||||
}
|
||||
}
|
||||
|
||||
@ -34,9 +40,9 @@ impl LocalBacking {
|
||||
let mut tables = Self::generate_tables(module);
|
||||
let globals = Self::generate_globals(module);
|
||||
|
||||
let vm_memories = Self::finalize_memories(module, &mut memories[..]);
|
||||
let vm_tables = Self::finalize_tables(module, imports, &mut tables[..], vmctx);
|
||||
let vm_globals = Self::finalize_globals(module, imports, globals);
|
||||
let vm_memories = Self::finalize_memories(module, imports, &mut memories);
|
||||
let vm_tables = Self::finalize_tables(module, imports, &mut tables, vmctx);
|
||||
let vm_globals = Self::finalize_globals(module, globals);
|
||||
|
||||
Self {
|
||||
memories,
|
||||
@ -48,8 +54,8 @@ impl LocalBacking {
|
||||
}
|
||||
}
|
||||
|
||||
fn generate_memories(module: &ModuleInner) -> Box<[LinearMemory]> {
|
||||
let mut memories = Vec::with_capacity(module.memories.len());
|
||||
fn generate_memories(module: &ModuleInner) -> BoxedMap<LocalMemoryIndex, LinearMemory> {
|
||||
let mut memories = Map::with_capacity(module.memories.len());
|
||||
|
||||
for (_, mem) in &module.memories {
|
||||
// If we use emscripten, we set a fixed initial and maximum
|
||||
@ -66,75 +72,155 @@ impl LocalBacking {
|
||||
memories.push(memory);
|
||||
}
|
||||
|
||||
memories.into_boxed_slice()
|
||||
memories.into_boxed_map()
|
||||
}
|
||||
|
||||
fn finalize_memories(
|
||||
module: &ModuleInner,
|
||||
memories: &mut [LinearMemory],
|
||||
) -> Box<[vm::LocalMemory]> {
|
||||
for init in &module.data_initializers {
|
||||
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)
|
||||
{
|
||||
assert!(init.base.is_none(), "global base not supported yet");
|
||||
assert!(init.offset + init.data.len() <= memories[init.memory_index.index()].size());
|
||||
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);
|
||||
|
||||
match init.memory_index.local_or_import(module) {
|
||||
LocalOrImport::Local(local_memory_index) => {
|
||||
let memory_desc = &module.memories[local_memory_index];
|
||||
let data_top = init.offset + init.data.len();
|
||||
assert!(memory_desc.min as usize >= data_top);
|
||||
let mem: &mut LinearMemory = &mut memories[local_memory_index];
|
||||
|
||||
let to_init = &mut mem[init.offset..init.offset + init.data.len()];
|
||||
to_init.copy_from_slice(&init.data);
|
||||
}
|
||||
LocalOrImport::Import(imported_memory_index) => {
|
||||
let _ = imported_memory_index;
|
||||
let _ = imports;
|
||||
unimplemented!()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
memories
|
||||
.iter_mut()
|
||||
.map(|mem| mem.into_vm_memory())
|
||||
.collect::<Vec<_>>()
|
||||
.into_boxed_slice()
|
||||
.map(|(_, mem)| mem.into_vm_memory())
|
||||
.collect::<Map<_, _>>()
|
||||
.into_boxed_map()
|
||||
}
|
||||
|
||||
fn generate_tables(module: &ModuleInner) -> Box<[TableBacking]> {
|
||||
let mut tables = Vec::with_capacity(module.tables.len());
|
||||
fn generate_tables(module: &ModuleInner) -> BoxedMap<LocalTableIndex, TableBacking> {
|
||||
let mut tables = Map::with_capacity(module.tables.len());
|
||||
|
||||
for (_, table) in &module.tables {
|
||||
let table_backing = TableBacking::new(table);
|
||||
tables.push(table_backing);
|
||||
}
|
||||
|
||||
tables.into_boxed_slice()
|
||||
tables.into_boxed_map()
|
||||
}
|
||||
|
||||
fn finalize_tables(
|
||||
module: &ModuleInner,
|
||||
imports: &ImportBacking,
|
||||
tables: &mut [TableBacking],
|
||||
tables: &mut SliceMap<LocalTableIndex, TableBacking>,
|
||||
vmctx: *mut vm::Ctx,
|
||||
) -> Box<[vm::LocalTable]> {
|
||||
) -> BoxedMap<LocalTableIndex, 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];
|
||||
let sig_id = vm::SigId(sig_index.index() as u32);
|
||||
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.desc.ty == Type::I32 {
|
||||
unsafe { (*imports.globals[imported_global_index].global).data as u32 }
|
||||
} else {
|
||||
panic!("unsupported global type for initialzer")
|
||||
}
|
||||
}
|
||||
} as usize;
|
||||
|
||||
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(),
|
||||
vmctx,
|
||||
assert!(
|
||||
init_base + init.elements.len()
|
||||
<= match init.table_index.local_or_import(module) {
|
||||
LocalOrImport::Local(local_table_index) => {
|
||||
module.tables[local_table_index].min
|
||||
}
|
||||
LocalOrImport::Import(imported_table_index) => {
|
||||
let (_, table_desc) = module.imported_tables[imported_table_index];
|
||||
table_desc.min
|
||||
}
|
||||
} 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) => {
|
||||
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 };
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
LocalOrImport::Import(imported_table_index) => {
|
||||
let imported_table = &imports.tables[imported_table_index];
|
||||
|
||||
elements[init.offset + i] = vm::Anyfunc { func_data, sig_id };
|
||||
let imported_local_table_slice = unsafe {
|
||||
let imported_local_table = (*imported_table).table;
|
||||
|
||||
slice::from_raw_parts_mut(
|
||||
(*imported_local_table).base as *mut vm::Anyfunc,
|
||||
(*imported_local_table).current_elements,
|
||||
)
|
||||
};
|
||||
|
||||
let (_, table_description) = module.imported_tables[imported_table_index];
|
||||
match table_description.ty {
|
||||
ElementType::Anyfunc => {
|
||||
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()
|
||||
}
|
||||
};
|
||||
|
||||
imported_local_table_slice[init_base + i] =
|
||||
vm::Anyfunc { func_data, sig_id };
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -142,34 +228,29 @@ impl LocalBacking {
|
||||
|
||||
tables
|
||||
.iter_mut()
|
||||
.map(|table| table.into_vm_table())
|
||||
.collect::<Vec<_>>()
|
||||
.into_boxed_slice()
|
||||
.map(|(_, table)| table.into_vm_table())
|
||||
.collect::<Map<_, _>>()
|
||||
.into_boxed_map()
|
||||
}
|
||||
|
||||
fn generate_globals(module: &ModuleInner) -> Box<[vm::LocalGlobal]> {
|
||||
let globals = vec![vm::LocalGlobal::null(); module.globals.len()];
|
||||
fn generate_globals(module: &ModuleInner) -> BoxedMap<LocalGlobalIndex, vm::LocalGlobal> {
|
||||
let mut globals = Map::with_capacity(module.globals.len());
|
||||
|
||||
globals.into_boxed_slice()
|
||||
globals.resize(module.globals.len(), vm::LocalGlobal::null());
|
||||
|
||||
globals.into_boxed_map()
|
||||
}
|
||||
|
||||
fn finalize_globals(
|
||||
module: &ModuleInner,
|
||||
imports: &ImportBacking,
|
||||
mut globals: Box<[vm::LocalGlobal]>,
|
||||
) -> Box<[vm::LocalGlobal]> {
|
||||
for (to, (global_index, from)) in globals.iter_mut().zip(module.globals.into_iter()) {
|
||||
mut globals: BoxedMap<LocalGlobalIndex, vm::LocalGlobal>,
|
||||
) -> BoxedMap<LocalGlobalIndex, 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,
|
||||
Initializer::Const(Value::F32(x)) => x.to_bits() as u64,
|
||||
Initializer::Const(Value::F64(x)) => x.to_bits(),
|
||||
Initializer::GetGlobal(index) => unsafe {
|
||||
(*imports.globals[index.index()].global).data
|
||||
},
|
||||
Initializer::Import => unsafe {
|
||||
(*imports.globals[global_index.index()].global).data
|
||||
},
|
||||
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(),
|
||||
};
|
||||
}
|
||||
|
||||
@ -179,10 +260,10 @@ impl LocalBacking {
|
||||
|
||||
#[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]>,
|
||||
pub functions: BoxedMap<ImportedFuncIndex, vm::ImportedFunc>,
|
||||
pub memories: BoxedMap<ImportedMemoryIndex, vm::ImportedMemory>,
|
||||
pub tables: BoxedMap<ImportedTableIndex, vm::ImportedTable>,
|
||||
pub globals: BoxedMap<ImportedGlobalIndex, vm::ImportedGlobal>,
|
||||
}
|
||||
|
||||
impl ImportBacking {
|
||||
@ -200,12 +281,56 @@ impl ImportBacking {
|
||||
}
|
||||
}
|
||||
|
||||
fn import_functions(
|
||||
module: &ModuleInner,
|
||||
imports: &mut Imports,
|
||||
vmctx: *mut vm::Ctx,
|
||||
) -> 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
|
||||
.get_namespace(namespace)
|
||||
.and_then(|namespace| namespace.get_export(name));
|
||||
match import {
|
||||
Some(Export::Function {
|
||||
func,
|
||||
ctx,
|
||||
signature,
|
||||
}) => {
|
||||
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!(
|
||||
"unexpected signature for {:?}:{:?}",
|
||||
namespace, name
|
||||
));
|
||||
}
|
||||
}
|
||||
Some(_) => {
|
||||
return Err(format!("incorrect import type for {}:{}", namespace, name));
|
||||
}
|
||||
None => {
|
||||
return Err(format!("import not found: {}:{}", namespace, name));
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(functions.into_boxed_map())
|
||||
}
|
||||
|
||||
fn import_memories(
|
||||
module: &ModuleInner,
|
||||
imports: &mut Imports,
|
||||
vmctx: *mut vm::Ctx,
|
||||
) -> Result<Box<[vm::ImportedMemory]>, String> {
|
||||
let mut memories = Vec::with_capacity(module.imported_memories.len());
|
||||
) -> 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
|
||||
{
|
||||
@ -241,15 +366,15 @@ fn import_memories(
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(memories.into_boxed_slice())
|
||||
Ok(memories.into_boxed_map())
|
||||
}
|
||||
|
||||
fn import_tables(
|
||||
module: &ModuleInner,
|
||||
imports: &mut Imports,
|
||||
vmctx: *mut vm::Ctx,
|
||||
) -> Result<Box<[vm::ImportedTable]>, String> {
|
||||
let mut tables = Vec::with_capacity(module.imported_tables.len());
|
||||
) -> 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
|
||||
.get_namespace(namespace)
|
||||
@ -283,65 +408,21 @@ fn import_tables(
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(tables.into_boxed_slice())
|
||||
}
|
||||
|
||||
fn import_functions(
|
||||
module: &ModuleInner,
|
||||
imports: &mut Imports,
|
||||
vmctx: *mut vm::Ctx,
|
||||
) -> Result<Box<[vm::ImportedFunc]>, String> {
|
||||
let mut functions = Vec::with_capacity(module.imported_functions.len());
|
||||
for (index, ImportName { namespace, name }) in &module.imported_functions {
|
||||
let sig_index = module.func_assoc[index];
|
||||
let expected_sig = module.sig_registry.lookup_func_sig(sig_index);
|
||||
let import = imports
|
||||
.get_namespace(namespace)
|
||||
.and_then(|namespace| namespace.get_export(name));
|
||||
match import {
|
||||
Some(Export::Function {
|
||||
func,
|
||||
ctx,
|
||||
signature,
|
||||
}) => {
|
||||
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!(
|
||||
"unexpected signature for {:?}:{:?}",
|
||||
namespace, name
|
||||
));
|
||||
}
|
||||
}
|
||||
Some(_) => {
|
||||
return Err(format!("incorrect import type for {}:{}", namespace, name));
|
||||
}
|
||||
None => {
|
||||
return Err(format!("import not found: {}:{}", namespace, name));
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(functions.into_boxed_slice())
|
||||
Ok(tables.into_boxed_map())
|
||||
}
|
||||
|
||||
fn import_globals(
|
||||
module: &ModuleInner,
|
||||
imports: &mut Imports,
|
||||
) -> Result<Box<[vm::ImportedGlobal]>, String> {
|
||||
let mut globals = Vec::with_capacity(module.imported_globals.len());
|
||||
for (_, (ImportName { namespace, name }, global_desc)) in &module.imported_globals {
|
||||
) -> Result<BoxedMap<ImportedGlobalIndex, vm::ImportedGlobal>, String> {
|
||||
let mut globals = Map::with_capacity(module.imported_globals.len());
|
||||
for (_, (ImportName { namespace, name }, imported_global)) in &module.imported_globals {
|
||||
let import = imports
|
||||
.get_namespace(namespace)
|
||||
.and_then(|namespace| namespace.get_export(name));
|
||||
match import {
|
||||
Some(Export::Global { local, global }) => {
|
||||
if &global == global_desc {
|
||||
if global == imported_global.desc {
|
||||
globals.push(vm::ImportedGlobal {
|
||||
global: local.inner(),
|
||||
});
|
||||
@ -360,5 +441,5 @@ fn import_globals(
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(globals.into_boxed_slice())
|
||||
Ok(globals.into_boxed_map())
|
||||
}
|
||||
|
@ -7,7 +7,7 @@ use crate::{
|
||||
import::{Imports, Namespace},
|
||||
module::{ExportIndex, Module, ModuleInner},
|
||||
types::{
|
||||
FuncIndex, FuncSig, GlobalDesc, GlobalIndex, MapIndex, Memory, MemoryIndex, Table,
|
||||
FuncIndex, FuncSig, GlobalDesc, GlobalIndex, LocalOrImport, Memory, MemoryIndex, Table,
|
||||
TableIndex, Type, Value,
|
||||
},
|
||||
vm,
|
||||
@ -202,22 +202,23 @@ impl InstanceInner {
|
||||
.get(func_index)
|
||||
.expect("broken invariant, incorrect func index");
|
||||
|
||||
let (func_ptr, ctx) = if module.is_imported_function(func_index) {
|
||||
let imported_func = &self.import_backing.functions[func_index.index()];
|
||||
(
|
||||
imported_func.func as *const _,
|
||||
Context::External(imported_func.vmctx),
|
||||
)
|
||||
} else {
|
||||
(
|
||||
let (func_ptr, ctx) = match func_index.local_or_import(module) {
|
||||
LocalOrImport::Local(local_func_index) => (
|
||||
module
|
||||
.func_resolver
|
||||
.get(&module, func_index)
|
||||
.get(&module, local_func_index)
|
||||
.expect("broken invariant, func resolver not synced with module.exports")
|
||||
.cast()
|
||||
.as_ptr() as *const _,
|
||||
Context::Internal,
|
||||
)
|
||||
),
|
||||
LocalOrImport::Import(imported_func_index) => {
|
||||
let imported_func = &self.import_backing.functions[imported_func_index];
|
||||
(
|
||||
imported_func.func as *const _,
|
||||
Context::External(imported_func.vmctx),
|
||||
)
|
||||
}
|
||||
};
|
||||
|
||||
let signature = module.sig_registry.lookup_func_sig(sig_index).clone();
|
||||
@ -230,28 +231,31 @@ impl InstanceInner {
|
||||
module: &ModuleInner,
|
||||
mem_index: MemoryIndex,
|
||||
) -> (MemoryPointer, Context, Memory) {
|
||||
if module.is_imported_memory(mem_index) {
|
||||
let &(_, mem) = &module
|
||||
.imported_memories
|
||||
.get(mem_index)
|
||||
.expect("missing imported memory index");
|
||||
let vm::ImportedMemory { memory, vmctx } =
|
||||
&self.import_backing.memories[mem_index.index()];
|
||||
(
|
||||
unsafe { MemoryPointer::new(*memory) },
|
||||
Context::External(*vmctx),
|
||||
*mem,
|
||||
)
|
||||
} else {
|
||||
let vm_mem = &mut self.backing.memories[mem_index.index() as usize];
|
||||
(
|
||||
unsafe { MemoryPointer::new(&mut vm_mem.into_vm_memory()) },
|
||||
Context::Internal,
|
||||
*module
|
||||
.memories
|
||||
.get(mem_index)
|
||||
.expect("broken invariant, memories"),
|
||||
)
|
||||
match mem_index.local_or_import(module) {
|
||||
LocalOrImport::Local(local_mem_index) => {
|
||||
let vm_mem = &mut self.backing.memories[local_mem_index];
|
||||
(
|
||||
unsafe { MemoryPointer::new(&mut vm_mem.into_vm_memory()) },
|
||||
Context::Internal,
|
||||
*module
|
||||
.memories
|
||||
.get(local_mem_index)
|
||||
.expect("broken invariant, memories"),
|
||||
)
|
||||
}
|
||||
LocalOrImport::Import(imported_mem_index) => {
|
||||
let &(_, mem) = &module
|
||||
.imported_memories
|
||||
.get(imported_mem_index)
|
||||
.expect("missing imported memory index");
|
||||
let vm::ImportedMemory { memory, vmctx } =
|
||||
&self.import_backing.memories[imported_mem_index];
|
||||
(
|
||||
unsafe { MemoryPointer::new(*memory) },
|
||||
Context::External(*vmctx),
|
||||
*mem,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -260,23 +264,27 @@ impl InstanceInner {
|
||||
module: &ModuleInner,
|
||||
global_index: GlobalIndex,
|
||||
) -> (GlobalPointer, GlobalDesc) {
|
||||
if module.is_imported_global(global_index) {
|
||||
let &(_, desc) = &module
|
||||
.imported_globals
|
||||
.get(global_index)
|
||||
.expect("missing imported global index");
|
||||
let vm::ImportedGlobal { global } = &self.import_backing.globals[global_index.index()];
|
||||
(unsafe { GlobalPointer::new(*global) }, *desc)
|
||||
} else {
|
||||
let vm_global = &mut self.backing.vm_globals[global_index.index() as usize];
|
||||
(
|
||||
unsafe { GlobalPointer::new(vm_global) },
|
||||
module
|
||||
.globals
|
||||
.get(global_index)
|
||||
.expect("broken invariant, globals")
|
||||
.desc,
|
||||
)
|
||||
match global_index.local_or_import(module) {
|
||||
LocalOrImport::Local(local_global_index) => {
|
||||
let vm_global = &mut self.backing.vm_globals[local_global_index];
|
||||
(
|
||||
unsafe { GlobalPointer::new(vm_global) },
|
||||
module
|
||||
.globals
|
||||
.get(local_global_index)
|
||||
.expect("broken invariant, globals")
|
||||
.desc,
|
||||
)
|
||||
}
|
||||
LocalOrImport::Import(imported_global_index) => {
|
||||
let &(_, imported_global) = &module
|
||||
.imported_globals
|
||||
.get(imported_global_index)
|
||||
.expect("missing imported global index");
|
||||
let vm::ImportedGlobal { global } =
|
||||
&self.import_backing.globals[imported_global_index];
|
||||
(unsafe { GlobalPointer::new(*global) }, imported_global.desc)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -285,28 +293,31 @@ impl InstanceInner {
|
||||
module: &ModuleInner,
|
||||
table_index: TableIndex,
|
||||
) -> (TablePointer, Context, Table) {
|
||||
if module.is_imported_table(table_index) {
|
||||
let &(_, tab) = &module
|
||||
.imported_tables
|
||||
.get(table_index)
|
||||
.expect("missing imported table index");
|
||||
let vm::ImportedTable { table, vmctx } =
|
||||
&self.import_backing.tables[table_index.index()];
|
||||
(
|
||||
unsafe { TablePointer::new(*table) },
|
||||
Context::External(*vmctx),
|
||||
*tab,
|
||||
)
|
||||
} else {
|
||||
let vm_table = &mut self.backing.tables[table_index.index() as usize];
|
||||
(
|
||||
unsafe { TablePointer::new(&mut vm_table.into_vm_table()) },
|
||||
Context::Internal,
|
||||
*module
|
||||
.tables
|
||||
.get(table_index)
|
||||
.expect("broken invariant, tables"),
|
||||
)
|
||||
match table_index.local_or_import(module) {
|
||||
LocalOrImport::Local(local_table_index) => {
|
||||
let vm_table = &mut self.backing.tables[local_table_index];
|
||||
(
|
||||
unsafe { TablePointer::new(&mut vm_table.into_vm_table()) },
|
||||
Context::Internal,
|
||||
*module
|
||||
.tables
|
||||
.get(local_table_index)
|
||||
.expect("broken invariant, tables"),
|
||||
)
|
||||
}
|
||||
LocalOrImport::Import(imported_table_index) => {
|
||||
let &(_, tab) = &module
|
||||
.imported_tables
|
||||
.get(imported_table_index)
|
||||
.expect("missing imported table index");
|
||||
let vm::ImportedTable { table, vmctx } =
|
||||
&self.import_backing.tables[imported_table_index];
|
||||
(
|
||||
unsafe { TablePointer::new(*table) },
|
||||
Context::External(*vmctx),
|
||||
*tab,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -16,6 +16,7 @@ pub mod module;
|
||||
mod recovery;
|
||||
mod sig_registry;
|
||||
mod sighandler;
|
||||
pub mod structures;
|
||||
pub mod table;
|
||||
pub mod types;
|
||||
pub mod vm;
|
||||
|
@ -93,7 +93,7 @@ impl LinearMemory {
|
||||
self.mmap.as_ptr()
|
||||
}
|
||||
|
||||
/// Returns a number of allocated wasm pages.
|
||||
/// Returns the size in bytes
|
||||
pub(crate) fn size(&self) -> usize {
|
||||
self.current as usize * Self::PAGE_SIZE as usize
|
||||
}
|
||||
|
@ -2,9 +2,11 @@ use crate::{
|
||||
backend::FuncResolver,
|
||||
import::Imports,
|
||||
sig_registry::SigRegistry,
|
||||
structures::Map,
|
||||
types::{
|
||||
FuncIndex, Global, GlobalDesc, GlobalIndex, Map, MapIndex, Memory, MemoryIndex, SigIndex,
|
||||
Table, TableIndex,
|
||||
FuncIndex, Global, GlobalIndex, ImportedFuncIndex, ImportedGlobal, ImportedGlobalIndex,
|
||||
ImportedMemoryIndex, ImportedTableIndex, Initializer, LocalGlobalIndex, LocalMemoryIndex,
|
||||
LocalTableIndex, Memory, MemoryIndex, SigIndex, Table, TableIndex,
|
||||
},
|
||||
Instance,
|
||||
};
|
||||
@ -15,14 +17,16 @@ use std::rc::Rc;
|
||||
#[doc(hidden)]
|
||||
pub struct ModuleInner {
|
||||
pub func_resolver: Box<dyn FuncResolver>,
|
||||
pub memories: Map<MemoryIndex, Memory>,
|
||||
pub globals: Map<GlobalIndex, Global>,
|
||||
pub tables: Map<TableIndex, Table>,
|
||||
// This are strictly local and the typsystem ensures that.
|
||||
pub memories: Map<LocalMemoryIndex, Memory>,
|
||||
pub globals: Map<LocalGlobalIndex, Global>,
|
||||
pub tables: Map<LocalTableIndex, Table>,
|
||||
|
||||
pub imported_functions: Map<FuncIndex, ImportName>,
|
||||
pub imported_memories: Map<MemoryIndex, (ImportName, Memory)>,
|
||||
pub imported_tables: Map<TableIndex, (ImportName, Table)>,
|
||||
pub imported_globals: Map<GlobalIndex, (ImportName, GlobalDesc)>,
|
||||
// These are strictly imported and the typesystem ensures that.
|
||||
pub imported_functions: Map<ImportedFuncIndex, ImportName>,
|
||||
pub imported_memories: Map<ImportedMemoryIndex, (ImportName, Memory)>,
|
||||
pub imported_tables: Map<ImportedTableIndex, (ImportName, Table)>,
|
||||
pub imported_globals: Map<ImportedGlobalIndex, (ImportName, ImportedGlobal)>,
|
||||
|
||||
pub exports: HashMap<String, ExportIndex>,
|
||||
|
||||
@ -47,23 +51,7 @@ impl Module {
|
||||
}
|
||||
}
|
||||
|
||||
impl ModuleInner {
|
||||
pub(crate) fn is_imported_function(&self, func_index: FuncIndex) -> bool {
|
||||
func_index.index() < self.imported_functions.len()
|
||||
}
|
||||
|
||||
pub(crate) fn is_imported_memory(&self, memory_index: MemoryIndex) -> bool {
|
||||
memory_index.index() < self.imported_memories.len()
|
||||
}
|
||||
|
||||
pub(crate) fn is_imported_table(&self, table_index: TableIndex) -> bool {
|
||||
table_index.index() < self.imported_tables.len()
|
||||
}
|
||||
|
||||
pub(crate) fn is_imported_global(&self, global_index: GlobalIndex) -> bool {
|
||||
global_index.index() < self.imported_globals.len()
|
||||
}
|
||||
}
|
||||
impl ModuleInner {}
|
||||
|
||||
#[doc(hidden)]
|
||||
#[derive(Debug, Clone)]
|
||||
@ -90,7 +78,7 @@ pub enum ExportIndex {
|
||||
}
|
||||
|
||||
/// A data initializer for linear memory.
|
||||
#[derive(Debug)]
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct DataInitializer {
|
||||
/// The index of the memory to initialize.
|
||||
pub memory_index: MemoryIndex,
|
||||
@ -103,14 +91,12 @@ pub struct DataInitializer {
|
||||
}
|
||||
|
||||
/// A WebAssembly table initializer.
|
||||
#[derive(Clone, Debug)]
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct TableInitializer {
|
||||
/// The index of a table to initialize.
|
||||
pub table_index: TableIndex,
|
||||
/// Optionally, a global variable giving a base index.
|
||||
pub base: Option<GlobalIndex>,
|
||||
/// The offset to add to the base.
|
||||
pub offset: usize,
|
||||
/// Either a constant offset or a `get_global`
|
||||
pub base: Initializer,
|
||||
/// The values to write into the table elements.
|
||||
pub elements: Vec<FuncIndex>,
|
||||
}
|
||||
|
@ -1,4 +1,7 @@
|
||||
use crate::types::{FuncSig, Map, SigIndex};
|
||||
use crate::{
|
||||
structures::Map,
|
||||
types::{FuncSig, SigIndex},
|
||||
};
|
||||
use hashbrown::HashMap;
|
||||
|
||||
#[derive(Debug)]
|
||||
|
46
lib/runtime/src/structures/boxed.rs
Normal file
46
lib/runtime/src/structures/boxed.rs
Normal file
@ -0,0 +1,46 @@
|
||||
use super::{SliceMap, TypedIndex};
|
||||
use std::{
|
||||
marker::PhantomData,
|
||||
mem,
|
||||
ops::{Deref, DerefMut},
|
||||
};
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct BoxedMap<K, V>
|
||||
where
|
||||
K: TypedIndex,
|
||||
{
|
||||
elems: Box<[V]>,
|
||||
_marker: PhantomData<K>,
|
||||
}
|
||||
|
||||
impl<K, V> BoxedMap<K, V>
|
||||
where
|
||||
K: TypedIndex,
|
||||
{
|
||||
pub(in crate::structures) fn new(elems: Box<[V]>) -> Self {
|
||||
Self {
|
||||
elems,
|
||||
_marker: PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<K, V> Deref for BoxedMap<K, V>
|
||||
where
|
||||
K: TypedIndex,
|
||||
{
|
||||
type Target = SliceMap<K, V>;
|
||||
fn deref(&self) -> &SliceMap<K, V> {
|
||||
unsafe { mem::transmute::<&[V], _>(&*self.elems) }
|
||||
}
|
||||
}
|
||||
|
||||
impl<K, V> DerefMut for BoxedMap<K, V>
|
||||
where
|
||||
K: TypedIndex,
|
||||
{
|
||||
fn deref_mut(&mut self) -> &mut SliceMap<K, V> {
|
||||
unsafe { mem::transmute::<&mut [V], _>(&mut *self.elems) }
|
||||
}
|
||||
}
|
174
lib/runtime/src/structures/map.rs
Normal file
174
lib/runtime/src/structures/map.rs
Normal file
@ -0,0 +1,174 @@
|
||||
use super::{BoxedMap, SliceMap, TypedIndex};
|
||||
use std::{
|
||||
iter::{self, Extend, FromIterator},
|
||||
marker::PhantomData,
|
||||
mem,
|
||||
ops::{Deref, DerefMut},
|
||||
slice,
|
||||
};
|
||||
|
||||
/// Dense item map
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Map<K, V>
|
||||
where
|
||||
K: TypedIndex,
|
||||
{
|
||||
elems: Vec<V>,
|
||||
_marker: PhantomData<K>,
|
||||
}
|
||||
|
||||
impl<K, V> Map<K, V>
|
||||
where
|
||||
K: TypedIndex,
|
||||
{
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
elems: Vec::new(),
|
||||
_marker: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn with_capacity(capacity: usize) -> Self {
|
||||
Self {
|
||||
elems: Vec::with_capacity(capacity),
|
||||
_marker: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn len(&self) -> usize {
|
||||
self.elems.len()
|
||||
}
|
||||
|
||||
pub fn push(&mut self, value: V) -> K {
|
||||
let len = self.len();
|
||||
self.elems.push(value);
|
||||
K::new(len)
|
||||
}
|
||||
|
||||
pub fn reserve_exact(&mut self, size: usize) {
|
||||
self.elems.reserve_exact(size);
|
||||
}
|
||||
|
||||
pub fn into_boxed_map(self) -> BoxedMap<K, V> {
|
||||
BoxedMap::new(self.elems.into_boxed_slice())
|
||||
}
|
||||
}
|
||||
|
||||
impl<K, V> Map<K, V>
|
||||
where
|
||||
K: TypedIndex,
|
||||
V: Clone,
|
||||
{
|
||||
pub fn resize(&mut self, new_len: usize, value: V) {
|
||||
self.elems.resize(new_len, value);
|
||||
}
|
||||
}
|
||||
|
||||
impl<K, V> Extend<V> for Map<K, V>
|
||||
where
|
||||
K: TypedIndex,
|
||||
{
|
||||
fn extend<I: IntoIterator<Item = V>>(&mut self, iter: I) {
|
||||
self.elems.extend(iter);
|
||||
}
|
||||
}
|
||||
|
||||
impl<K, V> FromIterator<V> for Map<K, V>
|
||||
where
|
||||
K: TypedIndex,
|
||||
{
|
||||
fn from_iter<I: IntoIterator<Item = V>>(iter: I) -> Self {
|
||||
let elems: Vec<V> = iter.into_iter().collect();
|
||||
Self {
|
||||
elems,
|
||||
_marker: PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<K, V> Deref for Map<K, V>
|
||||
where
|
||||
K: TypedIndex,
|
||||
{
|
||||
type Target = SliceMap<K, V>;
|
||||
fn deref(&self) -> &SliceMap<K, V> {
|
||||
unsafe { mem::transmute::<&[V], _>(self.elems.as_slice()) }
|
||||
}
|
||||
}
|
||||
|
||||
impl<K, V> DerefMut for Map<K, V>
|
||||
where
|
||||
K: TypedIndex,
|
||||
{
|
||||
fn deref_mut(&mut self) -> &mut SliceMap<K, V> {
|
||||
unsafe { mem::transmute::<&mut [V], _>(self.elems.as_mut_slice()) }
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, K, V> IntoIterator for &'a Map<K, V>
|
||||
where
|
||||
K: TypedIndex,
|
||||
{
|
||||
type Item = (K, &'a V);
|
||||
type IntoIter = Iter<'a, K, V>;
|
||||
|
||||
fn into_iter(self) -> Self::IntoIter {
|
||||
Iter::new(self.elems.iter())
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, K, V> IntoIterator for &'a mut Map<K, V>
|
||||
where
|
||||
K: TypedIndex,
|
||||
{
|
||||
type Item = (K, &'a mut V);
|
||||
type IntoIter = IterMut<'a, K, V>;
|
||||
|
||||
fn into_iter(self) -> Self::IntoIter {
|
||||
IterMut::new(self.elems.iter_mut())
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Iter<'a, K: TypedIndex, V: 'a> {
|
||||
enumerated: iter::Enumerate<slice::Iter<'a, V>>,
|
||||
_marker: PhantomData<K>,
|
||||
}
|
||||
|
||||
impl<'a, K: TypedIndex, V: 'a> Iter<'a, K, V> {
|
||||
pub(in crate::structures) fn new(iter: slice::Iter<'a, V>) -> Self {
|
||||
Self {
|
||||
enumerated: iter.enumerate(),
|
||||
_marker: PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, K: TypedIndex, V: 'a> Iterator for Iter<'a, K, V> {
|
||||
type Item = (K, &'a V);
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
self.enumerated.next().map(|(i, v)| (K::new(i), v))
|
||||
}
|
||||
}
|
||||
|
||||
pub struct IterMut<'a, K: TypedIndex, V: 'a> {
|
||||
enumerated: iter::Enumerate<slice::IterMut<'a, V>>,
|
||||
_marker: PhantomData<K>,
|
||||
}
|
||||
|
||||
impl<'a, K: TypedIndex, V: 'a> IterMut<'a, K, V> {
|
||||
pub(in crate::structures) fn new(iter: slice::IterMut<'a, V>) -> Self {
|
||||
Self {
|
||||
enumerated: iter.enumerate(),
|
||||
_marker: PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, K: TypedIndex, V: 'a> Iterator for IterMut<'a, K, V> {
|
||||
type Item = (K, &'a mut V);
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
self.enumerated.next().map(|(i, v)| (K::new(i), v))
|
||||
}
|
||||
}
|
12
lib/runtime/src/structures/mod.rs
Normal file
12
lib/runtime/src/structures/mod.rs
Normal file
@ -0,0 +1,12 @@
|
||||
mod boxed;
|
||||
mod map;
|
||||
mod slice;
|
||||
|
||||
pub use self::boxed::BoxedMap;
|
||||
pub use self::map::{Iter, IterMut, Map};
|
||||
pub use self::slice::SliceMap;
|
||||
|
||||
pub trait TypedIndex {
|
||||
fn new(index: usize) -> Self;
|
||||
fn index(&self) -> usize;
|
||||
}
|
86
lib/runtime/src/structures/mono_vec.rs
Normal file
86
lib/runtime/src/structures/mono_vec.rs
Normal file
@ -0,0 +1,86 @@
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
enum MonoVecInner<T> {
|
||||
None,
|
||||
Inline(T),
|
||||
Heap(Vec<T>),
|
||||
}
|
||||
|
||||
/// A type that can hold zero items,
|
||||
/// one item, or many items.
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct MonoVec<T> {
|
||||
inner: MonoVecInner<T>,
|
||||
}
|
||||
|
||||
impl<T> MonoVec<T> {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
inner: MonoVecInner::None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new_inline(item: T) -> Self {
|
||||
Self {
|
||||
inner: MonoVecInner::Inline(item),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn with_capacity(capacity: usize) -> Self {
|
||||
match capacity {
|
||||
0 | 1 => Self::new(),
|
||||
_ => Self {
|
||||
inner: MonoVecInner::Heap(Vec::with_capacity(capacity)),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
pub fn push(&mut self, item: T) {
|
||||
let uninit = unsafe { mem::uninitialized() };
|
||||
let prev = mem::replace(&mut self.inner, uninit);
|
||||
let next = match prev {
|
||||
MonoVecInner::None => MonoVecInner::Inline(item),
|
||||
MonoVecInner::Inline(previous_item) => MonoVecInner::Heap(vec![previous_item, item]),
|
||||
MonoVecInner::Heap(mut v) => {
|
||||
v.push(item);
|
||||
MonoVecInner::Heap(v)
|
||||
}
|
||||
};
|
||||
let uninit = mem::replace(&mut self.inner, next);
|
||||
mem::forget(uninit);
|
||||
}
|
||||
|
||||
pub fn pop(&mut self) -> Option<T> {
|
||||
match self.inner {
|
||||
MonoVecInner::None => None,
|
||||
MonoVecInner::Inline(ref mut item) => {
|
||||
let uninit = unsafe { mem::uninitialized() };
|
||||
let item = mem::replace(item, uninit);
|
||||
let uninit = mem::replace(&mut self.inner, MonoVecInner::None);
|
||||
mem::forget(uninit);
|
||||
Some(item)
|
||||
}
|
||||
MonoVecInner::Heap(ref mut v) => v.pop(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn as_slice(&self) -> &[T] {
|
||||
match self.inner {
|
||||
MonoVecInner::None => unsafe {
|
||||
slice::from_raw_parts(mem::align_of::<T>() as *const T, 0)
|
||||
},
|
||||
MonoVecInner::Inline(ref item) => slice::from_ref(item),
|
||||
MonoVecInner::Heap(ref v) => &v[..],
|
||||
}
|
||||
}
|
||||
|
||||
pub fn as_slice_mut(&mut self) -> &mut [T] {
|
||||
match self.inner {
|
||||
MonoVecInner::None => unsafe {
|
||||
slice::from_raw_parts_mut(mem::align_of::<T>() as *mut T, 0)
|
||||
},
|
||||
MonoVecInner::Inline(ref mut item) => slice::from_mut(item),
|
||||
MonoVecInner::Heap(ref mut v) => &mut v[..],
|
||||
}
|
||||
}
|
||||
}
|
68
lib/runtime/src/structures/slice.rs
Normal file
68
lib/runtime/src/structures/slice.rs
Normal file
@ -0,0 +1,68 @@
|
||||
use super::{Iter, IterMut, TypedIndex};
|
||||
use std::{
|
||||
marker::PhantomData,
|
||||
ops::{Index, IndexMut},
|
||||
};
|
||||
|
||||
/// This is a dynamically-sized slice
|
||||
/// that can only be indexed by the
|
||||
/// correct index type.
|
||||
pub struct SliceMap<K, V>
|
||||
where
|
||||
K: TypedIndex,
|
||||
{
|
||||
_marker: PhantomData<K>,
|
||||
slice: [V],
|
||||
}
|
||||
|
||||
impl<K, V> SliceMap<K, V>
|
||||
where
|
||||
K: TypedIndex,
|
||||
{
|
||||
pub fn get(&self, index: K) -> Option<&V> {
|
||||
self.slice.get(index.index())
|
||||
}
|
||||
|
||||
pub fn get_mut(&mut self, index: K) -> Option<&mut V> {
|
||||
self.slice.get_mut(index.index())
|
||||
}
|
||||
|
||||
pub fn len(&self) -> usize {
|
||||
self.slice.len()
|
||||
}
|
||||
|
||||
pub fn iter(&self) -> Iter<K, V> {
|
||||
Iter::new(self.slice.iter())
|
||||
}
|
||||
|
||||
pub fn iter_mut(&mut self) -> IterMut<K, V> {
|
||||
IterMut::new(self.slice.iter_mut())
|
||||
}
|
||||
|
||||
pub fn as_ptr(&self) -> *const V {
|
||||
self as *const SliceMap<K, V> as *const V
|
||||
}
|
||||
|
||||
pub fn as_mut_ptr(&mut self) -> *mut V {
|
||||
self as *mut SliceMap<K, V> as *mut V
|
||||
}
|
||||
}
|
||||
|
||||
impl<K, V> Index<K> for SliceMap<K, V>
|
||||
where
|
||||
K: TypedIndex,
|
||||
{
|
||||
type Output = V;
|
||||
fn index(&self, index: K) -> &V {
|
||||
&self.slice[index.index()]
|
||||
}
|
||||
}
|
||||
|
||||
impl<K, V> IndexMut<K> for SliceMap<K, V>
|
||||
where
|
||||
K: TypedIndex,
|
||||
{
|
||||
fn index_mut(&mut self, index: K) -> &mut V {
|
||||
&mut self.slice[index.index()]
|
||||
}
|
||||
}
|
@ -1,9 +1,4 @@
|
||||
use std::marker::PhantomData;
|
||||
use std::{
|
||||
iter, mem,
|
||||
ops::{Index, IndexMut},
|
||||
slice,
|
||||
};
|
||||
use crate::{module::ModuleInner, structures::TypedIndex};
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||
pub enum Type {
|
||||
@ -82,21 +77,22 @@ pub struct Table {
|
||||
|
||||
impl Table {
|
||||
pub(crate) fn fits_in_imported(&self, imported: &Table) -> bool {
|
||||
self.max == imported.max && self.min <= imported.min
|
||||
// TODO: We should define implementation limits.
|
||||
let imported_max = imported.max.unwrap_or(u32::max_value());
|
||||
let self_max = self.max.unwrap_or(u32::max_value());
|
||||
self.ty == imported.ty && imported_max <= self_max && self.min <= imported.min
|
||||
}
|
||||
}
|
||||
|
||||
/// A global value initializer.
|
||||
/// Overtime, this will be able to represent more and more
|
||||
/// A const value initializer.
|
||||
/// Over time, this will be able to represent more and more
|
||||
/// complex expressions.
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub enum Initializer {
|
||||
/// Corresponds to a `const.*` instruction.
|
||||
Const(Value),
|
||||
/// Corresponds to a `get_global` instruction.
|
||||
GetGlobal(GlobalIndex),
|
||||
/// Initialized externally
|
||||
Import,
|
||||
GetGlobal(ImportedGlobalIndex),
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
@ -105,11 +101,23 @@ pub struct GlobalDesc {
|
||||
pub ty: Type,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub enum ImportedGlobalInit {
|
||||
GetGlobal(ImportedGlobalIndex),
|
||||
Import,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub struct ImportedGlobal {
|
||||
pub desc: GlobalDesc,
|
||||
pub init: ImportedGlobalInit,
|
||||
}
|
||||
|
||||
/// A wasm global.
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Global {
|
||||
pub desc: GlobalDesc,
|
||||
pub init: Initializer,
|
||||
pub init: Value,
|
||||
}
|
||||
|
||||
/// A wasm memory.
|
||||
@ -129,11 +137,15 @@ impl Memory {
|
||||
}
|
||||
|
||||
pub(crate) fn fits_in_imported(&self, imported: &Memory) -> bool {
|
||||
self.shared == imported.shared && self.max == imported.max && self.min <= imported.min
|
||||
let imported_max = imported.max.unwrap_or(65_536);
|
||||
let self_max = self.max.unwrap_or(65_536);
|
||||
|
||||
self.shared == imported.shared && imported_max <= self_max && self.min <= imported.min
|
||||
}
|
||||
}
|
||||
|
||||
/// A wasm func.
|
||||
/// The signature of a function that is either implemented
|
||||
/// in a wasm module or exposed to wasm by the host.
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||
pub struct FuncSig {
|
||||
pub params: Vec<Type>,
|
||||
@ -151,158 +163,17 @@ impl FuncSig {
|
||||
}
|
||||
}
|
||||
|
||||
pub trait MapIndex {
|
||||
fn new(index: usize) -> Self;
|
||||
fn index(&self) -> usize;
|
||||
}
|
||||
|
||||
/// Dense item map
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Map<I, T>
|
||||
where
|
||||
I: MapIndex,
|
||||
{
|
||||
elems: Vec<T>,
|
||||
_marker: PhantomData<I>,
|
||||
}
|
||||
|
||||
impl<I, T> Map<I, T>
|
||||
where
|
||||
I: MapIndex,
|
||||
{
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
elems: Vec::new(),
|
||||
_marker: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn with_capacity(capacity: usize) -> Self {
|
||||
Self {
|
||||
elems: Vec::with_capacity(capacity),
|
||||
_marker: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get(&self, index: I) -> Option<&T> {
|
||||
self.elems.get(index.index())
|
||||
}
|
||||
|
||||
pub fn len(&self) -> usize {
|
||||
self.elems.len()
|
||||
}
|
||||
|
||||
pub fn push(&mut self, value: T) -> I {
|
||||
let len = self.len();
|
||||
self.elems.push(value);
|
||||
I::new(len)
|
||||
}
|
||||
|
||||
pub fn as_ptr(&self) -> *const T {
|
||||
self.elems.as_ptr()
|
||||
}
|
||||
|
||||
pub fn reserve_exact(&mut self, size: usize) {
|
||||
self.elems.reserve_exact(size);
|
||||
}
|
||||
|
||||
pub fn iter(&self) -> Iter<T, I> {
|
||||
Iter::new(self.elems.iter())
|
||||
}
|
||||
}
|
||||
|
||||
impl<I, T> Index<I> for Map<I, T>
|
||||
where
|
||||
I: MapIndex,
|
||||
{
|
||||
type Output = T;
|
||||
fn index(&self, index: I) -> &T {
|
||||
&self.elems[index.index()]
|
||||
}
|
||||
}
|
||||
|
||||
impl<I, T> IndexMut<I> for Map<I, T>
|
||||
where
|
||||
I: MapIndex,
|
||||
{
|
||||
fn index_mut(&mut self, index: I) -> &mut T {
|
||||
&mut self.elems[index.index()]
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, I, T> IntoIterator for &'a Map<I, T>
|
||||
where
|
||||
I: MapIndex,
|
||||
{
|
||||
type Item = (I, &'a T);
|
||||
type IntoIter = Iter<'a, T, I>;
|
||||
|
||||
fn into_iter(self) -> Self::IntoIter {
|
||||
Iter::new(self.elems.iter())
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, I, T> IntoIterator for &'a mut Map<I, T>
|
||||
where
|
||||
I: MapIndex,
|
||||
{
|
||||
type Item = (I, &'a mut T);
|
||||
type IntoIter = IterMut<'a, T, I>;
|
||||
|
||||
fn into_iter(self) -> Self::IntoIter {
|
||||
IterMut::new(self.elems.iter_mut())
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Iter<'a, T: 'a, I: MapIndex> {
|
||||
enumerated: iter::Enumerate<slice::Iter<'a, T>>,
|
||||
_marker: PhantomData<I>,
|
||||
}
|
||||
|
||||
impl<'a, T: 'a, I: MapIndex> Iter<'a, T, I> {
|
||||
fn new(iter: slice::Iter<'a, T>) -> Self {
|
||||
Self {
|
||||
enumerated: iter.enumerate(),
|
||||
_marker: PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T: 'a, I: MapIndex> Iterator for Iter<'a, T, I> {
|
||||
type Item = (I, &'a T);
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
self.enumerated.next().map(|(i, v)| (I::new(i), v))
|
||||
}
|
||||
}
|
||||
|
||||
pub struct IterMut<'a, T: 'a, I: MapIndex> {
|
||||
enumerated: iter::Enumerate<slice::IterMut<'a, T>>,
|
||||
_marker: PhantomData<I>,
|
||||
}
|
||||
|
||||
impl<'a, T: 'a, I: MapIndex> IterMut<'a, T, I> {
|
||||
fn new(iter: slice::IterMut<'a, T>) -> Self {
|
||||
Self {
|
||||
enumerated: iter.enumerate(),
|
||||
_marker: PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T: 'a, I: MapIndex> Iterator for IterMut<'a, T, I> {
|
||||
type Item = (I, &'a mut T);
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
self.enumerated.next().map(|(i, v)| (I::new(i), v))
|
||||
}
|
||||
pub trait LocalImport {
|
||||
type Local: TypedIndex;
|
||||
type Import: TypedIndex;
|
||||
}
|
||||
|
||||
#[rustfmt::skip]
|
||||
macro_rules! define_map_index {
|
||||
($ty:ident) => {
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
|
||||
pub struct $ty (u32);
|
||||
impl MapIndex for $ty {
|
||||
impl TypedIndex for $ty {
|
||||
fn new(index: usize) -> Self {
|
||||
$ty (index as _)
|
||||
}
|
||||
@ -312,20 +183,72 @@ macro_rules! define_map_index {
|
||||
}
|
||||
}
|
||||
};
|
||||
($($ty:ident,)*) => {
|
||||
($($normal_ty:ident,)* | local: $($local_ty:ident,)* | imported: $($imported_ty:ident,)*) => {
|
||||
$(
|
||||
define_map_index!($ty);
|
||||
define_map_index!($normal_ty);
|
||||
define_map_index!($local_ty);
|
||||
define_map_index!($imported_ty);
|
||||
|
||||
impl LocalImport for $normal_ty {
|
||||
type Local = $local_ty;
|
||||
type Import = $imported_ty;
|
||||
}
|
||||
)*
|
||||
};
|
||||
}
|
||||
|
||||
define_map_index![FuncIndex, MemoryIndex, TableIndex, SigIndex,];
|
||||
#[rustfmt::skip]
|
||||
define_map_index![
|
||||
FuncIndex, MemoryIndex, TableIndex, GlobalIndex,
|
||||
| local: LocalFuncIndex, LocalMemoryIndex, LocalTableIndex, LocalGlobalIndex,
|
||||
| imported: ImportedFuncIndex, ImportedMemoryIndex, ImportedTableIndex, ImportedGlobalIndex,
|
||||
];
|
||||
|
||||
#[rustfmt::skip]
|
||||
macro_rules! define_local_or_import {
|
||||
($ty:ident, $local_ty:ident, $imported_ty:ident, $imports:ident) => {
|
||||
impl $ty {
|
||||
pub fn local_or_import(self, module: &ModuleInner) -> LocalOrImport<$ty> {
|
||||
if self.index() < module.$imports.len() {
|
||||
LocalOrImport::Import(<Self as LocalImport>::Import::new(self.index()))
|
||||
} else {
|
||||
LocalOrImport::Local(<Self as LocalImport>::Local::new(self.index() - module.$imports.len()))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl $local_ty {
|
||||
pub fn convert_up(self, module: &ModuleInner) -> $ty {
|
||||
$ty ((self.index() + module.$imports.len()) as u32)
|
||||
}
|
||||
}
|
||||
|
||||
impl $imported_ty {
|
||||
pub fn convert_up(self, _module: &ModuleInner) -> $ty {
|
||||
$ty (self.index() as u32)
|
||||
}
|
||||
}
|
||||
};
|
||||
($(($ty:ident | ($local_ty:ident, $imported_ty:ident): $imports:ident),)*) => {
|
||||
$(
|
||||
define_local_or_import!($ty, $local_ty, $imported_ty, $imports);
|
||||
)*
|
||||
};
|
||||
}
|
||||
|
||||
#[rustfmt::skip]
|
||||
define_local_or_import![
|
||||
(FuncIndex | (LocalFuncIndex, ImportedFuncIndex): imported_functions),
|
||||
(MemoryIndex | (LocalMemoryIndex, ImportedMemoryIndex): imported_memories),
|
||||
(TableIndex | (LocalTableIndex, ImportedTableIndex): imported_tables),
|
||||
(GlobalIndex | (LocalGlobalIndex, ImportedGlobalIndex): imported_globals),
|
||||
];
|
||||
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
|
||||
pub struct GlobalIndex(u32);
|
||||
impl MapIndex for GlobalIndex {
|
||||
pub struct SigIndex(u32);
|
||||
impl TypedIndex for SigIndex {
|
||||
fn new(index: usize) -> Self {
|
||||
GlobalIndex(index as _)
|
||||
SigIndex(index as _)
|
||||
}
|
||||
|
||||
fn index(&self) -> usize {
|
||||
@ -333,88 +256,10 @@ impl MapIndex for GlobalIndex {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
enum MonoVecInner<T> {
|
||||
None,
|
||||
Inline(T),
|
||||
Heap(Vec<T>),
|
||||
}
|
||||
|
||||
/// A type that can hold zero items,
|
||||
/// one item, or many items.
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct MonoVec<T> {
|
||||
inner: MonoVecInner<T>,
|
||||
}
|
||||
|
||||
impl<T> MonoVec<T> {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
inner: MonoVecInner::None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new_inline(item: T) -> Self {
|
||||
Self {
|
||||
inner: MonoVecInner::Inline(item),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn with_capacity(capacity: usize) -> Self {
|
||||
match capacity {
|
||||
0 | 1 => Self::new(),
|
||||
_ => Self {
|
||||
inner: MonoVecInner::Heap(Vec::with_capacity(capacity)),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
pub fn push(&mut self, item: T) {
|
||||
let uninit = unsafe { mem::uninitialized() };
|
||||
let prev = mem::replace(&mut self.inner, uninit);
|
||||
let next = match prev {
|
||||
MonoVecInner::None => MonoVecInner::Inline(item),
|
||||
MonoVecInner::Inline(previous_item) => MonoVecInner::Heap(vec![previous_item, item]),
|
||||
MonoVecInner::Heap(mut v) => {
|
||||
v.push(item);
|
||||
MonoVecInner::Heap(v)
|
||||
}
|
||||
};
|
||||
let uninit = mem::replace(&mut self.inner, next);
|
||||
mem::forget(uninit);
|
||||
}
|
||||
|
||||
pub fn pop(&mut self) -> Option<T> {
|
||||
match self.inner {
|
||||
MonoVecInner::None => None,
|
||||
MonoVecInner::Inline(ref mut item) => {
|
||||
let uninit = unsafe { mem::uninitialized() };
|
||||
let item = mem::replace(item, uninit);
|
||||
let uninit = mem::replace(&mut self.inner, MonoVecInner::None);
|
||||
mem::forget(uninit);
|
||||
Some(item)
|
||||
}
|
||||
MonoVecInner::Heap(ref mut v) => v.pop(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn as_slice(&self) -> &[T] {
|
||||
match self.inner {
|
||||
MonoVecInner::None => unsafe {
|
||||
slice::from_raw_parts(mem::align_of::<T>() as *const T, 0)
|
||||
},
|
||||
MonoVecInner::Inline(ref item) => slice::from_ref(item),
|
||||
MonoVecInner::Heap(ref v) => &v[..],
|
||||
}
|
||||
}
|
||||
|
||||
pub fn as_slice_mut(&mut self) -> &mut [T] {
|
||||
match self.inner {
|
||||
MonoVecInner::None => unsafe {
|
||||
slice::from_raw_parts_mut(mem::align_of::<T>() as *mut T, 0)
|
||||
},
|
||||
MonoVecInner::Inline(ref mut item) => slice::from_mut(item),
|
||||
MonoVecInner::Heap(ref mut v) => &mut v[..],
|
||||
}
|
||||
}
|
||||
pub enum LocalOrImport<T>
|
||||
where
|
||||
T: LocalImport,
|
||||
{
|
||||
Local(T::Local),
|
||||
Import(T::Import),
|
||||
}
|
||||
|
@ -201,6 +201,10 @@ impl LocalGlobal {
|
||||
pub fn null() -> Self {
|
||||
Self { data: 0 }
|
||||
}
|
||||
|
||||
pub fn size() -> u8 {
|
||||
mem::size_of::<Self>() as u8
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
@ -213,6 +217,10 @@ impl ImportedGlobal {
|
||||
pub fn offset_global() -> u8 {
|
||||
0 * (mem::size_of::<usize>() as u8)
|
||||
}
|
||||
|
||||
pub fn size() -> u8 {
|
||||
mem::size_of::<Self>() as u8
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
|
@ -1,7 +1,7 @@
|
||||
use crate::{memory::LinearMemory, vm};
|
||||
use crate::{memory::LinearMemory, structures::TypedIndex, types::LocalMemoryIndex, vm};
|
||||
|
||||
pub unsafe extern "C" fn memory_grow_static(
|
||||
memory_index: u32,
|
||||
memory_index: LocalMemoryIndex,
|
||||
by_pages: u32,
|
||||
ctx: *mut vm::Ctx,
|
||||
) -> i32 {
|
||||
@ -10,7 +10,7 @@ pub unsafe extern "C" fn memory_grow_static(
|
||||
.grow_static(by_pages)
|
||||
{
|
||||
// Store the new size back into the vmctx.
|
||||
(*(*ctx).memories.add(memory_index as usize)).size =
|
||||
(*(*ctx).memories.add(memory_index.index())).size =
|
||||
(old as usize + by_pages as usize) * LinearMemory::PAGE_SIZE as usize;
|
||||
old
|
||||
} else {
|
||||
@ -18,12 +18,12 @@ pub unsafe extern "C" fn memory_grow_static(
|
||||
}
|
||||
}
|
||||
|
||||
pub unsafe extern "C" fn memory_size(memory_index: u32, ctx: *mut vm::Ctx) -> u32 {
|
||||
pub unsafe extern "C" fn memory_size(memory_index: LocalMemoryIndex, ctx: *mut vm::Ctx) -> u32 {
|
||||
(*(*ctx).local_backing).memory(memory_index).pages()
|
||||
}
|
||||
|
||||
pub unsafe extern "C" fn memory_grow_dynamic(
|
||||
memory_index: u32,
|
||||
memory_index: LocalMemoryIndex,
|
||||
by_pages: u32,
|
||||
ctx: *mut vm::Ctx,
|
||||
) -> i32 {
|
||||
@ -32,7 +32,7 @@ pub unsafe extern "C" fn memory_grow_dynamic(
|
||||
.grow_dynamic(by_pages)
|
||||
{
|
||||
// Store the new size back into the vmctx.
|
||||
(*(*ctx).memories.add(memory_index as usize)).size =
|
||||
(*(*ctx).memories.add(memory_index.index())).size =
|
||||
(old as usize + by_pages as usize) * LinearMemory::PAGE_SIZE as usize;
|
||||
old
|
||||
} else {
|
||||
|
Loading…
x
Reference in New Issue
Block a user