Skip to content

Commit dc20272

Browse files
author
Elliott Slaughter
committed
---
yaml --- r: 23774 b: refs/heads/master c: 3f0d207 h: refs/heads/master v: v3
1 parent e374808 commit dc20272

File tree

13 files changed

+376
-33
lines changed

13 files changed

+376
-33
lines changed

[refs]

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
---
2-
refs/heads/master: fb8786fe522ed96172cf1ae8e205e3f2722e834c
2+
refs/heads/master: 3f0d207b3251e598488588765b942bf6b7a4f9bb
33
refs/heads/snap-stage1: e33de59e47c5076a89eadeb38f4934f58a3618a6
44
refs/heads/snap-stage3: cd6f24f9d14ac90d167386a56e7a6ac1f0318195
55
refs/heads/try: ffbe0e0e00374358b789b0037bcb3a577cd218be

trunk/mk/rt.mk

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,9 @@ RUNTIME_CS_$(1) := \
6060
rt/rust_port.cpp \
6161
rt/rust_upcall.cpp \
6262
rt/rust_uv.cpp \
63+
rt/rust_crate_map.cpp \
6364
rt/rust_log.cpp \
65+
rt/rust_gc_metadata.cpp \
6466
rt/rust_port_selector.cpp \
6567
rt/rust_util.cpp \
6668
rt/circular_buffer.cpp \

trunk/src/libcore/core.rc

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ export uint, u8, u16, u32, u64;
4040
export float, f32, f64;
4141
export box, char, str, ptr, vec, at_vec, bool;
4242
export either, option, result, iter;
43-
export libc, os, io, run, rand, sys, unsafe, logging;
43+
export gc, io, libc, os, run, rand, sys, unsafe, logging;
4444
export comm, task, future, pipes;
4545
export extfmt;
4646
// The test harness links against core, so don't include runtime in tests.
@@ -216,6 +216,7 @@ mod pipes;
216216

217217
// Runtime and language-primitive support
218218

219+
mod gc;
219220
mod io;
220221
mod libc;
221222
mod os;

trunk/src/libcore/gc.rs

