11//! The JIT driver uses [`cranelift_simplejit`] to JIT execute programs without writing any object
22//! files.
33
4+ use std:: cell:: RefCell ;
45use std:: ffi:: CString ;
56use std:: os:: raw:: { c_char, c_int} ;
67
@@ -10,8 +11,13 @@ use rustc_middle::mir::mono::MonoItem;
1011use cranelift_jit:: { JITBuilder , JITModule } ;
1112
1213use crate :: prelude:: * ;
14+ use crate :: { CodegenCx , CodegenMode } ;
1315
14- pub ( super ) fn run_jit ( tcx : TyCtxt < ' _ > ) -> ! {
16+ thread_local ! {
17+ pub static CURRENT_MODULE : RefCell <Option <JITModule >> = RefCell :: new( None ) ;
18+ }
19+
20+ pub ( super ) fn run_jit ( tcx : TyCtxt < ' _ > , codegen_mode : CodegenMode ) -> ! {
1521 if !tcx. sess . opts . output_types . should_codegen ( ) {
1622 tcx. sess . fatal ( "JIT mode doesn't work with `cargo check`." ) ;
1723 }
@@ -40,6 +46,7 @@ pub(super) fn run_jit(tcx: TyCtxt<'_>) -> ! {
4046 crate :: build_isa ( tcx. sess ) ,
4147 cranelift_module:: default_libcall_names ( ) ,
4248 ) ;
49+ jit_builder. hotswap ( matches ! ( codegen_mode, CodegenMode :: JitLazy ) ) ;
4350 jit_builder. symbols ( imported_symbols) ;
4451 let mut jit_module = JITModule :: new ( jit_builder) ;
4552 assert_eq ! ( pointer_ty( tcx) , jit_module. target_config( ) . pointer_type( ) ) ;
@@ -74,13 +81,17 @@ pub(super) fn run_jit(tcx: TyCtxt<'_>) -> ! {
7481 for ( mono_item, ( linkage, visibility) ) in mono_items {
7582 let linkage = crate :: linkage:: get_clif_linkage ( mono_item, linkage, visibility) ;
7683 match mono_item {
77- MonoItem :: Fn ( inst) => {
78- cx. tcx . sess . time ( "codegen fn" , || {
79- crate :: base:: codegen_fn ( & mut cx, inst, linkage)
80- } ) ;
81- }
84+ MonoItem :: Fn ( inst) => match codegen_mode {
85+ CodegenMode :: Aot => unreachable ! ( ) ,
86+ CodegenMode :: Jit => {
87+ cx. tcx . sess . time ( "codegen fn" , || {
88+ crate :: base:: codegen_fn ( & mut cx, inst, linkage)
89+ } ) ;
90+ }
91+ CodegenMode :: JitLazy => codegen_shim ( & mut cx, inst) ,
92+ } ,
8293 MonoItem :: Static ( def_id) => {
83- crate :: constant:: codegen_static ( & mut cx. constants_cx , def_id)
94+ crate :: constant:: codegen_static ( & mut cx. constants_cx , def_id) ;
8495 }
8596 MonoItem :: GlobalAsm ( hir_id) => {
8697 let item = cx. tcx . hir ( ) . expect_item ( hir_id) ;
@@ -126,11 +137,50 @@ pub(super) fn run_jit(tcx: TyCtxt<'_>) -> ! {
126137 // useful as some dynamic linkers use it as a marker to jump over.
127138 argv. push ( std:: ptr:: null ( ) ) ;
128139
140+ CURRENT_MODULE
141+ . with ( |current_module| assert ! ( current_module. borrow_mut( ) . replace( jit_module) . is_none( ) ) ) ;
142+
129143 let ret = f ( args. len ( ) as c_int , argv. as_ptr ( ) ) ;
130144
131145 std:: process:: exit ( ret) ;
132146}
133147
148+ #[ no_mangle]
149+ extern "C" fn __clif_jit_fn ( instance_ptr : * const Instance < ' static > ) -> * const u8 {
150+ rustc_middle:: ty:: tls:: with ( |tcx| {
151+ // lift is used to ensure the correct lifetime for instance.
152+ let instance = tcx. lift ( unsafe { * instance_ptr } ) . unwrap ( ) ;
153+
154+ CURRENT_MODULE . with ( |jit_module| {
155+ let mut jit_module = jit_module. borrow_mut ( ) ;
156+ let jit_module = jit_module. as_mut ( ) . unwrap ( ) ;
157+ let mut cx = crate :: CodegenCx :: new ( tcx, jit_module, false , false ) ;
158+
159+ let ( name, sig) = crate :: abi:: get_function_name_and_sig (
160+ tcx,
161+ cx. module . isa ( ) . triple ( ) ,
162+ instance,
163+ true ,
164+ ) ;
165+ let func_id = cx
166+ . module
167+ . declare_function ( & name, Linkage :: Export , & sig)
168+ . unwrap ( ) ;
169+ cx. module . prepare_for_function_redefine ( func_id) . unwrap ( ) ;
170+
171+ tcx. sess . time ( "codegen fn" , || {
172+ crate :: base:: codegen_fn ( & mut cx, instance, Linkage :: Export )
173+ } ) ;
174+
175+ let ( jit_module, global_asm, _debug_context, unwind_context) = cx. finalize ( ) ;
176+ assert ! ( global_asm. is_empty( ) ) ;
177+ jit_module. finalize_definitions ( ) ;
178+ std:: mem:: forget ( unsafe { unwind_context. register_jit ( & jit_module) } ) ;
179+ jit_module. get_finalized_function ( func_id)
180+ } )
181+ } )
182+ }
183+
134184fn load_imported_symbols_for_jit ( tcx : TyCtxt < ' _ > ) -> Vec < ( String , * const u8 ) > {
135185 use rustc_middle:: middle:: dependency_format:: Linkage ;
136186
@@ -190,3 +240,68 @@ fn load_imported_symbols_for_jit(tcx: TyCtxt<'_>) -> Vec<(String, *const u8)> {
190240
191241 imported_symbols
192242}
243+
244+ pub ( super ) fn codegen_shim < ' tcx > ( cx : & mut CodegenCx < ' tcx , impl Module > , inst : Instance < ' tcx > ) {
245+ let tcx = cx. tcx ;
246+
247+ let pointer_type = cx. module . target_config ( ) . pointer_type ( ) ;
248+
249+ let ( name, sig) =
250+ crate :: abi:: get_function_name_and_sig ( tcx, cx. module . isa ( ) . triple ( ) , inst, true ) ;
251+ let func_id = cx
252+ . module
253+ . declare_function ( & name, Linkage :: Export , & sig)
254+ . unwrap ( ) ;
255+
256+ let instance_ptr = Box :: into_raw ( Box :: new ( inst) ) ;
257+
258+ let jit_fn = cx
259+ . module
260+ . declare_function (
261+ "__clif_jit_fn" ,
262+ Linkage :: Import ,
263+ & Signature {
264+ call_conv : cx. module . target_config ( ) . default_call_conv ,
265+ params : vec ! [ AbiParam :: new( pointer_type) ] ,
266+ returns : vec ! [ AbiParam :: new( pointer_type) ] ,
267+ } ,
268+ )
269+ . unwrap ( ) ;
270+
271+ let mut trampoline = Function :: with_name_signature ( ExternalName :: default ( ) , sig. clone ( ) ) ;
272+ let mut builder_ctx = FunctionBuilderContext :: new ( ) ;
273+ let mut trampoline_builder = FunctionBuilder :: new ( & mut trampoline, & mut builder_ctx) ;
274+
275+ let jit_fn = cx
276+ . module
277+ . declare_func_in_func ( jit_fn, trampoline_builder. func ) ;
278+ let sig_ref = trampoline_builder. func . import_signature ( sig) ;
279+
280+ let entry_block = trampoline_builder. create_block ( ) ;
281+ trampoline_builder. append_block_params_for_function_params ( entry_block) ;
282+ let fn_args = trampoline_builder
283+ . func
284+ . dfg
285+ . block_params ( entry_block)
286+ . to_vec ( ) ;
287+
288+ trampoline_builder. switch_to_block ( entry_block) ;
289+ let instance_ptr = trampoline_builder
290+ . ins ( )
291+ . iconst ( pointer_type, instance_ptr as u64 as i64 ) ;
292+ let jitted_fn = trampoline_builder. ins ( ) . call ( jit_fn, & [ instance_ptr] ) ;
293+ let jitted_fn = trampoline_builder. func . dfg . inst_results ( jitted_fn) [ 0 ] ;
294+ let call_inst = trampoline_builder
295+ . ins ( )
296+ . call_indirect ( sig_ref, jitted_fn, & fn_args) ;
297+ let ret_vals = trampoline_builder. func . dfg . inst_results ( call_inst) . to_vec ( ) ;
298+ trampoline_builder. ins ( ) . return_ ( & ret_vals) ;
299+
300+ cx. module
301+ . define_function (
302+ func_id,
303+ & mut Context :: for_function ( trampoline) ,
304+ & mut cranelift_codegen:: binemit:: NullTrapSink { } ,
305+ )
306+ . unwrap ( ) ;
307+ }
0 commit comments