From d2943ec32dd952f809191bc30bdf4dfe67aff6c8 Mon Sep 17 00:00:00 2001 From: Dan Gohman Date: Tue, 28 Aug 2018 16:10:39 -0700 Subject: [PATCH] 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. --- lib/faerie/src/backend.rs | 8 +++ lib/module/src/backend.rs | 6 +++ lib/module/src/module.rs | 34 ++++++++++-- lib/simplejit/Cargo.toml | 3 ++ lib/simplejit/README.md | 4 ++ lib/simplejit/examples/simplejit-minimal.rs | 58 +++++++++++++++++++++ lib/simplejit/src/backend.rs | 6 +++ 7 files changed, 114 insertions(+), 5 deletions(-) create mode 100644 lib/simplejit/examples/simplejit-minimal.rs diff --git a/lib/faerie/src/backend.rs b/lib/faerie/src/backend.rs index 395a5c376c..7100bf1917 100644 --- a/lib/faerie/src/backend.rs +++ b/lib/faerie/src/backend.rs @@ -277,10 +277,18 @@ impl Backend for FaerieBackend { // Nothing to do. } + fn get_finalized_function(&self, _func: &FaerieCompiledFunction) { + // Nothing to do. + } + fn finalize_data(&mut self, _data: &FaerieCompiledData, _namespace: &ModuleNamespace) { // Nothing to do. } + fn get_finalized_data(&self, _data: &FaerieCompiledData) { + // Nothing to do. + } + fn publish(&mut self) { // Nothing to do. } diff --git a/lib/module/src/backend.rs b/lib/module/src/backend.rs index f167126191..42e77acb2f 100644 --- a/lib/module/src/backend.rs +++ b/lib/module/src/backend.rs @@ -97,6 +97,9 @@ where namespace: &ModuleNamespace, ) -> 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 /// `Local` and `Export` entities referenced to be defined. fn finalize_data( @@ -105,6 +108,9 @@ where namespace: &ModuleNamespace, ) -> 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. fn publish(&mut self); diff --git a/lib/module/src/module.rs b/lib/module/src/module.rs index c15aa1ff58..91faef517e 100644 --- a/lib/module/src/module.rs +++ b/lib/module/src/module.rs @@ -581,7 +581,7 @@ where /// /// # 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 { let output = { let info = &self.contents.functions[func]; @@ -604,12 +604,23 @@ where 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 /// `Local` and `Export` entities referenced to be defined. /// /// # 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 { let output = { let info = &self.contents.data_objects[data]; @@ -632,8 +643,21 @@ where 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 - /// 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) { // TODO: Could we use something like `into_iter()` here? for info in self.contents.functions.values() { @@ -666,13 +690,13 @@ where for info in self.contents.data_objects.values_mut() { info.finalized = true; } + self.backend.publish(); } /// Consume the module and return the resulting `Product`. Some `Backend` /// implementations may provide additional functionality available after /// a `Module` is complete. - pub fn finish(mut self) -> B::Product { - self.backend.publish(); + pub fn finish(self) -> B::Product { self.backend.finish() } } diff --git a/lib/simplejit/Cargo.toml b/lib/simplejit/Cargo.toml index 4ed87adf58..799fe4ae03 100644 --- a/lib/simplejit/Cargo.toml +++ b/lib/simplejit/Cargo.toml @@ -21,6 +21,9 @@ target-lexicon = { version = "0.0.3", default-features = false } [target.'cfg(target_os = "windows")'.dependencies] winapi = { version = "0.3", features = ["winbase", "memoryapi"] } +[dev-dependencies] +cranelift = { path = "../umbrella", version = "0.19.0", default-features = false } + [features] default = ["std"] std = ["libc/use_std", "cranelift-codegen/std", "cranelift-module/std", "cranelift-native/std", "target-lexicon/std"] diff --git a/lib/simplejit/README.md b/lib/simplejit/README.md index d5f2cecc37..3d31bb98e9 100644 --- a/lib/simplejit/README.md +++ b/lib/simplejit/README.md @@ -2,3 +2,7 @@ This crate provides a simple JIT library that uses [Cranelift](https://crates.io/crates/cranelift). 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 diff --git a/lib/simplejit/examples/simplejit-minimal.rs b/lib/simplejit/examples/simplejit-minimal.rs new file mode 100644 index 0000000000..054204882e --- /dev/null +++ b/lib/simplejit/examples/simplejit-minimal.rs @@ -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 = 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(); +} diff --git a/lib/simplejit/src/backend.rs b/lib/simplejit/src/backend.rs index 15a8985578..fa3dbdc0fc 100644 --- a/lib/simplejit/src/backend.rs +++ b/lib/simplejit/src/backend.rs @@ -334,7 +334,10 @@ impl<'simple_jit_backend> Backend for SimpleJITBackend { _ => unimplemented!(), } } + func.code + } + fn get_finalized_function(&self, func: &Self::CompiledFunction) -> Self::FinalizedFunction { 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) }