1
1
//! The JIT driver uses [`cranelift_jit`] to JIT execute programs without writing any object
2
2
//! files.
3
3
4
- use std:: cell:: RefCell ;
5
4
use std:: ffi:: CString ;
6
5
use std:: os:: raw:: { c_char, c_int} ;
7
- use std:: sync:: { Mutex , OnceLock , mpsc} ;
8
6
9
- use cranelift_frontend:: { FunctionBuilder , FunctionBuilderContext } ;
10
7
use cranelift_jit:: { JITBuilder , JITModule } ;
11
8
use rustc_codegen_ssa:: CrateInfo ;
12
9
use rustc_middle:: mir:: mono:: MonoItem ;
@@ -18,58 +15,13 @@ use crate::debuginfo::TypeDebugContext;
18
15
use crate :: prelude:: * ;
19
16
use crate :: unwind_module:: UnwindModule ;
20
17
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 ) {
65
19
let crate_info = CrateInfo :: new ( tcx, "dummy_target_cpu" . to_string ( ) ) ;
66
20
67
21
let isa = crate :: build_isa ( tcx. sess ) ;
68
22
let mut jit_builder = JITBuilder :: with_isa ( isa, cranelift_module:: default_libcall_names ( ) ) ;
69
- jit_builder. hotswap ( hotswap) ;
70
23
crate :: compiler_builtins:: register_functions_for_jit ( & mut jit_builder) ;
71
24
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 ) ;
73
25
let mut jit_module = UnwindModule :: new ( JITModule :: new ( jit_builder) , false ) ;
74
26
75
27
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>
79
31
( jit_module, cx)
80
32
}
81
33
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 > ) -> ! {
83
35
if !tcx. sess . opts . output_types . should_codegen ( ) {
84
36
tcx. dcx ( ) . fatal ( "JIT mode doesn't work with `cargo check`" ) ;
85
37
}
@@ -88,7 +40,7 @@ pub(crate) fn run_jit(tcx: TyCtxt<'_>, jit_lazy: bool, jit_args: Vec<String>) ->
88
40
tcx. dcx ( ) . fatal ( "can't jit non-executable crate" ) ;
89
41
}
90
42
91
- let ( mut jit_module, mut cx) = create_jit_module ( tcx, jit_lazy ) ;
43
+ let ( mut jit_module, mut cx) = create_jit_module ( tcx) ;
92
44
let mut cached_context = Context :: new ( ) ;
93
45
94
46
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>) ->
105
57
for ( mono_item, _) in mono_items {
106
58
match mono_item {
107
59
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
+ ) ;
119
67
}
120
68
MonoItem :: Static ( def_id) => {
121
69
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>) ->
158
106
let start_func_id = jit_module. declare_function ( "main" , Linkage :: Import , & start_sig) . unwrap ( ) ;
159
107
let finalized_start: * const u8 = jit_module. module . get_finalized_function ( start_func_id) ;
160
108
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
-
167
109
let f: extern "C" fn ( c_int , * const * const c_char ) -> c_int =
168
110
unsafe { :: std:: mem:: transmute ( finalized_start) } ;
169
111
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 < _ > > ( ) ;
177
113
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 ( ) ) ;
181
117
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) ;
196
120
}
197
121
198
122
pub ( crate ) fn codegen_and_compile_fn < ' tcx > (
@@ -224,58 +148,6 @@ pub(crate) fn codegen_and_compile_fn<'tcx>(
224
148
} ) ;
225
149
}
226
150
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
-
279
151
fn dep_symbol_lookup_fn (
280
152
sess : & Session ,
281
153
crate_info : CrateInfo ,
@@ -323,57 +195,3 @@ fn dep_symbol_lookup_fn(
323
195
None
324
196
} )
325
197
}
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