separate the context intialization from the function execution (#21)

the start function is called from the initialization phase
This commit is contained in:
Geoffroy Couprie
2018-11-27 14:33:56 +01:00
committed by Dan Gohman
parent 95fba6a9de
commit bf5a06bc95
4 changed files with 60 additions and 20 deletions

View File

@@ -11,7 +11,7 @@ use std::ptr::{self, write_unaligned};
use std::string::String;
use std::vec::Vec;
use wasmtime_environ::{
compile_module, Compilation, Module, ModuleTranslation, Relocation, RelocationTarget,
compile_module, Compilation, Export, Module, ModuleTranslation, Relocation, RelocationTarget,
};
/// Executes a module that has been translated with the `wasmtime-environ` environment
@@ -132,16 +132,13 @@ fn make_vmctx(instance: &mut Instance, mem_base_addrs: &mut [*mut u8]) -> Vec<*m
vmctx
}
/// Jumps to the code region of memory and execute the start function of the module.
pub fn execute(
/// prepares the execution context
pub fn finish_instantiation(
module: &Module,
compilation: &Compilation,
instance: &mut Instance,
) -> Result<(), String> {
let start_index = module
.start_func
.ok_or_else(|| String::from("No start function defined, aborting execution"))?;
// FIXME: Put all the function bodies into a page-aligned memory region, and
) -> Result<Vec<*mut u8>, String> {
// TODO: Put all the function bodies into a page-aligned memory region, and
// then make them ReadExecute rather than ReadWriteExecute.
for code_buf in compilation.functions.values() {
match unsafe {
@@ -161,26 +158,59 @@ pub fn execute(
}
}
let code_buf =
&compilation.functions[module
.defined_func_index(start_index)
.expect("imported start functions not supported yet")];
// Collect all memory base addresses and Vec.
let mut mem_base_addrs = instance
.memories
.values_mut()
.map(LinearMemory::base_addr)
.collect::<Vec<_>>();
let vmctx = make_vmctx(instance, &mut mem_base_addrs);
if let Some(start_index) = module.start_func {
let code_buf =
&compilation.functions[module
.defined_func_index(start_index)
.expect("imported start functions not supported yet")];
// 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
// the generated code. Thanks to this, we can transmute the code region into a first-class
// Rust function and call it.
unsafe {
let start_func = transmute::<_, fn(*const *mut u8)>(code_buf.as_ptr());
start_func(vmctx.as_ptr());
}
}
Ok(vmctx)
}
/// Jumps to the code region of memory and execute the exported function
pub fn execute(
module: &Module,
compilation: &Compilation,
vmctx: &mut Vec<*mut u8>,
function: &str,
) -> Result<(), String> {
let fn_index = match module.exports.get(function) {
Some(Export::Function(index)) => *index,
Some(_) => return Err(format!("exported item \"{}\" is not a function", function)),
None => return Err(format!("no export named \"{}\"", function)),
};
let code_buf =
&compilation.functions[module
.defined_func_index(fn_index)
.expect("imported start functions not supported yet")];
// 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
// the generated code. Thanks to this, we can transmute the code region into a first-class
// Rust function and call it.
unsafe {
let start_func = transmute::<_, fn(*const *mut u8)>(code_buf.as_ptr());
start_func(vmctx.as_ptr());
let func = transmute::<_, fn(*const *mut u8)>(code_buf.as_ptr());
func(vmctx.as_ptr());
}
Ok(())
}

View File

@@ -41,7 +41,7 @@ mod execute;
mod instance;
mod memory;
pub use execute::{compile_and_link_module, execute};
pub use execute::{compile_and_link_module, execute, finish_instantiation};
pub use instance::Instance;
#[cfg(not(feature = "std"))]