Add scoped thread-local encoding and decoding contexts to cstore.

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.
This commit is contained in:
Michael Woerister 2015-12-01 16:07:15 +01:00
parent c212c0e1d1
commit f65823e39c
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

@ -639,6 +639,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

@ -62,6 +62,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

@ -405,3 +405,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

@ -59,3 +59,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
}