mirror of
https://github.com/fluencelabs/wasmer
synced 2025-06-20 12:16:30 +00:00
Split codegen into multiple modules
This commit is contained in:
@ -25,10 +25,11 @@ use wasmer_runtime::{
|
|||||||
types::{
|
types::{
|
||||||
ElementType as WasmerElementType, FuncIndex as WasmerFuncIndex, FuncSig as WasmerSignature,
|
ElementType as WasmerElementType, FuncIndex as WasmerFuncIndex, FuncSig as WasmerSignature,
|
||||||
Global as WasmerGlobal, GlobalDesc as WasmerGlobalDesc, GlobalIndex as WasmerGlobalIndex,
|
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,
|
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},
|
vm::{self, Ctx as WasmerVMContext},
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -94,7 +95,7 @@ pub mod converter {
|
|||||||
imported_globals,
|
imported_globals,
|
||||||
exports,
|
exports,
|
||||||
data_initializers,
|
data_initializers,
|
||||||
table_initializers,
|
elem_initializers,
|
||||||
start_func,
|
start_func,
|
||||||
sig_registry,
|
sig_registry,
|
||||||
..
|
..
|
||||||
@ -112,7 +113,7 @@ pub mod converter {
|
|||||||
imported_globals,
|
imported_globals,
|
||||||
exports,
|
exports,
|
||||||
data_initializers,
|
data_initializers,
|
||||||
table_initializers,
|
elem_initializers,
|
||||||
start_func,
|
start_func,
|
||||||
func_assoc,
|
func_assoc,
|
||||||
sig_registry,
|
sig_registry,
|
||||||
@ -255,7 +256,7 @@ pub struct CraneliftModule {
|
|||||||
pub data_initializers: Vec<DataInitializer>,
|
pub data_initializers: Vec<DataInitializer>,
|
||||||
|
|
||||||
// Function indices to add to table.
|
// Function indices to add to table.
|
||||||
pub table_initializers: Vec<TableInitializer>,
|
pub elem_initializers: Vec<TableInitializer>,
|
||||||
|
|
||||||
// The start function index.
|
// The start function index.
|
||||||
pub start_func: Option<WasmerFuncIndex>,
|
pub start_func: Option<WasmerFuncIndex>,
|
||||||
@ -289,7 +290,7 @@ impl CraneliftModule {
|
|||||||
imported_globals: Map::new(),
|
imported_globals: Map::new(),
|
||||||
exports: HashMap::new(),
|
exports: HashMap::new(),
|
||||||
data_initializers: Vec::new(),
|
data_initializers: Vec::new(),
|
||||||
table_initializers: Vec::new(),
|
elem_initializers: Vec::new(),
|
||||||
start_func: None,
|
start_func: None,
|
||||||
sig_registry: SigRegistry::new(),
|
sig_registry: SigRegistry::new(),
|
||||||
};
|
};
|
||||||
@ -922,7 +923,7 @@ impl<'data> ModuleEnvironment<'data> for CraneliftModule {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Add table initializer to list of table initializers
|
// 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()),
|
table_index: WasmerTableIndex::new(table_index.index()),
|
||||||
base,
|
base,
|
||||||
elements: elements
|
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 libcalls;
|
||||||
|
mod module;
|
||||||
|
mod module_env;
|
||||||
mod relocation;
|
mod relocation;
|
||||||
mod resolver;
|
mod resolver;
|
||||||
// mod module;
|
|
||||||
|
|
||||||
use cranelift_codegen::{
|
use cranelift_codegen::{
|
||||||
isa,
|
isa,
|
||||||
@ -12,9 +14,6 @@ use target_lexicon::Triple;
|
|||||||
use wasmer_runtime::{backend::Compiler, module::ModuleInner};
|
use wasmer_runtime::{backend::Compiler, module::ModuleInner};
|
||||||
use wasmparser::{self, WasmDecoder};
|
use wasmparser::{self, WasmDecoder};
|
||||||
|
|
||||||
use self::codegen::converter;
|
|
||||||
use self::codegen::CraneliftModule;
|
|
||||||
|
|
||||||
pub struct CraneliftCompiler {}
|
pub struct CraneliftCompiler {}
|
||||||
|
|
||||||
impl CraneliftCompiler {
|
impl CraneliftCompiler {
|
||||||
@ -29,14 +28,12 @@ impl Compiler for CraneliftCompiler {
|
|||||||
validate(wasm)?;
|
validate(wasm)?;
|
||||||
|
|
||||||
let isa = get_isa();
|
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 mut module = module::Module::empty();
|
||||||
let wasmer_module = converter::convert_module(cranelift_module);
|
let module_env = module_env::ModuleEnv::new(&mut module, &*isa);
|
||||||
|
let func_bodies = module_env.translate(wasm)?;
|
||||||
|
|
||||||
// Return new wasmer module
|
module.compile(&*isa, func_bodies)
|
||||||
Ok(wasmer_module)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -61,11 +58,11 @@ fn validate(bytes: &[u8]) -> Result<(), String> {
|
|||||||
loop {
|
loop {
|
||||||
let state = parser.read();
|
let state = parser.read();
|
||||||
match *state {
|
match *state {
|
||||||
wasmparser::ParserState::EndWasm => return Ok(()),
|
wasmparser::ParserState::EndWasm => break Ok(()),
|
||||||
wasmparser::ParserState::Error(err) => {
|
wasmparser::ParserState::Error(err) => {
|
||||||
return Err(format!("Validation error: {}", err.message));
|
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::{
|
use wasmer_runtime::{
|
||||||
|
backend::FuncResolver,
|
||||||
backend::SigRegistry,
|
backend::SigRegistry,
|
||||||
memory::LinearMemory,
|
module::ModuleInner,
|
||||||
module::{
|
structures::{Map, TypedIndex},
|
||||||
DataInitializer, ExportIndex, ImportName, ModuleInner, TableInitializer,
|
|
||||||
},
|
|
||||||
types::{
|
types::{
|
||||||
ElementType, FuncIndex, FuncSig,
|
FuncIndex, FuncSig, GlobalIndex, LocalFuncIndex, MemoryIndex, SigIndex, TableIndex, Type,
|
||||||
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},
|
vm,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// This is a wasmer module.
|
struct PlaceholderFuncResolver;
|
||||||
pub struct Module {
|
|
||||||
|
|
||||||
|
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.
|
//! function addrs in runtime with the functions we need.
|
||||||
use cranelift_codegen::binemit;
|
use cranelift_codegen::binemit;
|
||||||
use cranelift_codegen::ir::{self, ExternalName, LibCall, SourceLoc, TrapCode};
|
use cranelift_codegen::ir::{self, ExternalName, LibCall, SourceLoc, TrapCode};
|
||||||
|
use wasmer_runtime::{structures::TypedIndex, types::LocalFuncIndex};
|
||||||
|
|
||||||
pub use cranelift_codegen::binemit::Reloc;
|
pub use cranelift_codegen::binemit::Reloc;
|
||||||
|
|
||||||
@ -22,11 +23,11 @@ pub struct Relocation {
|
|||||||
/// Specify the type of relocation
|
/// Specify the type of relocation
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub enum RelocationType {
|
pub enum RelocationType {
|
||||||
Normal(u32),
|
Normal(LocalFuncIndex),
|
||||||
Intrinsic(String),
|
Intrinsic(String),
|
||||||
LibCall(LibCall),
|
LibCall(LibCall),
|
||||||
GrowMemory,
|
StaticGrowMemory,
|
||||||
CurrentMemory,
|
StaticCurrentMemory,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Implementation of a relocation sink that just saves all the information for later
|
/// Implementation of a relocation sink that just saves all the information for later
|
||||||
@ -61,22 +62,33 @@ impl binemit::RelocSink for RelocSink {
|
|||||||
reloc,
|
reloc,
|
||||||
offset,
|
offset,
|
||||||
addend,
|
addend,
|
||||||
target: RelocationType::Normal(index as _),
|
target: RelocationType::Normal(LocalFuncIndex::new(index as usize)),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
ExternalName::TestCase { length, ascii } => {
|
ExternalName::User {
|
||||||
let (slice, _) = ascii.split_at(length as usize);
|
namespace: 1,
|
||||||
let name = String::from_utf8(slice.to_vec()).unwrap();
|
index,
|
||||||
let relocation_type = match name.as_str() {
|
} => {
|
||||||
"current_memory" => RelocationType::CurrentMemory,
|
let target = match index {
|
||||||
"grow_memory" => RelocationType::GrowMemory,
|
0 => RelocationType::StaticGrowMemory,
|
||||||
_ => RelocationType::Intrinsic(name),
|
1 => RelocationType::StaticCurrentMemory,
|
||||||
|
_ => unimplemented!(),
|
||||||
};
|
};
|
||||||
self.func_relocs.push(Relocation {
|
self.func_relocs.push(Relocation {
|
||||||
reloc,
|
reloc,
|
||||||
offset,
|
offset,
|
||||||
addend,
|
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) => {
|
ExternalName::LibCall(libcall) => {
|
||||||
|
@ -7,7 +7,8 @@ use std::ptr::{write_unaligned, NonNull};
|
|||||||
use wasmer_runtime::{
|
use wasmer_runtime::{
|
||||||
self,
|
self,
|
||||||
backend::{self, Mmap, Protect},
|
backend::{self, Mmap, Protect},
|
||||||
types::{LocalFuncIndex, Map, TypedIndex},
|
structures::Map,
|
||||||
|
types::LocalFuncIndex,
|
||||||
vm, vmcalls,
|
vm, vmcalls,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -21,8 +22,7 @@ pub struct FuncResolverBuilder {
|
|||||||
impl FuncResolverBuilder {
|
impl FuncResolverBuilder {
|
||||||
pub fn new(
|
pub fn new(
|
||||||
isa: &isa::TargetIsa,
|
isa: &isa::TargetIsa,
|
||||||
function_bodies: Vec<ir::Function>,
|
function_bodies: Map<LocalFuncIndex, ir::Function>,
|
||||||
num_imported_funcs: usize,
|
|
||||||
) -> Result<Self, String> {
|
) -> Result<Self, String> {
|
||||||
let mut compiled_functions: Vec<Vec<u8>> = Vec::with_capacity(function_bodies.len());
|
let mut compiled_functions: Vec<Vec<u8>> = Vec::with_capacity(function_bodies.len());
|
||||||
let mut relocations = Map::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 ctx = Context::new();
|
||||||
let mut total_size = 0;
|
let mut total_size = 0;
|
||||||
|
|
||||||
for func in function_bodies.into_iter() {
|
for (_, func) in function_bodies {
|
||||||
ctx.func = func;
|
ctx.func = func;
|
||||||
let mut code_buf = Vec::new();
|
let mut code_buf = Vec::new();
|
||||||
let mut reloc_sink = RelocSink::new();
|
let mut reloc_sink = RelocSink::new();
|
||||||
@ -71,11 +71,7 @@ impl FuncResolverBuilder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
resolver: FuncResolver {
|
resolver: FuncResolver { map, memory },
|
||||||
num_imported_funcs,
|
|
||||||
map,
|
|
||||||
memory,
|
|
||||||
},
|
|
||||||
relocations,
|
relocations,
|
||||||
trap_sinks,
|
trap_sinks,
|
||||||
})
|
})
|
||||||
@ -85,17 +81,14 @@ impl FuncResolverBuilder {
|
|||||||
for (index, relocs) in self.relocations.iter() {
|
for (index, relocs) in self.relocations.iter() {
|
||||||
for ref reloc in relocs {
|
for ref reloc in relocs {
|
||||||
let target_func_address: isize = match reloc.target {
|
let target_func_address: isize = match reloc.target {
|
||||||
RelocationType::Normal(func_index) => {
|
RelocationType::Normal(local_func_index) => {
|
||||||
// This will always be an internal function
|
// This will always be an internal function
|
||||||
// because imported functions are not
|
// because imported functions are not
|
||||||
// called in this way.
|
// called in this way.
|
||||||
self.resolver
|
self.resolver.lookup(local_func_index).unwrap().as_ptr() as isize
|
||||||
.lookup(FuncIndex::new(func_index as _))
|
|
||||||
.unwrap()
|
|
||||||
.as_ptr() as isize
|
|
||||||
}
|
}
|
||||||
RelocationType::CurrentMemory => vmcalls::memory_size as isize,
|
RelocationType::StaticCurrentMemory => vmcalls::memory_size as isize,
|
||||||
RelocationType::GrowMemory => vmcalls::memory_grow_static as isize,
|
RelocationType::StaticGrowMemory => vmcalls::memory_grow_static as isize,
|
||||||
RelocationType::LibCall(libcall) => match libcall {
|
RelocationType::LibCall(libcall) => match libcall {
|
||||||
ir::LibCall::CeilF32 => libcalls::ceilf32 as isize,
|
ir::LibCall::CeilF32 => libcalls::ceilf32 as isize,
|
||||||
ir::LibCall::FloorF32 => libcalls::floorf32 as isize,
|
ir::LibCall::FloorF32 => libcalls::floorf32 as isize,
|
||||||
@ -157,7 +150,6 @@ impl FuncResolverBuilder {
|
|||||||
|
|
||||||
/// Resolves a function index to a function address.
|
/// Resolves a function index to a function address.
|
||||||
pub struct FuncResolver {
|
pub struct FuncResolver {
|
||||||
num_imported_funcs: usize,
|
|
||||||
map: Map<LocalFuncIndex, usize>,
|
map: Map<LocalFuncIndex, usize>,
|
||||||
memory: Mmap,
|
memory: Mmap,
|
||||||
}
|
}
|
||||||
@ -176,7 +168,7 @@ impl backend::FuncResolver for FuncResolver {
|
|||||||
fn get(
|
fn get(
|
||||||
&self,
|
&self,
|
||||||
_module: &wasmer_runtime::module::ModuleInner,
|
_module: &wasmer_runtime::module::ModuleInner,
|
||||||
index: FuncIndex,
|
index: LocalFuncIndex,
|
||||||
) -> Option<NonNull<vm::Func>> {
|
) -> Option<NonNull<vm::Func>> {
|
||||||
self.lookup(index)
|
self.lookup(index)
|
||||||
}
|
}
|
||||||
|
@ -42,7 +42,7 @@ impl LocalBacking {
|
|||||||
|
|
||||||
let vm_memories = Self::finalize_memories(module, imports, &mut memories);
|
let vm_memories = Self::finalize_memories(module, imports, &mut memories);
|
||||||
let vm_tables = Self::finalize_tables(module, imports, &mut tables, vmctx);
|
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 {
|
Self {
|
||||||
memories,
|
memories,
|
||||||
@ -86,16 +86,27 @@ impl LocalBacking {
|
|||||||
.iter()
|
.iter()
|
||||||
.filter(|init| init.data.len() > 0)
|
.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) {
|
match init.memory_index.local_or_import(module) {
|
||||||
LocalOrImport::Local(local_memory_index) => {
|
LocalOrImport::Local(local_memory_index) => {
|
||||||
let memory_desc = &module.memories[local_memory_index];
|
let memory_desc = &module.memories[local_memory_index];
|
||||||
let data_top = init.offset + init.data.len();
|
let data_top = init_base + init.data.len();
|
||||||
assert!(memory_desc.min as usize >= data_top);
|
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 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);
|
to_init.copy_from_slice(&init.data);
|
||||||
}
|
}
|
||||||
LocalOrImport::Import(imported_memory_index) => {
|
LocalOrImport::Import(imported_memory_index) => {
|
||||||
@ -130,12 +141,12 @@ impl LocalBacking {
|
|||||||
tables: &mut SliceMap<LocalTableIndex, TableBacking>,
|
tables: &mut SliceMap<LocalTableIndex, TableBacking>,
|
||||||
vmctx: *mut vm::Ctx,
|
vmctx: *mut vm::Ctx,
|
||||||
) -> BoxedMap<LocalTableIndex, vm::LocalTable> {
|
) -> BoxedMap<LocalTableIndex, vm::LocalTable> {
|
||||||
for init in &module.table_initializers {
|
for init in &module.elem_initializers {
|
||||||
let init_base = match init.base {
|
let init_base = match init.base {
|
||||||
Initializer::Const(Value::I32(offset)) => offset as u32,
|
Initializer::Const(Value::I32(offset)) => offset as u32,
|
||||||
Initializer::Const(_) => panic!("a const initializer must be the i32 type"),
|
Initializer::Const(_) => panic!("a const initializer must be the i32 type"),
|
||||||
Initializer::GetGlobal(imported_global_index) => {
|
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 }
|
unsafe { (*imports.globals[imported_global_index].global).data as u32 }
|
||||||
} else {
|
} else {
|
||||||
panic!("unsupported global type for initialzer")
|
panic!("unsupported global type for initialzer")
|
||||||
@ -243,14 +254,20 @@ impl LocalBacking {
|
|||||||
|
|
||||||
fn finalize_globals(
|
fn finalize_globals(
|
||||||
module: &ModuleInner,
|
module: &ModuleInner,
|
||||||
|
imports: &ImportBacking,
|
||||||
mut globals: BoxedMap<LocalGlobalIndex, vm::LocalGlobal>,
|
mut globals: BoxedMap<LocalGlobalIndex, vm::LocalGlobal>,
|
||||||
) -> 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 {
|
to.data = match from.init {
|
||||||
Value::I32(x) => x as u64,
|
Initializer::Const(ref value) => match value {
|
||||||
Value::I64(x) => x as u64,
|
Value::I32(x) => *x as u64,
|
||||||
|
Value::I64(x) => *x as u64,
|
||||||
Value::F32(x) => x.to_bits() as u64,
|
Value::F32(x) => x.to_bits() as u64,
|
||||||
Value::F64(x) => x.to_bits(),
|
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,
|
imports: &mut Imports,
|
||||||
) -> Result<BoxedMap<ImportedGlobalIndex, vm::ImportedGlobal>, String> {
|
) -> Result<BoxedMap<ImportedGlobalIndex, vm::ImportedGlobal>, String> {
|
||||||
let mut globals = Map::with_capacity(module.imported_globals.len());
|
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
|
let import = imports
|
||||||
.get_namespace(namespace)
|
.get_namespace(namespace)
|
||||||
.and_then(|namespace| namespace.get_export(name));
|
.and_then(|namespace| namespace.get_export(name));
|
||||||
match import {
|
match import {
|
||||||
Some(Export::Global { local, global }) => {
|
Some(Export::Global { local, global }) => {
|
||||||
if global == imported_global.desc {
|
if global == *imported_global_desc {
|
||||||
globals.push(vm::ImportedGlobal {
|
globals.push(vm::ImportedGlobal {
|
||||||
global: local.inner(),
|
global: local.inner(),
|
||||||
});
|
});
|
||||||
|
@ -277,13 +277,16 @@ impl InstanceInner {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
LocalOrImport::Import(imported_global_index) => {
|
LocalOrImport::Import(imported_global_index) => {
|
||||||
let &(_, imported_global) = &module
|
let &(_, imported_global_desc) = &module
|
||||||
.imported_globals
|
.imported_globals
|
||||||
.get(imported_global_index)
|
.get(imported_global_index)
|
||||||
.expect("missing imported global index");
|
.expect("missing imported global index");
|
||||||
let vm::ImportedGlobal { global } =
|
let vm::ImportedGlobal { global } =
|
||||||
&self.import_backing.globals[imported_global_index];
|
&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,
|
sig_registry::SigRegistry,
|
||||||
structures::Map,
|
structures::Map,
|
||||||
types::{
|
types::{
|
||||||
FuncIndex, Global, GlobalIndex, ImportedFuncIndex, ImportedGlobal, ImportedGlobalIndex,
|
FuncIndex, Global, GlobalDesc, GlobalIndex, ImportedFuncIndex, ImportedGlobalIndex,
|
||||||
ImportedMemoryIndex, ImportedTableIndex, Initializer, LocalGlobalIndex, LocalMemoryIndex,
|
ImportedMemoryIndex, ImportedTableIndex, Initializer, LocalGlobalIndex, LocalMemoryIndex,
|
||||||
LocalTableIndex, Memory, MemoryIndex, SigIndex, Table, TableIndex,
|
LocalTableIndex, Memory, MemoryIndex, SigIndex, Table, TableIndex,
|
||||||
},
|
},
|
||||||
@ -26,12 +26,13 @@ pub struct ModuleInner {
|
|||||||
pub imported_functions: Map<ImportedFuncIndex, ImportName>,
|
pub imported_functions: Map<ImportedFuncIndex, ImportName>,
|
||||||
pub imported_memories: Map<ImportedMemoryIndex, (ImportName, Memory)>,
|
pub imported_memories: Map<ImportedMemoryIndex, (ImportName, Memory)>,
|
||||||
pub imported_tables: Map<ImportedTableIndex, (ImportName, Table)>,
|
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 exports: HashMap<String, ExportIndex>,
|
||||||
|
|
||||||
pub data_initializers: Vec<DataInitializer>,
|
pub data_initializers: Vec<DataInitializer>,
|
||||||
pub table_initializers: Vec<TableInitializer>,
|
pub elem_initializers: Vec<TableInitializer>,
|
||||||
|
|
||||||
pub start_func: Option<FuncIndex>,
|
pub start_func: Option<FuncIndex>,
|
||||||
|
|
||||||
pub func_assoc: Map<FuncIndex, SigIndex>,
|
pub func_assoc: Map<FuncIndex, SigIndex>,
|
||||||
@ -82,10 +83,8 @@ pub enum ExportIndex {
|
|||||||
pub struct DataInitializer {
|
pub struct DataInitializer {
|
||||||
/// The index of the memory to initialize.
|
/// The index of the memory to initialize.
|
||||||
pub memory_index: MemoryIndex,
|
pub memory_index: MemoryIndex,
|
||||||
/// Optionally a globalvalue base to initialize at.
|
/// Either a constant offset or a `get_global`
|
||||||
pub base: Option<GlobalIndex>,
|
pub base: Initializer,
|
||||||
/// A constant offset to initialize at.
|
|
||||||
pub offset: usize,
|
|
||||||
/// The initialization data.
|
/// The initialization data.
|
||||||
pub data: Vec<u8>,
|
pub data: Vec<u8>,
|
||||||
}
|
}
|
||||||
|
@ -4,7 +4,7 @@ use std::{
|
|||||||
marker::PhantomData,
|
marker::PhantomData,
|
||||||
mem,
|
mem,
|
||||||
ops::{Deref, DerefMut},
|
ops::{Deref, DerefMut},
|
||||||
slice,
|
slice, vec,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Dense item map
|
/// Dense item map
|
||||||
@ -45,6 +45,10 @@ where
|
|||||||
K::new(len)
|
K::new(len)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn next_index(&self) -> K {
|
||||||
|
K::new(self.len())
|
||||||
|
}
|
||||||
|
|
||||||
pub fn reserve_exact(&mut self, size: usize) {
|
pub fn reserve_exact(&mut self, size: usize) {
|
||||||
self.elems.reserve_exact(size);
|
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>
|
impl<'a, K, V> IntoIterator for &'a Map<K, V>
|
||||||
where
|
where
|
||||||
K: TypedIndex,
|
K: TypedIndex,
|
||||||
|
@ -7,6 +7,8 @@ pub use self::map::{Iter, IterMut, Map};
|
|||||||
pub use self::slice::SliceMap;
|
pub use self::slice::SliceMap;
|
||||||
|
|
||||||
pub trait TypedIndex {
|
pub trait TypedIndex {
|
||||||
|
#[doc(hidden)]
|
||||||
fn new(index: usize) -> Self;
|
fn new(index: usize) -> Self;
|
||||||
|
#[doc(hidden)]
|
||||||
fn index(&self) -> usize;
|
fn index(&self) -> usize;
|
||||||
}
|
}
|
||||||
|
@ -101,23 +101,11 @@ pub struct GlobalDesc {
|
|||||||
pub ty: Type,
|
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.
|
/// A wasm global.
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct Global {
|
pub struct Global {
|
||||||
pub desc: GlobalDesc,
|
pub desc: GlobalDesc,
|
||||||
pub init: Value,
|
pub init: Initializer,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A wasm memory.
|
/// A wasm memory.
|
||||||
@ -174,10 +162,12 @@ macro_rules! define_map_index {
|
|||||||
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
|
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
|
||||||
pub struct $ty (u32);
|
pub struct $ty (u32);
|
||||||
impl TypedIndex for $ty {
|
impl TypedIndex for $ty {
|
||||||
|
#[doc(hidden)]
|
||||||
fn new(index: usize) -> Self {
|
fn new(index: usize) -> Self {
|
||||||
$ty (index as _)
|
$ty (index as _)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[doc(hidden)]
|
||||||
fn index(&self) -> usize {
|
fn index(&self) -> usize {
|
||||||
self.0 as usize
|
self.0 as usize
|
||||||
}
|
}
|
||||||
@ -247,10 +237,12 @@ define_local_or_import![
|
|||||||
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
|
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
|
||||||
pub struct SigIndex(u32);
|
pub struct SigIndex(u32);
|
||||||
impl TypedIndex for SigIndex {
|
impl TypedIndex for SigIndex {
|
||||||
|
#[doc(hidden)]
|
||||||
fn new(index: usize) -> Self {
|
fn new(index: usize) -> Self {
|
||||||
SigIndex(index as _)
|
SigIndex(index as _)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[doc(hidden)]
|
||||||
fn index(&self) -> usize {
|
fn index(&self) -> usize {
|
||||||
self.0 as usize
|
self.0 as usize
|
||||||
}
|
}
|
||||||
@ -263,3 +255,22 @@ where
|
|||||||
Local(T::Local),
|
Local(T::Local),
|
||||||
Import(T::Import),
|
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 {
|
pub fn offset_current_elements() -> u8 {
|
||||||
1 * (mem::size_of::<usize>() as u8)
|
1 * (mem::size_of::<usize>() as u8)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn size() -> u8 {
|
||||||
|
mem::size_of::<Self>() as u8
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
@ -146,6 +150,10 @@ impl ImportedTable {
|
|||||||
pub fn offset_vmctx() -> u8 {
|
pub fn offset_vmctx() -> u8 {
|
||||||
1 * (mem::size_of::<usize>() as 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.
|
/// Definition of a memory used by the VM.
|
||||||
@ -166,6 +174,10 @@ impl LocalMemory {
|
|||||||
pub fn offset_size() -> u8 {
|
pub fn offset_size() -> u8 {
|
||||||
1 * (mem::size_of::<usize>() as u8)
|
1 * (mem::size_of::<usize>() as u8)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn size() -> u8 {
|
||||||
|
mem::size_of::<Self>() as u8
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
@ -184,6 +196,10 @@ impl ImportedMemory {
|
|||||||
pub fn offset_vmctx() -> u8 {
|
pub fn offset_vmctx() -> u8 {
|
||||||
1 * (mem::size_of::<usize>() as 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.
|
/// Definition of a global used by the VM.
|
||||||
@ -257,6 +273,10 @@ impl Anyfunc {
|
|||||||
pub fn offset_sig_id() -> u8 {
|
pub fn offset_sig_id() -> u8 {
|
||||||
2 * (mem::size_of::<usize>() as u8)
|
2 * (mem::size_of::<usize>() as u8)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn size() -> u8 {
|
||||||
|
mem::size_of::<Self>() as u8
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
Reference in New Issue
Block a user