]> git.lizzy.rs Git - rust.git/blob - src/librustc_codegen_llvm/debuginfo/create_scope_map.rs
Split out growth functionality into BitVector type
[rust.git] / src / librustc_codegen_llvm / debuginfo / create_scope_map.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 use super::{FunctionDebugContext, FunctionDebugContextData};
12 use super::metadata::file_metadata;
13 use super::utils::{DIB, span_start};
14
15 use llvm;
16 use llvm::debuginfo::DIScope;
17 use common::CodegenCx;
18 use rustc::mir::{Mir, SourceScope};
19
20 use libc::c_uint;
21
22 use syntax_pos::Pos;
23
24 use rustc_data_structures::bitvec::BitArray;
25 use rustc_data_structures::indexed_vec::{Idx, IndexVec};
26
27 use syntax_pos::BytePos;
28
29 #[derive(Clone, Copy, Debug)]
30 pub struct MirDebugScope<'ll> {
31     pub scope_metadata: Option<&'ll DIScope>,
32     // Start and end offsets of the file to which this DIScope belongs.
33     // These are used to quickly determine whether some span refers to the same file.
34     pub file_start_pos: BytePos,
35     pub file_end_pos: BytePos,
36 }
37
38 impl MirDebugScope<'ll> {
39     pub fn is_valid(&self) -> bool {
40         !self.scope_metadata.is_none()
41     }
42 }
43
44 /// Produce DIScope DIEs for each MIR Scope which has variables defined in it.
45 /// If debuginfo is disabled, the returned vector is empty.
46 pub fn create_mir_scopes(
47     cx: &CodegenCx<'ll, '_>,
48     mir: &Mir,
49     debug_context: &FunctionDebugContext<'ll>,
50 ) -> IndexVec<SourceScope, MirDebugScope<'ll>> {
51     let null_scope = MirDebugScope {
52         scope_metadata: None,
53         file_start_pos: BytePos(0),
54         file_end_pos: BytePos(0)
55     };
56     let mut scopes = IndexVec::from_elem(null_scope, &mir.source_scopes);
57
58     let debug_context = match *debug_context {
59         FunctionDebugContext::RegularContext(ref data) => data,
60         FunctionDebugContext::DebugInfoDisabled |
61         FunctionDebugContext::FunctionWithoutDebugInfo => {
62             return scopes;
63         }
64     };
65
66     // Find all the scopes with variables defined in them.
67     let mut has_variables = BitArray::new(mir.source_scopes.len());
68     for var in mir.vars_iter() {
69         let decl = &mir.local_decls[var];
70         has_variables.insert(decl.visibility_scope);
71     }
72
73     // Instantiate all scopes.
74     for idx in 0..mir.source_scopes.len() {
75         let scope = SourceScope::new(idx);
76         make_mir_scope(cx, &mir, &has_variables, debug_context, scope, &mut scopes);
77     }
78
79     scopes
80 }
81
82 fn make_mir_scope(cx: &CodegenCx<'ll, '_>,
83                   mir: &Mir,
84                   has_variables: &BitArray<SourceScope>,
85                   debug_context: &FunctionDebugContextData<'ll>,
86                   scope: SourceScope,
87                   scopes: &mut IndexVec<SourceScope, MirDebugScope<'ll>>) {
88     if scopes[scope].is_valid() {
89         return;
90     }
91
92     let scope_data = &mir.source_scopes[scope];
93     let parent_scope = if let Some(parent) = scope_data.parent_scope {
94         make_mir_scope(cx, mir, has_variables, debug_context, parent, scopes);
95         scopes[parent]
96     } else {
97         // The root is the function itself.
98         let loc = span_start(cx, mir.span);
99         scopes[scope] = MirDebugScope {
100             scope_metadata: Some(debug_context.fn_metadata),
101             file_start_pos: loc.file.start_pos,
102             file_end_pos: loc.file.end_pos,
103         };
104         return;
105     };
106
107     if !has_variables.contains(scope) {
108         // Do not create a DIScope if there are no variables
109         // defined in this MIR Scope, to avoid debuginfo bloat.
110
111         // However, we don't skip creating a nested scope if
112         // our parent is the root, because we might want to
113         // put arguments in the root and not have shadowing.
114         if parent_scope.scope_metadata.unwrap() != debug_context.fn_metadata {
115             scopes[scope] = parent_scope;
116             return;
117         }
118     }
119
120     let loc = span_start(cx, scope_data.span);
121     let file_metadata = file_metadata(cx,
122                                       &loc.file.name,
123                                       debug_context.defining_crate);
124
125     let scope_metadata = unsafe {
126         Some(llvm::LLVMRustDIBuilderCreateLexicalBlock(
127             DIB(cx),
128             parent_scope.scope_metadata.unwrap(),
129             file_metadata,
130             loc.line as c_uint,
131             loc.col.to_usize() as c_uint))
132     };
133     scopes[scope] = MirDebugScope {
134         scope_metadata,
135         file_start_pos: loc.file.start_pos,
136         file_end_pos: loc.file.end_pos,
137     };
138 }