From 3c2b6110ddb99e3d4b67c15321b957bdd4b37671 Mon Sep 17 00:00:00 2001
From: Patrick Walton <pcwalton@mimiga.net>
Date: Fri, 21 Sep 2012 11:42:47 -0700
Subject: [PATCH] rustc: Shove the address of the box annihilator into the
 crate map

---
 src/rt/rust_crate_map.cpp      |  6 ++--
 src/rt/rust_crate_map.h        | 62 ++++++++++++++++++++++++++++++++--
 src/rt/rust_log.cpp            |  6 ++--
 src/rustc/middle/trans/base.rs | 22 ++++++++++--
 4 files changed, 84 insertions(+), 12 deletions(-)

diff --git a/src/rt/rust_crate_map.cpp b/src/rt/rust_crate_map.cpp
index 633361bb932..9f6c18d9207 100644
--- a/src/rt/rust_crate_map.cpp
+++ b/src/rt/rust_crate_map.cpp
@@ -12,13 +12,13 @@ void iter_crate_map(const cratemap* map,
                     void (*fn)(const mod_entry* map, void *cookie),
                     void *cookie) {
     // First iterate this crate
-    iter_module_map(map->entries, fn, cookie);
+    iter_module_map(map->entries(), fn, cookie);
     // Then recurse on linked crates
     // FIXME (#2673) this does double work in diamond-shaped deps. could
     //   keep a set of visited addresses, if it turns out to be actually
     //   slow
-    for (size_t i = 0; map->children[i]; i++) {
-        iter_crate_map(map->children[i], fn, cookie);
+    for (cratemap::iterator i = map->begin(), e = map->end(); i != e; ++i) {
+        iter_crate_map(*i, fn, cookie);
     }
 }
 
diff --git a/src/rt/rust_crate_map.h b/src/rt/rust_crate_map.h
index 453feb36e57..bdb0630a1af 100644
--- a/src/rt/rust_crate_map.h
+++ b/src/rt/rust_crate_map.h
@@ -2,15 +2,71 @@
 #define RUST_CRATE_MAP_H
 
 #include "rust_log.h"
+#include <stdint.h>
 
 struct mod_entry {
     const char* name;
     uint32_t* state;
 };
 
-struct cratemap {
-    const mod_entry* entries;
-    const cratemap* children[1];
+class cratemap;
+
+class cratemap_v0 {
+    friend class cratemap;
+    const mod_entry *m_entries;
+    const cratemap* m_children[1];
+};
+
+class cratemap {
+private:
+    int32_t m_version;
+    const void *m_annihilate_fn;
+    const mod_entry* m_entries;
+    const cratemap* m_children[1];
+
+    inline int32_t version() const {
+        switch (m_version) {
+        case 1:     return 1;
+        default:    return 0;
+        }
+    }
+
+public:
+    typedef const cratemap *const *iterator;
+
+    inline const void *annihilate_fn() const {
+        switch (version()) {
+        case 0: return NULL;
+        case 1: return m_annihilate_fn;
+        default: assert(false && "Unknown crate map version!");
+        }
+    }
+
+    inline const mod_entry *entries() const {
+        switch (version()) {
+        case 0: return reinterpret_cast<const cratemap_v0 *>(this)->m_entries;
+        case 1: return m_entries;
+        default: assert(false && "Unknown crate map version!");
+        }
+    }
+
+    inline const iterator begin() const {
+        switch (version()) {
+        case 0:
+            return &reinterpret_cast<const cratemap_v0 *>(this)->
+                m_children[0];
+        case 1:
+            return &m_children[1];
+        default: assert(false && "Unknown crate map version!");
+        }
+    }
+
+    inline const iterator end() const {
+        iterator i = begin();
+        while (*i)
+            i++;
+        return i;
+    }
 };
 
 void iter_module_map(const mod_entry* map,
diff --git a/src/rt/rust_log.cpp b/src/rt/rust_log.cpp
index 666183fcdd3..11671cf0326 100644
--- a/src/rt/rust_log.cpp
+++ b/src/rt/rust_log.cpp
@@ -236,11 +236,11 @@ void update_crate_map(const cratemap* map, log_directive* dirs,
 }
 
 void print_crate_log_map(const cratemap* map) {
-    for (const mod_entry* cur = map->entries; cur->name; cur++) {
+    for (const mod_entry* cur = map->entries(); cur->name; cur++) {
         printf("  %s\n", cur->name);
     }
-    for (size_t i = 0; map->children[i]; i++) {
-        print_crate_log_map(map->children[i]);
+    for (cratemap::iterator i = map->begin(), e = map->end(); i != e; ++i) {
+        print_crate_log_map(*i);
     }
 }
 
diff --git a/src/rustc/middle/trans/base.rs b/src/rustc/middle/trans/base.rs
index 3cd80a6e572..aaed7d35343 100644
--- a/src/rustc/middle/trans/base.rs
+++ b/src/rustc/middle/trans/base.rs
@@ -2478,7 +2478,7 @@ fn decl_crate_map(sess: session::session, mapmeta: link_meta,
     } else { ~"toplevel" };
     let sym_name = ~"_rust_crate_map_" + mapname;
     let arrtype = T_array(int_type, n_subcrates as uint);
-    let maptype = T_struct(~[int_type, arrtype]);
+    let maptype = T_struct(~[T_i32(), T_ptr(T_i8()), int_type, arrtype]);
     let map = str::as_c_str(sym_name, |buf| {
         llvm::LLVMAddGlobal(llmod, maptype, buf)
     });
@@ -2502,9 +2502,25 @@ fn fill_crate_map(ccx: @crate_ctxt, map: ValueRef) {
         i += 1;
     }
     vec::push(subcrates, C_int(ccx, 0));
+
+    let llannihilatefn;
+    let annihilate_def_id = ccx.tcx.lang_items.annihilate_fn.get();
+    if annihilate_def_id.crate == ast::local_crate {
+        llannihilatefn = get_item_val(ccx, annihilate_def_id.node);
+    } else {
+        let annihilate_fn_type = csearch::get_type(ccx.tcx,
+                                                   annihilate_def_id).ty;
+        llannihilatefn = trans_external_path(ccx,
+                                             annihilate_def_id,
+                                             annihilate_fn_type);
+    }
+
     llvm::LLVMSetInitializer(map, C_struct(
-        ~[p2i(ccx, create_module_map(ccx)),
-         C_array(ccx.int_type, subcrates)]));
+        ~[C_i32(1),
+          lib::llvm::llvm::LLVMConstPointerCast(llannihilatefn,
+                                                T_ptr(T_i8())),
+          p2i(ccx, create_module_map(ccx)),
+          C_array(ccx.int_type, subcrates)]));
 }
 
 fn crate_ctxt_to_encode_parms(cx: @crate_ctxt)