36
36
* - Pass #3
37
37
* Finally, a program is generated to deserialize the local variable state,
38
38
* run the code input, and then reserialize all bindings back into a local
39
- * hash map. Once this code runs, the input has fully been run and the REPL
40
- * waits for new input.
39
+ * hash map. This code is then run in the JIT engine provided by the rust
40
+ * compiler.
41
+ *
42
+ * - Pass #4
43
+ * Once this code runs, the input has fully been run and the hash map of local
44
+ * variables from TLS is read back into the local store of variables. This is
45
+ * then used later to pass back along to the parent rusti task and then begin
46
+ * waiting for input again.
47
+ *
48
+ * - Pass #5
49
+ * When running rusti code, it's important to consume ownership of the LLVM
50
+ * jit contextual information to prevent code from being deallocated too soon
51
+ * (before drop glue runs, see #7732). For this reason, the jit context is
52
+ * consumed and also passed along to the parent task. The parent task then
53
+ * keeps around all contexts while rusti is running. This must be done because
54
+ * tasks could in theory be spawned off and running in the background (still
55
+ * using the code).
41
56
*
42
57
* Encoding/decoding is done with EBML, and there is simply a map of ~str ->
43
58
* ~[u8] maintaining the values of each local binding (by name).
@@ -60,6 +75,7 @@ use std::cell::Cell;
60
75
use extra:: rl;
61
76
62
77
use rustc:: driver:: { driver, session} ;
78
+ use rustc:: back:: link:: jit;
63
79
use syntax:: { ast, diagnostic} ;
64
80
use syntax:: ast_util:: * ;
65
81
use syntax:: parse:: token;
@@ -80,8 +96,9 @@ pub struct Repl {
80
96
binary : ~str ,
81
97
running : bool ,
82
98
lib_search_paths : ~[ ~str ] ,
99
+ engines : ~[ ~jit:: Engine ] ,
83
100
84
- program : Program ,
101
+ program : ~ Program ,
85
102
}
86
103
87
104
// Action to do after reading a :command
@@ -91,13 +108,15 @@ enum CmdAction {
91
108
}
92
109
93
110
/// Run an input string in a Repl, returning the new Repl.
94
- fn run( mut repl : Repl , input : ~str ) -> Repl {
111
+ fn run( mut program : ~Program , binary : ~str , lib_search_paths : ~[ ~str ] ,
112
+ input : ~str ) -> ( ~Program , Option < ~jit:: Engine > )
113
+ {
95
114
// Build some necessary rustc boilerplate for compiling things
96
- let binary = repl . binary . to_managed ( ) ;
115
+ let binary = binary. to_managed ( ) ;
97
116
let options = @session:: options {
98
117
crate_type : session:: unknown_crate,
99
118
binary : binary,
100
- addl_lib_search_paths : @mut repl . lib_search_paths . map ( |p| Path ( * p) ) ,
119
+ addl_lib_search_paths : @mut lib_search_paths. map ( |p| Path ( * p) ) ,
101
120
jit : true ,
102
121
.. copy * session:: basic_options ( )
103
122
} ;
@@ -136,9 +155,9 @@ fn run(mut repl: Repl, input: ~str) -> Repl {
136
155
} ;
137
156
match vi. node {
138
157
ast : : view_item_extern_mod( * ) => {
139
- repl . program. record_extern( s) ;
158
+ program. record_extern( s) ;
140
159
}
141
- ast:: view_item_use( * ) => { repl . program. record_view_item( s) ; }
160
+ ast:: view_item_use( * ) => { program. record_view_item( s) ; }
142
161
}
143
162
}
144
163
@@ -156,10 +175,10 @@ fn run(mut repl: Repl, input: ~str) -> Repl {
156
175
// them at all usable they need to be decorated
157
176
// with #[deriving(Encoable, Decodable)]
158
177
ast : : item_struct( * ) => {
159
- repl . program. record_struct( name, s) ;
178
+ program. record_struct( name, s) ;
160
179
}
161
180
// Item declarations are hoisted out of main()
162
- _ => { repl . program. record_item( name, s) ; }
181
+ _ => { program. record_item( name, s) ; }
163
182
}
164
183
}
165
184
@@ -190,17 +209,17 @@ fn run(mut repl: Repl, input: ~str) -> Repl {
190
209
}
191
210
// return fast for empty inputs
192
211
if to_run. len( ) == 0 && result. is_none( ) {
193
- return repl ;
212
+ return ( program , None ) ;
194
213
}
195
214
196
215
//
197
216
// Stage 2: run everything up to typeck to learn the types of the new
198
217
// variables introduced into the program
199
218
//
200
219
info ! ( "Learning about the new types in the program" ) ;
201
- repl . program. set_cache( ) ; // before register_new_vars (which changes them)
220
+ program. set_cache( ) ; // before register_new_vars (which changes them)
202
221
let input = to_run. connect( "\n " ) ;
203
- let test = repl . program. test_code( input, & result, * new_locals) ;
222
+ let test = program. test_code( input, & result, * new_locals) ;
204
223
debug ! ( "testing with ^^^^^^ %?" , ( ||{ println( test) } ) ( ) ) ;
205
224
let dinput = driver:: str_input( test. to_managed( ) ) ;
206
225
let cfg = driver:: build_configuration( sess, binary, & dinput) ;
@@ -210,14 +229,14 @@ fn run(mut repl: Repl, input: ~str) -> Repl {
210
229
// Once we're typechecked, record the types of all local variables defined
211
230
// in this input
212
231
do find_main( crate . expect( "crate after cu_typeck" ) , sess) |blk| {
213
- repl . program. register_new_vars( blk, tcx. expect( "tcx after cu_typeck" ) ) ;
232
+ program. register_new_vars( blk, tcx. expect( "tcx after cu_typeck" ) ) ;
214
233
}
215
234
216
235
//
217
236
// Stage 3: Actually run the code in the JIT
218
237
//
219
238
info ! ( "actually running code" ) ;
220
- let code = repl . program. code( input, & result) ;
239
+ let code = program. code( input, & result) ;
221
240
debug ! ( "actually running ^^^^^^ %?" , ( ||{ println( code) } ) ( ) ) ;
222
241
let input = driver:: str_input( code. to_managed( ) ) ;
223
242
let cfg = driver:: build_configuration( sess, binary, & input) ;
@@ -231,9 +250,15 @@ fn run(mut repl: Repl, input: ~str) -> Repl {
231
250
// local variable bindings.
232
251
//
233
252
info ! ( "cleaning up after code" ) ;
234
- repl . program. consume_cache( ) ;
253
+ program. consume_cache( ) ;
235
254
236
- return repl;
255
+ //
256
+ // Stage 5: Extract the LLVM execution engine to take ownership of the
257
+ // generated JIT code. This means that rusti can spawn parallel
258
+ // tasks and we won't deallocate the code emitted until rusti
259
+ // itself is destroyed.
260
+ //
261
+ return ( program, jit:: consume_engine( ) ) ;
237
262
238
263
fn parse_input( sess: session:: Session , binary: @str ,
239
264
input: & str) -> @ast:: crate {
@@ -418,8 +443,8 @@ fn run_cmd(repl: &mut Repl, _in: @io::Reader, _out: @io::Writer,
418
443
/// Executes a line of input, which may either be rust code or a
419
444
/// :command. Returns a new Repl if it has changed.
420
445
pub fn run_line(repl: &mut Repl, in: @io::Reader, out: @io::Writer, line: ~str,
421
- use_rl: bool)
422
- -> Option<Repl> {
446
+ use_rl: bool) -> bool
447
+ {
423
448
if line.starts_with(" : ") {
424
449
// drop the : and the \n (one byte each)
425
450
let full = line. slice( 1 , line. len( ) ) ;
@@ -442,21 +467,30 @@ pub fn run_line(repl: &mut Repl, in: @io::Reader, out: @io::Writer, line: ~str,
442
467
}
443
468
}
444
469
}
445
- return None ;
470
+ return true ;
446
471
}
447
472
}
448
473
}
449
474
450
475
let line = Cell :: new( line) ;
451
- let r = Cell :: new( copy * repl) ;
476
+ let program = Cell :: new( copy repl. program) ;
477
+ let lib_search_paths = Cell :: new( copy repl. lib_search_paths) ;
478
+ let binary = Cell :: new( copy repl. binary) ;
452
479
let result = do task:: try {
453
- run( r . take( ) , line. take( ) )
480
+ run( program . take ( ) , binary . take ( ) , lib_search_paths . take( ) , line. take( ) )
454
481
} ;
455
482
456
- if result. is_ok( ) {
457
- return Some ( result. get( ) ) ;
483
+ match result {
484
+ Ok ( ( program, engine) ) => {
485
+ repl. program = program;
486
+ match engine {
487
+ Some ( e) => { repl. engines. push( e) ; }
488
+ None => { }
489
+ }
490
+ return true ;
491
+ }
492
+ Err ( * ) => { return false ; }
458
493
}
459
- return None ;
460
494
}
461
495
462
496
pub fn main ( ) {
@@ -468,8 +502,9 @@ pub fn main() {
468
502
binary: copy args[0],
469
503
running: true,
470
504
lib_search_paths: ~[],
505
+ engines: ~[],
471
506
472
- program: Program::new(),
507
+ program: ~ Program::new(),
473
508
};
474
509
475
510
let istty = unsafe { libc::isatty(libc::STDIN_FILENO as i32) } != 0;
@@ -502,10 +537,7 @@ pub fn main() {
502
537
}
503
538
loop ;
504
539
}
505
- match run_line( & mut repl, in, out, line, istty) {
506
- Some ( new_repl) => repl = new_repl,
507
- None => { }
508
- }
540
+ run_line( & mut repl, in, out, line, istty) ;
509
541
}
510
542
}
511
543
}
@@ -524,7 +556,8 @@ mod tests {
524
556
binary: ~" rusti",
525
557
running : true ,
526
558
lib_search_paths : ~[ ] ,
527
- program : Program :: new( ) ,
559
+ engines : ~[ ] ,
560
+ program : ~Program :: new( ) ,
528
561
}
529
562
}
530
563
@@ -535,9 +568,9 @@ mod tests {
535
568
fn run_program( prog: & str) {
536
569
let mut r = repl( ) ;
537
570
for prog. split_iter( '\n' ) . advance |cmd| {
538
- let result = run_line( & mut r, io:: stdin( ) , io:: stdout( ) ,
539
- cmd. to_owned( ) , false ) ;
540
- r = result . expect ( fmt ! ( "the command '%s' failed" , cmd) ) ;
571
+ assert ! ( run_line( & mut r, io:: stdin( ) , io:: stdout( ) ,
572
+ cmd. to_owned( ) , false ) ,
573
+ "the command '%s' failed" , cmd) ;
541
574
}
542
575
}
543
576
fn run_program( _: & str) { }
@@ -682,7 +715,7 @@ mod tests {
682
715
assert ! ( r. running) ;
683
716
let result = run_line( & mut r, io:: stdin( ) , io:: stdout( ) ,
684
717
~": exit", false ) ;
685
- assert ! ( result. is_none ( ) ) ;
718
+ assert ! ( result) ;
686
719
assert ! ( !r. running) ;
687
720
}
688
721
}
0 commit comments