(index<- )        ./libstd/rt/borrowck.rs

   1  // Copyright 2012 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  use cell::Cell;
  12  use c_str::{ToCStr, CString};
  13  use libc::{c_char, size_t};
  14  use option::{Option, None, Some};
  15  use ptr::RawPtr;
  16  use rt::env;
  17  use rt::local::Local;
  18  use rt::task;
  19  use rt::task::Task;
  20  use str::{OwnedStr, StrSlice};
  21  use str;
  22  use uint;
  23  use unstable::raw;
  24  use vec::ImmutableVector;
  25  
  26  pub static FROZEN_BIT: uint = 1 << (uint::bits - 1);
  27  pub static MUT_BIT: uint = 1 << (uint::bits - 2);
  28  static ALL_BITS: uint = FROZEN_BIT | MUT_BIT;
  29  
  30  #[deriving(Eq)]
  31  pub struct BorrowRecord {
  32      box: *mut raw::Box<()>,
  33      file: *c_char,
  34      line: size_t
  35  }
  36  
  37  fn try_take_task_borrow_list() -> Option<~[BorrowRecord]> {
  38      do Local::borrow |task&mut Task{
  39          task.borrow_list.take()
  40      }
  41  }
  42  
  43  fn swap_task_borrow_list(f&fn(~[BorrowRecord]) -> ~[BorrowRecord]) {
  44      let borrows = match try_take_task_borrow_list() {
  45          Some(l) => l,
  46          None => ~[]
  47      };
  48      let borrows = f(borrows);
  49      let borrows = Cell::new(borrows);
  50      do Local::borrow |task&mut Task{
  51          task.borrow_list = Some(borrows.take());
  52      }
  53  }
  54  
  55  pub fn clear_task_borrow_list() {
  56      // pub because it is used by the box annihilator.
  57      let _ = try_take_task_borrow_list();
  58  }
  59  
  60  unsafe fn fail_borrowed(box*mut raw::Box<()>, file*c_char, linesize_t) {
  61      debug_borrow("fail_borrowed: ", box, 0, 0, file, line);
  62  
  63      match try_take_task_borrow_list() {
  64          None => { // not recording borrows
  65              let msg = "borrowed";
  66              do msg.with_c_str |msg_p| {
  67                  task::begin_unwind(msg_p, file, line);
  68              }
  69          }
  70          Some(borrow_list) => { // recording borrows
  71              let mut msg = ~"borrowed";
  72              let mut sep = " at ";
  73              for entry in borrow_list.rev_iter() {
  74                  if entry.box == box {
  75                      msg.push_str(sep);
  76                      let filename = str::raw::from_c_str(entry.file);
  77                      msg.push_str(filename);
  78                      msg.push_str(format!(":{}", entry.line));
  79                      sep = " and at ";
  80                  }
  81              }
  82              do msg.with_c_str |msg_p| {
  83                  task::begin_unwind(msg_p, file, line)
  84              }
  85          }
  86      }
  87  }
  88  
  89  /// Because this code is so perf. sensitive, use a static constant so that
  90  /// debug printouts are compiled out most of the time.
  91  static ENABLE_DEBUG: bool = false;
  92  
  93  #[inline]
  94  unsafe fn debug_borrow<T,P:RawPtr<T>>(tag&'static str,
  95                                        pP,
  96                                        old_bitsuint,
  97                                        new_bitsuint,
  98                                        filename*c_char,
  99                                        linesize_t) {
 100      //! A useful debugging function that prints a pointer + tag + newline
 101      //! without allocating memory.
 102  
 103      if ENABLE_DEBUG && env::debug_borrow() {
 104          debug_borrow_slow(tag, p, old_bits, new_bits, filename, line);
 105      }
 106  
 107      unsafe fn debug_borrow_slow<T,P:RawPtr<T>>(tag&'static str,
 108                                                 pP,
 109                                                 old_bitsuint,
 110                                                 new_bitsuint,
 111                                                 filename*c_char,
 112                                                 linesize_t) {
 113          let filename = CString::new(filename, false);
 114          rterrln!("{}{:#x} {:x} {:x} {}:{}",
 115                   tag, p.to_uint(), old_bits, new_bits,
 116                   filename.as_str().unwrap(), line);
 117      }
 118  }
 119  
 120  #[inline]
 121  pub unsafe fn borrow_as_imm(a*u8, file*c_char, linesize_t) -> uint {
 122      let a = a as *mut raw::Box<()>;
 123      let old_ref_count = (*a).ref_count;
 124      let new_ref_count = old_ref_count | FROZEN_BIT;
 125  
 126      debug_borrow("borrow_as_imm:", a, old_ref_count, new_ref_count, file, line);
 127  
 128      if (old_ref_count & MUT_BIT) != 0 {
 129          fail_borrowed(a, file, line);
 130      }
 131  
 132      (*a).ref_count = new_ref_count;
 133  
 134      old_ref_count
 135  }
 136  
 137  #[inline]
 138  pub unsafe fn borrow_as_mut(a*u8, file*c_char, linesize_t) -> uint {
 139      let a = a as *mut raw::Box<()>;
 140      let old_ref_count = (*a).ref_count;
 141      let new_ref_count = old_ref_count | MUT_BIT | FROZEN_BIT;
 142  
 143      debug_borrow("borrow_as_mut:", a, old_ref_count, new_ref_count, file, line);
 144  
 145      if (old_ref_count & (MUT_BIT|FROZEN_BIT)) != 0 {
 146          fail_borrowed(a, file, line);
 147      }
 148  
 149      (*a).ref_count = new_ref_count;
 150  
 151      old_ref_count
 152  }
 153  
 154  pub unsafe fn record_borrow(a*u8, old_ref_countuint,
 155                              file*c_char, linesize_t) {
 156      if (old_ref_count & ALL_BITS) == 0 {
 157          // was not borrowed before
 158          let a = a as *mut raw::Box<()>;
 159          debug_borrow("record_borrow:", a, old_ref_count, 0, file, line);
 160          do swap_task_borrow_list |borrow_list| {
 161              let mut borrow_list = borrow_list;
 162              borrow_list.push(BorrowRecord {box: a, file: file, line: line});
 163              borrow_list
 164          }
 165      }
 166  }
 167  
 168  pub unsafe fn unrecord_borrow(a*u8, old_ref_countuint,
 169                                file*c_char, linesize_t) {
 170      if (old_ref_count & ALL_BITS) == 0 {
 171          // was not borrowed before, so we should find the record at
 172          // the end of the list
 173          let a = a as *mut raw::Box<()>;
 174          debug_borrow("unrecord_borrow:", a, old_ref_count, 0, file, line);
 175          do swap_task_borrow_list |borrow_list| {
 176              let mut borrow_list = borrow_list;
 177              assert!(!borrow_list.is_empty());
 178              let br = borrow_list.pop();
 179              if br.box != a || br.file != file || br.line != line {
 180                  let err = format!("wrong borrow found, br={:?}", br);
 181                  do err.with_c_str |msg_p| {
 182                      task::begin_unwind(msg_p, file, line)
 183                  }
 184              }
 185              borrow_list
 186          }
 187      }
 188  }
 189  
 190  #[inline]
 191  pub unsafe fn return_to_mut(a*u8, orig_ref_countuint,
 192                              file*c_char, linesize_t) {
 193      // Sometimes the box is null, if it is conditionally frozen.
 194      // See e.g. #4904.
 195      if !a.is_null() {
 196          let a = a as *mut raw::Box<()>;
 197          let old_ref_count = (*a).ref_count;
 198          let new_ref_count =
 199              (old_ref_count & !ALL_BITS) | (orig_ref_count & ALL_BITS);
 200  
 201          debug_borrow("return_to_mut:",
 202                       a, old_ref_count, new_ref_count, file, line);
 203  
 204          (*a).ref_count = new_ref_count;
 205      }
 206  }
 207  
 208  #[inline]
 209  pub unsafe fn check_not_borrowed(a*u8,
 210                                   file*c_char,
 211                                   linesize_t) {
 212      let a = a as *mut raw::Box<()>;
 213      let ref_count = (*a).ref_count;
 214      debug_borrow("check_not_borrowed:", a, ref_count, 0, file, line);
 215      if (ref_count & FROZEN_BIT) != 0 {
 216          fail_borrowed(a, file, line);
 217      }
 218  }

