restructure to better support method inlining

This commit is contained in:
Niko Matsakis 2012-03-01 19:37:52 -08:00
parent def72bda47
commit 6473a87cec
13 changed files with 274 additions and 192 deletions

View file

@ -2,6 +2,7 @@ import syntax::ast;
import syntax::fold;
import syntax::visit;
import syntax::ast_util;
import syntax::ast_util::inlined_item_methods;
import syntax::codemap::span;
import std::map::map;
import std::smallintmap::map;
@ -31,8 +32,6 @@ import syntax::print::pprust;
export encode_inlined_item;
export decode_inlined_item;
export encode_inlined_method;
export decode_inlined_method;
type decode_ctxt = @{
cdata: cstore::crate_metadata,
@ -53,123 +52,49 @@ iface tr {
// ______________________________________________________________________
// Top-level methods.
// The type inline_fn should be a type that can represent both methods
// and top-level items. As it happens, the type ast::method is perfect
// for this purpose, but I use this typedef just to keep clear when
// the thing may not, in fact, be an actual method in the AST but
// rather some sort of function.
enum inline_fn = @ast::method;
fn encode_inlined_item(ecx: @e::encode_ctxt,
ebml_w: ebml::writer,
path: ast_map::path,
item: @ast::item) {
let ifn = inline_fn(alt item.node {
ast::item_fn(decl, tps, body) {
@{ident: item.ident,
attrs: item.attrs,
tps: tps,
decl: decl,
body: body,
id: item.id,
span: item.span}
}
ii: ast::inlined_item) {
#debug["> Encoding inlined item: %s::%s (%u)",
ast_map::path_to_str(path), ii.ident(),
ebml_w.writer.tell()];
_ {
ecx.ccx.sess.span_bug(item.span, "Cannot inline non-function")
}
});
let id_range = compute_id_range(ii);
ebml_w.wr_tag(c::tag_ast as uint) {||
encode_id_range(ebml_w, id_range);
encode_ast(ebml_w, ii);
encode_side_tables_for_ii(ecx, ebml_w, ii);
}
encode_inlined_fn(ecx, ebml_w, path, ifn);
#debug["< Encoded inlined fn: %s::%s (%u)",
ast_map::path_to_str(path), ii.ident(),
ebml_w.writer.tell()];
}
fn decode_inlined_item(cdata: cstore::crate_metadata,
tcx: ty::ctxt,
maps: maps,
path: ast_map::path,
par_doc: ebml::doc) -> option<@ast::item> {
let oifn = decode_inlined_fn(cdata, tcx, maps, path, par_doc);
option::map(oifn) {|ifn|
let item = @{ident: ifn.ident,
attrs: ifn.attrs,
id: ifn.id,
node: ast::item_fn(ifn.decl, ifn.tps, ifn.body),
span: ifn.span};
ast_map::map_decoded_item(tcx.items, path, item);
item
}
}
fn encode_inlined_method(ecx: @e::encode_ctxt,
ebml_w: ebml::writer,
path: ast_map::path,
mthd: @ast::method) {
encode_inlined_fn(ecx, ebml_w, path, inline_fn(mthd))
}
fn decode_inlined_method(cdata: cstore::crate_metadata,
tcx: ty::ctxt,
maps: maps,
path: ast_map::path,
par_doc: ebml::doc) -> option<@ast::method> {
let oifn = decode_inlined_fn(cdata, tcx, maps, path, par_doc);
option::map(oifn) {|ifn|
ast_map::map_decoded_method(tcx.items, path, *ifn);
*ifn
}
}
fn encode_inlined_fn(ecx: @e::encode_ctxt,
ebml_w: ebml::writer,
path: ast_map::path,
ifn: inline_fn) {
#debug["> Encoding inlined item: %s::%s (%u)",
ast_map::path_to_str(path),
ifn.ident,
ebml_w.writer.tell()];
let id_range = compute_id_range(ifn);
ebml_w.wr_tag(c::tag_ast as uint) {||
encode_id_range(ebml_w, id_range);
encode_ast(ebml_w, ifn);
encode_side_tables_for_ifn(ecx, ebml_w, ifn);
}
#debug["< Encoded inlined fn: %s::%s (%u)",
ast_map::path_to_str(path),
ifn.ident,
ebml_w.writer.tell()];
}
// Decodes the inlined function and associated side tables. Does
// *not* insert the function into the ast_map, since the correct way
// to do this depends on whether this is an inlined item or method;
// therefore, you ought to be invoking decode_inlined_item() or
// decode_inlined_method() and not this helper function.
fn decode_inlined_fn(cdata: cstore::crate_metadata,
tcx: ty::ctxt,
maps: maps,
path: ast_map::path,
par_doc: ebml::doc) -> option<inline_fn> {
par_doc: ebml::doc) -> option<ast::inlined_item> {
let dcx = @{cdata: cdata, tcx: tcx, maps: maps};
alt par_doc.opt_child(c::tag_ast) {
none { none }
some(ast_doc) {
#debug["> Decoding inlined fn: %s", ast_map::path_to_str(path)];
#debug["> Decoding inlined fn: %s::?", ast_map::path_to_str(path)];
let from_id_range = decode_id_range(ast_doc);
let to_id_range = reserve_id_range(dcx.tcx.sess, from_id_range);
let xcx = @{dcx: dcx,
from_id_range: from_id_range,
to_id_range: to_id_range};
let raw_ifn = decode_ast(ast_doc);
let ifn = renumber_ast(xcx, raw_ifn);
#debug["Fn named: %s", ifn.ident];
let raw_ii = decode_ast(ast_doc);
let ii = renumber_ast(xcx, raw_ii);
ast_map::map_decoded_item(dcx.tcx.items, path, ii);
#debug["Fn named: %s", ii.ident()];
decode_side_tables(xcx, ast_doc);
#debug["< Decoded inlined fn: %s::%s",
ast_map::path_to_str(path),
ifn.ident];
some(ifn)
ast_map::path_to_str(path), ii.ident()];
some(ii)
}
}
}
@ -183,7 +108,7 @@ fn empty(range: id_range) -> bool {
range.min >= range.max
}
fn visit_ids(ifn: inline_fn, vfn: fn@(ast::node_id)) {
fn visit_ids(item: ast::inlined_item, vfn: fn@(ast::node_id)) {
let visitor = visit::mk_simple_visitor(@{
visit_mod: fn@(_m: ast::_mod, _sp: span, id: ast::node_id) {
vfn(id)
@ -292,13 +217,13 @@ fn visit_ids(ifn: inline_fn, vfn: fn@(ast::node_id)) {
}
});
visit::visit_method_helper(*ifn, (), visitor);
item.accept((), visitor)
}
fn compute_id_range(ifn: inline_fn) -> id_range {
fn compute_id_range(item: ast::inlined_item) -> id_range {
let min = @mutable int::max_value;
let max = @mutable int::min_value;
visit_ids(ifn) {|id|
visit_ids(item) {|id|
*min = int::min(*min, id);
*max = int::max(*max, id + 1);
}
@ -395,25 +320,34 @@ impl deserializer_helpers<D: serialization::deserializer> for D {
// We also have to adjust the spans: for now we just insert a dummy span,
// but eventually we should add entries to the local codemap as required.
fn encode_ast(ebml_w: ebml::writer, ifn: inline_fn) {
fn encode_ast(ebml_w: ebml::writer, item: ast::inlined_item) {
ebml_w.wr_tag(c::tag_tree as uint) {||
astencode_gen::serialize_syntax_ast_method(ebml_w, **ifn)
astencode_gen::serialize_syntax_ast_inlined_item(ebml_w, item)
}
}
fn decode_ast(par_doc: ebml::doc) -> inline_fn {
fn decode_ast(par_doc: ebml::doc) -> ast::inlined_item {
let chi_doc = par_doc[c::tag_tree];
let d = serialization::mk_ebml_deserializer(chi_doc);
inline_fn(@astencode_gen::deserialize_syntax_ast_method(d))
astencode_gen::deserialize_syntax_ast_inlined_item(d)
}
fn renumber_ast(xcx: extended_decode_ctxt, ifn: inline_fn) -> inline_fn {
fn renumber_ast(xcx: extended_decode_ctxt, ii: ast::inlined_item)
-> ast::inlined_item {
let fld = fold::make_fold({
new_id: xcx.tr_id(_),
new_span: xcx.tr_span(_)
with *fold::default_ast_fold()
});
inline_fn(fld.fold_method(*ifn))
alt ii {
ast::ii_item(i) {
ast::ii_item(fld.fold_item(i))
}
ast::ii_method(d, m) {
ast::ii_method(xcx.tr_def_id(d), fld.fold_method(m))
}
}
}
// ______________________________________________________________________
@ -664,11 +598,11 @@ impl writer for ebml::writer {
}
}
fn encode_side_tables_for_ifn(ecx: @e::encode_ctxt,
ebml_w: ebml::writer,
ifn: inline_fn) {
fn encode_side_tables_for_ii(ecx: @e::encode_ctxt,
ebml_w: ebml::writer,
ii: ast::inlined_item) {
ebml_w.wr_tag(c::tag_table as uint) {||
visit_ids(ifn, fn@(id: ast::node_id) {
visit_ids(ii, fn@(id: ast::node_id) {
// Note: this will cause a copy of ebml_w, which is bad as
// it has mutable fields. But I believe it's harmless since
// we generate balanced EBML.