Navigation Menu

Skip to content

Commit

Permalink
refactor away callee::Callee and translate virtual calls through a MI…
Browse files Browse the repository at this point in the history
…R 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.
  • Loading branch information
arielb1 committed Mar 18, 2017
1 parent aac5ba5 commit 65a4266
Show file tree
Hide file tree
Showing 13 changed files with 324 additions and 367 deletions.
1 change: 1 addition & 0 deletions src/librustc_mir/lib.rs
Expand Up @@ -23,6 +23,7 @@ Rust MIR: a lowered representation of Rust. Also: an experiment!
#![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)]
Expand Down
5 changes: 1 addition & 4 deletions src/librustc_mir/mir_map.rs
Expand Up @@ -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);

Expand Down
213 changes: 133 additions & 80 deletions src/librustc_mir/shim.rs
Expand Up @@ -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;
Expand All @@ -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")
};
Expand All @@ -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
}

Expand Down
31 changes: 26 additions & 5 deletions src/librustc_trans/abi.rs
Expand Up @@ -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;
Expand Down Expand Up @@ -334,9 +334,30 @@ impl FnType {
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 |
Expand Down Expand Up @@ -532,9 +553,9 @@ impl FnType {
}
}

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 }

Expand Down
8 changes: 4 additions & 4 deletions src/librustc_trans/base.rs
Expand Up @@ -47,7 +47,7 @@ use abi;
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};
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -688,8 +688,8 @@ pub fn maybe_create_entry_wrapper(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 {
Expand Down

0 comments on commit 65a4266

Please sign in to comment.