From d47fd9eb5a6cb18ab1e11febcef04b0a919e8bcb Mon Sep 17 00:00:00 2001 From: Eduard Burtescu Date: Mon, 19 Sep 2016 23:46:31 +0300 Subject: [PATCH] rustc_metadata: use specialization for {en,de}coding Ty and Substs. --- src/librustc/middle/cstore.rs | 120 ++++----------------------- src/librustc/ty/mod.rs | 23 +---- src/librustc/ty/sty.rs | 4 +- src/librustc/ty/subst.rs | 24 +----- src/librustc_metadata/encoder.rs | 45 +++++++++- src/librustc_metadata/lib.rs | 1 + src/librustc_metadata/tls_context.rs | 22 +---- 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> = 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: 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: 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(&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)) - }) - } -} - +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: &mut D) -> Result, 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: &mut D) -> Result, 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: &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(&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: &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> 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> for ::rbml::reader::Decoder<'a> { + fn specialized_decode(&mut self) -> Result, 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) };