Skip to content

Commit 432460a

Browse files
committed
Synthesize calls to box_free language item
This gets rid of Drop(Free, _) MIR construct by synthesizing a call to language item which takes care of dropping instead.
1 parent 7b9d6d3 commit 432460a

File tree

20 files changed

+127
-69
lines changed

20 files changed

+127
-69
lines changed

src/doc/book/lang-items.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,11 +39,17 @@ unsafe fn allocate(size: usize, _align: usize) -> *mut u8 {
3939

4040
p
4141
}
42+
4243
#[lang = "exchange_free"]
4344
unsafe fn deallocate(ptr: *mut u8, _size: usize, _align: usize) {
4445
libc::free(ptr as *mut libc::c_void)
4546
}
4647

48+
#[lang = "box_free"]
49+
unsafe fn box_free<T>(ptr: *mut T) {
50+
deallocate(ptr as *mut u8, ::core::mem::size_of::<T>(), ::core::mem::align_of::<T>());
51+
}
52+
4753
#[start]
4854
fn main(argc: isize, argv: *const *const u8) -> isize {
4955
let x = box 1;

src/liballoc/heap.rs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@
1616
issue = "27700")]
1717

1818
use core::{isize, usize};
19+
#[cfg(not(test))]
20+
use core::intrinsics::{size_of, min_align_of};
1921

