diff --git a/mk/crates.mk b/mk/crates.mk index 8ce0a41d978..7ad0a99aada 100644 --- a/mk/crates.mk +++ b/mk/crates.mk @@ -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 diff --git a/src/librbml/lib.rs b/src/librbml/lib.rs index 9cb160b7dec..3c0c9951613 100644 --- a/src/librbml/lib.rs +++ b/src/librbml/lib.rs @@ -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> { diff --git a/src/librustc/lib.rs b/src/librustc/lib.rs index bd97cb128e9..0890594f2b1 100644 --- a/src/librustc/lib.rs +++ b/src/librustc/lib.rs @@ -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; diff --git a/src/librustc/middle/cstore.rs b/src/librustc/middle/cstore.rs index fba6dea4448..4efa7bfac18 100644 --- a/src/librustc/middle/cstore.rs +++ b/src/librustc/middle/cstore.rs @@ -407,3 +407,141 @@ impl<'tcx> CrateStore<'tcx> for DummyCrateStore { krate: &hir::Crate) -> Vec { 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: 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: 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) + }) + } +} diff --git a/src/librustc/middle/subst.rs b/src/librustc/middle/subst.rs index c44891de0a0..aa47b32dc3e 100644 --- a/src/librustc/middle/subst.rs +++ b/src/librustc/middle/subst.rs @@ -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(&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: &mut D) -> Result, 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: &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(self, op: F) -> RegionSubsts where F: FnOnce(VecPerParamSpace) -> VecPerParamSpace, diff --git a/src/librustc/middle/ty/mod.rs b/src/librustc/middle/ty/mod.rs index 71ae8e40b45..7477c4dead0 100644 --- a/src/librustc/middle/ty/mod.rs +++ b/src/librustc/middle/ty/mod.rs @@ -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(&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: &mut D) -> Result, 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(&self, s: &mut S) -> Result<(), S::Error> { + self.did.encode(s) + } +} + +impl<'tcx> Decodable for AdtDef<'tcx> { + fn decode(d: &mut D) -> Result, 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 } diff --git a/src/librustc_metadata/astencode.rs b/src/librustc_metadata/astencode.rs index 9de7b3b0cc5..4c47d3ab990 100644 --- a/src/librustc_metadata/astencode.rs +++ b/src/librustc_metadata/astencode.rs @@ -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 { } } -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) } } diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs index 092f7849115..c139ec4f62a 100644 --- a/src/librustc_metadata/decoder.rs +++ b/src/librustc_metadata/decoder.rs @@ -1216,6 +1216,64 @@ fn reverse_translate_def_id(cdata: Cmd, did: DefId) -> Option { 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, + 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(cdata: Cmd, id: DefIndex, mut callback: F) diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs index 86ab7edf8dd..448a64c93c1 100644 --- a/src/librustc_metadata/encoder.rs +++ b/src/librustc_metadata/encoder.rs @@ -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 { + 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 { return v; } -fn encode_metadata_inner(wr: &mut Cursor>, - 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>, 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; diff --git a/src/librustc_metadata/lib.rs b/src/librustc_metadata/lib.rs index d2a6b0eaedf..c425ba1386e 100644 --- a/src/librustc_metadata/lib.rs +++ b/src/librustc_metadata/lib.rs @@ -58,3 +58,4 @@ pub mod cstore; pub mod index; pub mod loader; pub mod macro_import; +pub mod tls_context; diff --git a/src/librustc_metadata/tls_context.rs b/src/librustc_metadata/tls_context.rs new file mode 100644 index 00000000000..e368ff3822a --- /dev/null +++ b/src/librustc_metadata/tls_context.rs @@ -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 or the MIT license +// , 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) + } +} diff --git a/src/librustc_metadata/tydecode.rs b/src/librustc_metadata/tydecode.rs index 34f289456bb..64d634859cd 100644 --- a/src/librustc_metadata/tydecode.rs +++ b/src/librustc_metadata/tydecode.rs @@ -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 }