]> git.lizzy.rs Git - rust.git/commitdiff
Add scoped thread-local encoding and decoding contexts to cstore.
authorMichael Woerister <michaelwoerister@posteo.net>
Tue, 1 Dec 2015 15:07:15 +0000 (16:07 +0100)
committerMichael Woerister <michaelwoerister@posteo.net>
Wed, 9 Dec 2015 14:47:32 +0000 (09:47 -0500)
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.

12 files changed:
mk/crates.mk
src/librbml/lib.rs
src/librustc/lib.rs
src/librustc/middle/cstore.rs
src/librustc/middle/subst.rs
src/librustc/middle/ty/mod.rs
src/librustc_metadata/astencode.rs
src/librustc_metadata/decoder.rs
src/librustc_metadata/encoder.rs
src/librustc_metadata/lib.rs
src/librustc_metadata/tls_context.rs [new file with mode: 0644]
src/librustc_metadata/tydecode.rs

index 8ce0a41d9786c01c3eee35a481c71cc2b0574118..7ad0a99aadae9f1b4cb5b894828d2eef75887368 100644 (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
index d51280a187c3d62aad044d8744b8e8d15fe5adba..5405b8ea565e20223d88c52d3b73368756f2e859 100644 (file)
@@ -639,6 +639,14 @@ pub fn read_opaque<R, F>(&mut self, op: F) -> DecodeResult<R> where
             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> {
index 8b69767eee0e0a85626d1b61dd6242bdf1bfb13d..e0cb10f1563bfeae3c1072a1b6dacd2e03b35ef8 100644 (file)
@@ -62,6 +62,7 @@
 extern crate getopts;
 extern crate graphviz;
 extern crate libc;
+extern crate rbml;
 extern crate rustc_llvm;
 extern crate rustc_back;
 extern crate rustc_front;
index 81375bd3a5a14bfed03c2bfccccc460224f1c966..eb4e70ac50f2795c2a3303861c3f212fda39233f 100644 (file)
@@ -405,3 +405,141 @@ fn encode_metadata(&self,
                        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)
+        })
+    }
+}
index c44891de0a055356b81400c8d3239b5892f2c211..aa47b32dc3e4df2113fe26ed26a7dcb63f8ffde6 100644 (file)
 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 @@ pub fn method_to_trait(self) -> 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>,
index 71ae8e40b45f0ecbe7c331cb1602ee5626ecd906..7477c4dead031da5db039ae5a6716992eb72a1bf 100644 (file)
@@ -22,7 +22,7 @@
 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::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 @@ fn hash<H: Hasher>(&self, s: &mut H) {
 
 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 @@ fn hash<H: Hasher>(&self, s: &mut H) {
     }
 }
 
+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 }
index 2ecf715424b16cbde1e4885f213146e7e5c8e1c9..563be92bc88f66c066240f4930048af4d55e688c 100644 (file)
@@ -39,7 +39,6 @@
 
 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 @@ fn new_id(&self, id: ast::NodeId) -> ast::NodeId {
     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 @@ pub fn tr_def_id(&self, did: DefId) -> DefId {
     }
 
     /// 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 @@ fn tr(&self, dcx: &DecodeContext) -> 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)
     }
 }
index 092f7849115c3eed714dc13438f7462cf6c1319e..c139ec4f62a5e4a370f365049d76892e53ca370a 100644 (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)
index 1d88fa4454bda19f1bff4bde693d4d3513e7dac3..d836989198c902d178ee3e3d68096d5f8549abb3 100644 (file)
@@ -19,7 +19,7 @@
 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 @@ struct Stats {
         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;
index 6affbd2b5936c4323a08192352ee29e915860c1f..3dea0a5f104137efe65f76618dc65ea8fa495f54 100644 (file)
@@ -59,3 +59,4 @@
 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 (file)
index 0000000..e368ff3
--- /dev/null
@@ -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)
+    }
+}
index d03af6b672284b2accff9b886315e06aa71ad880..d0aa58e04f8de095609ea4f5dc6fa5189a2cdd5f 100644 (file)
@@ -68,6 +68,10 @@ pub fn new(data: &'a [u8],
         }
     }
 
+    pub fn position(&self) -> usize {
+        self.pos
+    }
+
     fn peek(&self) -> char {
         self.data[self.pos] as char
     }