Convert more resource tests to use classes with dtors

And monomorphize dtors correctly.
This commit is contained in:
Tim Chevalier 2012-05-22 21:44:28 -04:00
parent 8caf1403be
commit ed357af980
8 changed files with 221 additions and 102 deletions

View File

@ -698,6 +698,38 @@ fn make_free_glue(bcx: block, v: ValueRef, t: ty::t) {
build_return(bcx);
}
fn trans_class_drop(bcx: block, v0: ValueRef, dtor_did: ast::def_id,
class_did: ast::def_id,
substs: ty::substs) -> block {
let drop_flag = GEPi(bcx, v0, [0u, 0u]);
with_cond(bcx, IsNotNull(bcx, Load(bcx, drop_flag))) {|cx|
let mut bcx = cx;
// We have to cast v0
let classptr = GEPi(bcx, v0, [0u, 1u]);
// Find and call the actual destructor
let dtor_addr = get_res_dtor(bcx.ccx(), dtor_did, substs.tps);
// The second argument is the "self" argument for drop
let params = lib::llvm::fn_ty_param_tys
(llvm::LLVMGetElementType
(llvm::LLVMTypeOf(dtor_addr)));
// Class dtors have no explicit args, so the params should just consist
// of the output pointer and the environment (self)
assert(params.len() == 2u);
let self_arg = PointerCast(bcx, v0, params[1u]);
let args = [bcx.fcx.llretptr, self_arg];
Call(bcx, dtor_addr, args);
// Drop the fields
for vec::eachi(ty::class_items_as_fields(bcx.tcx(), class_did, substs))
{|i, fld|
let llfld_a = GEPi(bcx, classptr, [0u, i]);
bcx = drop_ty(bcx, llfld_a, fld.mt.ty);
}
Store(bcx, C_u8(0u), drop_flag);
bcx
}
}
fn make_drop_glue(bcx: block, v0: ValueRef, t: ty::t) {
// NB: v0 is an *alias* of type t here, not a direct value.
let _icx = bcx.insn_ctxt("make_drop_glue");
@ -718,37 +750,7 @@ fn make_drop_glue(bcx: block, v0: ValueRef, t: ty::t) {
let tcx = bcx.tcx();
alt ty::ty_dtor(tcx, did) {
some(dtor) {
let drop_flag = GEPi(bcx, v0, [0u, 0u]);
with_cond(bcx, IsNotNull(bcx, Load(bcx, drop_flag))) {|cx|
let mut bcx = cx;
// we have to cast v0
let classptr = GEPi(bcx, v0, [0u, 1u]);
// Find and call the actual destructor
let dtor_addr = get_res_dtor(bcx.ccx(), dtor, substs.tps);
// The second argument is the "self" argument for drop
let params = lib::llvm::fn_ty_param_tys
(llvm::LLVMGetElementType
(llvm::LLVMTypeOf(dtor_addr)));
let self_arg = PointerCast(bcx, v0, params[1u]);
let args = [bcx.fcx.llretptr, self_arg];
let val_llty = lib::llvm::fn_ty_param_tys
(llvm::LLVMGetElementType
(llvm::LLVMTypeOf(dtor_addr)))[args.len()];
let val_cast = BitCast(bcx, classptr, val_llty);
#debug("fn_ty: %s", ty_str(bcx.ccx().tn,
(llvm::LLVMGetElementType
(llvm::LLVMTypeOf(dtor_addr)))));
#debug("self's ty: %s", val_str(bcx.ccx().tn, v0));
Call(bcx, dtor_addr, args + [val_cast]);
// Drop the fields
for vec::eachi(ty::class_items_as_fields(tcx, did, substs))
{|i, fld|
let llfld_a = GEPi(bcx, classptr, [0u, i]);
bcx = drop_ty(bcx, llfld_a, fld.mt.ty);
}
Store(bcx, C_u8(0u), drop_flag);
bcx
}
trans_class_drop(bcx, v0, dtor, did, substs)
}
none {
// No dtor? Just the default case
@ -2063,8 +2065,21 @@ fn monomorphic_fn(ccx: @crate_ctxt, fn_id: ast::def_id, real_substs: [ty::t],
ret {val: get_item_val(ccx, fn_id.node),
must_cast: true};
}
ast_map::node_ctor(nm, _, _, pt) { (pt, nm, ast_util::dummy_sp()) }
_ { fail "unexpected node type"; }
ast_map::node_ctor(nm, _, ct, pt) { (pt, nm, alt ct {
ast_map::res_ctor(_, _, sp) { sp }
ast_map::class_ctor(ct_, _) { ct_.span }}) }
ast_map::node_dtor(_, dtor, _, pt) {(pt, "drop", dtor.span)}
ast_map::node_expr(*) { ccx.tcx.sess.bug("Can't monomorphize an expr") }
ast_map::node_export(*) {
ccx.tcx.sess.bug("Can't monomorphize an export")
}
ast_map::node_arg(*) { ccx.tcx.sess.bug("Can't monomorphize an arg") }
ast_map::node_block(*) {
ccx.tcx.sess.bug("Can't monomorphize a block")
}
ast_map::node_local(*) {
ccx.tcx.sess.bug("Can't monomorphize a local")
}
};
let mono_ty = ty::subst_tps(ccx.tcx, substs, item_ty);
let llfty = type_of_fn_from_ty(ccx, mono_ty);
@ -2081,55 +2096,97 @@ fn monomorphic_fn(ccx: @crate_ctxt, fn_id: ast::def_id, real_substs: [ty::t],
let pt = *pt + [path_name(ccx.names(name))];
let s = mangle_exported_name(ccx, pt, mono_ty);
let lldecl = decl_internal_cdecl_fn(ccx.llmod, s, llfty);
ccx.monomorphized.insert(hash_id, lldecl);
let mk_lldecl = {||
let lldecl = decl_internal_cdecl_fn(ccx.llmod, s, llfty);
ccx.monomorphized.insert(hash_id, lldecl);
lldecl
};
let psubsts = some({tys: substs, vtables: vtables, bounds: tpt.bounds});
alt check map_node {
let lldecl = alt map_node {
ast_map::node_item(i@@{node: ast::item_fn(decl, _, body), _}, _) {
set_inline_hint_if_appr(i.attrs, lldecl);
trans_fn(ccx, pt, decl, body, lldecl, no_self, psubsts, fn_id.node);
let d = mk_lldecl();
set_inline_hint_if_appr(i.attrs, d);
trans_fn(ccx, pt, decl, body, d, no_self, psubsts, fn_id.node);
d
}
ast_map::node_item(
@{node: ast::item_res(d, _, body, d_id, _, _), _}, _) {
trans_fn(ccx, pt, d, body, lldecl, no_self, psubsts, d_id);
@{node: ast::item_res(dt, _, body, d_id, _, _), _}, _) {
let d = mk_lldecl();
trans_fn(ccx, pt, dt, body, d, no_self, psubsts, d_id);
d
}
ast_map::node_item(*) {
ccx.tcx.sess.bug("Can't monomorphize this kind of item")
}
ast_map::node_native_item(i, _, _) {
native::trans_intrinsic(ccx, lldecl, i, pt, option::get(psubsts),
let d = mk_lldecl();
native::trans_intrinsic(ccx, d, i, pt, option::get(psubsts),
ref_id);
d
}
ast_map::node_variant(v, enum_item, _) {
let tvs = ty::enum_variants(ccx.tcx, local_def(enum_item.id));
let this_tv = option::get(vec::find(*tvs, {|tv|
tv.id.node == fn_id.node}));
set_inline_hint(lldecl);
let d = mk_lldecl();
set_inline_hint(d);
trans_enum_variant(ccx, enum_item.id, v, this_tv.disr_val,
(*tvs).len() == 1u, psubsts, lldecl);
(*tvs).len() == 1u, psubsts, d);
d
}
ast_map::node_method(mth, impl_def_id, _) {
set_inline_hint_if_appr(mth.attrs, lldecl);
let d = mk_lldecl();
set_inline_hint_if_appr(mth.attrs, d);
let selfty = ty::node_id_to_type(ccx.tcx, mth.self_id);
let selfty = ty::subst_tps(ccx.tcx, substs, selfty);
trans_fn(ccx, pt, mth.decl, mth.body, lldecl,
trans_fn(ccx, pt, mth.decl, mth.body, d,
impl_self(selfty), psubsts, fn_id.node);
d
}
ast_map::node_ctor(nm, tps, ct, _) {
let d = mk_lldecl();
alt ct {
ast_map::res_ctor(decl,_, _) {
set_inline_hint(lldecl);
trans_res_ctor(ccx, pt, decl, fn_id.node, psubsts, lldecl);
set_inline_hint(d);
trans_res_ctor(ccx, pt, decl, fn_id.node, psubsts, d);
d
}
ast_map::class_ctor(ctor, parent_id) {
// ctors don't have attrs, at least not right now
let tp_tys: [ty::t] = ty::ty_params_to_tys(ccx.tcx, tps);
trans_class_ctor(ccx, pt, ctor.node.dec, ctor.node.body, lldecl,
trans_class_ctor(ccx, pt, ctor.node.dec, ctor.node.body, d,
option::get_default(psubsts,
{tys:tp_tys, vtables: none, bounds: @[]}),
fn_id.node, parent_id, ctor.span);
d
}
}
}
}
ast_map::node_dtor(_, dtor, _, pt) {
let parent_id = alt ty::ty_to_def_id(ty::node_id_to_type(ccx.tcx,
dtor.node.self_id)) {
some(did) { did }
none { ccx.sess.span_bug(dtor.span, "Bad self ty in \
dtor"); }
};
trans_class_dtor(ccx, *pt, dtor.node.body,
dtor.node.id, psubsts, some(hash_id), parent_id, s)
}
// Ugh -- but this ensures any new variants won't be forgotten
ast_map::node_expr(*) { ccx.tcx.sess.bug("Can't monomorphize an expr") }
ast_map::node_export(*) {
ccx.tcx.sess.bug("Can't monomorphize an export")
}
ast_map::node_arg(*) { ccx.tcx.sess.bug("Can't monomorphize an arg") }
ast_map::node_block(*) {
ccx.tcx.sess.bug("Can't monomorphize a block")
}
ast_map::node_local(*) {
ccx.tcx.sess.bug("Can't monomorphize a local")
}
};
ccx.monomorphizing.insert(fn_id, depth);
{val: lldecl, must_cast: must_cast}
}
@ -2283,8 +2340,7 @@ fn lookup_discriminant(ccx: @crate_ctxt, vid: ast::def_id) -> ValueRef {
}
fn cast_self(cx: block, slf: val_self_pair) -> ValueRef {
let rslt = PointerCast(cx, slf.v, T_ptr(type_of(cx.ccx(), slf.t)));
rslt
PointerCast(cx, slf.v, T_ptr(type_of(cx.ccx(), slf.t)))
}
fn trans_local_var(cx: block, def: ast::def) -> local_var_result {
@ -2310,14 +2366,25 @@ fn trans_local_var(cx: block, def: ast::def) -> local_var_result {
assert (cx.fcx.lllocals.contains_key(nid));
ret take_local(cx.fcx.lllocals, nid);
}
ast::def_self(_) {
ast::def_self(sid) {
let slf = alt copy cx.fcx.llself {
some(s) { s }
none { cx.sess().bug("trans_local_var: reference to self \
some(s) {
alt option::map(ty::ty_to_def_id(s.t)) {|did|
ty::ty_dtor(cx.tcx(), did)} {
some(some(_)) {
/* self is a class with a dtor, which means we
have to select out the object itself
(If any other code does the same thing, that's
a bug */
GEPi(cx, cast_self(cx, s), [0u, 1u])
}
_ { cast_self(cx, s) }
}
}
none { cx.sess().bug("trans_local_var: reference to self \
out of context"); }
};
let ptr = cast_self(cx, slf);
ret {val: ptr, kind: owned};
ret {val: slf, kind: owned};
}
_ {
cx.sess().unimpl(#fmt("unsupported def type in trans_local_def: %?",
@ -2388,13 +2455,9 @@ fn trans_rec_field(bcx: block, base: @ast::expr,
fn trans_rec_field_inner(bcx: block, val: ValueRef, ty: ty::t,
field: ast::ident, sp: span) -> lval_result {
let mut is_class_with_dtor = false;
let fields = alt ty::get(ty).struct {
ty::ty_rec(fs) { fs }
ty::ty_class(did, substs) {
if option::is_some(ty::ty_dtor(bcx.tcx(), did)) {
is_class_with_dtor = true;
}
ty::class_items_as_fields(bcx.tcx(), did, substs)
}
// Constraint?
@ -2402,10 +2465,8 @@ fn trans_rec_field_inner(bcx: block, val: ValueRef, ty: ty::t,
base expr has non-record type"); }
};
let ix = field_idx_strict(bcx.tcx(), sp, field, fields);
let val = GEPi(bcx, if is_class_with_dtor {
GEPi(bcx, val, [0u, 1u])
}
else { val }, [0u, ix]);
let val = GEPi(bcx, val, [0u, ix]);
ret {bcx: bcx, val: val, kind: owned};
}
@ -4726,12 +4787,39 @@ fn trans_class_ctor(ccx: @crate_ctxt, path: path, decl: ast::fn_decl,
}
fn trans_class_dtor(ccx: @crate_ctxt, path: path,
body: ast::blk, lldtor_decl: ValueRef,
dtor_id: ast::node_id,
parent_id: ast::def_id) {
let class_ty = ty::lookup_item_type(ccx.tcx, parent_id).ty;
body: ast::blk,
dtor_id: ast::node_id, substs: option<param_substs>,
hash_id: option<mono_id>, parent_id: ast::def_id,
// mangled exported name for dtor
s: str) -> ValueRef {
let tcx = ccx.tcx;
/* Look up the parent class's def_id */
let mut class_ty = ty::lookup_item_type(tcx, parent_id).ty;
/* Substitute in the class type if necessary */
option::iter(substs) {|ss|
class_ty = ty::subst_tps(tcx, ss.tys, class_ty);
}
/* The dtor takes a (null) output pointer, and a self argument,
and returns () */
let lldty = T_fn([T_ptr(type_of(ccx, ty::mk_nil(tcx))),
T_ptr(type_of(ccx, class_ty))],
llvm::LLVMVoidType());
/* Register the dtor as a function. It has external linkage */
let lldecl = decl_internal_cdecl_fn(ccx.llmod, s, lldty);
lib::llvm::SetLinkage(lldecl, lib::llvm::ExternalLinkage);
/* If we're monomorphizing, register the monomorphized decl
for the dtor */
option::iter(hash_id) {|h_id|
ccx.monomorphized.insert(h_id, lldecl);
}
/* Register the symbol for the dtor, and generate the code for its
body */
ccx.item_symbols.insert(dtor_id, s);
trans_fn(ccx, path, ast_util::dtor_dec(),
body, lldtor_decl, impl_self(class_ty), none, dtor_id);
body, lldecl, impl_self(class_ty), substs, dtor_id);
lldecl
}
fn trans_item(ccx: @crate_ctxt, item: ast::item) {
@ -4811,9 +4899,11 @@ fn trans_item(ccx: @crate_ctxt, item: ast::item) {
get_item_val(ccx, ctor.node.id), psubsts,
ctor.node.id, local_def(item.id), ctor.span);
option::iter(m_dtor) {|dtor|
trans_class_dtor(ccx, *path, dtor.node.body,
get_item_val(ccx, dtor.node.id),
dtor.node.id, local_def(item.id));
let s = mangle_exported_name(ccx, *path +
[path_name(ccx.names("dtor"))],
ty::node_id_to_type(ccx.tcx, dtor.node.id));
trans_class_dtor(ccx, *path, dtor.node.body,
dtor.node.id, none, none, local_def(item.id), s);
};
}
// If there are ty params, the ctor will get monomorphized
@ -4976,6 +5066,7 @@ fn item_path(ccx: @crate_ctxt, i: @ast::item) -> path {
fn get_item_val(ccx: @crate_ctxt, id: ast::node_id) -> ValueRef {
#debug("get_item_val: %d", id);
let tcx = ccx.tcx;
alt ccx.item_vals.find(id) {
some(v) { v }
none {
@ -5041,9 +5132,27 @@ fn get_item_val(ccx: @crate_ctxt, id: ast::node_id) -> ValueRef {
}
}
ast_map::node_dtor(tps, dt, parent_id, pt) {
let my_path = *pt + [path_name("dtor")];
let t = ty::node_id_to_type(ccx.tcx, dt.node.id);
register_fn_full(ccx, dt.span, my_path, dt.node.id, t)
/*
Don't just call register_fn, since we don't want to add
the implicit self argument automatically (we want to make sure
it has the right type)
*/
// Want parent_id and not id, because id is the dtor's type
let class_ty = ty::lookup_item_type(tcx, parent_id).ty;
// This code shouldn't be reached if the class is generic
assert !ty::type_has_params(class_ty);
let lldty = T_fn([T_ptr(type_of(ccx, ty::mk_nil(tcx))),
T_ptr(type_of(ccx, class_ty))],
llvm::LLVMVoidType());
/* The symbol for the dtor should have already been registered */
let s: str = alt ccx.item_symbols.find(id) {
some(s) { s }
none { ccx.sess.bug("in get_item_val, dtor is unbound"); }
};
/* Make the declaration for the dtor */
let llfn = decl_internal_cdecl_fn(ccx.llmod, s, lldty);
lib::llvm::SetLinkage(llfn, lib::llvm::ExternalLinkage);
llfn
}
ast_map::node_variant(v, enm, pth) {

View File

@ -423,6 +423,12 @@ impl bcx_cxs for block {
fn tcx() -> ty::ctxt { self.fcx.ccx.tcx }
fn sess() -> session { self.fcx.ccx.sess }
fn val_str(val: ValueRef) -> str {
val_str(self.ccx().tn, val)
}
fn ty_to_str(t: ty::t) -> str {
ty_to_str(self.tcx(), t)
}
fn to_str() -> str {
alt self.node_info {
some(node_info) {

View File

@ -6,6 +6,7 @@ import build::*;
import driver::session::session;
import syntax::{ast, ast_map};
import ast_map::{path, path_mod, path_name, node_id_to_str};
import driver::session::expect;
import syntax::ast_util::{local_def, split_class_items};
import metadata::csearch;
import back::{link, abi};
@ -247,7 +248,10 @@ fn make_impl_vtable(ccx: @crate_ctxt, impl_id: ast::def_id, substs: [ty::t],
vtables: typeck::vtable_res) -> ValueRef {
let _icx = ccx.insn_ctxt("impl::make_impl_vtable");
let tcx = ccx.tcx;
let ifce_id = ty::ty_to_def_id(option::get(ty::impl_iface(tcx, impl_id)));
let ifce_id = expect(ccx.sess,
ty::ty_to_def_id(option::get(ty::impl_iface(tcx,
impl_id))),
{|| "make_impl_vtable: non-iface-type implemented"});
let has_tps = (*ty::lookup_item_type(ccx.tcx, impl_id).bounds).len() > 0u;
make_vtable(ccx, vec::map(*ty::iface_methods(tcx, ifce_id)) {|im|
let fty = ty::subst_tps(tcx, substs, ty::mk_fn(tcx, im.fty));

View File

@ -90,6 +90,10 @@ fn type_uses_for(ccx: @crate_ctxt, fn_id: def_id, n_tps: uint)
ast_map::node_ctor(_, _, ast_map::class_ctor(ctor, _), _){
handle_body(cx, ctor.node.body);
}
ast_map::node_dtor(_, dtor, _, _){
handle_body(cx, dtor.node.body);
}
}
let uses = vec::from_mut(cx.uses);
ccx.type_use_cache.insert(fn_id, uses);

View File

@ -2375,11 +2375,12 @@ fn impl_iface(cx: ctxt, id: ast::def_id) -> option<t> {
}
}
fn ty_to_def_id(ty: t) -> ast::def_id {
alt check get(ty).struct {
fn ty_to_def_id(ty: t) -> option<ast::def_id> {
alt get(ty).struct {
ty_iface(id, _) | ty_class(id, _) | ty_res(id, _, _) | ty_enum(id, _) {
id
some(id)
}
_ { none }
}
}
@ -2413,7 +2414,7 @@ fn ty_dtor(cx: ctxt, class_id: def_id) -> option<def_id> {
some(ast_map::node_item(@{node: ast::item_class(_, _, _, _,
some(dtor), _), _}, _))
{ some(local_def(dtor.node.id)) }
_ { none }
_ { none }
}
}
else {

View File

@ -1,13 +0,0 @@
class shrinky_pointer {
let i: @@mut int;
fn look_at() -> int { ret **(self.i); }
new(i: @@mut int) { self.i = i; }
drop { log(error, "Hello!"); **(self.i) -= 1; }
}
fn main() {
let my_total = @@mut 10;
{ let pt <- shrinky_pointer(my_total); assert (pt.look_at() == 10); }
log(error, #fmt("my_total = %d", **my_total));
assert (**my_total == 9);
}

View File

@ -1,9 +1,13 @@
resource shrinky_pointer(i: @mut int) { *i -= 1; }
fn look_at(pt: shrinky_pointer) -> int { ret **pt; }
class shrinky_pointer {
let i: @@mut int;
fn look_at() -> int { ret **(self.i); }
new(i: @@mut int) { self.i = i; }
drop { log(error, "Hello!"); **(self.i) -= 1; }
}
fn main() {
let my_total = @mut 10;
{ let pt <- shrinky_pointer(my_total); assert (look_at(pt) == 10); }
assert (*my_total == 9);
let my_total = @@mut 10;
{ let pt <- shrinky_pointer(my_total); assert (pt.look_at() == 10); }
log(error, #fmt("my_total = %d", **my_total));
assert (**my_total == 9);
}

View File

@ -1,11 +1,15 @@
resource finish<T>(arg: {val: T, fin: native fn(T)}) {
arg.fin(arg.val);
class finish<T: copy> {
let arg: {val: T, fin: native fn(T)};
new(arg: {val: T, fin: native fn(T)}) {
self.arg = arg;
}
drop { self.arg.fin(self.arg.val); }
}
fn main() {
let box = @mut 10;
fn dec_box(&&i: @mut int) { *i -= 1; }
{ let i <- finish({val: box, fin: dec_box}); }
{ let _i <- finish({val: box, fin: dec_box}); }
assert (*box == 9);
}