]> git.proxmox.com Git - rustc.git/blame - src/test/run-make/execution-engine/test.rs
Imported Upstream version 1.11.0+dfsg1
[rustc.git] / src / test / run-make / execution-engine / test.rs
CommitLineData
62682a34
SL
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)]
c1a9b12d 12#![feature(libc)]
62682a34 13
c1a9b12d 14extern crate libc;
62682a34
SL
15extern crate rustc;
16extern crate rustc_driver;
17extern crate rustc_lint;
54a0048b 18extern crate rustc_llvm as llvm;
92a42be0 19extern crate rustc_metadata;
62682a34 20extern crate rustc_resolve;
3157f602
XL
21extern crate rustc_errors;
22extern crate rustc_errors as errors;
54a0048b 23#[macro_use] extern crate syntax;
62682a34
SL
24
25use std::ffi::{CStr, CString};
26use std::mem::transmute;
27use std::path::PathBuf;
92a42be0 28use std::rc::Rc;
62682a34
SL
29use std::thread::Builder;
30
7453a54e 31use rustc::dep_graph::DepGraph;
54a0048b 32use rustc::hir::map as ast_map;
92a42be0 33use rustc::middle::cstore::{CrateStore, LinkagePreference};
54a0048b 34use rustc::ty;
62682a34
SL
35use rustc::session::config::{self, basic_options, build_configuration, Input, Options};
36use rustc::session::build_session;
7453a54e 37use rustc_driver::{driver, abort_on_err};
62682a34 38use rustc_resolve::MakeGlobMap;
a7813a04 39use rustc_metadata::creader::read_local_crates;
92a42be0 40use rustc_metadata::cstore::CStore;
c1a9b12d 41use libc::c_void;
62682a34 42
3157f602 43use rustc_errors::registry::Registry;
92a42be0 44use syntax::parse::token;
62682a34
SL
45
46fn main() {
7453a54e
SL
47 // Currently trips an assertion on i686-msvc, presumably because the support
48 // in LLVM is a little young.
49 if cfg!(target_env = "msvc") && cfg!(target_arch = "x86") {
50 return
51 }
52
62682a34
SL
53 let program = r#"
54 #[no_mangle]
55 pub static TEST_STATIC: i32 = 42;
56 "#;
57
58 let program2 = r#"
59 #[no_mangle]
60 pub fn test_add(a: i32, b: i32) -> i32 { a + b }
61 "#;
62
63 let mut path = match std::env::args().nth(2) {
64 Some(path) => PathBuf::from(&path),
65 None => panic!("missing rustc path")
66 };
67
68 // Remove two segments from rustc path to get sysroot.
69 path.pop();
70 path.pop();
71
72 let mut ee = ExecutionEngine::new(program, path);
73
74 let test_static = match ee.get_global("TEST_STATIC") {
75 Some(g) => g as *const i32,
76 None => panic!("failed to get global")
77 };
78
79 assert_eq!(unsafe { *test_static }, 42);
80
81 ee.add_module(program2);
82
83 let test_add: fn(i32, i32) -> i32;
84
85 test_add = match ee.get_function("test_add") {
86 Some(f) => unsafe { transmute(f) },
87 None => panic!("failed to get function")
88 };
89
90 assert_eq!(test_add(1, 2), 3);
91}
92
93struct ExecutionEngine {
94 ee: llvm::ExecutionEngineRef,
95 modules: Vec<llvm::ModuleRef>,
96 sysroot: PathBuf,
97}
98
99impl ExecutionEngine {
100 pub fn new(program: &str, sysroot: PathBuf) -> ExecutionEngine {
101 let (llmod, deps) = compile_program(program, sysroot.clone())
102 .expect("failed to compile program");
103
104 let ee = unsafe { llvm::LLVMBuildExecutionEngine(llmod) };
105
106 if ee.is_null() {
107 panic!("Failed to create ExecutionEngine: {}", llvm_error());
108 }
109
110 let ee = ExecutionEngine{
111 ee: ee,
112 modules: vec![llmod],
113 sysroot: sysroot,
114 };
115
116 ee.load_deps(&deps);
117 ee
118 }
119
120 pub fn add_module(&mut self, program: &str) {
121 let (llmod, deps) = compile_program(program, self.sysroot.clone())
122 .expect("failed to compile program in add_module");
123
124 unsafe { llvm::LLVMExecutionEngineAddModule(self.ee, llmod); }
125
126 self.modules.push(llmod);
127 self.load_deps(&deps);
128 }
129
130 /// Returns a raw pointer to the named function.
c1a9b12d 131 pub fn get_function(&mut self, name: &str) -> Option<*const c_void> {
62682a34
SL
132 let s = CString::new(name.as_bytes()).unwrap();
133
134 for &m in &self.modules {
135 let fv = unsafe { llvm::LLVMGetNamedFunction(m, s.as_ptr()) };
136
137 if !fv.is_null() {
138 let fp = unsafe { llvm::LLVMGetPointerToGlobal(self.ee, fv) };
139
140 assert!(!fp.is_null());
141 return Some(fp);
142 }
143 }
144 None
145 }
146
147 /// Returns a raw pointer to the named global item.
c1a9b12d 148 pub fn get_global(&mut self, name: &str) -> Option<*const c_void> {
62682a34
SL
149 let s = CString::new(name.as_bytes()).unwrap();
150
151 for &m in &self.modules {
152 let gv = unsafe { llvm::LLVMGetNamedGlobal(m, s.as_ptr()) };
153
154 if !gv.is_null() {
155 let gp = unsafe { llvm::LLVMGetPointerToGlobal(self.ee, gv) };
156
157 assert!(!gp.is_null());
158 return Some(gp);
159 }
160 }
161 None
162 }
163
164 /// Loads all dependencies of compiled code.
165 /// Expects a series of paths to dynamic library files.
166 fn load_deps(&self, deps: &[PathBuf]) {
167 for path in deps {
168 let s = match path.as_os_str().to_str() {
169 Some(s) => s,
170 None => panic!(
171 "Could not convert crate path to UTF-8 string: {:?}", path)
172 };
173 let cs = CString::new(s).unwrap();
174
175 let res = unsafe { llvm::LLVMRustLoadDynamicLibrary(cs.as_ptr()) };
176
177 if res == 0 {
178 panic!("Failed to load crate {:?}: {}",
179 path.display(), llvm_error());
180 }
181 }
182 }
183}
184
185impl Drop for ExecutionEngine {
186 fn drop(&mut self) {
187 unsafe { llvm::LLVMDisposeExecutionEngine(self.ee) };
188 }
189}
190
191/// Returns last error from LLVM wrapper code.
192fn llvm_error() -> String {
193 String::from_utf8_lossy(
194 unsafe { CStr::from_ptr(llvm::LLVMRustGetLastError()).to_bytes() })
195 .into_owned()
196}
197
198fn build_exec_options(sysroot: PathBuf) -> Options {
199 let mut opts = basic_options();
200
201 // librustc derives sysroot from the executable name.
202 // Since we are not rustc, we must specify it.
203 opts.maybe_sysroot = Some(sysroot);
204
205 // Prefer faster build time
9cc50fc6 206 opts.optimize = config::OptLevel::No;
62682a34
SL
207
208 // Don't require a `main` function
209 opts.crate_types = vec![config::CrateTypeDylib];
210
211 opts
212}
213
214/// Compiles input up to phase 4, translation to LLVM.
215///
216/// Returns the LLVM `ModuleRef` and a series of paths to dynamic libraries
217/// for crates used in the given input.
218fn compile_program(input: &str, sysroot: PathBuf)
219 -> Option<(llvm::ModuleRef, Vec<PathBuf>)> {
54a0048b
SL
220 let input = Input::Str {
221 name: driver::anon_src(),
222 input: input.to_string(),
223 };
62682a34
SL
224 let thread = Builder::new().name("compile_program".to_string());
225
226 let handle = thread.spawn(move || {
227 let opts = build_exec_options(sysroot);
a7813a04
XL
228 let dep_graph = DepGraph::new(opts.build_dep_graph());
229 let cstore = Rc::new(CStore::new(&dep_graph, token::get_ident_interner()));
230 let sess = build_session(opts,
231 &dep_graph,
232 None,
233 Registry::new(&rustc::DIAGNOSTICS),
9cc50fc6 234 cstore.clone());
62682a34
SL
235 rustc_lint::register_builtins(&mut sess.lint_store.borrow_mut(), Some(&sess));
236
237 let cfg = build_configuration(&sess);
238
239 let id = "input".to_string();
240
54a0048b 241 let krate = panictry!(driver::phase_1_parse_input(&sess, cfg, &input));
62682a34 242
3157f602
XL
243 let driver::ExpansionResult { defs, analysis, resolutions, mut hir_forest, .. } = {
244 driver::phase_2_configure_and_expand(
245 &sess, &cstore, krate, &id, None, MakeGlobMap::No, |_| Ok(()),
246 ).expect("phase_2 returned `None`")
a7813a04
XL
247 };
248
62682a34 249 let arenas = ty::CtxtArenas::new();
a7813a04 250 let ast_map = ast_map::map_crate(&mut hir_forest, defs);
62682a34 251
7453a54e 252 abort_on_err(driver::phase_3_run_analysis_passes(
a7813a04
XL
253 &sess, ast_map, analysis, resolutions, &arenas, &id,
254 |tcx, mir_map, analysis, _| {
62682a34 255
7453a54e 256 let trans = driver::phase_4_translate_to_llvm(tcx, mir_map.unwrap(), analysis);
62682a34 257
92a42be0 258 let crates = tcx.sess.cstore.used_crates(LinkagePreference::RequireDynamic);
62682a34
SL
259
260 // Collect crates used in the session.
261 // Reverse order finds dependencies first.
262 let deps = crates.into_iter().rev()
263 .filter_map(|(_, p)| p).collect();
264
265 assert_eq!(trans.modules.len(), 1);
266 let llmod = trans.modules[0].llmod;
267
268 // Workaround because raw pointers do not impl Send
269 let modp = llmod as usize;
270
271 (modp, deps)
7453a54e 272 }), &sess)
62682a34
SL
273 }).unwrap();
274
275 match handle.join() {
276 Ok((llmod, deps)) => Some((llmod as llvm::ModuleRef, deps)),
277 Err(_) => None
278 }
279}