3636 * - Pass #3
3737 * Finally, a program is generated to deserialize the local variable state,
3838 * 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).
4156 *
4257 * Encoding/decoding is done with EBML, and there is simply a map of ~str ->
4358 * ~[u8] maintaining the values of each local binding (by name).
@@ -60,6 +75,7 @@ use std::cell::Cell;
6075use extra:: rl;
6176
6277use rustc:: driver:: { driver, session} ;
78+ use rustc:: back:: link:: jit;
6379use syntax:: { ast, diagnostic} ;
6480use syntax:: ast_util:: * ;
6581use syntax:: parse:: token;
@@ -80,8 +96,9 @@ pub struct Repl {
8096 binary : ~str ,
8197 running : bool ,
8298 lib_search_paths : ~[ ~str ] ,
99+ engines : ~[ ~jit:: Engine ] ,
83100
84- program : Program ,
101+ program : ~ Program ,
85102}
86103
87104// Action to do after reading a :command
@@ -91,13 +108,15 @@ enum CmdAction {
91108}
92109
93110/// 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+ {
95114 // Build some necessary rustc boilerplate for compiling things
96- let binary = repl . binary . to_managed ( ) ;
115+ let binary = binary. to_managed ( ) ;
97116 let options = @session:: options {
98117 crate_type : session:: unknown_crate,
99118 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) ) ,
101120 jit : true ,
102121 .. copy * session:: basic_options ( )
103122 } ;
@@ -136,9 +155,9 @@ fn run(mut repl: Repl, input: ~str) -> Repl {
136155 } ;
137156 match vi. node {
138157 ast : : view_item_extern_mod( * ) => {
139- repl . program. record_extern( s) ;
158+ program. record_extern( s) ;
140159 }
141- ast:: view_item_use( * ) => { repl . program. record_view_item( s) ; }
160+ ast:: view_item_use( * ) => { program. record_view_item( s) ; }
142161 }
143162 }
144163
@@ -156,10 +175,10 @@ fn run(mut repl: Repl, input: ~str) -> Repl {
156175 // them at all usable they need to be decorated
157176 // with #[deriving(Encoable, Decodable)]
158177 ast : : item_struct( * ) => {
159- repl . program. record_struct( name, s) ;
178+ program. record_struct( name, s) ;
160179 }
161180 // Item declarations are hoisted out of main()
162- _ => { repl . program. record_item( name, s) ; }
181+ _ => { program. record_item( name, s) ; }
163182 }
164183 }
165184
@@ -190,17 +209,17 @@ fn run(mut repl: Repl, input: ~str) -> Repl {
190209 }
191210 // return fast for empty inputs
192211 if to_run. len( ) == 0 && result. is_none( ) {
193- return repl ;
212+ return ( program , None ) ;
194213 }
195214
196215 //
197216 // Stage 2: run everything up to typeck to learn the types of the new
198217 // variables introduced into the program
199218 //
200219 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)
202221 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) ;
204223 debug ! ( "testing with ^^^^^^ %?" , ( ||{ println( test) } ) ( ) ) ;
205224 let dinput = driver:: str_input( test. to_managed( ) ) ;
206225 let cfg = driver:: build_configuration( sess, binary, & dinput) ;
@@ -210,14 +229,14 @@ fn run(mut repl: Repl, input: ~str) -> Repl {
210229 // Once we're typechecked, record the types of all local variables defined
211230 // in this input
212231 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" ) ) ;
214233 }
215234
216235 //
217236 // Stage 3: Actually run the code in the JIT
218237 //
219238 info ! ( "actually running code" ) ;
220- let code = repl . program. code( input, & result) ;
239+ let code = program. code( input, & result) ;
221240 debug ! ( "actually running ^^^^^^ %?" , ( ||{ println( code) } ) ( ) ) ;
222241 let input = driver:: str_input( code. to_managed( ) ) ;
223242 let cfg = driver:: build_configuration( sess, binary, & input) ;
@@ -231,9 +250,15 @@ fn run(mut repl: Repl, input: ~str) -> Repl {
231250 // local variable bindings.
232251 //
233252 info ! ( "cleaning up after code" ) ;
234- repl . program. consume_cache( ) ;
253+ program. consume_cache( ) ;
235254
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( ) ) ;
237262
238263 fn parse_input( sess: session:: Session , binary: @str ,
239264 input: & str) -> @ast:: crate {
@@ -418,8 +443,8 @@ fn run_cmd(repl: &mut Repl, _in: @io::Reader, _out: @io::Writer,
418443/// Executes a line of input, which may either be rust code or a
419444/// :command. Returns a new Repl if it has changed.
420445pub 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+ {
423448 if line.starts_with(" : ") {
424449 // drop the : and the \n (one byte each)
425450 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,
442467 }
443468 }
444469 }
445- return None ;
470+ return true ;
446471 }
447472 }
448473 }
449474
450475 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) ;
452479 let result = do task:: try {
453- run( r . take( ) , line. take( ) )
480+ run( program . take ( ) , binary . take ( ) , lib_search_paths . take( ) , line. take( ) )
454481 } ;
455482
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 ; }
458493 }
459- return None ;
460494}
461495
462496pub fn main ( ) {
@@ -468,8 +502,9 @@ pub fn main() {
468502 binary: copy args[0],
469503 running: true,
470504 lib_search_paths: ~[],
505+ engines: ~[],
471506
472- program: Program::new(),
507+ program: ~ Program::new(),
473508 };
474509
475510 let istty = unsafe { libc::isatty(libc::STDIN_FILENO as i32) } != 0;
@@ -502,10 +537,7 @@ pub fn main() {
502537 }
503538 loop ;
504539 }
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) ;
509541 }
510542 }
511543 }
@@ -524,7 +556,8 @@ mod tests {
524556 binary: ~" rusti",
525557 running : true ,
526558 lib_search_paths : ~[ ] ,
527- program : Program :: new( ) ,
559+ engines : ~[ ] ,
560+ program : ~Program :: new( ) ,
528561 }
529562 }
530563
@@ -535,9 +568,9 @@ mod tests {
535568 fn run_program( prog: & str) {
536569 let mut r = repl( ) ;
537570 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) ;
541574 }
542575 }
543576 fn run_program( _: & str) { }
@@ -682,7 +715,7 @@ mod tests {
682715 assert ! ( r. running) ;
683716 let result = run_line( & mut r, io:: stdin( ) , io:: stdout( ) ,
684717 ~": exit", false ) ;
685- assert ! ( result. is_none ( ) ) ;
718+ assert ! ( result) ;
686719 assert ! ( !r. running) ;
687720 }
688721}
0 commit comments