提交 65a4266f 编写于 作者: A Ariel Ben-Yehuda

refactor away callee::Callee and translate virtual calls through a MIR shim

These changes are in the same commit to avoid needing to adapt
meth::trans_object_shim to the new scheme.

One codegen-units test is broken because we instantiate the shims even
when they are not needed. This will be fixed in the next PR.
上级 aac5ba5d
......@@ -23,6 +23,7 @@
#![feature(associated_consts)]
#![feature(box_patterns)]
#![feature(box_syntax)]
#![cfg_attr(stage0, feature(field_init_shorthand))]
#![feature(i128_type)]
#![feature(rustc_diagnostic_macros)]
#![feature(rustc_private)]
......
......@@ -252,12 +252,9 @@ fn closure_self_ty<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
-> Ty<'tcx> {
let closure_ty = tcx.body_tables(body_id).node_id_to_type(closure_expr_id);
// We're just hard-coding the idea that the signature will be
// &self or &mut self and hence will have a bound region with
// number 0, hokey.
let region = ty::Region::ReFree(ty::FreeRegion {
scope: tcx.region_maps.item_extent(body_id.node_id),
bound_region: ty::BoundRegion::BrAnon(0),
bound_region: ty::BoundRegion::BrEnv,
});
let region = tcx.mk_region(region);
......
......@@ -9,17 +9,19 @@
// except according to those terms.
use rustc::hir;
use rustc::hir::def_id::DefId;
use rustc::infer;
use rustc::middle::region::ROOT_CODE_EXTENT;
use rustc::mir::*;
use rustc::mir::transform::MirSource;
use rustc::ty::{self, Ty};
use rustc::ty::subst::Subst;
use rustc::ty::maps::Providers;
use rustc_data_structures::indexed_vec::{IndexVec, Idx};
use syntax::abi::Abi;
use syntax::ast;
use syntax::codemap::DUMMY_SP;
use syntax_pos::Span;
use std::cell::RefCell;
......@@ -35,11 +37,51 @@ fn make_shim<'a, 'tcx>(tcx: ty::TyCtxt<'a, 'tcx, 'tcx>,
-> &'tcx RefCell<Mir<'tcx>>
{
debug!("make_shim({:?})", instance);
let did = instance.def_id();
let span = tcx.def_span(did);
let param_env =
tcx.construct_parameter_environment(span, did, ROOT_CODE_EXTENT);
let result = match instance {
ty::InstanceDef::Item(..) =>
bug!("item {:?} passed to make_shim", instance),
ty::InstanceDef::FnPtrShim(_, ty) => {
build_fn_ptr_shim(tcx, ty, instance.def_ty(tcx))
ty::InstanceDef::FnPtrShim(def_id, ty) => {
let trait_ = tcx.trait_of_item(def_id).unwrap();
let adjustment = match tcx.lang_items.fn_trait_kind(trait_) {
Some(ty::ClosureKind::FnOnce) => Adjustment::Identity,
Some(ty::ClosureKind::FnMut) |
Some(ty::ClosureKind::Fn) => Adjustment::Deref,
None => bug!("fn pointer {:?} is not an fn", ty)
};
// HACK: we need the "real" argument types for the MIR,
// but because our substs are (Self, Args), where Args
// is a tuple, we must include the *concrete* argument
// types in the MIR. They will be substituted again with
// the param-substs, but because they are concrete, this
// will not do any harm.
let sig = tcx.erase_late_bound_regions(&ty.fn_sig());
let arg_tys = sig.inputs();
build_call_shim(
tcx,
&param_env,
def_id,
adjustment,
CallKind::Indirect,
Some(arg_tys)
)
}
ty::InstanceDef::Virtual(def_id, _) => {
// We are translating a call back to our def-id, which
// trans::mir knows to turn to an actual virtual call.
build_call_shim(
tcx,
&param_env,
def_id,
Adjustment::Identity,
CallKind::Direct(def_id),
None
)
}
_ => bug!("unknown shim kind")
};
......@@ -51,124 +93,135 @@ fn make_shim<'a, 'tcx>(tcx: ty::TyCtxt<'a, 'tcx, 'tcx>,
result
}
#[derive(Copy, Clone, Debug, PartialEq)]
enum Adjustment {
Identity,
Deref,
}
#[derive(Copy, Clone, Debug, PartialEq)]
enum CallKind {
Indirect,
Direct(DefId),
}
fn temp_decl(mutability: Mutability, ty: Ty) -> LocalDecl {
LocalDecl { mutability, ty, name: None, source_info: None }
}
fn local_decls_for_sig<'tcx>(sig: &ty::FnSig<'tcx>)
-> IndexVec<Local, LocalDecl<'tcx>>
{
iter::once(LocalDecl {
mutability: Mutability::Mut,
ty: sig.output(),
name: None,
source_info: None
}).chain(sig.inputs().iter().map(|ity| LocalDecl {
mutability: Mutability::Not,
ty: *ity,
name: None,
source_info: None,
})).collect()
iter::once(temp_decl(Mutability::Mut, sig.output()))
.chain(sig.inputs().iter().map(
|ity| temp_decl(Mutability::Not, ity)))
.collect()
}
fn build_fn_ptr_shim<'a, 'tcx>(tcx: ty::TyCtxt<'a, 'tcx, 'tcx>,
fn_ty: Ty<'tcx>,
sig_ty: Ty<'tcx>)
-> Mir<'tcx>
/// Build a "call" shim for `def_id`. The shim calls the
/// function specified by `call_kind`, first adjusting its first
/// argument according to `rcvr_adjustment`.
///
/// If `untuple_args` is a vec of types, the second argument of the
/// function will be untupled as these types.
fn build_call_shim<'a, 'tcx>(tcx: ty::TyCtxt<'a, 'tcx, 'tcx>,
param_env: &ty::ParameterEnvironment<'tcx>,
def_id: DefId,
rcvr_adjustment: Adjustment,
call_kind: CallKind,
untuple_args: Option<&[Ty<'tcx>]>)
-> Mir<'tcx>
{
debug!("build_fn_ptr_shim(fn_ty={:?}, sig_ty={:?})", fn_ty, sig_ty);
let trait_sig = match sig_ty.sty {
ty::TyFnDef(_, _, fty) => tcx.erase_late_bound_regions(&fty),
_ => bug!("unexpected type for shim {:?}", sig_ty)
};
debug!("build_call_shim(def_id={:?}, rcvr_adjustment={:?}, \
call_kind={:?}, untuple_args={:?})",
def_id, rcvr_adjustment, call_kind, untuple_args);
let self_ty = match trait_sig.inputs()[0].sty {
ty::TyParam(..) => fn_ty,
ty::TyRef(r, mt) => tcx.mk_ref(r, ty::TypeAndMut {
ty: fn_ty,
mutbl: mt.mutbl
}),
_ => bug!("unexpected self_ty {:?}", trait_sig),
};
let fn_ty = tcx.item_type(def_id).subst(tcx, param_env.free_substs);
// Not normalizing here without a param env.
let sig = tcx.erase_late_bound_regions(&fn_ty.fn_sig());
let span = tcx.def_span(def_id);
let fn_ptr_sig = match fn_ty.sty {
ty::TyFnPtr(fty) |
ty::TyFnDef(_, _, fty) =>
tcx.erase_late_bound_regions_and_normalize(&fty),
_ => bug!("non-fn-ptr {:?} in build_fn_ptr_shim", fn_ty)
};
let sig = tcx.mk_fn_sig(
[
self_ty,
tcx.intern_tup(fn_ptr_sig.inputs(), false)
].iter().cloned(),
fn_ptr_sig.output(),
false,
hir::Unsafety::Normal,
Abi::RustCall,
);
debug!("build_call_shim: sig={:?}", sig);
let local_decls = local_decls_for_sig(&sig);
let source_info = SourceInfo {
span: DUMMY_SP,
scope: ARGUMENT_VISIBILITY_SCOPE
let source_info = SourceInfo { span, scope: ARGUMENT_VISIBILITY_SCOPE };
let rcvr_l = Lvalue::Local(Local::new(1+0));
let return_block_id = BasicBlock::new(1);
let rcvr = match rcvr_adjustment {
Adjustment::Identity => Operand::Consume(rcvr_l),
Adjustment::Deref => Operand::Consume(Lvalue::Projection(
box Projection { base: rcvr_l, elem: ProjectionElem::Deref }
))
};
let fn_ptr = Lvalue::Local(Local::new(1+0));
let fn_ptr = match trait_sig.inputs()[0].sty {
ty::TyParam(..) => fn_ptr,
ty::TyRef(..) => Lvalue::Projection(box Projection {
base: fn_ptr, elem: ProjectionElem::Deref
}),
_ => bug!("unexpected self_ty {:?}", trait_sig),
let (callee, mut args) = match call_kind {
CallKind::Indirect => (rcvr, vec![]),
CallKind::Direct(def_id) => (
Operand::Constant(Constant {
span: span,
ty: tcx.item_type(def_id).subst(tcx, param_env.free_substs),
literal: Literal::Item { def_id, substs: param_env.free_substs },
}),
vec![rcvr]
)
};
let fn_args = Local::new(1+1);
let return_block_id = BasicBlock::new(1);
if let Some(untuple_args) = untuple_args {
args.extend(untuple_args.iter().enumerate().map(|(i, ity)| {
let arg_lv = Lvalue::Local(Local::new(1+1));
Operand::Consume(Lvalue::Projection(box Projection {
base: arg_lv,
elem: ProjectionElem::Field(Field::new(i), *ity)
}))
}));
} else {
args.extend((1..sig.inputs().len()).map(|i| {
Operand::Consume(Lvalue::Local(Local::new(1+i)))
}));
}
// return = ADT(arg0, arg1, ...); return
let start_block = BasicBlockData {
let mut blocks = IndexVec::new();
blocks.push(BasicBlockData {
statements: vec![],
terminator: Some(Terminator {
source_info: source_info,
kind: TerminatorKind::Call {
func: Operand::Consume(fn_ptr),
args: fn_ptr_sig.inputs().iter().enumerate().map(|(i, ity)| {
Operand::Consume(Lvalue::Projection(box Projection {
base: Lvalue::Local(fn_args),
elem: ProjectionElem::Field(
Field::new(i), *ity
)
}))
}).collect(),
// FIXME: can we pass a Some destination for an uninhabited ty?
func: callee,
args: args,
destination: Some((Lvalue::Local(RETURN_POINTER),
return_block_id)),
cleanup: None
}
}),
is_cleanup: false
};
let return_block = BasicBlockData {
});
blocks.push(BasicBlockData {
statements: vec![],
terminator: Some(Terminator {
source_info: source_info,
kind: TerminatorKind::Return
}),
is_cleanup: false
};
});
let mut mir = Mir::new(
vec![start_block, return_block].into_iter().collect(),
blocks,
IndexVec::from_elem_n(
VisibilityScopeData { span: DUMMY_SP, parent_scope: None }, 1
VisibilityScopeData { span: span, parent_scope: None }, 1
),
IndexVec::new(),
sig.output(),
local_decls,
sig.inputs().len(),
vec![],
DUMMY_SP
span
);
mir.spread_arg = Some(fn_args);
if let Abi::RustCall = sig.abi {
mir.spread_arg = Some(Local::new(sig.inputs().len()));
}
mir
}
......
......@@ -11,7 +11,7 @@
use llvm::{self, ValueRef, Integer, Pointer, Float, Double, Struct, Array, Vector, AttributePlace};
use base;
use builder::Builder;
use common::{type_is_fat_ptr, C_uint};
use common::{self, type_is_fat_ptr, C_uint};
use context::CrateContext;
use cabi_x86;
use cabi_x86_64;
......@@ -334,9 +334,30 @@ pub fn new<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
fn_ty
}
pub fn unadjusted<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
pub fn new_vtable<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
sig: ty::FnSig<'tcx>,
extra_args: &[Ty<'tcx>]) -> FnType {
let mut fn_ty = FnType::unadjusted(ccx, sig, extra_args);
// Don't pass the vtable, it's not an argument of the virtual fn.
fn_ty.args[1].ignore();
fn_ty.adjust_for_abi(ccx, sig);
fn_ty
}
pub fn from_instance<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
instance: &ty::Instance<'tcx>,
extra_args: &[Ty<'tcx>]) -> FnType
{
let ity = common::instance_ty(ccx.shared(), instance);
let sig = common::ty_fn_sig(ccx, ity);
let sig = ccx.tcx().erase_late_bound_regions_and_normalize(&sig);
Self::new(ccx, sig, extra_args)
}
fn unadjusted<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
sig: ty::FnSig<'tcx>,
extra_args: &[Ty<'tcx>]) -> FnType {
use self::Abi::*;
let cconv = match ccx.sess().target.target.adjust_abi(sig.abi) {
RustIntrinsic | PlatformIntrinsic |
......@@ -532,9 +553,9 @@ pub fn unadjusted<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
}
}
pub fn adjust_for_abi<'a, 'tcx>(&mut self,
ccx: &CrateContext<'a, 'tcx>,
sig: ty::FnSig<'tcx>) {
fn adjust_for_abi<'a, 'tcx>(&mut self,
ccx: &CrateContext<'a, 'tcx>,
sig: ty::FnSig<'tcx>) {
let abi = sig.abi;
if abi == Abi::Unadjusted { return }
......
......@@ -47,7 +47,7 @@
use mir::lvalue::LvalueRef;
use attributes;
use builder::Builder;
use callee::{Callee};
use callee;
use common::{C_bool, C_bytes_in_context, C_i32, C_uint};
use collector::{self, TransItemCollectionMode};
use common::{C_struct_in_context, C_u64, C_undef};
......@@ -654,7 +654,7 @@ pub fn maybe_create_entry_wrapper(ccx: &CrateContext) {
return;
}
let main_llfn = Callee::def(ccx, main_def_id, instance.substs).reify(ccx);
let main_llfn = callee::get_fn(ccx, instance);
let et = ccx.sess().entry_type.get().unwrap();
match et {
......@@ -688,8 +688,8 @@ fn create_entry_fn(ccx: &CrateContext,
let (start_fn, args) = if use_start_lang_item {
let start_def_id = ccx.tcx().require_lang_item(StartFnLangItem);
let empty_substs = ccx.tcx().intern_substs(&[]);
let start_fn = Callee::def(ccx, start_def_id, empty_substs).reify(ccx);
let start_instance = Instance::mono(ccx.tcx(), start_def_id);
let start_fn = callee::get_fn(ccx, start_instance);
(start_fn, vec![bld.pointercast(rust_main, Type::i8p(ccx).ptr_to()), get_param(llfn, 0),
get_param(llfn, 1)])
} else {
......
......@@ -14,8 +14,6 @@
//! and methods are represented as just a fn ptr and not a full
//! closure.
pub use self::CalleeData::*;
use llvm::{self, ValueRef, get_params};
use rustc::hir::def_id::DefId;
use rustc::ty::subst::{Substs, Subst};
......@@ -27,98 +25,17 @@
use mir::lvalue::LvalueRef;
use monomorphize;
use consts;
use common::instance_ty;
use declare;
use value::Value;
use meth;
use monomorphize::Instance;
use back::symbol_names::symbol_name;
use trans_item::TransItem;
use type_of;
use rustc::ty::{self, Ty, TypeFoldable};
use rustc::ty::{self, TypeFoldable};
use std::iter;
use mir::lvalue::Alignment;
#[derive(Debug)]
pub enum CalleeData {
/// Function pointer.
Fn(ValueRef),
Intrinsic,
/// Trait object found in the vtable at that index.
Virtual(usize)
}
#[derive(Debug)]
pub struct Callee<'tcx> {
pub data: CalleeData,
pub ty: Ty<'tcx>
}
impl<'tcx> Callee<'tcx> {
/// Function or method definition.
pub fn def<'a>(ccx: &CrateContext<'a, 'tcx>, def_id: DefId, substs: &'tcx Substs<'tcx>)
-> Callee<'tcx> {
let instance = monomorphize::resolve(ccx.shared(), def_id, substs);
let ty = instance_ty(ccx.shared(), &instance);
let data = match instance.def {
ty::InstanceDef::Intrinsic(_) => Intrinsic,
ty::InstanceDef::ClosureOnceShim { .. } => {
let closure_ty = instance.substs.type_at(0);
let (closure_def_id, closure_substs) = match closure_ty.sty {
ty::TyClosure(def_id, substs) => (def_id, substs),
_ => bug!("bad closure instance {:?}", instance)
};
Fn(trans_fn_once_adapter_shim(
ccx,
closure_def_id,
closure_substs,
instance,
get_fn(
ccx,
Instance::new(closure_def_id, closure_substs.substs)
)
))
}
ty::InstanceDef::Virtual(_, n) => Virtual(n),
ty::InstanceDef::FnPtrShim(..) |
ty::InstanceDef::Item(..) => {
Fn(get_fn(ccx, instance))
}
};
Callee { data, ty }
}
/// Get the abi::FnType for a direct call. Mainly deals with the fact
/// that a Virtual call doesn't take the vtable, like its shim does.
/// The extra argument types are for variadic (extern "C") functions.
pub fn direct_fn_type<'a>(&self, ccx: &CrateContext<'a, 'tcx>,
extra_args: &[Ty<'tcx>]) -> FnType {
let sig = common::ty_fn_sig(ccx, self.ty);
let sig = ccx.tcx().erase_late_bound_regions_and_normalize(&sig);
let mut fn_ty = FnType::unadjusted(ccx, sig, extra_args);
if let Virtual(_) = self.data {
// Don't pass the vtable, it's not an argument of the virtual fn.
fn_ty.args[1].ignore();
}
fn_ty.adjust_for_abi(ccx, sig);
fn_ty
}
/// Turn the callee into a function pointer.
pub fn reify<'a>(self, ccx: &CrateContext<'a, 'tcx>) -> ValueRef {
match self.data {
Fn(llfn) => llfn,
Virtual(_) => meth::trans_object_shim(ccx, self),
Intrinsic => bug!("intrinsic {} getting reified", self.ty)
}
}
}
fn trans_fn_once_adapter_shim<'a, 'tcx>(
ccx: &'a CrateContext<'a, 'tcx>,
def_id: DefId,
......@@ -145,13 +62,14 @@ fn trans_fn_once_adapter_shim<'a, 'tcx>(
let sig = tcx.closure_type(def_id).subst(tcx, substs.substs);
let sig = tcx.erase_late_bound_regions_and_normalize(&sig);
assert_eq!(sig.abi, Abi::RustCall);
let llref_fn_ty = tcx.mk_fn_ptr(ty::Binder(tcx.mk_fn_sig(
let llref_fn_sig = tcx.mk_fn_sig(
iter::once(ref_closure_ty).chain(sig.inputs().iter().cloned()),
sig.output(),
sig.variadic,
sig.unsafety,
Abi::RustCall
)));
);
let llref_fn_ty = tcx.mk_fn_ptr(ty::Binder(llref_fn_sig));
debug!("trans_fn_once_adapter_shim: llref_fn_ty={:?}",
llref_fn_ty);
......@@ -177,15 +95,10 @@ fn trans_fn_once_adapter_shim<'a, 'tcx>(
let orig_fn_ty = fn_ty;
let mut bcx = Builder::new_block(ccx, lloncefn, "entry-block");
let callee = Callee {
data: Fn(llreffn),
ty: llref_fn_ty
};
// the first argument (`self`) will be the (by value) closure env.
let mut llargs = get_params(lloncefn);
let fn_ty = callee.direct_fn_type(bcx.ccx, &[]);
let fn_ty = FnType::new(ccx, llref_fn_sig, &[]);
let self_idx = fn_ty.ret.is_indirect() as usize;
let env_arg = &orig_fn_ty.args[0];
let env = if env_arg.is_indirect() {
......@@ -210,14 +123,13 @@ fn trans_fn_once_adapter_shim<'a, 'tcx>(
// to drop `self` when the body returns, or in case it unwinds.
let self_scope = CleanupScope::schedule_drop_mem(&bcx, env);
let llfn = callee.reify(bcx.ccx);
let llret;
if let Some(landing_pad) = self_scope.landing_pad {
let normal_bcx = bcx.build_sibling_block("normal-return");
llret = bcx.invoke(llfn, &llargs[..], normal_bcx.llbb(), landing_pad, None);
llret = bcx.invoke(llreffn, &llargs[..], normal_bcx.llbb(), landing_pad, None);
bcx = normal_bcx;
} else {
llret = bcx.call(llfn, &llargs[..], None);
llret = bcx.call(llreffn, &llargs[..], None);
}
fn_ty.apply_attrs_callsite(llret);
......@@ -247,9 +159,9 @@ fn trans_fn_once_adapter_shim<'a, 'tcx>(
/// - `ccx`: the crate context
/// - `def_id`: def id of the fn or method item being referenced
/// - `substs`: values for each of the fn/method's parameters
fn get_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
instance: Instance<'tcx>)
-> ValueRef
fn do_get_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
instance: Instance<'tcx>)
-> ValueRef
{
let tcx = ccx.tcx();
......@@ -335,3 +247,45 @@ fn get_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
llfn
}
pub fn get_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
instance: Instance<'tcx>)
-> ValueRef
{
match instance.def {
ty::InstanceDef::Intrinsic(_) => {
bug!("intrinsic {} getting reified", instance)
}
ty::InstanceDef::ClosureOnceShim { .. } => {
let closure_ty = instance.substs.type_at(0);
let (closure_def_id, closure_substs) = match closure_ty.sty {
ty::TyClosure(def_id, substs) => (def_id, substs),
_ => bug!("bad closure instance {:?}", instance)
};
trans_fn_once_adapter_shim(
ccx,
closure_def_id,
closure_substs,
instance,
do_get_fn(
ccx,
Instance::new(closure_def_id, closure_substs.substs)
)
)
}
ty::InstanceDef::FnPtrShim(..) |
ty::InstanceDef::Item(..) |
ty::InstanceDef::Virtual(..) => {
do_get_fn(ccx, instance)
}
}
}
pub fn resolve_and_get_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
def_id: DefId,
substs: &'tcx Substs<'tcx>)
-> ValueRef
{
get_fn(ccx, monomorphize::resolve(ccx.shared(), def_id, substs))
}
......@@ -656,8 +656,8 @@ fn should_trans_locally<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, instance: &Instan
ty::InstanceDef::ClosureOnceShim {
call_once: _, closure_did: def_id
} => def_id,
ty::InstanceDef::FnPtrShim(..) => return true,
ty::InstanceDef::Virtual(..) |
ty::InstanceDef::FnPtrShim(..) => return true,
ty::InstanceDef::Intrinsic(_) => return false
};
match tcx.hir.get_if_local(def_id) {
......
......@@ -18,7 +18,7 @@
use rustc::hir::def_id::DefId;
use rustc::traits;
use debuginfo;
use callee::Callee;
use callee;
use base;
use declare;
use glue::DropGlueKind;
......@@ -920,7 +920,7 @@ pub fn eh_personality(&self) -> ValueRef {
let tcx = self.tcx();
let llfn = match tcx.lang_items.eh_personality() {
Some(def_id) if !base::wants_msvc_seh(self.sess()) => {
Callee::def(self, def_id, tcx.intern_substs(&[])).reify(self)
callee::resolve_and_get_fn(self, def_id, tcx.intern_substs(&[]))
}
_ => {
let name = if base::wants_msvc_seh(self.sess()) {
......@@ -948,7 +948,7 @@ pub fn eh_unwind_resume(&self) -> ValueRef {
let tcx = self.tcx();
assert!(self.sess().target.target.options.custom_unwind_resume);
if let Some(def_id) = tcx.lang_items.eh_unwind_resume() {
let llfn = Callee::def(self, def_id, tcx.intern_substs(&[])).reify(self);
let llfn = callee::resolve_and_get_fn(self, def_id, tcx.intern_substs(&[]));
unwresume.set(Some(llfn));
return llfn;
}
......
......@@ -24,9 +24,10 @@
use rustc::ty::subst::Kind;
use rustc::mir::tcx::LvalueTy;
use mir::lvalue::LvalueRef;
use abi::FnType;
use adt;
use base::*;
use callee::Callee;
use callee::get_fn;
use cleanup::CleanupScope;
use common::*;
use machine::*;
......@@ -45,11 +46,10 @@ pub fn trans_exchange_free_ty<'a, 'tcx>(bcx: &Builder<'a, 'tcx>, ptr: LvalueRef<
let content_ty = ptr.ty.to_ty(bcx.tcx());
let def_id = langcall(bcx.tcx(), None, "", BoxFreeFnLangItem);
let substs = bcx.tcx().mk_substs(iter::once(Kind::from(content_ty)));
let callee = Callee::def(bcx.ccx, def_id, substs);
let instance = monomorphize::resolve(bcx.ccx.shared(), def_id, substs);
let fn_ty = callee.direct_fn_type(bcx.ccx, &[]);
let llret = bcx.call(callee.reify(bcx.ccx),
let fn_ty = FnType::from_instance(bcx.ccx, &instance, &[]);
let llret = bcx.call(get_fn(bcx.ccx, instance),
&[ptr.llval, ptr.llextra][..1 + ptr.has_extra() as usize], None);
fn_ty.apply_attrs_callsite(llret);
}
......@@ -258,16 +258,18 @@ pub fn implement_drop_glue<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, g: DropGlueKi
.find(|it| it.kind == ty::AssociatedKind::Method)
.unwrap().def_id;
let self_type_substs = tcx.mk_substs_trait(t, &[]);
let callee = Callee::def(bcx.ccx, drop_method, self_type_substs);
let fn_ty = callee.direct_fn_type(bcx.ccx, &[]);
let drop_instance = monomorphize::resolve(
bcx.ccx.shared(), drop_method, self_type_substs);
let fn_ty = FnType::from_instance(bcx.ccx, &drop_instance, &[]);
let llfn = get_fn(bcx.ccx, drop_instance);
let llret;
let args = &[ptr.llval, ptr.llextra][..1 + ptr.has_extra() as usize];
if let Some(landing_pad) = contents_scope.landing_pad {
let normal_bcx = bcx.build_sibling_block("normal-return");
llret = bcx.invoke(callee.reify(ccx), args, normal_bcx.llbb(), landing_pad, None);
llret = bcx.invoke(llfn, args, normal_bcx.llbb(), landing_pad, None);
bcx = normal_bcx;
} else {
llret = bcx.call(callee.reify(bcx.ccx), args, None);
llret = bcx.call(llfn, args, None);
}
fn_ty.apply_attrs_callsite(llret);
contents_scope.trans(&bcx);
......
......@@ -8,20 +8,16 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use attributes;
use llvm::{ValueRef, get_params};
use llvm::ValueRef;
use rustc::traits;
use callee::{Callee, CalleeData};
use callee;
use common::*;
use builder::Builder;
use consts;
use declare;
use glue;
use machine;
use monomorphize::Instance;
use type_::Type;
use type_of::*;
use back::symbol_names;
use value::Value;
use rustc::ty;
......@@ -42,74 +38,6 @@ pub fn get_virtual_method<'a, 'tcx>(bcx: &Builder<'a, 'tcx>,
ptr
}
/// Generate a shim function that allows an object type like `SomeTrait` to
/// implement the type `SomeTrait`. Imagine a trait definition:
///
/// trait SomeTrait { fn get(&self) -> i32; ... }
///
/// And a generic bit of code:
///
/// fn foo<T:SomeTrait>(t: &T) {
/// let x = SomeTrait::get;
/// x(t)
/// }
///
/// What is the value of `x` when `foo` is invoked with `T=SomeTrait`?
/// The answer is that it is a shim function generated by this routine:
///
/// fn shim(t: &SomeTrait) -> i32 {
/// // ... call t.get() virtually ...
/// }
///
/// In fact, all virtual calls can be thought of as normal trait calls
/// that go through this shim function.
pub fn trans_object_shim<'a, 'tcx>(ccx: &'a CrateContext<'a, 'tcx>,
callee: Callee<'tcx>)
-> ValueRef {
debug!("trans_object_shim({:?})", callee);
let function_name = match callee.ty.sty {
ty::TyFnDef(def_id, substs, _) => {
let instance = Instance::new(def_id, substs);
symbol_names::symbol_name(instance, ccx.shared())
}
_ => bug!()
};
let llfn = declare::define_internal_fn(ccx, &function_name, callee.ty);
attributes::set_frame_pointer_elimination(ccx, llfn);
let bcx = Builder::new_block(ccx, llfn, "entry-block");
let mut llargs = get_params(llfn);
let fn_ret = callee.ty.fn_ret();
let fn_ty = callee.direct_fn_type(ccx, &[]);
let fn_ptr = match callee.data {
CalleeData::Virtual(idx) => {
let fn_ptr = get_virtual_method(&bcx,
llargs.remove(fn_ty.ret.is_indirect() as usize + 1), idx);
let llty = fn_ty.llvm_type(bcx.ccx).ptr_to();
bcx.pointercast(fn_ptr, llty)
},
_ => bug!("trans_object_shim called with non-virtual callee"),
};
let llret = bcx.call(fn_ptr, &llargs, None);
fn_ty.apply_attrs_callsite(llret);
if fn_ret.0.is_never() {
bcx.unreachable();
} else {
if fn_ty.ret.is_indirect() || fn_ty.ret.is_ignore() {
bcx.ret_void();
} else {
bcx.ret(llret);
}
}
llfn
}
/// Creates a dynamic vtable for the given type and vtable origin.
/// This is used only for objects.
///
......@@ -150,7 +78,7 @@ pub fn get_vtable<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
let trait_ref = trait_ref.with_self_ty(tcx, ty);
let methods = traits::get_vtable_methods(tcx, trait_ref).map(|opt_mth| {
opt_mth.map_or(nullptr, |(def_id, substs)| {
Callee::def(ccx, def_id, substs).reify(ccx)
callee::resolve_and_get_fn(ccx, def_id, substs)
})
});
components.extend(methods);
......
......@@ -16,13 +16,14 @@
use rustc::mir;
use abi::{Abi, FnType, ArgType};
use base::{self, Lifetime};
use callee::{Callee, CalleeData, Fn, Intrinsic, Virtual};
use callee;
use builder::Builder;
use common::{self, Funclet};
use common::{C_bool, C_str_slice, C_struct, C_u32, C_undef};
use consts;
use machine::llalign_of_min;
use meth;
use monomorphize;
use type_of::{self, align_of};
use glue;
use type_::Type;
......@@ -340,9 +341,8 @@ pub fn trans_block(&mut self, bb: mir::BasicBlock,
// Obtain the panic entry point.
let def_id = common::langcall(bcx.tcx(), Some(span), "", lang_item);
let callee = Callee::def(bcx.ccx, def_id,
bcx.ccx.empty_substs_for_def_id(def_id));
let llfn = callee.reify(bcx.ccx);
let instance = ty::Instance::mono(bcx.tcx(), def_id);
let llfn = callee::get_fn(bcx.ccx, instance);
// Translate the actual panic invoke/call.
if let Some(unwind) = cleanup {
......@@ -365,30 +365,30 @@ pub fn trans_block(&mut self, bb: mir::BasicBlock,
// Create the callee. This is a fn ptr or zero-sized and hence a kind of scalar.
let callee = self.trans_operand(&bcx, func);
let (mut callee, sig) = match callee.ty.sty {
let (instance, mut llfn, sig) = match callee.ty.sty {
ty::TyFnDef(def_id, substs, sig) => {
(Callee::def(bcx.ccx, def_id, substs), sig)
(Some(monomorphize::resolve(bcx.ccx.shared(), def_id, substs)),
None,
sig)
}
ty::TyFnPtr(sig) => {
(Callee {
data: Fn(callee.immediate()),
ty: callee.ty
}, sig)
(None,
Some(callee.immediate()),
sig)
}
_ => bug!("{} is not callable", callee.ty)
};
let def = instance.map(|i| i.def);
let sig = bcx.tcx().erase_late_bound_regions_and_normalize(&sig);
let abi = sig.abi;
// Handle intrinsics old trans wants Expr's for, ourselves.
let intrinsic = match (&callee.ty.sty, &callee.data) {
(&ty::TyFnDef(def_id, ..), &Intrinsic) => {
Some(bcx.tcx().item_name(def_id).as_str())
}
let intrinsic = match def {
Some(ty::InstanceDef::Intrinsic(def_id))
=> Some(bcx.tcx().item_name(def_id).as_str()),
_ => None
};
let mut intrinsic = intrinsic.as_ref().map(|s| &s[..]);
let intrinsic = intrinsic.as_ref().map(|s| &s[..]);
if intrinsic == Some("move_val_init") {
let &(_, target) = destination.as_ref().unwrap();
......@@ -412,15 +412,17 @@ pub fn trans_block(&mut self, bb: mir::BasicBlock,
let op_ty = op_arg.ty(&self.mir, bcx.tcx());
self.monomorphize(&op_ty)
}).collect::<Vec<_>>();
let fn_ty = callee.direct_fn_type(bcx.ccx, &extra_args);
let fn_ty = match def {
Some(ty::InstanceDef::Virtual(..)) => {
FnType::new_vtable(bcx.ccx, sig, &extra_args)
}
_ => FnType::new(bcx.ccx, sig, &extra_args)
};
if intrinsic == Some("drop_in_place") {
let &(_, target) = destination.as_ref().unwrap();
let ty = if let ty::TyFnDef(_, substs, _) = callee.ty.sty {
substs.type_at(0)
} else {
bug!("Unexpected ty: {}", callee.ty);
};
let ty = instance.unwrap().substs.type_at(0);
// Double check for necessity to drop
if !bcx.ccx.shared().type_needs_drop(ty) {
......@@ -430,8 +432,7 @@ pub fn trans_block(&mut self, bb: mir::BasicBlock,
let drop_fn = glue::get_drop_glue(bcx.ccx, ty);
let llty = fn_ty.llvm_type(bcx.ccx).ptr_to();
callee.data = Fn(bcx.pointercast(drop_fn, llty));
intrinsic = None;
llfn = Some(bcx.pointercast(drop_fn, llty));
}
// The arguments we'll be passing. Plus one to account for outptr, if used.
......@@ -440,12 +441,9 @@ pub fn trans_block(&mut self, bb: mir::BasicBlock,
// Prepare the return value destination
let ret_dest = if let Some((ref dest, _)) = *destination {
let is_intrinsic = if let Intrinsic = callee.data {
true
} else {
false
};
self.make_return_dest(&bcx, dest, &fn_ty.ret, &mut llargs, is_intrinsic)
let is_intrinsic = intrinsic.is_some();
self.make_return_dest(&bcx, dest, &fn_ty.ret, &mut llargs,
is_intrinsic)
} else {
ReturnDest::Nothing
};
......@@ -483,52 +481,56 @@ pub fn trans_block(&mut self, bb: mir::BasicBlock,
let op = self.trans_operand(&bcx, arg);
self.trans_argument(&bcx, op, &mut llargs, &fn_ty,
&mut idx, &mut callee.data);
&mut idx, &mut llfn, &def);
}
if let Some(tup) = untuple {
self.trans_arguments_untupled(&bcx, tup, &mut llargs, &fn_ty,
&mut idx, &mut callee.data)
&mut idx, &mut llfn, &def)
}
let fn_ptr = match callee.data {
Intrinsic => {
use intrinsic::trans_intrinsic_call;
let (dest, llargs) = match ret_dest {
_ if fn_ty.ret.is_indirect() => {
(llargs[0], &llargs[1..])
}
ReturnDest::Nothing => {
(C_undef(fn_ty.ret.original_ty.ptr_to()), &llargs[..])
}
ReturnDest::IndirectOperand(dst, _) |
ReturnDest::Store(dst) => (dst, &llargs[..]),
ReturnDest::DirectOperand(_) =>
bug!("Cannot use direct operand with an intrinsic call")
};
trans_intrinsic_call(&bcx, callee.ty, &fn_ty, &llargs, dest,
terminator.source_info.span);
if intrinsic.is_some() && intrinsic != Some("drop_in_place") {
use intrinsic::trans_intrinsic_call;
if let ReturnDest::IndirectOperand(dst, _) = ret_dest {
// Make a fake operand for store_return
let op = OperandRef {
val: Ref(dst, Alignment::AbiAligned),
ty: sig.output(),
};
self.store_return(&bcx, ret_dest, fn_ty.ret, op);
let (dest, llargs) = match ret_dest {
_ if fn_ty.ret.is_indirect() => {
(llargs[0], &llargs[1..])
}
if let Some((_, target)) = *destination {
funclet_br(self, bcx, target);
} else {
bcx.unreachable();
ReturnDest::Nothing => {
(C_undef(fn_ty.ret.original_ty.ptr_to()), &llargs[..])
}
ReturnDest::IndirectOperand(dst, _) |
ReturnDest::Store(dst) => (dst, &llargs[..]),
ReturnDest::DirectOperand(_) =>
bug!("Cannot use direct operand with an intrinsic call")
};
return;
let callee_ty = common::instance_ty(
bcx.ccx.shared(), instance.as_ref().unwrap());
trans_intrinsic_call(&bcx, callee_ty, &fn_ty, &llargs, dest,
terminator.source_info.span);
if let ReturnDest::IndirectOperand(dst, _) = ret_dest {
// Make a fake operand for store_return
let op = OperandRef {
val: Ref(dst, Alignment::AbiAligned),
ty: sig.output(),
};
self.store_return(&bcx, ret_dest, fn_ty.ret, op);
}
if let Some((_, target)) = *destination {
funclet_br(self, bcx, target);
} else {
bcx.unreachable();
}
Fn(f) => f,
Virtual(_) => bug!("Virtual fn ptr not extracted")
return;
}
let fn_ptr = match (llfn, instance) {
(Some(llfn), _) => llfn,
(None, Some(instance)) => callee::get_fn(bcx.ccx, instance),
_ => span_bug!(span, "no llfn for call"),
};
// Many different ways to call a function handled here
......@@ -578,16 +580,17 @@ fn trans_argument(&mut self,
llargs: &mut Vec<ValueRef>,
fn_ty: &FnType,
next_idx: &mut usize,
callee: &mut CalleeData) {
llfn: &mut Option<ValueRef>,
def: &Option<ty::InstanceDef<'tcx>>) {
if let Pair(a, b) = op.val {
// Treat the values in a fat pointer separately.
if common::type_is_fat_ptr(bcx.ccx, op.ty) {
let (ptr, meta) = (a, b);
if *next_idx == 0 {
if let Virtual(idx) = *callee {
let llfn = meth::get_virtual_method(bcx, meta, idx);
if let Some(ty::InstanceDef::Virtual(_, idx)) = *def {
let llmeth = meth::get_virtual_method(bcx, meta, idx);
let llty = fn_ty.llvm_type(bcx.ccx).ptr_to();
*callee = Fn(bcx.pointercast(llfn, llty));
*llfn = Some(bcx.pointercast(llmeth, llty));
}
}
......@@ -596,8 +599,8 @@ fn trans_argument(&mut self,
// We won't be checking the type again.
ty: bcx.tcx().types.err
};
self.trans_argument(bcx, imm_op(ptr), llargs, fn_ty, next_idx, callee);
self.trans_argument(bcx, imm_op(meta), llargs, fn_ty, next_idx, callee);
self.trans_argument(bcx, imm_op(ptr), llargs, fn_ty, next_idx, llfn, def);
self.trans_argument(bcx, imm_op(meta), llargs, fn_ty, next_idx, llfn, def);
return;
}
}
......@@ -660,7 +663,8 @@ fn trans_arguments_untupled(&mut self,
llargs: &mut Vec<ValueRef>,
fn_ty: &FnType,
next_idx: &mut usize,
callee: &mut CalleeData) {
llfn: &mut Option<ValueRef>,
def: &Option<ty::InstanceDef<'tcx>>) {
let tuple = self.trans_operand(bcx, operand);
let arg_types = match tuple.ty.sty {
......@@ -686,7 +690,7 @@ fn trans_arguments_untupled(&mut self,
val: val,
ty: ty
};
self.trans_argument(bcx, op, llargs, fn_ty, next_idx, callee);
self.trans_argument(bcx, op, llargs, fn_ty, next_idx, llfn, def);
}
}
......@@ -708,7 +712,7 @@ fn trans_arguments_untupled(&mut self,
val: Immediate(elem),
ty: ty
};
self.trans_argument(bcx, op, llargs, fn_ty, next_idx, callee);
self.trans_argument(bcx, op, llargs, fn_ty, next_idx, llfn, def);
}
}
Pair(a, b) => {
......@@ -724,7 +728,7 @@ fn trans_arguments_untupled(&mut self,
val: Immediate(elem),
ty: ty
};
self.trans_argument(bcx, op, llargs, fn_ty, next_idx, callee);
self.trans_argument(bcx, op, llargs, fn_ty, next_idx, llfn, def);
}
}
}
......
......@@ -23,7 +23,7 @@
use rustc::ty::subst::{Kind, Substs, Subst};
use rustc_data_structures::indexed_vec::{Idx, IndexVec};
use {abi, adt, base, Disr, machine};
use callee::Callee;
use callee;
use builder::Builder;
use common::{self, CrateContext, const_get_elt, val_ty};
use common::{C_array, C_bool, C_bytes, C_floating_f64, C_integral, C_big_integral};
......@@ -565,8 +565,7 @@ fn const_rvalue(&self, rvalue: &mir::Rvalue<'tcx>,
mir::CastKind::ReifyFnPointer => {
match operand.ty.sty {
ty::TyFnDef(def_id, substs, _) => {
Callee::def(self.ccx, def_id, substs)
.reify(self.ccx)
callee::resolve_and_get_fn(self.ccx, def_id, substs)
}
_ => {
span_bug!(span, "{} cannot be reified to a fn ptr",
......@@ -589,8 +588,7 @@ fn const_rvalue(&self, rvalue: &mir::Rvalue<'tcx>,
let input = tcx.erase_late_bound_regions_and_normalize(&input);
let substs = tcx.mk_substs([operand.ty, input]
.iter().cloned().map(Kind::from));
Callee::def(self.ccx, call_once, substs)
.reify(self.ccx)
callee::resolve_and_get_fn(self.ccx, call_once, substs)
}
_ => {
bug!("{} cannot be cast to a fn ptr", operand.ty)
......
......@@ -19,7 +19,7 @@
use base;
use builder::Builder;
use callee::Callee;
use callee;
use common::{self, val_ty, C_bool, C_null, C_uint};
use common::{C_integral};
use adt;
......@@ -183,8 +183,7 @@ pub fn trans_rvalue_operand(&mut self,
match operand.ty.sty {
ty::TyFnDef(def_id, substs, _) => {
OperandValue::Immediate(
Callee::def(bcx.ccx, def_id, substs)
.reify(bcx.ccx))
callee::resolve_and_get_fn(bcx.ccx, def_id, substs))
}
_ => {
bug!("{} cannot be reified to a fn ptr", operand.ty)
......@@ -208,8 +207,8 @@ pub fn trans_rvalue_operand(&mut self,
let substs = bcx.tcx().mk_substs([operand.ty, input]
.iter().cloned().map(Kind::from));
OperandValue::Immediate(
Callee::def(bcx.ccx, call_once, substs)
.reify(bcx.ccx))
callee::resolve_and_get_fn(bcx.ccx, call_once, substs)
)
}
_ => {
bug!("{} cannot be cast to a fn ptr", operand.ty)
......@@ -463,8 +462,8 @@ pub fn trans_rvalue_operand(&mut self,
bcx.sess().fatal(&format!("allocation of `{}` {}", box_ty, s));
}
};
let r = Callee::def(bcx.ccx, def_id, bcx.tcx().intern_substs(&[]))
.reify(bcx.ccx);
let instance = ty::Instance::mono(bcx.tcx(), def_id);
let r = callee::get_fn(bcx.ccx, instance);
let val = bcx.pointercast(bcx.call(r, &[llsize, llalign], None), llty_ptr);
let operand = OperandRef {
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册