]> git.lizzy.rs Git - rust.git/commitdiff
debuginfo: Implement discriminator type metadata re-use.
authorMichael Woerister <michaelwoerister@posteo>
Thu, 27 Mar 2014 14:47:13 +0000 (15:47 +0100)
committerAlex Crichton <alex@alexcrichton.com>
Thu, 10 Apr 2014 22:21:57 +0000 (15:21 -0700)
An optimization for sharing the type metadata of generic enum discriminators between monomorphized instances (fixes issue #12840)

src/librustc/middle/trans/debuginfo.rs

index 6f6484ae1a596c61d358f28416bc2c036d8064ab..c2828b333edd1bb66ab962566a37d712de266678 100644 (file)
@@ -130,6 +130,7 @@ struct List {
 use lib::llvm::llvm;
 use lib::llvm::{ModuleRef, ContextRef, ValueRef};
 use lib::llvm::debuginfo::*;
+use metadata::csearch;
 use middle::trans::adt;
 use middle::trans::common::*;
 use middle::trans::datum::{Datum, Lvalue};
@@ -178,6 +179,7 @@ pub struct CrateDebugContext {
     current_debug_location: Cell<DebugLocation>,
     created_files: RefCell<HashMap<~str, DIFile>>,
     created_types: RefCell<HashMap<uint, DIType>>,
+    created_enum_disr_types: RefCell<HashMap<ast::DefId, DIType>>,
     namespace_map: RefCell<HashMap<Vec<ast::Name> , @NamespaceTreeNode>>,
     // This collection is used to assert that composite types (structs, enums, ...) have their
     // members only set once:
@@ -196,6 +198,7 @@ pub fn new(llmod: ModuleRef) -> CrateDebugContext {
             current_debug_location: Cell::new(UnknownLocation),
             created_files: RefCell::new(HashMap::new()),
             created_types: RefCell::new(HashMap::new()),
+            created_enum_disr_types: RefCell::new(HashMap::new()),
             namespace_map: RefCell::new(HashMap::new()),
             composite_types_completed: RefCell::new(HashSet::new()),
         };
@@ -1542,24 +1545,45 @@ fn prepare_enum_metadata(cx: &CrateContext,
         .collect();
 
     let discriminant_type_metadata = |inttype| {
-        let discriminant_llvm_type = adt::ll_inttype(cx, inttype);
-        let (discriminant_size, discriminant_align) = size_and_align_of(cx, discriminant_llvm_type);
-        let discriminant_base_type_metadata = type_metadata(cx, adt::ty_of_inttype(inttype),
-                                                            codemap::DUMMY_SP);
-        enum_name.with_c_str(|enum_name| {
-            unsafe {
-                llvm::LLVMDIBuilderCreateEnumerationType(
-                    DIB(cx),
-                    containing_scope,
-                    enum_name,
-                    file_metadata,
-                    loc.line as c_uint,
-                    bytes_to_bits(discriminant_size),
-                    bytes_to_bits(discriminant_align),
-                    create_DIArray(DIB(cx), enumerators_metadata.as_slice()),
-                    discriminant_base_type_metadata)
+        // We can reuse the type of the discriminant for all monomorphized instances of an enum
+        // because it doesn't depend on any type parameters. The def_id, uniquely identifying the
+        // enum's polytype acts as key in this cache.
+        let cached_discriminant_type_metadata = debug_context(cx).created_enum_disr_types
+                                                                 .borrow()
+                                                                 .find_copy(&enum_def_id);
+        match cached_discriminant_type_metadata {
+            Some(discriminant_type_metadata) => discriminant_type_metadata,
+            None => {
+                let discriminant_llvm_type = adt::ll_inttype(cx, inttype);
+                let (discriminant_size, discriminant_align) =
+                    size_and_align_of(cx, discriminant_llvm_type);
+                let discriminant_base_type_metadata = type_metadata(cx,
+                                                                    adt::ty_of_inttype(inttype),
+                                                                    codemap::DUMMY_SP);
+                let discriminant_name = get_enum_discriminant_name(cx, enum_def_id);
+
+                let discriminant_type_metadata = discriminant_name.get().with_c_str(|name| {
+                    unsafe {
+                        llvm::LLVMDIBuilderCreateEnumerationType(
+                            DIB(cx),
+                            containing_scope,
+                            name,
+                            file_metadata,
+                            loc.line as c_uint,
+                            bytes_to_bits(discriminant_size),
+                            bytes_to_bits(discriminant_align),
+                            create_DIArray(DIB(cx), enumerators_metadata.as_slice()),
+                            discriminant_base_type_metadata)
+                    }
+                });
+
+                debug_context(cx).created_enum_disr_types
+                                 .borrow_mut()
+                                 .insert(enum_def_id, discriminant_type_metadata);
+
+                discriminant_type_metadata
             }
-        })
+        }
     };
 
     let type_rep = adt::represent_type(cx, enum_type);
@@ -1648,6 +1672,16 @@ fn prepare_enum_metadata(cx: &CrateContext,
             }
         }
     };
+
+    fn get_enum_discriminant_name(cx: &CrateContext, def_id: ast::DefId) -> token::InternedString {
+        let name = if def_id.krate == ast::LOCAL_CRATE {
+            cx.tcx.map.get_path_elem(def_id.node).name()
+        } else {
+            csearch::get_item_path(&cx.tcx, def_id).last().unwrap().name()
+        };
+
+        token::get_name(name)
+    }
 }
 
 enum MemberOffset {