Skip to content

Commit ae690cf

Browse files
author
Elliott Slaughter
committed
---
yaml --- r: 32442 b: refs/heads/dist-snap c: 961bd48 h: refs/heads/master v: v3
1 parent ba38ad7 commit ae690cf

File tree

5 files changed

+114
-43
lines changed

5 files changed

+114
-43
lines changed

[refs]

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,6 @@ refs/tags/release-0.1: 1f5c5126e96c79d22cb7862f75304136e204f105
77
refs/heads/ndm: f3868061cd7988080c30d6d5bf352a5a5fe2460b
88
refs/heads/try2: d0c6ce338884ee21843f4b40bf6bf18d222ce5df
99
refs/heads/incoming: d9317a174e434d4c99fc1a37fd7dc0d2f5328d37
10-
refs/heads/dist-snap: 578b036f9b0415852aae0af9286ff53630fa1c56
10+
refs/heads/dist-snap: 961bd48724a3b9e75685d23d8d0e52a20f6ccf68
1111
refs/tags/release-0.2: c870d2dffb391e14efb05aa27898f1f6333a9596
1212
refs/tags/release-0.3: b5f0d0f648d9a6153664837026ba1be43d3e2503

branches/dist-snap/src/libcore/gc.rs

Lines changed: 100 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,38 @@
11
import stackwalk::Word;
22
import libc::size_t;
3+
import libc::uintptr_t;
34
import send_map::linear::LinearMap;
45

56
export Word;
67
export gc;
78
export cleanup_stack_for_failure;
89

10+
// Mirrors rust_stack.h stk_seg
11+
struct StackSegment {
12+
let prev: *StackSegment;
13+
let next: *StackSegment;
14+
let end: uintptr_t;
15+
// And other fields which we don't care about...
16+
}
17+
918
extern mod rustrt {
1019
fn rust_annihilate_box(ptr: *Word);
1120

1221
#[rust_stack]
13-
fn rust_gc_metadata() -> *Word;
22+
fn rust_call_tydesc_glue(root: *Word, tydesc: *Word, field: size_t);
1423

1524
#[rust_stack]
16-
fn rust_call_tydesc_glue(root: *Word, tydesc: *Word, field: size_t);
25+
fn rust_gc_metadata() -> *Word;
26+
27+
fn rust_get_stack_segment() -> *StackSegment;
28+
}
29+
30+
unsafe fn is_frame_in_segment(fp: *Word, segment: *StackSegment) -> bool {
31+
let begin: Word = unsafe::reinterpret_cast(&segment);
32+
let end: Word = unsafe::reinterpret_cast(&(*segment).end);
33+
let frame: Word = unsafe::reinterpret_cast(&fp);
34+
35+
return begin <= frame && frame <= end;
1736
}
1837

