]> git.lizzy.rs Git - rust.git/blob - src/test/run-make/execution-engine/test.rs
Pass the mir map to trans
[rust.git] / src / test / run-make / execution-engine / test.rs
1 // Copyright 2015 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
4 //
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
10
11 #![feature(rustc_private)]
12 #![feature(libc)]
13
14 extern crate libc;
15 extern crate rustc;
16 extern crate rustc_driver;
17 extern crate rustc_front;
18 extern crate rustc_lint;
19 extern crate rustc_resolve;
20 extern crate syntax;
21
22 use std::ffi::{CStr, CString};
23 use std::mem::transmute;
24 use std::path::PathBuf;
25 use std::thread::Builder;
26
27 use rustc::front::map as ast_map;
28 use rustc::llvm;
29 use rustc::metadata::cstore::RequireDynamic;
30 use rustc::middle::ty;
31 use rustc::session::config::{self, basic_options, build_configuration, Input, Options};
32 use rustc::session::build_session;
33 use rustc_driver::driver;
34 use rustc_front::lowering::{lower_crate, LoweringContext};
35 use rustc_resolve::MakeGlobMap;
36 use libc::c_void;
37
38 use syntax::diagnostics::registry::Registry;
39
40 fn main() {
41     let program = r#"
42     #[no_mangle]
43     pub static TEST_STATIC: i32 = 42;
44     "#;
45
46     let program2 = r#"
47     #[no_mangle]
48     pub fn test_add(a: i32, b: i32) -> i32 { a + b }
49     "#;
50
51     let mut path = match std::env::args().nth(2) {
52         Some(path) => PathBuf::from(&path),
53         None => panic!("missing rustc path")
54     };
55
56     // Remove two segments from rustc path to get sysroot.
57     path.pop();
58     path.pop();
59
60     let mut ee = ExecutionEngine::new(program, path);
61
62     let test_static = match ee.get_global("TEST_STATIC") {
63         Some(g) => g as *const i32,
64         None => panic!("failed to get global")
65     };
66
67     assert_eq!(unsafe { *test_static }, 42);
68
69     ee.add_module(program2);
70
71     let test_add: fn(i32, i32) -> i32;
72
73     test_add = match ee.get_function("test_add") {
74         Some(f) => unsafe { transmute(f) },
75         None => panic!("failed to get function")
76     };
77
78     assert_eq!(test_add(1, 2), 3);
79 }
80
81 struct ExecutionEngine {
82     ee: llvm::ExecutionEngineRef,
83     modules: Vec<llvm::ModuleRef>,
84     sysroot: PathBuf,
85 }
86
87 impl ExecutionEngine {
88     pub fn new(program: &str, sysroot: PathBuf) -> ExecutionEngine {
89         let (llmod, deps) = compile_program(program, sysroot.clone())
90             .expect("failed to compile program");
91
92         let ee = unsafe { llvm::LLVMBuildExecutionEngine(llmod) };
93
94         if ee.is_null() {
95             panic!("Failed to create ExecutionEngine: {}", llvm_error());
96         }
97
98         let ee = ExecutionEngine{
99             ee: ee,
100             modules: vec![llmod],
101             sysroot: sysroot,
102         };
103
104         ee.load_deps(&deps);
105         ee
106     }
107
108     pub fn add_module(&mut self, program: &str) {
109         let (llmod, deps) = compile_program(program, self.sysroot.clone())
110             .expect("failed to compile program in add_module");
111
112         unsafe { llvm::LLVMExecutionEngineAddModule(self.ee, llmod); }
113
114         self.modules.push(llmod);
115         self.load_deps(&deps);
116     }
117
118     /// Returns a raw pointer to the named function.
119     pub fn get_function(&mut self, name: &str) -> Option<*const c_void> {
120         let s = CString::new(name.as_bytes()).unwrap();
121
122         for &m in &self.modules {
123             let fv = unsafe { llvm::LLVMGetNamedFunction(m, s.as_ptr()) };
124
125             if !fv.is_null() {
126                 let fp = unsafe { llvm::LLVMGetPointerToGlobal(self.ee, fv) };
127
128                 assert!(!fp.is_null());
129                 return Some(fp);
130             }
131         }
132         None
133     }
134
135     /// Returns a raw pointer to the named global item.
136     pub fn get_global(&mut self, name: &str) -> Option<*const c_void> {
137         let s = CString::new(name.as_bytes()).unwrap();
138
139         for &m in &self.modules {
140             let gv = unsafe { llvm::LLVMGetNamedGlobal(m, s.as_ptr()) };
141
142             if !gv.is_null() {
143                 let gp = unsafe { llvm::LLVMGetPointerToGlobal(self.ee, gv) };
144
145                 assert!(!gp.is_null());
146                 return Some(gp);
147             }
148         }
149         None
150     }
151
152     /// Loads all dependencies of compiled code.
153     /// Expects a series of paths to dynamic library files.
154     fn load_deps(&self, deps: &[PathBuf]) {
155         for path in deps {
156             let s = match path.as_os_str().to_str() {
157                 Some(s) => s,
158                 None => panic!(
159                     "Could not convert crate path to UTF-8 string: {:?}", path)
160             };
161             let cs = CString::new(s).unwrap();
162
163             let res = unsafe { llvm::LLVMRustLoadDynamicLibrary(cs.as_ptr()) };
164
165             if res == 0 {
166                 panic!("Failed to load crate {:?}: {}",
167                     path.display(), llvm_error());
168             }
169         }
170     }
171 }
172
173 impl Drop for ExecutionEngine {
174     fn drop(&mut self) {
175         unsafe { llvm::LLVMDisposeExecutionEngine(self.ee) };
176     }
177 }
178
179 /// Returns last error from LLVM wrapper code.
180 fn llvm_error() -> String {
181     String::from_utf8_lossy(
182         unsafe { CStr::from_ptr(llvm::LLVMRustGetLastError()).to_bytes() })
183         .into_owned()
184 }
185
186 fn build_exec_options(sysroot: PathBuf) -> Options {
187     let mut opts = basic_options();
188
189     // librustc derives sysroot from the executable name.
190     // Since we are not rustc, we must specify it.
191     opts.maybe_sysroot = Some(sysroot);
192
193     // Prefer faster build time
194     opts.optimize = config::No;
195
196     // Don't require a `main` function
197     opts.crate_types = vec![config::CrateTypeDylib];
198
199     opts
200 }
201
202 /// Compiles input up to phase 4, translation to LLVM.
203 ///
204 /// Returns the LLVM `ModuleRef` and a series of paths to dynamic libraries
205 /// for crates used in the given input.
206 fn compile_program(input: &str, sysroot: PathBuf)
207                    -> Option<(llvm::ModuleRef, Vec<PathBuf>)> {
208     let input = Input::Str(input.to_string());
209     let thread = Builder::new().name("compile_program".to_string());
210
211     let handle = thread.spawn(move || {
212         let opts = build_exec_options(sysroot);
213         let sess = build_session(opts, None, Registry::new(&rustc::DIAGNOSTICS));
214         rustc_lint::register_builtins(&mut sess.lint_store.borrow_mut(), Some(&sess));
215
216         let cfg = build_configuration(&sess);
217
218         let id = "input".to_string();
219
220         let krate = driver::phase_1_parse_input(&sess, cfg, &input);
221
222         let krate = driver::phase_2_configure_and_expand(&sess, krate, &id, None)
223             .expect("phase_2 returned `None`");
224
225         let krate = driver::assign_node_ids(&sess, krate);
226         let lcx = LoweringContext::new(&sess, Some(&krate));
227         let mut hir_forest = ast_map::Forest::new(lower_crate(&lcx, &krate));
228         let arenas = ty::CtxtArenas::new();
229         let ast_map = driver::make_map(&sess, &mut hir_forest);
230
231         driver::phase_3_run_analysis_passes(
232             &sess, ast_map, &arenas, &id, MakeGlobMap::No, |tcx, mir_map, analysis| {
233
234             let trans = driver::phase_4_translate_to_llvm(tcx, &mir_map, analysis);
235
236             let crates = tcx.sess.cstore.get_used_crates(RequireDynamic);
237
238             // Collect crates used in the session.
239             // Reverse order finds dependencies first.
240             let deps = crates.into_iter().rev()
241                 .filter_map(|(_, p)| p).collect();
242
243             assert_eq!(trans.modules.len(), 1);
244             let llmod = trans.modules[0].llmod;
245
246             // Workaround because raw pointers do not impl Send
247             let modp = llmod as usize;
248
249             (modp, deps)
250         })
251     }).unwrap();
252
253     match handle.join() {
254         Ok((llmod, deps)) => Some((llmod as llvm::ModuleRef, deps)),
255         Err(_) => None
256     }
257 }