]>
Commit | Line | Data |
---|---|---|
532ac7d7 | 1 | use crate::interface::{Compiler, Result}; |
60c5eb7d | 2 | use crate::passes::{self, BoxedResolver, QueryContext}; |
532ac7d7 XL |
3 | |
4 | use rustc_incremental::DepGraphFuture; | |
60c5eb7d XL |
5 | use rustc_data_structures::sync::{Lrc, Once, WorkerLocal}; |
6 | use rustc_codegen_utils::codegen_backend::CodegenBackend; | |
416331ca | 7 | use rustc::session::config::{OutputFilenames, OutputType}; |
532ac7d7 | 8 | use rustc::util::common::{time, ErrorReported}; |
60c5eb7d | 9 | use rustc::arena::Arena; |
532ac7d7 | 10 | use rustc::hir; |
e74abb32 XL |
11 | use rustc::lint; |
12 | use rustc::session::Session; | |
13 | use rustc::lint::LintStore; | |
532ac7d7 | 14 | use rustc::hir::def_id::LOCAL_CRATE; |
532ac7d7 | 15 | use rustc::ty::steal::Steal; |
60c5eb7d | 16 | use rustc::ty::{AllArenas, ResolverOutputs, GlobalCtxt}; |
532ac7d7 | 17 | use rustc::dep_graph::DepGraph; |
532ac7d7 | 18 | use std::cell::{Ref, RefMut, RefCell}; |
532ac7d7 | 19 | use std::rc::Rc; |
532ac7d7 XL |
20 | use std::any::Any; |
21 | use std::mem; | |
416331ca | 22 | use syntax::{self, ast}; |
532ac7d7 XL |
23 | |
24 | /// Represent the result of a query. | |
60c5eb7d | 25 | /// This result can be stolen with the `take` method and generated with the `compute` method. |
532ac7d7 XL |
26 | pub struct Query<T> { |
27 | result: RefCell<Option<Result<T>>>, | |
28 | } | |
29 | ||
30 | impl<T> Query<T> { | |
31 | fn compute<F: FnOnce() -> Result<T>>(&self, f: F) -> Result<&Query<T>> { | |
32 | let mut result = self.result.borrow_mut(); | |
33 | if result.is_none() { | |
34 | *result = Some(f()); | |
35 | } | |
36 | result.as_ref().unwrap().as_ref().map(|_| self).map_err(|err| *err) | |
37 | } | |
38 | ||
39 | /// Takes ownership of the query result. Further attempts to take or peek the query | |
60c5eb7d | 40 | /// result will panic unless it is generated by calling the `compute` method. |
532ac7d7 XL |
41 | pub fn take(&self) -> T { |
42 | self.result | |
43 | .borrow_mut() | |
44 | .take() | |
45 | .expect("missing query result") | |
46 | .unwrap() | |
47 | } | |
48 | ||
532ac7d7 XL |
49 | /// Borrows the query result using the RefCell. Panics if the result is stolen. |
50 | pub fn peek(&self) -> Ref<'_, T> { | |
51 | Ref::map(self.result.borrow(), |r| { | |
52 | r.as_ref().unwrap().as_ref().expect("missing query result") | |
53 | }) | |
54 | } | |
55 | ||
56 | /// Mutably borrows the query result using the RefCell. Panics if the result is stolen. | |
57 | pub fn peek_mut(&self) -> RefMut<'_, T> { | |
58 | RefMut::map(self.result.borrow_mut(), |r| { | |
59 | r.as_mut().unwrap().as_mut().expect("missing query result") | |
60 | }) | |
61 | } | |
62 | } | |
63 | ||
64 | impl<T> Default for Query<T> { | |
65 | fn default() -> Self { | |
66 | Query { | |
67 | result: RefCell::new(None), | |
68 | } | |
69 | } | |
70 | } | |
71 | ||
60c5eb7d XL |
72 | pub struct Queries<'tcx> { |
73 | compiler: &'tcx Compiler, | |
74 | gcx: Once<GlobalCtxt<'tcx>>, | |
75 | ||
76 | all_arenas: AllArenas, | |
77 | arena: WorkerLocal<Arena<'tcx>>, | |
78 | ||
532ac7d7 XL |
79 | dep_graph_future: Query<Option<DepGraphFuture>>, |
80 | parse: Query<ast::Crate>, | |
81 | crate_name: Query<String>, | |
60c5eb7d | 82 | register_plugins: Query<(ast::Crate, Lrc<LintStore>)>, |
e74abb32 | 83 | expansion: Query<(ast::Crate, Steal<Rc<RefCell<BoxedResolver>>>, Lrc<LintStore>)>, |
532ac7d7 | 84 | dep_graph: Query<DepGraph>, |
60c5eb7d | 85 | lower_to_hir: Query<(&'tcx hir::map::Forest, Steal<ResolverOutputs>)>, |
532ac7d7 | 86 | prepare_outputs: Query<OutputFilenames>, |
60c5eb7d | 87 | global_ctxt: Query<QueryContext<'tcx>>, |
532ac7d7 | 88 | ongoing_codegen: Query<Box<dyn Any>>, |
532ac7d7 XL |
89 | } |
90 | ||
60c5eb7d XL |
91 | impl<'tcx> Queries<'tcx> { |
92 | pub fn new(compiler: &'tcx Compiler) -> Queries<'tcx> { | |
93 | Queries { | |
94 | compiler, | |
95 | gcx: Once::new(), | |
96 | all_arenas: AllArenas::new(), | |
97 | arena: WorkerLocal::new(|_| Arena::default()), | |
98 | dep_graph_future: Default::default(), | |
99 | parse: Default::default(), | |
100 | crate_name: Default::default(), | |
101 | register_plugins: Default::default(), | |
102 | expansion: Default::default(), | |
103 | dep_graph: Default::default(), | |
104 | lower_to_hir: Default::default(), | |
105 | prepare_outputs: Default::default(), | |
106 | global_ctxt: Default::default(), | |
107 | ongoing_codegen: Default::default(), | |
108 | } | |
109 | } | |
110 | ||
111 | fn session(&self) -> &Lrc<Session> { | |
112 | &self.compiler.sess | |
113 | } | |
114 | fn codegen_backend(&self) -> &Lrc<Box<dyn CodegenBackend>> { | |
115 | &self.compiler.codegen_backend() | |
116 | } | |
117 | ||
532ac7d7 | 118 | pub fn dep_graph_future(&self) -> Result<&Query<Option<DepGraphFuture>>> { |
60c5eb7d XL |
119 | self.dep_graph_future.compute(|| { |
120 | Ok(self.session().opts.build_dep_graph().then(|| { | |
121 | rustc_incremental::load_dep_graph(self.session()) | |
122 | })) | |
532ac7d7 XL |
123 | }) |
124 | } | |
125 | ||
126 | pub fn parse(&self) -> Result<&Query<ast::Crate>> { | |
60c5eb7d XL |
127 | self.parse.compute(|| { |
128 | passes::parse(self.session(), &self.compiler.input).map_err( | |
532ac7d7 XL |
129 | |mut parse_error| { |
130 | parse_error.emit(); | |
131 | ErrorReported | |
132 | }, | |
133 | ) | |
134 | }) | |
135 | } | |
136 | ||
60c5eb7d XL |
137 | pub fn register_plugins(&self) -> Result<&Query<(ast::Crate, Lrc<LintStore>)>> { |
138 | self.register_plugins.compute(|| { | |
532ac7d7 XL |
139 | let crate_name = self.crate_name()?.peek().clone(); |
140 | let krate = self.parse()?.take(); | |
141 | ||
e74abb32 XL |
142 | let empty: &(dyn Fn(&Session, &mut lint::LintStore) + Sync + Send) = &|_, _| {}; |
143 | let result = passes::register_plugins( | |
532ac7d7 | 144 | self.session(), |
e74abb32 | 145 | &*self.codegen_backend().metadata_loader(), |
60c5eb7d | 146 | self.compiler.register_lints |
e74abb32 XL |
147 | .as_ref() |
148 | .map(|p| &**p) | |
149 | .unwrap_or_else(|| empty), | |
532ac7d7 XL |
150 | krate, |
151 | &crate_name, | |
e74abb32 XL |
152 | ); |
153 | ||
154 | // Compute the dependency graph (in the background). We want to do | |
155 | // this as early as possible, to give the DepGraph maximum time to | |
156 | // load before dep_graph() is called, but it also can't happen | |
157 | // until after rustc_incremental::prepare_session_directory() is | |
158 | // called, which happens within passes::register_plugins(). | |
159 | self.dep_graph_future().ok(); | |
160 | ||
161 | result | |
532ac7d7 XL |
162 | }) |
163 | } | |
164 | ||
165 | pub fn crate_name(&self) -> Result<&Query<String>> { | |
60c5eb7d XL |
166 | self.crate_name.compute(|| { |
167 | Ok(match self.compiler.crate_name { | |
532ac7d7 | 168 | Some(ref crate_name) => crate_name.clone(), |
e74abb32 XL |
169 | None => { |
170 | let parse_result = self.parse()?; | |
171 | let krate = parse_result.peek(); | |
172 | rustc_codegen_utils::link::find_crate_name( | |
173 | Some(self.session()), | |
174 | &krate.attrs, | |
60c5eb7d | 175 | &self.compiler.input |
e74abb32 XL |
176 | ) |
177 | } | |
178 | }) | |
532ac7d7 XL |
179 | }) |
180 | } | |
181 | ||
182 | pub fn expansion( | |
183 | &self | |
e74abb32 | 184 | ) -> Result<&Query<(ast::Crate, Steal<Rc<RefCell<BoxedResolver>>>, Lrc<LintStore>)>> { |
60c5eb7d | 185 | self.expansion.compute(|| { |
532ac7d7 | 186 | let crate_name = self.crate_name()?.peek().clone(); |
60c5eb7d | 187 | let (krate, lint_store) = self.register_plugins()?.take(); |
532ac7d7 | 188 | passes::configure_and_expand( |
60c5eb7d | 189 | self.session().clone(), |
e74abb32 XL |
190 | lint_store.clone(), |
191 | self.codegen_backend().metadata_loader(), | |
532ac7d7 XL |
192 | krate, |
193 | &crate_name, | |
e74abb32 XL |
194 | ).map(|(krate, resolver)| { |
195 | (krate, Steal::new(Rc::new(RefCell::new(resolver))), lint_store) | |
196 | }) | |
532ac7d7 XL |
197 | }) |
198 | } | |
199 | ||
200 | pub fn dep_graph(&self) -> Result<&Query<DepGraph>> { | |
60c5eb7d | 201 | self.dep_graph.compute(|| { |
532ac7d7 XL |
202 | Ok(match self.dep_graph_future()?.take() { |
203 | None => DepGraph::new_disabled(), | |
204 | Some(future) => { | |
205 | let (prev_graph, prev_work_products) = | |
206 | time(self.session(), "blocked while dep-graph loading finishes", || { | |
207 | future.open().unwrap_or_else(|e| rustc_incremental::LoadResult::Error { | |
208 | message: format!("could not decode incremental cache: {:?}", e), | |
209 | }).open(self.session()) | |
210 | }); | |
211 | DepGraph::new(prev_graph, prev_work_products) | |
212 | } | |
213 | }) | |
214 | }) | |
215 | } | |
216 | ||
e74abb32 | 217 | pub fn lower_to_hir( |
60c5eb7d XL |
218 | &'tcx self, |
219 | ) -> Result<&Query<(&'tcx hir::map::Forest, Steal<ResolverOutputs>)>> { | |
220 | self.lower_to_hir.compute(|| { | |
532ac7d7 | 221 | let expansion_result = self.expansion()?; |
416331ca XL |
222 | let peeked = expansion_result.peek(); |
223 | let krate = &peeked.0; | |
224 | let resolver = peeked.1.steal(); | |
e74abb32 | 225 | let lint_store = &peeked.2; |
60c5eb7d | 226 | let hir = resolver.borrow_mut().access(|resolver| { |
532ac7d7 XL |
227 | passes::lower_to_hir( |
228 | self.session(), | |
e74abb32 | 229 | lint_store, |
532ac7d7 XL |
230 | resolver, |
231 | &*self.dep_graph()?.peek(), | |
232 | &krate | |
233 | ) | |
60c5eb7d XL |
234 | })?; |
235 | let hir = self.arena.alloc(hir); | |
e74abb32 | 236 | Ok((hir, Steal::new(BoxedResolver::to_resolver_outputs(resolver)))) |
532ac7d7 XL |
237 | }) |
238 | } | |
239 | ||
240 | pub fn prepare_outputs(&self) -> Result<&Query<OutputFilenames>> { | |
60c5eb7d | 241 | self.prepare_outputs.compute(|| { |
e74abb32 XL |
242 | let expansion_result = self.expansion()?; |
243 | let (krate, boxed_resolver, _) = &*expansion_result.peek(); | |
532ac7d7 XL |
244 | let crate_name = self.crate_name()?; |
245 | let crate_name = crate_name.peek(); | |
60c5eb7d XL |
246 | passes::prepare_outputs( |
247 | self.session(), self.compiler, &krate, &boxed_resolver, &crate_name | |
248 | ) | |
532ac7d7 XL |
249 | }) |
250 | } | |
251 | ||
60c5eb7d XL |
252 | pub fn global_ctxt(&'tcx self) -> Result<&Query<QueryContext<'tcx>>> { |
253 | self.global_ctxt.compute(|| { | |
532ac7d7 XL |
254 | let crate_name = self.crate_name()?.peek().clone(); |
255 | let outputs = self.prepare_outputs()?.peek().clone(); | |
e74abb32 | 256 | let lint_store = self.expansion()?.peek().2.clone(); |
60c5eb7d XL |
257 | let hir = self.lower_to_hir()?.peek(); |
258 | let (ref hir_forest, ref resolver_outputs) = &*hir; | |
532ac7d7 | 259 | Ok(passes::create_global_ctxt( |
60c5eb7d | 260 | self.compiler, |
e74abb32 | 261 | lint_store, |
60c5eb7d | 262 | hir_forest, |
e74abb32 | 263 | resolver_outputs.steal(), |
532ac7d7 | 264 | outputs, |
60c5eb7d XL |
265 | &crate_name, |
266 | &self.gcx, | |
267 | &self.all_arenas, | |
268 | &self.arena, | |
269 | )) | |
532ac7d7 XL |
270 | }) |
271 | } | |
272 | ||
60c5eb7d XL |
273 | pub fn ongoing_codegen(&'tcx self) -> Result<&Query<Box<dyn Any>>> { |
274 | self.ongoing_codegen.compute(|| { | |
532ac7d7 XL |
275 | let outputs = self.prepare_outputs()?; |
276 | self.global_ctxt()?.peek_mut().enter(|tcx| { | |
277 | tcx.analysis(LOCAL_CRATE).ok(); | |
278 | ||
279 | // Don't do code generation if there were any errors | |
280 | self.session().compile_status()?; | |
281 | ||
282 | Ok(passes::start_codegen( | |
283 | &***self.codegen_backend(), | |
284 | tcx, | |
532ac7d7 XL |
285 | &*outputs.peek() |
286 | )) | |
287 | }) | |
288 | }) | |
289 | } | |
290 | ||
60c5eb7d XL |
291 | pub fn linker(&'tcx self) -> Result<Linker> { |
292 | let dep_graph = self.dep_graph()?; | |
293 | let prepare_outputs = self.prepare_outputs()?; | |
294 | let ongoing_codegen = self.ongoing_codegen()?; | |
532ac7d7 | 295 | |
60c5eb7d XL |
296 | let sess = self.session().clone(); |
297 | let codegen_backend = self.codegen_backend().clone(); | |
532ac7d7 | 298 | |
60c5eb7d XL |
299 | Ok(Linker { |
300 | sess, | |
301 | dep_graph: dep_graph.peek().clone(), | |
302 | prepare_outputs: prepare_outputs.take(), | |
303 | ongoing_codegen: ongoing_codegen.take(), | |
304 | codegen_backend, | |
532ac7d7 XL |
305 | }) |
306 | } | |
60c5eb7d XL |
307 | } |
308 | ||
309 | pub struct Linker { | |
310 | sess: Lrc<Session>, | |
311 | dep_graph: DepGraph, | |
312 | prepare_outputs: OutputFilenames, | |
313 | ongoing_codegen: Box<dyn Any>, | |
314 | codegen_backend: Lrc<Box<dyn CodegenBackend>>, | |
315 | } | |
316 | ||
317 | impl Linker { | |
318 | pub fn link(self) -> Result<()> { | |
319 | self.codegen_backend.join_codegen_and_link( | |
320 | self.ongoing_codegen, | |
321 | &self.sess, | |
322 | &self.dep_graph, | |
323 | &self.prepare_outputs, | |
324 | ).map_err(|_| ErrorReported) | |
325 | } | |
326 | } | |
327 | ||
328 | impl Compiler { | |
329 | pub fn enter<F, T>(&self, f: F) -> T | |
330 | where F: for<'tcx> FnOnce(&'tcx Queries<'tcx>) -> T | |
331 | { | |
332 | let queries = Queries::new(&self); | |
333 | let ret = f(&queries); | |
334 | ||
335 | if self.session().opts.debugging_opts.query_stats { | |
336 | if let Ok(gcx) = queries.global_ctxt() { | |
337 | gcx.peek().print_stats(); | |
338 | } | |
339 | } | |
340 | ||
341 | ret | |
342 | } | |
532ac7d7 | 343 | |
e74abb32 XL |
344 | // This method is different to all the other methods in `Compiler` because |
345 | // it lacks a `Queries` entry. It's also not currently used. It does serve | |
346 | // as an example of how `Compiler` can be used, with additional steps added | |
347 | // between some passes. And see `rustc_driver::run_compiler` for a more | |
348 | // complex example. | |
532ac7d7 | 349 | pub fn compile(&self) -> Result<()> { |
60c5eb7d XL |
350 | let linker = self.enter(|queries| { |
351 | queries.prepare_outputs()?; | |
532ac7d7 | 352 | |
60c5eb7d XL |
353 | if self.session().opts.output_types.contains_key(&OutputType::DepInfo) |
354 | && self.session().opts.output_types.len() == 1 | |
355 | { | |
356 | return Ok(None) | |
357 | } | |
358 | ||
359 | queries.global_ctxt()?; | |
532ac7d7 | 360 | |
60c5eb7d XL |
361 | // Drop AST after creating GlobalCtxt to free memory. |
362 | mem::drop(queries.expansion()?.take()); | |
532ac7d7 | 363 | |
60c5eb7d | 364 | queries.ongoing_codegen()?; |
532ac7d7 | 365 | |
60c5eb7d XL |
366 | let linker = queries.linker()?; |
367 | Ok(Some(linker)) | |
368 | })?; | |
532ac7d7 | 369 | |
60c5eb7d XL |
370 | if let Some(linker) = linker { |
371 | linker.link()? | |
372 | } | |
532ac7d7 | 373 | |
60c5eb7d | 374 | Ok(()) |
532ac7d7 XL |
375 | } |
376 | } |