diff --git a/lib/runtime-core/src/vm.rs b/lib/runtime-core/src/vm.rs index 2ef51c869..965e5ef1d 100644 --- a/lib/runtime-core/src/vm.rs +++ b/lib/runtime-core/src/vm.rs @@ -1,9 +1,11 @@ pub use crate::backing::{ImportBacking, LocalBacking}; use crate::{ - memory::Memory, - module::ModuleInner, + memory::{Memory, MemoryType}, + module::{ModuleInfo, ModuleInner}, structures::TypedIndex, - types::{LocalOrImport, MemoryIndex}, + types::{LocalOrImport, MemoryIndex, LocalMemoryIndex}, + units::{Pages}, + vmcalls, }; use std::{ffi::c_void, mem, ptr}; @@ -61,6 +63,77 @@ pub struct InternalCtx { /// signature id. This is used to allow call-indirect to other /// modules safely. pub dynamic_sigindices: *const SigId, + + pub intrinsics: *const Intrinsics, +} + +#[repr(C)] +pub struct Intrinsics { + pub memory_grow: *const Func, + pub memory_size: *const Func, + /*pub memory_grow: unsafe extern "C" fn( + ctx: &mut Ctx, + memory_index: usize, + delta: Pages, + ) -> i32, + pub memory_size: unsafe extern "C" fn( + ctx: &Ctx, + memory_index: usize, + ) -> Pages,*/ +} + +unsafe impl Send for Intrinsics {} +unsafe impl Sync for Intrinsics {} + +impl Intrinsics { + pub fn offset_memory_grow() -> u8 { + (0 * ::std::mem::size_of::()) as u8 + } + pub fn offset_memory_size() -> u8 { + (1 * ::std::mem::size_of::()) as u8 + } +} + +pub static INTRINSICS_LOCAL_STATIC_MEMORY: Intrinsics = Intrinsics { + memory_grow: vmcalls::local_static_memory_grow as _, + memory_size: vmcalls::local_static_memory_size as _, +}; +pub static INTRINSICS_LOCAL_DYNAMIC_MEMORY: Intrinsics = Intrinsics { + memory_grow: vmcalls::local_dynamic_memory_grow as _, + memory_size: vmcalls::local_dynamic_memory_size as _, +}; +pub static INTRINSICS_IMPORTED_STATIC_MEMORY: Intrinsics = Intrinsics { + memory_grow: vmcalls::imported_static_memory_grow as _, + memory_size: vmcalls::imported_static_memory_size as _, +}; +pub static INTRINSICS_IMPORTED_DYNAMIC_MEMORY: Intrinsics = Intrinsics { + memory_grow: vmcalls::imported_dynamic_memory_grow as _, + memory_size: vmcalls::imported_dynamic_memory_size as _, +}; + +fn get_intrinsics_for_module(m: &ModuleInfo) -> *const Intrinsics { + if m.memories.len() == 0 && m.imported_memories.len() == 0 { + ::std::ptr::null() + } else { + match MemoryIndex::new(0).local_or_import(m) { + LocalOrImport::Local(local_mem_index) => { + let mem_desc = &m.memories[local_mem_index]; + match mem_desc.memory_type() { + MemoryType::Dynamic => &INTRINSICS_LOCAL_DYNAMIC_MEMORY, + MemoryType::Static => &INTRINSICS_LOCAL_STATIC_MEMORY, + MemoryType::SharedStatic => unimplemented!(), + } + } + LocalOrImport::Import(import_mem_index) => { + let mem_desc = &m.imported_memories[import_mem_index].1; + match mem_desc.memory_type() { + MemoryType::Dynamic => &INTRINSICS_IMPORTED_DYNAMIC_MEMORY, + MemoryType::Static => &INTRINSICS_IMPORTED_STATIC_MEMORY, + MemoryType::SharedStatic => unimplemented!(), + } + } + } + } } impl Ctx { @@ -82,6 +155,8 @@ impl Ctx { imported_funcs: import_backing.vm_functions.as_mut_ptr(), dynamic_sigindices: local_backing.dynamic_sigindices.as_ptr(), + + intrinsics: get_intrinsics_for_module(&module.info), }, local_functions: local_backing.local_functions.as_ptr(), @@ -114,6 +189,8 @@ impl Ctx { imported_funcs: import_backing.vm_functions.as_mut_ptr(), dynamic_sigindices: local_backing.dynamic_sigindices.as_ptr(), + + intrinsics: get_intrinsics_for_module(&module.info), }, local_functions: local_backing.local_functions.as_ptr(), @@ -207,9 +284,13 @@ impl Ctx { 7 * (mem::size_of::() as u8) } - pub fn offset_local_functions() -> u8 { + pub fn offset_intrinsics() -> u8 { 8 * (mem::size_of::() as u8) } + + pub fn offset_local_functions() -> u8 { + 9 * (mem::size_of::() as u8) + } } enum InnerFunc {} @@ -403,6 +484,11 @@ mod vm_offset_tests { offset_of!(InternalCtx => imported_funcs).get_byte_offset(), ); + assert_eq!( + Ctx::offset_intrinsics() as usize, + offset_of!(InternalCtx => intrinsics).get_byte_offset(), + ); + assert_eq!( Ctx::offset_local_functions() as usize, offset_of!(Ctx => local_functions).get_byte_offset(), diff --git a/lib/singlepass-backend/src/codegen_x64.rs b/lib/singlepass-backend/src/codegen_x64.rs index 1dc932a20..0697d70e4 100644 --- a/lib/singlepass-backend/src/codegen_x64.rs +++ b/lib/singlepass-backend/src/codegen_x64.rs @@ -3284,33 +3284,20 @@ impl FunctionCodeGenerator for X64FunctionCode { Operator::Nop => {} Operator::MemorySize { reserved } => { let memory_index = MemoryIndex::new(reserved as usize); - let target: usize = match memory_index.local_or_import(module_info) { - LocalOrImport::Local(local_mem_index) => { - let mem_desc = &module_info.memories[local_mem_index]; - match mem_desc.memory_type() { - MemoryType::Dynamic => vmcalls::local_dynamic_memory_size as usize, - MemoryType::Static => vmcalls::local_static_memory_size as usize, - MemoryType::SharedStatic => unimplemented!(), - } - } - LocalOrImport::Import(import_mem_index) => { - let mem_desc = &module_info.imported_memories[import_mem_index].1; - match mem_desc.memory_type() { - MemoryType::Dynamic => vmcalls::imported_dynamic_memory_size as usize, - MemoryType::Static => vmcalls::imported_static_memory_size as usize, - MemoryType::SharedStatic => unimplemented!(), - } - } - }; + a.emit_mov( + Size::S64, + Location::Memory(Machine::get_vmctx_reg(), vm::Ctx::offset_intrinsics() as i32), + Location::GPR(GPR::RAX) + ); + a.emit_mov( + Size::S64, + Location::Memory(GPR::RAX, vm::Intrinsics::offset_memory_size() as i32), + Location::GPR(GPR::RAX) + ); Self::emit_call_sysv( a, &mut self.machine, |a| { - a.emit_mov( - Size::S64, - Location::Imm64(target as u64), - Location::GPR(GPR::RAX), - ); a.emit_call_location(Location::GPR(GPR::RAX)); }, ::std::iter::once(Location::Imm32(memory_index.index() as u32)), @@ -3321,40 +3308,27 @@ impl FunctionCodeGenerator for X64FunctionCode { } Operator::MemoryGrow { reserved } => { let memory_index = MemoryIndex::new(reserved as usize); - let target: usize = match memory_index.local_or_import(module_info) { - LocalOrImport::Local(local_mem_index) => { - let mem_desc = &module_info.memories[local_mem_index]; - match mem_desc.memory_type() { - MemoryType::Dynamic => vmcalls::local_dynamic_memory_grow as usize, - MemoryType::Static => vmcalls::local_static_memory_grow as usize, - MemoryType::SharedStatic => unimplemented!(), - } - } - LocalOrImport::Import(import_mem_index) => { - let mem_desc = &module_info.imported_memories[import_mem_index].1; - match mem_desc.memory_type() { - MemoryType::Dynamic => vmcalls::imported_dynamic_memory_grow as usize, - MemoryType::Static => vmcalls::imported_static_memory_grow as usize, - MemoryType::SharedStatic => unimplemented!(), - } - } - }; - let (param_pages, param_pages_lot) = self.value_stack.pop().unwrap(); if param_pages_lot == LocalOrTemp::Temp { self.machine.release_locations_only_regs(&[param_pages]); } + a.emit_mov( + Size::S64, + Location::Memory(Machine::get_vmctx_reg(), vm::Ctx::offset_intrinsics() as i32), + Location::GPR(GPR::RAX) + ); + a.emit_mov( + Size::S64, + Location::Memory(GPR::RAX, vm::Intrinsics::offset_memory_grow() as i32), + Location::GPR(GPR::RAX) + ); + Self::emit_call_sysv( a, &mut self.machine, |a| { - a.emit_mov( - Size::S64, - Location::Imm64(target as u64), - Location::GPR(GPR::RAX), - ); a.emit_call_location(Location::GPR(GPR::RAX)); }, ::std::iter::once(Location::Imm32(memory_index.index() as u32))