@@ -82,8 +82,111 @@ pub fn WriteOutputFile(
82
82
}
83
83
}
84
84
85
+ pub mod jit {
86
+
87
+ use back:: link:: llvm_err;
88
+ use driver:: session:: Session ;
89
+ use lib:: llvm:: llvm;
90
+ use lib:: llvm:: { ModuleRef , ContextRef , ExecutionEngineRef } ;
91
+
92
+ use std:: c_str:: ToCStr ;
93
+ use std:: cast;
94
+ use std:: local_data;
95
+ use std:: unstable:: intrinsics;
96
+
97
+ struct LLVMJITData {
98
+ ee : ExecutionEngineRef ,
99
+ llcx : ContextRef
100
+ }
101
+
102
+ pub trait Engine { }
103
+ impl Engine for LLVMJITData { }
104
+
105
+ impl Drop for LLVMJITData {
106
+ fn drop ( & mut self ) {
107
+ unsafe {
108
+ llvm:: LLVMDisposeExecutionEngine ( self . ee ) ;
109
+ llvm:: LLVMContextDispose ( self . llcx ) ;
110
+ }
111
+ }
112
+ }
113
+
114
+ pub fn exec ( sess : Session ,
115
+ c : ContextRef ,
116
+ m : ModuleRef ,
117
+ stacks : bool ) {
118
+ unsafe {
119
+ let manager = llvm:: LLVMRustPrepareJIT ( intrinsics:: morestack_addr ( ) ) ;
120
+
121
+ // We need to tell JIT where to resolve all linked
122
+ // symbols from. The equivalent of -lstd, -lcore, etc.
123
+ // By default the JIT will resolve symbols from the extra and
124
+ // core linked into rustc. We don't want that,
125
+ // incase the user wants to use an older extra library.
126
+
127
+ // We custom-build a JIT execution engine via some rust wrappers
128
+ // first. This wrappers takes ownership of the module passed in.
129
+ let ee = llvm:: LLVMRustBuildJIT ( manager, m, stacks) ;
130
+ if ee. is_null ( ) {
131
+ llvm:: LLVMContextDispose ( c) ;
132
+ llvm_err ( sess, ~"Could not create the JIT ") ;
133
+ }
134
+
135
+ // Next, we need to get a handle on the _rust_main function by
136
+ // looking up it's corresponding ValueRef and then requesting that
137
+ // the execution engine compiles the function.
138
+ let fun = "_rust_main" . with_c_str ( |entry| {
139
+ llvm:: LLVMGetNamedFunction ( m, entry)
140
+ } ) ;
141
+ if fun. is_null ( ) {
142
+ llvm:: LLVMDisposeExecutionEngine ( ee) ;
143
+ llvm:: LLVMContextDispose ( c) ;
144
+ llvm_err ( sess, ~"Could not find _rust_main in the JIT ") ;
145
+ }
146
+
147
+ // Finally, once we have the pointer to the code, we can do some
148
+ // closure magic here to turn it straight into a callable rust
149
+ // closure
150
+ let code = llvm:: LLVMGetPointerToGlobal ( ee, fun) ;
151
+ assert ! ( !code. is_null( ) ) ;
152
+ let func: extern "Rust" fn ( ) = cast:: transmute ( code) ;
153
+ func ( ) ;
154
+
155
+ // Currently there is no method of re-using the executing engine
156
+ // from LLVM in another call to the JIT. While this kinda defeats
157
+ // the purpose of having a JIT in the first place, there isn't
158
+ // actually much code currently which would re-use data between
159
+ // different invocations of this. Additionally, the compilation
160
+ // model currently isn't designed to support this scenario.
161
+ //
162
+ // We can't destroy the engine/context immediately here, however,
163
+ // because of annihilation. The JIT code contains drop glue for any
164
+ // types defined in the crate we just ran, and if any of those boxes
165
+ // are going to be dropped during annihilation, the drop glue must
166
+ // be run. Hence, we need to transfer ownership of this jit engine
167
+ // to the caller of this function. To be convenient for now, we
168
+ // shove it into TLS and have someone else remove it later on.
169
+ let data = ~LLVMJITData { ee : ee, llcx : c } ;
170
+ set_engine ( data as ~Engine ) ;
171
+ }
172
+ }
173
+
174
+ // The stage1 compiler won't work, but that doesn't really matter. TLS
175
+ // changed only very recently to allow storage of owned values.
176
+ local_data_key ! ( engine_key: ~Engine )
177
+
178
+ fn set_engine ( engine : ~Engine ) {
179
+ local_data:: set ( engine_key, engine)
180
+ }
181
+
182
+ pub fn consume_engine ( ) -> Option < ~Engine > {
183
+ local_data:: pop ( engine_key)
184
+ }
185
+ }
186
+
85
187
pub mod write {
86
188
189
+ use back:: link:: jit;
87
190
use back:: link:: { WriteOutputFile , output_type} ;
88
191
use back:: link:: { output_type_assembly, output_type_bitcode} ;
89
192
use back:: link:: { output_type_exe, output_type_llvm_assembly} ;
@@ -204,38 +307,48 @@ pub mod write {
204
307
} )
205
308
}
206
309
207
- // Create a codegen-specific pass manager to emit the actual
208
- // assembly or object files. This may not end up getting used,
209
- // but we make it anyway for good measure.
210
- let cpm = llvm:: LLVMCreatePassManager ( ) ;
211
- llvm:: LLVMRustAddAnalysisPasses ( tm, cpm, llmod) ;
212
- llvm:: LLVMRustAddLibraryInfo ( cpm, llmod) ;
213
-
214
- match output_type {
215
- output_type_none => { }
216
- output_type_bitcode => {
217
- output. with_c_str ( |buf| {
218
- llvm:: LLVMWriteBitcodeToFile ( llmod, buf) ;
219
- } )
220
- }
221
- output_type_llvm_assembly => {
222
- output. with_c_str ( |output| {
223
- llvm:: LLVMRustPrintModule ( cpm, llmod, output)
224
- } )
225
- }
226
- output_type_assembly => {
227
- WriteOutputFile ( sess, tm, cpm, llmod, output, lib:: llvm:: AssemblyFile ) ;
228
- }
229
- output_type_exe | output_type_object => {
230
- WriteOutputFile ( sess, tm, cpm, llmod, output, lib:: llvm:: ObjectFile ) ;
310
+ if sess. opts . jit {
311
+ // If we are using JIT, go ahead and create and execute the
312
+ // engine now. JIT execution takes ownership of the module and
313
+ // context, so don't dispose
314
+ jit:: exec ( sess, llcx, llmod, true ) ;
315
+ } else {
316
+ // Create a codegen-specific pass manager to emit the actual
317
+ // assembly or object files. This may not end up getting used,
318
+ // but we make it anyway for good measure.
319
+ let cpm = llvm:: LLVMCreatePassManager ( ) ;
320
+ llvm:: LLVMRustAddAnalysisPasses ( tm, cpm, llmod) ;
321
+ llvm:: LLVMRustAddLibraryInfo ( cpm, llmod) ;
322
+
323
+ match output_type {
324
+ output_type_none => { }
325
+ output_type_bitcode => {
326
+ output. with_c_str ( |buf| {
327
+ llvm:: LLVMWriteBitcodeToFile ( llmod, buf) ;
328
+ } )
329
+ }
330
+ output_type_llvm_assembly => {
331
+ output. with_c_str ( |output| {
332
+ llvm:: LLVMRustPrintModule ( cpm, llmod, output)
333
+ } )
334
+ }
335
+ output_type_assembly => {
336
+ WriteOutputFile ( sess, tm, cpm, llmod, output, lib:: llvm:: AssemblyFile ) ;
337
+ }
338
+ output_type_exe | output_type_object => {
339
+ WriteOutputFile ( sess, tm, cpm, llmod, output, lib:: llvm:: ObjectFile ) ;
340
+ }
231
341
}
232
- }
233
342
234
- llvm:: LLVMDisposePassManager ( cpm) ;
343
+ llvm:: LLVMDisposePassManager ( cpm) ;
344
+ }
235
345
236
346
llvm:: LLVMRustDisposeTargetMachine ( tm) ;
237
- llvm:: LLVMDisposeModule ( llmod) ;
238
- llvm:: LLVMContextDispose ( llcx) ;
347
+ // the jit takes ownership of these two items
348
+ if !sess. opts . jit {
349
+ llvm:: LLVMDisposeModule ( llmod) ;
350
+ llvm:: LLVMContextDispose ( llcx) ;
351
+ }
239
352
if sess. time_llvm_passes ( ) { llvm:: LLVMRustPrintPassTimings ( ) ; }
240
353
}
241
354
}
@@ -598,8 +711,8 @@ pub fn sanitize(s: &str) -> ~str {
598
711
',' => result. push_str ( "$C$" ) ,
599
712
600
713
// '.' doesn't occur in types and functions, so reuse it
601
- // for ':' and '-'
602
- '-' | ' :' => result. push_char ( '.' ) ,
714
+ // for ':'
715
+ ':' => result. push_char ( '.' ) ,
603
716
604
717
// These are legal symbols
605
718
'a' .. 'z'
0 commit comments