mirror of
https://github.com/fluencelabs/wasmer
synced 2025-06-20 04:06:30 +00:00
Split codegen into multiple modules
This commit is contained in:
@ -25,10 +25,11 @@ use wasmer_runtime::{
|
||||
types::{
|
||||
ElementType as WasmerElementType, FuncIndex as WasmerFuncIndex, FuncSig as WasmerSignature,
|
||||
Global as WasmerGlobal, GlobalDesc as WasmerGlobalDesc, GlobalIndex as WasmerGlobalIndex,
|
||||
GlobalInit as WasmerGlobalInit, Initializer as WasmerInitializer, Map,
|
||||
GlobalInit as WasmerGlobalInit, Initializer as WasmerInitializer,
|
||||
Memory as WasmerMemory, MemoryIndex as WasmerMemoryIndex, SigIndex as WasmerSignatureIndex,
|
||||
Table as WasmerTable, TableIndex as WasmerTableIndex, Type as WasmerType, TypedIndex,
|
||||
Table as WasmerTable, TableIndex as WasmerTableIndex, Type as WasmerType,
|
||||
},
|
||||
structures::{TypedIndex, Map},
|
||||
vm::{self, Ctx as WasmerVMContext},
|
||||
};
|
||||
|
||||
@ -94,7 +95,7 @@ pub mod converter {
|
||||
imported_globals,
|
||||
exports,
|
||||
data_initializers,
|
||||
table_initializers,
|
||||
elem_initializers,
|
||||
start_func,
|
||||
sig_registry,
|
||||
..
|
||||
@ -112,7 +113,7 @@ pub mod converter {
|
||||
imported_globals,
|
||||
exports,
|
||||
data_initializers,
|
||||
table_initializers,
|
||||
elem_initializers,
|
||||
start_func,
|
||||
func_assoc,
|
||||
sig_registry,
|
||||
@ -255,7 +256,7 @@ pub struct CraneliftModule {
|
||||
pub data_initializers: Vec<DataInitializer>,
|
||||
|
||||
// Function indices to add to table.
|
||||
pub table_initializers: Vec<TableInitializer>,
|
||||
pub elem_initializers: Vec<TableInitializer>,
|
||||
|
||||
// The start function index.
|
||||
pub start_func: Option<WasmerFuncIndex>,
|
||||
@ -289,7 +290,7 @@ impl CraneliftModule {
|
||||
imported_globals: Map::new(),
|
||||
exports: HashMap::new(),
|
||||
data_initializers: Vec::new(),
|
||||
table_initializers: Vec::new(),
|
||||
elem_initializers: Vec::new(),
|
||||
start_func: None,
|
||||
sig_registry: SigRegistry::new(),
|
||||
};
|
||||
@ -922,7 +923,7 @@ impl<'data> ModuleEnvironment<'data> for CraneliftModule {
|
||||
};
|
||||
|
||||
// Add table initializer to list of table initializers
|
||||
self.table_initializers.push(TableInitializer {
|
||||
self.elem_initializers.push(TableInitializer {
|
||||
table_index: WasmerTableIndex::new(table_index.index()),
|
||||
base,
|
||||
elements: elements
|
||||
|
607
lib/clif-backend/src/func_env.rs
Normal file
607
lib/clif-backend/src/func_env.rs
Normal file
@ -0,0 +1,607 @@
|
||||
use crate::{module::Converter, module_env::ModuleEnv};
|
||||
use cranelift_codegen::{
|
||||
cursor::FuncCursor,
|
||||
ir::{self, InstBuilder},
|
||||
isa,
|
||||
};
|
||||
use cranelift_entity::EntityRef;
|
||||
use cranelift_wasm::{self, FuncEnvironment, ModuleEnvironment};
|
||||
use wasmer_runtime::{
|
||||
memory::LinearMemory,
|
||||
structures::TypedIndex,
|
||||
types::{FuncIndex, GlobalIndex, LocalOrImport, MemoryIndex, TableIndex},
|
||||
vm,
|
||||
};
|
||||
|
||||
pub struct FuncEnv<'env, 'module, 'isa> {
|
||||
env: &'env ModuleEnv<'module, 'isa>,
|
||||
}
|
||||
|
||||
impl<'env, 'module, 'isa> FuncEnv<'env, 'module, 'isa> {
|
||||
pub fn new(env: &'env ModuleEnv<'module, 'isa>) -> Self {
|
||||
Self { env }
|
||||
}
|
||||
|
||||
/// Creates a signature with VMContext as the last param
|
||||
pub fn generate_signature(&self, sig_index: cranelift_wasm::SignatureIndex) -> ir::Signature {
|
||||
// Get signature
|
||||
let mut signature = self.env.signatures[Converter(sig_index).into()].clone();
|
||||
|
||||
// Add the vmctx parameter type to it
|
||||
signature.params.push(ir::AbiParam::special(
|
||||
self.pointer_type(),
|
||||
ir::ArgumentPurpose::VMContext,
|
||||
));
|
||||
|
||||
// Return signature
|
||||
signature
|
||||
}
|
||||
}
|
||||
|
||||
impl<'env, 'module, 'isa> FuncEnvironment for FuncEnv<'env, 'module, 'isa> {
|
||||
/// Gets configuration information needed for compiling functions
|
||||
fn target_config(&self) -> isa::TargetFrontendConfig {
|
||||
self.env.target_config()
|
||||
}
|
||||
|
||||
/// Gets native pointers types.
|
||||
///
|
||||
/// `I64` on 64-bit arch; `I32` on 32-bit arch.
|
||||
fn pointer_type(&self) -> ir::Type {
|
||||
ir::Type::int(u16::from(self.target_config().pointer_bits())).unwrap()
|
||||
}
|
||||
|
||||
/// Gets the size of a native pointer in bytes.
|
||||
fn pointer_bytes(&self) -> u8 {
|
||||
self.target_config().pointer_bytes()
|
||||
}
|
||||
|
||||
/// Sets up the necessary preamble definitions in `func` to access the global identified
|
||||
/// by `index`.
|
||||
///
|
||||
/// The index space covers both imported and locally declared globals.
|
||||
fn make_global(
|
||||
&mut self,
|
||||
func: &mut ir::Function,
|
||||
clif_global_index: cranelift_wasm::GlobalIndex,
|
||||
) -> cranelift_wasm::GlobalVariable {
|
||||
let global_index: GlobalIndex = Converter(clif_global_index).into();
|
||||
|
||||
// Create VMContext value.
|
||||
let vmctx = func.create_global_value(ir::GlobalValueData::VMContext);
|
||||
let ptr_type = self.pointer_type();
|
||||
|
||||
match global_index.local_or_import(self.env.module) {
|
||||
LocalOrImport::Local(local_global_index) => {
|
||||
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,
|
||||
});
|
||||
|
||||
let offset = local_global_index.index() * 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: ptr_type,
|
||||
});
|
||||
|
||||
// Create global variable based on the data above.
|
||||
cranelift_wasm::GlobalVariable::Memory {
|
||||
gv: local_global_addr,
|
||||
offset: (vm::LocalGlobal::offset_data() as i32).into(),
|
||||
ty: self.env.get_global(clif_global_index).ty,
|
||||
}
|
||||
}
|
||||
LocalOrImport::Import(imported_global_index) => {
|
||||
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: ptr_type,
|
||||
readonly: true,
|
||||
});
|
||||
|
||||
let offset = imported_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: ptr_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: ptr_type,
|
||||
readonly: true,
|
||||
});
|
||||
|
||||
cranelift_wasm::GlobalVariable::Memory {
|
||||
gv: local_global_addr,
|
||||
offset: (vm::LocalGlobal::offset_data() as i32).into(),
|
||||
ty: self.env.get_global(clif_global_index).ty,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Sets up the necessary preamble definitions in `func` to access the linear memory identified
|
||||
/// by `index`.
|
||||
///
|
||||
/// The index space covers both imported and locally declared memories.
|
||||
fn make_heap(
|
||||
&mut self,
|
||||
func: &mut ir::Function,
|
||||
clif_mem_index: cranelift_wasm::MemoryIndex,
|
||||
) -> ir::Heap {
|
||||
let mem_index: MemoryIndex = Converter(clif_mem_index).into();
|
||||
// Create VMContext value.
|
||||
let vmctx = func.create_global_value(ir::GlobalValueData::VMContext);
|
||||
let ptr_type = self.pointer_type();
|
||||
|
||||
match mem_index.local_or_import(self.env.module) {
|
||||
LocalOrImport::Local(local_mem_index) => {
|
||||
let memories_base_addr = func.create_global_value(ir::GlobalValueData::Load {
|
||||
base: vmctx,
|
||||
offset: (vm::Ctx::offset_memories() as i32).into(),
|
||||
global_type: ptr_type,
|
||||
readonly: true,
|
||||
});
|
||||
|
||||
let memory_offset = local_mem_index.index() * vm::LocalMemory::size() as usize;
|
||||
|
||||
let memory_struct_addr = func.create_global_value(ir::GlobalValueData::IAddImm {
|
||||
base: memories_base_addr,
|
||||
offset: (memory_offset as i64).into(),
|
||||
global_type: ptr_type,
|
||||
});
|
||||
|
||||
let memory_base_addr = func.create_global_value(ir::GlobalValueData::Load {
|
||||
base: memory_struct_addr,
|
||||
offset: (vm::LocalMemory::offset_base() as i32).into(),
|
||||
global_type: ptr_type,
|
||||
readonly: true,
|
||||
});
|
||||
|
||||
func.create_heap(ir::HeapData {
|
||||
base: memory_base_addr,
|
||||
min_size: (self.env.module.memories[local_mem_index].min as u64).into(),
|
||||
offset_guard_size: (LinearMemory::DEFAULT_GUARD_SIZE as u64).into(),
|
||||
style: ir::HeapStyle::Static {
|
||||
bound: (LinearMemory::DEFAULT_HEAP_SIZE as u64).into(),
|
||||
},
|
||||
index_type: ir::types::I32,
|
||||
})
|
||||
}
|
||||
LocalOrImport::Import(imported_mem_index) => {
|
||||
let imported_memories_base = func.create_global_value(ir::GlobalValueData::Load {
|
||||
base: vmctx,
|
||||
offset: (vm::Ctx::offset_imported_memories() as i32).into(),
|
||||
global_type: ptr_type,
|
||||
readonly: true,
|
||||
});
|
||||
|
||||
let imported_memory_offset =
|
||||
imported_mem_index.index() * vm::ImportedMemory::size() as usize;
|
||||
|
||||
let imported_memory_struct_addr =
|
||||
func.create_global_value(ir::GlobalValueData::IAddImm {
|
||||
base: imported_memories_base,
|
||||
offset: (imported_memory_offset as i64).into(),
|
||||
global_type: ptr_type,
|
||||
});
|
||||
|
||||
let local_memory_struct_addr =
|
||||
func.create_global_value(ir::GlobalValueData::Load {
|
||||
base: imported_memory_struct_addr,
|
||||
offset: (vm::ImportedMemory::offset_memory() as i32).into(),
|
||||
global_type: ptr_type,
|
||||
readonly: true,
|
||||
});
|
||||
|
||||
let local_memory_base = func.create_global_value(ir::GlobalValueData::Load {
|
||||
base: local_memory_struct_addr,
|
||||
offset: (vm::LocalMemory::offset_base() as i32).into(),
|
||||
global_type: ptr_type,
|
||||
readonly: true,
|
||||
});
|
||||
|
||||
func.create_heap(ir::HeapData {
|
||||
base: local_memory_base,
|
||||
min_size: (self.env.module.imported_memories[imported_mem_index].1.min as u64)
|
||||
.into(),
|
||||
offset_guard_size: (LinearMemory::DEFAULT_GUARD_SIZE as u64).into(),
|
||||
style: ir::HeapStyle::Static {
|
||||
bound: (LinearMemory::DEFAULT_HEAP_SIZE as u64).into(),
|
||||
},
|
||||
index_type: ir::types::I32,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Sets up the necessary preamble definitions in `func` to access the table identified
|
||||
/// by `index`.
|
||||
///
|
||||
/// The index space covers both imported and locally declared tables.
|
||||
fn make_table(
|
||||
&mut self,
|
||||
func: &mut ir::Function,
|
||||
clif_table_index: cranelift_wasm::TableIndex,
|
||||
) -> ir::Table {
|
||||
let table_index: TableIndex = Converter(clif_table_index).into();
|
||||
// Create VMContext value.
|
||||
let vmctx = func.create_global_value(ir::GlobalValueData::VMContext);
|
||||
let ptr_type = self.pointer_type();
|
||||
|
||||
match table_index.local_or_import(self.env.module) {
|
||||
LocalOrImport::Local(local_table_index) => {
|
||||
let tables_base = func.create_global_value(ir::GlobalValueData::Load {
|
||||
base: vmctx,
|
||||
offset: (vm::Ctx::offset_tables() as i32).into(),
|
||||
global_type: ptr_type,
|
||||
readonly: true,
|
||||
});
|
||||
|
||||
let table_struct_offset =
|
||||
local_table_index.index() * vm::LocalTable::size() as usize;
|
||||
|
||||
let table_struct_addr = func.create_global_value(ir::GlobalValueData::IAddImm {
|
||||
base: tables_base,
|
||||
offset: (table_struct_offset as i64).into(),
|
||||
global_type: ptr_type,
|
||||
});
|
||||
|
||||
let table_base = func.create_global_value(ir::GlobalValueData::Load {
|
||||
base: table_struct_addr,
|
||||
offset: (vm::LocalTable::offset_base() as i32).into(),
|
||||
global_type: ptr_type,
|
||||
// we will support growing tables, so this cannot be readonly.
|
||||
readonly: false,
|
||||
});
|
||||
|
||||
let table_bound = func.create_global_value(ir::GlobalValueData::Load {
|
||||
base: table_struct_addr,
|
||||
offset: (vm::LocalTable::offset_current_elements() as i32).into(),
|
||||
// the number of elements in a table will always fit in an `i32`.
|
||||
global_type: ir::types::I32,
|
||||
readonly: false,
|
||||
});
|
||||
|
||||
func.create_table(ir::TableData {
|
||||
base_gv: table_base,
|
||||
min_size: (self.env.module.tables[local_table_index].min as u64).into(),
|
||||
bound_gv: table_bound,
|
||||
element_size: (vm::Anyfunc::size() as u64).into(),
|
||||
index_type: ir::types::I32,
|
||||
})
|
||||
}
|
||||
LocalOrImport::Import(imported_table_index) => {
|
||||
let imported_tables_base = func.create_global_value(ir::GlobalValueData::Load {
|
||||
base: vmctx,
|
||||
offset: (vm::Ctx::offset_imported_memories() as i32).into(),
|
||||
global_type: ptr_type,
|
||||
readonly: true,
|
||||
});
|
||||
|
||||
let imported_table_struct_offset =
|
||||
imported_table_index.index() * vm::ImportedTable::size() as usize;
|
||||
|
||||
let imported_table_struct_addr =
|
||||
func.create_global_value(ir::GlobalValueData::IAddImm {
|
||||
base: imported_tables_base,
|
||||
offset: (imported_table_struct_offset as i64).into(),
|
||||
global_type: ptr_type,
|
||||
});
|
||||
|
||||
let local_table_struct_addr = func.create_global_value(ir::GlobalValueData::Load {
|
||||
base: imported_table_struct_addr,
|
||||
offset: (vm::ImportedTable::offset_table() as i32).into(),
|
||||
global_type: ptr_type,
|
||||
readonly: true,
|
||||
});
|
||||
|
||||
let local_table_base = func.create_global_value(ir::GlobalValueData::Load {
|
||||
base: local_table_struct_addr,
|
||||
offset: (vm::LocalTable::offset_base() as i32).into(),
|
||||
global_type: ptr_type,
|
||||
readonly: false,
|
||||
});
|
||||
|
||||
let local_table_bound = func.create_global_value(ir::GlobalValueData::Load {
|
||||
base: local_table_struct_addr,
|
||||
offset: (vm::LocalTable::offset_current_elements() as i32).into(),
|
||||
global_type: ir::types::I32,
|
||||
readonly: false,
|
||||
});
|
||||
|
||||
func.create_table(ir::TableData {
|
||||
base_gv: local_table_base,
|
||||
min_size: (self.env.module.imported_tables[imported_table_index].1.min as u64)
|
||||
.into(),
|
||||
bound_gv: local_table_bound,
|
||||
element_size: (vm::Anyfunc::size() as u64).into(),
|
||||
index_type: ir::types::I32,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Sets up a signature definition in `func`'s preamble.
|
||||
///
|
||||
/// Signature may contain additional argument, but arguments marked as ArgumentPurpose::Normal`
|
||||
/// must correspond to the arguments in the wasm signature
|
||||
fn make_indirect_sig(
|
||||
&mut self,
|
||||
func: &mut ir::Function,
|
||||
index: cranelift_wasm::SignatureIndex,
|
||||
) -> ir::SigRef {
|
||||
// Create a signature reference out of specified signature (with VMContext param added).
|
||||
func.import_signature(self.generate_signature(index))
|
||||
}
|
||||
|
||||
/// Sets up an external function definition in the preamble of `func` that can be used to
|
||||
/// directly call the function `index`.
|
||||
///
|
||||
/// The index space covers both imported functions and functions defined in the current module.
|
||||
fn make_direct_func(
|
||||
&mut self,
|
||||
func: &mut ir::Function,
|
||||
func_index: cranelift_wasm::FuncIndex,
|
||||
) -> ir::FuncRef {
|
||||
// Get signature of function.
|
||||
let signature_index = self.env.get_func_type(func_index);
|
||||
|
||||
// Create a signature reference from specified signature (with VMContext param added).
|
||||
let signature = func.import_signature(self.generate_signature(signature_index));
|
||||
|
||||
// Get name of function.
|
||||
let name = ir::ExternalName::user(0, func_index.as_u32());
|
||||
|
||||
// Create function reference from fuction data.
|
||||
func.import_function(ir::ExtFuncData {
|
||||
name,
|
||||
signature,
|
||||
colocated: false,
|
||||
})
|
||||
}
|
||||
|
||||
/// Generates an indirect call IR with `callee` and `call_args`.
|
||||
///
|
||||
/// Inserts instructions at `pos` to the function `callee` in the table
|
||||
/// `table_index` with WebAssembly signature `sig_index`
|
||||
#[cfg_attr(feature = "cargo-clippy", allow(clippy::too_many_arguments))]
|
||||
fn translate_call_indirect(
|
||||
&mut self,
|
||||
mut pos: FuncCursor,
|
||||
_table_index: cranelift_wasm::TableIndex,
|
||||
table: ir::Table,
|
||||
sig_index: cranelift_wasm::SignatureIndex,
|
||||
sig_ref: ir::SigRef,
|
||||
callee: ir::Value,
|
||||
call_args: &[ir::Value],
|
||||
) -> cranelift_wasm::WasmResult<ir::Inst> {
|
||||
// Get the pointer type based on machine's pointer size.
|
||||
let ptr_type = self.pointer_type();
|
||||
|
||||
// The `callee` value is an index into a table of Anyfunc structures.
|
||||
let entry_addr = pos.ins().table_addr(ptr_type, table, callee, 0);
|
||||
|
||||
let mflags = ir::MemFlags::trusted();
|
||||
|
||||
let func_ptr = pos.ins().load(
|
||||
ptr_type,
|
||||
mflags,
|
||||
entry_addr,
|
||||
vm::Anyfunc::offset_func() as i32,
|
||||
);
|
||||
let vmctx_ptr = pos.ins().load(
|
||||
ptr_type,
|
||||
mflags,
|
||||
entry_addr,
|
||||
vm::Anyfunc::offset_vmctx() as i32,
|
||||
);
|
||||
let found_sig = pos.ins().load(
|
||||
ir::types::I32,
|
||||
mflags,
|
||||
entry_addr,
|
||||
vm::Anyfunc::offset_sig_id() as i32,
|
||||
);
|
||||
|
||||
pos.ins().trapz(func_ptr, ir::TrapCode::IndirectCallToNull);
|
||||
|
||||
let deduplicated_sig_index = self
|
||||
.env
|
||||
.module
|
||||
.sig_registry
|
||||
.lookup_deduplicated_sigindex(Converter(sig_index).into());
|
||||
let expected_sig = pos
|
||||
.ins()
|
||||
.iconst(ir::types::I32, deduplicated_sig_index.index() as i64);
|
||||
let not_equal_flags = pos.ins().ifcmp(found_sig, expected_sig);
|
||||
|
||||
pos.ins().trapif(
|
||||
ir::condcodes::IntCC::NotEqual,
|
||||
not_equal_flags,
|
||||
ir::TrapCode::BadSignature,
|
||||
);
|
||||
|
||||
// Build a value list for the indirect call instruction containing the call_args
|
||||
// and the vmctx parameter.
|
||||
let mut args = Vec::with_capacity(call_args.len() + 1);
|
||||
args.extend(call_args.iter().cloned());
|
||||
args.push(vmctx_ptr);
|
||||
|
||||
Ok(pos.ins().call_indirect(sig_ref, func_ptr, &args))
|
||||
}
|
||||
|
||||
/// Generates a call IR with `callee` and `call_args` and inserts it at `pos`
|
||||
/// TODO: add support for imported functions
|
||||
fn translate_call(
|
||||
&mut self,
|
||||
mut pos: FuncCursor,
|
||||
clif_callee_index: cranelift_wasm::FuncIndex,
|
||||
callee: ir::FuncRef,
|
||||
call_args: &[ir::Value],
|
||||
) -> cranelift_wasm::WasmResult<ir::Inst> {
|
||||
let callee_index: FuncIndex = Converter(clif_callee_index).into();
|
||||
|
||||
match callee_index.local_or_import(self.env.module) {
|
||||
LocalOrImport::Local(_) => {
|
||||
// this is an internal function
|
||||
let vmctx = pos
|
||||
.func
|
||||
.special_param(ir::ArgumentPurpose::VMContext)
|
||||
.expect("missing vmctx parameter");
|
||||
|
||||
let mut args = Vec::with_capacity(call_args.len() + 1);
|
||||
args.extend(call_args.iter().cloned());
|
||||
args.push(vmctx);
|
||||
|
||||
Ok(pos.ins().call(callee, &args))
|
||||
}
|
||||
LocalOrImport::Import(imported_func_index) => {
|
||||
let ptr_type = self.pointer_type();
|
||||
// this is an imported function
|
||||
let vmctx = pos.func.create_global_value(ir::GlobalValueData::VMContext);
|
||||
|
||||
let imported_funcs = pos.func.create_global_value(ir::GlobalValueData::Load {
|
||||
base: vmctx,
|
||||
offset: (vm::Ctx::offset_imported_funcs() as i32).into(),
|
||||
global_type: ptr_type,
|
||||
readonly: true,
|
||||
});
|
||||
|
||||
let imported_func_offset =
|
||||
imported_func_index.index() * vm::ImportedFunc::size() as usize;
|
||||
|
||||
let imported_func_struct_addr =
|
||||
pos.func.create_global_value(ir::GlobalValueData::IAddImm {
|
||||
base: imported_funcs,
|
||||
offset: (imported_func_offset as i64).into(),
|
||||
global_type: ptr_type,
|
||||
});
|
||||
|
||||
let imported_func_addr = pos.func.create_global_value(ir::GlobalValueData::Load {
|
||||
base: imported_func_struct_addr,
|
||||
offset: (vm::ImportedFunc::offset_func() as i32).into(),
|
||||
global_type: ptr_type,
|
||||
readonly: true,
|
||||
});
|
||||
|
||||
let imported_vmctx_addr = pos.func.create_global_value(ir::GlobalValueData::Load {
|
||||
base: imported_func_struct_addr,
|
||||
offset: (vm::ImportedFunc::offset_vmctx() as i32).into(),
|
||||
global_type: ptr_type,
|
||||
readonly: true,
|
||||
});
|
||||
|
||||
let imported_func_addr = pos.ins().global_value(ptr_type, imported_func_addr);
|
||||
let imported_vmctx_addr = pos.ins().global_value(ptr_type, imported_vmctx_addr);
|
||||
|
||||
let sig_ref = pos.func.dfg.ext_funcs[callee].signature;
|
||||
|
||||
let mut args = Vec::with_capacity(call_args.len() + 1);
|
||||
args.extend(call_args.iter().cloned());
|
||||
args.push(imported_vmctx_addr);
|
||||
|
||||
Ok(pos
|
||||
.ins()
|
||||
.call_indirect(sig_ref, imported_func_addr, &args[..]))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Generates code corresponding to wasm `memory.grow`.
|
||||
///
|
||||
/// `index` refers to the linear memory to query.
|
||||
///
|
||||
/// `heap` refers to the IR generated by `make_heap`.
|
||||
///
|
||||
/// `val` refers the value to grow the memory by.
|
||||
fn translate_memory_grow(
|
||||
&mut self,
|
||||
mut pos: FuncCursor,
|
||||
index: cranelift_wasm::MemoryIndex,
|
||||
_heap: ir::Heap,
|
||||
val: ir::Value,
|
||||
) -> cranelift_wasm::WasmResult<ir::Value> {
|
||||
let signature = pos.func.import_signature(ir::Signature {
|
||||
call_conv: self.target_config().default_call_conv,
|
||||
params: vec![
|
||||
ir::AbiParam::new(ir::types::I32),
|
||||
ir::AbiParam::new(ir::types::I32),
|
||||
ir::AbiParam::special(self.pointer_type(), ir::ArgumentPurpose::VMContext),
|
||||
],
|
||||
returns: vec![ir::AbiParam::new(ir::types::I32)],
|
||||
});
|
||||
|
||||
let grow_mem_func = pos.func.import_function(ir::ExtFuncData {
|
||||
// `ir::ExternalName` for static_grow_memory`
|
||||
name: ir::ExternalName::user(1, 0),
|
||||
signature,
|
||||
colocated: false,
|
||||
});
|
||||
|
||||
// Create a memory index value.
|
||||
let memory_index = pos.ins().iconst(ir::types::I32, index.index() as i64);
|
||||
|
||||
// Create a VMContext value.
|
||||
let vmctx = pos
|
||||
.func
|
||||
.special_param(ir::ArgumentPurpose::VMContext)
|
||||
.expect("missing vmctx parameter");
|
||||
|
||||
// Insert call instructions for `grow_memory`.
|
||||
let call_inst = pos.ins().call(grow_mem_func, &[memory_index, val, vmctx]);
|
||||
|
||||
// Return value.
|
||||
Ok(*pos.func.dfg.inst_results(call_inst).first().unwrap())
|
||||
}
|
||||
|
||||
/// Generates code corresponding to wasm `memory.size`.
|
||||
///
|
||||
/// `index` refers to the linear memory to query.
|
||||
///
|
||||
/// `heap` refers to the IR generated by `make_heap`.
|
||||
fn translate_memory_size(
|
||||
&mut self,
|
||||
mut pos: FuncCursor,
|
||||
index: cranelift_wasm::MemoryIndex,
|
||||
_heap: ir::Heap,
|
||||
) -> cranelift_wasm::WasmResult<ir::Value> {
|
||||
let signature = pos.func.import_signature(ir::Signature {
|
||||
call_conv: self.target_config().default_call_conv,
|
||||
params: vec![
|
||||
ir::AbiParam::new(ir::types::I32),
|
||||
ir::AbiParam::special(self.pointer_type(), ir::ArgumentPurpose::VMContext),
|
||||
],
|
||||
returns: vec![ir::AbiParam::new(ir::types::I32)],
|
||||
});
|
||||
|
||||
let size_mem_func = pos.func.import_function(ir::ExtFuncData {
|
||||
// `ir::ExternalName` for static_grow_memory`
|
||||
name: ir::ExternalName::user(1, 1),
|
||||
signature,
|
||||
colocated: false,
|
||||
});
|
||||
|
||||
// Create a memory index value.
|
||||
let memory_index = pos.ins().iconst(ir::types::I32, index.index() as i64);
|
||||
|
||||
// Create a VMContext value.
|
||||
let vmctx = pos
|
||||
.func
|
||||
.special_param(ir::ArgumentPurpose::VMContext)
|
||||
.expect("missing vmctx parameter");
|
||||
|
||||
// Insert call instructions for `grow_memory`.
|
||||
let call_inst = pos.ins().call(size_mem_func, &[memory_index, vmctx]);
|
||||
|
||||
// Return value.
|
||||
Ok(*pos.func.dfg.inst_results(call_inst).first().unwrap())
|
||||
}
|
||||
}
|
@ -1,8 +1,10 @@
|
||||
pub mod codegen;
|
||||
// pub mod codegen;
|
||||
mod func_env;
|
||||
mod libcalls;
|
||||
mod module;
|
||||
mod module_env;
|
||||
mod relocation;
|
||||
mod resolver;
|
||||
// mod module;
|
||||
|
||||
use cranelift_codegen::{
|
||||
isa,
|
||||
@ -12,9 +14,6 @@ use target_lexicon::Triple;
|
||||
use wasmer_runtime::{backend::Compiler, module::ModuleInner};
|
||||
use wasmparser::{self, WasmDecoder};
|
||||
|
||||
use self::codegen::converter;
|
||||
use self::codegen::CraneliftModule;
|
||||
|
||||
pub struct CraneliftCompiler {}
|
||||
|
||||
impl CraneliftCompiler {
|
||||
@ -29,14 +28,12 @@ impl Compiler for CraneliftCompiler {
|
||||
validate(wasm)?;
|
||||
|
||||
let isa = get_isa();
|
||||
// Generate a Cranlift module from wasm binary
|
||||
let cranelift_module = CraneliftModule::from_bytes(&wasm.to_vec(), isa.frontend_config())?;
|
||||
|
||||
// Convert Cranelift module to wasmer module
|
||||
let wasmer_module = converter::convert_module(cranelift_module);
|
||||
let mut module = module::Module::empty();
|
||||
let module_env = module_env::ModuleEnv::new(&mut module, &*isa);
|
||||
let func_bodies = module_env.translate(wasm)?;
|
||||
|
||||
// Return new wasmer module
|
||||
Ok(wasmer_module)
|
||||
module.compile(&*isa, func_bodies)
|
||||
}
|
||||
}
|
||||
|
||||
@ -61,11 +58,11 @@ fn validate(bytes: &[u8]) -> Result<(), String> {
|
||||
loop {
|
||||
let state = parser.read();
|
||||
match *state {
|
||||
wasmparser::ParserState::EndWasm => return Ok(()),
|
||||
wasmparser::ParserState::EndWasm => break Ok(()),
|
||||
wasmparser::ParserState::Error(err) => {
|
||||
return Err(format!("Validation error: {}", err.message));
|
||||
}
|
||||
_ => (),
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,20 +1,158 @@
|
||||
use crate::resolver::FuncResolverBuilder;
|
||||
use cranelift_codegen::{ir, isa};
|
||||
use cranelift_entity::EntityRef;
|
||||
use cranelift_wasm;
|
||||
use hashbrown::HashMap;
|
||||
use std::{
|
||||
ops::{Deref, DerefMut},
|
||||
ptr::NonNull,
|
||||
};
|
||||
use wasmer_runtime::{
|
||||
backend::FuncResolver,
|
||||
backend::SigRegistry,
|
||||
memory::LinearMemory,
|
||||
module::{
|
||||
DataInitializer, ExportIndex, ImportName, ModuleInner, TableInitializer,
|
||||
},
|
||||
module::ModuleInner,
|
||||
structures::{Map, TypedIndex},
|
||||
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,
|
||||
FuncIndex, FuncSig, GlobalIndex, LocalFuncIndex, MemoryIndex, SigIndex, TableIndex, Type,
|
||||
},
|
||||
vm::{self, Ctx as WasmerVMContext},
|
||||
vm,
|
||||
};
|
||||
|
||||
/// This is a wasmer module.
|
||||
pub struct Module {
|
||||
struct PlaceholderFuncResolver;
|
||||
|
||||
impl FuncResolver for PlaceholderFuncResolver {
|
||||
fn get(
|
||||
&self,
|
||||
_module: &ModuleInner,
|
||||
_local_func_index: LocalFuncIndex,
|
||||
) -> Option<NonNull<vm::Func>> {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
/// This contains all of the items in a `ModuleInner` except the `func_resolver`.
|
||||
pub struct Module {
|
||||
module: ModuleInner,
|
||||
}
|
||||
|
||||
impl Module {
|
||||
pub fn empty() -> Self {
|
||||
Self {
|
||||
module: ModuleInner {
|
||||
// this is a placeholder
|
||||
func_resolver: Box::new(PlaceholderFuncResolver),
|
||||
memories: Map::new(),
|
||||
globals: Map::new(),
|
||||
tables: Map::new(),
|
||||
|
||||
imported_functions: Map::new(),
|
||||
imported_memories: Map::new(),
|
||||
imported_tables: Map::new(),
|
||||
imported_globals: Map::new(),
|
||||
|
||||
exports: HashMap::new(),
|
||||
|
||||
data_initializers: Vec::new(),
|
||||
elem_initializers: Vec::new(),
|
||||
|
||||
start_func: None,
|
||||
|
||||
func_assoc: Map::new(),
|
||||
sig_registry: SigRegistry::new(),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
pub fn compile(
|
||||
mut self,
|
||||
isa: &isa::TargetIsa,
|
||||
functions: Map<LocalFuncIndex, ir::Function>,
|
||||
) -> Result<ModuleInner, String> {
|
||||
// we have to deduplicate `module.func_assoc`
|
||||
let func_assoc = &mut self.module.func_assoc;
|
||||
let sig_registry = &self.module.sig_registry;
|
||||
func_assoc.iter_mut().for_each(|(_, sig_index)| {
|
||||
*sig_index = sig_registry.lookup_deduplicated_sigindex(*sig_index);
|
||||
});
|
||||
|
||||
let func_resolver_builder = FuncResolverBuilder::new(isa, functions)?;
|
||||
self.module.func_resolver = Box::new(func_resolver_builder.finalize()?);
|
||||
Ok(self.module)
|
||||
}
|
||||
}
|
||||
|
||||
impl Deref for Module {
|
||||
type Target = ModuleInner;
|
||||
|
||||
fn deref(&self) -> &ModuleInner {
|
||||
&self.module
|
||||
}
|
||||
}
|
||||
|
||||
impl DerefMut for Module {
|
||||
fn deref_mut(&mut self) -> &mut ModuleInner {
|
||||
&mut self.module
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Converter<T>(pub T);
|
||||
|
||||
macro_rules! convert_clif_to_runtime_index {
|
||||
($clif_index:ident, $runtime_index:ident) => {
|
||||
impl From<Converter<cranelift_wasm::$clif_index>> for $runtime_index {
|
||||
fn from(clif_index: Converter<cranelift_wasm::$clif_index>) -> Self {
|
||||
$runtime_index::new(clif_index.0.index())
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Converter<$runtime_index>> for cranelift_wasm::$clif_index {
|
||||
fn from(runtime_index: Converter<$runtime_index>) -> Self {
|
||||
cranelift_wasm::$clif_index::new(runtime_index.0.index())
|
||||
}
|
||||
}
|
||||
};
|
||||
($(($clif_index:ident: $runtime_index:ident),)*) => {
|
||||
$(
|
||||
convert_clif_to_runtime_index!($clif_index, $runtime_index);
|
||||
)*
|
||||
};
|
||||
}
|
||||
|
||||
convert_clif_to_runtime_index![
|
||||
(FuncIndex: FuncIndex),
|
||||
(MemoryIndex: MemoryIndex),
|
||||
(TableIndex: TableIndex),
|
||||
(GlobalIndex: GlobalIndex),
|
||||
(SignatureIndex: SigIndex),
|
||||
];
|
||||
|
||||
impl<'a> From<Converter<&'a ir::Signature>> for FuncSig {
|
||||
fn from(signature: Converter<&'a ir::Signature>) -> Self {
|
||||
FuncSig {
|
||||
params: signature
|
||||
.0
|
||||
.params
|
||||
.iter()
|
||||
.map(|param| Converter(param.value_type).into())
|
||||
.collect(),
|
||||
returns: signature
|
||||
.0
|
||||
.returns
|
||||
.iter()
|
||||
.map(|ret| Converter(ret.value_type).into())
|
||||
.collect(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Converter<ir::Type>> for Type {
|
||||
fn from(ty: Converter<ir::Type>) -> Self {
|
||||
match ty.0 {
|
||||
ir::types::I32 => Type::I32,
|
||||
ir::types::I64 => Type::I64,
|
||||
ir::types::F32 => Type::F32,
|
||||
ir::types::F64 => Type::F64,
|
||||
_ => panic!("unsupported wasm type"),
|
||||
}
|
||||
}
|
||||
}
|
364
lib/clif-backend/src/module_env.rs
Normal file
364
lib/clif-backend/src/module_env.rs
Normal file
@ -0,0 +1,364 @@
|
||||
use crate::{
|
||||
func_env::FuncEnv,
|
||||
module::{Converter, Module},
|
||||
};
|
||||
use cranelift_codegen::{ir, isa};
|
||||
use cranelift_wasm::{self, translate_module, FuncTranslator, ModuleEnvironment};
|
||||
use wasmer_runtime::{
|
||||
module::{DataInitializer, ExportIndex, ImportName, TableInitializer},
|
||||
structures::{Map, TypedIndex},
|
||||
types::{
|
||||
ElementType, Global, GlobalDesc, GlobalIndex, Initializer, LocalFuncIndex, LocalOrImport,
|
||||
Memory, SigIndex, Table, Value,
|
||||
},
|
||||
};
|
||||
|
||||
pub struct ModuleEnv<'module, 'isa> {
|
||||
pub module: &'module mut Module,
|
||||
isa: &'isa isa::TargetIsa,
|
||||
pub signatures: Map<SigIndex, ir::Signature>,
|
||||
globals: Map<GlobalIndex, cranelift_wasm::Global>,
|
||||
func_bodies: Map<LocalFuncIndex, ir::Function>,
|
||||
}
|
||||
|
||||
impl<'module, 'isa> ModuleEnv<'module, 'isa> {
|
||||
pub fn new(module: &'module mut Module, isa: &'isa isa::TargetIsa) -> Self {
|
||||
Self {
|
||||
module,
|
||||
isa,
|
||||
signatures: Map::new(),
|
||||
globals: Map::new(),
|
||||
func_bodies: Map::new(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn translate(mut self, wasm: &[u8]) -> Result<Map<LocalFuncIndex, ir::Function>, String> {
|
||||
translate_module(wasm, &mut self).map_err(|e| e.to_string())?;
|
||||
Ok(self.func_bodies)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'module, 'isa, 'data> ModuleEnvironment<'data> for ModuleEnv<'module, 'isa> {
|
||||
/// Get the information needed to produce Cranelift IR for the current target.
|
||||
fn target_config(&self) -> isa::TargetFrontendConfig {
|
||||
self.isa.frontend_config()
|
||||
}
|
||||
|
||||
/// Declares a function signature to the environment.
|
||||
fn declare_signature(&mut self, sig: &ir::Signature) {
|
||||
self.signatures.push(sig.clone());
|
||||
self.module.sig_registry.register(Converter(sig).into());
|
||||
}
|
||||
|
||||
/// Return the signature with the given index.
|
||||
fn get_signature(&self, sig_index: cranelift_wasm::SignatureIndex) -> &ir::Signature {
|
||||
&self.signatures[Converter(sig_index).into()]
|
||||
}
|
||||
|
||||
/// Declares a function import to the environment.
|
||||
fn declare_func_import(
|
||||
&mut self,
|
||||
sig_index: cranelift_wasm::SignatureIndex,
|
||||
namespace: &'data str,
|
||||
name: &'data str,
|
||||
) {
|
||||
self.module.func_assoc.push(Converter(sig_index).into());
|
||||
|
||||
// Add import names to list of imported functions
|
||||
self.module.imported_functions.push(ImportName {
|
||||
namespace: namespace.to_string(),
|
||||
name: name.to_string(),
|
||||
});
|
||||
}
|
||||
|
||||
/// Return the number of imported funcs.
|
||||
fn get_num_func_imports(&self) -> usize {
|
||||
self.module.imported_functions.len()
|
||||
}
|
||||
|
||||
/// Declares the type (signature) of a local function in the module.
|
||||
fn declare_func_type(&mut self, sig_index: cranelift_wasm::SignatureIndex) {
|
||||
self.module.func_assoc.push(Converter(sig_index).into());
|
||||
}
|
||||
|
||||
/// Return the signature index for the given function index.
|
||||
fn get_func_type(
|
||||
&self,
|
||||
func_index: cranelift_wasm::FuncIndex,
|
||||
) -> cranelift_wasm::SignatureIndex {
|
||||
Converter(self.module.func_assoc[Converter(func_index).into()]).into()
|
||||
}
|
||||
|
||||
/// Declares a global to the environment.
|
||||
fn declare_global(&mut self, global: cranelift_wasm::Global) {
|
||||
use cranelift_wasm::GlobalInit;
|
||||
|
||||
let desc = GlobalDesc {
|
||||
mutable: global.mutability,
|
||||
ty: Converter(global.ty).into(),
|
||||
};
|
||||
|
||||
let init = match global.initializer {
|
||||
GlobalInit::I32Const(x) => Initializer::Const(Value::I32(x)),
|
||||
GlobalInit::I64Const(x) => Initializer::Const(Value::I64(x)),
|
||||
GlobalInit::F32Const(x) => Initializer::Const(Value::F32(f32::from_bits(x))),
|
||||
GlobalInit::F64Const(x) => Initializer::Const(Value::F64(f64::from_bits(x))),
|
||||
GlobalInit::GetGlobal(global_index) => {
|
||||
assert!(!desc.mutable);
|
||||
let global_index: GlobalIndex = Converter(global_index).into();
|
||||
let imported_global_index = global_index
|
||||
.local_or_import(self.module)
|
||||
.import()
|
||||
.expect("invalid global initializer when declaring an imported global");
|
||||
Initializer::GetGlobal(imported_global_index)
|
||||
}
|
||||
_ => panic!("invalid global initializer when declaring a local global"),
|
||||
};
|
||||
|
||||
// Add global ir to the list of globals
|
||||
self.module.globals.push(Global { desc, init });
|
||||
|
||||
self.globals.push(global);
|
||||
}
|
||||
|
||||
/// Declares a global import to the environment.
|
||||
fn declare_global_import(
|
||||
&mut self,
|
||||
global: cranelift_wasm::Global,
|
||||
namespace: &'data str,
|
||||
name: &'data str,
|
||||
) {
|
||||
assert!(match global.initializer {
|
||||
cranelift_wasm::GlobalInit::Import => true,
|
||||
_ => false,
|
||||
});
|
||||
|
||||
let import_name = ImportName {
|
||||
namespace: namespace.to_string(),
|
||||
name: name.to_string(),
|
||||
};
|
||||
|
||||
let desc = GlobalDesc {
|
||||
mutable: global.mutability,
|
||||
ty: Converter(global.ty).into(),
|
||||
};
|
||||
|
||||
// Add global ir to the list of globals
|
||||
self.module.imported_globals.push((import_name, desc));
|
||||
|
||||
self.globals.push(global);
|
||||
}
|
||||
|
||||
/// Return the global for the given global index.
|
||||
fn get_global(&self, global_index: cranelift_wasm::GlobalIndex) -> &cranelift_wasm::Global {
|
||||
&self.globals[Converter(global_index).into()]
|
||||
}
|
||||
|
||||
/// Declares a table to the environment.
|
||||
fn declare_table(&mut self, table: cranelift_wasm::Table) {
|
||||
use cranelift_wasm::TableElementType;
|
||||
// Add table ir to the list of tables
|
||||
self.module.tables.push(Table {
|
||||
ty: match table.ty {
|
||||
TableElementType::Func => ElementType::Anyfunc,
|
||||
_ => unimplemented!(),
|
||||
},
|
||||
min: table.minimum,
|
||||
max: table.maximum,
|
||||
});
|
||||
}
|
||||
|
||||
/// Declares a table import to the environment.
|
||||
fn declare_table_import(
|
||||
&mut self,
|
||||
table: cranelift_wasm::Table,
|
||||
namespace: &'data str,
|
||||
name: &'data str,
|
||||
) {
|
||||
use cranelift_wasm::TableElementType;
|
||||
|
||||
let import_name = ImportName {
|
||||
namespace: namespace.to_string(),
|
||||
name: name.to_string(),
|
||||
};
|
||||
|
||||
let imported_table = Table {
|
||||
ty: match table.ty {
|
||||
TableElementType::Func => ElementType::Anyfunc,
|
||||
_ => unimplemented!(),
|
||||
},
|
||||
min: table.minimum,
|
||||
max: table.maximum,
|
||||
};
|
||||
|
||||
// Add import names to list of imported tables
|
||||
self.module
|
||||
.imported_tables
|
||||
.push((import_name, imported_table));
|
||||
}
|
||||
|
||||
/// Fills a declared table with references to functions in the module.
|
||||
fn declare_table_elements(
|
||||
&mut self,
|
||||
table_index: cranelift_wasm::TableIndex,
|
||||
base: Option<cranelift_wasm::GlobalIndex>,
|
||||
offset: usize,
|
||||
elements: Vec<cranelift_wasm::FuncIndex>,
|
||||
) {
|
||||
// Convert Cranelift GlobalIndex to wamser GlobalIndex
|
||||
// let base = base.map(|index| WasmerGlobalIndex::new(index.index()));
|
||||
let base = match base {
|
||||
Some(global_index) => {
|
||||
let global_index: GlobalIndex = Converter(global_index).into();
|
||||
Initializer::GetGlobal(match global_index.local_or_import(self.module) {
|
||||
LocalOrImport::Import(imported_global_index) => imported_global_index,
|
||||
LocalOrImport::Local(_) => {
|
||||
panic!("invalid global initializer when declaring an imported global")
|
||||
}
|
||||
})
|
||||
}
|
||||
None => Initializer::Const((offset as i32).into()),
|
||||
};
|
||||
|
||||
// Add table initializer to list of table initializers
|
||||
self.module.elem_initializers.push(TableInitializer {
|
||||
table_index: Converter(table_index).into(),
|
||||
base,
|
||||
elements: elements
|
||||
.iter()
|
||||
.map(|&func_index| Converter(func_index).into())
|
||||
.collect(),
|
||||
});
|
||||
}
|
||||
|
||||
/// Declares a memory to the environment
|
||||
fn declare_memory(&mut self, memory: cranelift_wasm::Memory) {
|
||||
self.module.memories.push(Memory {
|
||||
min: memory.minimum,
|
||||
max: memory.maximum,
|
||||
shared: memory.shared,
|
||||
});
|
||||
}
|
||||
|
||||
/// Declares a memory import to the environment.
|
||||
fn declare_memory_import(
|
||||
&mut self,
|
||||
memory: cranelift_wasm::Memory,
|
||||
namespace: &'data str,
|
||||
name: &'data str,
|
||||
) {
|
||||
let import_name = ImportName {
|
||||
namespace: namespace.to_string(),
|
||||
name: name.to_string(),
|
||||
};
|
||||
|
||||
let memory = Memory {
|
||||
min: memory.minimum,
|
||||
max: memory.maximum,
|
||||
shared: memory.shared,
|
||||
};
|
||||
|
||||
// Add import names to list of imported memories
|
||||
self.module.imported_memories.push((import_name, memory));
|
||||
}
|
||||
|
||||
/// Fills a declared memory with bytes at module instantiation.
|
||||
fn declare_data_initialization(
|
||||
&mut self,
|
||||
memory_index: cranelift_wasm::MemoryIndex,
|
||||
base: Option<cranelift_wasm::GlobalIndex>,
|
||||
offset: usize,
|
||||
data: &'data [u8],
|
||||
) {
|
||||
// Convert Cranelift GlobalIndex to wamser GlobalIndex
|
||||
let base = match base {
|
||||
Some(global_index) => {
|
||||
let global_index: GlobalIndex = Converter(global_index).into();
|
||||
Initializer::GetGlobal(match global_index.local_or_import(self.module) {
|
||||
LocalOrImport::Import(imported_global_index) => imported_global_index,
|
||||
LocalOrImport::Local(_) => {
|
||||
panic!("invalid global initializer when declaring an imported global")
|
||||
}
|
||||
})
|
||||
}
|
||||
None => Initializer::Const((offset as i32).into()),
|
||||
};
|
||||
|
||||
// Add data initializer to list of data initializers
|
||||
self.module.data_initializers.push(DataInitializer {
|
||||
memory_index: Converter(memory_index).into(),
|
||||
base,
|
||||
data: data.to_vec(),
|
||||
});
|
||||
}
|
||||
|
||||
/// Declares a function export to the environment.
|
||||
fn declare_func_export(&mut self, func_index: cranelift_wasm::FuncIndex, name: &'data str) {
|
||||
self.module.exports.insert(
|
||||
name.to_string(),
|
||||
ExportIndex::Func(Converter(func_index).into()),
|
||||
);
|
||||
}
|
||||
/// Declares a table export to the environment.
|
||||
fn declare_table_export(&mut self, table_index: cranelift_wasm::TableIndex, name: &'data str) {
|
||||
self.module.exports.insert(
|
||||
name.to_string(),
|
||||
ExportIndex::Table(Converter(table_index).into()),
|
||||
);
|
||||
}
|
||||
/// Declares a memory export to the environment.
|
||||
fn declare_memory_export(
|
||||
&mut self,
|
||||
memory_index: cranelift_wasm::MemoryIndex,
|
||||
name: &'data str,
|
||||
) {
|
||||
self.module.exports.insert(
|
||||
name.to_string(),
|
||||
ExportIndex::Memory(Converter(memory_index).into()),
|
||||
);
|
||||
}
|
||||
/// Declares a global export to the environment.
|
||||
fn declare_global_export(
|
||||
&mut self,
|
||||
global_index: cranelift_wasm::GlobalIndex,
|
||||
name: &'data str,
|
||||
) {
|
||||
self.module.exports.insert(
|
||||
name.to_string(),
|
||||
ExportIndex::Global(Converter(global_index).into()),
|
||||
);
|
||||
}
|
||||
|
||||
/// Declares a start function.
|
||||
fn declare_start_func(&mut self, func_index: cranelift_wasm::FuncIndex) {
|
||||
self.module.start_func = Some(Converter(func_index).into());
|
||||
}
|
||||
|
||||
/// Provides the contents of a function body.
|
||||
fn define_function_body(&mut self, body_bytes: &'data [u8]) -> cranelift_wasm::WasmResult<()> {
|
||||
let mut func_translator = FuncTranslator::new();
|
||||
|
||||
let func_body = {
|
||||
let mut func_env = FuncEnv::new(self);
|
||||
let func_index = self.func_bodies.next_index();
|
||||
let name = ir::ExternalName::user(0, func_index.index() as u32);
|
||||
|
||||
let sig = func_env.generate_signature(
|
||||
self.get_func_type(Converter(func_index.convert_up(self.module)).into()),
|
||||
);
|
||||
|
||||
let mut func = ir::Function::with_name_signature(name, sig);
|
||||
|
||||
println!("translating function");
|
||||
func_translator.translate(body_bytes, &mut func, &mut func_env)?;
|
||||
println!("done translating function");
|
||||
|
||||
func
|
||||
};
|
||||
|
||||
// Add function body to list of function bodies.
|
||||
self.func_bodies.push(func_body);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
@ -4,6 +4,7 @@
|
||||
//! function addrs in runtime with the functions we need.
|
||||
use cranelift_codegen::binemit;
|
||||
use cranelift_codegen::ir::{self, ExternalName, LibCall, SourceLoc, TrapCode};
|
||||
use wasmer_runtime::{structures::TypedIndex, types::LocalFuncIndex};
|
||||
|
||||
pub use cranelift_codegen::binemit::Reloc;
|
||||
|
||||
@ -22,11 +23,11 @@ pub struct Relocation {
|
||||
/// Specify the type of relocation
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum RelocationType {
|
||||
Normal(u32),
|
||||
Normal(LocalFuncIndex),
|
||||
Intrinsic(String),
|
||||
LibCall(LibCall),
|
||||
GrowMemory,
|
||||
CurrentMemory,
|
||||
StaticGrowMemory,
|
||||
StaticCurrentMemory,
|
||||
}
|
||||
|
||||
/// Implementation of a relocation sink that just saves all the information for later
|
||||
@ -61,22 +62,33 @@ impl binemit::RelocSink for RelocSink {
|
||||
reloc,
|
||||
offset,
|
||||
addend,
|
||||
target: RelocationType::Normal(index as _),
|
||||
target: RelocationType::Normal(LocalFuncIndex::new(index as usize)),
|
||||
});
|
||||
}
|
||||
ExternalName::TestCase { length, ascii } => {
|
||||
let (slice, _) = ascii.split_at(length as usize);
|
||||
let name = String::from_utf8(slice.to_vec()).unwrap();
|
||||
let relocation_type = match name.as_str() {
|
||||
"current_memory" => RelocationType::CurrentMemory,
|
||||
"grow_memory" => RelocationType::GrowMemory,
|
||||
_ => RelocationType::Intrinsic(name),
|
||||
ExternalName::User {
|
||||
namespace: 1,
|
||||
index,
|
||||
} => {
|
||||
let target = match index {
|
||||
0 => RelocationType::StaticGrowMemory,
|
||||
1 => RelocationType::StaticCurrentMemory,
|
||||
_ => unimplemented!(),
|
||||
};
|
||||
self.func_relocs.push(Relocation {
|
||||
reloc,
|
||||
offset,
|
||||
addend,
|
||||
target: relocation_type,
|
||||
target,
|
||||
});
|
||||
}
|
||||
ExternalName::TestCase { length, ascii } => {
|
||||
let (slice, _) = ascii.split_at(length as usize);
|
||||
let name = String::from_utf8(slice.to_vec()).unwrap();
|
||||
self.func_relocs.push(Relocation {
|
||||
reloc,
|
||||
offset,
|
||||
addend,
|
||||
target: RelocationType::Intrinsic(name),
|
||||
});
|
||||
}
|
||||
ExternalName::LibCall(libcall) => {
|
||||
|
@ -7,7 +7,8 @@ use std::ptr::{write_unaligned, NonNull};
|
||||
use wasmer_runtime::{
|
||||
self,
|
||||
backend::{self, Mmap, Protect},
|
||||
types::{LocalFuncIndex, Map, TypedIndex},
|
||||
structures::Map,
|
||||
types::LocalFuncIndex,
|
||||
vm, vmcalls,
|
||||
};
|
||||
|
||||
@ -21,8 +22,7 @@ pub struct FuncResolverBuilder {
|
||||
impl FuncResolverBuilder {
|
||||
pub fn new(
|
||||
isa: &isa::TargetIsa,
|
||||
function_bodies: Vec<ir::Function>,
|
||||
num_imported_funcs: usize,
|
||||
function_bodies: Map<LocalFuncIndex, ir::Function>,
|
||||
) -> Result<Self, String> {
|
||||
let mut compiled_functions: Vec<Vec<u8>> = Vec::with_capacity(function_bodies.len());
|
||||
let mut relocations = Map::with_capacity(function_bodies.len());
|
||||
@ -31,7 +31,7 @@ impl FuncResolverBuilder {
|
||||
let mut ctx = Context::new();
|
||||
let mut total_size = 0;
|
||||
|
||||
for func in function_bodies.into_iter() {
|
||||
for (_, func) in function_bodies {
|
||||
ctx.func = func;
|
||||
let mut code_buf = Vec::new();
|
||||
let mut reloc_sink = RelocSink::new();
|
||||
@ -71,11 +71,7 @@ impl FuncResolverBuilder {
|
||||
}
|
||||
|
||||
Ok(Self {
|
||||
resolver: FuncResolver {
|
||||
num_imported_funcs,
|
||||
map,
|
||||
memory,
|
||||
},
|
||||
resolver: FuncResolver { map, memory },
|
||||
relocations,
|
||||
trap_sinks,
|
||||
})
|
||||
@ -85,17 +81,14 @@ impl FuncResolverBuilder {
|
||||
for (index, relocs) in self.relocations.iter() {
|
||||
for ref reloc in relocs {
|
||||
let target_func_address: isize = match reloc.target {
|
||||
RelocationType::Normal(func_index) => {
|
||||
RelocationType::Normal(local_func_index) => {
|
||||
// This will always be an internal function
|
||||
// because imported functions are not
|
||||
// called in this way.
|
||||
self.resolver
|
||||
.lookup(FuncIndex::new(func_index as _))
|
||||
.unwrap()
|
||||
.as_ptr() as isize
|
||||
self.resolver.lookup(local_func_index).unwrap().as_ptr() as isize
|
||||
}
|
||||
RelocationType::CurrentMemory => vmcalls::memory_size as isize,
|
||||
RelocationType::GrowMemory => vmcalls::memory_grow_static as isize,
|
||||
RelocationType::StaticCurrentMemory => vmcalls::memory_size as isize,
|
||||
RelocationType::StaticGrowMemory => vmcalls::memory_grow_static as isize,
|
||||
RelocationType::LibCall(libcall) => match libcall {
|
||||
ir::LibCall::CeilF32 => libcalls::ceilf32 as isize,
|
||||
ir::LibCall::FloorF32 => libcalls::floorf32 as isize,
|
||||
@ -157,7 +150,6 @@ impl FuncResolverBuilder {
|
||||
|
||||
/// Resolves a function index to a function address.
|
||||
pub struct FuncResolver {
|
||||
num_imported_funcs: usize,
|
||||
map: Map<LocalFuncIndex, usize>,
|
||||
memory: Mmap,
|
||||
}
|
||||
@ -176,7 +168,7 @@ impl backend::FuncResolver for FuncResolver {
|
||||
fn get(
|
||||
&self,
|
||||
_module: &wasmer_runtime::module::ModuleInner,
|
||||
index: FuncIndex,
|
||||
index: LocalFuncIndex,
|
||||
) -> Option<NonNull<vm::Func>> {
|
||||
self.lookup(index)
|
||||
}
|
||||
|
@ -42,7 +42,7 @@ impl LocalBacking {
|
||||
|
||||
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);
|
||||
let vm_globals = Self::finalize_globals(module, imports, globals);
|
||||
|
||||
Self {
|
||||
memories,
|
||||
@ -86,16 +86,27 @@ impl LocalBacking {
|
||||
.iter()
|
||||
.filter(|init| init.data.len() > 0)
|
||||
{
|
||||
assert!(init.base.is_none(), "global base not supported yet");
|
||||
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;
|
||||
|
||||
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 data_top = init_base + init.data.len();
|
||||
println!("data_top: {}", data_top);
|
||||
assert!((memory_desc.min * LinearMemory::PAGE_SIZE) 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()];
|
||||
let to_init = &mut mem[init_base..init_base + init.data.len()];
|
||||
to_init.copy_from_slice(&init.data);
|
||||
}
|
||||
LocalOrImport::Import(imported_memory_index) => {
|
||||
@ -130,12 +141,12 @@ impl LocalBacking {
|
||||
tables: &mut SliceMap<LocalTableIndex, TableBacking>,
|
||||
vmctx: *mut vm::Ctx,
|
||||
) -> BoxedMap<LocalTableIndex, vm::LocalTable> {
|
||||
for init in &module.table_initializers {
|
||||
for init in &module.elem_initializers {
|
||||
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 {
|
||||
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")
|
||||
@ -243,14 +254,20 @@ impl LocalBacking {
|
||||
|
||||
fn finalize_globals(
|
||||
module: &ModuleInner,
|
||||
imports: &ImportBacking,
|
||||
mut globals: BoxedMap<LocalGlobalIndex, vm::LocalGlobal>,
|
||||
) -> BoxedMap<LocalGlobalIndex, vm::LocalGlobal> {
|
||||
for ((_, to), (_, from)) in globals.iter_mut().zip(module.globals.into_iter()) {
|
||||
for ((_, to), (_, from)) in globals.iter_mut().zip(module.globals.iter()) {
|
||||
to.data = match from.init {
|
||||
Value::I32(x) => x as u64,
|
||||
Value::I64(x) => x as u64,
|
||||
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
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
@ -416,13 +433,13 @@ fn import_globals(
|
||||
imports: &mut Imports,
|
||||
) -> 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 {
|
||||
for (_, (ImportName { namespace, name }, imported_global_desc)) 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 == imported_global.desc {
|
||||
if global == *imported_global_desc {
|
||||
globals.push(vm::ImportedGlobal {
|
||||
global: local.inner(),
|
||||
});
|
||||
|
@ -277,13 +277,16 @@ impl InstanceInner {
|
||||
)
|
||||
}
|
||||
LocalOrImport::Import(imported_global_index) => {
|
||||
let &(_, imported_global) = &module
|
||||
let &(_, imported_global_desc) = &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)
|
||||
(
|
||||
unsafe { GlobalPointer::new(*global) },
|
||||
*imported_global_desc,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -4,7 +4,7 @@ use crate::{
|
||||
sig_registry::SigRegistry,
|
||||
structures::Map,
|
||||
types::{
|
||||
FuncIndex, Global, GlobalIndex, ImportedFuncIndex, ImportedGlobal, ImportedGlobalIndex,
|
||||
FuncIndex, Global, GlobalDesc, GlobalIndex, ImportedFuncIndex, ImportedGlobalIndex,
|
||||
ImportedMemoryIndex, ImportedTableIndex, Initializer, LocalGlobalIndex, LocalMemoryIndex,
|
||||
LocalTableIndex, Memory, MemoryIndex, SigIndex, Table, TableIndex,
|
||||
},
|
||||
@ -26,12 +26,13 @@ pub struct ModuleInner {
|
||||
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 imported_globals: Map<ImportedGlobalIndex, (ImportName, GlobalDesc)>,
|
||||
|
||||
pub exports: HashMap<String, ExportIndex>,
|
||||
|
||||
pub data_initializers: Vec<DataInitializer>,
|
||||
pub table_initializers: Vec<TableInitializer>,
|
||||
pub elem_initializers: Vec<TableInitializer>,
|
||||
|
||||
pub start_func: Option<FuncIndex>,
|
||||
|
||||
pub func_assoc: Map<FuncIndex, SigIndex>,
|
||||
@ -82,10 +83,8 @@ pub enum ExportIndex {
|
||||
pub struct DataInitializer {
|
||||
/// The index of the memory to initialize.
|
||||
pub memory_index: MemoryIndex,
|
||||
/// Optionally a globalvalue base to initialize at.
|
||||
pub base: Option<GlobalIndex>,
|
||||
/// A constant offset to initialize at.
|
||||
pub offset: usize,
|
||||
/// Either a constant offset or a `get_global`
|
||||
pub base: Initializer,
|
||||
/// The initialization data.
|
||||
pub data: Vec<u8>,
|
||||
}
|
||||
|
@ -4,7 +4,7 @@ use std::{
|
||||
marker::PhantomData,
|
||||
mem,
|
||||
ops::{Deref, DerefMut},
|
||||
slice,
|
||||
slice, vec,
|
||||
};
|
||||
|
||||
/// Dense item map
|
||||
@ -45,6 +45,10 @@ where
|
||||
K::new(len)
|
||||
}
|
||||
|
||||
pub fn next_index(&self) -> K {
|
||||
K::new(self.len())
|
||||
}
|
||||
|
||||
pub fn reserve_exact(&mut self, size: usize) {
|
||||
self.elems.reserve_exact(size);
|
||||
}
|
||||
@ -105,6 +109,49 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
pub struct IntoIter<K, V>
|
||||
where
|
||||
K: TypedIndex,
|
||||
{
|
||||
enumerated: iter::Enumerate<vec::IntoIter<V>>,
|
||||
_marker: PhantomData<K>,
|
||||
}
|
||||
|
||||
impl<K, V> IntoIter<K, V>
|
||||
where
|
||||
K: TypedIndex,
|
||||
{
|
||||
pub(in crate::structures) fn new(into_iter: vec::IntoIter<V>) -> Self {
|
||||
Self {
|
||||
enumerated: into_iter.enumerate(),
|
||||
_marker: PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<K, V> Iterator for IntoIter<K, V>
|
||||
where
|
||||
K: TypedIndex,
|
||||
{
|
||||
type Item = (K, V);
|
||||
|
||||
fn next(&mut self) -> Option<(K, V)> {
|
||||
self.enumerated.next().map(|(i, v)| (K::new(i), v))
|
||||
}
|
||||
}
|
||||
|
||||
impl<K, V> IntoIterator for Map<K, V>
|
||||
where
|
||||
K: TypedIndex,
|
||||
{
|
||||
type Item = (K, V);
|
||||
type IntoIter = IntoIter<K, V>;
|
||||
|
||||
fn into_iter(self) -> Self::IntoIter {
|
||||
IntoIter::new(self.elems.into_iter())
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, K, V> IntoIterator for &'a Map<K, V>
|
||||
where
|
||||
K: TypedIndex,
|
||||
|
@ -7,6 +7,8 @@ pub use self::map::{Iter, IterMut, Map};
|
||||
pub use self::slice::SliceMap;
|
||||
|
||||
pub trait TypedIndex {
|
||||
#[doc(hidden)]
|
||||
fn new(index: usize) -> Self;
|
||||
#[doc(hidden)]
|
||||
fn index(&self) -> usize;
|
||||
}
|
||||
|
@ -101,23 +101,11 @@ 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: Value,
|
||||
pub init: Initializer,
|
||||
}
|
||||
|
||||
/// A wasm memory.
|
||||
@ -174,10 +162,12 @@ macro_rules! define_map_index {
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
|
||||
pub struct $ty (u32);
|
||||
impl TypedIndex for $ty {
|
||||
#[doc(hidden)]
|
||||
fn new(index: usize) -> Self {
|
||||
$ty (index as _)
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
fn index(&self) -> usize {
|
||||
self.0 as usize
|
||||
}
|
||||
@ -247,10 +237,12 @@ define_local_or_import![
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
|
||||
pub struct SigIndex(u32);
|
||||
impl TypedIndex for SigIndex {
|
||||
#[doc(hidden)]
|
||||
fn new(index: usize) -> Self {
|
||||
SigIndex(index as _)
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
fn index(&self) -> usize {
|
||||
self.0 as usize
|
||||
}
|
||||
@ -263,3 +255,22 @@ where
|
||||
Local(T::Local),
|
||||
Import(T::Import),
|
||||
}
|
||||
|
||||
impl<T> LocalOrImport<T>
|
||||
where
|
||||
T: LocalImport,
|
||||
{
|
||||
pub fn local(self) -> Option<T::Local> {
|
||||
match self {
|
||||
LocalOrImport::Local(local) => Some(local),
|
||||
LocalOrImport::Import(_) => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn import(self) -> Option<T::Import> {
|
||||
match self {
|
||||
LocalOrImport::Import(import) => Some(import),
|
||||
LocalOrImport::Local(_) => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -127,6 +127,10 @@ impl LocalTable {
|
||||
pub fn offset_current_elements() -> u8 {
|
||||
1 * (mem::size_of::<usize>() as u8)
|
||||
}
|
||||
|
||||
pub fn size() -> u8 {
|
||||
mem::size_of::<Self>() as u8
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
@ -146,6 +150,10 @@ impl ImportedTable {
|
||||
pub fn offset_vmctx() -> u8 {
|
||||
1 * (mem::size_of::<usize>() as u8)
|
||||
}
|
||||
|
||||
pub fn size() -> u8 {
|
||||
mem::size_of::<Self>() as u8
|
||||
}
|
||||
}
|
||||
|
||||
/// Definition of a memory used by the VM.
|
||||
@ -166,6 +174,10 @@ impl LocalMemory {
|
||||
pub fn offset_size() -> u8 {
|
||||
1 * (mem::size_of::<usize>() as u8)
|
||||
}
|
||||
|
||||
pub fn size() -> u8 {
|
||||
mem::size_of::<Self>() as u8
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
@ -184,6 +196,10 @@ impl ImportedMemory {
|
||||
pub fn offset_vmctx() -> u8 {
|
||||
1 * (mem::size_of::<usize>() as u8)
|
||||
}
|
||||
|
||||
pub fn size() -> u8 {
|
||||
mem::size_of::<Self>() as u8
|
||||
}
|
||||
}
|
||||
|
||||
/// Definition of a global used by the VM.
|
||||
@ -257,6 +273,10 @@ impl Anyfunc {
|
||||
pub fn offset_sig_id() -> u8 {
|
||||
2 * (mem::size_of::<usize>() as u8)
|
||||
}
|
||||
|
||||
pub fn size() -> u8 {
|
||||
mem::size_of::<Self>() as u8
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
Reference in New Issue
Block a user