From 65a4266f1f4ce9dac5a6ef588443b7cac911d265 Mon Sep 17 00:00:00 2001 From: Ariel Ben-Yehuda Date: Wed, 8 Mar 2017 18:33:21 +0200 Subject: [PATCH] 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. --- src/librustc_mir/lib.rs | 1 + src/librustc_mir/mir_map.rs | 5 +- src/librustc_mir/shim.rs | 213 ++++++++++++++++++----------- src/librustc_trans/abi.rs | 31 ++++- src/librustc_trans/base.rs | 8 +- src/librustc_trans/callee.rs | 150 +++++++------------- src/librustc_trans/collector.rs | 2 +- src/librustc_trans/context.rs | 6 +- src/librustc_trans/glue.rs | 20 +-- src/librustc_trans/meth.rs | 78 +---------- src/librustc_trans/mir/block.rs | 156 +++++++++++---------- src/librustc_trans/mir/constant.rs | 8 +- src/librustc_trans/mir/rvalue.rs | 13 +- 13 files changed, 324 insertions(+), 367 deletions(-) diff --git a/src/librustc_mir/lib.rs b/src/librustc_mir/lib.rs index 9e6b77dbabd..2718a0204a1 100644 --- a/src/librustc_mir/lib.rs +++ b/src/librustc_mir/lib.rs @@ -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)] diff --git a/src/librustc_mir/mir_map.rs b/src/librustc_mir/mir_map.rs index 3fa7131a2b6..2d2b90235ca 100644 --- a/src/librustc_mir/mir_map.rs +++ b/src/librustc_mir/mir_map.rs @@ -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); diff --git a/src/librustc_mir/shim.rs b/src/librustc_mir/shim.rs index 2a053535e7e..97c83c7a42e 100644 --- a/src/librustc_mir/shim.rs +++ b/src/librustc_mir/shim.rs @@ -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> { 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, + ¶m_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, + ¶m_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> { - 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 } diff --git a/src/librustc_trans/abi.rs b/src/librustc_trans/abi.rs index 0bbe981f2f7..710aa1fbbc6 100644 --- a/src/librustc_trans/abi.rs +++ b/src/librustc_trans/abi.rs @@ -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 } diff --git a/src/librustc_trans/base.rs b/src/librustc_trans/base.rs index 10ab199671f..a58764878a3 100644 --- a/src/librustc_trans/base.rs +++ b/src/librustc_trans/base.rs @@ -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 { diff --git a/src/librustc_trans/callee.rs b/src/librustc_trans/callee.rs index 70da2a69ef4..5c7be56b56d 100644 --- a/src/librustc_trans/callee.rs +++ b/src/librustc_trans/callee.rs @@ -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)) +} diff --git a/src/librustc_trans/collector.rs b/src/librustc_trans/collector.rs index 9476ffc9444..2113b9b203c 100644 --- a/src/librustc_trans/collector.rs +++ b/src/librustc_trans/collector.rs @@ -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) { diff --git a/src/librustc_trans/context.rs b/src/librustc_trans/context.rs index b7381dd07dc..9297c010846 100644 --- a/src/librustc_trans/context.rs +++ b/src/librustc_trans/context.rs @@ -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; } diff --git a/src/librustc_trans/glue.rs b/src/librustc_trans/glue.rs index 2eb94aa56ab..9a639ed21f1 100644 --- a/src/librustc_trans/glue.rs +++ b/src/librustc_trans/glue.rs @@ -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); diff --git a/src/librustc_trans/meth.rs b/src/librustc_trans/meth.rs index bfd9f69a922..6b823756c8e 100644 --- a/src/librustc_trans/meth.rs +++ b/src/librustc_trans/meth.rs @@ -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: &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); diff --git a/src/librustc_trans/mir/block.rs b/src/librustc_trans/mir/block.rs index 2f1a2c9134c..761f6b208e7 100644 --- a/src/librustc_trans/mir/block.rs +++ b/src/librustc_trans/mir/block.rs @@ -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::>(); - 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, fn_ty: &FnType, next_idx: &mut usize, - callee: &mut CalleeData) { + llfn: &mut Option, + def: &Option>) { 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, fn_ty: &FnType, next_idx: &mut usize, - callee: &mut CalleeData) { + llfn: &mut Option, + def: &Option>) { 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); } } } diff --git a/src/librustc_trans/mir/constant.rs b/src/librustc_trans/mir/constant.rs index 69009ab3560..107b0982af9 100644 --- a/src/librustc_trans/mir/constant.rs +++ b/src/librustc_trans/mir/constant.rs @@ -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) diff --git a/src/librustc_trans/mir/rvalue.rs b/src/librustc_trans/mir/rvalue.rs index bbaf0f9d35f..3832c21d10a 100644 --- a/src/librustc_trans/mir/rvalue.rs +++ b/src/librustc_trans/mir/rvalue.rs @@ -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 { -- GitLab