Skip to content

Commit

Permalink
librustc: Make ~Trait two words by storing the type descriptor in t…
Browse files Browse the repository at this point in the history
…he vtable.
  • Loading branch information
pcwalton committed May 23, 2013
1 parent db518ef commit 211d038
Show file tree
Hide file tree
Showing 4 changed files with 73 additions and 53 deletions.
3 changes: 1 addition & 2 deletions src/librustc/middle/trans/common.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1089,8 +1089,7 @@ pub fn T_opaque_trait(cx: @CrateContext, store: ty::TraitStore) -> TypeRef {
}
ty::UniqTraitStore => {
T_struct([T_ptr(cx.tydesc_type),
T_unique_ptr(T_unique(cx, T_i8())),
T_ptr(cx.tydesc_type)],
T_unique_ptr(T_unique(cx, T_i8()))],
false)
}
ty::RegionTraitStore(_) => {
Expand Down
15 changes: 12 additions & 3 deletions src/librustc/middle/trans/glue.rs
Original file line number Diff line number Diff line change
Expand Up @@ -545,9 +545,18 @@ pub fn make_drop_glue(bcx: block, v0: ValueRef, t: ty::t) {
}
ty::ty_trait(_, _, ty::UniqTraitStore, _) => {
let lluniquevalue = GEPi(bcx, v0, [0, abi::trt_field_box]);
let lltydesc = Load(bcx, GEPi(bcx, v0, [0, abi::trt_field_tydesc]));
call_tydesc_glue_full(bcx, lluniquevalue, lltydesc,
abi::tydesc_field_free_glue, None);
let llvtable = Load(bcx, GEPi(bcx, v0, [0, abi::trt_field_vtable]));

// Cast the vtable to a pointer to a pointer to a tydesc.
let llvtable = PointerCast(bcx,
llvtable,
T_ptr(T_ptr(ccx.tydesc_type)));
let lltydesc = Load(bcx, llvtable);
call_tydesc_glue_full(bcx,
lluniquevalue,
lltydesc,
abi::tydesc_field_free_glue,
None);
bcx
}
ty::ty_opaque_closure_ptr(ck) => {
Expand Down
107 changes: 60 additions & 47 deletions src/librustc/middle/trans/meth.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,9 +39,13 @@ for non-monomorphized methods only. Other methods will
be generated once they are invoked with specific type parameters,
see `trans::base::lval_static_fn()` or `trans::base::monomorphic_fn()`.
*/
pub fn trans_impl(ccx: @CrateContext, path: path, name: ast::ident,
methods: &[@ast::method], generics: &ast::Generics,
self_ty: Option<ty::t>, id: ast::node_id) {
pub fn trans_impl(ccx: @CrateContext,
path: path,
name: ast::ident,
methods: &[@ast::method],
generics: &ast::Generics,
self_ty: Option<ty::t>,
id: ast::node_id) {
let _icx = ccx.insn_ctxt("impl::trans_impl");
let tcx = ccx.tcx;

Expand Down Expand Up @@ -718,7 +722,10 @@ pub fn trans_trait_callee_from_llval(bcx: block,
// Load the function from the vtable and cast it to the expected type.
debug!("(translating trait callee) loading method");
let llcallee_ty = type_of_fn_from_ty(ccx, callee_ty);
let mptr = Load(bcx, GEPi(bcx, llvtable, [0u, n_method]));

// Plus one in order to skip past the type descriptor.
let mptr = Load(bcx, GEPi(bcx, llvtable, [0u, n_method + 1]));

let mptr = PointerCast(bcx, mptr, T_ptr(llcallee_ty));

return Callee {
Expand Down Expand Up @@ -756,25 +763,40 @@ pub fn vtable_id(ccx: @CrateContext,
}
}

/// Creates a returns a dynamic vtable for the given type and vtable origin.
/// This is used only for objects.
pub fn get_vtable(ccx: @CrateContext,
self_ty: ty::t,
origin: typeck::vtable_origin)
-> ValueRef {
-> ValueRef {
let hash_id = vtable_id(ccx, &origin);
match ccx.vtables.find(&hash_id) {
Some(&val) => val,
None => match origin {
typeck::vtable_static(id, substs, sub_vtables) => {
make_impl_vtable(ccx, id, substs, sub_vtables)
Some(&val) => val,
None => {
match origin {
typeck::vtable_static(id, substs, sub_vtables) => {
make_impl_vtable(ccx, id, self_ty, substs, sub_vtables)
}
_ => fail!("get_vtable: expected a static origin"),
}
}
_ => fail!("get_vtable: expected a static origin")
}
}
}

pub fn make_vtable(ccx: @CrateContext, ptrs: ~[ValueRef]) -> ValueRef {
/// Helper function to declare and initialize the vtable.
pub fn make_vtable(ccx: @CrateContext,
tydesc: @mut tydesc_info,
ptrs: &[ValueRef])
-> ValueRef {
unsafe {
let _icx = ccx.insn_ctxt("impl::make_vtable");
let tbl = C_struct(ptrs);

let mut components = ~[ tydesc.tydesc ];
for ptrs.each |&ptr| {
components.push(ptr)
}

let tbl = C_struct(components);
let vtable = ccx.sess.str_of((ccx.names)("vtable"));
let vt_gvar = do str::as_c_str(*vtable) |buf| {
llvm::LLVMAddGlobal(ccx.llmod, val_ty(tbl), buf)
Expand All @@ -786,11 +808,13 @@ pub fn make_vtable(ccx: @CrateContext, ptrs: ~[ValueRef]) -> ValueRef {
}
}

/// Generates a dynamic vtable for objects.
pub fn make_impl_vtable(ccx: @CrateContext,
impl_id: ast::def_id,
self_ty: ty::t,
substs: ~[ty::t],
vtables: typeck::vtable_res)
-> ValueRef {
-> ValueRef {
let _icx = ccx.insn_ctxt("impl::make_impl_vtable");
let tcx = ccx.tcx;

Expand All @@ -802,9 +826,13 @@ pub fn make_impl_vtable(ccx: @CrateContext,

let has_tps =
!ty::lookup_item_type(ccx.tcx, impl_id).generics.type_param_defs.is_empty();
make_vtable(ccx, ty::trait_method_def_ids(tcx, trt_id).map(|method_def_id| {

let trait_method_def_ids = ty::trait_method_def_ids(tcx, trt_id);
let methods = do trait_method_def_ids.map |method_def_id| {
let im = ty::method(tcx, *method_def_id);
let fty = ty::subst_tps(tcx, substs, None,
let fty = ty::subst_tps(tcx,
substs,
None,
ty::mk_bare_fn(tcx, copy im.fty));
if im.generics.has_type_params() || ty::type_has_self(fty) {
debug!("(making impl vtable) method has self or type params: %s",
Expand All @@ -830,7 +858,13 @@ pub fn make_impl_vtable(ccx: @CrateContext,
trans_external_path(ccx, m_id, fty)
}
}
}))
};

// Generate a type descriptor for the vtable.
let tydesc = get_tydesc(ccx, self_ty);
glue::lazily_emit_all_tydesc_glue(ccx, tydesc);

make_vtable(ccx, tydesc, methods)
}

pub fn trans_trait_cast(bcx: block,
Expand All @@ -852,40 +886,19 @@ pub fn trans_trait_cast(bcx: block,
let ccx = bcx.ccx();
let v_ty = expr_ty(bcx, val);

match store {
ty::RegionTraitStore(_) | ty::BoxTraitStore => {
let mut llboxdest = GEPi(bcx, lldest, [0u, abi::trt_field_box]);
// Just store the pointer into the pair. (Region/borrowed
// and boxed trait objects are represented as pairs, and
// have no type descriptor field.)
llboxdest = PointerCast(bcx,
llboxdest,
T_ptr(type_of(bcx.ccx(), v_ty)));
bcx = expr::trans_into(bcx, val, SaveIn(llboxdest));
}
ty::UniqTraitStore => {
// Translate the uniquely-owned value in the
// triple. (Unique trait objects are represented as
// triples.)
let mut llvaldest = GEPi(bcx, lldest, [0, abi::trt_field_box]);
llvaldest = PointerCast(bcx,
llvaldest,
T_ptr(type_of(bcx.ccx(), v_ty)));
bcx = expr::trans_into(bcx, val, SaveIn(llvaldest));

// Get the type descriptor of the wrapped value and store
// it in the triple as well.
let tydesc = get_tydesc(bcx.ccx(), v_ty);
glue::lazily_emit_all_tydesc_glue(bcx.ccx(), tydesc);
let lltydescdest = GEPi(bcx, lldest, [0, abi::trt_field_tydesc]);
Store(bcx, tydesc.tydesc, lltydescdest);
}
}
let mut llboxdest = GEPi(bcx, lldest, [0u, abi::trt_field_box]);
// Just store the pointer into the pair. (Region/borrowed
// and boxed trait objects are represented as pairs, and
// have no type descriptor field.)
llboxdest = PointerCast(bcx,
llboxdest,
T_ptr(type_of(bcx.ccx(), v_ty)));
bcx = expr::trans_into(bcx, val, SaveIn(llboxdest));

// Store the vtable into the pair or triple.
let orig = /*bad*/copy ccx.maps.vtable_map.get(&id)[0];
let orig = resolve_vtable_in_fn_ctxt(bcx.fcx, orig);
let vtable = get_vtable(bcx.ccx(), orig);
let vtable = get_vtable(bcx.ccx(), v_ty, orig);
Store(bcx, vtable, PointerCast(bcx,
GEPi(bcx, lldest, [0u, abi::trt_field_vtable]),
T_ptr(val_ty(vtable))));
Expand Down
1 change: 0 additions & 1 deletion src/librustc/middle/trans/write_guard.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ use middle::trans::common::*;
use middle::trans::datum::*;
use middle::trans::expr;
use middle::ty;
use driver::session;
use syntax::codemap::span;
use syntax::ast;

Expand Down

0 comments on commit 211d038

Please sign in to comment.