diff options
| author | Niko Matsakis <niko@alum.mit.edu> | 2013-05-01 10:29:47 -0400 |
|---|---|---|
| committer | Niko Matsakis <niko@alum.mit.edu> | 2013-05-01 10:30:54 -0400 |
| commit | 4af2d90af59bb5e28e5d114d8a6004d68fad3bd5 (patch) | |
| tree | c5be284688af69a2843258f71511686827bc21d1 | |
| parent | 84861101eca12942b42f36f8adb18cfc74515431 (diff) | |
| download | rust-4af2d90af59bb5e28e5d114d8a6004d68fad3bd5.tar.gz rust-4af2d90af59bb5e28e5d114d8a6004d68fad3bd5.zip | |
add an option to debug borrows (RUST_DEBUG_BORROW) so you can
find out where the offending borrow occurred. This ... still needs some work.
| -rw-r--r-- | src/libcore/rt/env.rs | 6 | ||||
| -rw-r--r-- | src/libcore/unstable/lang.rs | 78 | ||||
| -rw-r--r-- | src/librustc/middle/trans/_match.rs | 2 | ||||
| -rw-r--r-- | src/librustc/middle/trans/datum.rs | 14 | ||||
| -rw-r--r-- | src/librustc/middle/trans/expr.rs | 2 | ||||
| -rw-r--r-- | src/rt/rust_builtin.cpp | 14 | ||||
| -rw-r--r-- | src/rt/rust_env.cpp | 2 | ||||
| -rw-r--r-- | src/rt/rust_env.h | 1 | ||||
| -rw-r--r-- | src/rt/rust_task.cpp | 11 | ||||
| -rw-r--r-- | src/rt/rust_task.h | 5 |
10 files changed, 121 insertions, 14 deletions
diff --git a/src/libcore/rt/env.rs b/src/libcore/rt/env.rs index 92e2ec51306..1f52cf77868 100644 --- a/src/libcore/rt/env.rs +++ b/src/libcore/rt/env.rs @@ -31,8 +31,10 @@ pub struct Environment { argc: c_int, /// The argv value passed to main argv: **c_char, - /// Print GC debugging info - debug_mem: bool + /// Print GC debugging info (true if env var RUST_DEBUG_MEM is set) + debug_mem: bool, + /// Track origin of `@mut` borrows (true if env var RUST_DEBUG_BORROWS is set) + debug_borrows: bool } /// Get the global environment settings diff --git a/src/libcore/unstable/lang.rs b/src/libcore/unstable/lang.rs index c5062f25ea5..0705be7cdef 100644 --- a/src/libcore/unstable/lang.rs +++ b/src/libcore/unstable/lang.rs @@ -17,6 +17,7 @@ use str; use sys; use unstable::exchange_alloc; use cast::transmute; +use task::rt::rust_get_task; #[allow(non_camel_case_types)] pub type rust_task = c_void; @@ -27,7 +28,8 @@ pub static FROZEN_BIT: uint = 0x80000000; pub static FROZEN_BIT: uint = 0x8000000000000000; pub mod rustrt { - use libc::{c_char, uintptr_t}; + use unstable::lang::rust_task; + use libc::{c_void, c_char, uintptr_t}; pub extern { #[rust_stack] @@ -43,6 +45,12 @@ pub mod rustrt { #[fast_ffi] unsafe fn rust_upcall_free_noswitch(ptr: *c_char); + + #[rust_stack] + fn rust_take_task_borrow_list(task: *rust_task) -> *c_void; + + #[rust_stack] + fn rust_set_task_borrow_list(task: *rust_task, map: *c_void); } } @@ -61,10 +69,50 @@ pub fn fail_bounds_check(file: *c_char, line: size_t, } } -pub fn fail_borrowed(file: *c_char, line: size_t) { - let msg = "borrowed"; - do str::as_buf(msg) |msg_p, _| { - fail_(msg_p as *c_char, file, line); +struct BorrowRecord { + box: *mut BoxRepr, + file: *c_char, + line: size_t +} + +fn swap_task_borrow_list(f: &fn(~[BorrowRecord]) -> ~[BorrowRecord]) { + unsafe { + let cur_task = rust_get_task(); + let mut borrow_list: ~[BorrowRecord] = { + let ptr = rustrt::rust_take_task_borrow_list(cur_task); + if ptr.is_null() { ~[] } else { transmute(ptr) } + }; + borrow_list = f(borrow_list); + rustrt::rust_set_task_borrow_list(cur_task, transmute(borrow_list)); + } +} + +pub fn fail_borrowed(box: *mut BoxRepr, file: *c_char, line: size_t) { + if !::rt::env::get().debug_borrows { + let msg = "borrowed"; + do str::as_buf(msg) |msg_p, _| { + fail_(msg_p as *c_char, file, line); + } + } else { + do swap_task_borrow_list |borrow_list| { + let mut msg = ~"borrowed"; + let mut sep = " at "; + for borrow_list.each_reverse |entry| { + if entry.box == box { + str::push_str(&mut msg, sep); + let filename = unsafe { + str::raw::from_c_str(entry.file) + }; + str::push_str(&mut msg, filename); + str::push_str(&mut msg, fmt!(":%u", line as uint)); + sep = " and at "; + } + } + do str::as_buf(msg) |msg_p, _| { + fail_(msg_p as *c_char, file, line) + } + borrow_list + } } } @@ -140,6 +188,7 @@ pub unsafe fn local_free(ptr: *c_char) { rustrt::rust_upcall_free_noswitch(ptr); } +#[cfg(stage0)] #[lang="borrow_as_imm"] #[inline(always)] pub unsafe fn borrow_as_imm(a: *u8) { @@ -147,6 +196,21 @@ pub unsafe fn borrow_as_imm(a: *u8) { (*a).header.ref_count |= FROZEN_BIT; } +#[cfg(not(stage0))] +#[lang="borrow_as_imm"] +#[inline(always)] +pub unsafe fn borrow_as_imm(a: *u8, file: *c_char, line: size_t) { + let a: *mut BoxRepr = transmute(a); + (*a).header.ref_count |= FROZEN_BIT; + if ::rt::env::get().debug_borrows { + do swap_task_borrow_list |borrow_list| { + let mut borrow_list = borrow_list; + borrow_list.push(BorrowRecord {box: a, file: file, line: line}); + borrow_list + } + } +} + #[lang="return_to_mut"] #[inline(always)] pub unsafe fn return_to_mut(a: *u8) { @@ -165,7 +229,7 @@ pub unsafe fn check_not_borrowed(a: *u8) { let a: *mut BoxRepr = transmute(a); if ((*a).header.ref_count & FROZEN_BIT) != 0 { do str::as_buf("XXX") |file_p, _| { - fail_borrowed(file_p as *c_char, 0); + fail_borrowed(a, file_p as *c_char, 0); } } } @@ -178,7 +242,7 @@ pub unsafe fn check_not_borrowed(a: *u8, line: size_t) { let a: *mut BoxRepr = transmute(a); if ((*a).header.ref_count & FROZEN_BIT) != 0 { - fail_borrowed(file, line); + fail_borrowed(a, file, line); } } diff --git a/src/librustc/middle/trans/_match.rs b/src/librustc/middle/trans/_match.rs index 785bb3edc07..d7f9567c333 100644 --- a/src/librustc/middle/trans/_match.rs +++ b/src/librustc/middle/trans/_match.rs @@ -966,7 +966,7 @@ pub fn root_pats_as_necessary(bcx: block, let datum = Datum {val: val, ty: node_id_type(bcx, pat_id), mode: ByRef, source: ZeroMem}; - bcx = datum.root(bcx, root_info); + bcx = datum.root(bcx, br.pats[col].span, root_info); // If we kept going, we'd only re-root the same value, so // return now. return bcx; diff --git a/src/librustc/middle/trans/datum.rs b/src/librustc/middle/trans/datum.rs index 03c81cad50e..ae71a3e6c22 100644 --- a/src/librustc/middle/trans/datum.rs +++ b/src/librustc/middle/trans/datum.rs @@ -517,7 +517,7 @@ pub impl Datum { } } - fn root(&self, bcx: block, root_info: RootInfo) -> block { + fn root(&self, bcx: block, span: span, root_info: RootInfo) -> block { /*! * * In some cases, borrowck will decide that an @T/@[]/@str @@ -542,6 +542,12 @@ pub impl Datum { // If we need to freeze the box, do that now. if root_info.freeze.is_some() { // NOTE distinguish the two kinds of freezing here + + let loc = bcx.sess().parse_sess.cm.lookup_char_pos(span.lo); + let line = C_int(bcx.ccx(), loc.line as int); + let filename_cstr = C_cstr(bcx.ccx(), @/*bad*/copy loc.file.name); + let filename = PointerCast(bcx, filename_cstr, T_ptr(T_i8())); + callee::trans_lang_call( bcx, bcx.tcx().lang_items.borrow_as_imm_fn(), @@ -549,7 +555,9 @@ pub impl Datum { Load(bcx, PointerCast(bcx, scratch.val, - T_ptr(T_ptr(T_i8())))) + T_ptr(T_ptr(T_i8())))), + filename, + line ], expr::Ignore) } else { @@ -647,7 +655,7 @@ pub impl Datum { let key = root_map_key { id: expr_id, derefs: derefs }; let bcx = match ccx.maps.root_map.find(&key) { None => bcx, - Some(&root_info) => self.root(bcx, root_info) + Some(&root_info) => self.root(bcx, span, root_info) }; // Perform the write guard, if necessary. diff --git a/src/librustc/middle/trans/expr.rs b/src/librustc/middle/trans/expr.rs index bc44d7de983..166b8bc01f8 100644 --- a/src/librustc/middle/trans/expr.rs +++ b/src/librustc/middle/trans/expr.rs @@ -828,7 +828,7 @@ fn trans_lvalue_unadjusted(bcx: block, expr: @ast::expr) -> DatumBlock { // at the end of the scope with id `scope_id`: let root_key = root_map_key { id: expr.id, derefs: 0u }; for bcx.ccx().maps.root_map.find(&root_key).each |&root_info| { - bcx = unrooted_datum.root(bcx, *root_info); + bcx = unrooted_datum.root(bcx, expr.span, *root_info); } return DatumBlock {bcx: bcx, datum: unrooted_datum}; diff --git a/src/rt/rust_builtin.cpp b/src/rt/rust_builtin.cpp index ee025a39ff4..197b8b36d2d 100644 --- a/src/rt/rust_builtin.cpp +++ b/src/rt/rust_builtin.cpp @@ -683,6 +683,20 @@ rust_task_local_data_atexit(rust_task *task, void (*cleanup_fn)(void *data)) { task->task_local_data_cleanup = cleanup_fn; } +// set/get/atexit task_borrow_list can run on the rust stack for speed. +extern "C" void * +rust_take_task_borrow_list(rust_task *task) { + void *r = task->borrow_list; + task->borrow_list = NULL; + return r; +} +extern "C" void +rust_set_task_borrow_list(rust_task *task, void *data) { + assert(task->borrow_list == NULL); + assert(data != NULL); + task->borrow_list = data; +} + extern "C" void task_clear_event_reject(rust_task *task) { task->clear_event_reject(); diff --git a/src/rt/rust_env.cpp b/src/rt/rust_env.cpp index 041b4efac52..e6fe35609ec 100644 --- a/src/rt/rust_env.cpp +++ b/src/rt/rust_env.cpp @@ -24,6 +24,7 @@ #define RUST_SEED "RUST_SEED" #define RUST_POISON_ON_FREE "RUST_POISON_ON_FREE" #define RUST_DEBUG_MEM "RUST_DEBUG_MEM" +#define RUST_DEBUG_BORROWS "RUST_DEBUG_BORROWS" #if defined(__WIN32__) static int @@ -130,6 +131,7 @@ load_env(int argc, char **argv) { env->argc = argc; env->argv = argv; env->debug_mem = getenv(RUST_DEBUG_MEM) != NULL; + env->debug_borrows = getenv(RUST_DEBUG_BORROWS) != NULL; return env; } diff --git a/src/rt/rust_env.h b/src/rt/rust_env.h index df27f7674f2..322198bb031 100644 --- a/src/rt/rust_env.h +++ b/src/rt/rust_env.h @@ -28,6 +28,7 @@ struct rust_env { int argc; char **argv; rust_bool debug_mem; + rust_bool debug_borrows; }; rust_env* load_env(int argc, char **argv); diff --git a/src/rt/rust_task.cpp b/src/rt/rust_task.cpp index e6293aa5c1d..ea42936f2e5 100644 --- a/src/rt/rust_task.cpp +++ b/src/rt/rust_task.cpp @@ -42,6 +42,7 @@ rust_task::rust_task(rust_sched_loop *sched_loop, rust_task_state state, total_stack_sz(0), task_local_data(NULL), task_local_data_cleanup(NULL), + borrow_list(NULL), state(state), cond(NULL), cond_name("none"), @@ -75,6 +76,16 @@ rust_task::delete_this() assert(ref_count == 0); // || // (ref_count == 1 && this == sched->root_task)); + if (borrow_list) { + // NOTE should free borrow_list from within rust code! + // If there is a pointer in there, it is a ~[BorrowRecord] pointer, + // which are currently allocated with LIBC malloc/free. But this is + // not really the right way to do this, we should be freeing this + // pointer from Rust code. + free(borrow_list); + borrow_list = NULL; + } + sched_loop->release_task(this); } diff --git a/src/rt/rust_task.h b/src/rt/rust_task.h index 4aa1199cabc..dc45c0439ea 100644 --- a/src/rt/rust_task.h +++ b/src/rt/rust_task.h @@ -241,6 +241,11 @@ rust_task : public kernel_owned<rust_task> void *task_local_data; void (*task_local_data_cleanup)(void *data); + // Contains a ~[BorrowRecord] pointer, or NULL. + // + // Used by borrow management code in libcore/unstable/lang.rs. + void *borrow_list; + private: // Protects state, cond, cond_name |
