]> git.lizzy.rs Git - rust.git/blob - src/driver/mod.rs
e56794bc4a94641583f871eb2680192dababfd53
[rust.git] / src / driver / mod.rs
1 use std::any::Any;
2 use std::ffi::CString;
3 use std::os::raw::{c_char, c_int};
4
5 use rustc::dep_graph::{WorkProduct, WorkProductFileKind, WorkProductId};
6 use rustc::middle::cstore::EncodedMetadata;
7 use rustc::mir::mono::{CodegenUnit, Linkage as RLinkage, Visibility};
8 use rustc::session::config::{DebugInfo, OutputType};
9 use rustc_session::cgu_reuse_tracker::CguReuse;
10 use rustc_codegen_ssa::back::linker::LinkerInfo;
11 use rustc_codegen_ssa::CrateInfo;
12
13 use crate::prelude::*;
14
15 use crate::backend::{Emit, WriteDebugInfo};
16
17 pub fn codegen_crate(
18     tcx: TyCtxt<'_>,
19     metadata: EncodedMetadata,
20     need_metadata_module: bool,
21 ) -> Box<dyn Any> {
22     tcx.sess.abort_if_errors();
23
24     if std::env::var("CG_CLIF_JIT").is_ok()
25         && tcx.sess.crate_types.get().contains(&CrateType::Executable)
26     {
27         #[cfg(not(target_arch = "wasm32"))]
28         let _: ! = run_jit(tcx);
29
30         #[cfg(target_arch = "wasm32")]
31         panic!("jit not supported on wasm");
32     }
33
34     run_aot(tcx, metadata, need_metadata_module)
35 }
36
37 #[cfg(not(target_arch = "wasm32"))]
38 fn run_jit(tcx: TyCtxt<'_>) -> ! {
39     use cranelift_simplejit::{SimpleJITBackend, SimpleJITBuilder};
40
41     // Rustc opens us without the RTLD_GLOBAL flag, so __cg_clif_global_atomic_mutex will not be
42     // exported. We fix this by opening ourself again as global.
43     // FIXME remove once atomic_shim is gone
44     let cg_dylib = std::ffi::OsString::from(&tcx.sess.opts.debugging_opts.codegen_backend.as_ref().unwrap());
45     std::mem::forget(libloading::os::unix::Library::open(Some(cg_dylib), libc::RTLD_NOW | libc::RTLD_GLOBAL).unwrap());
46
47
48     let imported_symbols = load_imported_symbols_for_jit(tcx);
49
50     let mut jit_builder = SimpleJITBuilder::with_isa(
51         crate::build_isa(tcx.sess, false),
52         cranelift_module::default_libcall_names(),
53     );
54     jit_builder.symbols(imported_symbols);
55     let mut jit_module: Module<SimpleJITBackend> = Module::new(jit_builder);
56     assert_eq!(pointer_ty(tcx), jit_module.target_config().pointer_type());
57
58     let sig = Signature {
59         params: vec![
60             AbiParam::new(jit_module.target_config().pointer_type()),
61             AbiParam::new(jit_module.target_config().pointer_type()),
62         ],
63         returns: vec![AbiParam::new(
64             jit_module.target_config().pointer_type(), /*isize*/
65         )],
66         call_conv: CallConv::triple_default(&crate::target_triple(tcx.sess)),
67     };
68     let main_func_id = jit_module
69         .declare_function("main", Linkage::Import, &sig)
70         .unwrap();
71
72     let (_, cgus) = tcx.collect_and_partition_mono_items(LOCAL_CRATE);
73     let mono_items = cgus
74         .iter()
75         .map(|cgu| cgu.items_in_deterministic_order(tcx).into_iter())
76         .flatten()
77         .collect::<FxHashMap<_, (_, _)>>()
78         .into_iter()
79         .collect::<Vec<(_, (_, _))>>();
80
81     time(tcx, "codegen mono items", || {
82         codegen_mono_items(tcx, &mut jit_module, None, mono_items);
83     });
84     crate::main_shim::maybe_create_entry_wrapper(tcx, &mut jit_module);
85     crate::allocator::codegen(tcx, &mut jit_module);
86
87     jit_module.finalize_definitions();
88
89     tcx.sess.abort_if_errors();
90
91     let finalized_main: *const u8 = jit_module.get_finalized_function(main_func_id);
92
93     println!("Rustc codegen cranelift will JIT run the executable, because the CG_CLIF_JIT env var is set");
94
95     let f: extern "C" fn(c_int, *const *const c_char) -> c_int =
96         unsafe { ::std::mem::transmute(finalized_main) };
97
98     let args = ::std::env::var("CG_CLIF_JIT_ARGS").unwrap_or_else(|_| String::new());
99     let args = args
100         .split(" ")
101         .chain(Some(&*tcx.crate_name(LOCAL_CRATE).as_str().to_string()))
102         .map(|arg| CString::new(arg).unwrap())
103         .collect::<Vec<_>>();
104     let argv = args.iter().map(|arg| arg.as_ptr()).collect::<Vec<_>>();
105     // TODO: Rust doesn't care, but POSIX argv has a NULL sentinel at the end
106
107     let ret = f(args.len() as c_int, argv.as_ptr());
108
109     jit_module.finish();
110     std::process::exit(ret);
111 }
112
113 fn load_imported_symbols_for_jit(tcx: TyCtxt<'_>) -> Vec<(String, *const u8)> {
114     use rustc::middle::dependency_format::Linkage;
115
116     let mut dylib_paths = Vec::new();
117
118     let crate_info = CrateInfo::new(tcx);
119     let formats = tcx.dependency_formats(LOCAL_CRATE);
120     let data = &formats
121         .iter()
122         .find(|(crate_type, _data)| *crate_type == CrateType::Executable)
123         .unwrap()
124         .1;
125     for &(cnum, _) in &crate_info.used_crates_dynamic {
126         let src = &crate_info.used_crate_source[&cnum];
127         match data[cnum.as_usize() - 1] {
128             Linkage::NotLinked | Linkage::IncludedFromDylib => {}
129             Linkage::Static => {
130                 let name = tcx.crate_name(cnum);
131                 let mut err = tcx
132                     .sess
133                     .struct_err(&format!("Can't load static lib {}", name.as_str()));
134                 err.note("rustc_codegen_cranelift can only load dylibs in JIT mode.");
135                 err.emit();
136             }
137             Linkage::Dynamic => {
138                 dylib_paths.push(src.dylib.as_ref().unwrap().0.clone());
139             }
140         }
141     }
142
143     let mut imported_symbols = Vec::new();
144     for path in dylib_paths {
145         use object::Object;
146         let lib = libloading::Library::new(&path).unwrap();
147         let obj = std::fs::read(path).unwrap();
148         let obj = object::File::parse(&obj).unwrap();
149         imported_symbols.extend(obj.dynamic_symbols().filter_map(|(_idx, symbol)| {
150             let name = symbol.name().unwrap().to_string();
151             if name.is_empty() || !symbol.is_global() || symbol.is_undefined() {
152                 return None;
153             }
154             let dlsym_name = if cfg!(target_os = "macos") {
155                 // On macOS `dlsym` expects the name without leading `_`.
156                 assert!(name.starts_with("_"), "{:?}", name);
157                 &name[1..]
158             } else {
159                 &name
160             };
161             let symbol: libloading::Symbol<*const u8> =
162                 unsafe { lib.get(dlsym_name.as_bytes()) }.unwrap();
163             Some((name, *symbol))
164         }));
165         std::mem::forget(lib)
166     }
167
168     tcx.sess.abort_if_errors();
169
170     imported_symbols
171 }
172
173 fn run_aot(
174     tcx: TyCtxt<'_>,
175     metadata: EncodedMetadata,
176     need_metadata_module: bool,
177 ) -> Box<(CodegenResults, FxHashMap<WorkProductId, WorkProduct>)> {
178     let mut work_products = FxHashMap::default();
179
180     fn new_module(tcx: TyCtxt<'_>, name: String) -> Module<crate::backend::Backend> {
181         let module = crate::backend::make_module(tcx.sess, name);
182         assert_eq!(pointer_ty(tcx), module.target_config().pointer_type());
183         module
184     };
185
186     struct ModuleCodegenResult(CompiledModule, Option<(WorkProductId, WorkProduct)>);
187
188     use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
189
190     impl<HCX> HashStable<HCX> for ModuleCodegenResult {
191         fn hash_stable(&self, _: &mut HCX, _: &mut StableHasher) {
192             // do nothing
193         }
194     }
195
196     fn emit_module<B: Backend>(
197         tcx: TyCtxt<'_>,
198         name: String,
199         kind: ModuleKind,
200         mut module: Module<B>,
201         debug: Option<DebugContext>,
202     ) -> ModuleCodegenResult
203         where B::Product: Emit + WriteDebugInfo,
204     {
205             module.finalize_definitions();
206             let mut product = module.finish();
207
208             if let Some(mut debug) = debug {
209                 debug.emit(&mut product);
210             }
211
212             let tmp_file = tcx
213                 .output_filenames(LOCAL_CRATE)
214                 .temp_path(OutputType::Object, Some(&name));
215             let obj = product.emit();
216             std::fs::write(&tmp_file, obj).unwrap();
217
218             let work_product = if std::env::var("CG_CLIF_INCR_CACHE_DISABLED").is_ok() {
219                 None
220             } else {
221                 rustc_incremental::copy_cgu_workproducts_to_incr_comp_cache_dir(
222                     tcx.sess,
223                     &name,
224                     &[(WorkProductFileKind::Object, tmp_file.clone())],
225                 )
226             };
227
228             ModuleCodegenResult(
229                 CompiledModule {
230                     name,
231                     kind,
232                     object: Some(tmp_file),
233                     bytecode: None,
234                     bytecode_compressed: None,
235                 },
236                 work_product,
237             )
238         };
239
240     let (_, cgus) = tcx.collect_and_partition_mono_items(LOCAL_CRATE);
241
242     if tcx.dep_graph.is_fully_enabled() {
243         for cgu in &*cgus {
244             tcx.codegen_unit(cgu.name());
245         }
246     }
247
248     let modules = time(tcx, "codegen mono items", || {
249         cgus.iter().map(|cgu| {
250             let cgu_reuse = determine_cgu_reuse(tcx, cgu);
251             tcx.sess.cgu_reuse_tracker.set_actual_reuse(&cgu.name().as_str(), cgu_reuse);
252
253             match cgu_reuse {
254                 _ if std::env::var("CG_CLIF_INCR_CACHE_DISABLED").is_ok() => {}
255                 CguReuse::No => {}
256                 CguReuse::PreLto => {
257                     let incr_comp_session_dir = tcx.sess.incr_comp_session_dir();
258                     let mut object = None;
259                     let work_product = cgu.work_product(tcx);
260                     for (kind, saved_file) in &work_product.saved_files {
261                         let obj_out = match kind {
262                             WorkProductFileKind::Object => {
263                                 let path = tcx.output_filenames(LOCAL_CRATE).temp_path(OutputType::Object, Some(&cgu.name().as_str()));
264                                 object = Some(path.clone());
265                                 path
266                             }
267                             WorkProductFileKind::Bytecode | WorkProductFileKind::BytecodeCompressed => {
268                                 panic!("cg_clif doesn't use bytecode");
269                             }
270                         };
271                         let source_file = rustc_incremental::in_incr_comp_dir(&incr_comp_session_dir, &saved_file);
272                         if let Err(err) = rustc_fs_util::link_or_copy(&source_file, &obj_out) {
273                             tcx.sess.err(&format!(
274                                 "unable to copy {} to {}: {}",
275                                 source_file.display(),
276                                 obj_out.display(),
277                                 err
278                             ));
279                         }
280                     }
281
282                     work_products.insert(cgu.work_product_id(), work_product);
283
284                     return CompiledModule {
285                         name: cgu.name().to_string(),
286                         kind: ModuleKind::Regular,
287                         object,
288                         bytecode: None,
289                         bytecode_compressed: None,
290                     };
291                 }
292                 CguReuse::PostLto => unreachable!(),
293             }
294
295             let dep_node = cgu.codegen_dep_node(tcx);
296             let (ModuleCodegenResult(module, work_product), _) =
297                 tcx.dep_graph.with_task(dep_node, tcx, cgu.name(), module_codegen, rustc::dep_graph::hash_result);
298
299             fn module_codegen(tcx: TyCtxt<'_>, cgu_name: rustc_span::Symbol) -> ModuleCodegenResult {
300                 let cgu = tcx.codegen_unit(cgu_name);
301                 let mono_items = cgu.items_in_deterministic_order(tcx);
302
303                 let mut module = new_module(tcx, cgu_name.as_str().to_string());
304
305                 let mut debug = if tcx.sess.opts.debuginfo != DebugInfo::None {
306                     let debug = DebugContext::new(
307                         tcx,
308                         module.target_config().pointer_type().bytes() as u8,
309                     );
310                     Some(debug)
311                 } else {
312                     None
313                 };
314
315                 codegen_mono_items(tcx, &mut module, debug.as_mut(), mono_items);
316                 crate::main_shim::maybe_create_entry_wrapper(tcx, &mut module);
317
318                 emit_module(
319                     tcx,
320                     cgu.name().as_str().to_string(),
321                     ModuleKind::Regular,
322                     module,
323                     debug,
324                 )
325             }
326
327             if let Some((id, product)) = work_product {
328                 work_products.insert(id, product);
329             }
330
331             module
332         }).collect::<Vec<_>>()
333     });
334
335     tcx.sess.abort_if_errors();
336
337     let mut allocator_module = new_module(tcx, "allocator_shim".to_string());
338     let created_alloc_shim = crate::allocator::codegen(tcx, &mut allocator_module);
339
340     let allocator_module = if created_alloc_shim {
341         let ModuleCodegenResult(module, work_product) = emit_module(
342             tcx,
343             "allocator_shim".to_string(),
344             ModuleKind::Allocator,
345             allocator_module,
346             None,
347         );
348         if let Some((id, product)) = work_product {
349             work_products.insert(id, product);
350         }
351         Some(module)
352     } else {
353         None
354     };
355
356     rustc_incremental::assert_dep_graph(tcx);
357     rustc_incremental::save_dep_graph(tcx);
358
359     let metadata_module = if need_metadata_module {
360         let _timer = tcx.prof.generic_activity("codegen crate metadata");
361         let (metadata_cgu_name, tmp_file) = tcx.sess.time("write compressed metadata", || {
362             use rustc::mir::mono::CodegenUnitNameBuilder;
363
364             let cgu_name_builder = &mut CodegenUnitNameBuilder::new(tcx);
365             let metadata_cgu_name = cgu_name_builder
366                 .build_cgu_name(LOCAL_CRATE, &["crate"], Some("metadata"))
367                 .as_str()
368                 .to_string();
369
370             let tmp_file = tcx
371                 .output_filenames(LOCAL_CRATE)
372                 .temp_path(OutputType::Metadata, Some(&metadata_cgu_name));
373
374             let obj = crate::backend::with_object(tcx.sess, &metadata_cgu_name, |object| {
375                 crate::metadata::write_metadata(tcx, object);
376             });
377
378             std::fs::write(&tmp_file, obj).unwrap();
379
380             (metadata_cgu_name, tmp_file)
381         });
382
383         Some(CompiledModule {
384             name: metadata_cgu_name,
385             kind: ModuleKind::Metadata,
386             object: Some(tmp_file),
387             bytecode: None,
388             bytecode_compressed: None,
389         })
390     } else {
391         None
392     };
393
394     Box::new((CodegenResults {
395         crate_name: tcx.crate_name(LOCAL_CRATE),
396         modules,
397         allocator_module,
398         metadata_module,
399         crate_hash: tcx.crate_hash(LOCAL_CRATE),
400         metadata,
401         windows_subsystem: None, // Windows is not yet supported
402         linker_info: LinkerInfo::new(tcx),
403         crate_info: CrateInfo::new(tcx),
404     }, work_products))
405 }
406
407 fn codegen_mono_items<'tcx>(
408     tcx: TyCtxt<'tcx>,
409     module: &mut Module<impl Backend + 'static>,
410     debug_context: Option<&mut DebugContext<'tcx>>,
411     mono_items: Vec<(MonoItem<'tcx>, (RLinkage, Visibility))>,
412 ) {
413     let mut cx = CodegenCx::new(tcx, module, debug_context);
414
415     tcx.sess.time("predefine functions", || {
416         for &(mono_item, (linkage, visibility)) in &mono_items {
417             match mono_item {
418                 MonoItem::Fn(instance) => {
419                     let (name, sig) =
420                         get_function_name_and_sig(tcx, cx.module.isa().triple(), instance, false);
421                     let linkage = crate::linkage::get_clif_linkage(mono_item, linkage, visibility);
422                     cx.module.declare_function(&name, linkage, &sig).unwrap();
423                 }
424                 MonoItem::Static(_) | MonoItem::GlobalAsm(_) => {}
425             }
426         }
427     });
428
429     for (mono_item, (linkage, visibility)) in mono_items {
430         crate::unimpl::try_unimpl(tcx, || {
431             let linkage = crate::linkage::get_clif_linkage(mono_item, linkage, visibility);
432             trans_mono_item(&mut cx, mono_item, linkage);
433         });
434     }
435
436     tcx.sess.time("finalize CodegenCx", || cx.finalize());
437 }
438
439 fn trans_mono_item<'clif, 'tcx, B: Backend + 'static>(
440     cx: &mut crate::CodegenCx<'clif, 'tcx, B>,
441     mono_item: MonoItem<'tcx>,
442     linkage: Linkage,
443 ) {
444     let tcx = cx.tcx;
445     match mono_item {
446         MonoItem::Fn(inst) => {
447             let _inst_guard =
448                 PrintOnPanic(|| format!("{:?} {}", inst, tcx.symbol_name(inst).name.as_str()));
449             debug_assert!(!inst.substs.needs_infer());
450             let _mir_guard = PrintOnPanic(|| {
451                 match inst.def {
452                     InstanceDef::Item(_)
453                     | InstanceDef::DropGlue(_, _)
454                     | InstanceDef::Virtual(_, _) => {
455                         let mut mir = ::std::io::Cursor::new(Vec::new());
456                         crate::rustc_mir::util::write_mir_pretty(
457                             tcx,
458                             Some(inst.def_id()),
459                             &mut mir,
460                         )
461                         .unwrap();
462                         String::from_utf8(mir.into_inner()).unwrap()
463                     }
464                     _ => {
465                         // FIXME fix write_mir_pretty for these instances
466                         format!("{:#?}", tcx.instance_mir(inst.def))
467                     }
468                 }
469             });
470
471             cx.tcx.sess.time("codegen fn", || crate::base::trans_fn(cx, inst, linkage));
472         }
473         MonoItem::Static(def_id) => {
474             crate::constant::codegen_static(&mut cx.constants_cx, def_id);
475         }
476         MonoItem::GlobalAsm(hir_id) => {
477             let item = tcx.hir().expect_item(hir_id);
478             if let rustc_hir::ItemKind::GlobalAsm(rustc_hir::GlobalAsm { asm }) = item.kind {
479                 // FIXME implement global asm using an external assembler
480                 if asm.as_str().contains("__rust_probestack") {
481                     return;
482                 } else {
483                     tcx
484                         .sess
485                         .fatal(&format!("Unimplemented global asm mono item \"{}\"", asm));
486                 }
487             } else {
488                 bug!("Expected GlobalAsm found {:?}", item);
489             }
490         }
491     }
492 }
493
494 fn time<R>(tcx: TyCtxt<'_>, name: &'static str, f: impl FnOnce() -> R) -> R {
495     if std::env::var("CG_CLIF_DISPLAY_CG_TIME").is_ok() {
496         println!("[{:<30}: {}] start", tcx.crate_name(LOCAL_CRATE), name);
497         let before = std::time::Instant::now();
498         let res = tcx.sess.time(name, f);
499         let after = std::time::Instant::now();
500         println!("[{:<30}: {}] end time: {:?}", tcx.crate_name(LOCAL_CRATE), name, after - before);
501         res
502     } else {
503         tcx.sess.time(name, f)
504     }
505 }
506
507 // Adapted from https://github.com/rust-lang/rust/blob/303d8aff6092709edd4dbd35b1c88e9aa40bf6d8/src/librustc_codegen_ssa/base.rs#L922-L953
508 fn determine_cgu_reuse<'tcx>(tcx: TyCtxt<'tcx>, cgu: &CodegenUnit<'tcx>) -> CguReuse {
509     if !tcx.dep_graph.is_fully_enabled() {
510         return CguReuse::No;
511     }
512
513     let work_product_id = &cgu.work_product_id();
514     if tcx.dep_graph.previous_work_product(work_product_id).is_none() {
515         // We don't have anything cached for this CGU. This can happen
516         // if the CGU did not exist in the previous session.
517         return CguReuse::No;
518     }
519
520     // Try to mark the CGU as green. If it we can do so, it means that nothing
521     // affecting the LLVM module has changed and we can re-use a cached version.
522     // If we compile with any kind of LTO, this means we can re-use the bitcode
523     // of the Pre-LTO stage (possibly also the Post-LTO version but we'll only
524     // know that later). If we are not doing LTO, there is only one optimized
525     // version of each module, so we re-use that.
526     let dep_node = cgu.codegen_dep_node(tcx);
527     assert!(
528         !tcx.dep_graph.dep_node_exists(&dep_node),
529         "CompileCodegenUnit dep-node for CGU `{}` already exists before marking.",
530         cgu.name()
531     );
532
533     if tcx.dep_graph.try_mark_green(tcx, &dep_node).is_some() {
534         CguReuse::PreLto
535     } else {
536         CguReuse::No
537     }
538 }