about summary refs log tree commit diff
diff options
context:
space:
mode:
authorEduard Burtescu <edy.burt@gmail.com>2016-09-19 23:46:31 +0300
committerEduard Burtescu <edy.burt@gmail.com>2016-09-20 19:21:33 +0300
commitd47fd9eb5a6cb18ab1e11febcef04b0a919e8bcb (patch)
tree357fc24b4f1877ea8e3d9610529cf5eb454eaa70
parent82197287a204376ac6c1aa102f8af79bd20246cf (diff)
downloadrust-d47fd9eb5a6cb18ab1e11febcef04b0a919e8bcb.tar.gz
rust-d47fd9eb5a6cb18ab1e11febcef04b0a919e8bcb.zip
rustc_metadata: use specialization for {en,de}coding Ty and Substs.
-rw-r--r--src/librustc/middle/cstore.rs120
-rw-r--r--src/librustc/ty/mod.rs23
-rw-r--r--src/librustc/ty/sty.rs4
-rw-r--r--src/librustc/ty/subst.rs24
-rw-r--r--src/librustc_metadata/encoder.rs45
-rw-r--r--src/librustc_metadata/lib.rs1
-rw-r--r--src/librustc_metadata/tls_context.rs22
7 files changed, 71 insertions, 168 deletions
diff --git a/src/librustc/middle/cstore.rs b/src/librustc/middle/cstore.rs
index b2c293a290a..9dacb9062c1 100644
--- a/src/librustc/middle/cstore.rs
+++ b/src/librustc/middle/cstore.rs
@@ -509,85 +509,20 @@ pub trait MacroLoader {
 /// Note, however, that this only works for RBML-based encoding and decoding at
 /// the moment.
 pub mod tls {
-    use rbml::opaque::Encoder as OpaqueEncoder;
     use rbml::opaque::Decoder as OpaqueDecoder;
-    use serialize;
     use std::cell::Cell;
-    use std::mem;
-    use ty::{self, Ty, TyCtxt};
+    use ty::{Ty, TyCtxt};
     use ty::subst::Substs;
     use hir::def_id::DefId;
 
-    pub trait EncodingContext<'tcx> {
-        fn tcx<'a>(&'a self) -> TyCtxt<'a, 'tcx, 'tcx>;
-        fn encode_ty(&self, encoder: &mut OpaqueEncoder, t: Ty<'tcx>);
-        fn encode_substs(&self, encoder: &mut OpaqueEncoder, substs: &Substs<'tcx>);
-    }
-
     /// Marker type used for the TLS slot.
     /// The type context cannot be used directly because the TLS
     /// in libstd doesn't allow types generic over lifetimes.
     struct TlsPayload;
 
-    thread_local! {
-        static TLS_ENCODING: Cell<Option<*const TlsPayload>> = Cell::new(None)
-    }
-
-    /// Execute f after pushing the given EncodingContext onto the TLS stack.
-    pub fn enter_encoding_context<'tcx, F, R>(ecx: &EncodingContext<'tcx>,
-                                              encoder: &mut OpaqueEncoder,
-                                              f: F) -> R
-        where F: FnOnce(&EncodingContext<'tcx>, &mut OpaqueEncoder) -> R
-    {
-        let tls_payload = (ecx as *const _, encoder as *mut _);
-        let tls_ptr = &tls_payload as *const _ as *const TlsPayload;
-        TLS_ENCODING.with(|tls| {
-            let prev = tls.get();
-            tls.set(Some(tls_ptr));
-            let ret = f(ecx, encoder);
-            tls.set(prev);
-            return ret
-        })
-    }
-
-    /// 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 OpaqueEncoder) -> R,
-              E: serialize::Encoder
-    {
-        unsafe {
-            unsafe_with_encoding_context(|ecx, tls_encoder| {
-                assert!(encoder as *mut _ as usize == tls_encoder as *mut _ as usize);
-
-                let ecx: &EncodingContext<'tcx> = mem::transmute(ecx);
-
-                f(ecx, tls_encoder)
-            })
-        }
-    }
-
-    /// 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 OpaqueEncoder) -> R
-    {
-        TLS_ENCODING.with(|tls| {
-            let tls = tls.get().unwrap();
-            let tls_payload = tls as *mut (&EncodingContext, &mut OpaqueEncoder);
-            f((*tls_payload).0, (*tls_payload).1)
-        })
-    }
-
     pub trait DecodingContext<'tcx> {
         fn tcx<'a>(&'a self) -> TyCtxt<'a, 'tcx, 'tcx>;
-        fn decode_ty(&self, decoder: &mut OpaqueDecoder) -> ty::Ty<'tcx>;
+        fn decode_ty(&self, decoder: &mut OpaqueDecoder) -> Ty<'tcx>;
         fn decode_substs(&self, decoder: &mut OpaqueDecoder) -> &'tcx Substs<'tcx>;
         fn translate_def_id(&self, def_id: DefId) -> DefId;
     }
