1
1
use libc:: c_int;
2
2
use llvm_sys:: execution_engine:: { LLVMGetExecutionEngineTargetData , LLVMExecutionEngineRef , LLVMRunFunction , LLVMRunFunctionAsMain , LLVMDisposeExecutionEngine , LLVMGetFunctionAddress , LLVMAddModule , LLVMFindFunction , LLVMLinkInMCJIT , LLVMLinkInInterpreter , LLVMRemoveModule , LLVMGenericValueRef , LLVMFreeMachineCodeForFunction , LLVMAddGlobalMapping , LLVMRunStaticConstructors , LLVMRunStaticDestructors } ;
3
3
4
+ use context:: Context ;
4
5
use module:: Module ;
5
6
use support:: LLVMString ;
6
7
use targets:: TargetData ;
@@ -13,6 +14,8 @@ use std::ffi::CString;
13
14
use std:: fmt:: { self , Debug , Display , Formatter } ;
14
15
use std:: mem:: { forget, zeroed, transmute_copy, size_of} ;
15
16
17
+ static EE_INNER_PANIC : & str = "ExecutionEngineInner should exist until Drop" ;
18
+
16
19
#[ derive( Debug , PartialEq , Eq ) ]
17
20
pub enum FunctionLookupError {
18
21
JITNotEnabled ,
@@ -83,19 +86,28 @@ impl Display for RemoveModuleError {
83
86
84
87
/// A reference-counted wrapper around LLVM's execution engine.
85
88
///
89
+ /// # Note
90
+ ///
86
91
/// Cloning this object is essentially just a case of copying a couple pointers
87
92
/// and incrementing one or two atomics, so this should be quite cheap to create
88
93
/// copies. The underlying LLVM object will be automatically deallocated when
89
94
/// there are no more references to it.
95
+ // non_global_context is required to ensure last remaining Context ref will drop
96
+ // after EE drop. execution_engine & target_data are an option for drop purposes
90
97
#[ derive( PartialEq , Eq , Debug ) ]
91
98
pub struct ExecutionEngine {
92
- execution_engine : ExecEngineInner ,
99
+ non_global_context : Option < Context > ,
100
+ execution_engine : Option < ExecEngineInner > ,
93
101
target_data : Option < TargetData > ,
94
102
jit_mode : bool ,
95
103
}
96
104
97
105
impl ExecutionEngine {
98
- pub ( crate ) fn new ( execution_engine : Rc < LLVMExecutionEngineRef > , jit_mode : bool ) -> ExecutionEngine {
106
+ pub ( crate ) fn new (
107
+ execution_engine : Rc < LLVMExecutionEngineRef > ,
108
+ non_global_context : Option < Context > ,
109
+ jit_mode : bool ,
110
+ ) -> ExecutionEngine {
99
111
assert ! ( !execution_engine. is_null( ) ) ;
100
112
101
113
// REVIEW: Will we have to do this for LLVMGetExecutionEngineTargetMachine too?
@@ -104,12 +116,22 @@ impl ExecutionEngine {
104
116
} ;
105
117
106
118
ExecutionEngine {
107
- execution_engine : ExecEngineInner ( execution_engine) ,
119
+ non_global_context,
120
+ execution_engine : Some ( ExecEngineInner ( execution_engine) ) ,
108
121
target_data : Some ( TargetData :: new ( target_data) ) ,
109
122
jit_mode : jit_mode,
110
123
}
111
124
}
112
125
126
+ pub ( crate ) fn execution_engine_rc ( & self ) -> & Rc < LLVMExecutionEngineRef > {
127
+ & self . execution_engine . as_ref ( ) . expect ( EE_INNER_PANIC ) . 0
128
+ }
129
+
130
+ #[ inline]
131
+ pub ( crate ) fn execution_engine_inner ( & self ) -> LLVMExecutionEngineRef {
132
+ * * self . execution_engine_rc ( )
133
+ }
134
+
113
135
/// This function probably doesn't need to be called, but is here due to
114
136
/// linking(?) requirements. Bad things happen if we don't provide it.
115
137
pub fn link_in_mc_jit ( ) {
@@ -169,7 +191,7 @@ impl ExecutionEngine {
169
191
/// ```
170
192
pub fn add_global_mapping ( & self , value : & AnyValue , addr : usize ) {
171
193
unsafe {
172
- LLVMAddGlobalMapping ( * self . execution_engine , value. as_value_ref ( ) , addr as * mut _ )
194
+ LLVMAddGlobalMapping ( self . execution_engine_inner ( ) , value. as_value_ref ( ) , addr as * mut _ )
173
195
}
174
196
}
175
197
@@ -192,7 +214,7 @@ impl ExecutionEngine {
192
214
/// ```
193
215
pub fn add_module ( & self , module : & Module ) -> Result < ( ) , ( ) > {
194
216
unsafe {
195
- LLVMAddModule ( * self . execution_engine , module. module . get ( ) )
217
+ LLVMAddModule ( self . execution_engine_inner ( ) , module. module . get ( ) )
196
218
}
197
219
198
220
if module. owned_by_ee . borrow ( ) . is_some ( ) {
@@ -206,7 +228,8 @@ impl ExecutionEngine {
206
228
207
229
pub fn remove_module ( & self , module : & Module ) -> Result < ( ) , RemoveModuleError > {
208
230
match * module. owned_by_ee . borrow ( ) {
209
- Some ( ref ee) if * ee. execution_engine != * self . execution_engine => return Err ( RemoveModuleError :: IncorrectModuleOwner ) ,
231
+ Some ( ref ee) if ee. execution_engine_inner ( ) != self . execution_engine_inner ( ) =>
232
+ return Err ( RemoveModuleError :: IncorrectModuleOwner ) ,
210
233
None => return Err ( RemoveModuleError :: ModuleNotOwned ) ,
211
234
_ => ( )
212
235
}
@@ -215,7 +238,7 @@ impl ExecutionEngine {
215
238
let mut err_string = unsafe { zeroed ( ) } ;
216
239
217
240
let code = unsafe {
218
- LLVMRemoveModule ( * self . execution_engine , module. module . get ( ) , & mut new_module, & mut err_string)
241
+ LLVMRemoveModule ( self . execution_engine_inner ( ) , module. module . get ( ) , & mut new_module, & mut err_string)
219
242
} ;
220
243
221
244
if code == 1 {
@@ -300,7 +323,7 @@ impl ExecutionEngine {
300
323
301
324
let c_string = CString :: new ( fn_name) . expect ( "Conversion to CString failed unexpectedly" ) ;
302
325
303
- let address = LLVMGetFunctionAddress ( * self . execution_engine , c_string. as_ptr ( ) ) ;
326
+ let address = LLVMGetFunctionAddress ( self . execution_engine_inner ( ) , c_string. as_ptr ( ) ) ;
304
327
305
328
// REVIEW: Can also return 0 if no targets are initialized.
306
329
// One option might be to set a (thread local?) global to true if any at all of the targets have been
@@ -313,8 +336,10 @@ impl ExecutionEngine {
313
336
assert_eq ! ( size_of:: <F >( ) , size_of:: <usize >( ) ,
314
337
"The type `F` must have the same size as a function pointer" ) ;
315
338
339
+ let execution_engine = self . execution_engine . as_ref ( ) . expect ( EE_INNER_PANIC ) ;
340
+
316
341
Ok ( JitFunction {
317
- _execution_engine : self . execution_engine . clone ( ) ,
342
+ _execution_engine : execution_engine. clone ( ) ,
318
343
inner : transmute_copy ( & address) ,
319
344
} )
320
345
}
@@ -337,7 +362,7 @@ impl ExecutionEngine {
337
362
let mut function = unsafe { zeroed ( ) } ;
338
363
339
364
let code = unsafe {
340
- LLVMFindFunction ( * self . execution_engine , c_string. as_ptr ( ) , & mut function)
365
+ LLVMFindFunction ( self . execution_engine_inner ( ) , c_string. as_ptr ( ) , & mut function)
341
366
} ;
342
367
343
368
if code == 0 {
@@ -354,7 +379,7 @@ impl ExecutionEngine {
354
379
. map ( |val| val. generic_value )
355
380
. collect ( ) ;
356
381
357
- let value = LLVMRunFunction ( * self . execution_engine , function. as_value_ref ( ) , args. len ( ) as u32 , args. as_mut_ptr ( ) ) ; // REVIEW: usize to u32 ok??
382
+ let value = LLVMRunFunction ( self . execution_engine_inner ( ) , function. as_value_ref ( ) , args. len ( ) as u32 , args. as_mut_ptr ( ) ) ; // REVIEW: usize to u32 ok??
358
383
359
384
GenericValue :: new ( value)
360
385
}
@@ -368,26 +393,26 @@ impl ExecutionEngine {
368
393
369
394
let environment_variables = vec ! [ ] ; // TODO: Support envp. Likely needs to be null terminated
370
395
371
- LLVMRunFunctionAsMain ( * self . execution_engine , function. as_value_ref ( ) , raw_args. len ( ) as u32 , raw_args. as_ptr ( ) , environment_variables. as_ptr ( ) ) // REVIEW: usize to u32 cast ok??
396
+ LLVMRunFunctionAsMain ( self . execution_engine_inner ( ) , function. as_value_ref ( ) , raw_args. len ( ) as u32 , raw_args. as_ptr ( ) , environment_variables. as_ptr ( ) ) // REVIEW: usize to u32 cast ok??
372
397
}
373
398
374
399
pub fn free_fn_machine_code ( & self , function : & FunctionValue ) {
375
400
unsafe {
376
- LLVMFreeMachineCodeForFunction ( * self . execution_engine , function. as_value_ref ( ) )
401
+ LLVMFreeMachineCodeForFunction ( self . execution_engine_inner ( ) , function. as_value_ref ( ) )
377
402
}
378
403
}
379
404
380
405
// REVIEW: Is this actually safe?
381
406
pub fn run_static_constructors ( & self ) {
382
407
unsafe {
383
- LLVMRunStaticConstructors ( * self . execution_engine )
408
+ LLVMRunStaticConstructors ( self . execution_engine_inner ( ) )
384
409
}
385
410
}
386
411
387
412
// REVIEW: Is this actually safe? Can you double destruct/free?
388
413
pub fn run_static_destructors ( & self ) {
389
414
unsafe {
390
- LLVMRunStaticDestructors ( * self . execution_engine )
415
+ LLVMRunStaticDestructors ( self . execution_engine_inner ( ) )
391
416
}
392
417
}
393
418
}
@@ -401,12 +426,20 @@ impl Drop for ExecutionEngine {
401
426
. take ( )
402
427
. expect ( "TargetData should always exist until Drop" ) ,
403
428
) ;
429
+
430
+ // We must ensure the EE gets dropped before its context does,
431
+ // which is important in the case where the EE has the last
432
+ // remaining reference to it context
433
+ drop ( self . execution_engine . take ( ) . expect ( EE_INNER_PANIC ) ) ;
404
434
}
405
435
}
406
436
407
437
impl Clone for ExecutionEngine {
408
438
fn clone ( & self ) -> ExecutionEngine {
409
- ExecutionEngine :: new ( self . execution_engine . 0 . clone ( ) , self . jit_mode )
439
+ let context = self . non_global_context . clone ( ) ;
440
+ let execution_engine_rc = self . execution_engine_rc ( ) . clone ( ) ;
441
+
442
+ ExecutionEngine :: new ( execution_engine_rc, context, self . jit_mode )
410
443
}
411
444
}
412
445
0 commit comments