wip---work on making rooting work properly
This commit is contained in:
parent
3159335ac3
commit
38f93f2121
8 changed files with 178 additions and 120 deletions
|
|
@ -200,6 +200,8 @@ impl Mul<T,T> for T {
|
|||
#[inline(always)]
|
||||
fn mul(&self, other: &T) -> T { *self * *other }
|
||||
}
|
||||
|
||||
#[cfg(notest)]
|
||||
impl Quot<T,T> for T {
|
||||
///
|
||||
/// Returns the integer quotient, truncated towards 0. As this behaviour reflects
|
||||
|
|
@ -222,6 +224,8 @@ impl Quot<T,T> for T {
|
|||
#[inline(always)]
|
||||
fn quot(&self, other: &T) -> T { *self / *other }
|
||||
}
|
||||
|
||||
#[cfg(notest)]
|
||||
impl Rem<T,T> for T {
|
||||
///
|
||||
/// Returns the integer remainder after division, satisfying:
|
||||
|
|
|
|||
|
|
@ -165,10 +165,14 @@ impl Mul<T,T> for T {
|
|||
#[inline(always)]
|
||||
fn mul(&self, other: &T) -> T { *self * *other }
|
||||
}
|
||||
|
||||
#[cfg(notest)]
|
||||
impl Quot<T,T> for T {
|
||||
#[inline(always)]
|
||||
fn quot(&self, other: &T) -> T { *self / *other }
|
||||
}
|
||||
|
||||
#[cfg(notest)]
|
||||
impl Rem<T,T> for T {
|
||||
#[inline(always)]
|
||||
fn rem(&self, other: &T) -> T { *self % *other }
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@
|
|||
|
||||
//! Runtime calls emitted by the compiler.
|
||||
|
||||
use uint;
|
||||
use cast::transmute;
|
||||
use libc::{c_char, c_uchar, c_void, size_t, uintptr_t, c_int, STDERR_FILENO};
|
||||
use managed::raw::BoxRepr;
|
||||
|
|
@ -22,10 +23,9 @@ use task::rt::rust_get_task;
|
|||
#[allow(non_camel_case_types)]
|
||||
pub type rust_task = c_void;
|
||||
|
||||
#[cfg(target_word_size = "32")]
|
||||
pub static FROZEN_BIT: uint = 0x80000000;
|
||||
#[cfg(target_word_size = "64")]
|
||||
pub static FROZEN_BIT: uint = 0x8000000000000000;
|
||||
pub static FROZEN_BIT: uint = 1 << (uint::bits - 1);
|
||||
pub static MUT_BIT: uint = 1 << (uint::bits - 2);
|
||||
static ALL_BITS: uint = FROZEN_BIT | MUT_BIT;
|
||||
|
||||
pub mod rustrt {
|
||||
use unstable::lang::rust_task;
|
||||
|
|
@ -196,21 +196,51 @@ 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
|
||||
}
|
||||
fn add_borrow_to_task_list(a: *mut BoxRepr, file: *c_char, line: size_t) {
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(stage0))]
|
||||
#[lang="borrow_as_imm"]
|
||||
#[inline(always)]
|
||||
pub unsafe fn borrow_as_imm(a: *u8, file: *c_char, line: size_t) -> uint {
|
||||
let a: *mut BoxRepr = transmute(a);
|
||||
|
||||
let ref_count = (*a).header.ref_count;
|
||||
if (ref_count & MUT_BIT) != 0 {
|
||||
fail_borrowed(a, file, line);
|
||||
} else {
|
||||
(*a).header.ref_count |= FROZEN_BIT;
|
||||
if ::rt::env::get().debug_borrows {
|
||||
add_borrow_to_list(a, file, line);
|
||||
}
|
||||
}
|
||||
ref_count
|
||||
}
|
||||
|
||||
#[cfg(not(stage0))]
|
||||
#[lang="borrow_as_mut"]
|
||||
#[inline(always)]
|
||||
pub unsafe fn borrow_as_mut(a: *u8, file: *c_char, line: size_t) -> uint {
|
||||
let a: *mut BoxRepr = transmute(a);
|
||||
|
||||
let ref_count = (*a).header.ref_count;
|
||||
if (ref_count & (MUT_BIT|FROZEN_BIT)) != 0 {
|
||||
fail_borrowed(a, file, line);
|
||||
} else {
|
||||
(*a).header.ref_count |= (MUT_BIT|FROZEN_BIT);
|
||||
if ::rt::env::get().debug_borrows {
|
||||
add_borrow_to_list(a, file, line);
|
||||
}
|
||||
}
|
||||
ref_count
|
||||
}
|
||||
|
||||
#[cfg(stage0)]
|
||||
#[lang="return_to_mut"]
|
||||
#[inline(always)]
|
||||
pub unsafe fn return_to_mut(a: *u8) {
|
||||
|
|
@ -222,6 +252,21 @@ pub unsafe fn return_to_mut(a: *u8) {
|
|||
}
|
||||
}
|
||||
|
||||
#[cfg(not(stage0))]
|
||||
#[lang="return_to_mut"]
|
||||
#[inline(always)]
|
||||
pub unsafe fn return_to_mut(a: *u8, old_ref_count: uint) {
|
||||
// Sometimes the box is null, if it is conditionally frozen.
|
||||
// See e.g. #4904.
|
||||
if !a.is_null() {
|
||||
let a: *mut BoxRepr = transmute(a);
|
||||
|
||||
let ref_count = (*a).header.ref_count & !ALL_BITS;
|
||||
let old_bits = old_ref_count & ALL_BITS;
|
||||
(*a).header.ref_count = ref_count | old_bits;
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(stage0)]
|
||||
#[lang="check_not_borrowed"]
|
||||
#[inline(always)]
|
||||
|
|
|
|||
|
|
@ -66,11 +66,12 @@ pub enum LangItem {
|
|||
MallocFnLangItem, // 28
|
||||
FreeFnLangItem, // 29
|
||||
BorrowAsImmFnLangItem, // 30
|
||||
ReturnToMutFnLangItem, // 31
|
||||
CheckNotBorrowedFnLangItem, // 32
|
||||
StrDupUniqFnLangItem, // 33
|
||||
BorrowAsMutFnLangItem, // 31
|
||||
ReturnToMutFnLangItem, // 32
|
||||
CheckNotBorrowedFnLangItem, // 33
|
||||
StrDupUniqFnLangItem, // 34
|
||||
|
||||
StartFnLangItem, // 34
|
||||
StartFnLangItem, // 35
|
||||
}
|
||||
|
||||
pub struct LanguageItems {
|
||||
|
|
@ -128,11 +129,12 @@ pub impl LanguageItems {
|
|||
28 => "malloc",
|
||||
29 => "free",
|
||||
30 => "borrow_as_imm",
|
||||
31 => "return_to_mut",
|
||||
32 => "check_not_borrowed",
|
||||
33 => "strdup_uniq",
|
||||
31 => "borrow_as_mut",
|
||||
32 => "return_to_mut",
|
||||
33 => "check_not_borrowed",
|
||||
34 => "strdup_uniq",
|
||||
|
||||
34 => "start",
|
||||
35 => "start",
|
||||
|
||||
_ => "???"
|
||||
}
|
||||
|
|
@ -237,6 +239,9 @@ pub impl LanguageItems {
|
|||
pub fn borrow_as_imm_fn(&const self) -> def_id {
|
||||
self.items[BorrowAsImmFnLangItem as uint].get()
|
||||
}
|
||||
pub fn borrow_as_mut_fn(&const self) -> def_id {
|
||||
self.items[BorrowAsMutFnLangItem as uint].get()
|
||||
}
|
||||
pub fn return_to_mut_fn(&const self) -> def_id {
|
||||
self.items[ReturnToMutFnLangItem as uint].get()
|
||||
}
|
||||
|
|
@ -292,6 +297,7 @@ fn LanguageItemCollector(crate: @crate,
|
|||
item_refs.insert(@~"malloc", MallocFnLangItem as uint);
|
||||
item_refs.insert(@~"free", FreeFnLangItem as uint);
|
||||
item_refs.insert(@~"borrow_as_imm", BorrowAsImmFnLangItem as uint);
|
||||
item_refs.insert(@~"borrow_as_mut", BorrowAsMutFnLangItem as uint);
|
||||
item_refs.insert(@~"return_to_mut", ReturnToMutFnLangItem as uint);
|
||||
item_refs.insert(@~"check_not_borrowed",
|
||||
CheckNotBorrowedFnLangItem as uint);
|
||||
|
|
|
|||
|
|
@ -991,63 +991,30 @@ pub fn get_landing_pad(bcx: block) -> BasicBlockRef {
|
|||
return pad_bcx.llbb;
|
||||
}
|
||||
|
||||
// Arranges for the value found in `*root_loc` to be dropped once the scope
|
||||
// associated with `scope_id` exits. This is used to keep boxes live when
|
||||
// there are extant region pointers pointing at the interior.
|
||||
//
|
||||
// Note that `root_loc` is not the value itself but rather a pointer to the
|
||||
// value. Generally it in alloca'd value. The reason for this is that the
|
||||
// value is initialized in an inner block but may be freed in some outer
|
||||
// block, so an SSA value that is valid in the inner block may not be valid in
|
||||
// the outer block. In fact, the inner block may not even execute. Rather
|
||||
// than generate the full SSA form, we just use an alloca'd value.
|
||||
pub fn add_root_cleanup(bcx: block,
|
||||
root_info: RootInfo,
|
||||
root_loc: ValueRef,
|
||||
ty: ty::t) {
|
||||
|
||||
debug!("add_root_cleanup(bcx=%s, \
|
||||
scope=%d, \
|
||||
freezes=%?, \
|
||||
root_loc=%s, \
|
||||
ty=%s)",
|
||||
bcx.to_str(),
|
||||
root_info.scope,
|
||||
root_info.freeze,
|
||||
val_str(bcx.ccx().tn, root_loc),
|
||||
ppaux::ty_to_str(bcx.ccx().tcx, ty));
|
||||
|
||||
let bcx_scope = find_bcx_for_scope(bcx, root_info.scope);
|
||||
if root_info.freeze.is_some() {
|
||||
add_clean_frozen_root(bcx_scope, root_loc, ty);
|
||||
} else {
|
||||
add_clean_temp_mem(bcx_scope, root_loc, ty);
|
||||
}
|
||||
|
||||
fn find_bcx_for_scope(bcx: block, scope_id: ast::node_id) -> block {
|
||||
let mut bcx_sid = bcx;
|
||||
loop {
|
||||
bcx_sid = match bcx_sid.node_info {
|
||||
Some(NodeInfo { id, _ }) if id == scope_id => {
|
||||
pub fn find_bcx_for_scope(bcx: block, scope_id: ast::node_id) -> block {
|
||||
let mut bcx_sid = bcx;
|
||||
loop {
|
||||
bcx_sid = match bcx_sid.node_info {
|
||||
Some(NodeInfo { id, _ }) if id == scope_id => {
|
||||
return bcx_sid
|
||||
}
|
||||
|
||||
// NOTE This is messier than it ought to be and not really right
|
||||
Some(NodeInfo { callee_id: Some(id), _ }) if id == scope_id => {
|
||||
return bcx_sid
|
||||
}
|
||||
|
||||
_ => {
|
||||
match bcx_sid.parent {
|
||||
None => bcx.tcx().sess.bug(
|
||||
fmt!("no enclosing scope with id %d", scope_id)),
|
||||
Some(bcx_par) => bcx_par
|
||||
// NOTE This is messier than it ought to be and not really right
|
||||
Some(NodeInfo { callee_id: Some(id), _ }) if id == scope_id => {
|
||||
return bcx_sid
|
||||
}
|
||||
|
||||
_ => {
|
||||
match bcx_sid.parent {
|
||||
None => bcx.tcx().sess.bug(
|
||||
fmt!("no enclosing scope with id %d", scope_id)),
|
||||
Some(bcx_par) => bcx_par
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
pub fn do_spill(bcx: block, v: ValueRef, t: ty::t) -> ValueRef {
|
||||
if ty::type_is_bot(t) {
|
||||
|
|
|
|||
|
|
@ -467,28 +467,40 @@ pub fn add_clean_temp_mem(bcx: block, val: ValueRef, t: ty::t) {
|
|||
scope_clean_changed(scope_info);
|
||||
}
|
||||
}
|
||||
pub fn add_clean_frozen_root(bcx: block, val: ValueRef, t: ty::t) {
|
||||
debug!("add_clean_frozen_root(%s, %s, %s)",
|
||||
bcx.to_str(), val_str(bcx.ccx().tn, val),
|
||||
t.repr(bcx.tcx()));
|
||||
let (root, rooted) = root_for_cleanup(bcx, val, t);
|
||||
let cleanup_type = cleanup_type(bcx.tcx(), t);
|
||||
pub fn add_clean_return_to_mut(bcx: block,
|
||||
frozen_val_ref: ValueRef,
|
||||
bits_val_ref: ValueRef) {
|
||||
//! When an `@mut` has been frozen, we have to
|
||||
//! call the lang-item `return_to_mut` when the
|
||||
//! freeze goes out of scope. We need to pass
|
||||
//! in both the value which was frozen (`frozen_val`) and
|
||||
//! the value (`bits_val_ref`) which was returned when the
|
||||
//! box was frozen initially. Here, both `frozen_val_ref` and
|
||||
//! `bits_val_ref` are in fact pointers to stack slots.
|
||||
|
||||
debug!("add_clean_return_to_mut(%s, %s, %s)",
|
||||
bcx.to_str(),
|
||||
val_str(bcx.ccx().tn, frozen_val_ref),
|
||||
val_str(bcx.ccx().tn, bits_val_ref));
|
||||
do in_scope_cx(bcx) |scope_info| {
|
||||
scope_info.cleanups.push(
|
||||
clean_temp(val, |bcx| {
|
||||
let bcx = callee::trans_lang_call(
|
||||
bcx,
|
||||
bcx.tcx().lang_items.return_to_mut_fn(),
|
||||
~[
|
||||
build::Load(bcx,
|
||||
build::PointerCast(bcx,
|
||||
root,
|
||||
T_ptr(T_ptr(T_i8()))))
|
||||
],
|
||||
expr::Ignore
|
||||
);
|
||||
glue::drop_ty_root(bcx, root, rooted, t)
|
||||
}, cleanup_type));
|
||||
clean_temp(
|
||||
frozen_val_ref,
|
||||
|bcx| {
|
||||
callee::trans_lang_call(
|
||||
bcx,
|
||||
bcx.tcx().lang_items.return_to_mut_fn(),
|
||||
~[
|
||||
build::Load(bcx,
|
||||
build::PointerCast(bcx,
|
||||
frozen_val_ref,
|
||||
T_ptr(T_ptr(T_i8())))),
|
||||
build::Load(bcx, bits_val_ref)
|
||||
],
|
||||
expr::Ignore
|
||||
)
|
||||
},
|
||||
normal_exit_only));
|
||||
scope_clean_changed(scope_info);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -87,7 +87,7 @@
|
|||
|
||||
use lib;
|
||||
use lib::llvm::ValueRef;
|
||||
use middle::borrowck::{RootInfo, root_map_key};
|
||||
use middle::borrowck::{RootInfo, root_map_key, DynaImm, DynaMut};
|
||||
use middle::trans::adt;
|
||||
use middle::trans::base::*;
|
||||
use middle::trans::build::*;
|
||||
|
|
@ -517,7 +517,7 @@ pub impl Datum {
|
|||
}
|
||||
}
|
||||
|
||||
fn root(&self, bcx: block, span: span, root_info: RootInfo) -> block {
|
||||
fn root(&self, mut bcx: block, span: span, root_info: RootInfo) -> block {
|
||||
/*!
|
||||
*
|
||||
* In some cases, borrowck will decide that an @T/@[]/@str
|
||||
|
|
@ -535,34 +535,53 @@ pub impl Datum {
|
|||
root_info.scope));
|
||||
}
|
||||
|
||||
// First, root the datum. Note that we must zero this value,
|
||||
// because sometimes we root on one path but not another.
|
||||
// See e.g. #4904.
|
||||
let scratch = scratch_datum(bcx, self.ty, true);
|
||||
self.copy_to_datum(bcx, INIT, scratch);
|
||||
add_root_cleanup(bcx, root_info, scratch.val, scratch.ty);
|
||||
let cleanup_bcx = find_bcx_for_scope(bcx, root_info.scope);
|
||||
add_clean_temp_mem(cleanup_bcx, scratch.val, scratch.ty);
|
||||
|
||||
// If we need to freeze the box, do that now.
|
||||
if root_info.freeze.is_some() {
|
||||
// NOTE distinguish the two kinds of freezing here
|
||||
// Now, consider also freezing it.
|
||||
match root_info.freeze {
|
||||
None => {}
|
||||
Some(freeze_kind) => {
|
||||
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()));
|
||||
|
||||
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()));
|
||||
// in this case, we don't have to zero, because
|
||||
// scratch.val will be NULL should the cleanup get
|
||||
// called without the freezing actually occurring, and
|
||||
// return_to_mut checks for this condition.
|
||||
let scratch_bits = scratch_datum(bcx, ty::mk_uint(), false);
|
||||
|
||||
callee::trans_lang_call(
|
||||
bcx,
|
||||
bcx.tcx().lang_items.borrow_as_imm_fn(),
|
||||
~[
|
||||
Load(bcx,
|
||||
PointerCast(bcx,
|
||||
scratch.val,
|
||||
T_ptr(T_ptr(T_i8())))),
|
||||
filename,
|
||||
line
|
||||
],
|
||||
expr::Ignore)
|
||||
} else {
|
||||
bcx
|
||||
let freeze_did = match freeze_kind {
|
||||
DynaImm => bcx.tcx().lang_items.borrow_as_imm_fn(),
|
||||
DynaMut => bcx.tcx().lang_items.borrow_as_mut_fn(),
|
||||
};
|
||||
|
||||
bcx = callee::trans_lang_call(
|
||||
bcx,
|
||||
freeze_did,
|
||||
~[
|
||||
Load(bcx,
|
||||
PointerCast(bcx,
|
||||
scratch.val,
|
||||
T_ptr(T_ptr(T_i8())))),
|
||||
filename,
|
||||
line
|
||||
],
|
||||
expr::SaveIn(scratch_bits.val));
|
||||
|
||||
add_clean_return_to_mut(
|
||||
cleanup_bcx, scratch.val, scratch_bits.val);
|
||||
}
|
||||
}
|
||||
|
||||
bcx
|
||||
}
|
||||
|
||||
fn perform_write_guard(&self, bcx: block, span: span) -> block {
|
||||
|
|
|
|||
|
|
@ -40,10 +40,11 @@ fn b() {
|
|||
|
||||
let q = &mut p;
|
||||
|
||||
p + 3; // ok for pure fns
|
||||
p + 3; //~ ERROR cannot borrow `p`
|
||||
p.times(3); //~ ERROR cannot borrow `p`
|
||||
|
||||
q.x += 1;
|
||||
*q + 3; // OK to use the new alias `q`
|
||||
q.x += 1; // and OK to mutate it
|
||||
}
|
||||
|
||||
fn c() {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue