separate the context intialization from the function execution (#21)
the start function is called from the initialization phase
This commit is contained in:
committed by
Dan Gohman
parent
95fba6a9de
commit
bf5a06bc95
@@ -46,7 +46,7 @@ mod vmcontext;
|
|||||||
|
|
||||||
pub use compilation::{compile_module, Compilation, Relocation, RelocationTarget, Relocations};
|
pub use compilation::{compile_module, Compilation, Relocation, RelocationTarget, Relocations};
|
||||||
pub use environ::{ModuleEnvironment, ModuleTranslation};
|
pub use environ::{ModuleEnvironment, ModuleTranslation};
|
||||||
pub use module::{DataInitializer, Module, TableElements};
|
pub use module::{DataInitializer, Export, Module, TableElements};
|
||||||
|
|
||||||
#[cfg(not(feature = "std"))]
|
#[cfg(not(feature = "std"))]
|
||||||
mod std {
|
mod std {
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ use std::ptr::{self, write_unaligned};
|
|||||||
use std::string::String;
|
use std::string::String;
|
||||||
use std::vec::Vec;
|
use std::vec::Vec;
|
||||||
use wasmtime_environ::{
|
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
|
/// 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
|
vmctx
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Jumps to the code region of memory and execute the start function of the module.
|
/// prepares the execution context
|
||||||
pub fn execute(
|
pub fn finish_instantiation(
|
||||||
module: &Module,
|
module: &Module,
|
||||||
compilation: &Compilation,
|
compilation: &Compilation,
|
||||||
instance: &mut Instance,
|
instance: &mut Instance,
|
||||||
) -> Result<(), String> {
|
) -> Result<Vec<*mut u8>, String> {
|
||||||
let start_index = module
|
// TODO: Put all the function bodies into a page-aligned memory region, and
|
||||||
.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
|
|
||||||
// then make them ReadExecute rather than ReadWriteExecute.
|
// then make them ReadExecute rather than ReadWriteExecute.
|
||||||
for code_buf in compilation.functions.values() {
|
for code_buf in compilation.functions.values() {
|
||||||
match unsafe {
|
match unsafe {
|
||||||
@@ -161,19 +158,21 @@ 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.
|
// Collect all memory base addresses and Vec.
|
||||||
let mut mem_base_addrs = instance
|
let mut mem_base_addrs = instance
|
||||||
.memories
|
.memories
|
||||||
.values_mut()
|
.values_mut()
|
||||||
.map(LinearMemory::base_addr)
|
.map(LinearMemory::base_addr)
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
let vmctx = make_vmctx(instance, &mut mem_base_addrs);
|
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
|
// 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 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
|
// the generated code. Thanks to this, we can transmute the code region into a first-class
|
||||||
@@ -182,5 +181,36 @@ pub fn execute(
|
|||||||
let start_func = transmute::<_, fn(*const *mut u8)>(code_buf.as_ptr());
|
let start_func = transmute::<_, fn(*const *mut u8)>(code_buf.as_ptr());
|
||||||
start_func(vmctx.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 func = transmute::<_, fn(*const *mut u8)>(code_buf.as_ptr());
|
||||||
|
func(vmctx.as_ptr());
|
||||||
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -41,7 +41,7 @@ mod execute;
|
|||||||
mod instance;
|
mod instance;
|
||||||
mod memory;
|
mod memory;
|
||||||
|
|
||||||
pub use execute::{compile_and_link_module, execute};
|
pub use execute::{compile_and_link_module, execute, finish_instantiation};
|
||||||
pub use instance::Instance;
|
pub use instance::Instance;
|
||||||
|
|
||||||
#[cfg(not(feature = "std"))]
|
#[cfg(not(feature = "std"))]
|
||||||
|
|||||||
14
src/main.rs
14
src/main.rs
@@ -60,7 +60,7 @@ use std::path::PathBuf;
|
|||||||
use std::process::{exit, Command};
|
use std::process::{exit, Command};
|
||||||
use tempdir::TempDir;
|
use tempdir::TempDir;
|
||||||
use wasmtime_environ::{Module, ModuleEnvironment};
|
use wasmtime_environ::{Module, ModuleEnvironment};
|
||||||
use wasmtime_execute::{compile_and_link_module, execute, Instance};
|
use wasmtime_execute::{compile_and_link_module, execute, finish_instantiation, Instance};
|
||||||
|
|
||||||
const USAGE: &str = "
|
const USAGE: &str = "
|
||||||
Wasm to Cranelift IL translation utility.
|
Wasm to Cranelift IL translation utility.
|
||||||
@@ -69,11 +69,13 @@ The translation is dependent on the environment chosen.
|
|||||||
|
|
||||||
Usage:
|
Usage:
|
||||||
wasmtime [-mop] <file>...
|
wasmtime [-mop] <file>...
|
||||||
|
wasmtime [-mop] <file>... --function=<fn>
|
||||||
wasmtime --help | --version
|
wasmtime --help | --version
|
||||||
|
|
||||||
Options:
|
Options:
|
||||||
-o, --optimize runs optimization passes on the translated functions
|
-o, --optimize runs optimization passes on the translated functions
|
||||||
-m, --memory interactive memory inspector after execution
|
-m, --memory interactive memory inspector after execution
|
||||||
|
--function=<fn> name of function to run
|
||||||
-h, --help print this help message
|
-h, --help print this help message
|
||||||
--version print the Cranelift version
|
--version print the Cranelift version
|
||||||
";
|
";
|
||||||
@@ -83,6 +85,7 @@ struct Args {
|
|||||||
arg_file: Vec<String>,
|
arg_file: Vec<String>,
|
||||||
flag_memory: bool,
|
flag_memory: bool,
|
||||||
flag_optimize: bool,
|
flag_optimize: bool,
|
||||||
|
flag_function: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn read_to_end(path: PathBuf) -> Result<Vec<u8>, io::Error> {
|
fn read_to_end(path: PathBuf) -> Result<Vec<u8>, io::Error> {
|
||||||
@@ -162,7 +165,14 @@ fn handle_module(args: &Args, path: PathBuf, isa: &TargetIsa) -> Result<(), Stri
|
|||||||
&compilation,
|
&compilation,
|
||||||
&translation.lazy.data_initializers,
|
&translation.lazy.data_initializers,
|
||||||
);
|
);
|
||||||
execute(&translation.module, &compilation, &mut instance)?;
|
|
||||||
|
let mut context =
|
||||||
|
finish_instantiation(&translation.module, &compilation, &mut instance)?;
|
||||||
|
|
||||||
|
if let Some(ref f) = args.flag_function {
|
||||||
|
execute(&translation.module, &compilation, &mut context, &f)?;
|
||||||
|
}
|
||||||
|
|
||||||
instance
|
instance
|
||||||
}
|
}
|
||||||
Err(s) => {
|
Err(s) => {
|
||||||
|
|||||||
Reference in New Issue
Block a user