Lines changed: 155 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,155 @@
1+
import stackwalk::Word;
2+
import libc::size_t;
3+
4+
extern mod rustrt {
5+
fn rust_annihilate_box(ptr: *Word);
6+
7+
#[rust_stack]
8+
fn rust_gc_metadata() -> *Word;
9+
10+
#[rust_stack]
11+
fn rust_call_tydesc_glue(root: *Word, tydesc: *Word, field: size_t);
12+
}
13+
14+
type SafePoint = { sp_meta: *Word, fn_meta: *Word };
15+
16+
unsafe fn is_safe_point(pc: *Word) -> Option<SafePoint> {
17+
let module_meta = rustrt::rust_gc_metadata();
18+
let num_safe_points_ptr: *u32 = unsafe::reinterpret_cast(&module_meta);
19+
let num_safe_points = *num_safe_points_ptr as Word;
20+
let safe_points: *Word =
21+
ptr::offset(unsafe::reinterpret_cast(&module_meta), 1);
22+
23+
if ptr::is_null(pc) {
24+
return None;
25+
}
26+
27+
let mut sp = 0 as Word;
28+
while sp < num_safe_points {
29+
let sp_loc = *ptr::offset(safe_points, sp*3) as *Word;
30+
if sp_loc == pc {
31+
return Some(
32+
{sp_meta: *ptr::offset(safe_points, sp*3 + 1) as *Word,
33+
fn_meta: *ptr::offset(safe_points, sp*3 + 2) as *Word});
34+
}
35+
sp += 1;
36+
}
37+
return None;
38+
}
39+
40+
type Visitor = fn(root: **Word, tydesc: *Word);
41+
42+
unsafe fn walk_safe_point(fp: *Word, sp: SafePoint, visitor: Visitor) {
43+
let fp_bytes: *u8 = unsafe::reinterpret_cast(&fp);
44+
let sp_meta_u32s: *u32 = unsafe::reinterpret_cast(&sp.sp_meta);
45+
46+
let num_stack_roots = *sp_meta_u32s as uint;
47+
let num_reg_roots = *ptr::offset(sp_meta_u32s, 1) as uint;
48+
49+
let stack_roots: *u32 =
50+
unsafe::reinterpret_cast(&ptr::offset(sp_meta_u32s, 2));
51+
let reg_roots: *u8 =
52+
unsafe::reinterpret_cast(&ptr::offset(stack_roots, num_stack_roots));
53+
let addrspaces: *Word =
54+
unsafe::reinterpret_cast(&ptr::offset(reg_roots, num_reg_roots));
55+
let tydescs: ***Word =
56+
unsafe::reinterpret_cast(&ptr::offset(addrspaces, num_stack_roots));
57+
58+
// Stack roots
59+
let mut sri = 0;
60+
while sri < num_stack_roots {
61+
if *ptr::offset(addrspaces, sri) >= 1 {
62+
let root =
63+
ptr::offset(fp_bytes, *ptr::offset(stack_roots, sri) as Word)
64+
as **Word;
65+
let tydescpp = ptr::offset(tydescs, sri);
66+
let tydesc = if ptr::is_not_null(tydescpp) &&
67+
ptr::is_not_null(*tydescpp) {
68+
**tydescpp
69+
} else {
70+
ptr::null()
71+
};
72+
visitor(root, tydesc);
73+
}
74+
sri += 1;
75+
}
76+
77+
// Register roots
78+
let mut rri = 0;
79+
while rri < num_reg_roots {
80+
if *ptr::offset(addrspaces, num_stack_roots + rri) == 1 {
81+
// FIXME(#2997): Need to find callee saved registers on the stack.
82+
}
83+
rri += 1;
84+
}
85+
}
86+
87+
type Memory = uint;
88+
89+
const task_local_heap: Memory = 1;
90+
const exchange_heap: Memory = 2;
91+
const stack: Memory = 4;
92+
93+
const need_cleanup: Memory = exchange_heap | stack;
94+
95+
unsafe fn walk_gc_roots(mem: Memory, visitor: Visitor) {
96+
let mut last_ret: *Word = ptr::null();
97+
do stackwalk::walk_stack |frame| {
98+
unsafe {
99+
if ptr::is_not_null(last_ret) {
100+
let sp = is_safe_point(last_ret);
101+
match sp {
102+
Some(sp_info) => {
103+
do walk_safe_point(frame.fp, sp_info) |root, tydesc| {
104+
if ptr::is_null(tydesc) {
105+
// Root is a generic box.
106+
let refcount = **root;
107+
if mem | task_local_heap != 0 && refcount != -1 {
108+
visitor(root, tydesc);
109+
} else if mem | exchange_heap != 0 {
110+
visitor(root, tydesc);
111+
}
112+
} else {
113+
// Root is a non-immediate.
114+
if mem | stack != 0 {
115+
visitor(root, tydesc);
116+
}
117+
}
118+
}
119+
}
120+
None => ()
121+
}
122+
}
123+
last_ret = *ptr::offset(frame.fp, 1) as *Word;
124+
}
125+
true
126+
}
127+
}
128+
129+
fn gc() {
130+
unsafe {
131+
let mut i = 0;
132+
do walk_gc_roots(task_local_heap) |_root, _tydesc| {
133+
// FIXME(#2997): Walk roots and mark them.
134+
io::stdout().write([46]); // .
135+
i += 1;
136+
}
137+
}
138+
}
139+
140+
// This should only be called from fail, as it will drop the roots
141+
// which are *live* on the stack, rather than dropping those that are
142+
// dead.
143+
fn cleanup_stack_for_failure() {
144+
unsafe {
145+
let mut i = 0;
146+
do walk_gc_roots(need_cleanup) |root, tydesc| {
147+
if ptr::is_null(tydesc) {
148+
rustrt::rust_annihilate_box(*root);
149+
} else {
150+
rustrt::rust_call_tydesc_glue(*root, tydesc, 3 as size_t);
151+
}
152+
i += 1;
153+
}
154+
}
155+
}

trunk/src/libcore/rt.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,9 @@ use libc::c_void;
88
use libc::size_t;
99
use libc::uintptr_t;
1010

11+
import gc::gc;
12+
import gc::cleanup_stack_for_failure;
13+
1114
#[allow(non_camel_case_types)]
1215
type rust_task = c_void;
1316

