Implement memory.grow and memory.current (#9)
* Implement. * Clean and doc * Collect base addresses instead of leaking them * Fix code for 1.25. * Simplify $assert * Use AbiParam::special. * Use &mut self in base_addr
This commit is contained in:
committed by
Dan Gohman
parent
5379605737
commit
e7c8d23a42
@@ -1,11 +1,14 @@
|
||||
use cranelift_codegen::binemit::Reloc;
|
||||
use cranelift_codegen::isa::TargetIsa;
|
||||
use instance::Instance;
|
||||
use memory::LinearMemory;
|
||||
use region::protect;
|
||||
use region::Protection;
|
||||
use std::mem::transmute;
|
||||
use std::ptr::write_unaligned;
|
||||
use wasmtime_environ::{compile_module, Compilation, Module, ModuleTranslation, Relocation};
|
||||
use wasmtime_environ::{
|
||||
compile_module, Compilation, Module, ModuleTranslation, Relocation, RelocationTarget,
|
||||
};
|
||||
|
||||
/// Executes a module that has been translated with the `wasmtime-environ` environment
|
||||
/// implementation.
|
||||
@@ -33,7 +36,12 @@ fn relocate(compilation: &mut Compilation, relocations: &[Vec<Relocation>]) {
|
||||
// TODO: Support architectures other than x64, and other reloc kinds.
|
||||
for (i, function_relocs) in relocations.iter().enumerate() {
|
||||
for r in function_relocs {
|
||||
let target_func_address: isize = compilation.functions[r.func_index].as_ptr() as isize;
|
||||
let target_func_address: isize = match r.reloc_target {
|
||||
RelocationTarget::UserFunc(index) => compilation.functions[index].as_ptr() as isize,
|
||||
RelocationTarget::GrowMemory => grow_memory as isize,
|
||||
RelocationTarget::CurrentMemory => current_memory as isize,
|
||||
};
|
||||
|
||||
let body = &mut compilation.functions[i];
|
||||
match r.reloc {
|
||||
Reloc::Abs8 => unsafe {
|
||||
@@ -56,16 +64,30 @@ fn relocate(compilation: &mut Compilation, relocations: &[Vec<Relocation>]) {
|
||||
}
|
||||
}
|
||||
|
||||
extern "C" fn grow_memory(size: u32, vmctx: *mut *mut u8) -> u32 {
|
||||
unsafe {
|
||||
let instance = (*vmctx.offset(2)) as *mut Instance;
|
||||
(*instance)
|
||||
.memory_mut(0)
|
||||
.grow(size)
|
||||
.unwrap_or(u32::max_value())
|
||||
}
|
||||
}
|
||||
|
||||
extern "C" fn current_memory(vmctx: *mut *mut u8) -> u32 {
|
||||
unsafe {
|
||||
let instance = (*vmctx.offset(2)) as *mut Instance;
|
||||
(*instance).memory_mut(0).current_size()
|
||||
}
|
||||
}
|
||||
|
||||
/// Create the VmCtx data structure for the JIT'd code to use. This must
|
||||
/// match the VmCtx layout in the environment.
|
||||
fn make_vmctx(instance: &mut Instance) -> Vec<*mut u8> {
|
||||
let mut memories = Vec::new();
|
||||
fn make_vmctx(instance: &mut Instance, mem_base_addrs: &mut [*mut u8]) -> Vec<*mut u8> {
|
||||
let mut vmctx = Vec::new();
|
||||
vmctx.push(instance.globals.as_mut_ptr());
|
||||
for mem in &mut instance.memories {
|
||||
memories.push(mem.as_mut_ptr());
|
||||
}
|
||||
vmctx.push(memories.as_mut_ptr() as *mut u8);
|
||||
vmctx.push(mem_base_addrs.as_mut_ptr() as *mut u8);
|
||||
vmctx.push(instance as *mut Instance as *mut u8);
|
||||
vmctx
|
||||
}
|
||||
|
||||
@@ -100,7 +122,13 @@ pub fn execute(
|
||||
|
||||
let code_buf = &compilation.functions[start_index];
|
||||
|
||||
let vmctx = make_vmctx(instance);
|
||||
// Collect all memory base addresses and Vec.
|
||||
let mut mem_base_addrs = instance
|
||||
.memories
|
||||
.iter_mut()
|
||||
.map(LinearMemory::base_addr)
|
||||
.collect::<Vec<_>>();
|
||||
let vmctx = make_vmctx(instance, &mut mem_base_addrs);
|
||||
|
||||
// Rather than writing inline assembly to jump to the code region, we use the fact that
|
||||
// the Rust ABI for calling a function with no arguments and no return matches the one of
|
||||
|
||||
Reference in New Issue
Block a user