2022
#[allow(improper_ctypes)]
2123
extern "C" {
@@ -147,6 +149,17 @@ unsafe fn exchange_free(ptr: *mut u8, old_size: usize, align: usize) {
147149
deallocate(ptr, old_size, align);
148150
}
149151

152+
#[cfg(not(test))]
153+
#[lang = "box_free"]
154+
#[inline]
155+
unsafe fn box_free<T>(ptr: *mut T) {
156+
let size = size_of::<T>();
157+
// We do not allocate for Box<T> when T is ZST, so deallocation is also not necessary.
158+
if size != 0 {
159+
deallocate(ptr as *mut u8, size, min_align_of::<T>());
160+
}
161+
}
162+
150163
#[cfg(test)]
151164
mod tests {
152165
extern crate test;

src/librustc/middle/dead.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -435,7 +435,7 @@ impl<'a, 'tcx> DeadVisitor<'a, 'tcx> {
435435
let is_named = node.name().is_some();
436436
let field_type = self.tcx.node_id_to_type(node.id);
437437
let is_marker_field = match field_type.ty_to_def_id() {
438-
Some(def_id) => self.tcx.lang_items.items().any(|(_, item)| *item == Some(def_id)),
438+
Some(def_id) => self.tcx.lang_items.items().iter().any(|item| *item == Some(def_id)),
439439
_ => false
440440
};
441441
is_named

src/librustc/middle/lang_items.rs

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -36,9 +36,6 @@ use syntax::parse::token::InternedString;
3636
use rustc_front::intravisit::Visitor;
3737
use rustc_front::hir;
3838

39-
use std::iter::Enumerate;
40-
use std::slice;
41-
4239
// The actual lang items defined come at the end of this file in one handy table.
4340
// So you probably just want to nip down to the end.
4441
macro_rules! lets_do_this {
@@ -69,8 +66,8 @@ impl LanguageItems {
6966
}
7067
}
7168

72-
pub fn items<'a>(&'a self) -> Enumerate<slice::Iter<'a, Option<DefId>>> {
73-
self.items.iter().enumerate()
69+
pub fn items(&self) -> &[Option<DefId>] {
70+
&*self.items
7471
}
7572

7673
pub fn item_name(index: usize) -> &'static str {
@@ -334,6 +331,7 @@ lets_do_this! {
334331

335332
ExchangeMallocFnLangItem, "exchange_malloc", exchange_malloc_fn;
336333
ExchangeFreeFnLangItem, "exchange_free", exchange_free_fn;
334+
BoxFreeFnLangItem, "box_free", box_free_fn;
337335
StrDupUniqFnLangItem, "strdup_uniq", strdup_uniq_fn;
338336

339337
StartFnLangItem, "start", start_fn;

src/librustc/middle/reachable.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -362,7 +362,7 @@ pub fn find_reachable(tcx: &ty::ctxt,
362362
for (id, _) in &access_levels.map {
363363
reachable_context.worklist.push(*id);
364364
}
365-
for (_, item) in tcx.lang_items.items() {
365+
for item in tcx.lang_items.items().iter() {
366366
if let Some(did) = *item {
367367
if let Some(node_id) = tcx.map.as_local_node_id(did) {
368368
reachable_context.worklist.push(node_id);

src/librustc/mir/repr.rs

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -490,23 +490,15 @@ pub struct Statement<'tcx> {
490490
#[derive(Clone, Debug, RustcEncodable, RustcDecodable)]
491491
pub enum StatementKind<'tcx> {
492492
Assign(Lvalue<'tcx>, Rvalue<'tcx>),
493-
Drop(DropKind, Lvalue<'tcx>),
494-
}
495-
496-
#[derive(Copy, Clone, Debug, PartialEq, Eq, RustcEncodable, RustcDecodable)]
497-
pub enum DropKind {
498-
/// free a partially constructed box, should go away eventually
499-
Free,
500-
Deep
493+
Drop(Lvalue<'tcx>),
501494
}
502495

503496
impl<'tcx> Debug for Statement<'tcx> {
504497
fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
505498
use self::StatementKind::*;
506499
match self.kind {
507500
Assign(ref lv, ref rv) => write!(fmt, "{:?} = {:?}", lv, rv),
508-
Drop(DropKind::Free, ref lv) => write!(fmt, "free {:?}", lv),
509-
Drop(DropKind::Deep, ref lv) => write!(fmt, "drop {:?}", lv),
501+
Drop(ref lv) => write!(fmt, "drop {:?}", lv),
510502
}
511503
}
512504
}

src/librustc/mir/visit.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,7 @@ macro_rules! make_mir_visitor {
124124
ref $($mutability)* rvalue) => {
125125
self.visit_assign(block, lvalue, rvalue);
126126
}
127-
StatementKind::Drop(_, ref $($mutability)* lvalue) => {
127+
StatementKind::Drop(ref $($mutability)* lvalue) => {
128128
self.visit_lvalue(lvalue, LvalueContext::Drop);
129129
}
130130
}

src/librustc_metadata/encoder.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1649,7 +1649,7 @@ fn encode_crate_deps(rbml_w: &mut Encoder, cstore: &cstore::CStore) {
16491649
fn encode_lang_items(ecx: &EncodeContext, rbml_w: &mut Encoder) {
16501650
rbml_w.start_tag(tag_lang_items);
16511651

1652-
for (i, &opt_def_id) in ecx.tcx.lang_items.items() {
1652+
for (i, &opt_def_id) in ecx.tcx.lang_items.items().iter().enumerate() {
16531653
if let Some(def_id) = opt_def_id {
16541654
if def_id.is_local() {
16551655
rbml_w.start_tag(tag_lang_items_item);

src/librustc_mir/build/cfg.rs

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,16 +32,21 @@ impl<'tcx> CFG<'tcx> {
3232
BasicBlock::new(node_index)
3333
}
3434

35+
pub fn start_new_cleanup_block(&mut self) -> BasicBlock {
36+
let bb = self.start_new_block();
37+
self.block_data_mut(bb).is_cleanup = true;
38+
bb
39+
}
40+
3541
pub fn push(&mut self, block: BasicBlock, statement: Statement<'tcx>) {
3642
debug!("push({:?}, {:?})", block, statement);
3743
self.block_data_mut(block).statements.push(statement);
3844
}
3945

40-
pub fn push_drop(&mut self, block: BasicBlock, span: Span,
41-
kind: DropKind, lvalue: &Lvalue<'tcx>) {
46+
pub fn push_drop(&mut self, block: BasicBlock, span: Span, lvalue: &Lvalue<'tcx>) {
4247
self.push(block, Statement {
4348
span: span,
44-
kind: StatementKind::Drop(kind, lvalue.clone())
49+
kind: StatementKind::Drop(lvalue.clone())
4550
});
4651
}
4752

src/librustc_mir/build/expr/as_rvalue.rs

Lines changed: 9 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -59,25 +59,18 @@ impl<'a,'tcx> Builder<'a,'tcx> {
5959
let arg = unpack!(block = this.as_operand(block, arg));
6060
block.and(Rvalue::UnaryOp(op, arg))
6161
}
62-
ExprKind::Box { value } => {
62+
ExprKind::Box { value, value_extents } => {
6363
let value = this.hir.mirror(value);
6464
let result = this.temp(expr.ty);
65-
6665
// to start, malloc some memory of suitable type (thus far, uninitialized):
67-
let rvalue = Rvalue::Box(value.ty);
68-
this.cfg.push_assign(block, expr_span, &result, rvalue);
69-
70-
// schedule a shallow free of that memory, lest we unwind:
71-
let extent = this.extent_of_innermost_scope();
72-
this.schedule_drop(expr_span, extent, DropKind::Free, &result, value.ty);
73-
74-
// initialize the box contents:
75-
let contents = result.clone().deref();
76-
unpack!(block = this.into(&contents, block, value));
77-
78-
// now that the result is fully initialized, cancel the drop
79-
// by "using" the result (which is linear):
80-
block.and(Rvalue::Use(Operand::Consume(result)))
66+
this.cfg.push_assign(block, expr_span, &result, Rvalue::Box(value.ty));
67+
this.in_scope(value_extents, block, |this| {
68+
// schedule a shallow free of that memory, lest we unwind:
69+
this.schedule_box_free(expr_span, value_extents, &result, value.ty);
70+
// initialize the box contents:
71+
unpack!(block = this.into(&result.clone().deref(), block, value));
72+
block.and(Rvalue::Use(Operand::Consume(result)))
73+
})
8174
}
8275
ExprKind::Cast { source } => {
8376
let source = unpack!(block = this.as_operand(block, source));

0 commit comments

Comments
 (0)