rustc: Don't generate landing pad cleanups for boxy things

This commit is contained in:
Brian Anderson 2012-03-23 17:52:20 -07:00
parent 3a7a408386
commit b420f46f03
4 changed files with 90 additions and 11 deletions

@ -1 +1 @@
Subproject commit 1d6aec9d54c7a684ade521f71a4d538a6a88b14f
Subproject commit 1170ffba3ac5191930b40c897d4569a9d8a296a3

View File

@ -3640,7 +3640,11 @@ fn raw_block(fcx: fn_ctxt, llbb: BasicBlockRef) -> block {
// need to make sure those variables go out of scope when the block ends. We
// do that by running a 'cleanup' function for each variable.
// trans_block_cleanups runs all the cleanup functions for the block.
fn trans_block_cleanups(bcx: block, cleanup_cx: block) ->
fn trans_block_cleanups(bcx: block, cleanup_cx: block) -> block {
trans_block_cleanups_(bcx, cleanup_cx, false)
}
fn trans_block_cleanups_(bcx: block, cleanup_cx: block, is_lpad: bool) ->
block {
let _icx = bcx.insn_ctxt("trans_block_cleanups");
if bcx.unreachable { ret bcx; }
@ -3648,7 +3652,15 @@ fn trans_block_cleanups(bcx: block, cleanup_cx: block) ->
alt check cleanup_cx.kind {
block_scope({cleanups, _}) {
vec::riter(copy cleanups) {|cu|
alt cu { clean(cfn) | clean_temp(_, cfn) { bcx = cfn(bcx); } }
alt cu {
clean(cfn, cleanup_type) | clean_temp(_, cfn, cleanup_type) {
// Some types don't need to be cleaned up during
// landing pads because they can be freed en mass later
if cleanup_type == normal_exit_and_unwind || !is_lpad {
bcx = cfn(bcx);
}
}
}
}
}
}
@ -3662,6 +3674,7 @@ fn cleanup_and_leave(bcx: block, upto: option<BasicBlockRef>,
leave: option<BasicBlockRef>) {
let _icx = bcx.insn_ctxt("cleanup_and_leave");
let mut cur = bcx, bcx = bcx;
let is_lpad = leave == none;
loop {
alt cur.kind {
block_scope(info) if info.cleanups.len() > 0u {
@ -3674,7 +3687,7 @@ fn cleanup_and_leave(bcx: block, upto: option<BasicBlockRef>,
let sub_cx = sub_block(bcx, "cleanup");
Br(bcx, sub_cx.llbb);
info.cleanup_paths += [{target: leave, dest: sub_cx.llbb}];
bcx = trans_block_cleanups(sub_cx, cur);
bcx = trans_block_cleanups_(sub_cx, cur, is_lpad);
}
_ {}
}

View File

@ -201,9 +201,14 @@ fn warn_not_to_commit(ccx: @crate_ctxt, msg: str) {
}
}
enum cleantype {
normal_exit_only,
normal_exit_and_unwind
}
enum cleanup {
clean(fn@(block) -> block),
clean_temp(ValueRef, fn@(block) -> block),
clean(fn@(block) -> block, cleantype),
clean_temp(ValueRef, fn@(block) -> block, cleantype),
}
// Used to remember and reuse existing cleanup paths
@ -216,15 +221,26 @@ fn scope_clean_changed(info: scope_info) {
info.landing_pad = none;
}
fn cleanup_type(cx: ty::ctxt, ty: ty::t) -> cleantype {
if ty::type_needs_unwind_cleanup(cx, ty) {
normal_exit_and_unwind
} else {
normal_exit_only
}
}
fn add_clean(cx: block, val: ValueRef, ty: ty::t) {
if !ty::type_needs_drop(cx.tcx(), ty) { ret; }
let cleanup_type = cleanup_type(cx.tcx(), ty);
in_scope_cx(cx) {|info|
info.cleanups += [clean(bind base::drop_ty(_, val, ty))];
info.cleanups += [clean(bind base::drop_ty(_, val, ty),
cleanup_type)];
scope_clean_changed(info);
}
}
fn add_clean_temp(cx: block, val: ValueRef, ty: ty::t) {
if !ty::type_needs_drop(cx.tcx(), ty) { ret; }
let cleanup_type = cleanup_type(cx.tcx(), ty);
fn do_drop(bcx: block, val: ValueRef, ty: ty::t) ->
block {
if ty::type_is_immediate(ty) {
@ -234,14 +250,17 @@ fn add_clean_temp(cx: block, val: ValueRef, ty: ty::t) {
}
}
in_scope_cx(cx) {|info|
info.cleanups += [clean_temp(val, bind do_drop(_, val, ty))];
info.cleanups += [clean_temp(val, bind do_drop(_, val, ty),
cleanup_type)];
scope_clean_changed(info);
}
}
fn add_clean_temp_mem(cx: block, val: ValueRef, ty: ty::t) {
if !ty::type_needs_drop(cx.tcx(), ty) { ret; }
let cleanup_type = cleanup_type(cx.tcx(), ty);
in_scope_cx(cx) {|info|
info.cleanups += [clean_temp(val, bind base::drop_ty(_, val, ty))];
info.cleanups += [clean_temp(val, bind base::drop_ty(_, val, ty),
cleanup_type)];
scope_clean_changed(info);
}
}
@ -249,7 +268,8 @@ fn add_clean_free(cx: block, ptr: ValueRef, shared: bool) {
let free_fn = if shared { bind base::trans_shared_free(_, ptr) }
else { bind base::trans_free(_, ptr) };
in_scope_cx(cx) {|info|
info.cleanups += [clean_temp(ptr, free_fn)];
info.cleanups += [clean_temp(ptr, free_fn,
normal_exit_and_unwind)];
scope_clean_changed(info);
}
}
@ -263,7 +283,7 @@ fn revoke_clean(cx: block, val: ValueRef) {
let mut i = 0u;
for cu in info.cleanups {
alt cu {
clean_temp(v, _) if v == val {
clean_temp(v, _, _) if v == val {
info.cleanups =
vec::slice(info.cleanups, 0u, i) +
vec::slice(info.cleanups, i + 1u, info.cleanups.len());

View File

@ -121,6 +121,7 @@ export type_structurally_contains;
export type_structurally_contains_uniques;
export type_autoderef;
export type_param;
export type_needs_unwind_cleanup;
export canon_mode;
export resolved_mode;
export arg_mode;
@ -201,6 +202,7 @@ type ctxt =
rcache: creader_cache,
short_names_cache: hashmap<t, @str>,
needs_drop_cache: hashmap<t, bool>,
needs_unwind_cleanup_cache: hashmap<t, bool>,
kind_cache: hashmap<t, kind>,
ast_ty_to_ty_cache: hashmap<@ast::ty, ast_ty_to_ty_cache_entry>,
enum_var_cache: hashmap<def_id, @[variant_info]>,
@ -388,6 +390,7 @@ fn mk_ctxt(s: session::session, dm: resolve::def_map, amap: ast_map::map,
rcache: mk_rcache(),
short_names_cache: new_ty_hash(),
needs_drop_cache: new_ty_hash(),
needs_unwind_cleanup_cache: new_ty_hash(),
kind_cache: new_ty_hash(),
ast_ty_to_ty_cache: map::hashmap(
ast_util::hash_ty, ast_util::eq_ty),
@ -902,6 +905,48 @@ fn type_needs_drop(cx: ctxt, ty: t) -> bool {
ret result;
}
// Some things don't need cleanups during unwinding because the
// task can free them all at once later. Currently only things
// that only contain scalars and shared boxes can avoid unwind
// cleanups.
fn type_needs_unwind_cleanup(cx: ctxt, ty: t) -> bool {
alt cx.needs_unwind_cleanup_cache.find(ty) {
some(result) { ret result; }
none { }
}
// Prevent infinite recursion
cx.needs_unwind_cleanup_cache.insert(ty, false);
let mut needs_unwind_cleanup = false;
maybe_walk_ty(ty) {|ty|
alt get(ty).struct {
ty_nil | ty_bot | ty_bool |
ty_int(_) | ty_uint(_) | ty_float(_) |
ty_box(_) | ty_rec(_) | ty_tup(_) {
true
}
ty_enum(did, tps) {
for v in *enum_variants(cx, did) {
for aty in v.args {
let t = substitute_type_params(cx, tps, aty);
needs_unwind_cleanup |= type_needs_unwind_cleanup(cx, t);
}
}
!needs_unwind_cleanup
}
_ {
needs_unwind_cleanup = true;
false
}
}
}
cx.needs_unwind_cleanup_cache.insert(ty, needs_unwind_cleanup);
ret needs_unwind_cleanup;
}
enum kind { kind_sendable, kind_copyable, kind_noncopyable, }
// Using these query functons is preferable to direct comparison or matching
@ -2323,6 +2368,7 @@ fn ast_constr_to_constr<T>(tcx: ctxt, c: @ast::constr_general<T>) ->
}
}
// Local Variables:
// mode: rust
// fill-column: 78;