]> git.lizzy.rs Git - rust.git/commitdiff
debuginfo: Big cleanup refactoring and support for foreign_item_fn.
authorMichael Woerister <michaelwoerister@gmail>
Fri, 16 Aug 2013 16:46:29 +0000 (18:46 +0200)
committerMichael Woerister <michaelwoerister@gmail>
Thu, 22 Aug 2013 08:58:01 +0000 (10:58 +0200)
src/librustc/middle/trans/base.rs
src/librustc/middle/trans/debuginfo.rs

index f19decaa38cde1b9f7e37d6eb9a4860c5ec3c150..9d5d80373ab00e9e389444842a64896392b93a47 100644 (file)
@@ -136,6 +136,13 @@ fn fcx_has_nonzero_span(fcx: &FunctionContext) -> bool {
     }
 }
 
+fn span_is_empty(opt_span: &Option<span>) -> bool {
+    match *opt_span {
+        None => true,
+        Some(span) => *span.lo == 0 && *span.hi == 0
+    }
+}
+
 struct StatRecorder<'self> {
     ccx: @mut CrateContext,
     name: &'self str,
@@ -1623,6 +1630,13 @@ pub fn new_fn_ctxt_w_id(ccx: @mut CrateContext,
         }
     };
     let uses_outptr = type_of::return_uses_outptr(ccx.tcx, substd_output_type);
