Auto merge of #30140 - michaelwoerister:tls-encoding, r=nikomatsakis

With this commit, metadata encoding and decoding can make use of thread-local encoding and decoding contexts. These allow implementers of `serialize::Encodable` and `Decodable` to access information and
datastructures that would otherwise not be available to them. For example, we can automatically translate def-id and span information during decoding because the decoding context knows which crate the data is decoded from. Or it allows to make `ty::Ty` decodable because the context has access to the `ty::ctxt` that is needed for creating `ty::Ty` instances.

Some notes:
- `tls::with_encoding_context()` and `tls::with_decoding_context()` (as opposed to their unsafe versions) try to prevent the TLS data getting out-of-sync by making sure that the encoder/decoder passed in is actually the same as the one stored in the context. This should prevent accidentally reading from the wrong decoder.
- There are no real tests in this PR. I had a unit tests for some of the core aspects of the TLS implementation but it was kind of brittle, a lot of code for mocking `ty::ctxt`, `crate_metadata`, etc and did actually test not so much. The code will soon be tested by the first incremental compilation auto-tests that rely on MIR being properly serialized. However, if people think that some tests should be added before this can land, I'll try to provide some that make sense.

r? @nikomatsakis
This commit is contained in:
bors 2015-12-09 15:10:37 +00:00
commit eebf6743d8
12 changed files with 450 additions and 108 deletions

View File

@ -88,7 +88,7 @@ DEPS_test := std getopts serialize rbml term native:rust_test_helpers
DEPS_syntax := std term serialize log fmt_macros arena libc rustc_bitflags
DEPS_rustc := syntax flate arena serialize getopts rustc_front\
DEPS_rustc := syntax flate arena serialize getopts rbml rustc_front\
log graphviz rustc_llvm rustc_back rustc_data_structures
DEPS_rustc_back := std syntax rustc_llvm rustc_front flate log libc
DEPS_rustc_borrowck := rustc rustc_front log graphviz syntax

View File

