From d2d1d989687eb350072ddb4da7ae102d86ab551a Mon Sep 17 00:00:00 2001 From: Patrick Walton Date: Mon, 7 Jan 2013 10:51:53 -0800 Subject: [PATCH] librustc: Encode language items into a special lookup table. 9% improvement in hello world compile time. --- src/librustc/metadata/common.rs | 12 ++++ src/librustc/metadata/csearch.rs | 9 +++ src/librustc/metadata/decoder.rs | 18 ++++++ src/librustc/metadata/encoder.rs | 32 +++++++++++ src/librustc/middle/lang_items.rs | 95 ++++++++++++++++++++----------- 5 files changed, 134 insertions(+), 32 deletions(-) diff --git a/src/librustc/metadata/common.rs b/src/librustc/metadata/common.rs index 69dcdc389d62a..1c821480df481 100644 --- a/src/librustc/metadata/common.rs +++ b/src/librustc/metadata/common.rs @@ -139,5 +139,17 @@ const tag_item_trait_method_sort: uint = 0x70; const tag_item_impl_type_basename: uint = 0x71; +// Language items are a top-level directory (for speed). Hierarchy: +// +// tag_lang_items +// - tag_lang_items_item +// - tag_lang_items_item_id: u32 +// - tag_lang_items_item_node_id: u32 + +const tag_lang_items: uint = 0x72; +const tag_lang_items_item: uint = 0x73; +const tag_lang_items_item_id: uint = 0x74; +const tag_lang_items_item_node_id: uint = 0x75; + type link_meta = {name: ~str, vers: ~str, extras_hash: ~str}; diff --git a/src/librustc/metadata/csearch.rs b/src/librustc/metadata/csearch.rs index 24bbebd1000d4..be0f71f0e5da7 100644 --- a/src/librustc/metadata/csearch.rs +++ b/src/librustc/metadata/csearch.rs @@ -43,6 +43,7 @@ export get_method_names_if_trait; export get_type_name_if_impl; export get_static_methods_if_impl; export get_item_attrs; +export each_lang_item; export each_path; export get_type; export get_impl_traits; @@ -74,6 +75,14 @@ fn get_type_param_count(cstore: cstore::CStore, def: ast::def_id) -> uint { return decoder::get_type_param_count(cdata, def.node); } +/// Iterates over all the language items in the given crate. +fn each_lang_item(cstore: cstore::CStore, + cnum: ast::crate_num, + f: &fn(ast::node_id, uint) -> bool) { + let crate_data = cstore::get_crate_data(cstore, cnum); + decoder::each_lang_item(crate_data, f) +} + /// Iterates over all the paths in the given crate. fn each_path(cstore: cstore::CStore, cnum: ast::crate_num, f: fn(decoder::path_entry) -> bool) { diff --git a/src/librustc/metadata/decoder.rs b/src/librustc/metadata/decoder.rs index 294e34248bcc8..d9486bf4e9f5c 100644 --- a/src/librustc/metadata/decoder.rs +++ b/src/librustc/metadata/decoder.rs @@ -74,6 +74,7 @@ export dl_def; export dl_impl; export dl_field; export path_entry; +export each_lang_item; export each_path; export get_item_path; export maybe_find_item; // sketchy @@ -479,6 +480,23 @@ fn path_entry(path_string: ~str, def_like: def_like) -> path_entry { } } +/// Iterates over the language items in the given crate. +fn each_lang_item(cdata: cmd, f: &fn(ast::node_id, uint) -> bool) { + let root = reader::Doc(cdata.data); + let lang_items = reader::get_doc(root, tag_lang_items); + for reader::tagged_docs(lang_items, tag_lang_items_item) |item_doc| { + let id_doc = reader::get_doc(item_doc, tag_lang_items_item_id); + let id = reader::doc_as_u32(id_doc) as uint; + let node_id_doc = reader::get_doc(item_doc, + tag_lang_items_item_node_id); + let node_id = reader::doc_as_u32(node_id_doc) as ast::node_id; + + if !f(node_id, id) { + break; + } + } +} + /// Iterates over all the paths in the given crate. fn each_path(intr: @ident_interner, cdata: cmd, get_crate_data: GetCrateDataCb, diff --git a/src/librustc/metadata/encoder.rs b/src/librustc/metadata/encoder.rs index d44b47593ba6e..b327e8f31969d 100644 --- a/src/librustc/metadata/encoder.rs +++ b/src/librustc/metadata/encoder.rs @@ -84,6 +84,7 @@ type stats = { mut inline_bytes: uint, mut attr_bytes: uint, mut dep_bytes: uint, + mut lang_item_bytes: uint, mut item_bytes: uint, mut index_bytes: uint, mut zero_bytes: uint, @@ -1088,6 +1089,30 @@ fn encode_crate_deps(ecx: @encode_ctxt, ebml_w: writer::Encoder, ebml_w.end_tag(); } +fn encode_lang_items(ecx: @encode_ctxt, ebml_w: writer::Encoder) { + ebml_w.start_tag(tag_lang_items); + + for ecx.tcx.lang_items.each_item |def_id, i| { + if def_id.crate != local_crate { + loop; + } + + ebml_w.start_tag(tag_lang_items_item); + + ebml_w.start_tag(tag_lang_items_item_id); + ebml_w.writer.write_be_u32(i as u32); + ebml_w.end_tag(); // tag_lang_items_item_id + + ebml_w.start_tag(tag_lang_items_item_node_id); + ebml_w.writer.write_be_u32(def_id.node as u32); + ebml_w.end_tag(); // tag_lang_items_item_node_id + + ebml_w.end_tag(); // tag_lang_items_item + } + + ebml_w.end_tag(); // tag_lang_items +} + fn encode_crate_dep(ecx: @encode_ctxt, ebml_w: writer::Encoder, dep: decoder::crate_dep) { ebml_w.start_tag(tag_crate_dep); @@ -1122,6 +1147,7 @@ fn encode_metadata(parms: encode_parms, crate: @crate) -> ~[u8] { {mut inline_bytes: 0, mut attr_bytes: 0, mut dep_bytes: 0, + mut lang_item_bytes: 0, mut item_bytes: 0, mut index_bytes: 0, mut zero_bytes: 0, @@ -1154,6 +1180,11 @@ fn encode_metadata(parms: encode_parms, crate: @crate) -> ~[u8] { encode_crate_deps(ecx, ebml_w, ecx.cstore); ecx.stats.dep_bytes = wr.pos - i; + // Encode the language items. + i = wr.pos; + encode_lang_items(ecx, ebml_w); + ecx.stats.lang_item_bytes = wr.pos - i; + // Encode and index the items. ebml_w.start_tag(tag_items); i = wr.pos; @@ -1183,6 +1214,7 @@ fn encode_metadata(parms: encode_parms, crate: @crate) -> ~[u8] { io::println(fmt!(" inline bytes: %u", ecx.stats.inline_bytes)); io::println(fmt!(" attribute bytes: %u", ecx.stats.attr_bytes)); 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!(" 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)); diff --git a/src/librustc/middle/lang_items.rs b/src/librustc/middle/lang_items.rs index deaba1b225c77..def3f0fb98272 100644 --- a/src/librustc/middle/lang_items.rs +++ b/src/librustc/middle/lang_items.rs @@ -20,7 +20,7 @@ // * Functions called by the compiler itself. use driver::session::Session; -use metadata::csearch::{each_path, get_item_attrs}; +use metadata::csearch::{each_lang_item, get_item_attrs}; use metadata::cstore::{iter_crate_data}; use metadata::decoder::{dl_def, dl_field, dl_impl}; use syntax::ast::{crate, def_fn, def_id, def_ty, lit_str, meta_item}; @@ -74,6 +74,47 @@ impl LanguageItems { } } + fn each_item(&self, f: &fn(def_id: def_id, i: uint) -> bool) { + for self.items.eachi |i, &item| { + if !f(item.get(), i) { + break; + } + } + } + + static pub fn item_name(index: uint) -> &static/str { + match index { + 0 => "const", + 1 => "copy", + 2 => "owned", + 3 => "durable", + + 4 => "drop", + + 5 => "add", + 6 => "sub", + 7 => "mul", + 8 => "div", + 9 => "modulo", + 10 => "neg", + 11 => "bitxor", + 12 => "bitand", + 13 => "bitor", + 14 => "shl", + 15 => "shr", + 16 => "index", + 17 => "eq", + 18 => "ord", + + 19 => "str_eq", + 20 => "uniq_str_eq", + 21 => "annihilate", + 22 => "log_type", + + _ => "???" + } + } + // XXX: Method macros sure would be nice here. pub fn const_trait(&const self) -> def_id { @@ -220,6 +261,22 @@ impl LanguageItemCollector { } } + fn collect_item(item_index: uint, item_def_id: def_id) { + // Check for duplicates. + match self.items.items[item_index] { + Some(original_def_id) if original_def_id != item_def_id => { + self.session.err(fmt!("duplicate entry for `%s`", + LanguageItems::item_name(item_index))); + } + Some(_) | None => { + // OK. + } + } + + // Matched. + self.items.items[item_index] = Some(item_def_id); + } + fn match_and_collect_item(item_def_id: def_id, key: ~str, value: ~str) { if key != ~"lang" { return; // Didn't match. @@ -230,20 +287,7 @@ impl LanguageItemCollector { // Didn't match. } Some(item_index) => { - // Check for duplicates. - match self.items.items[item_index] { - Some(original_def_id) - if original_def_id != item_def_id => { - self.session.err(fmt!("duplicate entry for `%s`", - value)); - } - Some(_) | None => { - // OK. - } - } - - // Matched. - self.items.items[item_index] = Some(item_def_id); + self.collect_item(item_index, item_def_id) } } } @@ -268,23 +312,10 @@ impl LanguageItemCollector { fn collect_external_language_items() { let crate_store = self.session.cstore; do iter_crate_data(crate_store) |crate_number, _crate_metadata| { - for each_path(crate_store, crate_number) |path_entry| { - let def_id; - match path_entry.def_like { - dl_def(def_ty(did)) | dl_def(def_fn(did, _)) => { - def_id = did; - } - dl_def(_) | dl_impl(_) | dl_field => { - // Skip this. - loop; - } - } - - do get_item_attrs(crate_store, def_id) |meta_items| { - for meta_items.each |meta_item| { - self.match_and_collect_meta_item(def_id, **meta_item); - } - } + for each_lang_item(crate_store, crate_number) + |node_id, item_index| { + let def_id = { crate: crate_number, node: node_id }; + self.collect_item(item_index, def_id); } } }