Skip to content

librustc: Encode language items into a special lookup table. 9% improvement in hello world compile time. #4368

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jan 7, 2013
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions src/librustc/metadata/common.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};

9 changes: 9 additions & 0 deletions src/librustc/metadata/csearch.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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) {
Expand Down
18 changes: 18 additions & 0 deletions src/librustc/metadata/decoder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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,
Expand Down
32 changes: 32 additions & 0 deletions src/librustc/metadata/encoder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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));
Expand Down
95 changes: 63 additions & 32 deletions src/librustc/middle/lang_items.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -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.
Expand All @@ -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)
}
}
}
Expand All @@ -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);
}
}
}
Expand Down