@ -638,6 +638,14 @@ pub mod reader {
self.pos = old_pos;
Ok(result)
}
pub fn position(&self) -> usize {
self.pos
}
pub fn advance(&mut self, bytes: usize) {
self.pos += bytes;
}
}
impl<'doc> serialize::Decoder for Decoder<'doc> {

View File

@ -59,6 +59,7 @@ extern crate fmt_macros;
extern crate getopts;
extern crate graphviz;
extern crate libc;
extern crate rbml;
extern crate rustc_llvm;
extern crate rustc_back;
extern crate rustc_front;

View File

@ -407,3 +407,141 @@ impl<'tcx> CrateStore<'tcx> for DummyCrateStore {
krate: &hir::Crate) -> Vec<u8> { vec![] }
fn metadata_encoding_version(&self) -> &[u8] { unimplemented!() }
}
/// Metadata encoding and decoding can make use of thread-local encoding and
/// decoding contexts. These allow implementers of serialize::Encodable and
/// Decodable to access information and datastructures that would otherwise not
/// be available to them. For example, we can automatically translate def-id and
/// span information during decoding because the decoding context knows which
/// crate the data is decoded from. Or it allows to make ty::Ty decodable
/// because the context has access to the ty::ctxt that is needed for creating
/// ty::Ty instances.
///
/// Note, however, that this only works for RBML-based encoding and decoding at
/// the moment.
pub mod tls {
use rbml::writer::Encoder as RbmlEncoder;
use rbml::reader::Decoder as RbmlDecoder;
use serialize;
use std::mem;
use middle::ty::{self, Ty};
use middle::subst::Substs;
use middle::def_id::DefId;
pub trait EncodingContext<'tcx> {
fn tcx<'a>(&'a self) -> &'a ty::ctxt<'tcx>;
fn encode_ty(&self, rbml_w: &mut RbmlEncoder, t: Ty<'tcx>);
fn encode_substs(&self, rbml_w: &mut RbmlEncoder, substs: &Substs<'tcx>);
}
/// Marker type used for the scoped TLS slot.
/// The type context cannot be used directly because the scoped TLS
/// in libstd doesn't allow types generic over lifetimes.
struct TlsPayload;
scoped_thread_local!(static TLS_ENCODING: TlsPayload);
/// Execute f after pushing the given EncodingContext onto the TLS stack.
pub fn enter_encoding_context<'tcx, F, R>(ecx: &EncodingContext<'tcx>,
rbml_w: &mut RbmlEncoder,
f: F) -> R
where F: FnOnce(&EncodingContext<'tcx>, &mut RbmlEncoder) -> R
{
let tls_payload = (ecx as *const _, rbml_w as *mut _);
let tls_ptr = &tls_payload as *const _ as *const TlsPayload;
TLS_ENCODING.set(unsafe { &*tls_ptr }, || f(ecx, rbml_w))
}
/// Execute f with access to the thread-local encoding context and
/// rbml encoder. This function will panic if the encoder passed in and the
/// context encoder are not the same.
///
/// Note that this method is 'practically' safe due to its checking that the
/// encoder passed in is the same as the one in TLS, but it would still be
/// possible to construct cases where the EncodingContext is exchanged
/// while the same encoder is used, thus working with a wrong context.
pub fn with_encoding_context<'tcx, E, F, R>(encoder: &mut E, f: F) -> R
where F: FnOnce(&EncodingContext<'tcx>, &mut RbmlEncoder) -> R,
E: serialize::Encoder
{
unsafe {
unsafe_with_encoding_context(|ecx, rbml_w| {
assert!(encoder as *mut _ as usize == rbml_w as *mut _ as usize);
let ecx: &EncodingContext<'tcx> = mem::transmute(ecx);
f(ecx, rbml_w)
})
}
}
/// Execute f with access to the thread-local encoding context and
/// rbml encoder.
pub unsafe fn unsafe_with_encoding_context<F, R>(f: F) -> R
where F: FnOnce(&EncodingContext, &mut RbmlEncoder) -> R
{
TLS_ENCODING.with(|tls| {
let tls_payload = (tls as *const TlsPayload)
as *mut (&EncodingContext, &mut RbmlEncoder);
f((*tls_payload).0, (*tls_payload).1)
})
}
pub trait DecodingContext<'tcx> {
fn tcx<'a>(&'a self) -> &'a ty::ctxt<'tcx>;
fn decode_ty(&self, rbml_r: &mut RbmlDecoder) -> ty::Ty<'tcx>;
fn decode_substs(&self, rbml_r: &mut RbmlDecoder) -> Substs<'tcx>;
fn translate_def_id(&self, def_id: DefId) -> DefId;
}
scoped_thread_local!(static TLS_DECODING: TlsPayload);
/// Execute f after pushing the given DecodingContext onto the TLS stack.
pub fn enter_decoding_context<'tcx, F, R>(dcx: &DecodingContext<'tcx>,
rbml_r: &mut RbmlDecoder,
f: F) -> R
where F: FnOnce(&DecodingContext<'tcx>, &mut RbmlDecoder) -> R
{
let tls_payload = (dcx as *const _, rbml_r as *mut _);
let tls_ptr = &tls_payload as *const _ as *const TlsPayload;
TLS_DECODING.set(unsafe { &*tls_ptr }, || f(dcx, rbml_r))
}
/// Execute f with access to the thread-local decoding context and
/// rbml decoder. This function will panic if the decoder passed in and the
/// context decoder are not the same.
///
/// Note that this method is 'practically' safe due to its checking that the
/// decoder passed in is the same as the one in TLS, but it would still be
/// possible to construct cases where the DecodingContext is exchanged
/// while the same decoder is used, thus working with a wrong context.
pub fn with_decoding_context<'decoder, 'tcx, D, F, R>(d: &'decoder mut D, f: F) -> R
where D: serialize::Decoder,
F: FnOnce(&DecodingContext<'tcx>,
&mut RbmlDecoder) -> R,
'tcx: 'decoder
{
unsafe {
unsafe_with_decoding_context(|dcx, rbml_r| {
assert!((d as *mut _ as usize) == (rbml_r as *mut _ as usize));
let dcx: &DecodingContext<'tcx> = mem::transmute(dcx);
f(dcx, rbml_r)
})
}
}
/// Execute f with access to the thread-local decoding context and
/// rbml decoder.
pub unsafe fn unsafe_with_decoding_context<F, R>(f: F) -> R
where F: FnOnce(&DecodingContext, &mut RbmlDecoder) -> R
{
TLS_DECODING.with(|tls| {
let tls_payload = (tls as *const TlsPayload)
as *mut (&DecodingContext, &mut RbmlDecoder);
f((*tls_payload).0, (*tls_payload).1)
})
}
}

View File

@ -13,9 +13,11 @@
pub use self::ParamSpace::*;
pub use self::RegionSubsts::*;
use middle::cstore;
use middle::ty::{self, Ty, HasTypeFlags, RegionEscape};
use middle::ty::fold::{TypeFoldable, TypeFolder};
use serialize::{Encodable, Encoder, Decodable, Decoder};
use std::fmt;
use std::iter::IntoIterator;
use std::slice::Iter;
@ -153,6 +155,35 @@ impl<'tcx> Substs<'tcx> {
}
}
impl<'tcx> Encodable for Substs<'tcx> {
fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
cstore::tls::with_encoding_context(s, |ecx, rbml_w| {
ecx.encode_substs(rbml_w, self);
Ok(())
})
}
}
impl<'tcx> Decodable for Substs<'tcx> {
fn decode<D: Decoder>(d: &mut D) -> Result<Substs<'tcx>, D::Error> {
cstore::tls::with_decoding_context(d, |dcx, rbml_r| {
Ok(dcx.decode_substs(rbml_r))
})
}
}
impl<'tcx> Decodable for &'tcx Substs<'tcx> {
fn decode<D: Decoder>(d: &mut D) -> Result<&'tcx Substs<'tcx>, D::Error> {
let substs = cstore::tls::with_decoding_context(d, |dcx, rbml_r| {
let substs = dcx.decode_substs(rbml_r);
dcx.tcx().mk_substs(substs)
});
Ok(substs)
}
}
impl RegionSubsts {
pub fn map<F>(self, op: F) -> RegionSubsts where
F: FnOnce(VecPerParamSpace<ty::Region>) -> VecPerParamSpace<ty::Region>,

View File

@ -22,7 +22,7 @@ pub use self::LvaluePreference::*;
use front::map as ast_map;
use front::map::LinkedPath;
use middle;
use middle::cstore::{CrateStore, LOCAL_CRATE};
use middle::cstore::{self, CrateStore, LOCAL_CRATE};
use middle::def::{self, ExportMap};
use middle::def_id::DefId;
use middle::lang_items::{FnTraitLangItem, FnMutTraitLangItem, FnOnceTraitLangItem};
@ -35,6 +35,7 @@ use util::common::memoized;
use util::nodemap::{NodeMap, NodeSet, DefIdMap};
use util::nodemap::FnvHashMap;
use serialize::{Encodable, Encoder, Decodable, Decoder};
use std::borrow::{Borrow, Cow};
use std::cell::{Cell, RefCell};
use std::hash::{Hash, Hasher};
@ -479,6 +480,24 @@ impl<'tcx> Hash for TyS<'tcx> {
pub type Ty<'tcx> = &'tcx TyS<'tcx>;
impl<'tcx> Encodable for Ty<'tcx> {
fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
cstore::tls::with_encoding_context(s, |ecx, rbml_w| {
ecx.encode_ty(rbml_w, *self);
Ok(())
})
}
}
impl<'tcx> Decodable for Ty<'tcx> {
fn decode<D: Decoder>(d: &mut D) -> Result<Ty<'tcx>, D::Error> {
cstore::tls::with_decoding_context(d, |dcx, rbml_r| {
Ok(dcx.decode_ty(rbml_r))
})
}
}
/// Upvars do not get their own node-id. Instead, we use the pair of
/// the original var id (that is, the root variable that is referenced
/// by the upvar) and the id of the closure expression.
@ -1529,6 +1548,23 @@ impl<'tcx, 'container> Hash for AdtDefData<'tcx, 'container> {
}
}
impl<'tcx> Encodable for AdtDef<'tcx> {
fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
self.did.encode(s)
}
}
impl<'tcx> Decodable for AdtDef<'tcx> {
fn decode<D: Decoder>(d: &mut D) -> Result<AdtDef<'tcx>, D::Error> {
let def_id: DefId = try!{ Decodable::decode(d) };
cstore::tls::with_decoding_context(d, |dcx, _| {
let def_id = dcx.translate_def_id(def_id);
Ok(dcx.tcx().lookup_adt_def(def_id))
})
}
}
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub enum AdtKind { Struct, Enum }