+
+    let debug_context = if id != -1 && ccx.sess.opts.debuginfo && !span_is_empty(&sp) {
+        Some(debuginfo::create_function_debug_context(ccx, id, param_substs, llfndecl))
+    } else {
+        None
+    };
+
     let fcx = @mut FunctionContext {
           llfn: llfndecl,
           llenv: unsafe {
@@ -1643,7 +1657,7 @@ pub fn new_fn_ctxt_w_id(ccx: @mut CrateContext,
           span: sp,
           path: path,
           ccx: ccx,
-          debug_context: None,
+          debug_context: debug_context,
     };
     fcx.llenv = unsafe {
           llvm::LLVMGetParam(llfndecl, fcx.env_arg_pos() as c_uint)
@@ -1880,10 +1894,6 @@ pub fn trans_closure(ccx: @mut CrateContext,
         set_fixed_stack_segment(fcx.llfn);
     }
 
-    if ccx.sess.opts.debuginfo && fcx_has_nonzero_span(fcx) {
-        debuginfo::create_function_metadata(fcx);
-    }
-
     // Create the first basic block in the function and keep a handle on it to
     //  pass to finish_fn later.
     let bcx_top = fcx.entry_bcx.unwrap();
index f5073cc71e5d031559a410f17a27f85cd0d094ab..0f9fa61c668bffae359056b9eaab76ca5539e102 100644 (file)
@@ -98,9 +98,7 @@ pub struct DebugContext {
     priv builder: DIBuilderRef,
     priv curr_loc: (uint, uint),
     priv created_files: HashMap<~str, DIFile>,
-    priv created_functions: HashMap<FunctionCacheKey, DISubprogram>,
-    priv created_blocks: HashMap<ast::NodeId, DILexicalBlock>,
-    priv created_types: HashMap<uint, DIType>
+    priv created_types: HashMap<uint, DIType>,
 }
 
 impl DebugContext {
@@ -115,29 +113,14 @@ pub fn new(llmod: ModuleRef, crate: ~str) -> DebugContext {
             builder: builder,
             curr_loc: (0, 0),
             created_files: HashMap::new(),
-            created_functions: HashMap::new(),
-            created_blocks: HashMap::new(),
-            created_types: HashMap::new()
+            created_types: HashMap::new(),
         };
     }
 }
 
-#[deriving(Eq,IterBytes)]
-struct FunctionCacheKey {
-    // Use the address of the llvm function (FunctionContext::llfn) as key for the cache. This
-    // nicely takes care of monomorphization, where two specializations will have the same
-    // ast::NodeId but different llvm functions (each needing its own debug description).
-    priv llfn: ValueRef
-}
-
-impl FunctionCacheKey {
-    fn for_function_context(fcx: &FunctionContext) -> FunctionCacheKey {
-        FunctionCacheKey { llfn: fcx.llfn }
-    }
-}
-
 pub struct FunctionDebugContext {
     priv scope_map: HashMap<ast::NodeId, DIScope>,
+    priv fn_metadata: DISubprogram,
     priv argument_counter: uint,
 }
 
@@ -194,7 +177,14 @@ pub fn create_self_argument_metadata(bcx: @mut Block,
 
     let loc = span_start(cx, span);
     let type_metadata = type_metadata(cx, variable_type, span);
-    let scope = create_function_metadata(bcx.fcx);
+    let scope = bcx.fcx.debug_context.get_ref().fn_metadata;
+
+    let argument_index = {
+        let counter = &mut bcx.fcx.debug_context.get_mut_ref().argument_counter;
+        let argument_index = *counter;
+        *counter += 1;
+        argument_index as c_uint
+    };
 
     let var_metadata = do cx.sess.str_of(special_idents::self_).to_c_str().with_ref |name| {
         unsafe {
@@ -208,7 +198,7 @@ pub fn create_self_argument_metadata(bcx: @mut Block,
                 type_metadata,
                 false,
                 0,
-                1)
+                argument_index)
         }
     };
 
@@ -243,7 +233,7 @@ pub fn create_argument_metadata(bcx: @mut Block,
 
     let def_map = cx.tcx.def_map;
     let file_metadata = file_metadata(cx, filename);
-    let scope = create_function_metadata(fcx);
+    let scope = bcx.fcx.debug_context.get_ref().fn_metadata;//create_function_metadata(fcx);
 
     do pat_util::pat_bindings(def_map, pattern) |_, node_id, span, path_ref| {
 
@@ -318,33 +308,25 @@ pub fn update_source_pos(fcx: &FunctionContext,
     set_debug_location(cx, scope, loc.line, loc.col.to_uint());
 }
 
-/// Creates debug information for the given function.
-///
-/// Adds the created metadata nodes directly to the crate's IR.
-/// The return value should be ignored if called from outside of the debuginfo module.
-pub fn create_function_metadata(fcx: &mut FunctionContext) -> DISubprogram {
-    let cx = fcx.ccx;
-    let cache_key = FunctionCacheKey::for_function_context(fcx);
-
-    match dbg_cx(cx).created_functions.find_copy(&cache_key) {
-        Some(fn_metadata) => {
-            assert!(fcx.debug_context.is_some());
-            return fn_metadata;
-        }
-        None => { /* fallthrough */}
-    }
+pub fn create_function_debug_context(cx: &mut CrateContext,
+                                     fn_ast_id: ast::NodeId,
+                                     param_substs: Option<@param_substs>,
+                                     llfn: ValueRef) -> ~FunctionDebugContext {
+    assert!(fn_ast_id != -1);
 
     let empty_generics = ast::Generics { lifetimes: opt_vec::Empty, ty_params: opt_vec::Empty };
 
-    let fnitem = cx.tcx.items.get_copy(&fcx.id);
-    let (ident, fn_decl, generics, span) = match fnitem {
+    let fnitem = cx.tcx.items.get_copy(&fn_ast_id);
+    let (ident, fn_decl, generics, top_level_block, span) = match fnitem {
         ast_map::node_item(ref item, _) => {
             match item.node {
-                ast::item_fn(ref fn_decl, _, _, ref generics, _) => {
-                    (item.ident, fn_decl, generics, item.span)
+                ast::item_fn(ref fn_decl, _, _, ref generics, ref top_level_block) => {
+                    (item.ident, fn_decl, generics, Some(top_level_block), item.span)
+                }
+                _ => {
+                    cx.sess.span_bug(item.span,
+                        "create_function_debug_context: item bound to non-function");
                 }
-                _ => fcx.ccx.sess.span_bug(item.span,
-                                           "create_function_metadata: item bound to non-function")
             }
         }
         ast_map::node_method(
@@ -352,25 +334,27 @@ pub fn create_function_metadata(fcx: &mut FunctionContext) -> DISubprogram {
                 decl: ref fn_decl,
                 ident: ident,
                 generics: ref generics,
+                body: ref top_level_block,
                 span: span,
                 _
             },
             _,
             _) => {
-            (ident, fn_decl, generics, span)
+            (ident, fn_decl, generics, Some(top_level_block), span)
         }
         ast_map::node_expr(ref expr) => {
             match expr.node {
-                ast::expr_fn_block(ref fn_decl, _) => {
+                ast::expr_fn_block(ref fn_decl, ref top_level_block) => {
                     let name = gensym_name("fn");
                     (name, fn_decl,
                         // This is not quite right. It should actually inherit the generics of the
                         // enclosing function.
                         &empty_generics,
+                        Some(top_level_block),
                         expr.span)
                 }
-                _ => fcx.ccx.sess.span_bug(expr.span,
-                        "create_function_metadata: expected an expr_fn_block here")
+                _ => cx.sess.span_bug(expr.span,
+                        "create_function_debug_context: expected an expr_fn_block here")
             }
         }
         ast_map::node_trait_method(
@@ -379,34 +363,43 @@ pub fn create_function_metadata(fcx: &mut FunctionContext) -> DISubprogram {
                     decl: ref fn_decl,
                     ident: ident,
                     generics: ref generics,
+                    body: ref top_level_block,
                     span: span,
                     _
                 }),
             _,
             _) => {
-            (ident, fn_decl, generics, span)
+            (ident, fn_decl, generics, Some(top_level_block), span)
+        }
+        ast_map::node_foreign_item(@ast::foreign_item {
+                ident: ident,
+                node: ast::foreign_item_fn(ref fn_decl, ref generics),
+                span: span,
+                _
+            },
+            _,
+            _,
+            _) => {
+            (ident, fn_decl, generics, None, span)
         }
-        _ => fcx.ccx.sess.bug(fmt!("create_function_metadata: unexpected sort of node: %?", fnitem))
+        _ => cx.sess.bug(fmt!("create_function_debug_context: unexpected sort of node: %?", fnitem))
     };
 
-    debug!("create_function_metadata: %s, %s",
-           cx.sess.str_of(ident),
-           cx.sess.codemap.span_to_str(span));
-
     let loc = span_start(cx, span);
     let file_metadata = file_metadata(cx, loc.file.name);
 
     let function_type_metadata = unsafe {
-        let fn_signature = get_function_signature(fcx, fn_decl);
+        let fn_signature = get_function_signature(cx, fn_ast_id, fn_decl, param_substs);
         llvm::LLVMDIBuilderCreateSubroutineType(DIB(cx), file_metadata, fn_signature)
     };
 
     // get_template_parameters() will append a `<...>` clause to the function name if necessary.
     let mut function_name = cx.sess.str_of(ident).to_owned();
-    let template_parameters = get_template_parameters(fcx,
-                                                      generics,
-                                                      file_metadata,
-                                                      &mut function_name);
+    let template_parameters = if cx.sess.opts.extra_debuginfo {
+        get_template_parameters(cx, generics, param_substs, file_metadata, &mut function_name)
+    } else {
+        ptr::null()
+    };
 
     let fn_metadata = do function_name.to_c_str().with_ref |function_name| {
         unsafe {
@@ -423,46 +416,29 @@ pub fn create_function_metadata(fcx: &mut FunctionContext) -> DISubprogram {
                 loc.line as c_uint,
                 FlagPrototyped as c_uint,
                 cx.sess.opts.optimize != session::No,
-                fcx.llfn,
+                llfn,
                 template_parameters,
                 ptr::null())
         }
     };
 
-    dbg_cx(cx).created_functions.insert(cache_key, fn_metadata);
-
     // Initialize fn debug context (including scope map)
-    {
-        assert!(fcx.debug_context.is_none());
-
-        let mut fn_debug_context = ~FunctionDebugContext {
-            scope_map: HashMap::new(),
-            argument_counter: if fcx.llself.is_some() { 2 } else { 1 }
-        };
-
-        let entry_block_id = fcx.entry_bcx.get_ref().node_info.get_ref().id;
-        let entry_block = cx.tcx.items.get(&entry_block_id);
-
-        match *entry_block {
-            ast_map::node_block(ref block) => {
-                let scope_map = &mut fn_debug_context.scope_map;
-                let arg_pats = do fn_decl.inputs.map |arg_ref| { arg_ref.pat };
-
-                populate_scope_map(cx, arg_pats, block, fn_metadata, scope_map);
-            }
-            _ => cx.sess.span_bug(span,
-                    fmt!("debuginfo::create_function_metadata() - \
-                         FunctionContext::entry_bcx::node_info points to wrong type of ast_map \
-                         entry. Expected: ast_map::node_block, actual: %?", *entry_block))
-        }
+    let mut fn_debug_context = ~FunctionDebugContext {
+        scope_map: HashMap::new(),
+        fn_metadata: fn_metadata,
+        argument_counter: 1,
+    };
 
-        fcx.debug_context = Some(fn_debug_context);
-    }
+    let arg_pats = do fn_decl.inputs.map |arg_ref| { arg_ref.pat };
+    populate_scope_map(cx, arg_pats, top_level_block, fn_metadata, &mut fn_debug_context.scope_map);
 
-    return fn_metadata;
+    return fn_debug_context;
 
-    fn get_function_signature(fcx: &FunctionContext, fn_decl: &ast::fn_decl) -> DIArray {
-        let cx = fcx.ccx;
+    fn get_function_signature(cx: &mut CrateContext,
+                              fn_ast_id: ast::NodeId,
+                              fn_decl: &ast::fn_decl,
+                              param_substs: Option<@param_substs>) -> DIArray {
+        //let cx = fcx.ccx;
 
         if !cx.sess.opts.extra_debuginfo {
             return create_DIArray(DIB(cx), []);
@@ -476,8 +452,8 @@ fn get_function_signature(fcx: &FunctionContext, fn_decl: &ast::fn_decl) -> DIAr
                 signature.push(ptr::null());
             }
             _ => {
-                let return_type = ty::node_id_to_type(cx.tcx, fcx.id);
-                let return_type = match fcx.param_substs {
+                let return_type = ty::node_id_to_type(cx.tcx, fn_ast_id);
+                let return_type = match param_substs {
                     None => return_type,
                     Some(substs) => {
                         ty::subst_tps(cx.tcx, substs.tys, substs.self_ty, return_type)
@@ -491,7 +467,7 @@ fn get_function_signature(fcx: &FunctionContext, fn_decl: &ast::fn_decl) -> DIAr
         // arguments types
         for arg in fn_decl.inputs.iter() {
             let arg_type = ty::node_id_to_type(cx.tcx, arg.pat.id);
-            let arg_type = match fcx.param_substs {
+            let arg_type = match param_substs {
                 None => arg_type,
                 Some(substs) => {
                     ty::subst_tps(cx.tcx, substs.tys, substs.self_ty, arg_type)
@@ -504,14 +480,13 @@ fn get_function_signature(fcx: &FunctionContext, fn_decl: &ast::fn_decl) -> DIAr
         return create_DIArray(DIB(cx), signature);
     }
 
-    fn get_template_parameters(fcx: &FunctionContext,
+    fn get_template_parameters(cx: &mut CrateContext,
                                generics: &ast::Generics,
+                               param_substs: Option<@param_substs>,
                                file_metadata: DIFile,
                                name_to_append_suffix_to: &mut ~str)
                             -> DIArray {
-        let cx = fcx.ccx;
-
-        let self_type = match fcx.param_substs {
+        let self_type = match param_substs {
             Some(@param_substs{ self_ty: self_type, _ }) => self_type,
             _ => None
         };
@@ -561,7 +536,7 @@ fn get_template_parameters(fcx: &FunctionContext,
         }
 
         // Handle other generic parameters
-        let actual_types = match fcx.param_substs {
+        let actual_types = match param_substs {
             Some(@param_substs { tys: ref types, _ }) => types,
             None => {
                 return create_DIArray(DIB(cx), template_params);
@@ -604,7 +579,6 @@ fn get_template_parameters(fcx: &FunctionContext,
 
 
 
-
 //=-------------------------------------------------------------------------------------------------
 // Module-Internal debug info creation functions
 //=-------------------------------------------------------------------------------------------------
@@ -1424,7 +1398,11 @@ fn create_pointer_to_box_metadata(cx: &mut CrateContext,
         ty::ty_tup(ref elements) => {
             tuple_metadata(cx, t, *elements, span)
         },
-        _ => cx.sess.bug("debuginfo: unexpected type in type_metadata")
+        ty::ty_opaque_box => {
+            cx.sess.span_note(span, "debuginfo for ty_opaque_box NYI");
+            unimplemented_type_metadata(cx, t)
+        }
+        _ => cx.sess.bug(fmt!("debuginfo: unexpected type in type_metadata: %?", sty))
     };
 
     dbg_cx(cx).created_types.insert(type_id, type_metadata);
@@ -1498,7 +1476,7 @@ fn assert_fcx_has_span(fcx: &FunctionContext) {
 // shadowing.
 fn populate_scope_map(cx: &mut CrateContext,
                       arg_pats: &[@ast::pat],
-                      fn_entry_block: &ast::Block,
+                      fn_entry_block: Option<&ast::Block>,
                       fn_metadata: DISubprogram,
                       scope_map: &mut HashMap<ast::NodeId, DIScope>) {
     let def_map = cx.tcx.def_map;
@@ -1519,7 +1497,10 @@ struct ScopeStackEntry {
         }
     }
 
-    walk_block(cx, fn_entry_block, &mut scope_stack, scope_map);
+    for &fn_entry_block in fn_entry_block.iter() {
+        walk_block(cx, fn_entry_block, &mut scope_stack, scope_map);
+    }
+
 
     // local helper functions for walking the AST.
 
@@ -1898,7 +1879,9 @@ fn walk_expr(cx: &mut CrateContext,
                     do with_new_scope(cx, arm_span, scope_stack, scope_map) |cx,
                                                                              scope_stack,
                                                                              scope_map| {
-                        walk_pattern(cx, arm_ref.pats[0], scope_stack, scope_map);
+                        for &pat in arm_ref.pats.iter() {
+                            walk_pattern(cx, pat, scope_stack, scope_map);
+                        }
 
                         for &@ref guard_exp in arm_ref.guard.iter() {
                             walk_expr(cx, guard_exp, scope_stack, scope_map)