Skip to content

Commit 323e8f0

Browse files
committed
auto merge of #9087 : fhahn/rust/rust_crate_map, r=brson
This patch converts the rust_crate_map.cpp to Rust as mentioned at the end of #8880.
2 parents 2bdf4af + 2b5f4b5 commit 323e8f0

File tree

8 files changed

+224
-230
lines changed

8 files changed

+224
-230
lines changed

mk/rt.mk

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,6 @@ RUNTIME_CXXS_$(1)_$(2) := \
7575
rt/rust_rng.cpp \
7676
rt/rust_upcall.cpp \
7777
rt/rust_uv.cpp \
78-
rt/rust_crate_map.cpp \
7978
rt/isaac/randport.cpp \
8079
rt/miniz.cpp \
8180
rt/memory_region.cpp \

src/libstd/hashmap.rs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -687,6 +687,17 @@ impl<T:Hash + Eq> HashSet<T> {
687687
HashSet { map: HashMap::with_capacity(capacity) }
688688
}
689689

690+
/// Create an empty HashSet with space for at least `capacity`
691+
/// elements in the hash table, using `k0` and `k1` as the keys.
692+
///
693+
/// Warning: `k0` and `k1` are normally randomly generated, and
694+
/// are designed to allow HashSets to be resistant to attacks that
695+
/// cause many collisions and very poor performance. Setting them
696+
/// manually using this function can expose a DoS attack vector.
697+
pub fn with_capacity_and_keys(k0: u64, k1: u64, capacity: uint) -> HashSet<T> {
698+
HashSet { map: HashMap::with_capacity_and_keys(k0, k1, capacity) }
699+
}
700+
690701
/// Reserve space for at least `n` elements in the hash table.
691702
pub fn reserve_at_least(&mut self, n: uint) {
692703
self.map.reserve_at_least(n)

src/libstd/rt/crate_map.rs

Lines changed: 200 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,200 @@
1+
// Copyright 2013 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+
12+
use libc::{c_void, c_char};
13+
use ptr;
14+
use ptr::RawPtr;
15+
use vec;
16+
use hashmap::HashSet;
17+
use container::MutableSet;
18+
19+
pub struct ModEntry{
20+
name: *c_char,
21+
log_level: *mut u32
22+
}
23+
struct CrateMapV0 {
24+
entries: *ModEntry,
25+
children: [*CrateMap, ..1]
26+
}
27+
28+
struct CrateMap {
29+
version: i32,
30+
annihilate_fn: *c_void,
31+
entries: *ModEntry,
32+
/// a dynamically sized struct, where all pointers to children are listed adjacent
33+
/// to the struct, terminated with NULL
34+
children: [*CrateMap, ..1]
35+
}
36+
37+
unsafe fn version(crate_map: *CrateMap) -> i32 {
38+
match (*crate_map).version {
39+
1 => return 1,
40+
_ => return 0
41+
}
42+
}
43+
44+
/// Returns a pointer to the annihilate function of the CrateMap
45+
pub unsafe fn annihilate_fn(crate_map: *CrateMap) -> *c_void {
46+
match version(crate_map) {
47+
0 => return ptr::null(),
48+
1 => return (*crate_map).annihilate_fn,
49+
_ => fail!("Unknown crate map version!")
50+
}
51+
}
52+
53+
unsafe fn entries(crate_map: *CrateMap) -> *ModEntry {
54+
match version(crate_map) {
55+
0 => {
56+
let v0 = crate_map as (*CrateMapV0);
57+
return (*v0).entries;
58+
}
59+
1 => return (*crate_map).entries,
60+
_ => fail!("Unknown crate map version!")
61+
}
62+
}
63+
64+
unsafe fn iterator(crate_map: *CrateMap) -> **CrateMap {
65+
match version(crate_map) {
66+
0 => {
67+
let v0 = crate_map as (*CrateMapV0);
68+
return vec::raw::to_ptr((*v0).children);
69+
}
70+
1 => return vec::raw::to_ptr((*crate_map).children),
71+
_ => fail!("Unknown crate map version!")
72+
}
73+
}
74+
75+
unsafe fn iter_module_map(mod_entries: *ModEntry, f: &fn(*mut ModEntry)) {
76+
let mut curr = mod_entries;
77+
78+
while !(*curr).name.is_null() {
79+
f(curr as *mut ModEntry);
80+
curr = curr.offset(1);
81+
}
82+
}
83+
84+
unsafe fn do_iter_crate_map(crate_map: *CrateMap, f: &fn(*mut ModEntry),
85+
visited: &mut HashSet<*CrateMap>) {
86+
if visited.insert(crate_map) {
87+
iter_module_map(entries(crate_map), |x| f(x));
88+
let child_crates = iterator(crate_map);
89+
do ptr::array_each(child_crates) |child| {
90+
do_iter_crate_map(child, |x| f(x), visited);
91+
}
92+
}
93+
}
94+
95+
/// Iterates recursively over `crate_map` and all child crate maps
96+
pub unsafe fn iter_crate_map(crate_map: *CrateMap, f: &fn(*mut ModEntry)) {
97+
// XXX: use random numbers as keys from the OS-level RNG when there is a nice
98+
// way to do this
99+
let mut v: HashSet<*CrateMap> = HashSet::with_capacity_and_keys(0, 0, 32);
100+
do_iter_crate_map(crate_map, f, &mut v);
101+
}
102+
103+
#[test]
104+
fn iter_crate_map_duplicates() {
105+
use c_str::ToCStr;
106+
use cast::transmute;
107+
108+
struct CrateMapT3 {
109+
version: i32,
110+
annihilate_fn: *c_void,
111+
entries: *ModEntry,
112+
children: [*CrateMap, ..3]
113+
}
114+
115+
unsafe {
116+
let mod_name1 = "c::m1".to_c_str();
117+
let mut level3: u32 = 3;
118+
119+
let entries: ~[ModEntry] = ~[
120+
ModEntry { name: mod_name1.with_ref(|buf| buf), log_level: &mut level3},
121+
ModEntry { name: ptr::null(), log_level: ptr::mut_null()}
122+
];
123+
let child_crate = CrateMap {
124+
version: 1,
125+
annihilate_fn: ptr::null(),
126+
entries: vec::raw::to_ptr(entries),
127+
children: [ptr::null()]
128+
};
129+
130+
let root_crate = CrateMapT3 {
131+
version: 1, annihilate_fn: ptr::null(),
132+
entries: vec::raw::to_ptr([ModEntry { name: ptr::null(), log_level: ptr::mut_null()}]),
133+
children: [&child_crate as *CrateMap, &child_crate as *CrateMap, ptr::null()]
134+
};
135+
136+
let mut cnt = 0;
137+
do iter_crate_map(transmute(&root_crate)) |entry| {
138+
assert!(*(*entry).log_level == 3);
139+
cnt += 1;
140+
}
141+
assert!(cnt == 1);
142+
}
143+
}
144+
145+
#[test]
146+
fn iter_crate_map_follow_children() {
147+
use c_str::ToCStr;
148+
use cast::transmute;
149+
150+
struct CrateMapT2 {
151+
version: i32,
152+
annihilate_fn: *c_void,
153+
entries: *ModEntry,
154+
children: [*CrateMap, ..2]
155+
}
156+
157+
unsafe {
158+
let mod_name1 = "c::m1".to_c_str();
159+
let mod_name2 = "c::m2".to_c_str();
160+
let mut level2: u32 = 2;
161+
let mut level3: u32 = 3;
162+
let child_crate2 = CrateMap {
163+
version: 1,
164+
annihilate_fn: ptr::null(),
165+
entries: vec::raw::to_ptr([
166+
ModEntry { name: mod_name1.with_ref(|buf| buf), log_level: &mut level2},
167+
ModEntry { name: mod_name2.with_ref(|buf| buf), log_level: &mut level3},
168+
ModEntry { name: ptr::null(), log_level: ptr::mut_null()}
169+
]),
170+
children: [ptr::null()]
171+
};
172+
173+
let child_crate1 = CrateMapT2 {
174+
version: 1,
175+
annihilate_fn: ptr::null(),
176+
entries: vec::raw::to_ptr([
177+
ModEntry { name: "t::f1".to_c_str().with_ref(|buf| buf), log_level: &mut 1},
178+
ModEntry { name: ptr::null(), log_level: ptr::mut_null()}
179+
]),
180+
children: [&child_crate2 as *CrateMap, ptr::null()]
181+
};
182+
183+
let child_crate1_ptr: *CrateMap = transmute(&child_crate1);
184+
let root_crate = CrateMapT2 {
185+
version: 1, annihilate_fn: ptr::null(),
186+
entries: vec::raw::to_ptr([
187+
ModEntry { name: "t::f1".to_c_str().with_ref(|buf| buf), log_level: &mut 0},
188+
ModEntry { name: ptr::null(), log_level: ptr::mut_null()}
189+
]),
190+
children: [child_crate1_ptr, ptr::null()]
191+
};
192+
193+
let mut cnt = 0;
194+
do iter_crate_map(transmute(&root_crate)) |entry| {
195+
assert!(*(*entry).log_level == cnt);
196+
cnt += 1;
197+
}
198+
assert!(cnt == 4);
199+
}
200+
}

src/libstd/rt/logging.rs

Lines changed: 10 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -7,66 +7,24 @@
77
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
88
// option. This file may not be copied, modified, or distributed
99
// except according to those terms.
10-
use cast::transmute;
1110
use either::*;
12-
use libc::{c_void, uintptr_t, c_char, exit, STDERR_FILENO};
11+
use libc::{uintptr_t, exit, STDERR_FILENO};
1312
use option::{Some, None, Option};
1413
use rt::util::dumb_println;
14+
use rt::crate_map::{ModEntry, iter_crate_map};
1515
use str::StrSlice;
1616
use str::raw::from_c_str;
1717
use u32;
18-
use unstable::raw::Closure;
1918
use vec::ImmutableVector;
20-
19+
use cast::transmute;
2120

2221
struct LogDirective {
2322
name: Option<~str>,
2423
level: u32
2524
}
2625

27-
// This is the Rust representation of the mod_entry struct in src/rt/rust_crate_map.h
28-
struct ModEntry{
29-
name: *c_char,
30-
log_level: *mut u32
31-
}
32-
3326
static MAX_LOG_LEVEL: u32 = 255;
3427
static DEFAULT_LOG_LEVEL: u32 = 1;
35-
36-
fn iter_crate_map(map: *u8, f: &fn(*mut ModEntry)) {
37-
unsafe {
38-
let closure : Closure = transmute(f);
39-
let code = transmute(closure.code);
40-
let env = transmute(closure.env);
41-
rust_iter_crate_map(transmute(map), iter_cb, code, env);
42-
}
43-
44-
extern fn iter_cb(code: *c_void, env: *c_void, entry: *ModEntry){
45-
unsafe {
46-
let closure: Closure = Closure {
47-
code: transmute(code),
48-
env: transmute(env),
49-
};
50-
let closure: &fn(*ModEntry) = transmute(closure);
51-
return closure(entry);
52-
}
53-
}
54-
extern {
55-
#[cfg(not(stage0))]
56-
#[rust_stack]
57-
fn rust_iter_crate_map(map: *c_void,
58-
f: extern "C" fn(*c_void, *c_void, entry: *ModEntry),
59-
code: *c_void,
60-
data: *c_void);
61-
62-
#[cfg(stage0)]
63-
#[rust_stack]
64-
fn rust_iter_crate_map(map: *c_void,
65-
f: *u8,
66-
code: *c_void,
67-
data: *c_void);
68-
}
69-
}
7028
static log_level_names : &'static[&'static str] = &'static["error", "warn", "info", "debug"];
7129

