Skip to content

Commit e1f3c67

Browse files
committed
translate closure shims using MIR
1 parent a5e3c3d commit e1f3c67

File tree

8 files changed

+183
-321
lines changed

8 files changed

+183
-321
lines changed

src/librustc/ty/instance.rs

Lines changed: 5 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -34,10 +34,7 @@ pub enum InstanceDef<'tcx> {
3434
// <Trait as Trait>::fn
3535
Virtual(DefId, usize),
3636
// <[mut closure] as FnOnce>::call_once
37-
ClosureOnceShim {
38-
call_once: DefId,
39-
closure_did: DefId
40-
},
37+
ClosureOnceShim { call_once: DefId },
4138
}
4239

4340
impl<'tcx> InstanceDef<'tcx> {
@@ -48,9 +45,8 @@ impl<'tcx> InstanceDef<'tcx> {
4845
InstanceDef::FnPtrShim(def_id, _) |
4946
InstanceDef::Virtual(def_id, _) |
5047
InstanceDef::Intrinsic(def_id, ) |
51-
InstanceDef::ClosureOnceShim {
52-
call_once: def_id, closure_did: _
53-
} => def_id
48+
InstanceDef::ClosureOnceShim { call_once: def_id }
49+
=> def_id
5450
}
5551
}
5652

@@ -98,10 +94,8 @@ impl<'tcx> fmt::Display for Instance<'tcx> {
9894
InstanceDef::FnPtrShim(_, ty) => {
9995
write!(f, " - shim({:?})", ty)
10096
}
101-
InstanceDef::ClosureOnceShim {
102-
call_once: _, closure_did
103-
} => {
104-
write!(f, " - shim({:?})", closure_did)
97+
InstanceDef::ClosureOnceShim { .. } => {
98+
write!(f, " - shim")
10599
}
106100
}
107101
}

src/librustc_mir/shim.rs

Lines changed: 94 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,25 @@ fn make_shim<'a, 'tcx>(tcx: ty::TyCtxt<'a, 'tcx, 'tcx>,
8383
None
8484
)
8585
}
86-
_ => bug!("unknown shim kind")
86+
ty::InstanceDef::ClosureOnceShim { call_once } => {
87+
let fn_mut = tcx.lang_items.fn_mut_trait().unwrap();
88+
let call_mut = tcx.global_tcx()
89+
.associated_items(fn_mut)
90+
.find(|it| it.kind == ty::AssociatedKind::Method)
91+
.unwrap().def_id;
92+
93+
build_call_shim(
94+
tcx,
95+
&param_env,
96+
call_once,
97+
Adjustment::RefMut,
98+
CallKind::Direct(call_mut),
99+
None
100+
)
101+
}
102+
ty::InstanceDef::Intrinsic(_) => {
103+
bug!("creating shims from intrinsics ({:?}) is unsupported", instance)
104+
}
87105
};
88106
debug!("make_shim({:?}) = {:?}", instance, result);
89107

@@ -97,6 +115,7 @@ fn make_shim<'a, 'tcx>(tcx: ty::TyCtxt<'a, 'tcx, 'tcx>,
97115
enum Adjustment {
98116
Identity,
99117
Deref,
118+
RefMut,
100119
}
101120

102121
#[derive(Copy, Clone, Debug, PartialEq)]
@@ -143,18 +162,37 @@ fn build_call_shim<'a, 'tcx>(tcx: ty::TyCtxt<'a, 'tcx, 'tcx>,
143162

144163
debug!("build_call_shim: sig={:?}", sig);
145164

146-
let local_decls = local_decls_for_sig(&sig);
165+
let mut local_decls = local_decls_for_sig(&sig);
147166
let source_info = SourceInfo { span, scope: ARGUMENT_VISIBILITY_SCOPE };
148167

149-
let rcvr_l = Lvalue::Local(Local::new(1+0));
150-
151-
let return_block_id = BasicBlock::new(1);
168+
let rcvr_arg = Local::new(1+0);
169+
let rcvr_l = Lvalue::Local(rcvr_arg);
170+
let mut statements = vec![];
152171

153172
let rcvr = match rcvr_adjustment {
154173
Adjustment::Identity => Operand::Consume(rcvr_l),
155174
Adjustment::Deref => Operand::Consume(Lvalue::Projection(
156175
box Projection { base: rcvr_l, elem: ProjectionElem::Deref }
157-
))
176+
)),
177+
Adjustment::RefMut => {
178+
// let rcvr = &mut rcvr;
179+
let re_erased = tcx.mk_region(ty::ReErased);
180+
let ref_rcvr = local_decls.push(temp_decl(
181+
Mutability::Not,
182+
tcx.mk_ref(re_erased, ty::TypeAndMut {
183+
ty: sig.inputs()[0],
184+
mutbl: hir::Mutability::MutMutable
185+
})
186+
));
187+
statements.push(Statement {
188+
source_info: source_info,
189+
kind: StatementKind::Assign(
190+
Lvalue::Local(ref_rcvr),
191+
Rvalue::Ref(re_erased, BorrowKind::Mut, rcvr_l)
192+
)
193+
});
194+
Operand::Consume(Lvalue::Local(ref_rcvr))
195+
}
158196
};
159197