libstd/rt/borrowck.rs:167:1-167:1 -fn- definition:

pub unsafe fn unrecord_borrow(a: *u8, old_ref_count: uint,
references:-
libstd/unstable/lang.rs:
68:     borrowck::unrecord_borrow(a, old_ref_count, file, line)


libstd/rt/borrowck.rs:93:10-93:10 -fn- definition:
#[inline]
unsafe fn debug_borrow<T,P:RawPtr<T>>(tag: &'static str,
references:-
61:     debug_borrow("fail_borrowed: ", box, 0, 0, file, line);
174:         debug_borrow("unrecord_borrow:", a, old_ref_count, 0, file, line);
214:     debug_borrow("check_not_borrowed:", a, ref_count, 0, file, line);
159:         debug_borrow("record_borrow:", a, old_ref_count, 0, file, line);
126:     debug_borrow("borrow_as_imm:", a, old_ref_count, new_ref_count, file, line);
201:         debug_borrow("return_to_mut:",
143:     debug_borrow("borrow_as_mut:", a, old_ref_count, new_ref_count, file, line);


libstd/rt/borrowck.rs:54:1-54:1 -fn- definition:

pub fn clear_task_borrow_list() {
references:-
libstd/rt/task.rs:
263:         borrowck::clear_task_borrow_list();


libstd/rt/borrowck.rs:30:16-30:16 -struct- definition:
#[deriving(Eq)]
pub struct BorrowRecord {
references:-
30: #[deriving(Eq)]
30: #[deriving(Eq)]
43: fn swap_task_borrow_list(f: &fn(~[BorrowRecord]) -> ~[BorrowRecord]) {
30: #[deriving(Eq)]
37: fn try_take_task_borrow_list() -> Option<~[BorrowRecord]> {
30: #[deriving(Eq)]
43: fn swap_task_borrow_list(f: &fn(~[BorrowRecord]) -> ~[BorrowRecord]) {
30: #[deriving(Eq)]
30: #[deriving(Eq)]
162:             borrow_list.push(BorrowRecord {box: a, file: file, line: line});
30: #[deriving(Eq)]
libstd/rt/task.rs:
58:     borrow_list: Option<~[BorrowRecord]>


libstd/rt/borrowck.rs:36:1-36:1 -fn- definition:

fn try_take_task_borrow_list() -> Option<~[BorrowRecord]> {
references:-
57:     let _ = try_take_task_borrow_list();
63:     match try_take_task_borrow_list() {
44:     let borrows = match try_take_task_borrow_list() {


libstd/rt/borrowck.rs:42:1-42:1 -fn- definition:

fn swap_task_borrow_list(f: &fn(~[BorrowRecord]) -> ~[BorrowRecord]) {
references:-
160:         do swap_task_borrow_list |borrow_list| {
175:         do swap_task_borrow_list |borrow_list| {


libstd/rt/borrowck.rs:153:1-153:1 -fn- definition:

pub unsafe fn record_borrow(a: *u8, old_ref_count: uint,
references:-
libstd/unstable/lang.rs:
62:     borrowck::record_borrow(a, old_ref_count, file, line)


libstd/rt/borrowck.rs:190:10-190:10 -fn- definition:
#[inline]
pub unsafe fn return_to_mut(a: *u8, orig_ref_count: uint,
references:-
libstd/unstable/lang.rs:
75:     borrowck::return_to_mut(a, orig_ref_count, file, line)


libstd/rt/borrowck.rs:107:4-107:4 -fn- definition:
    unsafe fn debug_borrow_slow<T,P:RawPtr<T>>(tag: &'static str,
                                               p: P,
references:-
104:         debug_borrow_slow(tag, p, old_bits, new_bits, filename, line);


libstd/rt/borrowck.rs:208:10-208:10 -fn- definition:
#[inline]
pub unsafe fn check_not_borrowed(a: *u8,
references:-
libstd/unstable/lang.rs:
83:     borrowck::check_not_borrowed(a, file, line)


libstd/rt/borrowck.rs:137:10-137:10 -fn- definition:
#[inline]
pub unsafe fn borrow_as_mut(a: *u8, file: *c_char, line: size_t) -> uint {
references:-
libstd/unstable/lang.rs:
56:     borrowck::borrow_as_mut(a, file, line)


libstd/rt/borrowck.rs:120:10-120:10 -fn- definition:
#[inline]
pub unsafe fn borrow_as_imm(a: *u8, file: *c_char, line: size_t) -> uint {
references:-
libstd/unstable/lang.rs:
50:     borrowck::borrow_as_imm(a, file, line)


libstd/rt/borrowck.rs:59:1-59:1 -fn- definition:

unsafe fn fail_borrowed(box: *mut raw::Box<()>, file: *c_char, line: size_t) {
references:-
129:         fail_borrowed(a, file, line);
146:         fail_borrowed(a, file, line);
216:         fail_borrowed(a, file, line);