Rewrite each_path to allow performance improvements in the future.

Instead of determining paths from the path tag, we iterate through
modules' children recursively in the metadata. This will allow for
lazy external module resolution.
This commit is contained in:
Patrick Walton 2013-06-18 09:39:16 -07:00 committed by Corey Richardson
parent 89eb995195
commit e015bee286
17 changed files with 578 additions and 364 deletions

View File

@ -381,7 +381,7 @@ impl Sem<~[Waitqueue]> {
// The only other places that condvars get built are rwlock.write_cond()
// and rwlock_write_mode.
pub fn access_cond<U>(&self, blk: &fn(c: &Condvar) -> U) -> U {
do self.access {
do self.access_waitqueue {
blk(&Condvar { sem: self, order: Nothing })
}
}

View File

@ -176,6 +176,10 @@ pub static tag_item_method_tps: uint = 0x7b;
pub static tag_item_method_fty: uint = 0x7c;
pub static tag_item_method_transformed_self_ty: uint = 0x7d;
pub static tag_mod_child: uint = 0x7e;
pub static tag_misc_info: uint = 0x7f;
pub static tag_misc_info_crate_items: uint = 0x80;
pub struct LinkMeta {
name: @str,
vers: @str,

View File

@ -97,18 +97,14 @@ pub fn get_enum_variants(tcx: ty::ctxt, def: ast::def_id)
return decoder::get_enum_variants(cstore.intr, cdata, def.node, tcx)
}
pub fn get_impls_for_mod(cstore: @mut cstore::CStore, def: ast::def_id,
name: Option<ast::ident>)
-> @~[@resolve::Impl] {
let cdata = cstore::get_crate_data(cstore, def.crate);
do decoder::get_impls_for_mod(cstore.intr, cdata, def.node, name) |cnum| {
cstore::get_crate_data(cstore, cnum)
}
/// Returns information about the given implementation.
pub fn get_impl(cstore: @mut cstore::CStore, impl_def_id: ast::def_id)
-> resolve::Impl {
let cdata = cstore::get_crate_data(cstore, impl_def_id.crate);
decoder::get_impl(cstore.intr, cdata, impl_def_id.node)
}
pub fn get_method(tcx: ty::ctxt,
def: ast::def_id) -> ty::Method
{
pub fn get_method(tcx: ty::ctxt, def: ast::def_id) -> ty::Method {
let cdata = cstore::get_crate_data(tcx.cstore, def.crate);
decoder::get_method(tcx.cstore.intr, cdata, def.node, tcx)
}

View File

@ -458,64 +458,192 @@ pub fn each_lang_item(cdata: cmd, f: &fn(ast::node_id, uint) -> bool) -> bool {
return true;
}
/// Iterates over all the paths in the given crate.
pub fn each_path(intr: @ident_interner,
struct EachItemContext<'self> {
intr: @ident_interner,
cdata: cmd,
get_crate_data: GetCrateDataCb,
f: &fn(&str, def_like, ast::visibility) -> bool)
get_crate_data: GetCrateDataCb<'self>,
path_builder: &'self mut ~str,
callback: &'self fn(&str, def_like, ast::visibility) -> bool,
}
impl<'self> EachItemContext<'self> {
// Pushes the given name and returns the old length.
fn push_name(&mut self, string: &str) -> uint {
let path_len = self.path_builder.len();
if path_len != 0 {
self.path_builder.push_str("::")
}
self.path_builder.push_str(string);
path_len
}
// Pops the given name.
fn pop_name(&mut self, old_len: uint) {
// XXX(pcwalton): There's no safe function to do this. :(
unsafe {
str::raw::set_len(self.path_builder, old_len)
}
}
fn process_item_and_pop_name(&mut self,
doc: ebml::Doc,
def_id: ast::def_id,
old_len: uint)
-> bool {
// FIXME #4572: This function needs to be nuked, as it's impossible to make fast.
// It's the source of most of the performance problems when compiling small crates.
let root = reader::Doc(cdata.data);
let items = reader::get_doc(root, tag_items);
let items_data = reader::get_doc(items, tag_items_data);
// First, go through all the explicit items.
for reader::tagged_docs(items_data, tag_items_data_item) |item_doc| {
let path = ast_map::path_to_str(item_path(item_doc), intr);
let path_is_empty = path.is_empty();
if !path_is_empty {
// Extract the def ID.
let def_id = item_def_id(item_doc, cdata);
// Construct the def for this item.
debug!("(each_path) yielding explicit item: %s", path);
let def_like = item_to_def_like(item_doc, def_id, cdata.cnum);
let vis = item_visibility(item_doc);
// Hand the information off to the iteratee.
if !f(path, def_like, vis) {
return false;
let def_like = item_to_def_like(doc, def_id, self.cdata.cnum);
match def_like {
dl_def(def) => {
debug!("(iterating over each item of a module) processing \
`%s` (def %?)",
*self.path_builder,
def);
}
_ => {
debug!("(iterating over each item of a module) processing \
`%s` (%d:%d)",
*self.path_builder,
def_id.crate,
def_id.node);
}
}
// If this is a module, find the reexports.
let vis = item_visibility(doc);
let mut continue = (self.callback)(*self.path_builder, def_like, vis);
let family = item_family(doc);
if family == ForeignMod {
// These are unnamed; pop the name now.
self.pop_name(old_len)
}
if continue {
// Recurse if necessary.
match family {
Mod | ForeignMod | Trait | Impl => {
continue = self.each_item_of_module(def_id);
}
Freeze | Struct | UnsafeFn | Fn | PureFn | ForeignFn |
UnsafeStaticMethod | StaticMethod | PureStaticMethod | Type |
ForeignType | Variant | Enum | PublicField | PrivateField |
InheritedField => {}
}
}
if family != ForeignMod {
self.pop_name(old_len)
}
continue
}
fn each_item_of_module(&mut self, def_id: ast::def_id) -> bool {
// This item might not be in this crate. If it's not, look it up.
let (cdata, items) = if def_id.crate == self.cdata.cnum {
let items = reader::get_doc(reader::Doc(self.cdata.data),
tag_items);
(self.cdata, items)
} else {
let crate_data = (self.get_crate_data)(def_id.crate);
let root = reader::Doc(crate_data.data);
(crate_data, reader::get_doc(root, tag_items))
};
// Look up the item.
let item_doc = match maybe_find_item(def_id.node, items) {
None => return false,
Some(item_doc) => item_doc,
};
self.each_child_of_module_or_crate(item_doc)
}
fn each_child_of_module_or_crate(&mut self, item_doc: ebml::Doc) -> bool {
let mut continue = true;
// Iterate over all children.
for reader::tagged_docs(item_doc, tag_mod_child) |child_info_doc| {
let child_def_id = reader::with_doc_data(child_info_doc,
parse_def_id);
let child_def_id = translate_def_id(self.cdata, child_def_id);
// This item may be in yet another crate, if it was the child of
// a reexport.
let other_crates_items = if child_def_id.crate ==
self.cdata.cnum {
reader::get_doc(reader::Doc(self.cdata.data), tag_items)
} else {
let crate_data = (self.get_crate_data)(child_def_id.crate);
let root = reader::Doc(crate_data.data);
reader::get_doc(root, tag_items)
};
debug!("(iterating over each item of a module) looking up item \
%d:%d in `%s`, crate %d",
child_def_id.crate,
child_def_id.node,
*self.path_builder,
self.cdata.cnum);
// Get the item.
match maybe_find_item(child_def_id.node, other_crates_items) {
None => {}
Some(child_item_doc) => {
// Push the name.
let child_name = item_name(self.intr, child_item_doc);
debug!("(iterating over each item of a module) pushing \
name `%s` onto `%s`",
token::ident_to_str(&child_name),
*self.path_builder);
let old_len =
self.push_name(token::ident_to_str(&child_name));
// Process this item.
continue = self.process_item_and_pop_name(child_item_doc,
child_def_id,
old_len);
if !continue {
break
}
}
}
}
if !continue {
return false
}
// Iterate over reexports.
for each_reexport(item_doc) |reexport_doc| {
let def_id_doc =
reader::get_doc(reexport_doc,
let def_id_doc = reader::get_doc(
reexport_doc,
tag_items_data_item_reexport_def_id);
let def_id = reader::with_doc_data(def_id_doc, parse_def_id);
let def_id = translate_def_id(cdata, def_id);
let orig_def_id = reader::with_doc_data(def_id_doc, parse_def_id);
let reexport_name_doc =
reader::get_doc(reexport_doc,
// NB: was "cdata"
let def_id = translate_def_id(self.cdata, orig_def_id);
let name_doc = reader::get_doc(reexport_doc,
tag_items_data_item_reexport_name);
let reexport_name = reexport_name_doc.as_str_slice();
let name = name_doc.as_str_slice();
let reexport_path;
if path_is_empty {
reexport_path = reexport_name.to_owned();
} else {
reexport_path = path + "::" + reexport_name;
}
// Push the name.
debug!("(iterating over each item of a module) pushing \
reexported name `%s` onto `%s` (crate %d, orig %d, \
in crate %d)",
name,
*self.path_builder,
def_id.crate,
orig_def_id.crate,
self.cdata.cnum);
let old_len = self.push_name(name);
// This reexport may be in yet another crate
let other_crates_items = if def_id.crate == cdata.cnum {
items
// This reexport may be in yet another crate.
let other_crates_items = if def_id.crate == self.cdata.cnum {
reader::get_doc(reader::Doc(self.cdata.data), tag_items)
} else {
let crate_data = get_crate_data(def_id.crate);
let crate_data = (self.get_crate_data)(def_id.crate);
let root = reader::Doc(crate_data.data);
reader::get_doc(root, tag_items)
};
@ -523,29 +651,53 @@ pub fn each_path(intr: @ident_interner,
// Get the item.
match maybe_find_item(def_id.node, other_crates_items) {
None => {}
Some(item_doc) => {
// Construct the def for this item.
let def_like = item_to_def_like(item_doc,
Some(reexported_item_doc) => {
continue = self.process_item_and_pop_name(
reexported_item_doc,
def_id,
cdata.cnum);
// Hand the information off to the iteratee.
debug!("(each_path) yielding reexported \
item: %s", reexport_path);
if (!f(reexport_path, def_like, ast::public)) {
return false;
}
}
}
old_len);
}
}
return true;
if !continue {
break
}
}
pub fn get_item_path(cdata: cmd, id: ast::node_id)
-> ast_map::path {
continue
}
}
/// Iterates over all the paths in the given crate.
pub fn each_path(intr: @ident_interner,
cdata: cmd,
get_crate_data: GetCrateDataCb,
f: &fn(&str, def_like, ast::visibility) -> bool)
-> bool {
// FIXME #4572: This function needs to be nuked, as it's impossible to
// make fast. It's the source of most of the performance problems when
// compiling small crates.
let root_doc = reader::Doc(cdata.data);
let misc_info_doc = reader::get_doc(root_doc, tag_misc_info);
let crate_items_doc = reader::get_doc(misc_info_doc,
tag_misc_info_crate_items);
let mut path_builder = ~"";
let mut context = EachItemContext {
intr: intr,
cdata: cdata,
get_crate_data: get_crate_data,
path_builder: &mut path_builder,
callback: f,
};
// Iterate over all top-level crate items.
context.each_child_of_module_or_crate(crate_items_doc)
}
pub fn get_item_path(cdata: cmd, id: ast::node_id) -> ast_map::path {
item_path(lookup_item(id, cdata.data))
}
@ -661,35 +813,20 @@ fn item_impl_methods(intr: @ident_interner, cdata: cmd, item: ebml::Doc,
rslt
}
pub fn get_impls_for_mod(intr: @ident_interner,
cdata: cmd,
m_id: ast::node_id,
name: Option<ast::ident>,
get_cdata: &fn(ast::crate_num) -> cmd)
-> @~[@resolve::Impl] {
/// Returns information about the given implementation.
pub fn get_impl(intr: @ident_interner, cdata: cmd, impl_id: ast::node_id)
-> resolve::Impl {
let data = cdata.data;
let mod_item = lookup_item(m_id, data);
let mut result = ~[];
for reader::tagged_docs(mod_item, tag_mod_impl) |doc| {
let did = reader::with_doc_data(doc, parse_def_id);
let local_did = translate_def_id(cdata, did);
debug!("(get impls for mod) getting did %? for '%?'",
local_did, name);
// The impl may be defined in a different crate. Ask the caller
// to give us the metadata
let impl_cdata = get_cdata(local_did.crate);
let impl_data = impl_cdata.data;
let item = lookup_item(local_did.node, impl_data);
let nm = item_name(intr, item);
if match name { Some(n) => { n == nm } None => { true } } {
let base_tps = item_ty_param_count(item);
result.push(@resolve::Impl {
did: local_did, ident: nm,
methods: item_impl_methods(intr, impl_cdata, item, base_tps)
});
};
let impl_item = lookup_item(impl_id, data);
let base_tps = item_ty_param_count(impl_item);
resolve::Impl {
did: ast::def_id {
crate: cdata.cnum,
node: impl_id,
},
ident: item_name(intr, impl_item),
methods: item_impl_methods(intr, cdata, impl_item, base_tps),
}
@result
}
pub fn get_method_name_and_explicit_self(

View File

@ -22,7 +22,7 @@ use middle;
use util::ppaux::ty_to_str;
use core::hash::HashUtil;
use core::hashmap::HashMap;
use core::hashmap::{HashMap, HashSet};
use core::int;
use core::io;
use core::str;
@ -64,7 +64,8 @@ pub struct EncodeParams<'self> {
discrim_symbols: &'self HashMap<ast::node_id, @str>,
link_meta: &'self LinkMeta,
cstore: @mut cstore::CStore,
encode_inlined_item: encode_inlined_item<'self>
encode_inlined_item: encode_inlined_item<'self>,
reachable: @mut HashSet<ast::node_id>,
}
struct Stats {
@ -73,6 +74,7 @@ struct Stats {
dep_bytes: uint,
lang_item_bytes: uint,
link_args_bytes: uint,
misc_bytes: uint,
item_bytes: uint,
index_bytes: uint,
zero_bytes: uint,
@ -91,7 +93,8 @@ pub struct EncodeContext<'self> {
link_meta: &'self LinkMeta,
cstore: &'self cstore::CStore,
encode_inlined_item: encode_inlined_item<'self>,
type_abbrevs: abbrev_map
type_abbrevs: abbrev_map,
reachable: @mut HashSet<ast::node_id>,
}
pub fn reachable(ecx: &EncodeContext, id: node_id) -> bool {
@ -470,45 +473,50 @@ fn encode_reexported_static_methods(ecx: &EncodeContext,
}
}
fn encode_info_for_mod(ecx: &EncodeContext,
ebml_w: &mut writer::Encoder,
md: &_mod,
id: node_id,
path: &[ast_map::path_elt],
name: ident) {
ebml_w.start_tag(tag_items_data_item);
encode_def_id(ebml_w, local_def(id));
encode_family(ebml_w, 'm');
encode_name(ecx, ebml_w, name);
debug!("(encoding info for module) encoding info for module ID %d", id);
// Encode info about all the module children.
for md.items.iter().advance |item| {
/// Iterates through "auxiliary node IDs", which are node IDs that describe
/// top-level items that are sub-items of the given item. Specifically:
///
/// * For enums, iterates through the node IDs of the variants.
///
/// * For newtype structs, iterates through the node ID of the constructor.
fn each_auxiliary_node_id(item: @item, callback: &fn(node_id) -> bool)
-> bool {
let mut continue = true;
match item.node {
item_impl(*) => {
let (ident, did) = (item.ident, item.id);
debug!("(encoding info for module) ... encoding impl %s \
(%?/%?)",
ecx.tcx.sess.str_of(ident),
did,
ast_map::node_id_to_str(ecx.tcx.items, did, token::get_ident_interner()));
ebml_w.start_tag(tag_mod_impl);
ebml_w.wr_str(def_to_str(local_def(did)));
ebml_w.end_tag();
}
_ => {} // FIXME #4573: Encode these too.
item_enum(ref enum_def, _) => {
for enum_def.variants.each |variant| {
continue = callback(variant.node.id);
if !continue {
break
}
}
}
item_struct(struct_def, _) => {
// If this is a newtype struct, return the constructor.
match struct_def.ctor_id {
Some(ctor_id) if struct_def.fields.len() > 0 &&
struct_def.fields[0].node.kind ==
ast::unnamed_field => {
continue = callback(ctor_id);
}
_ => {}
}
}
_ => {}
}
encode_path(ecx, ebml_w, path, ast_map::path_mod(name));
continue
}
// Encode the reexports of this module.
fn encode_reexports(ecx: &EncodeContext,
ebml_w: &mut writer::Encoder,
id: node_id,
path: &[ast_map::path_elt]) {
debug!("(encoding info for module) encoding reexports for %d", id);
match ecx.reexports2.find(&id) {
Some(ref exports) => {
debug!("(encoding info for module) found reexports for %d", id);
for exports.iter().advance |exp| {
for exports.each |exp| {
debug!("(encoding info for module) reexport '%s' for %d",
exp.name, id);
ebml_w.start_tag(tag_items_data_item_reexport);
@ -527,6 +535,57 @@ fn encode_info_for_mod(ecx: &EncodeContext,
id);
}
}
}
fn encode_info_for_mod(ecx: &EncodeContext,
ebml_w: &mut writer::Encoder,
md: &_mod,
id: node_id,
path: &[ast_map::path_elt],
name: ident,
vis: visibility) {
ebml_w.start_tag(tag_items_data_item);
encode_def_id(ebml_w, local_def(id));
encode_family(ebml_w, 'm');
encode_name(ecx, ebml_w, name);
debug!("(encoding info for module) encoding info for module ID %d", id);
// Encode info about all the module children.
for md.items.iter().advance |item| {
ebml_w.start_tag(tag_mod_child);
ebml_w.wr_str(def_to_str(local_def(item.id)));
ebml_w.end_tag();
for each_auxiliary_node_id(*item) |auxiliary_node_id| {
ebml_w.start_tag(tag_mod_child);
ebml_w.wr_str(def_to_str(local_def(auxiliary_node_id)));
ebml_w.end_tag();
}
match item.node {
item_impl(*) => {
let (ident, did) = (item.ident, item.id);
debug!("(encoding info for module) ... encoding impl %s \
(%?/%?)",
ecx.tcx.sess.str_of(ident),
did,
ast_map::node_id_to_str(ecx.tcx.items, did, token::get_ident_interner()));
ebml_w.start_tag(tag_mod_impl);
ebml_w.wr_str(def_to_str(local_def(did)));
ebml_w.end_tag();
}
_ => {}
}
}
encode_path(ecx, ebml_w, path, ast_map::path_mod(name));
// Encode the reexports of this module, if this module is public.
if vis == public {
debug!("(encoding info for module) encoding reexports for %d", id);
encode_reexports(ecx, ebml_w, id, path);
}
ebml_w.end_tag();
}
@ -799,6 +858,7 @@ fn encode_info_for_item(ecx: &EncodeContext,
}
encode_type(ecx, ebml_w, node_id_to_type(tcx, item.id));
encode_symbol(ecx, ebml_w, item.id);
encode_name(ecx, ebml_w, item.ident);
encode_path(ecx, ebml_w, path, ast_map::path_name(item.ident));
(ecx.encode_inlined_item)(ecx, ebml_w, path, ii_item(item));
ebml_w.end_tag();
@ -811,6 +871,7 @@ fn encode_info_for_item(ecx: &EncodeContext,
let tps_len = generics.ty_params.len();
encode_type_param_bounds(ebml_w, ecx, &generics.ty_params);
encode_type(ecx, ebml_w, node_id_to_type(tcx, item.id));
encode_name(ecx, ebml_w, item.ident);
encode_path(ecx, ebml_w, path, ast_map::path_name(item.ident));
encode_attributes(ebml_w, item.attrs);
if tps_len > 0u || should_inline(item.attrs) {
@ -822,15 +883,29 @@ fn encode_info_for_item(ecx: &EncodeContext,
}
item_mod(ref m) => {
add_to_index();
encode_info_for_mod(ecx, ebml_w, m, item.id, path, item.ident);
encode_info_for_mod(ecx,
ebml_w,
m,
item.id,
path,
item.ident,
item.vis);
}
item_foreign_mod(_) => {
item_foreign_mod(ref fm) => {
add_to_index();
ebml_w.start_tag(tag_items_data_item);
encode_def_id(ebml_w, local_def(item.id));
encode_family(ebml_w, 'n');
encode_name(ecx, ebml_w, item.ident);
encode_path(ecx, ebml_w, path, ast_map::path_name(item.ident));
// Encode all the items in this module.
for fm.items.each |foreign_item| {
ebml_w.start_tag(tag_mod_child);
ebml_w.wr_str(def_to_str(local_def(foreign_item.id)));
ebml_w.end_tag();
}
ebml_w.end_tag();
}
item_ty(_, ref generics) => {
@ -998,6 +1073,10 @@ fn encode_info_for_item(ecx: &EncodeContext,
ebml_w.start_tag(tag_item_trait_method);
encode_def_id(ebml_w, method_def_id);
ebml_w.end_tag();
ebml_w.start_tag(tag_mod_child);
ebml_w.wr_str(def_to_str(method_def_id));
ebml_w.end_tag();
}
encode_path(ecx, ebml_w, path, ast_map::path_name(item.ident));
for super_traits.iter().advance |ast_trait_ref| {
@ -1091,6 +1170,7 @@ fn encode_info_for_foreign_item(ecx: &EncodeContext,
encode_family(ebml_w, purity_fn_family(purity));
encode_type_param_bounds(ebml_w, ecx, &generics.ty_params);
encode_type(ecx, ebml_w, node_id_to_type(ecx.tcx, nitem.id));
encode_name(ecx, ebml_w, nitem.ident);
if abi.is_intrinsic() {
(ecx.encode_inlined_item)(ecx, ebml_w, path, ii_foreign(nitem));
} else {
@ -1107,6 +1187,7 @@ fn encode_info_for_foreign_item(ecx: &EncodeContext,
}
encode_type(ecx, ebml_w, node_id_to_type(ecx.tcx, nitem.id));
encode_symbol(ecx, ebml_w, nitem.id);
encode_name(ecx, ebml_w, nitem.ident);
encode_path(ecx, ebml_w, path, ast_map::path_name(nitem.ident));
}
}
@ -1120,9 +1201,13 @@ fn encode_info_for_items(ecx: &EncodeContext,
let index = @mut ~[];
ebml_w.start_tag(tag_items_data);
index.push(entry { val: crate_node_id, pos: ebml_w.writer.tell() });
encode_info_for_mod(ecx, ebml_w, &crate.node.module,
crate_node_id, [],
syntax::parse::token::special_idents::invalid);
encode_info_for_mod(ecx,
ebml_w,
&crate.node.module,
crate_node_id,
[],
syntax::parse::token::special_idents::invalid,
public);
let items = ecx.tcx.items;
// See comment in `encode_side_tables_for_ii` in astencode
@ -1416,6 +1501,30 @@ fn encode_link_args(ecx: &EncodeContext, ebml_w: &mut writer::Encoder) {
ebml_w.end_tag();
}
fn encode_misc_info(ecx: &EncodeContext,
crate: &crate,
ebml_w: &mut writer::Encoder) {
ebml_w.start_tag(tag_misc_info);
ebml_w.start_tag(tag_misc_info_crate_items);
for crate.node.module.items.each |&item| {
ebml_w.start_tag(tag_mod_child);
ebml_w.wr_str(def_to_str(local_def(item.id)));
ebml_w.end_tag();
for each_auxiliary_node_id(item) |auxiliary_node_id| {
ebml_w.start_tag(tag_mod_child);
ebml_w.wr_str(def_to_str(local_def(auxiliary_node_id)));
ebml_w.end_tag();
}
}
// Encode reexports for the root module.
encode_reexports(ecx, ebml_w, 0, []);
ebml_w.end_tag();
ebml_w.end_tag();
}
fn encode_crate_dep(ecx: &EncodeContext,
ebml_w: &mut writer::Encoder,
dep: decoder::crate_dep) {
@ -1455,15 +1564,25 @@ pub fn encode_metadata(parms: EncodeParams, crate: &crate) -> ~[u8] {
dep_bytes: 0,
lang_item_bytes: 0,
link_args_bytes: 0,
misc_bytes: 0,
item_bytes: 0,
index_bytes: 0,
zero_bytes: 0,
total_bytes: 0,
n_inlines: 0
};
let EncodeParams{item_symbols, diag, tcx, reexports2,
discrim_symbols, cstore, encode_inlined_item,
link_meta, _} = parms;
let EncodeParams {
item_symbols,
diag,
tcx,
reexports2,
discrim_symbols,
cstore,
encode_inlined_item,
link_meta,
reachable,
_
} = parms;
let type_abbrevs = @mut HashMap::new();
let stats = @mut stats;
let ecx = EncodeContext {
@ -1476,7 +1595,8 @@ pub fn encode_metadata(parms: EncodeParams, crate: &crate) -> ~[u8] {
link_meta: link_meta,
cstore: cstore,
encode_inlined_item: encode_inlined_item,
type_abbrevs: type_abbrevs
type_abbrevs: type_abbrevs,
reachable: reachable,
};
let mut ebml_w = writer::Encoder(wr as @io::Writer);
@ -1502,6 +1622,11 @@ pub fn encode_metadata(parms: EncodeParams, crate: &crate) -> ~[u8] {
encode_link_args(&ecx, &mut ebml_w);
ecx.stats.link_args_bytes = *wr.pos - i;
// Encode miscellaneous info.
i = *wr.pos;
encode_misc_info(&ecx, crate, &mut ebml_w);
ecx.stats.misc_bytes = *wr.pos - i;
// Encode and index the items.
ebml_w.start_tag(tag_items);
i = *wr.pos;
@ -1529,6 +1654,7 @@ pub fn encode_metadata(parms: EncodeParams, crate: &crate) -> ~[u8] {
io::println(fmt!(" dep bytes: %u", ecx.stats.dep_bytes));
io::println(fmt!(" lang item bytes: %u", ecx.stats.lang_item_bytes));
io::println(fmt!(" link args bytes: %u", ecx.stats.link_args_bytes));
io::println(fmt!(" misc bytes: %u", ecx.stats.misc_bytes));
io::println(fmt!(" item bytes: %u", ecx.stats.item_bytes));
io::println(fmt!(" index bytes: %u", ecx.stats.index_bytes));
io::println(fmt!(" zero bytes: %u", ecx.stats.zero_bytes));

View File

@ -77,6 +77,15 @@ fn trait_method_might_be_inlined(trait_method: &trait_method) -> bool {
}
}
// The context we're in. If we're in a public context, then public symbols are
// marked reachable. If we're in a private context, then only trait
// implementations are marked reachable.
#[deriving(Eq)]
enum PrivacyContext {
PublicContext,
PrivateContext,
}
// Information needed while computing reachability.
struct ReachableContext {
// The type context.
@ -109,27 +118,33 @@ impl ReachableContext {
let reachable_symbols = self.reachable_symbols;
let worklist = self.worklist;
let visitor = visit::mk_vt(@Visitor {
visit_item: |item, (_, visitor)| {
visit_item: |item, (privacy_context, visitor):
(PrivacyContext, visit::vt<PrivacyContext>)| {
match item.node {
item_fn(*) => {
if privacy_context == PublicContext {
reachable_symbols.insert(item.id);
}
if item_might_be_inlined(item) {
worklist.push(item.id)
}
}
item_struct(ref struct_def, _) => {
match struct_def.ctor_id {
None => {}
Some(ctor_id) => {
Some(ctor_id) if
privacy_context == PublicContext => {
reachable_symbols.insert(ctor_id);
}
Some(_) | None => {}
}
}
item_enum(ref enum_def, _) => {
if privacy_context == PublicContext {
for enum_def.variants.each |variant| {
reachable_symbols.insert(variant.node.id);
}
}
}
item_impl(ref generics, trait_ref, _, ref methods) => {
// XXX(pcwalton): We conservatively assume any methods
// on a trait implementation are reachable, when this
@ -137,9 +152,15 @@ impl ReachableContext {
// treating implementations of reachable or cross-
// crate traits as reachable.
let should_be_considered_public = |method: @method| {
(method.vis == public &&
privacy_context == PublicContext) ||
trait_ref.is_some()
};
// Mark all public methods as reachable.
for methods.each |method| {
if method.vis == public || trait_ref.is_some() {
for methods.each |&method| {
if should_be_considered_public(method) {
reachable_symbols.insert(method.id);
}
}
@ -147,9 +168,8 @@ impl ReachableContext {
if generics_require_inlining(generics) {
// If the impl itself has generics, add all public
// symbols to the worklist.
for methods.each |method| {
if method.vis == public ||
trait_ref.is_some() {
for methods.each |&method| {
if should_be_considered_public(method) {
worklist.push(method.id)
}
}
@ -161,8 +181,7 @@ impl ReachableContext {
let attrs = &method.attrs;
if generics_require_inlining(generics) ||
attributes_specify_inlining(*attrs) ||
method.vis == public ||
trait_ref.is_some() {
should_be_considered_public(*method) {
worklist.push(method.id)
}
}
@ -170,6 +189,7 @@ impl ReachableContext {
}
item_trait(_, _, ref trait_methods) => {
// Mark all provided methods as reachable.
if privacy_context == PublicContext {
for trait_methods.each |trait_method| {
match *trait_method {
provided(method) => {
@ -180,17 +200,20 @@ impl ReachableContext {
}
}
}
}
_ => {}
}
if item.vis == public {
visit::visit_item(item, ((), visitor))
if item.vis == public && privacy_context == PublicContext {
visit::visit_item(item, (PublicContext, visitor))
} else {
visit::visit_item(item, (PrivateContext, visitor))
}
},
.. *visit::default_visitor()
});
visit::visit_crate(crate, ((), visitor))
visit::visit_crate(crate, (PublicContext, visitor))
}
// Returns true if the given def ID represents a local item that is
@ -247,7 +270,7 @@ impl ReachableContext {
}
}
Some(_) => false,
None => tcx.sess.bug("def ID not in def map?!"),
None => false // This will happen for default methods.
}
}

View File

@ -654,9 +654,19 @@ impl NameBindings {
Some(ref type_def) => {
match (*type_def).type_def {
Some(type_def) => Some(type_def),
None => {
match type_def.module_def {
Some(module) => {
match module.def_id {
Some(did) => Some(def_mod(did)),
None => None,
}
}
None => None,
}
}
}
}
}
}
ValueNS => {
@ -3149,12 +3159,14 @@ impl Resolver {
Some(def_id) if def_id.crate == local_crate => {
// OK. Continue.
debug!("(recording exports for module subtree) recording \
exports for local module");
exports for local module `%s`",
self.module_to_str(module_));
}
None => {
// Record exports for the root module.
debug!("(recording exports for module subtree) recording \
exports for root module");
exports for root module `%s`",
self.module_to_str(module_));
}
Some(_) => {
// Bail out.
@ -5037,6 +5049,9 @@ impl Resolver {
self.trait_map.insert(expr.id, @mut traits);
}
expr_method_call(_, _, ident, _, _, _) => {
debug!("(recording candidate traits for expr) recording \
traits for %d",
expr.id);
let traits = self.search_for_traits_containing_method(ident);
self.trait_map.insert(expr.id, @mut traits);
}
@ -5112,7 +5127,6 @@ impl Resolver {
debug!("(searching for traits containing method) looking for '%s'",
self.session.str_of(name));
let mut found_traits = ~[];
let mut search_module = self.current_module;
match self.method_map.find(&name) {

View File

@ -64,7 +64,7 @@ use util::ppaux::{Repr, ty_to_str};
use middle::trans::type_::Type;
use core::hash;
use core::hashmap::{HashMap};
use core::hashmap::{HashMap, HashSet};
use core::int;
use core::io;
use core::libc::c_uint;
@ -2509,7 +2509,7 @@ pub fn get_item_val(ccx: @mut CrateContext, id: ast::node_id) -> ValueRef {
variant))
}
};
if !exprt {
if !exprt && !ccx.reachable.contains(&id) {
lib::llvm::SetLinkage(val, lib::llvm::InternalLinkage);
}
ccx.item_vals.insert(id, val);
@ -2816,13 +2816,13 @@ pub fn crate_ctxt_to_encode_parms<'r>(cx: &'r CrateContext, ie: encoder::encode_
encoder::EncodeParams {
diag: diag,
tcx: cx.tcx,
reachable: cx.reachable,
reexports2: cx.exp_map2,
item_symbols: item_symbols,
discrim_symbols: discrim_symbols,
link_meta: link_meta,
cstore: cx.sess.cstore,
encode_inlined_item: ie
encode_inlined_item: ie,
reachable: cx.reachable,
}
}
@ -2890,7 +2890,7 @@ pub fn trans_crate(sess: session::Session,
emap2: resolve::ExportMap2,
reachable_map: @mut HashSet<ast::node_id>,
maps: astencode::Maps)
-> (ModuleRef, LinkMeta) {
-> (ContextRef, ModuleRef, LinkMeta) {
let mut symbol_hasher = hash::default_state();
let link_meta = link::build_link_meta(sess, crate, output, &mut symbol_hasher);
@ -2911,8 +2911,15 @@ pub fn trans_crate(sess: session::Session,
// sess.bug("couldn't enable multi-threaded LLVM");
// }
let ccx = @mut CrateContext::new(sess, llmod_id, tcx, emap2, maps,
symbol_hasher, link_meta, reachable);
let ccx = @mut CrateContext::new(sess,
llmod_id,
tcx,
emap2,
maps,
symbol_hasher,
link_meta,
reachable_map);
{
let _icx = push_ctxt("data");
trans_constants(ccx, crate);

View File

@ -117,84 +117,7 @@ pub fn BuilderRef_res(B: BuilderRef) -> BuilderRef_res {
}
}
pub type ExternMap = @mut HashMap<@str, ValueRef>;
// Crate context. Every crate we compile has one of these.
pub struct CrateContext {
sess: session::Session,
llmod: ModuleRef,
td: TargetData,
tn: @TypeNames,
externs: ExternMap,
intrinsics: HashMap<&'static str, ValueRef>,
item_vals: @mut HashMap<ast::node_id, ValueRef>,
exp_map2: resolve::ExportMap2,
item_symbols: @mut HashMap<ast::node_id, ~str>,
link_meta: LinkMeta,
enum_sizes: @mut HashMap<ty::t, uint>,
discrims: @mut HashMap<ast::def_id, ValueRef>,
discrim_symbols: @mut HashMap<ast::node_id, @str>,
tydescs: @mut HashMap<ty::t, @mut tydesc_info>,
// Set when running emit_tydescs to enforce that no more tydescs are
// created.
finished_tydescs: @mut bool,
// Track mapping of external ids to local items imported for inlining
external: @mut HashMap<ast::def_id, Option<ast::node_id>>,
// Cache instances of monomorphized functions
monomorphized: @mut HashMap<mono_id, ValueRef>,
monomorphizing: @mut HashMap<ast::def_id, uint>,
// Cache computed type parameter uses (see type_use.rs)
type_use_cache: @mut HashMap<ast::def_id, @~[type_use::type_uses]>,
// Cache generated vtables
vtables: @mut HashMap<mono_id, ValueRef>,
// Cache of constant strings,
const_cstr_cache: @mut HashMap<@str, ValueRef>,
// Reverse-direction for const ptrs cast from globals.
// Key is an int, cast from a ValueRef holding a *T,
// Val is a ValueRef holding a *[T].
//
// Needed because LLVM loses pointer->pointee association
// when we ptrcast, and we have to ptrcast during translation
// of a [T] const because we form a slice, a [*T,int] pair, not
// a pointer to an LLVM array type.
const_globals: @mut HashMap<int, ValueRef>,
// Cache of emitted const values
const_values: @mut HashMap<ast::node_id, ValueRef>,
// Cache of external const values
extern_const_values: @mut HashMap<ast::def_id, ValueRef>,
module_data: @mut HashMap<~str, ValueRef>,
lltypes: @mut HashMap<ty::t, TypeRef>,
llsizingtypes: @mut HashMap<ty::t, TypeRef>,
adt_reprs: @mut HashMap<ty::t, @adt::Repr>,
names: namegen,
next_addrspace: addrspace_gen,
symbol_hasher: @mut hash::State,
type_hashcodes: @mut HashMap<ty::t, @str>,
type_short_names: @mut HashMap<ty::t, ~str>,
all_llvm_symbols: @mut HashSet<@str>,
tcx: ty::ctxt,
maps: astencode::Maps,
stats: @mut Stats,
upcalls: @upcall::Upcalls,
tydesc_type: TypeRef,
int_type: TypeRef,
float_type: TypeRef,
opaque_vec_type: TypeRef,
builder: BuilderRef_res,
shape_cx: shape::Ctxt,
crate_map: ValueRef,
// Set when at least one function uses GC. Needed so that
// decl_gc_metadata knows whether to link to the module metadata, which
// is not emitted by LLVM's GC pass when no functions use GC.
uses_gc: @mut bool,
dbg_cx: Option<debuginfo::DebugContext>,
do_not_commit_warning_issued: @mut bool,
reachable_map: @mut HashSet<ast::node_id>,
}
pub type ExternMap = HashMap<@str, ValueRef>;
// Types used for llself.
pub struct ValSelfData {

View File

@ -21,7 +21,6 @@ use middle::resolve;
use middle::trans::adt;
use middle::trans::base;
use middle::trans::debuginfo;
use middle::trans::reachable;
use middle::trans::type_use;
use middle::ty;
@ -48,7 +47,7 @@ pub struct CrateContext {
intrinsics: HashMap<&'static str, ValueRef>,
item_vals: HashMap<ast::node_id, ValueRef>,
exp_map2: resolve::ExportMap2,
reachable: reachable::map,
reachable: @mut HashSet<ast::node_id>,
item_symbols: HashMap<ast::node_id, ~str>,
link_meta: LinkMeta,
enum_sizes: HashMap<ty::t, uint>,
@ -115,10 +114,15 @@ pub struct CrateContext {
}
impl CrateContext {
pub fn new(sess: session::Session, name: &str, tcx: ty::ctxt,
emap2: resolve::ExportMap2, maps: astencode::Maps,
symbol_hasher: hash::State, link_meta: LinkMeta,
reachable: reachable::map) -> CrateContext {
pub fn new(sess: session::Session,
name: &str,
tcx: ty::ctxt,
emap2: resolve::ExportMap2,
maps: astencode::Maps,
symbol_hasher: hash::State,
link_meta: LinkMeta,
reachable: @mut HashSet<ast::node_id>)
-> CrateContext {
unsafe {
let llcx = llvm::LLVMContextCreate();
set_task_llcx(llcx);

View File

@ -1393,6 +1393,8 @@ pub fn check_expr_with_unifier(fcx: @mut FnCtxt,
method_map.insert(expr.id, (*entry));
}
None => {
debug!("(checking method call) failing expr is %d", expr.id);
fcx.type_error_message(expr.span,
|actual| {
fmt!("type `%s` does not implement any method in scope \

View File

@ -17,7 +17,7 @@
use core::prelude::*;
use metadata::csearch::{each_path, get_impl_trait};
use metadata::csearch::{get_impls_for_mod};
use metadata::csearch;
use metadata::cstore::{CStore, iter_crate_data};
use metadata::decoder::{dl_def, dl_field, dl_impl};
use middle::resolve::{Impl, MethodInfo};
@ -855,23 +855,19 @@ impl CoherenceChecker {
// External crate handling
pub fn add_impls_for_module(&self,
pub fn add_external_impl(&self,
impls_seen: &mut HashSet<def_id>,
crate_store: @mut CStore,
module_def_id: def_id) {
let implementations = get_impls_for_mod(crate_store,
module_def_id,
None);
for implementations.iter().advance |implementation| {
debug!("coherence: adding impl from external crate: %s",
ty::item_path_str(self.crate_context.tcx,
implementation.did));
impl_def_id: def_id) {
let implementation = csearch::get_impl(crate_store, impl_def_id);
// Make sure we don't visit the same implementation
// multiple times.
debug!("coherence: adding impl from external crate: %s",
ty::item_path_str(self.crate_context.tcx, implementation.did));
// Make sure we don't visit the same implementation multiple times.
if !impls_seen.insert(implementation.did) {
// Skip this one.
loop;
return
}
// Good. Continue.
@ -882,54 +878,34 @@ impl CoherenceChecker {
// Do a sanity check to make sure that inherent methods have base
// types.
if associated_traits.is_none() {
match get_base_type_def_id(self.inference_context,
dummy_sp(),
self_type.ty) {
None => {
let session = self.crate_context.tcx.sess;
session.bug(fmt!(
"no base type for external impl \
with no trait: %s (type %s)!",
session.bug(fmt!("no base type for external impl with no \
trait: %s (type %s)!",
session.str_of(implementation.ident),
ty_to_str(self.crate_context.tcx,self_type.ty)));
ty_to_str(self.crate_context.tcx,
self_type.ty)));
}
Some(_) => {
// Nothing to do.
Some(_) => {} // Nothing to do.
}
}
}
let mut implementation = *implementation;
// Record all the trait methods.
let implementation = @implementation;
for associated_traits.iter().advance |trait_ref| {
self.instantiate_default_methods(implementation.did,
&**trait_ref);
// Could we avoid these copies when we don't need them?
let mut methods = /*bad?*/ copy implementation.methods;
self.add_provided_methods_to_impl(
&mut methods,
&trait_ref.def_id,
&implementation.did);
implementation = @Impl { methods: methods,
.. *implementation };
self.add_trait_method(trait_ref.def_id, implementation);
}
// Add the implementation to the mapping from
// implementation to base type def ID, if there is a base
// type for this implementation.
// Add the implementation to the mapping from implementation to base
// type def ID, if there is a base type for this implementation.
match get_base_type_def_id(self.inference_context,
dummy_sp(),
self_type.ty) {
None => {
// Nothing to do.
}
None => {} // Nothing to do.
Some(base_type_def_id) => {
// inherent methods apply to `impl Type` but not
// `impl Trait for Type`:
@ -943,7 +919,6 @@ impl CoherenceChecker {
}
}
}
}
// Adds implementations and traits from external crates to the coherence
// info.
@ -952,22 +927,17 @@ impl CoherenceChecker {
let crate_store = self.crate_context.tcx.sess.cstore;
do iter_crate_data(crate_store) |crate_number, _crate_metadata| {
self.add_impls_for_module(&mut impls_seen,
crate_store,
def_id { crate: crate_number,
node: 0 });
for each_path(crate_store, crate_number) |_, def_like, _| {
match def_like {
dl_def(def_mod(def_id)) => {
self.add_impls_for_module(&mut impls_seen,
dl_def(def_trait(def_id)) => {
self.add_default_methods_for_external_trait(def_id);
}
dl_impl(def_id) => {
self.add_external_impl(&mut impls_seen,
crate_store,
def_id);
}
dl_def(_) | dl_impl(_) | dl_field => {
// Skip this.
loop;
def_id)
}
dl_def(_) | dl_field => loop, // Skip this.
}
}
}

View File

@ -10,6 +10,7 @@
//! Utilities for manipulating the char type
use container::Container;
use option::{None, Option, Some};
use str;
use str::{StrSlice, OwnedStr};

View File

@ -29,6 +29,7 @@
#[allow(missing_doc)];
use cast;
use container::Container;
use io;
use iterator::IteratorUtil;
use libc;
@ -1500,7 +1501,10 @@ mod tests {
fn test_getenv_big() {
let mut s = ~"";
let mut i = 0;
while i < 100 { s += "aaaaaaaaaa"; i += 1; }
while i < 100 {
s = s + "aaaaaaaaaa";
i += 1;
}
let n = make_rand_name();
setenv(n, s);
debug!(copy s);

View File

@ -42,6 +42,7 @@ fn main () {
use cast;
use cmp;
use container::Container;
use int;
use iterator::IteratorUtil;
use local_data;

View File

@ -1140,6 +1140,17 @@ impl<'self> Str for @str {
}
}
impl<'self> Container for &'self str {
#[inline]
fn len(&self) -> uint {
do as_buf(*self) |_p, n| { n - 1u }
}
#[inline]
fn is_empty(&self) -> bool {
self.len() == 0
}
}
#[allow(missing_doc)]
pub trait StrSlice<'self> {
fn contains<'a>(&self, needle: &'a str) -> bool;
@ -1158,10 +1169,8 @@ pub trait StrSlice<'self> {
fn any_line_iter(&self) -> AnyLineIterator<'self>;
fn word_iter(&self) -> WordIterator<'self>;
fn ends_with(&self, needle: &str) -> bool;
fn is_empty(&self) -> bool;
fn is_whitespace(&self) -> bool;
fn is_alphanumeric(&self) -> bool;
fn len(&self) -> uint;
fn char_len(&self) -> uint;
fn slice(&self, begin: uint, end: uint) -> &'self str;
@ -1362,9 +1371,6 @@ impl<'self> StrSlice<'self> for &'self str {
self.split_iter(char::is_whitespace).filter(|s| !s.is_empty())
}
/// Returns true if the string has length 0
#[inline]
fn is_empty(&self) -> bool { self.len() == 0 }
/**
* Returns true if the string contains only whitespace
*
@ -1379,11 +1385,6 @@ impl<'self> StrSlice<'self> for &'self str {
*/
#[inline]
fn is_alphanumeric(&self) -> bool { self.iter().all(char::is_alphanumeric) }
/// Returns the size in bytes not counting the null terminator
#[inline]
fn len(&self) -> uint {
do as_buf(*self) |_p, n| { n - 1u }
}
/// Returns the number of characters that a string holds
#[inline]
fn char_len(&self) -> uint { self.iter().len_() }

View File

@ -94,6 +94,7 @@ use iterator::IteratorUtil;
#[doc(hidden)]
pub mod ct {
use char;
use container::Container;
use prelude::*;
use str;