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:
parent
c212c0e1d1
commit
f65823e39c
12 changed files with 450 additions and 108 deletions
|
@ -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
|
||||
|
|
|
@ -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> {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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>,
|
||||
|
|
|
@ -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 }
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -59,3 +59,4 @@ pub mod cstore;
|
|||
pub mod index;
|
||||
pub mod loader;
|
||||
pub mod macro_import;
|
||||
pub mod tls_context;
|
||||
|
|
109
src/librustc_metadata/tls_context.rs
Normal file
109
src/librustc_metadata/tls_context.rs
Normal 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)
|
||||
}
|
||||
}
|
|
@ -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
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue