]> git.lizzy.rs Git - rust.git/blob - src/librustc/middle/trans/write_guard.rs
b9a9a57d0461d576e8b31972ac23cf4c81839d31
[rust.git] / src / librustc / middle / trans / write_guard.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 //! 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`).
16
17
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;
30 use middle::ty;
31 use syntax::codemap::span;
32 use syntax::ast;
33
34 use middle::trans::type_::Type;
35
36 pub fn root_and_write_guard(datum: &Datum,
37                             mut bcx: block,
38                             span: span,
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);
43
44     // root the autoderef'd value, if necessary:
45     //
46     // (Note: root'd values are always boxes)
47     let ccx = bcx.ccx();
48     bcx = match ccx.maps.root_map.find(&key) {
49         None => bcx,
50         Some(&root_info) => root(datum, bcx, span, key, root_info)
51     };
52
53     // Perform the write guard, if necessary.
54     //
55     // (Note: write-guarded values are always boxes)
56     if ccx.maps.write_guard_map.contains(&key) {
57         perform_write_guard(datum, bcx, span)
58     } else {
59         bcx
60     }
61 }
62
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)",
70            root_key,
71            bcx.to_str(),
72            bcx.val_to_str(frozen_val_ref),
73            bcx.val_to_str(bits_val_ref));
74
75     let box_ptr = Load(bcx, PointerCast(bcx, frozen_val_ref, Type::i8p().ptr_to()));
76
77     let bits_val = Load(bcx, bits_val_ref);
78
79     if bcx.tcx().sess.debug_borrows() {
80         bcx = callee::trans_lang_call( bcx,
81             langcall(bcx, None, "unborrow", UnrecordBorrowFnLangItem),
82             [
83                 box_ptr,
84                 bits_val,
85                 filename_val,
86                 line_val
87             ],
88             Some(expr::Ignore)).bcx;
89     }
90
91     callee::trans_lang_call(
92         bcx,
93         langcall(bcx, None, "unborrow", ReturnToMutFnLangItem),
94         [
95             box_ptr,
96             bits_val,
97             filename_val,
98             line_val
99         ],
100         Some(expr::Ignore)
101     ).bcx
102 }
103
104 fn root(datum: &Datum,
105         mut bcx: block,
106         span: span,
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`.
113
114     debug!("write_guard::root(root_key=%?, root_info=%?, datum=%?)",
115            root_key, root_info, datum.to_str(bcx.ccx()));
116
117     if bcx.sess().trace() {
118         trans_trace(
119             bcx, None,
120             (fmt!("preserving until end of scope %d",
121                   root_info.scope)).to_managed());
122     }
123
124     // First, root the datum. Note that we must zero this value,
125     // because sometimes we root on one path but not another.
126     // See e.g. #4904.
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);
131
132     // Now, consider also freezing it.
133     match root_info.freeze {
134         None => {}
135         Some(freeze_kind) => {
136             let (filename, line) = filename_and_line_num_from_span(bcx, span);
137
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);
144
145             let freeze_item = match freeze_kind {
146                 DynaImm => BorrowAsImmFnLangItem,
147                 DynaMut => BorrowAsMutFnLangItem,
148             };
149
150             let box_ptr = Load(bcx, PointerCast(bcx, scratch.val, Type::i8p().ptr_to()));
151
152             let llresult = unpack_result!(bcx, callee::trans_lang_call(
153                 bcx,
154                 langcall(bcx, Some(span), "freeze", freeze_item),
155                 [
156                     box_ptr,
157                     filename,
158                     line
159                 ],
160                 Some(expr::SaveIn(scratch_bits.val))));
161
162             if bcx.tcx().sess.debug_borrows() {
163                 bcx = callee::trans_lang_call(
164                     bcx,
165                     langcall(bcx, Some(span), "freeze", RecordBorrowFnLangItem),
166                     [
167                         box_ptr,
168                         llresult,
169                         filename,
170                         line
171                     ],
172                     Some(expr::Ignore)).bcx;
173             }
174
175             add_clean_return_to_mut(
176                 cleanup_bcx, root_info.scope, root_key, scratch.val, scratch_bits.val,
177                 filename, line);
178         }
179     }
180
181     bcx
182 }
183
184 fn perform_write_guard(datum: &Datum,
185                        bcx: block,
186                        span: span) -> block {
187     debug!("perform_write_guard");
188
189     let llval = datum.to_value_llval(bcx);
190     let (filename, line) = filename_and_line_num_from_span(bcx, span);
191
192     callee::trans_lang_call(
193         bcx,
194         langcall(bcx, Some(span), "write guard", CheckNotBorrowedFnLangItem),
195         [PointerCast(bcx, llval, Type::i8p()), filename, line],
196         Some(expr::Ignore)).bcx
197 }