rustc_metadata: use specialization for {en,de}coding Ty and Substs.

This commit is contained in:
Eduard Burtescu 2016-09-19 23:46:31 +03:00
parent 82197287a2
commit d47fd9eb5a
7 changed files with 71 additions and 168 deletions

View file

@ -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)
})
}
}

View file

@ -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))
})

View file

@ -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))
})
}

View file

@ -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`

View file

@ -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());
}

View file

@ -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))]

View file

@ -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)
};