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_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
|
log graphviz rustc_llvm rustc_back rustc_data_structures
|
||||||
DEPS_rustc_back := std syntax rustc_llvm rustc_front flate log libc
|
DEPS_rustc_back := std syntax rustc_llvm rustc_front flate log libc
|
||||||
DEPS_rustc_borrowck := rustc rustc_front log graphviz syntax
|
DEPS_rustc_borrowck := rustc rustc_front log graphviz syntax
|
||||||
|
|
|
@ -639,6 +639,14 @@ pub mod reader {
|
||||||
self.pos = old_pos;
|
self.pos = old_pos;
|
||||||
Ok(result)
|
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> {
|
impl<'doc> serialize::Decoder for Decoder<'doc> {
|
||||||
|
|
|
@ -62,6 +62,7 @@ extern crate fmt_macros;
|
||||||
extern crate getopts;
|
extern crate getopts;
|
||||||
extern crate graphviz;
|
extern crate graphviz;
|
||||||
extern crate libc;
|
extern crate libc;
|
||||||
|
extern crate rbml;
|
||||||
extern crate rustc_llvm;
|
extern crate rustc_llvm;
|
||||||
extern crate rustc_back;
|
extern crate rustc_back;
|
||||||
extern crate rustc_front;
|
extern crate rustc_front;
|
||||||
|
|
|
@ -405,3 +405,141 @@ impl<'tcx> CrateStore<'tcx> for DummyCrateStore {
|
||||||
krate: &hir::Crate) -> Vec<u8> { vec![] }
|
krate: &hir::Crate) -> Vec<u8> { vec![] }
|
||||||
fn metadata_encoding_version(&self) -> &[u8] { unimplemented!() }
|
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::ParamSpace::*;
|
||||||
pub use self::RegionSubsts::*;
|
pub use self::RegionSubsts::*;
|
||||||
|
|
||||||
|
use middle::cstore;
|
||||||
use middle::ty::{self, Ty, HasTypeFlags, RegionEscape};
|
use middle::ty::{self, Ty, HasTypeFlags, RegionEscape};
|
||||||
use middle::ty::fold::{TypeFoldable, TypeFolder};
|
use middle::ty::fold::{TypeFoldable, TypeFolder};
|
||||||
|
|
||||||
|
use serialize::{Encodable, Encoder, Decodable, Decoder};
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::iter::IntoIterator;
|
use std::iter::IntoIterator;
|
||||||
use std::slice::Iter;
|
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 {
|
impl RegionSubsts {
|
||||||
pub fn map<F>(self, op: F) -> RegionSubsts where
|
pub fn map<F>(self, op: F) -> RegionSubsts where
|
||||||
F: FnOnce(VecPerParamSpace<ty::Region>) -> VecPerParamSpace<ty::Region>,
|
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 as ast_map;
|
||||||
use front::map::LinkedPath;
|
use front::map::LinkedPath;
|
||||||
use middle;
|
use middle;
|
||||||
use middle::cstore::{CrateStore, LOCAL_CRATE};
|
use middle::cstore::{self, CrateStore, LOCAL_CRATE};
|
||||||
use middle::def::{self, ExportMap};
|
use middle::def::{self, ExportMap};
|
||||||
use middle::def_id::DefId;
|
use middle::def_id::DefId;
|
||||||
use middle::lang_items::{FnTraitLangItem, FnMutTraitLangItem, FnOnceTraitLangItem};
|
use middle::lang_items::{FnTraitLangItem, FnMutTraitLangItem, FnOnceTraitLangItem};
|
||||||
|
@ -35,6 +35,7 @@ use util::common::memoized;
|
||||||
use util::nodemap::{NodeMap, NodeSet, DefIdMap};
|
use util::nodemap::{NodeMap, NodeSet, DefIdMap};
|
||||||
use util::nodemap::FnvHashMap;
|
use util::nodemap::FnvHashMap;
|
||||||
|
|
||||||
|
use serialize::{Encodable, Encoder, Decodable, Decoder};
|
||||||
use std::borrow::{Borrow, Cow};
|
use std::borrow::{Borrow, Cow};
|
||||||
use std::cell::{Cell, RefCell};
|
use std::cell::{Cell, RefCell};
|
||||||
use std::hash::{Hash, Hasher};
|
use std::hash::{Hash, Hasher};
|
||||||
|
@ -479,6 +480,24 @@ impl<'tcx> Hash for TyS<'tcx> {
|
||||||
|
|
||||||
pub type Ty<'tcx> = &'tcx 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
|
/// 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
|
/// the original var id (that is, the root variable that is referenced
|
||||||
/// by the upvar) and the id of the closure expression.
|
/// 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)]
|
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
|
||||||
pub enum AdtKind { Struct, Enum }
|
pub enum AdtKind { Struct, Enum }
|
||||||
|
|
|
@ -39,7 +39,6 @@ use middle::ty::{self, Ty};
|
||||||
|
|
||||||
use syntax::{ast, ast_util, codemap};
|
use syntax::{ast, ast_util, codemap};
|
||||||
use syntax::ast::NodeIdAssigner;
|
use syntax::ast::NodeIdAssigner;
|
||||||
use syntax::codemap::Span;
|
|
||||||
use syntax::ptr::P;
|
use syntax::ptr::P;
|
||||||
|
|
||||||
use std::cell::Cell;
|
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 {
|
fn new_def_id(&self, def_id: DefId) -> DefId {
|
||||||
self.tr_def_id(def_id)
|
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)
|
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`
|
/// Translates a `Span` from an extern crate to the corresponding `Span`
|
||||||
/// within the local crate's codemap. `creader::import_codemap()` will
|
/// within the local crate's codemap.
|
||||||
/// already have allocated any additionally needed FileMaps in the local
|
pub fn tr_span(&self, span: codemap::Span) -> codemap::Span {
|
||||||
/// codemap as a side-effect of creating the crate_metadata's
|
decoder::translate_span(self.cdata,
|
||||||
/// `codemap_import_info`.
|
self.tcx.sess.codemap(),
|
||||||
pub fn tr_span(&self, span: Span) -> Span {
|
&self.last_filemap_index,
|
||||||
let span = if span.lo > span.hi {
|
span)
|
||||||
// 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)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -288,8 +239,8 @@ impl tr for Option<DefId> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl tr for Span {
|
impl tr for codemap::Span {
|
||||||
fn tr(&self, dcx: &DecodeContext) -> Span {
|
fn tr(&self, dcx: &DecodeContext) -> codemap::Span {
|
||||||
dcx.tr_span(*self)
|
dcx.tr_span(*self)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1216,6 +1216,64 @@ fn reverse_translate_def_id(cdata: Cmd, did: DefId) -> Option<DefId> {
|
||||||
None
|
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,
|
pub fn each_inherent_implementation_for_type<F>(cdata: Cmd,
|
||||||
id: DefIndex,
|
id: DefIndex,
|
||||||
mut callback: F)
|
mut callback: F)
|
||||||
|
|
|
@ -19,7 +19,7 @@ use decoder;
|
||||||
use tyencode;
|
use tyencode;
|
||||||
use index::{self, IndexData};
|
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;
|
||||||
use middle::def_id::{CRATE_DEF_INDEX, DefId};
|
use middle::def_id::{CRATE_DEF_INDEX, DefId};
|
||||||
use middle::dependency_format::Linkage;
|
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 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> {
|
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());
|
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,
|
// RBML compacts the encoded bytes whenever appropriate,
|
||||||
// so there are some garbages left after the end of the data.
|
// 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;
|
return v;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn encode_metadata_inner(wr: &mut Cursor<Vec<u8>>,
|
fn encode_metadata_inner(rbml_w: &mut Encoder,
|
||||||
parms: EncodeParams,
|
ecx: &EncodeContext,
|
||||||
krate: &hir::Crate) {
|
krate: &hir::Crate) {
|
||||||
struct Stats {
|
struct Stats {
|
||||||
attr_bytes: u64,
|
attr_bytes: u64,
|
||||||
|
@ -1946,101 +1975,77 @@ fn encode_metadata_inner(wr: &mut Cursor<Vec<u8>>,
|
||||||
zero_bytes: 0,
|
zero_bytes: 0,
|
||||||
total_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(rbml_w);
|
||||||
|
encode_crate_name(rbml_w, &ecx.link_meta.crate_name);
|
||||||
encode_rustc_version(&mut rbml_w);
|
encode_crate_triple(rbml_w, &ecx.tcx.sess.opts.target_triple);
|
||||||
encode_crate_name(&mut rbml_w, &ecx.link_meta.crate_name);
|
encode_hash(rbml_w, &ecx.link_meta.crate_hash);
|
||||||
encode_crate_triple(&mut rbml_w, &tcx.sess.opts.target_triple);
|
encode_dylib_dependency_formats(rbml_w, &ecx);
|
||||||
encode_hash(&mut rbml_w, &ecx.link_meta.crate_hash);
|
|
||||||
encode_dylib_dependency_formats(&mut rbml_w, &ecx);
|
|
||||||
|
|
||||||
let mut i = rbml_w.writer.seek(SeekFrom::Current(0)).unwrap();
|
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;
|
stats.attr_bytes = rbml_w.writer.seek(SeekFrom::Current(0)).unwrap() - i;
|
||||||
|
|
||||||
i = rbml_w.writer.seek(SeekFrom::Current(0)).unwrap();
|
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;
|
stats.dep_bytes = rbml_w.writer.seek(SeekFrom::Current(0)).unwrap() - i;
|
||||||
|
|
||||||
// Encode the language items.
|
// Encode the language items.
|
||||||
i = rbml_w.writer.seek(SeekFrom::Current(0)).unwrap();
|
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;
|
stats.lang_item_bytes = rbml_w.writer.seek(SeekFrom::Current(0)).unwrap() - i;
|
||||||
|
|
||||||
// Encode the native libraries used
|
// Encode the native libraries used
|
||||||
i = rbml_w.writer.seek(SeekFrom::Current(0)).unwrap();
|
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;
|
stats.native_lib_bytes = rbml_w.writer.seek(SeekFrom::Current(0)).unwrap() - i;
|
||||||
|
|
||||||
// Encode the plugin registrar function
|
// Encode the plugin registrar function
|
||||||
i = rbml_w.writer.seek(SeekFrom::Current(0)).unwrap();
|
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;
|
stats.plugin_registrar_fn_bytes = rbml_w.writer.seek(SeekFrom::Current(0)).unwrap() - i;
|
||||||
|
|
||||||
// Encode codemap
|
// Encode codemap
|
||||||
i = rbml_w.writer.seek(SeekFrom::Current(0)).unwrap();
|
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;
|
stats.codemap_bytes = rbml_w.writer.seek(SeekFrom::Current(0)).unwrap() - i;
|
||||||
|
|
||||||
// Encode macro definitions
|
// Encode macro definitions
|
||||||
i = rbml_w.writer.seek(SeekFrom::Current(0)).unwrap();
|
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;
|
stats.macro_defs_bytes = rbml_w.writer.seek(SeekFrom::Current(0)).unwrap() - i;
|
||||||
|
|
||||||
// Encode the def IDs of impls, for coherence checking.
|
// Encode the def IDs of impls, for coherence checking.
|
||||||
i = rbml_w.writer.seek(SeekFrom::Current(0)).unwrap();
|
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;
|
stats.impl_bytes = rbml_w.writer.seek(SeekFrom::Current(0)).unwrap() - i;
|
||||||
|
|
||||||
// Encode miscellaneous info.
|
// Encode miscellaneous info.
|
||||||
i = rbml_w.writer.seek(SeekFrom::Current(0)).unwrap();
|
i = rbml_w.writer.seek(SeekFrom::Current(0)).unwrap();
|
||||||
encode_misc_info(&ecx, krate, &mut rbml_w);
|
encode_misc_info(&ecx, krate, rbml_w);
|
||||||
encode_reachable(&ecx, &mut rbml_w);
|
encode_reachable(&ecx, rbml_w);
|
||||||
stats.misc_bytes = rbml_w.writer.seek(SeekFrom::Current(0)).unwrap() - i;
|
stats.misc_bytes = rbml_w.writer.seek(SeekFrom::Current(0)).unwrap() - i;
|
||||||
|
|
||||||
// Encode and index the items.
|
// Encode and index the items.
|
||||||
rbml_w.start_tag(tag_items);
|
rbml_w.start_tag(tag_items);
|
||||||
i = rbml_w.writer.seek(SeekFrom::Current(0)).unwrap();
|
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;
|
stats.item_bytes = rbml_w.writer.seek(SeekFrom::Current(0)).unwrap() - i;
|
||||||
rbml_w.end_tag();
|
rbml_w.end_tag();
|
||||||
|
|
||||||
i = rbml_w.writer.seek(SeekFrom::Current(0)).unwrap();
|
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;
|
stats.index_bytes = rbml_w.writer.seek(SeekFrom::Current(0)).unwrap() - i;
|
||||||
|
|
||||||
i = rbml_w.writer.seek(SeekFrom::Current(0)).unwrap();
|
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;
|
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();
|
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() {
|
for e in rbml_w.writer.get_ref() {
|
||||||
if *e == 0 {
|
if *e == 0 {
|
||||||
stats.zero_bytes += 1;
|
stats.zero_bytes += 1;
|
||||||
|
|
|
@ -59,3 +59,4 @@ pub mod cstore;
|
||||||
pub mod index;
|
pub mod index;
|
||||||
pub mod loader;
|
pub mod loader;
|
||||||
pub mod macro_import;
|
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 {
|
fn peek(&self) -> char {
|
||||||
self.data[self.pos] as char
|
self.data[self.pos] as char
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue