rust/src/rustc/metadata/reachable.rs
Patrick Walton c9375fed8d stdlib: Stop incurring vtable dispatch costs when hashmaps are used
This required changing almost all users of hashmaps to import the hashmap interface first.

The `size` member in the hashmap structure was renamed to `count` to work around a name conflict.
2012-03-07 17:35:13 -08:00

127 lines
3.9 KiB
Rust

// Finds items that are externally reachable, to determine which items
// need to have their metadata (and possibly their AST) serialized.
// All items that can be referred to through an exported name are
// reachable, and when a reachable thing is inline or generic, it
// makes all other generics or inline functions that it references
// reachable as well.
import middle::{resolve, ast_map, typeck};
import syntax::ast::*;
import syntax::visit;
import syntax::ast_util::def_id_of_def;
import front::attr;
import std::map::hashmap;
export map, find_reachable;
type map = std::map::hashmap<node_id, ()>;
type ctx = {ccx: middle::trans::common::crate_ctxt,
rmap: map};
fn find_reachable(ccx: middle::trans::common::crate_ctxt, crate_mod: _mod)
-> map {
let rmap = std::map::new_int_hash();
traverse_public_mod({ccx: ccx, rmap: rmap}, crate_mod);
rmap
}
fn traverse_exports(cx: ctx, vis: [@view_item]) -> bool {
let found_export = false;
for vi in vis {
alt vi.node {
view_item_export(vps) {
found_export = true;
for vp in vps {
alt vp.node {
view_path_simple(_, _, id) | view_path_glob(_, id) |
view_path_list(_, _, id) {
traverse_export(cx, id);
}
}
}
}
_ {}
}
}
found_export
}
fn traverse_export(cx: ctx, exp_id: node_id) {
option::may(cx.ccx.exp_map.find(exp_id)) {|defs|
for def in defs { traverse_def_id(cx, def.id); }
}
}
fn traverse_def_id(cx: ctx, did: def_id) {
if did.crate != local_crate { ret; }
alt cx.ccx.tcx.items.get(did.node) {
ast_map::node_item(item, _) { traverse_public_item(cx, item); }
ast_map::node_method(_, impl_id, _) { traverse_def_id(cx, impl_id); }
ast_map::node_native_item(item, _) { cx.rmap.insert(item.id, ()); }
ast_map::node_variant(v, _, _) { cx.rmap.insert(v.node.id, ()); }
_ {}
}
}
fn traverse_public_mod(cx: ctx, m: _mod) {
if !traverse_exports(cx, m.view_items) {
// No exports, so every local item is exported
for item in m.items { traverse_public_item(cx, item); }
}
}
fn traverse_public_item(cx: ctx, item: @item) {
if cx.rmap.contains_key(item.id) { ret; }
cx.rmap.insert(item.id, ());
alt item.node {
item_mod(m) { traverse_public_mod(cx, m); }
item_native_mod(nm) {
if !traverse_exports(cx, nm.view_items) {
for item in nm.items { cx.rmap.insert(item.id, ()); }
}
}
item_res(_, tps, blk, _, _) | item_fn(_, tps, blk) {
if tps.len() > 0u ||
attr::find_inline_attr(item.attrs) != attr::ia_none {
traverse_inline_body(cx, blk);
}
}
item_impl(tps, _, _, ms) {
for m in ms {
if tps.len() > 0u || m.tps.len() > 0u ||
attr::find_inline_attr(m.attrs) != attr::ia_none {
traverse_inline_body(cx, m.body);
}
}
}
item_class(_tps, _items, _) {} // FIXME handle these when stable
item_const(_, _) | item_ty(_, _) | item_enum(_, _) | item_iface(_, _) {}
}
}
fn traverse_inline_body(cx: ctx, body: blk) {
fn traverse_expr(e: @expr, cx: ctx, v: visit::vt<ctx>) {
alt e.node {
expr_path(_) {
traverse_def_id(cx, def_id_of_def(cx.ccx.tcx.def_map.get(e.id)));
}
expr_field(_, _, _) {
alt cx.ccx.maps.method_map.find(e.id) {
some(typeck::method_static(did)) { traverse_def_id(cx, did); }
_ {}
}
}
_ {}
}
visit::visit_expr(e, cx, v);
}
// Ignore nested items
fn traverse_item(_i: @item, _cx: ctx, _v: visit::vt<ctx>) {}
visit::visit_block(body, cx, visit::mk_vt(@{
visit_expr: traverse_expr,
visit_item: traverse_item
with *visit::default_visitor()
}));
}