2013-09-09 17:04:29 -05:00
|
|
|
// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
|
|
|
|
// file at the top-level directory of this distribution and at
|
|
|
|
// http://rust-lang.org/COPYRIGHT.
|
|
|
|
//
|
|
|
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
|
|
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
|
|
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
|
|
|
// option. This file may not be copied, modified, or distributed
|
|
|
|
// except according to those terms.
|
|
|
|
|
2013-09-15 14:41:02 -05:00
|
|
|
use cast::transmute;
|
2013-09-09 17:04:29 -05:00
|
|
|
use container::MutableSet;
|
2013-09-15 14:41:02 -05:00
|
|
|
use hashmap::HashSet;
|
|
|
|
use libc::c_char;
|
2013-09-09 17:04:29 -05:00
|
|
|
|
2013-09-19 16:22:59 -05:00
|
|
|
// Need to tell the linker on OS X to not barf on undefined symbols
|
|
|
|
// and instead look them up at runtime, which we need to resolve
|
|
|
|
// the crate_map properly.
|
|
|
|
#[cfg(target_os = "macos")]
|
|
|
|
#[link_args = "-undefined dynamic_lookup"]
|
|
|
|
extern {}
|
|
|
|
|
2013-09-23 20:13:21 -05:00
|
|
|
#[cfg(not(windows))]
|
2013-09-18 03:58:52 -05:00
|
|
|
extern {
|
2013-09-18 16:44:04 -05:00
|
|
|
#[weak_linkage]
|
|
|
|
#[link_name = "_rust_crate_map_toplevel"]
|
2013-09-18 03:58:52 -05:00
|
|
|
static CRATE_MAP: CrateMap;
|
|
|
|
}
|
|
|
|
|
|
|
|
pub struct ModEntry {
|
2013-09-09 17:04:29 -05:00
|
|
|
name: *c_char,
|
|
|
|
log_level: *mut u32
|
|
|
|
}
|
2013-09-15 14:41:02 -05:00
|
|
|
|
2013-09-09 17:04:29 -05:00
|
|
|
struct CrateMapV0 {
|
2013-09-15 14:41:02 -05:00
|
|
|
entries: &static [ModEntry],
|
|
|
|
children: &'static [&'static CrateMap]
|
2013-09-09 17:04:29 -05:00
|
|
|
}
|
|
|
|
|
2013-09-24 12:35:42 -05:00
|
|
|
struct CrateMap {
|
|
|
|
version: i32,
|
2013-09-15 14:41:02 -05:00
|
|
|
entries: &static [ModEntry],
|
2013-09-24 12:35:42 -05:00
|
|
|
/// a dynamically sized struct, where all pointers to children are listed adjacent
|
|
|
|
/// to the struct, terminated with NULL
|
|
|
|
children: [*CrateMap, ..1]
|
|
|
|
}
|
|
|
|
|
2013-09-23 20:13:21 -05:00
|
|
|
#[cfg(not(windows))]
|
2013-09-18 03:58:52 -05:00
|
|
|
pub fn get_crate_map() -> *CrateMap {
|
|
|
|
&'static CRATE_MAP as *CrateMap
|
|
|
|
}
|
|
|
|
|
2013-09-23 20:13:21 -05:00
|
|
|
#[cfg(windows)]
|
2013-09-21 21:48:12 -05:00
|
|
|
#[fixed_stack_segment]
|
|
|
|
#[inline(never)]
|
|
|
|
pub fn get_crate_map() -> *CrateMap {
|
|
|
|
use c_str::ToCStr;
|
|
|
|
use unstable::dynamic_lib::dl;
|
|
|
|
|
|
|
|
let sym = unsafe {
|
|
|
|
let module = dl::open_internal();
|
|
|
|
let sym = do "__rust_crate_map_toplevel".with_c_str |buf| {
|
|
|
|
dl::symbol(module, buf)
|
|
|
|
};
|
|
|
|
dl::close(module);
|
|
|
|
sym
|
|
|
|
};
|
|
|
|
|
|
|
|
sym as *CrateMap
|
|
|
|
}
|
|
|
|
|
2013-09-15 14:41:02 -05:00
|
|
|
fn version(crate_map: &'static CrateMap) -> i32 {
|
|
|
|
match crate_map.version {
|
2013-09-09 17:04:29 -05:00
|
|
|
1 => return 1,
|
|
|
|
_ => return 0
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-09-15 14:41:02 -05:00
|
|
|
#[cfg(not(stage0))]
|
|
|
|
fn entries(crate_map: &'static CrateMap) -> *ModEntry {
|
2013-09-09 17:04:29 -05:00
|
|
|
match version(crate_map) {
|
|
|
|
0 => {
|
2013-09-15 14:41:02 -05:00
|
|
|
unsafe {
|
|
|
|
let v0: &'static CrateMapV0 = transmute(crate_map);
|
|
|
|
return v0.entries;
|
|
|
|
}
|
2013-09-09 17:04:29 -05:00
|
|
|
}
|
|
|
|
1 => return (*crate_map).entries,
|
2013-09-27 19:02:31 -05:00
|
|
|
_ => fail2!("Unknown crate map version!")
|
2013-09-09 17:04:29 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-09-15 14:41:02 -05:00
|
|
|
#[cfg(not(stage0))]
|
|
|
|
fn iterator(crate_map: &'static CrateMap) -> &'static [&'static CrateMap] {
|
2013-09-09 17:04:29 -05:00
|
|
|
match version(crate_map) {
|
|
|
|
0 => {
|
2013-09-15 14:41:02 -05:00
|
|
|
unsafe {
|
|
|
|
let v0: &'static CrateMapV0 = transmute(crate_map);
|
|
|
|
return v0.children;
|
|
|
|
}
|
2013-09-09 17:04:29 -05:00
|
|
|
}
|
|
|
|
1 => return vec::raw::to_ptr((*crate_map).children),
|
2013-09-27 19:02:31 -05:00
|
|
|
_ => fail2!("Unknown crate map version!")
|
2013-09-09 17:04:29 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-09-15 14:41:02 -05:00
|
|
|
fn iter_module_map(mod_entries: *ModEntry, f: &fn(&mut ModEntry)) {
|
2013-09-09 17:04:29 -05:00
|
|
|
let mut curr = mod_entries;
|
|
|
|
|
2013-09-15 14:41:02 -05:00
|
|
|
unsafe {
|
|
|
|
while !(*curr).name.is_null() {
|
|
|
|
f(transmute(curr));
|
|
|
|
curr = curr.offset(1);
|
|
|
|
}
|
2013-09-09 17:04:29 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-09-15 14:41:02 -05:00
|
|
|
|
|
|
|
|
|
|
|
#[cfg(not(stage0))]
|
|
|
|
fn do_iter_crate_map(crate_map: &'static CrateMap, f: &fn(&mut ModEntry),
|
2013-09-09 17:04:29 -05:00
|
|
|
visited: &mut HashSet<*CrateMap>) {
|
2013-09-15 14:41:02 -05:00
|
|
|
if visited.insert(crate_map as *CrateMap) {
|
|
|
|
iter_module_map(crate_map.entries, |x| f(x));
|
2013-09-09 17:04:29 -05:00
|
|
|
let child_crates = iterator(crate_map);
|
2013-09-15 14:41:02 -05:00
|
|
|
|
|
|
|
let mut i = 0;
|
|
|
|
while i < child_crates.len() {
|
|
|
|
do_iter_crate_map(child_crates[i], |x| f(x), visited);
|
|
|
|
i = i + 1;
|
2013-09-09 17:04:29 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-09-15 14:41:02 -05:00
|
|
|
#[cfg(stage0)]
|
2013-09-09 17:04:29 -05:00
|
|
|
/// Iterates recursively over `crate_map` and all child crate maps
|
2013-09-15 14:41:02 -05:00
|
|
|
pub fn iter_crate_map(crate_map: *u8, f: &fn(&mut ModEntry)) {
|
|
|
|
}
|
|
|
|
|
|
|
|
#[cfg(not(stage0))]
|
|
|
|
/// Iterates recursively over `crate_map` and all child crate maps
|
|
|
|
pub fn iter_crate_map(crate_map: &'static CrateMap, f: &fn(&mut ModEntry)) {
|
2013-09-09 17:04:29 -05:00
|
|
|
// XXX: use random numbers as keys from the OS-level RNG when there is a nice
|
|
|
|
// way to do this
|
|
|
|
let mut v: HashSet<*CrateMap> = HashSet::with_capacity_and_keys(0, 0, 32);
|
|
|
|
unsafe {
|
2013-09-15 14:41:02 -05:00
|
|
|
do_iter_crate_map(transmute(crate_map), f, &mut v);
|
2013-09-09 17:04:29 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-09-15 14:41:02 -05:00
|
|
|
#[cfg(test)]
|
|
|
|
mod tests {
|
2013-09-09 17:04:29 -05:00
|
|
|
use c_str::ToCStr;
|
|
|
|
use cast::transmute;
|
2013-09-15 14:41:02 -05:00
|
|
|
use ptr;
|
|
|
|
use vec;
|
|
|
|
|
|
|
|
use rt::crate_map::{ModEntry, iter_crate_map};
|
2013-09-09 17:04:29 -05:00
|
|
|
|
2013-09-15 14:41:02 -05:00
|
|
|
struct CrateMap<'self> {
|
2013-09-09 17:04:29 -05:00
|
|
|
version: i32,
|
|
|
|
entries: *ModEntry,
|
2013-09-15 14:41:02 -05:00
|
|
|
/// a dynamically sized struct, where all pointers to children are listed adjacent
|
|
|
|
/// to the struct, terminated with NULL
|
|
|
|
children: &'self [&'self CrateMap<'self>]
|
2013-09-09 17:04:29 -05:00
|
|
|
}
|
|
|
|
|
2013-09-15 14:41:02 -05:00
|
|
|
#[test]
|
|
|
|
fn iter_crate_map_duplicates() {
|
|
|
|
unsafe {
|
|
|
|
let mod_name1 = "c::m1".to_c_str();
|
|
|
|
let mut level3: u32 = 3;
|
2013-09-09 17:04:29 -05:00
|
|
|
|
2013-09-15 14:41:02 -05:00
|
|
|
let entries: ~[ModEntry] = ~[
|
|
|
|
ModEntry { name: mod_name1.with_ref(|buf| buf), log_level: &mut level3},
|
2013-09-09 17:04:29 -05:00
|
|
|
ModEntry { name: ptr::null(), log_level: ptr::mut_null()}
|
2013-09-15 14:41:02 -05:00
|
|
|
];
|
|
|
|
|
|
|
|
let child_crate = CrateMap {
|
|
|
|
version: 1,
|
|
|
|
entries: vec::raw::to_ptr(entries),
|
|
|
|
children: []
|
|
|
|
};
|
|
|
|
|
|
|
|
let root_crate = CrateMap {
|
|
|
|
version: 1,
|
|
|
|
entries: vec::raw::to_ptr([ModEntry { name: ptr::null(), log_level: ptr::mut_null()}]),
|
|
|
|
children: [&child_crate, &child_crate]
|
|
|
|
};
|
|
|
|
|
|
|
|
let mut cnt = 0;
|
|
|
|
do iter_crate_map(transmute(&root_crate)) |entry| {
|
|
|
|
assert!(*entry.log_level == 3);
|
|
|
|
cnt += 1;
|
|
|
|
}
|
|
|
|
assert!(cnt == 1);
|
|
|
|
}
|
|
|
|
}
|
2013-09-09 17:04:29 -05:00
|
|
|
|
2013-09-15 14:41:02 -05:00
|
|
|
#[test]
|
|
|
|
fn iter_crate_map_follow_children() {
|
|
|
|
unsafe {
|
|
|
|
let mod_name1 = "c::m1".to_c_str();
|
|
|
|
let mod_name2 = "c::m2".to_c_str();
|
|
|
|
let mut level2: u32 = 2;
|
|
|
|
let mut level3: u32 = 3;
|
|
|
|
let child_crate2 = CrateMap {
|
|
|
|
version: 1,
|
|
|
|
entries: vec::raw::to_ptr([
|
|
|
|
ModEntry { name: mod_name1.with_ref(|buf| buf), log_level: &mut level2},
|
|
|
|
ModEntry { name: mod_name2.with_ref(|buf| buf), log_level: &mut level3},
|
|
|
|
ModEntry { name: ptr::null(), log_level: ptr::mut_null()}
|
|
|
|
]),
|
|
|
|
children: []
|
|
|
|
};
|
|
|
|
|
|
|
|
let child_crate1 = CrateMap {
|
|
|
|
version: 1,
|
|
|
|
entries: vec::raw::to_ptr([
|
|
|
|
ModEntry { name: "t::f1".to_c_str().with_ref(|buf| buf), log_level: &mut 1},
|
|
|
|
ModEntry { name: ptr::null(), log_level: ptr::mut_null()}
|
|
|
|
]),
|
|
|
|
children: [&child_crate2]
|
|
|
|
};
|
|
|
|
|
|
|
|
let root_crate = CrateMap {
|
|
|
|
version: 1,
|
|
|
|
entries: vec::raw::to_ptr([
|
|
|
|
ModEntry { name: "t::f1".to_c_str().with_ref(|buf| buf), log_level: &mut 0},
|
|
|
|
ModEntry { name: ptr::null(), log_level: ptr::mut_null()}
|
|
|
|
]),
|
|
|
|
children: [&child_crate1]
|
|
|
|
};
|
|
|
|
|
|
|
|
let mut cnt = 0;
|
|
|
|
do iter_crate_map(transmute(&root_crate)) |entry| {
|
|
|
|
assert!(*entry.log_level == cnt);
|
|
|
|
cnt += 1;
|
|
|
|
}
|
|
|
|
assert!(cnt == 4);
|
2013-09-09 17:04:29 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|