@@ -597,56 +532,31 @@ pub mod tls {
     }
 
     /// Execute f after pushing the given DecodingContext onto the TLS stack.
-    pub fn enter_decoding_context<'tcx, F, R>(dcx: &DecodingContext<'tcx>,
-                                              decoder: &mut OpaqueDecoder,
-                                              f: F) -> R
-        where F: FnOnce(&DecodingContext<'tcx>, &mut OpaqueDecoder) -> R
+    pub fn enter_decoding_context<'tcx, F, R>(dcx: &DecodingContext<'tcx>, f: F) -> R
+        where F: FnOnce(&DecodingContext<'tcx>) -> R
     {
-        let tls_payload = (dcx as *const _, decoder as *mut _);
+        let tls_payload = dcx as *const _;
         let tls_ptr = &tls_payload as *const _ as *const TlsPayload;
         TLS_DECODING.with(|tls| {
             let prev = tls.get();
             tls.set(Some(tls_ptr));
-            let ret = f(dcx, decoder);
+            let ret = f(dcx);
             tls.set(prev);
-            return ret
+            ret
         })
     }
 
-    /// 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 OpaqueDecoder) -> R,
-              'tcx: 'decoder
+    /// Execute f with access to the thread-local decoding context.
+    /// FIXME(eddyb) This is horribly unsound as it allows the
+    /// caler to pick any lifetime for 'tcx, including 'static.
+    pub fn with_decoding_context<'tcx, F, R>(f: F) -> R
+        where F: FnOnce(&DecodingContext<'tcx>) -> R,
     {
         unsafe {
-            unsafe_with_decoding_context(|dcx, decoder| {
-                assert!((d as *mut _ as usize) == (decoder as *mut _ as usize));
-
-                let dcx: &DecodingContext<'tcx> = mem::transmute(dcx);
-
-                f(dcx, decoder)
+            TLS_DECODING.with(|tls| {
+                let tls = tls.get().unwrap();
+                f(*(tls as *mut &DecodingContext))
             })
         }
     }
-
-    /// 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 OpaqueDecoder) -> R
-    {
-        TLS_DECODING.with(|tls| {
-            let tls = tls.get().unwrap();
-            let tls_payload = tls as *mut (&DecodingContext, &mut OpaqueDecoder);
-            f((*tls_payload).0, (*tls_payload).1)
-        })
-    }
 }
diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs
index 14eb2fb7914..716b4672ec7 100644
--- a/src/librustc/ty/mod.rs
+++ b/src/librustc/ty/mod.rs
@@ -34,7 +34,7 @@ use util::common::MemoizationMap;
 use util::nodemap::NodeSet;
 use util::nodemap::FnvHashMap;
 
-use serialize::{Encodable, Encoder, Decodable, Decoder};
+use serialize::{self, Encodable, Encoder, Decodable, Decoder};
 use std::borrow::Cow;
 use std::cell::Cell;
 use std::hash::{Hash, Hasher};
@@ -567,23 +567,8 @@ impl<'tcx> Hash for TyS<'tcx> {
 
 pub type Ty<'tcx> = &'tcx TyS<'tcx>;
 
-impl<'tcx> Encodable for Ty<'tcx> {
-    fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
-        cstore::tls::with_encoding_context(s, |ecx, rbml_w| {
-            ecx.encode_ty(rbml_w, *self);
-            Ok(())
-        })
-    }
-}
-
-impl<'tcx> Decodable for Ty<'tcx> {
-    fn decode<D: Decoder>(d: &mut D) -> Result<Ty<'tcx>, D::Error> {
-        cstore::tls::with_decoding_context(d, |dcx, rbml_r| {
-            Ok(dcx.decode_ty(rbml_r))
-        })
-    }
-}
-
+impl<'tcx> serialize::UseSpecializedEncodable for Ty<'tcx> {}
+impl<'tcx> serialize::UseSpecializedDecodable for Ty<'tcx> {}
 
 /// 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
@@ -1506,7 +1491,7 @@ impl<'tcx> Decodable for AdtDef<'tcx> {
     fn decode<D: Decoder>(d: &mut D) -> Result<AdtDef<'tcx>, D::Error> {
         let def_id: DefId = Decodable::decode(d)?;
 
-        cstore::tls::with_decoding_context(d, |dcx, _| {
+        cstore::tls::with_decoding_context(|dcx| {
             let def_id = dcx.translate_def_id(def_id);
             Ok(dcx.tcx().lookup_adt_def(def_id))
         })
diff --git a/src/librustc/ty/sty.rs b/src/librustc/ty/sty.rs
index 5fdc7abc0af..5f02b1be44a 100644
--- a/src/librustc/ty/sty.rs
+++ b/src/librustc/ty/sty.rs
@@ -275,7 +275,7 @@ impl<'tcx> Encodable for ClosureSubsts<'tcx> {
 impl<'tcx> Decodable for ClosureSubsts<'tcx> {
     fn decode<D: Decoder>(d: &mut D) -> Result<ClosureSubsts<'tcx>, D::Error> {
         let (func_substs, upvar_tys) = Decodable::decode(d)?;
-        cstore::tls::with_decoding_context(d, |dcx, _| {
+        cstore::tls::with_decoding_context(|dcx| {
             Ok(ClosureSubsts {
                 func_substs: func_substs,
                 upvar_tys: dcx.tcx().mk_type_list(upvar_tys)
@@ -666,7 +666,7 @@ pub enum Region {
 impl<'tcx> Decodable for &'tcx Region {
     fn decode<D: Decoder>(d: &mut D) -> Result<&'tcx Region, D::Error> {
         let r = Decodable::decode(d)?;
-        cstore::tls::with_decoding_context(d, |dcx, _| {
+        cstore::tls::with_decoding_context(|dcx| {
             Ok(dcx.tcx().mk_region(r))
         })
     }
diff --git a/src/librustc/ty/subst.rs b/src/librustc/ty/subst.rs
index 0ccfea23309..6b493118bcf 100644
--- a/src/librustc/ty/subst.rs
+++ b/src/librustc/ty/subst.rs
@@ -10,12 +10,11 @@
 
 // Type substitutions.
 
-use middle::cstore;
 use hir::def_id::DefId;
 use ty::{self, Ty, TyCtxt};
 use ty::fold::{TypeFoldable, TypeFolder, TypeVisitor};
 
-use serialize::{Encodable, Encoder, Decodable, Decoder};
+use serialize;
 use syntax_pos::{Span, DUMMY_SP};
 
 use core::nonzero::NonZero;
@@ -298,25 +297,8 @@ impl<'tcx> TypeFoldable<'tcx> for &'tcx Substs<'tcx> {
     }
 }
 
-impl<'tcx> Encodable for &'tcx 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 &'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| {
-            dcx.decode_substs(rbml_r)
-        });
-
-        Ok(substs)
-    }
-}
-
+impl<'tcx> serialize::UseSpecializedEncodable for &'tcx Substs<'tcx> {}
+impl<'tcx> serialize::UseSpecializedDecodable for &'tcx Substs<'tcx> {}
 
 ///////////////////////////////////////////////////////////////////////////
 // Public trait `Subst`
diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs
index 4bc8caf037a..3b6984a8c46 100644
--- a/src/librustc_metadata/encoder.rs
+++ b/src/librustc_metadata/encoder.rs
@@ -28,13 +28,14 @@ use middle::dependency_format::Linkage;
 use rustc::dep_graph::DepNode;
 use rustc::traits::specialization_graph;
 use rustc::ty::{self, Ty, TyCtxt};
+use rustc::ty::subst::Substs;
 
 use rustc::hir::svh::Svh;
 use rustc::mir::mir_map::MirMap;
 use rustc::session::config::{self, PanicStrategy, CrateTypeRustcMacro};
 use rustc::util::nodemap::{FnvHashMap, NodeSet};
 
-use rustc_serialize::Encodable;
+use rustc_serialize::{Encodable, SpecializedEncoder, SpecializedDecoder};
 use std::cell::RefCell;
 use std::io::prelude::*;
 use std::io::{Cursor, SeekFrom};
@@ -78,6 +79,48 @@ impl<'a, 'tcx> DerefMut for EncodeContext<'a, 'tcx> {
     }
 }
 
+impl<'a, 'tcx> SpecializedEncoder<Ty<'tcx>> for EncodeContext<'a, 'tcx> {
+    fn specialized_encode(&mut self, ty: &Ty<'tcx>) -> Result<(), Self::Error> {
+        let cx = self.ty_str_ctxt();
+        self.emit_opaque(|opaque_encoder| {
+            Ok(tyencode::enc_ty(opaque_encoder.cursor, &cx, ty))
+        })
+    }
+}
+
+impl<'a, 'tcx> SpecializedEncoder<&'tcx Substs<'tcx>> for EncodeContext<'a, 'tcx> {
+    fn specialized_encode(&mut self, substs: &&'tcx Substs<'tcx>) -> Result<(), Self::Error> {
+        let cx = self.ty_str_ctxt();
+        self.emit_opaque(|opaque_encoder| {
+            Ok(tyencode::enc_substs(opaque_encoder.cursor, &cx, substs))
+        })
+    }
+}
+
+/// FIXME(#31844) This is horribly unsound as it allows the
+/// caller to pick any lifetime for 'tcx, including 'static.
+impl<'a, 'tcx> SpecializedDecoder<Ty<'tcx>> for ::rbml::reader::Decoder<'a> {
+    fn specialized_decode(&mut self) -> Result<Ty<'tcx>, Self::Error> {
+        self.read_opaque(|opaque_decoder, _| {
+            ::middle::cstore::tls::with_decoding_context(|dcx| {
+                Ok(dcx.decode_ty(opaque_decoder))
+            })
+        })
+    }
+}
+
+/// FIXME(#31844) This is horribly unsound as it allows the
+/// caller to pick any lifetime for 'tcx, including 'static.
+impl<'a, 'tcx> SpecializedDecoder<&'tcx Substs<'tcx>> for ::rbml::reader::Decoder<'a> {
+    fn specialized_decode(&mut self) -> Result<&'tcx Substs<'tcx>, Self::Error> {
+        self.read_opaque(|opaque_decoder, _| {
+            ::middle::cstore::tls::with_decoding_context(|dcx| {
+                Ok(dcx.decode_substs(opaque_decoder))
+            })
+        })
+    }
+}
+
 fn encode_name(ecx: &mut EncodeContext, name: Name) {
     ecx.wr_tagged_str(tag_paths_data_name, &name.as_str());
 }
diff --git a/src/librustc_metadata/lib.rs b/src/librustc_metadata/lib.rs
index d0d3d822f86..d9d103beaf0 100644
--- a/src/librustc_metadata/lib.rs
+++ b/src/librustc_metadata/lib.rs
@@ -26,6 +26,7 @@
 #![feature(rustc_macro_lib)]
 #![feature(rustc_macro_internals)]
 #![feature(rustc_private)]
+#![feature(specialization)]
 #![feature(staged_api)]
 #![cfg_attr(test, feature(test))]
 
diff --git a/src/librustc_metadata/tls_context.rs b/src/librustc_metadata/tls_context.rs
index 6e78cbcd28e..da6d04fc0ef 100644
--- a/src/librustc_metadata/tls_context.rs
+++ b/src/librustc_metadata/tls_context.rs
@@ -11,32 +11,14 @@
 // This module provides implementations for the thread-local encoding and
 // decoding context traits in rustc::middle::cstore::tls.
 
-use rbml::opaque::Encoder as OpaqueEncoder;
 use rbml::opaque::Decoder as OpaqueDecoder;
 use rustc::middle::cstore::tls;
 use rustc::hir::def_id::DefId;
 use rustc::ty::subst::Substs;
-use rustc::ty::{self, TyCtxt};
+use rustc::ty::{Ty, TyCtxt};
 
 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) -> TyCtxt<'s, 'tcx, 'tcx> {
-        self.tcx
-    }
-
-    fn encode_ty(&self, encoder: &mut OpaqueEncoder, t: ty::Ty<'tcx>) {
-        tyencode::enc_ty(encoder.cursor, &self.ty_str_ctxt(), t);
-    }
-
-    fn encode_substs(&self, encoder: &mut OpaqueEncoder, substs: &Substs<'tcx>) {
-        tyencode::enc_substs(encoder.cursor, &self.ty_str_ctxt(), substs);
-    }
-}
 
 pub struct DecodingContext<'a, 'tcx: 'a> {
     pub crate_metadata: Cmd<'a>,
@@ -49,7 +31,7 @@ impl<'a, 'tcx: 'a> tls::DecodingContext<'tcx> for DecodingContext<'a, 'tcx> {
         self.tcx
     }
 
-    fn decode_ty(&self, decoder: &mut OpaqueDecoder) -> ty::Ty<'tcx> {
+    fn decode_ty(&self, decoder: &mut OpaqueDecoder) -> Ty<'tcx> {
         let def_id_convert = &mut |did| {
             decoder::translate_def_id(self.crate_metadata, did)
         };