7230
/// Parse an individual log level that is either a number or a symbolic log level
@@ -96,12 +54,10 @@ fn parse_log_level(level: &str) -> Option<u32> {
9654
log_level
9755
}
9856

99-
10057
/// Parse a logging specification string (e.g: "crate1,crate2::mod3,crate3::x=1")
10158
/// and return a vector with log directives.
10259
/// Valid log levels are 0-255, with the most likely ones being 1-4 (defined in std::).
10360
/// Also supports string log levels of error, warn, info, and debug
104-
10561
fn parse_logging_spec(spec: ~str) -> ~[LogDirective]{
10662
let mut dirs = ~[];
10763
for s in spec.split_iter(',') {
@@ -186,22 +142,22 @@ fn update_log_settings(crate_map: *u8, settings: ~str) {
186142
if settings.len() > 0 {
187143
if settings == ~"::help" || settings == ~"?" {
188144
dumb_println("\nCrate log map:\n");
189-
do iter_crate_map(crate_map) |entry: *mut ModEntry| {
190-
unsafe {
145+
unsafe {
146+
do iter_crate_map(transmute(crate_map)) |entry: *mut ModEntry| {
191147
dumb_println(" "+from_c_str((*entry).name));
192148
}
193-
}
194-
unsafe {
195149
exit(1);
196150
}
197151
}
198152
dirs = parse_logging_spec(settings);
199153
}
200154

201155
let mut n_matches: u32 = 0;
202-
do iter_crate_map(crate_map) |entry: *mut ModEntry| {
203-
let m = update_entry(dirs, entry);
204-
n_matches += m;
156+
unsafe {
157+
do iter_crate_map(transmute(crate_map)) |entry: *mut ModEntry| {
158+
let m = update_entry(dirs, entry);
159+
n_matches += m;
160+
}
205161
}
206162

207163
if n_matches < (dirs.len() as u32) {

src/libstd/rt/mod.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,9 @@ pub mod local_heap;
126126
/// The Logger trait and implementations
127127
pub mod logging;
128128

129+
/// Crate map
130+
pub mod crate_map;
131+
129132
/// Tools for testing the runtime
130133
pub mod test;
131134

0 commit comments

Comments
 (0)