11//! The JIT driver uses [`cranelift_jit`] to JIT execute programs without writing any object
22//! files.
33
4- use std:: cell:: RefCell ;
54use std:: ffi:: CString ;
65use std:: os:: raw:: { c_char, c_int} ;
7- use std:: sync:: { Mutex , OnceLock , mpsc} ;
86
9- use cranelift_frontend:: { FunctionBuilder , FunctionBuilderContext } ;
107use cranelift_jit:: { JITBuilder , JITModule } ;
118use rustc_codegen_ssa:: CrateInfo ;
129use rustc_middle:: mir:: mono:: MonoItem ;
@@ -18,58 +15,13 @@ use crate::debuginfo::TypeDebugContext;
1815use crate :: prelude:: * ;
1916use crate :: unwind_module:: UnwindModule ;
2017
21- struct JitState {
22- jit_module : UnwindModule < JITModule > ,
23- }
24-
25- thread_local ! {
26- static LAZY_JIT_STATE : RefCell <Option <JitState >> = const { RefCell :: new( None ) } ;
27- }
28-
29- /// The Sender owned by the rustc thread
30- static GLOBAL_MESSAGE_SENDER : OnceLock < Mutex < mpsc:: Sender < UnsafeMessage > > > = OnceLock :: new ( ) ;
31-
32- /// A message that is sent from the jitted runtime to the rustc thread.
33- /// Senders are responsible for upholding `Send` semantics.
34- enum UnsafeMessage {
35- /// Request that the specified `Instance` be lazily jitted.
36- ///
37- /// Nothing accessible through `instance_ptr` may be moved or mutated by the sender after
38- /// this message is sent.
39- JitFn {
40- instance_ptr : * const Instance < ' static > ,
41- trampoline_ptr : * const u8 ,
42- tx : mpsc:: Sender < * const u8 > ,
43- } ,
44- }
45- unsafe impl Send for UnsafeMessage { }
46-
47- impl UnsafeMessage {
48- /// Send the message.
49- fn send ( self ) {
50- thread_local ! {
51- /// The Sender owned by the local thread
52- static LOCAL_MESSAGE_SENDER : mpsc:: Sender <UnsafeMessage > =
53- GLOBAL_MESSAGE_SENDER
54- . get( ) . unwrap( )
55- . lock( ) . unwrap( )
56- . clone( ) ;
57- }
58- LOCAL_MESSAGE_SENDER . with ( |sender| {
59- sender. send ( self ) . expect ( "rustc thread hung up before lazy JIT request was sent" )
60- } )
61- }
62- }
63-
64- fn create_jit_module ( tcx : TyCtxt < ' _ > , hotswap : bool ) -> ( UnwindModule < JITModule > , CodegenCx ) {
18+ fn create_jit_module ( tcx : TyCtxt < ' _ > ) -> ( UnwindModule < JITModule > , CodegenCx ) {
6519 let crate_info = CrateInfo :: new ( tcx, "dummy_target_cpu" . to_string ( ) ) ;
6620
6721 let isa = crate :: build_isa ( tcx. sess ) ;
6822 let mut jit_builder = JITBuilder :: with_isa ( isa, cranelift_module:: default_libcall_names ( ) ) ;
69- jit_builder. hotswap ( hotswap) ;
7023 crate :: compiler_builtins:: register_functions_for_jit ( & mut jit_builder) ;
7124 jit_builder. symbol_lookup_fn ( dep_symbol_lookup_fn ( tcx. sess , crate_info) ) ;
72- jit_builder. symbol ( "__clif_jit_fn" , clif_jit_fn as * const u8 ) ;
7325 let mut jit_module = UnwindModule :: new ( JITModule :: new ( jit_builder) , false ) ;
7426
7527 let cx = crate :: CodegenCx :: new ( tcx, jit_module. isa ( ) , false , sym:: dummy_cgu_name) ;
@@ -79,7 +31,7 @@ fn create_jit_module(tcx: TyCtxt<'_>, hotswap: bool) -> (UnwindModule<JITModule>
7931 ( jit_module, cx)
8032}
8133
82- pub ( crate ) fn run_jit ( tcx : TyCtxt < ' _ > , jit_lazy : bool , jit_args : Vec < String > ) -> ! {
34+ pub ( crate ) fn run_jit ( tcx : TyCtxt < ' _ > , jit_args : Vec < String > ) -> ! {
8335 if !tcx. sess . opts . output_types . should_codegen ( ) {
8436 tcx. dcx ( ) . fatal ( "JIT mode doesn't work with `cargo check`" ) ;
8537 }
@@ -88,7 +40,7 @@ pub(crate) fn run_jit(tcx: TyCtxt<'_>, jit_lazy: bool, jit_args: Vec<String>) ->
8840 tcx. dcx ( ) . fatal ( "can't jit non-executable crate" ) ;
8941 }
9042
91- let ( mut jit_module, mut cx) = create_jit_module ( tcx, jit_lazy ) ;
43+ let ( mut jit_module, mut cx) = create_jit_module ( tcx) ;
9244 let mut cached_context = Context :: new ( ) ;
9345
9446 let cgus = tcx. collect_and_partition_mono_items ( ( ) ) . codegen_units ;
@@ -105,17 +57,13 @@ pub(crate) fn run_jit(tcx: TyCtxt<'_>, jit_lazy: bool, jit_args: Vec<String>) ->
10557 for ( mono_item, _) in mono_items {
10658 match mono_item {
10759 MonoItem :: Fn ( inst) => {
108- if jit_lazy {
109- codegen_shim ( tcx, & mut cached_context, & mut jit_module, inst)
110- } else {
111- codegen_and_compile_fn (
112- tcx,
113- & mut cx,
114- & mut cached_context,
115- & mut jit_module,
116- inst,
117- ) ;
118- }
60+ codegen_and_compile_fn (
61+ tcx,
62+ & mut cx,
63+ & mut cached_context,
64+ & mut jit_module,
65+ inst,
66+ ) ;
11967 }
12068 MonoItem :: Static ( def_id) => {
12169 crate :: constant:: codegen_static ( tcx, & mut jit_module, def_id) ;
@@ -158,41 +106,17 @@ pub(crate) fn run_jit(tcx: TyCtxt<'_>, jit_lazy: bool, jit_args: Vec<String>) ->
158106 let start_func_id = jit_module. declare_function ( "main" , Linkage :: Import , & start_sig) . unwrap ( ) ;
159107 let finalized_start: * const u8 = jit_module. module . get_finalized_function ( start_func_id) ;
160108
161- LAZY_JIT_STATE . with ( |lazy_jit_state| {
162- let mut lazy_jit_state = lazy_jit_state. borrow_mut ( ) ;
163- assert ! ( lazy_jit_state. is_none( ) ) ;
164- * lazy_jit_state = Some ( JitState { jit_module } ) ;
165- } ) ;
166-
167109 let f: extern "C" fn ( c_int , * const * const c_char ) -> c_int =
168110 unsafe { :: std:: mem:: transmute ( finalized_start) } ;
169111
170- let ( tx, rx) = mpsc:: channel ( ) ;
171- GLOBAL_MESSAGE_SENDER . set ( Mutex :: new ( tx) ) . unwrap ( ) ;
172-
173- // Spawn the jitted runtime in a new thread so that this rustc thread can handle messages
174- // (eg to lazily JIT further functions as required)
175- std:: thread:: spawn ( move || {
176- let mut argv = args. iter ( ) . map ( |arg| arg. as_ptr ( ) ) . collect :: < Vec < _ > > ( ) ;
112+ let mut argv = args. iter ( ) . map ( |arg| arg. as_ptr ( ) ) . collect :: < Vec < _ > > ( ) ;
177113
178- // Push a null pointer as a terminating argument. This is required by POSIX and
179- // useful as some dynamic linkers use it as a marker to jump over.
180- argv. push ( std:: ptr:: null ( ) ) ;
114+ // Push a null pointer as a terminating argument. This is required by POSIX and
115+ // useful as some dynamic linkers use it as a marker to jump over.
116+ argv. push ( std:: ptr:: null ( ) ) ;
181117
182- let ret = f ( args. len ( ) as c_int , argv. as_ptr ( ) ) ;
183- std:: process:: exit ( ret) ;
184- } ) ;
185-
186- // Handle messages
187- loop {
188- match rx. recv ( ) . unwrap ( ) {
189- // lazy JIT compilation request - compile requested instance and return pointer to result
190- UnsafeMessage :: JitFn { instance_ptr, trampoline_ptr, tx } => {
191- tx. send ( jit_fn ( instance_ptr, trampoline_ptr) )
192- . expect ( "jitted runtime hung up before response to lazy JIT request was sent" ) ;
193- }
194- }
195- }
118+ let ret = f ( args. len ( ) as c_int , argv. as_ptr ( ) ) ;
119+ std:: process:: exit ( ret) ;
196120}
197121
198122pub ( crate ) fn codegen_and_compile_fn < ' tcx > (
@@ -224,58 +148,6 @@ pub(crate) fn codegen_and_compile_fn<'tcx>(
224148 } ) ;
225149}
226150
227- extern "C" fn clif_jit_fn (
228- instance_ptr : * const Instance < ' static > ,
229- trampoline_ptr : * const u8 ,
230- ) -> * const u8 {
231- // send the JIT request to the rustc thread, with a channel for the response
232- let ( tx, rx) = mpsc:: channel ( ) ;
233- UnsafeMessage :: JitFn { instance_ptr, trampoline_ptr, tx } . send ( ) ;
234-
235- // block on JIT compilation result
236- rx. recv ( ) . expect ( "rustc thread hung up before responding to sent lazy JIT request" )
237- }
238-
239- fn jit_fn ( instance_ptr : * const Instance < ' static > , trampoline_ptr : * const u8 ) -> * const u8 {
240- rustc_middle:: ty:: tls:: with ( |tcx| {
241- // lift is used to ensure the correct lifetime for instance.
242- let instance = tcx. lift ( unsafe { * instance_ptr } ) . unwrap ( ) ;
243-
244- LAZY_JIT_STATE . with ( |lazy_jit_state| {
245- let mut lazy_jit_state = lazy_jit_state. borrow_mut ( ) ;
246- let lazy_jit_state = lazy_jit_state. as_mut ( ) . unwrap ( ) ;
247- let jit_module = & mut lazy_jit_state. jit_module ;
248-
249- let name = tcx. symbol_name ( instance) . name ;
250- let sig = crate :: abi:: get_function_sig (
251- tcx,
252- jit_module. target_config ( ) . default_call_conv ,
253- instance,
254- ) ;
255- let func_id = jit_module. declare_function ( name, Linkage :: Export , & sig) . unwrap ( ) ;
256-
257- let current_ptr = jit_module. module . read_got_entry ( func_id) ;
258-
259- // If the function's GOT entry has already been updated to point at something other
260- // than the shim trampoline, don't re-jit but just return the new pointer instead.
261- // This does not need synchronization as this code is executed only by a sole rustc
262- // thread.
263- if current_ptr != trampoline_ptr {
264- return current_ptr;
265- }
266-
267- jit_module. module . prepare_for_function_redefine ( func_id) . unwrap ( ) ;
268-
269- let mut cx = crate :: CodegenCx :: new ( tcx, jit_module. isa ( ) , false , sym:: dummy_cgu_name) ;
270- codegen_and_compile_fn ( tcx, & mut cx, & mut Context :: new ( ) , jit_module, instance) ;
271-
272- assert ! ( cx. global_asm. is_empty( ) ) ;
273- jit_module. finalize_definitions ( ) ;
274- jit_module. module . get_finalized_function ( func_id)
275- } )
276- } )
277- }
278-
279151fn dep_symbol_lookup_fn (
280152 sess : & Session ,
281153 crate_info : CrateInfo ,
@@ -323,57 +195,3 @@ fn dep_symbol_lookup_fn(
323195 None
324196 } )
325197}
326-
327- fn codegen_shim < ' tcx > (
328- tcx : TyCtxt < ' tcx > ,
329- cached_context : & mut Context ,
330- module : & mut UnwindModule < JITModule > ,
331- inst : Instance < ' tcx > ,
332- ) {
333- let pointer_type = module. target_config ( ) . pointer_type ( ) ;
334-
335- let name = tcx. symbol_name ( inst) . name ;
336- let sig = crate :: abi:: get_function_sig ( tcx, module. target_config ( ) . default_call_conv , inst) ;
337- let func_id = module. declare_function ( name, Linkage :: Export , & sig) . unwrap ( ) ;
338-
339- let instance_ptr = Box :: into_raw ( Box :: new ( inst) ) ;
340-
341- let jit_fn = module
342- . declare_function (
343- "__clif_jit_fn" ,
344- Linkage :: Import ,
345- & Signature {
346- call_conv : module. target_config ( ) . default_call_conv ,
347- params : vec ! [ AbiParam :: new( pointer_type) , AbiParam :: new( pointer_type) ] ,
348- returns : vec ! [ AbiParam :: new( pointer_type) ] ,
349- } ,
350- )
351- . unwrap ( ) ;
352-
353- let context = cached_context;
354- context. clear ( ) ;
355- let trampoline = & mut context. func ;
356- trampoline. signature = sig. clone ( ) ;
357-
358- let mut builder_ctx = FunctionBuilderContext :: new ( ) ;
359- let mut trampoline_builder = FunctionBuilder :: new ( trampoline, & mut builder_ctx) ;
360-
361- let trampoline_fn = module. declare_func_in_func ( func_id, trampoline_builder. func ) ;
362- let jit_fn = module. declare_func_in_func ( jit_fn, trampoline_builder. func ) ;
363- let sig_ref = trampoline_builder. func . import_signature ( sig) ;
364-
365- let entry_block = trampoline_builder. create_block ( ) ;
366- trampoline_builder. append_block_params_for_function_params ( entry_block) ;
367- let fn_args = trampoline_builder. func . dfg . block_params ( entry_block) . to_vec ( ) ;
368-
369- trampoline_builder. switch_to_block ( entry_block) ;
370- let instance_ptr = trampoline_builder. ins ( ) . iconst ( pointer_type, instance_ptr as u64 as i64 ) ;
371- let trampoline_ptr = trampoline_builder. ins ( ) . func_addr ( pointer_type, trampoline_fn) ;
372- let jitted_fn = trampoline_builder. ins ( ) . call ( jit_fn, & [ instance_ptr, trampoline_ptr] ) ;
373- let jitted_fn = trampoline_builder. func . dfg . inst_results ( jitted_fn) [ 0 ] ;
374- let call_inst = trampoline_builder. ins ( ) . call_indirect ( sig_ref, jitted_fn, & fn_args) ;
375- let ret_vals = trampoline_builder. func . dfg . inst_results ( call_inst) . to_vec ( ) ;
376- trampoline_builder. ins ( ) . return_ ( & ret_vals) ;
377-
378- module. define_function ( func_id, context) . unwrap ( ) ;
379- }
0 commit comments