diff --git a/lib/runtime/src/compilation.rs b/lib/runtime/src/compilation.rs index f0e0c19a59..6fd4a578d9 100644 --- a/lib/runtime/src/compilation.rs +++ b/lib/runtime/src/compilation.rs @@ -6,7 +6,7 @@ use module::Module; /// An Instance of a WebAssemby module. #[derive(Debug)] pub struct Compilation<'module> { - /// The module this `Instance` is instantiated from. + /// The module this `Compilation` is compiled from. pub module: &'module Module, /// Compiled machine code for the function bodies. diff --git a/lib/runtime/src/environ.rs b/lib/runtime/src/environ.rs new file mode 100644 index 0000000000..9c928be41c --- /dev/null +++ b/lib/runtime/src/environ.rs @@ -0,0 +1,460 @@ +use cranelift_codegen::cursor::FuncCursor; +use cranelift_codegen::ir; +use cranelift_codegen::ir::immediates::Offset32; +use cranelift_codegen::ir::types::*; +use cranelift_codegen::ir::{ + AbiParam, ArgumentExtension, ArgumentLoc, ArgumentPurpose, ExtFuncData, ExternalName, FuncRef, + Function, InstBuilder, Signature, +}; +use cranelift_codegen::isa; +use cranelift_codegen::settings; +use cranelift_wasm; +use cranelift_wasm::{ + FunctionIndex, Global, GlobalIndex, GlobalVariable, Memory, MemoryIndex, SignatureIndex, Table, + TableIndex, WasmResult, +}; +use module; +use module::Module; +use target_lexicon::Triple; +use ModuleTranslation; + +/// Compute a `ir::ExternalName` for a given wasm function index. +pub fn get_func_name(func_index: FunctionIndex) -> ir::ExternalName { + debug_assert!(func_index as u32 as FunctionIndex == func_index); + ir::ExternalName::user(0, func_index as u32) +} + +/// A data initializer for linear memory. +pub struct DataInitializer<'data> { + /// The index of the memory to initialize. + pub memory_index: MemoryIndex, + /// Optionally a globalvar base to initialize at. + pub base: Option, + /// A constant offset to initialize at. + pub offset: usize, + /// The initialization data. + pub data: &'data [u8], +} + +/// References to the input wasm data buffer to be decoded and processed later. +/// separately from the main module translation. +pub struct LazyContents<'data> { + /// References to the function bodies. + pub function_body_inputs: Vec<&'data [u8]>, + + /// References to the data initializers. + pub data_initializers: Vec>, +} + +impl<'data> LazyContents<'data> { + fn new() -> Self { + Self { + function_body_inputs: Vec::new(), + data_initializers: Vec::new(), + } + } +} + +/// Object containing the standalone runtime information. To be passed after creation as argument +/// to `cranelift_wasm::translatemodule`. +pub struct ModuleEnvironment<'data, 'module> { + /// Compilation setting flags. + pub isa: &'module isa::TargetIsa, + + /// Module information. + pub module: &'module mut Module, + + /// References to information to be decoded later. + pub lazy: LazyContents<'data>, +} + +impl<'data, 'module> ModuleEnvironment<'data, 'module> { + /// Allocates the runtime data structures with the given isa. + pub fn new(isa: &'module isa::TargetIsa, module: &'module mut Module) -> Self { + Self { + isa, + module, + lazy: LazyContents::new(), + } + } + + fn func_env(&self) -> FuncEnvironment { + FuncEnvironment::new(self.isa, &self.module) + } + + fn pointer_type(&self) -> ir::Type { + use cranelift_wasm::FuncEnvironment; + self.func_env().pointer_type() + } + + /// Declare that translation of the module is complete. This consumes the + /// `ModuleEnvironment` with its mutable reference to the `Module` and + /// produces a `ModuleTranslation` with an immutable reference to the + /// `Module`. + pub fn finish_translation(self) -> ModuleTranslation<'data, 'module> { + ModuleTranslation { + isa: self.isa, + module: self.module, + lazy: self.lazy, + } + } +} + +/// The FuncEnvironment implementation for use by the `ModuleEnvironment`. +pub struct FuncEnvironment<'module_environment> { + /// Compilation setting flags. + isa: &'module_environment isa::TargetIsa, + + /// The module-level environment which this function-level environment belongs to. + pub module: &'module_environment Module, + + /// The Cranelift global holding the base address of the memories vector. + pub memories_base: Option, + + /// The Cranelift global holding the base address of the globals vector. + pub globals_base: Option, + + /// The external function declaration for implementing wasm's `current_memory`. + pub current_memory_extfunc: Option, + + /// The external function declaration for implementing wasm's `grow_memory`. + pub grow_memory_extfunc: Option, +} + +impl<'module_environment> FuncEnvironment<'module_environment> { + pub fn new( + isa: &'module_environment isa::TargetIsa, + module: &'module_environment Module, + ) -> Self { + Self { + isa, + module, + memories_base: None, + globals_base: None, + current_memory_extfunc: None, + grow_memory_extfunc: None, + } + } + + /// Transform the call argument list in preparation for making a call. + fn get_real_call_args(func: &Function, call_args: &[ir::Value]) -> Vec { + let mut real_call_args = Vec::with_capacity(call_args.len() + 1); + real_call_args.extend_from_slice(call_args); + real_call_args.push(func.special_param(ArgumentPurpose::VMContext).unwrap()); + real_call_args + } + + fn ptr_size(&self) -> usize { + usize::from(self.isa.pointer_bytes()) + } +} + +/// This trait is useful for +/// `cranelift_wasm::translatemodule` because it +/// tells how to translate runtime-dependent wasm instructions. These functions should not be +/// called by the user. +impl<'data, 'module> cranelift_wasm::ModuleEnvironment<'data> + for ModuleEnvironment<'data, 'module> +{ + fn get_func_name(&self, func_index: FunctionIndex) -> ir::ExternalName { + get_func_name(func_index) + } + + fn flags(&self) -> &settings::Flags { + self.isa.flags() + } + + fn declare_signature(&mut self, sig: &ir::Signature) { + let mut sig = sig.clone(); + sig.params.push(AbiParam { + value_type: self.pointer_type(), + purpose: ArgumentPurpose::VMContext, + extension: ArgumentExtension::None, + location: ArgumentLoc::Unassigned, + }); + // TODO: Deduplicate signatures. + self.module.signatures.push(sig); + } + + fn get_signature(&self, sig_index: SignatureIndex) -> &ir::Signature { + &self.module.signatures[sig_index] + } + + fn declare_func_import(&mut self, sig_index: SignatureIndex, module: &str, field: &str) { + debug_assert_eq!( + self.module.functions.len(), + self.module.imported_funcs.len(), + "Imported functions must be declared first" + ); + self.module.functions.push(sig_index); + + self.module + .imported_funcs + .push((String::from(module), String::from(field))); + } + + fn get_num_func_imports(&self) -> usize { + self.module.imported_funcs.len() + } + + fn declare_func_type(&mut self, sig_index: SignatureIndex) { + self.module.functions.push(sig_index); + } + + fn get_func_type(&self, func_index: FunctionIndex) -> SignatureIndex { + self.module.functions[func_index] + } + + fn declare_global(&mut self, global: Global) { + self.module.globals.push(global); + } + + fn get_global(&self, global_index: GlobalIndex) -> &cranelift_wasm::Global { + &self.module.globals[global_index] + } + + fn declare_table(&mut self, table: Table) { + self.module.tables.push(table); + } + + fn declare_table_elements( + &mut self, + table_index: TableIndex, + base: Option, + offset: usize, + elements: Vec, + ) { + debug_assert!(base.is_none(), "global-value offsets not supported yet"); + self.module.table_elements.push(module::TableElements { + table_index, + base, + offset, + elements, + }); + } + + fn declare_memory(&mut self, memory: Memory) { + self.module.memories.push(memory); + } + + fn declare_data_initialization( + &mut self, + memory_index: MemoryIndex, + base: Option, + offset: usize, + data: &'data [u8], + ) { + debug_assert!(base.is_none(), "global-value offsets not supported yet"); + self.lazy.data_initializers.push(DataInitializer { + memory_index, + base, + offset, + data, + }); + } + + fn declare_func_export(&mut self, func_index: FunctionIndex, name: &str) { + self.module + .exports + .insert(String::from(name), module::Export::Function(func_index)); + } + + fn declare_table_export(&mut self, table_index: TableIndex, name: &str) { + self.module + .exports + .insert(String::from(name), module::Export::Table(table_index)); + } + + fn declare_memory_export(&mut self, memory_index: MemoryIndex, name: &str) { + self.module + .exports + .insert(String::from(name), module::Export::Memory(memory_index)); + } + + fn declare_global_export(&mut self, global_index: GlobalIndex, name: &str) { + self.module + .exports + .insert(String::from(name), module::Export::Global(global_index)); + } + + fn declare_start_func(&mut self, func_index: FunctionIndex) { + debug_assert!(self.module.start_func.is_none()); + self.module.start_func = Some(func_index); + } + + fn define_function_body(&mut self, body_bytes: &'data [u8]) -> WasmResult<()> { + self.lazy.function_body_inputs.push(body_bytes); + Ok(()) + } +} + +impl<'module_environment> cranelift_wasm::FuncEnvironment for FuncEnvironment<'module_environment> { + fn flags(&self) -> &settings::Flags { + &self.isa.flags() + } + + fn triple(&self) -> &Triple { + self.isa.triple() + } + + fn make_global(&mut self, func: &mut ir::Function, index: GlobalIndex) -> GlobalVariable { + let ptr_size = self.ptr_size(); + let globals_base = self.globals_base.unwrap_or_else(|| { + let new_base = func.create_global_value(ir::GlobalValueData::VMContext { + offset: Offset32::new(0), + }); + self.globals_base = Some(new_base); + new_base + }); + let offset = index as usize * ptr_size; + let offset32 = offset as i32; + debug_assert_eq!(offset32 as usize, offset); + let gv = func.create_global_value(ir::GlobalValueData::Deref { + base: globals_base, + offset: Offset32::new(offset32), + }); + GlobalVariable::Memory { + gv, + ty: self.module.globals[index].ty, + } + } + + fn make_heap(&mut self, func: &mut ir::Function, index: MemoryIndex) -> ir::Heap { + let ptr_size = self.ptr_size(); + let memories_base = self.memories_base.unwrap_or_else(|| { + let new_base = func.create_global_value(ir::GlobalValueData::VMContext { + offset: Offset32::new(ptr_size as i32), + }); + self.globals_base = Some(new_base); + new_base + }); + let offset = index as usize * ptr_size; + let offset32 = offset as i32; + debug_assert_eq!(offset32 as usize, offset); + let heap_base_addr = func.create_global_value(ir::GlobalValueData::Deref { + base: memories_base, + offset: Offset32::new(offset32), + }); + let heap_base = func.create_global_value(ir::GlobalValueData::Deref { + base: heap_base_addr, + offset: Offset32::new(0), + }); + func.create_heap(ir::HeapData { + base: heap_base, + min_size: 0.into(), + guard_size: 0x8000_0000.into(), + style: ir::HeapStyle::Static { + bound: 0x1_0000_0000.into(), + }, + }) + } + + fn make_table(&mut self, _func: &mut ir::Function, _index: TableIndex) -> ir::Table { + unimplemented!("make_table"); + } + + fn make_indirect_sig(&mut self, func: &mut ir::Function, index: SignatureIndex) -> ir::SigRef { + func.import_signature(self.module.signatures[index].clone()) + } + + fn make_direct_func(&mut self, func: &mut ir::Function, index: FunctionIndex) -> ir::FuncRef { + let sigidx = self.module.functions[index]; + let signature = func.import_signature(self.module.signatures[sigidx].clone()); + let name = get_func_name(index); + // We currently allocate all code segments independently, so nothing + // is colocated. + let colocated = false; + func.import_function(ir::ExtFuncData { + name, + signature, + colocated, + }) + } + + fn translate_call_indirect( + &mut self, + mut pos: FuncCursor, + table_index: TableIndex, + _table: ir::Table, + _sig_index: SignatureIndex, + sig_ref: ir::SigRef, + callee: ir::Value, + call_args: &[ir::Value], + ) -> WasmResult { + // TODO: Cranelift's call_indirect doesn't implement bounds checking + // or signature checking, so we need to implement it ourselves. + debug_assert_eq!(table_index, 0, "non-default tables not supported yet"); + let real_call_args = FuncEnvironment::get_real_call_args(pos.func, call_args); + Ok(pos.ins().call_indirect(sig_ref, callee, &real_call_args)) + } + + fn translate_call( + &mut self, + mut pos: FuncCursor, + _callee_index: FunctionIndex, + callee: ir::FuncRef, + call_args: &[ir::Value], + ) -> WasmResult { + let real_call_args = FuncEnvironment::get_real_call_args(pos.func, call_args); + Ok(pos.ins().call(callee, &real_call_args)) + } + + fn translate_memory_grow( + &mut self, + mut pos: FuncCursor, + index: MemoryIndex, + _heap: ir::Heap, + val: ir::Value, + ) -> WasmResult { + debug_assert_eq!(index, 0, "non-default memories not supported yet"); + let grow_mem_func = self.grow_memory_extfunc.unwrap_or_else(|| { + let sig_ref = pos.func.import_signature(Signature { + call_conv: self.isa.flags().call_conv(), + argument_bytes: None, + params: vec![AbiParam::new(I32)], + returns: vec![AbiParam::new(I32)], + }); + // We currently allocate all code segments independently, so nothing + // is colocated. + let colocated = false; + // FIXME: Use a real ExternalName system. + pos.func.import_function(ExtFuncData { + name: ExternalName::testcase("grow_memory"), + signature: sig_ref, + colocated, + }) + }); + self.grow_memory_extfunc = Some(grow_mem_func); + let call_inst = pos.ins().call(grow_mem_func, &[val]); + Ok(*pos.func.dfg.inst_results(call_inst).first().unwrap()) + } + + fn translate_memory_size( + &mut self, + mut pos: FuncCursor, + index: MemoryIndex, + _heap: ir::Heap, + ) -> WasmResult { + debug_assert_eq!(index, 0, "non-default memories not supported yet"); + let cur_mem_func = self.current_memory_extfunc.unwrap_or_else(|| { + let sig_ref = pos.func.import_signature(Signature { + call_conv: self.isa.flags().call_conv(), + argument_bytes: None, + params: Vec::new(), + returns: vec![AbiParam::new(I32)], + }); + // We currently allocate all code segments independently, so nothing + // is colocated. + let colocated = false; + // FIXME: Use a real ExternalName system. + pos.func.import_function(ExtFuncData { + name: ExternalName::testcase("current_memory"), + signature: sig_ref, + colocated, + }) + }); + self.current_memory_extfunc = Some(cur_mem_func); + let call_inst = pos.ins().call(cur_mem_func, &[]); + Ok(*pos.func.dfg.inst_results(call_inst).first().unwrap()) + } +} diff --git a/lib/runtime/src/instance.rs b/lib/runtime/src/instance.rs index e4818803d5..5b9b72d4d9 100644 --- a/lib/runtime/src/instance.rs +++ b/lib/runtime/src/instance.rs @@ -3,8 +3,8 @@ use cranelift_codegen::ir; use cranelift_wasm::GlobalIndex; +use environ::DataInitializer; use module::{Module, TableElements}; -use DataInitializer; const PAGE_SIZE: usize = 65536; @@ -83,7 +83,8 @@ impl Instance { /// Returns a slice of the contents of allocated linear memory. pub fn inspect_memory(&self, memory_index: usize, address: usize, len: usize) -> &[u8] { - &self.memories + &self + .memories .get(memory_index) .unwrap_or_else(|| panic!("no memory for index {}", memory_index)) [address..address + len] diff --git a/lib/runtime/src/lib.rs b/lib/runtime/src/lib.rs index 2934b28286..e0abe18432 100644 --- a/lib/runtime/src/lib.rs +++ b/lib/runtime/src/lib.rs @@ -9,30 +9,22 @@ extern crate cranelift_codegen; extern crate cranelift_wasm; extern crate target_lexicon; -pub mod compilation; -pub mod instance; -pub mod module; +mod compilation; +mod environ; +mod instance; +mod module; pub use compilation::Compilation; +pub use environ::ModuleEnvironment; pub use instance::Instance; pub use module::Module; use cranelift_codegen::binemit; -use cranelift_codegen::cursor::FuncCursor; use cranelift_codegen::ir; -use cranelift_codegen::ir::immediates::Offset32; -use cranelift_codegen::ir::types::*; -use cranelift_codegen::ir::{ - AbiParam, ArgumentExtension, ArgumentLoc, ArgumentPurpose, ExtFuncData, ExternalName, FuncRef, - Function, InstBuilder, Signature, -}; +use cranelift_codegen::ir::ExternalName; use cranelift_codegen::isa; -use cranelift_codegen::settings; -use cranelift_wasm::{ - FuncTranslator, FunctionIndex, Global, GlobalIndex, GlobalVariable, Memory, MemoryIndex, - SignatureIndex, Table, TableIndex, WasmResult, -}; -use target_lexicon::Triple; +use cranelift_wasm::{FuncTranslator, FunctionIndex, GlobalIndex, MemoryIndex, TableIndex}; +use environ::{FuncEnvironment, LazyContents}; /// Compute a `ir::ExternalName` for a given wasm function index. pub fn get_func_name(func_index: FunctionIndex) -> cranelift_codegen::ir::ExternalName { @@ -107,438 +99,6 @@ impl RelocSink { } } -/// A data initializer for linear memory. -pub struct DataInitializer<'data> { - /// The index of the memory to initialize. - pub memory_index: MemoryIndex, - /// Optionally a globalvar base to initialize at. - pub base: Option, - /// A constant offset to initialize at. - pub offset: usize, - /// The initialization data. - pub data: &'data [u8], -} - -/// References to the input wasm data buffer to be decoded and processed later. -/// separately from the main module translation. -pub struct LazyContents<'data> { - /// References to the function bodies. - pub function_body_inputs: Vec<&'data [u8]>, - - /// References to the data initializers. - pub data_initializers: Vec>, -} - -impl<'data> LazyContents<'data> { - fn new() -> Self { - Self { - function_body_inputs: Vec::new(), - data_initializers: Vec::new(), - } - } -} - -/// Object containing the standalone runtime information. To be passed after creation as argument -/// to `cranelift_wasm::translatemodule`. -pub struct ModuleEnvironment<'data, 'module> { - /// Compilation setting flags. - pub isa: &'module isa::TargetIsa, - - /// Module information. - pub module: &'module mut Module, - - /// References to information to be decoded later. - pub lazy: LazyContents<'data>, -} - -impl<'data, 'module> ModuleEnvironment<'data, 'module> { - /// Allocates the runtime data structures with the given isa. - pub fn new(isa: &'module isa::TargetIsa, module: &'module mut Module) -> Self { - Self { - isa, - module, - lazy: LazyContents::new(), - } - } - - fn func_env(&self) -> FuncEnvironment { - FuncEnvironment::new(self.isa, &self.module) - } - - fn pointer_type(&self) -> ir::Type { - use cranelift_wasm::FuncEnvironment; - self.func_env().pointer_type() - } - - /// Declare that translation of the module is complete. This consumes the - /// `ModuleEnvironment` with its mutable reference to the `Module` and - /// produces a `ModuleTranslation` with an immutable reference to the - /// `Module`. - pub fn finish_translation(self) -> ModuleTranslation<'data, 'module> { - ModuleTranslation { - isa: self.isa, - module: self.module, - lazy: self.lazy, - } - } -} - -/// The FuncEnvironment implementation for use by the `ModuleEnvironment`. -pub struct FuncEnvironment<'module_environment> { - /// Compilation setting flags. - isa: &'module_environment isa::TargetIsa, - - /// The module-level environment which this function-level environment belongs to. - pub module: &'module_environment Module, - - /// The Cranelift global holding the base address of the memories vector. - pub memories_base: Option, - - /// The Cranelift global holding the base address of the globals vector. - pub globals_base: Option, - - /// The external function declaration for implementing wasm's `current_memory`. - pub current_memory_extfunc: Option, - - /// The external function declaration for implementing wasm's `grow_memory`. - pub grow_memory_extfunc: Option, -} - -impl<'module_environment> FuncEnvironment<'module_environment> { - fn new(isa: &'module_environment isa::TargetIsa, module: &'module_environment Module) -> Self { - Self { - isa, - module, - memories_base: None, - globals_base: None, - current_memory_extfunc: None, - grow_memory_extfunc: None, - } - } - - /// Transform the call argument list in preparation for making a call. - fn get_real_call_args(func: &Function, call_args: &[ir::Value]) -> Vec { - let mut real_call_args = Vec::with_capacity(call_args.len() + 1); - real_call_args.extend_from_slice(call_args); - real_call_args.push(func.special_param(ArgumentPurpose::VMContext).unwrap()); - real_call_args - } - - fn ptr_size(&self) -> usize { - usize::from(self.isa.pointer_bytes()) - } -} - -impl<'module_environment> cranelift_wasm::FuncEnvironment for FuncEnvironment<'module_environment> { - fn flags(&self) -> &settings::Flags { - &self.isa.flags() - } - - fn triple(&self) -> &Triple { - self.isa.triple() - } - - fn make_global(&mut self, func: &mut ir::Function, index: GlobalIndex) -> GlobalVariable { - let ptr_size = self.ptr_size(); - let globals_base = self.globals_base.unwrap_or_else(|| { - let new_base = func.create_global_value(ir::GlobalValueData::VMContext { - offset: Offset32::new(0), - }); - self.globals_base = Some(new_base); - new_base - }); - let offset = index as usize * ptr_size; - let offset32 = offset as i32; - debug_assert_eq!(offset32 as usize, offset); - let gv = func.create_global_value(ir::GlobalValueData::Deref { - base: globals_base, - offset: Offset32::new(offset32), - }); - GlobalVariable::Memory { - gv, - ty: self.module.globals[index].ty, - } - } - - fn make_heap(&mut self, func: &mut ir::Function, index: MemoryIndex) -> ir::Heap { - let ptr_size = self.ptr_size(); - let memories_base = self.memories_base.unwrap_or_else(|| { - let new_base = func.create_global_value(ir::GlobalValueData::VMContext { - offset: Offset32::new(ptr_size as i32), - }); - self.globals_base = Some(new_base); - new_base - }); - let offset = index as usize * ptr_size; - let offset32 = offset as i32; - debug_assert_eq!(offset32 as usize, offset); - let heap_base_addr = func.create_global_value(ir::GlobalValueData::Deref { - base: memories_base, - offset: Offset32::new(offset32), - }); - let heap_base = func.create_global_value(ir::GlobalValueData::Deref { - base: heap_base_addr, - offset: Offset32::new(0), - }); - func.create_heap(ir::HeapData { - base: heap_base, - min_size: 0.into(), - guard_size: 0x8000_0000.into(), - style: ir::HeapStyle::Static { - bound: 0x1_0000_0000.into(), - }, - }) - } - - fn make_table(&mut self, _func: &mut ir::Function, _index: TableIndex) -> ir::Table { - unimplemented!("make_table"); - } - - fn make_indirect_sig(&mut self, func: &mut ir::Function, index: SignatureIndex) -> ir::SigRef { - func.import_signature(self.module.signatures[index].clone()) - } - - fn make_direct_func(&mut self, func: &mut ir::Function, index: FunctionIndex) -> ir::FuncRef { - let sigidx = self.module.functions[index]; - let signature = func.import_signature(self.module.signatures[sigidx].clone()); - let name = get_func_name(index); - // We currently allocate all code segments independently, so nothing - // is colocated. - let colocated = false; - func.import_function(ir::ExtFuncData { - name, - signature, - colocated, - }) - } - - fn translate_call_indirect( - &mut self, - mut pos: FuncCursor, - table_index: TableIndex, - _table: ir::Table, - _sig_index: SignatureIndex, - sig_ref: ir::SigRef, - callee: ir::Value, - call_args: &[ir::Value], - ) -> WasmResult { - // TODO: Cranelift's call_indirect doesn't implement bounds checking - // or signature checking, so we need to implement it ourselves. - debug_assert_eq!(table_index, 0, "non-default tables not supported yet"); - let real_call_args = FuncEnvironment::get_real_call_args(pos.func, call_args); - Ok(pos.ins().call_indirect(sig_ref, callee, &real_call_args)) - } - - fn translate_call( - &mut self, - mut pos: FuncCursor, - _callee_index: FunctionIndex, - callee: ir::FuncRef, - call_args: &[ir::Value], - ) -> WasmResult { - let real_call_args = FuncEnvironment::get_real_call_args(pos.func, call_args); - Ok(pos.ins().call(callee, &real_call_args)) - } - - fn translate_memory_grow( - &mut self, - mut pos: FuncCursor, - index: MemoryIndex, - _heap: ir::Heap, - val: ir::Value, - ) -> WasmResult { - debug_assert_eq!(index, 0, "non-default memories not supported yet"); - let grow_mem_func = self.grow_memory_extfunc.unwrap_or_else(|| { - let sig_ref = pos.func.import_signature(Signature { - call_conv: self.isa.flags().call_conv(), - argument_bytes: None, - params: vec![AbiParam::new(I32)], - returns: vec![AbiParam::new(I32)], - }); - // We currently allocate all code segments independently, so nothing - // is colocated. - let colocated = false; - // FIXME: Use a real ExternalName system. - pos.func.import_function(ExtFuncData { - name: ExternalName::testcase("grow_memory"), - signature: sig_ref, - colocated, - }) - }); - self.grow_memory_extfunc = Some(grow_mem_func); - let call_inst = pos.ins().call(grow_mem_func, &[val]); - Ok(*pos.func.dfg.inst_results(call_inst).first().unwrap()) - } - - fn translate_memory_size( - &mut self, - mut pos: FuncCursor, - index: MemoryIndex, - _heap: ir::Heap, - ) -> WasmResult { - debug_assert_eq!(index, 0, "non-default memories not supported yet"); - let cur_mem_func = self.current_memory_extfunc.unwrap_or_else(|| { - let sig_ref = pos.func.import_signature(Signature { - call_conv: self.isa.flags().call_conv(), - argument_bytes: None, - params: Vec::new(), - returns: vec![AbiParam::new(I32)], - }); - // We currently allocate all code segments independently, so nothing - // is colocated. - let colocated = false; - // FIXME: Use a real ExternalName system. - pos.func.import_function(ExtFuncData { - name: ExternalName::testcase("current_memory"), - signature: sig_ref, - colocated, - }) - }); - self.current_memory_extfunc = Some(cur_mem_func); - let call_inst = pos.ins().call(cur_mem_func, &[]); - Ok(*pos.func.dfg.inst_results(call_inst).first().unwrap()) - } -} - -/// This trait is useful for -/// `cranelift_wasm::translatemodule` because it -/// tells how to translate runtime-dependent wasm instructions. These functions should not be -/// called by the user. -impl<'data, 'module> cranelift_wasm::ModuleEnvironment<'data> - for ModuleEnvironment<'data, 'module> -{ - fn get_func_name(&self, func_index: FunctionIndex) -> cranelift_codegen::ir::ExternalName { - get_func_name(func_index) - } - - fn flags(&self) -> &settings::Flags { - self.isa.flags() - } - - fn declare_signature(&mut self, sig: &ir::Signature) { - let mut sig = sig.clone(); - sig.params.push(AbiParam { - value_type: self.pointer_type(), - purpose: ArgumentPurpose::VMContext, - extension: ArgumentExtension::None, - location: ArgumentLoc::Unassigned, - }); - // TODO: Deduplicate signatures. - self.module.signatures.push(sig); - } - - fn get_signature(&self, sig_index: SignatureIndex) -> &ir::Signature { - &self.module.signatures[sig_index] - } - - fn declare_func_import(&mut self, sig_index: SignatureIndex, module: &str, field: &str) { - debug_assert_eq!( - self.module.functions.len(), - self.module.imported_funcs.len(), - "Imported functions must be declared first" - ); - self.module.functions.push(sig_index); - - self.module - .imported_funcs - .push((String::from(module), String::from(field))); - } - - fn get_num_func_imports(&self) -> usize { - self.module.imported_funcs.len() - } - - fn declare_func_type(&mut self, sig_index: SignatureIndex) { - self.module.functions.push(sig_index); - } - - fn get_func_type(&self, func_index: FunctionIndex) -> SignatureIndex { - self.module.functions[func_index] - } - - fn declare_global(&mut self, global: Global) { - self.module.globals.push(global); - } - - fn get_global(&self, global_index: GlobalIndex) -> &cranelift_wasm::Global { - &self.module.globals[global_index] - } - - fn declare_table(&mut self, table: Table) { - self.module.tables.push(table); - } - - fn declare_table_elements( - &mut self, - table_index: TableIndex, - base: Option, - offset: usize, - elements: Vec, - ) { - debug_assert!(base.is_none(), "global-value offsets not supported yet"); - self.module.table_elements.push(module::TableElements { - table_index, - base, - offset, - elements, - }); - } - - fn declare_memory(&mut self, memory: Memory) { - self.module.memories.push(memory); - } - - fn declare_data_initialization( - &mut self, - memory_index: MemoryIndex, - base: Option, - offset: usize, - data: &'data [u8], - ) { - debug_assert!(base.is_none(), "global-value offsets not supported yet"); - self.lazy.data_initializers.push(DataInitializer { - memory_index, - base, - offset, - data, - }); - } - - fn declare_func_export(&mut self, func_index: FunctionIndex, name: &str) { - self.module - .exports - .insert(String::from(name), module::Export::Function(func_index)); - } - - fn declare_table_export(&mut self, table_index: TableIndex, name: &str) { - self.module - .exports - .insert(String::from(name), module::Export::Table(table_index)); - } - - fn declare_memory_export(&mut self, memory_index: MemoryIndex, name: &str) { - self.module - .exports - .insert(String::from(name), module::Export::Memory(memory_index)); - } - - fn declare_global_export(&mut self, global_index: GlobalIndex, name: &str) { - self.module - .exports - .insert(String::from(name), module::Export::Global(global_index)); - } - - fn declare_start_func(&mut self, func_index: FunctionIndex) { - debug_assert!(self.module.start_func.is_none()); - self.module.start_func = Some(func_index); - } - - fn define_function_body(&mut self, body_bytes: &'data [u8]) -> WasmResult<()> { - self.lazy.function_body_inputs.push(body_bytes); - Ok(()) - } -} - /// A record of a relocation to perform. #[derive(Debug)] pub struct Relocation {