Skip to content

Commit 6854dec

Browse files
committed
separate the context intialization from the function execution
the start function is called from the initialization phase
1 parent 9e56ed5 commit 6854dec

File tree

4 files changed

+61
-18
lines changed

4 files changed

+61
-18
lines changed

lib/environ/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,4 +43,4 @@ mod module;
4343

4444
pub use compilation::{compile_module, Compilation, Relocation, RelocationTarget, Relocations};
4545
pub use environ::{ModuleEnvironment, ModuleTranslation};
46-
pub use module::{DataInitializer, Module, TableElements};
46+
pub use module::{DataInitializer, Export, Module, TableElements};

lib/execute/src/execute.rs

Lines changed: 47 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ use region::Protection;
99
use std::mem::transmute;
1010
use std::ptr::{self, write_unaligned};
1111
use wasmtime_environ::{
12-
compile_module, Compilation, Module, ModuleTranslation, Relocation, RelocationTarget,
12+
compile_module, Compilation, Export, Module, ModuleTranslation, Relocation, RelocationTarget,
1313
};
1414

1515
/// Executes a module that has been translated with the `wasmtime-environ` environment
@@ -125,15 +125,12 @@ fn make_vmctx(instance: &mut Instance, mem_base_addrs: &mut [*mut u8]) -> Vec<*m
125125
vmctx
126126
}
127127

128-
/// Jumps to the code region of memory and execute the start function of the module.
129-
pub fn execute(
128+
/// prepares the execution context
129+
pub fn finish_instantiation(
130130
module: &Module,
131131
compilation: &Compilation,
132132
instance: &mut Instance,
133-
) -> Result<(), String> {
134-
let start_index = module
135-
.start_func
136-
.ok_or_else(|| String::from("No start function defined, aborting execution"))?;
133+
) -> Result<Vec<*mut u8>, String> {
137134
// TODO: Put all the function bodies into a page-aligned memory region, and
138135
// then make them ReadExecute rather than ReadWriteExecute.
139136
for code_buf in compilation.functions.values() {
@@ -154,26 +151,62 @@ pub fn execute(
154151
}
155152
}
156153

157-
let code_buf =
158-
&compilation.functions[module
159-
.defined_func_index(start_index)
160-
.expect("imported start functions not supported yet")];
161-
162154
// Collect all memory base addresses and Vec.
163155
let mut mem_base_addrs = instance
164156
.memories
165157
.iter_mut()
166158
.map(LinearMemory::base_addr)
167159
.collect::<Vec<_>>();
160+
168161
let vmctx = make_vmctx(instance, &mut mem_base_addrs);
169162

163+
if let Ok(start_index) = module
164+
.start_func
165+
.ok_or_else(|| String::from("No start function defined, aborting execution"))
166+
{
167+
let code_buf =
168+
&compilation.functions[module
169+
.defined_func_index(start_index)
170+
.expect("imported start functions not supported yet")];
171+
172+
// Rather than writing inline assembly to jump to the code region, we use the fact that
173+
// the Rust ABI for calling a function with no arguments and no return matches the one of
174+
// the generated code. Thanks to this, we can transmute the code region into a first-class
175+
// Rust function and call it.
176+
unsafe {
177+
let start_func = transmute::<_, fn(*const *mut u8)>(code_buf.as_ptr());
178+
start_func(vmctx.as_ptr());
179+
}
180+
}
181+
182+
Ok(vmctx)
183+
}
184+
185+
/// Jumps to the code region of memory and execute the exported function
186+
pub fn execute(
187+
module: &Module,
188+
compilation: &Compilation,
189+
vmctx: &mut Vec<*mut u8>,
190+
function: &str,
191+
) -> Result<(), String> {
192+
let fn_index = match module.exports.get(function) {
193+
Some(Export::Function(index)) => *index,
194+
Some(_) => return Err(format!("exported item \"{}\" is not a function", function)),
195+
None => return Err(format!("no export named \"{}\"", function)),
196+
};
197+
198+
let code_buf =
199+
&compilation.functions[module
200+
.defined_func_index(fn_index)
201+
.expect("imported start functions not supported yet")];
202+
170203
// Rather than writing inline assembly to jump to the code region, we use the fact that
171204
// the Rust ABI for calling a function with no arguments and no return matches the one of
172205
// the generated code. Thanks to this, we can transmute the code region into a first-class
173206
// Rust function and call it.
174207
unsafe {
175-
let start_func = transmute::<_, fn(*const *mut u8)>(code_buf.as_ptr());
176-
start_func(vmctx.as_ptr());
208+
let func = transmute::<_, fn(*const *mut u8)>(code_buf.as_ptr());
209+
func(vmctx.as_ptr());
177210
}
178211
Ok(())
179212
}

lib/execute/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,5 +40,5 @@ mod execute;
4040
mod instance;
4141
mod memory;
4242

43-
pub use execute::{compile_and_link_module, execute};
43+
pub use execute::{compile_and_link_module, execute, finish_instantiation};
4444
pub use instance::Instance;

src/main.rs

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ use std::path::PathBuf;
5656
use std::process::{exit, Command};
5757
use tempdir::TempDir;
5858
use wasmtime_environ::{Module, ModuleEnvironment};
59-
use wasmtime_execute::{compile_and_link_module, execute, Instance};
59+
use wasmtime_execute::{compile_and_link_module, execute, finish_instantiation, Instance};
6060

6161
const USAGE: &str = "
6262
Wasm to Cranelift IL translation utility.
@@ -65,11 +65,13 @@ The translation is dependent on the environment chosen.
6565
6666
Usage:
6767
wasmtime [-mop] <file>...
68+
wasmtime [-mop] <file>... --function=<fn>
6869
wasmtime --help | --version
6970
7071
Options:
7172
-o, --optimize runs optimization passes on the translated functions
7273
-m, --memory interactive memory inspector after execution
74+
--function=<fn> name of function to run
7375
-h, --help print this help message
7476
--version print the Cranelift version
7577
";
@@ -79,6 +81,7 @@ struct Args {
7981
arg_file: Vec<String>,
8082
flag_memory: bool,
8183
flag_optimize: bool,
84+
flag_function: Option<String>,
8285
}
8386

8487
fn read_to_end(path: PathBuf) -> Result<Vec<u8>, io::Error> {
@@ -157,7 +160,14 @@ fn handle_module(args: &Args, path: PathBuf, isa: &TargetIsa) -> Result<(), Stri
157160
&compilation,
158161
&translation.lazy.data_initializers,
159162
);
160-
execute(&translation.module, &compilation, &mut instance)?;
163+
164+
let mut context =
165+
finish_instantiation(&translation.module, &compilation, &mut instance)?;
166+
167+
if let Some(ref f) = args.flag_function {
168+
execute(&translation.module, &compilation, &mut context, &f)?;
169+
}
170+
161171
instance
162172
}
163173
Err(s) => {

0 commit comments

Comments
 (0)