rustc_metadata: use specialization for {en,de}coding Ty and Substs.
This commit is contained in:
parent
82197287a2
commit
d47fd9eb5a
7 changed files with 71 additions and 168 deletions
|
@ -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)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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))
|
||||
})
|
||||
|
|
|
@ -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))
|
||||
})
|
||||
}
|
||||
|
|
|
@ -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`
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
|
|
|
@ -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))]
|
||||
|
||||
|
|
|
@ -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)
|
||||
};
|
||||
|
|
Loading…
Add table
Reference in a new issue