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.
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.
11 //! Logic relating to rooting and write guards for managed values
12 //! (`@` and `@mut`). This code is primarily for use by datum;
13 //! it exists in its own module both to keep datum.rs bite-sized
14 //! and for each in debugging (e.g., so you can use
15 //! `RUST_LOG=rustc::middle::trans::write_guard`).
18 use lib::llvm::ValueRef;
19 use middle::borrowck::{RootInfo, root_map_key, DynaImm, DynaMut};
20 use middle::lang_items::CheckNotBorrowedFnLangItem;
21 use middle::lang_items::{BorrowAsImmFnLangItem, BorrowAsMutFnLangItem};
22 use middle::lang_items::{RecordBorrowFnLangItem, UnrecordBorrowFnLangItem};
23 use middle::lang_items::ReturnToMutFnLangItem;
24 use middle::trans::base::*;
25 use middle::trans::build::*;
26 use middle::trans::callee;
27 use middle::trans::common::*;
28 use middle::trans::datum::*;
29 use middle::trans::expr;
31 use syntax::codemap::span;
34 use middle::trans::type_::Type;
36 pub fn root_and_write_guard(datum: &Datum,
39 expr_id: ast::node_id,
40 derefs: uint) -> block {
41 let key = root_map_key { id: expr_id, derefs: derefs };
42 debug!("write_guard::root_and_write_guard(key=%?)", key);
44 // root the autoderef'd value, if necessary:
46 // (Note: root'd values are always boxes)
48 bcx = match ccx.maps.root_map.find(&key) {
50 Some(&root_info) => root(datum, bcx, span, key, root_info)
53 // Perform the write guard, if necessary.
55 // (Note: write-guarded values are always boxes)
56 if ccx.maps.write_guard_map.contains(&key) {
57 perform_write_guard(datum, bcx, span)
63 pub fn return_to_mut(mut bcx: block,
64 root_key: root_map_key,
65 frozen_val_ref: ValueRef,
66 bits_val_ref: ValueRef,
67 filename_val: ValueRef,
68 line_val: ValueRef) -> block {
69 debug!("write_guard::return_to_mut(root_key=%?, %s, %s, %s)",
72 bcx.val_to_str(frozen_val_ref),
73 bcx.val_to_str(bits_val_ref));
75 let box_ptr = Load(bcx, PointerCast(bcx, frozen_val_ref, Type::i8p().ptr_to()));
77 let bits_val = Load(bcx, bits_val_ref);
79 if bcx.tcx().sess.debug_borrows() {
80 bcx = callee::trans_lang_call( bcx,
81 langcall(bcx, None, "unborrow", UnrecordBorrowFnLangItem),
88 Some(expr::Ignore)).bcx;
91 callee::trans_lang_call(
93 langcall(bcx, None, "unborrow", ReturnToMutFnLangItem),
104 fn root(datum: &Datum,
107 root_key: root_map_key,
108 root_info: RootInfo) -> block {
109 //! In some cases, borrowck will decide that an @T/@[]/@str
110 //! value must be rooted for the program to be safe. In that
111 //! case, we will call this function, which will stash a copy
112 //! away until we exit the scope `scope_id`.
114 debug!("write_guard::root(root_key=%?, root_info=%?, datum=%?)",
115 root_key, root_info, datum.to_str(bcx.ccx()));
117 if bcx.sess().trace() {
120 (fmt!("preserving until end of scope %d",
121 root_info.scope)).to_managed());
124 // First, root the datum. Note that we must zero this value,
125 // because sometimes we root on one path but not another.
127 let scratch = scratch_datum(bcx, datum.ty, "__write_guard", true);
128 datum.copy_to_datum(bcx, INIT, scratch);
129 let cleanup_bcx = find_bcx_for_scope(bcx, root_info.scope);
130 add_clean_temp_mem_in_scope(cleanup_bcx, root_info.scope, scratch.val, scratch.ty);
132 // Now, consider also freezing it.
133 match root_info.freeze {
135 Some(freeze_kind) => {
136 let (filename, line) = filename_and_line_num_from_span(bcx, span);
138 // in this case, we don't have to zero, because
139 // scratch.val will be NULL should the cleanup get
140 // called without the freezing actually occurring, and
141 // return_to_mut checks for this condition.
142 let scratch_bits = scratch_datum(bcx, ty::mk_uint(),
143 "__write_guard_bits", false);
145 let freeze_item = match freeze_kind {
146 DynaImm => BorrowAsImmFnLangItem,
147 DynaMut => BorrowAsMutFnLangItem,
150 let box_ptr = Load(bcx, PointerCast(bcx, scratch.val, Type::i8p().ptr_to()));
152 let llresult = unpack_result!(bcx, callee::trans_lang_call(
154 langcall(bcx, Some(span), "freeze", freeze_item),
160 Some(expr::SaveIn(scratch_bits.val))));
162 if bcx.tcx().sess.debug_borrows() {
163 bcx = callee::trans_lang_call(
165 langcall(bcx, Some(span), "freeze", RecordBorrowFnLangItem),
172 Some(expr::Ignore)).bcx;
175 add_clean_return_to_mut(
176 cleanup_bcx, root_info.scope, root_key, scratch.val, scratch_bits.val,
184 fn perform_write_guard(datum: &Datum,
186 span: span) -> block {
187 debug!("perform_write_guard");
189 let llval = datum.to_value_llval(bcx);
190 let (filename, line) = filename_and_line_num_from_span(bcx, span);
192 callee::trans_lang_call(
194 langcall(bcx, Some(span), "write guard", CheckNotBorrowedFnLangItem),
195 [PointerCast(bcx, llval, Type::i8p()), filename, line],
196 Some(expr::Ignore)).bcx