1
1
//! The JIT driver uses [`cranelift_simplejit`] to JIT execute programs without writing any object
2
2
//! files.
3
3
4
+ use std:: cell:: RefCell ;
4
5
use std:: ffi:: CString ;
5
6
use std:: os:: raw:: { c_char, c_int} ;
6
7
@@ -10,8 +11,13 @@ use rustc_middle::mir::mono::MonoItem;
10
11
use cranelift_jit:: { JITBuilder , JITModule } ;
11
12
12
13
use crate :: prelude:: * ;
14
+ use crate :: { CodegenCx , CodegenMode } ;
13
15
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 ) -> ! {
15
21
if !tcx. sess . opts . output_types . should_codegen ( ) {
16
22
tcx. sess . fatal ( "JIT mode doesn't work with `cargo check`." ) ;
17
23
}
@@ -40,6 +46,7 @@ pub(super) fn run_jit(tcx: TyCtxt<'_>) -> ! {
40
46
crate :: build_isa ( tcx. sess ) ,
41
47
cranelift_module:: default_libcall_names ( ) ,
42
48
) ;
49
+ jit_builder. hotswap ( matches ! ( codegen_mode, CodegenMode :: JitLazy ) ) ;
43
50
jit_builder. symbols ( imported_symbols) ;
44
51
let mut jit_module = JITModule :: new ( jit_builder) ;
45
52
assert_eq ! ( pointer_ty( tcx) , jit_module. target_config( ) . pointer_type( ) ) ;
@@ -74,13 +81,17 @@ pub(super) fn run_jit(tcx: TyCtxt<'_>) -> ! {
74
81
for ( mono_item, ( linkage, visibility) ) in mono_items {
75
82
let linkage = crate :: linkage:: get_clif_linkage ( mono_item, linkage, visibility) ;
76
83
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
+ } ,
82
93
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) ;
84
95
}
85
96
MonoItem :: GlobalAsm ( hir_id) => {
86
97
let item = cx. tcx . hir ( ) . expect_item ( hir_id) ;
@@ -126,11 +137,50 @@ pub(super) fn run_jit(tcx: TyCtxt<'_>) -> ! {
126
137
// useful as some dynamic linkers use it as a marker to jump over.
127
138
argv. push ( std:: ptr:: null ( ) ) ;
128
139
140
+ CURRENT_MODULE
141
+ . with ( |current_module| assert ! ( current_module. borrow_mut( ) . replace( jit_module) . is_none( ) ) ) ;
142
+
129
143
let ret = f ( args. len ( ) as c_int , argv. as_ptr ( ) ) ;
130
144
131
145
std:: process:: exit ( ret) ;
132
146
}
133
147
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
+
134
184
fn load_imported_symbols_for_jit ( tcx : TyCtxt < ' _ > ) -> Vec < ( String , * const u8 ) > {
135
185
use rustc_middle:: middle:: dependency_format:: Linkage ;
136
186
@@ -190,3 +240,68 @@ fn load_imported_symbols_for_jit(tcx: TyCtxt<'_>) -> Vec<(String, *const u8)> {
190
240
191
241
imported_symbols
192
242
}
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