@@ -33,6 +36,7 @@ extern mod rustrt {
3336
// gather_rust_rtcalls.
3437
#[rt(fail)]
3538
fn rt_fail(expr: *c_char, file: *c_char, line: size_t) {
39+
cleanup_stack_for_failure();
3640
rustrt::rust_upcall_fail(expr, file, line);
3741
}
3842

trunk/src/rt/rust.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
#include "rust_kernel.h"
88
#include "rust_util.h"
99
#include "rust_scheduler.h"
10+
#include "rust_gc_metadata.h"
1011

1112
// Creates a rust argument vector from the platform argument vector
1213
struct
@@ -85,6 +86,8 @@ rust_start(uintptr_t main_fn, int argc, char **argv, void* crate_map) {
8586
// line as well.
8687
rust_env *env = load_env();
8788

89+
update_gc_metadata(crate_map);
90+
8891
update_log_settings(crate_map, env->logspec);
8992

9093
// Maybe turn on typestate claim checking

trunk/src/rt/rust_crate_map.cpp

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
#include "rust_crate_map.h"
2+
3+
void iter_module_map(const mod_entry* map,
4+
void (*fn)(const mod_entry* entry, void *cookie),
5+
void *cookie) {
6+
for (const mod_entry* cur = map; cur->name; cur++) {
7+
fn(cur, cookie);
8+
}
9+
}
10+
11+
void iter_crate_map(const cratemap* map,
12+
void (*fn)(const mod_entry* map, void *cookie),
13+
void *cookie) {
14+
// First iterate this crate
15+
iter_module_map(map->entries, fn, cookie);
16+
// Then recurse on linked crates
17+
// FIXME (#2673) this does double work in diamond-shaped deps. could
18+
// keep a set of visited addresses, if it turns out to be actually
19+
// slow
20+
for (size_t i = 0; map->children[i]; i++) {
21+
iter_crate_map(map->children[i], fn, cookie);
22+
}
23+
}
24+
25+
//
26+
// Local Variables:
27+
// mode: C++
28+
// fill-column: 78;
29+
// indent-tabs-mode: nil
30+
// c-basic-offset: 4
31+
// buffer-file-coding-system: utf-8-unix
32+
// End:
33+
//

trunk/src/rt/rust_crate_map.h

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
#ifndef RUST_CRATE_MAP_H
2+
#define RUST_CRATE_MAP_H
3+
4+
#include "rust_log.h"
5+
6+
struct mod_entry {
7+
const char* name;
8+
uint32_t* state;
9+
};
10+
11+
struct cratemap {
12+
const mod_entry* entries;
13+
const cratemap* children[1];
14+
};
15+
16+
void iter_module_map(const mod_entry* map,
17+
void (*fn)(const mod_entry* entry, void *cookie),
18+
void *cookie);
19+
20+
void iter_crate_map(const cratemap* map,
21+
void (*fn)(const mod_entry* entry, void *cookie),
22+
void *cookie);
23+
24+
//
25+
// Local Variables:
26+
// mode: C++
27+
// fill-column: 78;
28+
// indent-tabs-mode: nil
29+
// c-basic-offset: 4
30+
// buffer-file-coding-system: utf-8-unix
31+
// End:
32+
//
33+
34+
#endif /* RUST_CRATE_MAP_H */

trunk/src/rt/rust_gc_metadata.cpp

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
#include "rust_gc_metadata.h"
2+
#include "rust_crate_map.h"
3+
#include "rust_globals.h"
4+
5+
#include <algorithm>
6+
#include <vector>
7+
8+
struct safe_point {
9+
size_t safe_point_loc;
10+
size_t safe_point_meta;
11+
size_t function_meta;
12+
};
13+
14+
struct update_gc_entry_args {
15+
std::vector<safe_point> *safe_points;
16+
};
17+
18+
static void
19+
update_gc_entry(const mod_entry* entry, void *cookie) {
20+
update_gc_entry_args *args = (update_gc_entry_args *)cookie;
21+
if (!strcmp(entry->name, "_gc_module_metadata")) {
22+
size_t *next = entry->state;
23+
uint32_t num_safe_points = *(uint32_t *)next;
24+
next++;
25+
26+
for (uint32_t i = 0; i < num_safe_points; i++) {
27+
safe_point sp = { next[0], next[1], next[2] };
28+
next += 3;
29+
30+
args->safe_points->push_back(sp);
31+
}
32+
}
33+
}
34+
35+
static bool
36+
cmp_safe_point(safe_point a, safe_point b) {
37+
return a.safe_point_loc < b.safe_point_loc;
38+
}
39+
40+
size_t *global_safe_points = 0;
41+
42+
void
43+
update_gc_metadata(const void* map) {
44+
std::vector<safe_point> safe_points;
45+
update_gc_entry_args args = { &safe_points };
46+
47+
// Extract list of safe points from each module.
48+
iter_crate_map((const cratemap *)map, update_gc_entry, (void *)&args);
49+
std::sort(safe_points.begin(), safe_points.end(), cmp_safe_point);
50+
51+
// Serialize safe point list into format expected by runtime.
52+
global_safe_points =
53+
(size_t *)malloc((safe_points.size()*3 + 1)*sizeof(size_t));
54+
if (!global_safe_points) return;
55+
56+
size_t *next = global_safe_points;
57+
*(uint32_t *)next = safe_points.size();
58+
next++;
59+
for (uint32_t i = 0; i < safe_points.size(); i++) {
60+
next[0] = safe_points[i].safe_point_loc;
61+
next[1] = safe_points[i].safe_point_meta;
62+
next[2] = safe_points[i].function_meta;
63+
next += 3;
64+
}
65+
}
66+
67+
extern "C" CDECL void *
68+
rust_gc_metadata() {
69+
return (void *)global_safe_points;
70+
}
71+
72+
//
73+
// Local Variables:
74+
// mode: C++
75+
// fill-column: 78;
76+
// indent-tabs-mode: nil
77+
// c-basic-offset: 4
78+
// buffer-file-coding-system: utf-8-unix
79+
// End:
80+
//

trunk/src/rt/rust_gc_metadata.h

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
#ifndef RUST_GC_METADATA_H
2+
#define RUST_GC_METADATA_H
3+
4+
void update_gc_metadata(const void* map);
5+
6+
//
7+
// Local Variables:
8+
// mode: C++
9+
// fill-column: 78;
10+
// indent-tabs-mode: nil
11+
// c-basic-offset: 4
12+
// buffer-file-coding-system: utf-8-unix
13+
// End:
14+
//
15+
16+
#endif /* RUST_GC_METADATA_H */

0 commit comments

Comments
 (0)