Skip to content

Commit 2f12e26

Browse files
committed
auto merge of #5083 : graydon/rust/gc, r=graydon
r? @pcwalton Local testing shows it's correctly putting things like ~(@10) in the managed heap. Not entirely sure how to turn such tests (which just log annihilation stats) into a regression test; we don't have much in the way of feedback from the annihilator. Open to suggestions. I will want to be keeping more detailed runtime stats on the gc as I proceed.
2 parents cec1f38 + 0309af4 commit 2f12e26

File tree

13 files changed

+186
-60
lines changed

13 files changed

+186
-60
lines changed

src/libcore/cleanup.rs

+81-24
Original file line numberDiff line numberDiff line change
@@ -111,45 +111,102 @@ struct Task {
111111
* This runs at task death to free all boxes.
112112
*/
113113

114+
struct AnnihilateStats {
115+
n_total_boxes: uint,
116+
n_unique_boxes: uint,
117+
n_bytes_freed: uint
118+
}
119+
120+
unsafe fn each_live_alloc(f: fn(box: *mut BoxRepr, uniq: bool) -> bool) {
121+
use managed;
122+
123+
let task: *Task = transmute(rustrt::rust_get_task());
124+
let box = (*task).boxed_region.live_allocs;
125+
let mut box: *mut BoxRepr = transmute(copy box);
126+
while box != mut_null() {
127+
let next = transmute(copy (*box).header.next);
128+
let uniq =
129+
(*box).header.ref_count == managed::raw::RC_MANAGED_UNIQUE;
130+
131+
if ! f(box, uniq) {
132+
break
133+
}
134+
135+
box = next
136+
}
137+
}
138+
139+
#[cfg(unix)]
140+
fn debug_mem() -> bool {
141+
use os;
142+
use libc;
143+
do os::as_c_charp("RUST_DEBUG_MEM") |p| {
144+
unsafe { libc::getenv(p) != null() }
145+
}
146+
}
147+
148+
#[cfg(windows)]
149+
fn debug_mem() -> bool {
150+
false
151+
}
152+
114153
/// Destroys all managed memory (i.e. @ boxes) held by the current task.
115154
#[cfg(notest)]
116155
#[lang="annihilate"]
117156
pub unsafe fn annihilate() {
118157
use rt::rt_free;
119158
use io::WriterUtil;
159+
use io;
160+
use libc;
161+
use sys;
162+
use managed;
120163

121-
let task: *Task = transmute(rustrt::rust_get_task());
164+
let mut stats = AnnihilateStats {
165+
n_total_boxes: 0,
166+
n_unique_boxes: 0,
167+
n_bytes_freed: 0
168+
};
122169

123170
// Pass 1: Make all boxes immortal.
124-
let box = (*task).boxed_region.live_allocs;
125-
let mut box: *mut BoxRepr = transmute(copy box);
126-
while box != mut_null() {
127-
debug!("making box immortal: %x", box as uint);
128-
(*box).header.ref_count = 0x77777777;
129-
box = transmute(copy (*box).header.next);
171+
for each_live_alloc |box, uniq| {
172+
stats.n_total_boxes += 1;
173+
if uniq {
174+
stats.n_unique_boxes += 1;
175+
} else {
176+
(*box).header.ref_count = managed::raw::RC_IMMORTAL;
177+
}
130178
}
131179

132180
// Pass 2: Drop all boxes.
133-
let box = (*task).boxed_region.live_allocs;
134-
let mut box: *mut BoxRepr = transmute(copy box);
135-
while box != mut_null() {
136-
debug!("calling drop glue for box: %x", box as uint);
137-
let tydesc: *TypeDesc = transmute(copy (*box).header.type_desc);
138-
let drop_glue: DropGlue = transmute(((*tydesc).drop_glue, 0));
139-
drop_glue(to_unsafe_ptr(&tydesc), transmute(&(*box).data));
140-
141-
box = transmute(copy (*box).header.next);
181+
for each_live_alloc |box, uniq| {
182+
if !uniq {
183+
let tydesc: *TypeDesc = transmute(copy (*box).header.type_desc);
184+
let drop_glue: DropGlue = transmute(((*tydesc).drop_glue, 0));
185+
drop_glue(to_unsafe_ptr(&tydesc), transmute(&(*box).data));
186+
}
142187
}
143188

144189
// Pass 3: Free all boxes.
145-
loop {
146-
let box = (*task).boxed_region.live_allocs;
147-
if box == null() { break; }
148-
let mut box: *mut BoxRepr = transmute(copy box);
149-
assert (*box).header.prev == null();
150-
151-
debug!("freeing box: %x", box as uint);
152-
rt_free(transmute(box));
190+
for each_live_alloc |box, uniq| {
191+
if !uniq {
192+
stats.n_bytes_freed +=
193+
(*((*box).header.type_desc)).size
194+
+ sys::size_of::<BoxRepr>();
195+
rt_free(transmute(box));
196+
}
197+
}
198+
199+
if debug_mem() {
200+
// We do logging here w/o allocation.
201+
let dbg = libc::STDERR_FILENO as io::fd_t;
202+
dbg.write_str("annihilator stats:");
203+
dbg.write_str("\n total_boxes: ");
204+
dbg.write_uint(stats.n_total_boxes);
205+
dbg.write_str("\n unique_boxes: ");
206+
dbg.write_uint(stats.n_unique_boxes);
207+
dbg.write_str("\n bytes_freed: ");
208+
dbg.write_uint(stats.n_bytes_freed);
209+
dbg.write_str("\n");
153210
}
154211
}
155212

src/libcore/managed.rs

+6
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,13 @@ use managed::raw::BoxRepr;
1616
use prelude::*;
1717
use ptr;
1818

19+
1920
pub mod raw {
21+
22+
pub const RC_EXCHANGE_UNIQUE : uint = (-1) as uint;
23+
pub const RC_MANAGED_UNIQUE : uint = (-2) as uint;
24+
pub const RC_IMMORTAL : uint = 0x77777777;
25+
2026
use intrinsic::TyDesc;
2127

2228
pub struct BoxHeaderRepr {

src/libcore/vec.rs

+14-3
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
1+
// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
22
// file at the top-level directory of this distribution and at
33
// http://rust-lang.org/COPYRIGHT.
44
//
@@ -31,9 +31,14 @@ use vec;
3131

3232
#[abi = "cdecl"]
3333
pub extern mod rustrt {
34+
// These names are terrible. reserve_shared applies
35+
// to ~[] and reserve_shared_actual applies to @[].
3436
unsafe fn vec_reserve_shared(++t: *sys::TypeDesc,
3537
++v: **raw::VecRepr,
3638
++n: libc::size_t);
39+
unsafe fn vec_reserve_shared_actual(++t: *sys::TypeDesc,
40+
++v: **raw::VecRepr,
41+
++n: libc::size_t);
3742
}
3843

3944
/// Returns true if a vector contains no elements
@@ -59,11 +64,17 @@ pub pure fn same_length<T, U>(xs: &[const T], ys: &[const U]) -> bool {
5964
*/
6065
pub fn reserve<T>(v: &mut ~[T], n: uint) {
6166
// Only make the (slow) call into the runtime if we have to
67+
use managed;
6268
if capacity(v) < n {
6369
unsafe {
6470
let ptr: **raw::VecRepr = cast::transmute(v);
65-
rustrt::vec_reserve_shared(sys::get_type_desc::<T>(),
66-
ptr, n as size_t);
71+
let td = sys::get_type_desc::<T>();
72+
if ((**ptr).box_header.ref_count ==
73+
managed::raw::RC_MANAGED_UNIQUE) {
74+
rustrt::vec_reserve_shared_actual(td, ptr, n as size_t);
75+
} else {
76+
rustrt::vec_reserve_shared(td, ptr, n as size_t);
77+
}
6778
}
6879
}
6980
}

src/librustc/middle/trans/base.rs

+26-4
Original file line numberDiff line numberDiff line change
@@ -286,7 +286,7 @@ pub fn malloc_raw_dyn(bcx: block,
286286
let ccx = bcx.ccx();
287287

288288
let (mk_fn, langcall) = match heap {
289-
heap_shared => {
289+
heap_managed | heap_managed_unique => {
290290
(ty::mk_imm_box, bcx.tcx().lang_items.malloc_fn())
291291
}
292292
heap_exchange => {
@@ -310,7 +310,9 @@ pub fn malloc_raw_dyn(bcx: block,
310310
langcall,
311311
~[tydesc, size],
312312
expr::SaveIn(rval));
313-
return rslt(bcx, PointerCast(bcx, Load(bcx, rval), llty));
313+
let r = rslt(bcx, PointerCast(bcx, Load(bcx, rval), llty));
314+
maybe_set_managed_unique_rc(r.bcx, r.val, heap);
315+
r
314316
}
315317

316318
/**
@@ -364,11 +366,31 @@ pub fn malloc_general(bcx: block, t: ty::t, heap: heap)
364366
}
365367
pub fn malloc_boxed(bcx: block, t: ty::t)
366368
-> MallocResult {
367-
malloc_general(bcx, t, heap_shared)
369+
malloc_general(bcx, t, heap_managed)
368370
}
371+
372+
pub fn heap_for_unique(bcx: block, t: ty::t) -> heap {
373+
if ty::type_contents(bcx.tcx(), t).contains_managed() {
374+
heap_managed_unique
375+
} else {
376+
heap_exchange
377+
}
378+
}
379+
380+
pub fn maybe_set_managed_unique_rc(bcx: block, bx: ValueRef, heap: heap) {
381+
if heap == heap_managed_unique {
382+
// In cases where we are looking at a unique-typed allocation in the
383+
// managed heap (thus have refcount 1 from the managed allocator),
384+
// such as a ~(@foo) or such. These need to have their refcount forced
385+
// to -2 so the annihilator ignores them.
386+
let rc = GEPi(bcx, bx, [0u, abi::box_field_refcnt]);
387+
Store(bcx, C_int(bcx.ccx(), -2), rc);
388+
}
389+
}
390+
369391
pub fn malloc_unique(bcx: block, t: ty::t)
370392
-> MallocResult {
371-
malloc_general(bcx, t, heap_exchange)
393+
malloc_general(bcx, t, heap_for_unique(bcx, t))
372394
}
373395

374396
// Type descriptor and type glue stuff

src/librustc/middle/trans/closure.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -178,10 +178,10 @@ pub fn allocate_cbox(bcx: block, sigil: ast::Sigil, cdata_ty: ty::t)
178178
// Allocate and initialize the box:
179179
match sigil {
180180
ast::ManagedSigil => {
181-
malloc_raw(bcx, cdata_ty, heap_shared)
181+
malloc_raw(bcx, cdata_ty, heap_managed)
182182
}
183183
ast::OwnedSigil => {
184-
malloc_raw(bcx, cdata_ty, heap_exchange)
184+
malloc_raw(bcx, cdata_ty, heap_for_unique(bcx, cdata_ty))
185185
}
186186
ast::BorrowedSigil => {
187187
let cbox_ty = tuplify_box_ty(tcx, cdata_ty);
@@ -574,7 +574,7 @@ pub fn make_opaque_cbox_free_glue(
574574
// Free the ty descr (if necc) and the box itself
575575
match sigil {
576576
ast::ManagedSigil => glue::trans_free(bcx, cbox),
577-
ast::OwnedSigil => glue::trans_unique_free(bcx, cbox),
577+
ast::OwnedSigil => glue::trans_exchange_free(bcx, cbox),
578578
ast::BorrowedSigil => {
579579
bcx.sess().bug(~"impossible")
580580
}

src/librustc/middle/trans/common.rs

+5-3
Original file line numberDiff line numberDiff line change
@@ -332,8 +332,10 @@ pub fn warn_not_to_commit(ccx: @CrateContext, msg: ~str) {
332332
}
333333
334334
// Heap selectors. Indicate which heap something should go on.
335+
#[deriving_eq]
335336
pub enum heap {
336-
heap_shared,
337+
heap_managed,
338+
heap_managed_unique,
337339
heap_exchange,
338340
}
339341
@@ -458,12 +460,12 @@ pub fn add_clean_frozen_root(bcx: block, val: ValueRef, t: ty::t) {
458460
}
459461
pub fn add_clean_free(cx: block, ptr: ValueRef, heap: heap) {
460462
let free_fn = match heap {
461-
heap_shared => {
463+
heap_managed | heap_managed_unique => {
462464
let f: @fn(block) -> block = |a| glue::trans_free(a, ptr);
463465
f
464466
}
465467
heap_exchange => {
466-
let f: @fn(block) -> block = |a| glue::trans_unique_free(a, ptr);
468+
let f: @fn(block) -> block = |a| glue::trans_exchange_free(a, ptr);
467469
f
468470
}
469471
};

src/librustc/middle/trans/expr.rs

+7-4
Original file line numberDiff line numberDiff line change
@@ -414,11 +414,12 @@ fn trans_rvalue_datum_unadjusted(bcx: block, expr: @ast::expr) -> DatumBlock {
414414
match expr.node {
415415
ast::expr_vstore(contents, ast::expr_vstore_box) |
416416
ast::expr_vstore(contents, ast::expr_vstore_mut_box) => {
417-
return tvec::trans_uniq_or_managed_vstore(bcx, heap_shared,
417+
return tvec::trans_uniq_or_managed_vstore(bcx, heap_managed,
418418
expr, contents);
419419
}
420420
ast::expr_vstore(contents, ast::expr_vstore_uniq) => {
421-
return tvec::trans_uniq_or_managed_vstore(bcx, heap_exchange,
421+
let heap = heap_for_unique(bcx, expr_ty(bcx, contents));
422+
return tvec::trans_uniq_or_managed_vstore(bcx, heap,
422423
expr, contents);
423424
}
424425
ast::expr_lit(lit) => {
@@ -1272,10 +1273,12 @@ fn trans_unary_datum(bcx: block,
12721273
immediate_rvalue_bcx(bcx, llneg, un_ty)
12731274
}
12741275
ast::box(_) => {
1275-
trans_boxed_expr(bcx, un_ty, sub_expr, sub_ty, heap_shared)
1276+
trans_boxed_expr(bcx, un_ty, sub_expr, sub_ty,
1277+
heap_managed)
12761278
}
12771279
ast::uniq(_) => {
1278-
trans_boxed_expr(bcx, un_ty, sub_expr, sub_ty, heap_exchange)
1280+
let heap = heap_for_unique(bcx, un_ty);
1281+
trans_boxed_expr(bcx, un_ty, sub_expr, sub_ty, heap)
12791282
}
12801283
ast::deref => {
12811284
bcx.sess().bug(~"deref expressions should have been \

src/librustc/middle/trans/glue.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,8 @@ pub fn trans_free(cx: block, v: ValueRef) -> block {
3737
expr::Ignore)
3838
}
3939

40-
pub fn trans_unique_free(cx: block, v: ValueRef) -> block {
41-
let _icx = cx.insn_ctxt("trans_unique_free");
40+
pub fn trans_exchange_free(cx: block, v: ValueRef) -> block {
41+
let _icx = cx.insn_ctxt("trans_exchange_free");
4242
callee::trans_rtcall_or_lang_call(
4343
cx,
4444
cx.tcx().lang_items.exchange_free_fn(),

src/librustc/middle/trans/meth.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -878,7 +878,7 @@ pub fn trans_trait_cast(bcx: block,
878878
let MallocResult {bcx: new_bcx, box: llbox, body: body} =
879879
malloc_boxed(bcx, v_ty);
880880
bcx = new_bcx;
881-
add_clean_free(bcx, llbox, heap_shared);
881+
add_clean_free(bcx, llbox, heap_managed);
882882
bcx = expr::trans_into(bcx, val, SaveIn(body));
883883
revoke_clean(bcx, llbox);
884884

src/librustc/middle/trans/tvec.rs

+5-2
Original file line numberDiff line numberDiff line change
@@ -85,11 +85,13 @@ pub fn alloc_raw(bcx: block, unit_ty: ty::t,
8585
base::malloc_general_dyn(bcx, vecbodyty, heap, vecsize);
8686
Store(bcx, fill, GEPi(bcx, body, [0u, abi::vec_elt_fill]));
8787
Store(bcx, alloc, GEPi(bcx, body, [0u, abi::vec_elt_alloc]));
88+
base::maybe_set_managed_unique_rc(bcx, bx, heap);
8889
return rslt(bcx, bx);
8990
}
91+
9092
pub fn alloc_uniq_raw(bcx: block, unit_ty: ty::t,
9193
fill: ValueRef, alloc: ValueRef) -> Result {
92-
alloc_raw(bcx, unit_ty, fill, alloc, heap_exchange)
94+
alloc_raw(bcx, unit_ty, fill, alloc, heap_for_unique(bcx, unit_ty))
9395
}
9496

9597
pub fn alloc_vec(bcx: block,
@@ -317,13 +319,14 @@ pub fn trans_uniq_or_managed_vstore(bcx: block,
317319
_ => {}
318320
}
319321
}
320-
heap_shared => {}
322+
heap_managed | heap_managed_unique => {}
321323
}
322324

323325
let vt = vec_types_from_expr(bcx, vstore_expr);
324326
let count = elements_required(bcx, content_expr);
325327

326328
let Result {bcx, val} = alloc_vec(bcx, vt.unit_ty, count, heap);
329+
327330
add_clean_free(bcx, val, heap);
328331
let dataptr = get_dataptr(bcx, get_bodyptr(bcx, val));
329332

src/librustc/middle/trans/uniq.rs

+5-1
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,11 @@ pub fn make_free_glue(bcx: block, vptrptr: ValueRef, box_ty: ty::t)
3030
let body_datum = box_datum.box_body(bcx);
3131
let bcx = glue::drop_ty(bcx, body_datum.to_ref_llval(bcx),
3232
body_datum.ty);
33-
glue::trans_unique_free(bcx, box_datum.val)
33+
if ty::type_contents(bcx.tcx(), box_ty).contains_managed() {
34+
glue::trans_free(bcx, box_datum.val)
35+
} else {
36+
glue::trans_exchange_free(bcx, box_datum.val)
37+
}
3438
}
3539
}
3640

0 commit comments

Comments
 (0)