1938
type SafePoint = { sp_meta: *Word, fn_meta: *Word };
@@ -44,6 +63,17 @@ unsafe fn is_safe_point(pc: *Word) -> Option<SafePoint> {
4463

4564
type Visitor = fn(root: **Word, tydesc: *Word) -> bool;
4665

66+
unsafe fn bump<T, U>(ptr: *T, count: uint) -> *U {
67+
return unsafe::reinterpret_cast(&ptr::offset(ptr, count));
68+
}
69+
70+
unsafe fn align_to_pointer<T>(ptr: *T) -> *T {
71+
let align = sys::min_align_of::<*T>();
72+
let ptr: uint = unsafe::reinterpret_cast(&ptr);
73+
let ptr = (ptr + (align - 1)) & -align;
74+
return unsafe::reinterpret_cast(&ptr);
75+
}
76+
4777
unsafe fn walk_safe_point(fp: *Word, sp: SafePoint, visitor: Visitor) {
4878
let fp_bytes: *u8 = unsafe::reinterpret_cast(&fp);
4979
let sp_meta_u32s: *u32 = unsafe::reinterpret_cast(&sp.sp_meta);
@@ -97,7 +127,35 @@ const stack: Memory = 4;
97127

98128
const need_cleanup: Memory = exchange_heap | stack;
99129

130+
unsafe fn find_segment_for_frame(fp: *Word, segment: *StackSegment)
131+
-> {segment: *StackSegment, boundary: bool} {
132+
// Check if frame is in either current frame or previous frame.
133+
let in_segment = is_frame_in_segment(fp, segment);
134+
let in_prev_segment = ptr::is_not_null((*segment).prev) &&
135+
is_frame_in_segment(fp, (*segment).prev);
136+
137+
// If frame is not in either segment, walk down segment list until
138+
// we find the segment containing this frame.
139+
if !in_segment && !in_prev_segment {
140+
let mut segment = segment;
141+
while ptr::is_not_null((*segment).next) &&
142+
is_frame_in_segment(fp, (*segment).next) {
143+
segment = (*segment).next;
144+
}
145+
return {segment: segment, boundary: false};
146+
}
147+
148+
// If frame is in previous frame, then we're at a boundary.
149+
if !in_segment && in_prev_segment {
150+
return {segment: (*segment).prev, boundary: true};
151+
}
152+
153+
// Otherwise, we're somewhere on the inside of the frame.
154+
return {segment: segment, boundary: false};
155+
}
156+
100157
unsafe fn walk_gc_roots(mem: Memory, sentinel: **Word, visitor: Visitor) {
158+
let mut segment = rustrt::rust_get_stack_segment();
101159
let mut last_ret: *Word = ptr::null();
102160
// To avoid collecting memory used by the GC itself, skip stack
103161
// frames until past the root GC stack frame. The root GC stack
@@ -106,48 +164,55 @@ unsafe fn walk_gc_roots(mem: Memory, sentinel: **Word, visitor: Visitor) {
106164
let mut reached_sentinel = ptr::is_null(sentinel);
107165
for stackwalk::walk_stack |frame| {
108166
unsafe {
167+
let pc = last_ret;
168+
let {segment: next_segment, boundary: boundary} =
169+
find_segment_for_frame(frame.fp, segment);
170+
segment = next_segment;
171+
let ret_offset = if boundary { 4 } else { 1 };
172+
last_ret = *ptr::offset(frame.fp, ret_offset) as *Word;
173+
174+
if ptr::is_null(pc) {
175+
again;
176+
}
177+
109178
let mut delay_reached_sentinel = reached_sentinel;
110-
if ptr::is_not_null(last_ret) {
111-
let sp = is_safe_point(last_ret);
112-
match sp {
113-
Some(sp_info) => {
114-
for walk_safe_point(frame.fp, sp_info) |root, tydesc| {
115-
// Skip roots until we see the sentinel.
116-
if !reached_sentinel {
117-
if root == sentinel {
118-
delay_reached_sentinel = true;
119-
}
120-
again;
179+
let sp = is_safe_point(pc);
180+
match sp {
181+
Some(sp_info) => {
182+
for walk_safe_point(frame.fp, sp_info) |root, tydesc| {
183+
// Skip roots until we see the sentinel.
184+
if !reached_sentinel {
185+
if root == sentinel {
186+
delay_reached_sentinel = true;
121187
}
188+
again;
189+
}
122190

123-
// Skip null pointers, which can occur when a
124-
// unique pointer has already been freed.
125-
if ptr::is_null(*root) {
126-
again;
127-
}
191+
// Skip null pointers, which can occur when a
192+
// unique pointer has already been freed.
193+
if ptr::is_null(*root) {
194+
again;
195+
}
128196

129-
if ptr::is_null(tydesc) {
130-
// Root is a generic box.
131-
let refcount = **root;
132-
if mem | task_local_heap != 0 && refcount != -1 {
133-
if !visitor(root, tydesc) { return; }
134-
} else if mem | exchange_heap != 0
135-
&& refcount == -1 {
136-
if !visitor(root, tydesc) { return; }
137-
}
138-
} else {
139-
// Root is a non-immediate.
140-
if mem | stack != 0 {
141-
if !visitor(root, tydesc) { return; }
142-
}
197+
if ptr::is_null(tydesc) {
198+
// Root is a generic box.
199+
let refcount = **root;
200+
if mem | task_local_heap != 0 && refcount != -1 {
201+
if !visitor(root, tydesc) { return; }
202+
} else if mem | exchange_heap != 0 && refcount == -1 {
203+
if !visitor(root, tydesc) { return; }
204+
}
205+
} else {
206+
// Root is a non-immediate.
207+
if mem | stack != 0 {
208+
if !visitor(root, tydesc) { return; }
143209
}
144210
}
145-
}
146-
None => ()
147211
}
212+
}
213+
None => ()
148214
}
149215
reached_sentinel = delay_reached_sentinel;
150-
last_ret = *ptr::offset(frame.fp, 1) as *Word;
151216
}
152217
}
153218
}

branches/dist-snap/src/rt/rust_builtin.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -610,6 +610,11 @@ rust_get_task() {
610610
return rust_get_current_task();
611611
}
612612

613+
extern "C" CDECL stk_seg *
614+
rust_get_stack_segment() {
615+
return rust_get_current_task()->stk;
616+
}
617+
613618
extern "C" CDECL void
614619
start_task(rust_task *target, fn_env_pair *f) {
615620
target->start(f->f, f->env, NULL);

branches/dist-snap/src/rt/rust_gc_metadata.cpp

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,9 @@
66
#include <vector>
77

88
struct safe_point {
9-
size_t safe_point_loc;
10-
size_t safe_point_meta;
11-
size_t function_meta;
9+
uintptr_t safe_point_loc;
10+
uintptr_t safe_point_meta;
11+
uintptr_t function_meta;
1212
};
1313

1414
struct update_gc_entry_args {
@@ -19,7 +19,7 @@ static void
1919
update_gc_entry(const mod_entry* entry, void *cookie) {
2020
update_gc_entry_args *args = (update_gc_entry_args *)cookie;
2121
if (!strcmp(entry->name, "_gc_module_metadata")) {
22-
size_t *next = entry->state;
22+
uintptr_t *next = entry->state;
2323
uint32_t num_safe_points = *(uint32_t *)next;
2424
next++;
2525

@@ -37,7 +37,7 @@ cmp_safe_point(safe_point a, safe_point b) {
3737
return a.safe_point_loc < b.safe_point_loc;
3838
}
3939

40-
size_t *global_safe_points = 0;
40+
uintptr_t *global_safe_points = 0;
4141

4242
void
4343
update_gc_metadata(const void* map) {
@@ -50,10 +50,10 @@ update_gc_metadata(const void* map) {
5050

5151
// Serialize safe point list into format expected by runtime.
5252
global_safe_points =
53-
(size_t *)malloc((safe_points.size()*3 + 1)*sizeof(size_t));
53+
(uintptr_t *)malloc((safe_points.size()*3 + 1)*sizeof(uintptr_t));
5454
if (!global_safe_points) return;
5555

56-
size_t *next = global_safe_points;
56+
uintptr_t *next = global_safe_points;
5757
*(uint32_t *)next = safe_points.size();
5858
next++;
5959
for (uint32_t i = 0; i < safe_points.size(); i++) {

branches/dist-snap/src/rt/rustrt.def.in

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ rust_env_pairs
5454
rust_task_yield
5555
rust_task_is_unwinding
5656
rust_get_task
57+
rust_get_stack_segment
5758
rust_task_weaken
5859
rust_task_unweaken
5960
sched_threads

0 commit comments

Comments
 (0)