View File

@ -39,7 +39,6 @@ use middle::ty::{self, Ty};
use syntax::{ast, ast_util, codemap};
use syntax::ast::NodeIdAssigner;
use syntax::codemap::Span;
use syntax::ptr::P;
use std::cell::Cell;
@ -116,7 +115,7 @@ impl<'a, 'b, 'c, 'tcx> ast_map::FoldOps for &'a DecodeContext<'b, 'c, 'tcx> {
fn new_def_id(&self, def_id: DefId) -> DefId {
self.tr_def_id(def_id)
}
fn new_span(&self, span: Span) -> Span {
fn new_span(&self, span: codemap::Span) -> codemap::Span {
self.tr_span(span)
}
}
@ -219,60 +218,12 @@ impl<'a, 'b, 'tcx> DecodeContext<'a, 'b, 'tcx> {
}
/// Translates a `Span` from an extern crate to the corresponding `Span`
/// within the local crate's codemap. `creader::import_codemap()` will
/// already have allocated any additionally needed FileMaps in the local
/// codemap as a side-effect of creating the crate_metadata's
/// `codemap_import_info`.
pub fn tr_span(&self, span: Span) -> Span {
let span = if span.lo > span.hi {
// Currently macro expansion sometimes produces invalid Span values
// where lo > hi. In order not to crash the compiler when trying to
// translate these values, let's transform them into something we
// can handle (and which will produce useful debug locations at
// least some of the time).
// This workaround is only necessary as long as macro expansion is
// not fixed. FIXME(#23480)
codemap::mk_sp(span.lo, span.lo)
} else {
span
};
let imported_filemaps = self.cdata.imported_filemaps(self.tcx.sess.codemap());
let filemap = {
// Optimize for the case that most spans within a translated item
// originate from the same filemap.
let last_filemap_index = self.last_filemap_index.get();
let last_filemap = &imported_filemaps[last_filemap_index];
if span.lo >= last_filemap.original_start_pos &&
span.lo <= last_filemap.original_end_pos &&
span.hi >= last_filemap.original_start_pos &&
span.hi <= last_filemap.original_end_pos {
last_filemap
} else {
let mut a = 0;
let mut b = imported_filemaps.len();
while b - a > 1 {
let m = (a + b) / 2;
if imported_filemaps[m].original_start_pos > span.lo {
b = m;
} else {
a = m;
}
}
self.last_filemap_index.set(a);
&imported_filemaps[a]
}
};
let lo = (span.lo - filemap.original_start_pos) +
filemap.translated_filemap.start_pos;
let hi = (span.hi - filemap.original_start_pos) +
filemap.translated_filemap.start_pos;
codemap::mk_sp(lo, hi)
/// within the local crate's codemap.
pub fn tr_span(&self, span: codemap::Span) -> codemap::Span {
decoder::translate_span(self.cdata,
self.tcx.sess.codemap(),
&self.last_filemap_index,
span)
}
}
@ -288,8 +239,8 @@ impl tr for Option<DefId> {
}
}
impl tr for Span {
fn tr(&self, dcx: &DecodeContext) -> Span {
impl tr for codemap::Span {
fn tr(&self, dcx: &DecodeContext) -> codemap::Span {
dcx.tr_span(*self)
}
}

View File

@ -1216,6 +1216,64 @@ fn reverse_translate_def_id(cdata: Cmd, did: DefId) -> Option<DefId> {
None
}
/// Translates a `Span` from an extern crate to the corresponding `Span`
/// within the local crate's codemap.
pub fn translate_span(cdata: Cmd,
codemap: &codemap::CodeMap,
last_filemap_index_hint: &Cell<usize>,
span: codemap::Span)
-> codemap::Span {
let span = if span.lo > span.hi {
// Currently macro expansion sometimes produces invalid Span values
// where lo > hi. In order not to crash the compiler when trying to
// translate these values, let's transform them into something we
// can handle (and which will produce useful debug locations at
// least some of the time).
// This workaround is only necessary as long as macro expansion is
// not fixed. FIXME(#23480)
codemap::mk_sp(span.lo, span.lo)
} else {
span
};
let imported_filemaps = cdata.imported_filemaps(&codemap);
let filemap = {
// Optimize for the case that most spans within a translated item
// originate from the same filemap.
let last_filemap_index = last_filemap_index_hint.get();
let last_filemap = &imported_filemaps[last_filemap_index];
if span.lo >= last_filemap.original_start_pos &&
span.lo <= last_filemap.original_end_pos &&
span.hi >= last_filemap.original_start_pos &&
span.hi <= last_filemap.original_end_pos {
last_filemap
} else {
let mut a = 0;
let mut b = imported_filemaps.len();
while b - a > 1 {
let m = (a + b) / 2;
if imported_filemaps[m].original_start_pos > span.lo {
b = m;
} else {
a = m;
}
}
last_filemap_index_hint.set(a);
&imported_filemaps[a]
}
};
let lo = (span.lo - filemap.original_start_pos) +
filemap.translated_filemap.start_pos;
let hi = (span.hi - filemap.original_start_pos) +
filemap.translated_filemap.start_pos;
codemap::mk_sp(lo, hi)
}
pub fn each_inherent_implementation_for_type<F>(cdata: Cmd,
id: DefIndex,
mut callback: F)

View File

@ -19,7 +19,7 @@ use decoder;
use tyencode;
use index::{self, IndexData};
use middle::cstore::{LOCAL_CRATE, CrateStore, InlinedItemRef, LinkMeta};
use middle::cstore::{LOCAL_CRATE, CrateStore, InlinedItemRef, LinkMeta, tls};
use middle::def;
use middle::def_id::{CRATE_DEF_INDEX, DefId};
use middle::dependency_format::Linkage;
@ -1875,8 +1875,37 @@ fn encode_dylib_dependency_formats(rbml_w: &mut Encoder, ecx: &EncodeContext) {
pub const metadata_encoding_version : &'static [u8] = &[b'r', b'u', b's', b't', 0, 0, 0, 2 ];
pub fn encode_metadata(parms: EncodeParams, krate: &hir::Crate) -> Vec<u8> {
let EncodeParams {
item_symbols,
diag,
tcx,
reexports,
cstore,
encode_inlined_item,
link_meta,
reachable,
..
} = parms;
let ecx = EncodeContext {
diag: diag,
tcx: tcx,
reexports: reexports,
item_symbols: item_symbols,
link_meta: link_meta,
cstore: cstore,
encode_inlined_item: RefCell::new(encode_inlined_item),
type_abbrevs: RefCell::new(FnvHashMap()),
reachable: reachable,
};
let mut wr = Cursor::new(Vec::new());
encode_metadata_inner(&mut wr, parms, krate);
{
let mut rbml_w = Encoder::new(&mut wr);
tls::enter_encoding_context(&ecx, &mut rbml_w, |_, rbml_w| {
encode_metadata_inner(rbml_w, &ecx, krate)
});
}
// RBML compacts the encoded bytes whenever appropriate,
// so there are some garbages left after the end of the data.
@ -1911,8 +1940,8 @@ pub fn encode_metadata(parms: EncodeParams, krate: &hir::Crate) -> Vec<u8> {
return v;
}
fn encode_metadata_inner(wr: &mut Cursor<Vec<u8>>,
parms: EncodeParams,
fn encode_metadata_inner(rbml_w: &mut Encoder,
ecx: &EncodeContext,
krate: &hir::Crate) {
struct Stats {
attr_bytes: u64,
@ -1946,101 +1975,77 @@ fn encode_metadata_inner(wr: &mut Cursor<Vec<u8>>,
zero_bytes: 0,
total_bytes: 0,
};
let EncodeParams {
item_symbols,
diag,
tcx,
reexports,
cstore,
encode_inlined_item,
link_meta,
reachable,
..
} = parms;
let ecx = EncodeContext {
diag: diag,
tcx: tcx,
reexports: reexports,
item_symbols: item_symbols,
link_meta: link_meta,
cstore: cstore,
encode_inlined_item: RefCell::new(encode_inlined_item),
type_abbrevs: RefCell::new(FnvHashMap()),
reachable: reachable,
};
let mut rbml_w = Encoder::new(wr);
encode_rustc_version(&mut rbml_w);
encode_crate_name(&mut rbml_w, &ecx.link_meta.crate_name);
encode_crate_triple(&mut rbml_w, &tcx.sess.opts.target_triple);
encode_hash(&mut rbml_w, &ecx.link_meta.crate_hash);
encode_dylib_dependency_formats(&mut rbml_w, &ecx);
encode_rustc_version(rbml_w);
encode_crate_name(rbml_w, &ecx.link_meta.crate_name);
encode_crate_triple(rbml_w, &ecx.tcx.sess.opts.target_triple);
encode_hash(rbml_w, &ecx.link_meta.crate_hash);
encode_dylib_dependency_formats(rbml_w, &ecx);
let mut i = rbml_w.writer.seek(SeekFrom::Current(0)).unwrap();
encode_attributes(&mut rbml_w, &krate.attrs);
encode_attributes(rbml_w, &krate.attrs);
stats.attr_bytes = rbml_w.writer.seek(SeekFrom::Current(0)).unwrap() - i;
i = rbml_w.writer.seek(SeekFrom::Current(0)).unwrap();
encode_crate_deps(&mut rbml_w, ecx.cstore);
encode_crate_deps(rbml_w, ecx.cstore);
stats.dep_bytes = rbml_w.writer.seek(SeekFrom::Current(0)).unwrap() - i;
// Encode the language items.
i = rbml_w.writer.seek(SeekFrom::Current(0)).unwrap();
encode_lang_items(&ecx, &mut rbml_w);
encode_lang_items(&ecx, rbml_w);
stats.lang_item_bytes = rbml_w.writer.seek(SeekFrom::Current(0)).unwrap() - i;
// Encode the native libraries used
i = rbml_w.writer.seek(SeekFrom::Current(0)).unwrap();
encode_native_libraries(&ecx, &mut rbml_w);
encode_native_libraries(&ecx, rbml_w);
stats.native_lib_bytes = rbml_w.writer.seek(SeekFrom::Current(0)).unwrap() - i;
// Encode the plugin registrar function
i = rbml_w.writer.seek(SeekFrom::Current(0)).unwrap();
encode_plugin_registrar_fn(&ecx, &mut rbml_w);
encode_plugin_registrar_fn(&ecx, rbml_w);
stats.plugin_registrar_fn_bytes = rbml_w.writer.seek(SeekFrom::Current(0)).unwrap() - i;
// Encode codemap
i = rbml_w.writer.seek(SeekFrom::Current(0)).unwrap();
encode_codemap(&ecx, &mut rbml_w);
encode_codemap(&ecx, rbml_w);
stats.codemap_bytes = rbml_w.writer.seek(SeekFrom::Current(0)).unwrap() - i;
// Encode macro definitions
i = rbml_w.writer.seek(SeekFrom::Current(0)).unwrap();
encode_macro_defs(&mut rbml_w, krate);
encode_macro_defs(rbml_w, krate);
stats.macro_defs_bytes = rbml_w.writer.seek(SeekFrom::Current(0)).unwrap() - i;
// Encode the def IDs of impls, for coherence checking.
i = rbml_w.writer.seek(SeekFrom::Current(0)).unwrap();
encode_impls(&ecx, krate, &mut rbml_w);
encode_impls(&ecx, krate, rbml_w);
stats.impl_bytes = rbml_w.writer.seek(SeekFrom::Current(0)).unwrap() - i;
// Encode miscellaneous info.
i = rbml_w.writer.seek(SeekFrom::Current(0)).unwrap();
encode_misc_info(&ecx, krate, &mut rbml_w);
encode_reachable(&ecx, &mut rbml_w);
encode_misc_info(&ecx, krate, rbml_w);
encode_reachable(&ecx, rbml_w);
stats.misc_bytes = rbml_w.writer.seek(SeekFrom::Current(0)).unwrap() - i;
// Encode and index the items.
rbml_w.start_tag(tag_items);
i = rbml_w.writer.seek(SeekFrom::Current(0)).unwrap();
let index = encode_info_for_items(&ecx, &mut rbml_w);
let index = encode_info_for_items(&ecx, rbml_w);
stats.item_bytes = rbml_w.writer.seek(SeekFrom::Current(0)).unwrap() - i;
rbml_w.end_tag();
i = rbml_w.writer.seek(SeekFrom::Current(0)).unwrap();
encode_item_index(&mut rbml_w, index.items);
encode_item_index(rbml_w, index.items);
stats.index_bytes = rbml_w.writer.seek(SeekFrom::Current(0)).unwrap() - i;
i = rbml_w.writer.seek(SeekFrom::Current(0)).unwrap();
encode_xrefs(&ecx, &mut rbml_w, index.xrefs);
encode_xrefs(&ecx, rbml_w, index.xrefs);
stats.xref_bytes = rbml_w.writer.seek(SeekFrom::Current(0)).unwrap() - i;
encode_struct_field_attrs(&ecx, &mut rbml_w, krate);
encode_struct_field_attrs(&ecx, rbml_w, krate);
stats.total_bytes = rbml_w.writer.seek(SeekFrom::Current(0)).unwrap();
if tcx.sess.meta_stats() {
if ecx.tcx.sess.meta_stats() {
for e in rbml_w.writer.get_ref() {
if *e == 0 {
stats.zero_bytes += 1;

View File

@ -58,3 +58,4 @@ pub mod cstore;
pub mod index;
pub mod loader;
pub mod macro_import;
pub mod tls_context;

View File

@ -0,0 +1,109 @@
// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// This module provides implementations for the thread-local encoding and
// decoding context traits in rustc::middle::cstore::tls.
use rbml::writer::Encoder as RbmlEncoder;
use rbml::reader::Decoder as RbmlDecoder;
use rustc::middle::cstore::tls;
use rustc::middle::def_id::DefId;
use rustc::middle::subst::Substs;
use rustc::middle::ty::{self, Ty};
use decoder::{self, Cmd};
use encoder;
use tydecode::TyDecoder;
use tyencode;
impl<'a, 'tcx: 'a> tls::EncodingContext<'tcx> for encoder::EncodeContext<'a, 'tcx> {
fn tcx<'s>(&'s self) -> &'s ty::ctxt<'tcx> {
&self.tcx
}
fn encode_ty(&self, rbml_w: &mut RbmlEncoder, t: ty::Ty<'tcx>) {
encoder::write_type(self, rbml_w, t);
}
fn encode_substs(&self, rbml_w: &mut RbmlEncoder, substs: &Substs<'tcx>) {
let ty_str_ctxt = &tyencode::ctxt {
diag: self.diag,
ds: encoder::def_to_string,
tcx: self.tcx,
abbrevs: &self.type_abbrevs
};
tyencode::enc_substs(rbml_w, ty_str_ctxt, substs);
}
}
pub struct DecodingContext<'a, 'tcx: 'a> {
pub crate_metadata: Cmd<'a>,
pub tcx: &'a ty::ctxt<'tcx>,
}
impl<'a, 'tcx: 'a> tls::DecodingContext<'tcx> for DecodingContext<'a, 'tcx> {
fn tcx<'s>(&'s self) -> &'s ty::ctxt<'tcx> {
&self.tcx
}
fn decode_ty(&self, rbml_r: &mut RbmlDecoder) -> ty::Ty<'tcx> {
let def_id_convert = &mut |did| {
decoder::translate_def_id(self.crate_metadata, did)
};
let starting_position = rbml_r.position();
let mut ty_decoder = TyDecoder::new(
self.crate_metadata.data.as_slice(),
self.crate_metadata.cnum,
starting_position,
self.tcx,
def_id_convert);
let ty = ty_decoder.parse_ty();
let end_position = ty_decoder.position();
// We can just reuse the tydecode implementation for parsing types, but
// we have to make sure to leave the rbml reader at the position just
// after the type.
rbml_r.advance(end_position - starting_position);
ty
}
fn decode_substs(&self, rbml_r: &mut RbmlDecoder) -> Substs<'tcx> {
let def_id_convert = &mut |did| {
decoder::translate_def_id(self.crate_metadata, did)
};
let starting_position = rbml_r.position();
let mut ty_decoder = TyDecoder::new(
self.crate_metadata.data.as_slice(),
self.crate_metadata.cnum,
starting_position,
self.tcx,
def_id_convert);
let substs = ty_decoder.parse_substs();
let end_position = ty_decoder.position();
rbml_r.advance(end_position - starting_position);
substs
}
fn translate_def_id(&self, def_id: DefId) -> DefId {
decoder::translate_def_id(self.crate_metadata, def_id)
}
}

View File

@ -68,6 +68,10 @@ impl<'a,'tcx> TyDecoder<'a,'tcx> {
}
}
pub fn position(&self) -> usize {
self.pos
}
fn peek(&self) -> char {
self.data[self.pos] as char
}