160198
let (callee, mut args) = match call_kind {
@@ -184,28 +222,57 @@ fn build_call_shim<'a, 'tcx>(tcx: ty::TyCtxt<'a, 'tcx, 'tcx>,
184222
}
185223

186224
let mut blocks = IndexVec::new();
187-
blocks.push(BasicBlockData {
188-
statements: vec![],
189-
terminator: Some(Terminator {
190-
source_info: source_info,
191-
kind: TerminatorKind::Call {
192-
func: callee,
193-
args: args,
194-
destination: Some((Lvalue::Local(RETURN_POINTER),
195-
return_block_id)),
196-
cleanup: None
225+
let block = |blocks: &mut IndexVec<_, _>, statements, kind, is_cleanup| {
226+
blocks.push(BasicBlockData {
227+
statements,
228+
terminator: Some(Terminator { source_info, kind }),
229+
is_cleanup
230+
})
231+
};
232+
233+
let have_unwind = match (rcvr_adjustment, tcx.sess.no_landing_pads()) {
234+
(Adjustment::RefMut, false) => true,
235+
_ => false
236+
};
237+
238+
// BB #0
239+
block(&mut blocks, statements, TerminatorKind::Call {
240+
func: callee,
241+
args: args,
242+
destination: Some((Lvalue::Local(RETURN_POINTER),
243+
BasicBlock::new(1))),
244+
cleanup: if have_unwind {
245+
Some(BasicBlock::new(3))
246+
} else {
247+
None
248+
}
249+
}, false);
250+
251+
if let Adjustment::RefMut = rcvr_adjustment {
252+
// BB #1 - drop for Self
253+
block(&mut blocks, vec![], TerminatorKind::Drop {
254+
location: Lvalue::Local(rcvr_arg),
255+
target: BasicBlock::new(2),
256+
unwind: if have_unwind {
257+
Some(BasicBlock::new(4))
258+
} else {
259+
None
197260
}
198-
}),
199-
is_cleanup: false
200-
});
201-
blocks.push(BasicBlockData {
202-
statements: vec![],
203-
terminator: Some(Terminator {
204-
source_info: source_info,
205-
kind: TerminatorKind::Return
206-
}),
207-
is_cleanup: false
208-
});
261+
}, false);
262+
}
263+
// BB #1/#2 - return
264+
block(&mut blocks, vec![], TerminatorKind::Return, false);
265+
if have_unwind {
266+
// BB #3 - drop if closure panics
267+
block(&mut blocks, vec![], TerminatorKind::Drop {
268+
location: Lvalue::Local(rcvr_arg),
269+
target: BasicBlock::new(4),
270+
unwind: None
271+
}, true);
272+
273+
// BB #4 - resume
274+
block(&mut blocks, vec![], TerminatorKind::Resume, true);
275+
}
209276

210277
let mut mir = Mir::new(
211278
blocks,

src/librustc_trans/callee.rs

Lines changed: 7 additions & 166 deletions
Original file line numberDiff line numberDiff line change
@@ -14,154 +14,29 @@
1414
//! and methods are represented as just a fn ptr and not a full
1515
//! closure.
1616
17-
use llvm::{self, ValueRef, get_params};
17+
use llvm::{self, ValueRef};
1818
use rustc::hir::def_id::DefId;
19-
use rustc::ty::subst::{Substs, Subst};
20-
use abi::{Abi, FnType};
19+
use rustc::ty::subst::Substs;
2120
use attributes;
22-
use builder::Builder;
2321
use common::{self, CrateContext};
24-
use cleanup::CleanupScope;
25-
use mir::lvalue::LvalueRef;
2622
use monomorphize;
2723
use consts;
2824
use declare;
29-
use value::Value;
3025
use monomorphize::Instance;
31-
use back::symbol_names::symbol_name;
3226
use trans_item::TransItem;
3327
use type_of;
34-
use rustc::ty::{self, TypeFoldable};
35-
use std::iter;
36-
37-
use mir::lvalue::Alignment;
38-
39-
fn trans_fn_once_adapter_shim<'a, 'tcx>(
40-
ccx: &'a CrateContext<'a, 'tcx>,
41-
def_id: DefId,
42-
substs: ty::ClosureSubsts<'tcx>,
43-
method_instance: Instance<'tcx>,
44-
llreffn: ValueRef)
45-
-> ValueRef
46-
{
47-
if let Some(&llfn) = ccx.instances().borrow().get(&method_instance) {
48-
return llfn;
49-
}
50-
51-
debug!("trans_fn_once_adapter_shim(def_id={:?}, substs={:?}, llreffn={:?})",
52-
def_id, substs, Value(llreffn));
53-
54-
let tcx = ccx.tcx();
55-
56-
// Find a version of the closure type. Substitute static for the
57-
// region since it doesn't really matter.
58-
let closure_ty = tcx.mk_closure_from_closure_substs(def_id, substs);
59-
let ref_closure_ty = tcx.mk_imm_ref(tcx.mk_region(ty::ReErased), closure_ty);
60-
61-
// Make a version with the type of by-ref closure.
62-
let sig = tcx.closure_type(def_id).subst(tcx, substs.substs);
63-
let sig = tcx.erase_late_bound_regions_and_normalize(&sig);
64-
assert_eq!(sig.abi, Abi::RustCall);
65-
let llref_fn_sig = tcx.mk_fn_sig(
66-
iter::once(ref_closure_ty).chain(sig.inputs().iter().cloned()),
67-
sig.output(),
68-
sig.variadic,
69-
sig.unsafety,
70-
Abi::RustCall
71-
);
72-
let llref_fn_ty = tcx.mk_fn_ptr(ty::Binder(llref_fn_sig));
73-
debug!("trans_fn_once_adapter_shim: llref_fn_ty={:?}",
74-
llref_fn_ty);
75-
76-
77-
// Make a version of the closure type with the same arguments, but
78-
// with argument #0 being by value.
79-
let sig = tcx.mk_fn_sig(
80-
iter::once(closure_ty).chain(sig.inputs().iter().cloned()),
81-
sig.output(),
82-
sig.variadic,
83-
sig.unsafety,
84-
Abi::RustCall
85-
);
86-
87-
let fn_ty = FnType::new(ccx, sig, &[]);
88-
let llonce_fn_ty = tcx.mk_fn_ptr(ty::Binder(sig));
89-
90-
// Create the by-value helper.
91-
let function_name = symbol_name(method_instance, ccx.shared());
92-
let lloncefn = declare::define_internal_fn(ccx, &function_name, llonce_fn_ty);
93-
attributes::set_frame_pointer_elimination(ccx, lloncefn);
94-
95-
let orig_fn_ty = fn_ty;
96-
let mut bcx = Builder::new_block(ccx, lloncefn, "entry-block");
97-
98-
// the first argument (`self`) will be the (by value) closure env.
99-
100-
let mut llargs = get_params(lloncefn);
101-
let fn_ty = FnType::new(ccx, llref_fn_sig, &[]);
102-
let self_idx = fn_ty.ret.is_indirect() as usize;
103-
let env_arg = &orig_fn_ty.args[0];
104-
let env = if env_arg.is_indirect() {
105-
LvalueRef::new_sized_ty(llargs[self_idx], closure_ty, Alignment::AbiAligned)
106-
} else {
107-
let scratch = LvalueRef::alloca(&bcx, closure_ty, "self");
108-
let mut llarg_idx = self_idx;
109-
env_arg.store_fn_arg(&bcx, &mut llarg_idx, scratch.llval);
110-
scratch
111-
};
112-
113-
debug!("trans_fn_once_adapter_shim: env={:?}", env);
114-
// Adjust llargs such that llargs[self_idx..] has the call arguments.
115-
// For zero-sized closures that means sneaking in a new argument.
116-
if env_arg.is_ignore() {
117-
llargs.insert(self_idx, env.llval);
118-
} else {
119-
llargs[self_idx] = env.llval;
120-
}
121-
122-
// Call the by-ref closure body with `self` in a cleanup scope,
123-
// to drop `self` when the body returns, or in case it unwinds.
124-
let self_scope = CleanupScope::schedule_drop_mem(&bcx, env);
125-
126-
let llret;
127-
if let Some(landing_pad) = self_scope.landing_pad {
128-
let normal_bcx = bcx.build_sibling_block("normal-return");
129-
llret = bcx.invoke(llreffn, &llargs[..], normal_bcx.llbb(), landing_pad, None);
130-
bcx = normal_bcx;
131-
} else {
132-
llret = bcx.call(llreffn, &llargs[..], None);
133-
}
134-
fn_ty.apply_attrs_callsite(llret);
135-
136-
if sig.output().is_never() {
137-
bcx.unreachable();
138-
} else {
139-
self_scope.trans(&bcx);
140-
141-
if fn_ty.ret.is_indirect() || fn_ty.ret.is_ignore() {
142-
bcx.ret_void();
143-
} else {
144-
bcx.ret(llret);
145-
}
146-
}
147-
148-
ccx.instances().borrow_mut().insert(method_instance, lloncefn);
149-
150-
lloncefn
151-
}
152-
28+
use rustc::ty::TypeFoldable;
15329

15430
/// Translates a reference to a fn/method item, monomorphizing and
15531
/// inlining as it goes.
15632
///
15733
/// # Parameters
15834
///
15935
/// - `ccx`: the crate context
160-
/// - `def_id`: def id of the fn or method item being referenced
161-
/// - `substs`: values for each of the fn/method's parameters
162-
fn do_get_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
163-
instance: Instance<'tcx>)
164-
-> ValueRef
36+
/// - `instance`: the instance to be instantiated
37+
pub fn get_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
38+
instance: Instance<'tcx>)
39+
-> ValueRef
16540
{
16641
let tcx = ccx.tcx();
16742

@@ -248,40 +123,6 @@ fn do_get_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
248123
llfn
249124
}
250125

251-
pub fn get_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
252-
instance: Instance<'tcx>)
253-
-> ValueRef
254-
{
255-
match instance.def {
256-
ty::InstanceDef::Intrinsic(_) => {
257-
bug!("intrinsic {} getting reified", instance)
258-
}
259-
ty::InstanceDef::ClosureOnceShim { .. } => {
260-
let closure_ty = instance.substs.type_at(0);
261-
let (closure_def_id, closure_substs) = match closure_ty.sty {
262-
ty::TyClosure(def_id, substs) => (def_id, substs),
263-
_ => bug!("bad closure instance {:?}", instance)
264-
};
265-
266-
trans_fn_once_adapter_shim(
267-
ccx,
268-
closure_def_id,
269-
closure_substs,
270-
instance,
271-
do_get_fn(
272-
ccx,
273-
Instance::new(closure_def_id, closure_substs.substs)
274-
)
275-
)
276-
}
277-
ty::InstanceDef::FnPtrShim(..) |
278-
ty::InstanceDef::Item(..) |
279-
ty::InstanceDef::Virtual(..) => {
280-
do_get_fn(ccx, instance)
281-
}
282-
}
283-
}
284-
285126
pub fn resolve_and_get_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
286127
def_id: DefId,
287128
substs: &'tcx Substs<'tcx>)

0 commit comments

Comments
 (0)