Add a minimal SimpleJIT example program.
This minimally demonstrates usage of the API, and serves as a very small testcase to test that the basic JIT mechanisms are working.
This commit is contained in:
@@ -277,10 +277,18 @@ impl Backend for FaerieBackend {
|
|||||||
// Nothing to do.
|
// Nothing to do.
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn get_finalized_function(&self, _func: &FaerieCompiledFunction) {
|
||||||
|
// Nothing to do.
|
||||||
|
}
|
||||||
|
|
||||||
fn finalize_data(&mut self, _data: &FaerieCompiledData, _namespace: &ModuleNamespace<Self>) {
|
fn finalize_data(&mut self, _data: &FaerieCompiledData, _namespace: &ModuleNamespace<Self>) {
|
||||||
// Nothing to do.
|
// Nothing to do.
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn get_finalized_data(&self, _data: &FaerieCompiledData) {
|
||||||
|
// Nothing to do.
|
||||||
|
}
|
||||||
|
|
||||||
fn publish(&mut self) {
|
fn publish(&mut self) {
|
||||||
// Nothing to do.
|
// Nothing to do.
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -97,6 +97,9 @@ where
|
|||||||
namespace: &ModuleNamespace<Self>,
|
namespace: &ModuleNamespace<Self>,
|
||||||
) -> Self::FinalizedFunction;
|
) -> Self::FinalizedFunction;
|
||||||
|
|
||||||
|
/// Return the finalized artifact from the backend, if relevant.
|
||||||
|
fn get_finalized_function(&self, func: &Self::CompiledFunction) -> Self::FinalizedFunction;
|
||||||
|
|
||||||
/// Perform all outstanding relocations on the given data object. This requires all
|
/// Perform all outstanding relocations on the given data object. This requires all
|
||||||
/// `Local` and `Export` entities referenced to be defined.
|
/// `Local` and `Export` entities referenced to be defined.
|
||||||
fn finalize_data(
|
fn finalize_data(
|
||||||
@@ -105,6 +108,9 @@ where
|
|||||||
namespace: &ModuleNamespace<Self>,
|
namespace: &ModuleNamespace<Self>,
|
||||||
) -> Self::FinalizedData;
|
) -> Self::FinalizedData;
|
||||||
|
|
||||||
|
/// Return the finalized artifact from the backend, if relevant.
|
||||||
|
fn get_finalized_data(&self, data: &Self::CompiledData) -> Self::FinalizedData;
|
||||||
|
|
||||||
/// "Publish" all finalized functions and data objects to their ultimate destinations.
|
/// "Publish" all finalized functions and data objects to their ultimate destinations.
|
||||||
fn publish(&mut self);
|
fn publish(&mut self);
|
||||||
|
|
||||||
|
|||||||
@@ -581,7 +581,7 @@ where
|
|||||||
///
|
///
|
||||||
/// # Panics
|
/// # Panics
|
||||||
///
|
///
|
||||||
/// When the function has already been finalized this panics
|
/// When the function has already been finalized this panics.
|
||||||
pub fn finalize_function(&mut self, func: FuncId) -> B::FinalizedFunction {
|
pub fn finalize_function(&mut self, func: FuncId) -> B::FinalizedFunction {
|
||||||
let output = {
|
let output = {
|
||||||
let info = &self.contents.functions[func];
|
let info = &self.contents.functions[func];
|
||||||
@@ -604,12 +604,23 @@ where
|
|||||||
output
|
output
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Return the finalized artifact from the backend, if it provides one.
|
||||||
|
pub fn get_finalized_function(&mut self, func: FuncId) -> B::FinalizedFunction {
|
||||||
|
let info = &self.contents.functions[func];
|
||||||
|
debug_assert!(info.finalized, "data object not yet finalized");
|
||||||
|
self.backend.get_finalized_function(
|
||||||
|
info.compiled
|
||||||
|
.as_ref()
|
||||||
|
.expect("function must be compiled before it can be finalized"),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
/// Perform all outstanding relocations on the given data object. This requires all
|
/// Perform all outstanding relocations on the given data object. This requires all
|
||||||
/// `Local` and `Export` entities referenced to be defined.
|
/// `Local` and `Export` entities referenced to be defined.
|
||||||
///
|
///
|
||||||
/// # Panics
|
/// # Panics
|
||||||
///
|
///
|
||||||
/// When the data object has already been finalized this panics
|
/// When the data object has already been finalized this panics.
|
||||||
pub fn finalize_data(&mut self, data: DataId) -> B::FinalizedData {
|
pub fn finalize_data(&mut self, data: DataId) -> B::FinalizedData {
|
||||||
let output = {
|
let output = {
|
||||||
let info = &self.contents.data_objects[data];
|
let info = &self.contents.data_objects[data];
|
||||||
@@ -632,8 +643,21 @@ where
|
|||||||
output
|
output
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Return the finalized artifact from the backend, if it provides one.
|
||||||
|
pub fn get_finalized_data(&mut self, data: DataId) -> B::FinalizedData {
|
||||||
|
let info = &self.contents.data_objects[data];
|
||||||
|
debug_assert!(info.finalized, "data object not yet finalized");
|
||||||
|
self.backend.get_finalized_data(
|
||||||
|
info.compiled
|
||||||
|
.as_ref()
|
||||||
|
.expect("data object must be compiled before it can be finalized"),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
/// Finalize all functions and data objects. Note that this doesn't return the
|
/// Finalize all functions and data objects. Note that this doesn't return the
|
||||||
/// final artifacts returned from `finalize_function` or `finalize_data`.
|
/// final artifacts returned from `finalize_function` or `finalize_data`. Use
|
||||||
|
/// `get_finalized_function` and `get_finalized_data` to obtain the final
|
||||||
|
/// artifacts.
|
||||||
pub fn finalize_all(&mut self) {
|
pub fn finalize_all(&mut self) {
|
||||||
// TODO: Could we use something like `into_iter()` here?
|
// TODO: Could we use something like `into_iter()` here?
|
||||||
for info in self.contents.functions.values() {
|
for info in self.contents.functions.values() {
|
||||||
@@ -666,13 +690,13 @@ where
|
|||||||
for info in self.contents.data_objects.values_mut() {
|
for info in self.contents.data_objects.values_mut() {
|
||||||
info.finalized = true;
|
info.finalized = true;
|
||||||
}
|
}
|
||||||
|
self.backend.publish();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Consume the module and return the resulting `Product`. Some `Backend`
|
/// Consume the module and return the resulting `Product`. Some `Backend`
|
||||||
/// implementations may provide additional functionality available after
|
/// implementations may provide additional functionality available after
|
||||||
/// a `Module` is complete.
|
/// a `Module` is complete.
|
||||||
pub fn finish(mut self) -> B::Product {
|
pub fn finish(self) -> B::Product {
|
||||||
self.backend.publish();
|
|
||||||
self.backend.finish()
|
self.backend.finish()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,6 +21,9 @@ target-lexicon = { version = "0.0.3", default-features = false }
|
|||||||
[target.'cfg(target_os = "windows")'.dependencies]
|
[target.'cfg(target_os = "windows")'.dependencies]
|
||||||
winapi = { version = "0.3", features = ["winbase", "memoryapi"] }
|
winapi = { version = "0.3", features = ["winbase", "memoryapi"] }
|
||||||
|
|
||||||
|
[dev-dependencies]
|
||||||
|
cranelift = { path = "../umbrella", version = "0.19.0", default-features = false }
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = ["std"]
|
default = ["std"]
|
||||||
std = ["libc/use_std", "cranelift-codegen/std", "cranelift-module/std", "cranelift-native/std", "target-lexicon/std"]
|
std = ["libc/use_std", "cranelift-codegen/std", "cranelift-module/std", "cranelift-native/std", "target-lexicon/std"]
|
||||||
|
|||||||
@@ -2,3 +2,7 @@ This crate provides a simple JIT library that uses
|
|||||||
[Cranelift](https://crates.io/crates/cranelift).
|
[Cranelift](https://crates.io/crates/cranelift).
|
||||||
|
|
||||||
This crate is extremely experimental.
|
This crate is extremely experimental.
|
||||||
|
|
||||||
|
See the [example program] for a brief overview of how to use this.
|
||||||
|
|
||||||
|
[example program]: https://github.com/CraneStation/cranelift/tree/master/lib/simplejit/examples/simplejit-minimal.rs
|
||||||
|
|||||||
58
lib/simplejit/examples/simplejit-minimal.rs
Normal file
58
lib/simplejit/examples/simplejit-minimal.rs
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
extern crate cranelift;
|
||||||
|
extern crate cranelift_module;
|
||||||
|
extern crate cranelift_simplejit;
|
||||||
|
|
||||||
|
use cranelift::prelude::*;
|
||||||
|
use cranelift_module::{Linkage, Module};
|
||||||
|
use cranelift_simplejit::{SimpleJITBackend, SimpleJITBuilder};
|
||||||
|
use std::mem;
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let mut module: Module<SimpleJITBackend> = Module::new(SimpleJITBuilder::new());
|
||||||
|
let mut ctx = module.make_context();
|
||||||
|
let mut func_ctx = FunctionBuilderContext::new();
|
||||||
|
let sig = module.make_signature();
|
||||||
|
|
||||||
|
let func_a = module.declare_function("a", Linkage::Local, &sig).unwrap();
|
||||||
|
let func_b = module.declare_function("b", Linkage::Local, &sig).unwrap();
|
||||||
|
|
||||||
|
ctx.func.name = ExternalName::user(0, func_a.index() as u32);
|
||||||
|
{
|
||||||
|
let mut bcx: FunctionBuilder = FunctionBuilder::new(&mut ctx.func, &mut func_ctx);
|
||||||
|
let ebb = bcx.create_ebb();
|
||||||
|
|
||||||
|
bcx.switch_to_block(ebb);
|
||||||
|
bcx.ins().return_(&[]);
|
||||||
|
bcx.seal_all_blocks();
|
||||||
|
bcx.finalize();
|
||||||
|
}
|
||||||
|
module.define_function(func_a, &mut ctx).unwrap();
|
||||||
|
module.clear_context(&mut ctx);
|
||||||
|
|
||||||
|
ctx.func.name = ExternalName::user(0, func_b.index() as u32);
|
||||||
|
{
|
||||||
|
let mut bcx: FunctionBuilder = FunctionBuilder::new(&mut ctx.func, &mut func_ctx);
|
||||||
|
let ebb = bcx.create_ebb();
|
||||||
|
|
||||||
|
bcx.switch_to_block(ebb);
|
||||||
|
let local_func = module.declare_func_in_func(func_a, &mut bcx.func);
|
||||||
|
bcx.ins().call(local_func, &[]);
|
||||||
|
bcx.ins().return_(&[]);
|
||||||
|
bcx.seal_all_blocks();
|
||||||
|
bcx.finalize();
|
||||||
|
}
|
||||||
|
module.define_function(func_b, &mut ctx).unwrap();
|
||||||
|
module.clear_context(&mut ctx);
|
||||||
|
|
||||||
|
// Perform linking.
|
||||||
|
module.finalize_all();
|
||||||
|
|
||||||
|
// Get a raw pointer to the generated code.
|
||||||
|
let code_b = module.get_finalized_function(func_b);
|
||||||
|
|
||||||
|
// Cast it to a rust function pointer type.
|
||||||
|
let ptr_b = unsafe { mem::transmute::<_, fn()>(code_b) };
|
||||||
|
|
||||||
|
// Call it!
|
||||||
|
ptr_b();
|
||||||
|
}
|
||||||
@@ -334,7 +334,10 @@ impl<'simple_jit_backend> Backend for SimpleJITBackend {
|
|||||||
_ => unimplemented!(),
|
_ => unimplemented!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
func.code
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_finalized_function(&self, func: &Self::CompiledFunction) -> Self::FinalizedFunction {
|
||||||
func.code
|
func.code
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -394,7 +397,10 @@ impl<'simple_jit_backend> Backend for SimpleJITBackend {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
(data.storage, data.size)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_finalized_data(&self, data: &Self::CompiledData) -> Self::FinalizedData {
|
||||||
(data.storage, data.size)
|
(data.storage, data.size)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user