Skip to content

Commit 4a7068d

Browse files
committed
Ensure Instances are only jitted once
1 parent 2945b96 commit 4a7068d

File tree

1 file changed

+21
-7
lines changed

1 file changed

+21
-7
lines changed

src/driver/jit.rs

Lines changed: 21 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ enum UnsafeMessage {
3737
/// this message is sent.
3838
JitFn {
3939
instance_ptr: *const Instance<'static>,
40+
trampoline_ptr: *const u8,
4041
tx: mpsc::Sender<*const u8>,
4142
},
4243
}
@@ -192,19 +193,19 @@ pub(crate) fn run_jit(tcx: TyCtxt<'_>, backend_config: BackendConfig) -> ! {
192193
loop {
193194
match rx.recv().unwrap() {
194195
// lazy JIT compilation request - compile requested instance and return pointer to result
195-
UnsafeMessage::JitFn { instance_ptr, tx } => {
196-
tx.send(jit_fn(instance_ptr))
196+
UnsafeMessage::JitFn { instance_ptr, trampoline_ptr, tx } => {
197+
tx.send(jit_fn(instance_ptr, trampoline_ptr))
197198
.expect("jitted runtime hung up before response to lazy JIT request was sent");
198199
}
199200
}
200201
}
201202
}
202203

203204
#[no_mangle]
204-
extern "C" fn __clif_jit_fn(instance_ptr: *const Instance<'static>) -> *const u8 {
205+
extern "C" fn __clif_jit_fn(instance_ptr: *const Instance<'static>, trampoline_ptr: *const u8) -> *const u8 {
205206
// send the JIT request to the rustc thread, with a channel for the response
206207
let (tx, rx) = mpsc::channel();
207-
UnsafeMessage::JitFn { instance_ptr, tx }
208+
UnsafeMessage::JitFn { instance_ptr, trampoline_ptr, tx }
208209
.send()
209210
.expect("rustc thread hung up before lazy JIT request was sent");
210211

@@ -213,7 +214,7 @@ extern "C" fn __clif_jit_fn(instance_ptr: *const Instance<'static>) -> *const u8
213214
.expect("rustc thread hung up before responding to sent lazy JIT request")
214215
}
215216

216-
fn jit_fn(instance_ptr: *const Instance<'static>) -> *const u8 {
217+
fn jit_fn(instance_ptr: *const Instance<'static>, trampoline_ptr: *const u8) -> *const u8 {
217218
rustc_middle::ty::tls::with(|tcx| {
218219
// lift is used to ensure the correct lifetime for instance.
219220
let instance = tcx.lift(unsafe { *instance_ptr }).unwrap();
@@ -227,6 +228,17 @@ fn jit_fn(instance_ptr: *const Instance<'static>) -> *const u8 {
227228
let name = tcx.symbol_name(instance).name;
228229
let sig = crate::abi::get_function_sig(tcx, jit_module.isa().triple(), instance);
229230
let func_id = jit_module.declare_function(name, Linkage::Export, &sig).unwrap();
231+
232+
let current_ptr = jit_module.read_got_entry(func_id);
233+
234+
// If the function's GOT entry has already been updated to point at something other
235+
// than the shim trampoline, don't re-jit but just return the new pointer instead.
236+
// This does not need synchronization as this code is executed only by a sole rustc
237+
// thread.
238+
if current_ptr != trampoline_ptr {
239+
return current_ptr;
240+
}
241+
230242
jit_module.prepare_for_function_redefine(func_id).unwrap();
231243

232244
let mut cx = crate::CodegenCx::new(tcx, backend_config, jit_module.isa(), false);
@@ -321,7 +333,7 @@ fn codegen_shim<'tcx>(cx: &mut CodegenCx<'tcx>, module: &mut JITModule, inst: In
321333
Linkage::Import,
322334
&Signature {
323335
call_conv: module.target_config().default_call_conv,
324-
params: vec![AbiParam::new(pointer_type)],
336+
params: vec![AbiParam::new(pointer_type), AbiParam::new(pointer_type)],
325337
returns: vec![AbiParam::new(pointer_type)],
326338
},
327339
)
@@ -334,6 +346,7 @@ fn codegen_shim<'tcx>(cx: &mut CodegenCx<'tcx>, module: &mut JITModule, inst: In
334346
let mut builder_ctx = FunctionBuilderContext::new();
335347
let mut trampoline_builder = FunctionBuilder::new(trampoline, &mut builder_ctx);
336348

349+
let trampoline_fn = module.declare_func_in_func(func_id, trampoline_builder.func);
337350
let jit_fn = module.declare_func_in_func(jit_fn, trampoline_builder.func);
338351
let sig_ref = trampoline_builder.func.import_signature(sig);
339352

@@ -343,7 +356,8 @@ fn codegen_shim<'tcx>(cx: &mut CodegenCx<'tcx>, module: &mut JITModule, inst: In
343356

344357
trampoline_builder.switch_to_block(entry_block);
345358
let instance_ptr = trampoline_builder.ins().iconst(pointer_type, instance_ptr as u64 as i64);
346-
let jitted_fn = trampoline_builder.ins().call(jit_fn, &[instance_ptr]);
359+
let trampoline_ptr = trampoline_builder.ins().func_addr(pointer_type, trampoline_fn);
360+
let jitted_fn = trampoline_builder.ins().call(jit_fn, &[instance_ptr, trampoline_ptr]);
347361
let jitted_fn = trampoline_builder.func.dfg.inst_results(jitted_fn)[0];
348362
let call_inst = trampoline_builder.ins().call_indirect(sig_ref, jitted_fn, &fn_args);
349363
let ret_vals = trampoline_builder.func.dfg.inst_results(call_inst).to_vec();

0 commit comments

Comments
 (0)