rust/src/librustc/metadata/tyencode.rs

474 lines
14 KiB
Rust
Raw Normal View History

// Copyright 2012-2014 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.
// Type encoding
#![allow(unused_must_use)] // as with encoding, everything is a no-fail MemWriter
#![allow(non_camel_case_types)]
2014-01-29 18:42:19 -08:00
use std::cell::RefCell;
use middle::region;
use middle::subst;
use middle::subst::VecPerParamSpace;
use middle::ty::ParamTy;
use middle::ty::{mod, Ty};
use util::nodemap::FnvHashMap;
use syntax::abi::Abi;
use syntax::ast;
use syntax::diagnostic::SpanHandler;
use syntax::parse::token;
2014-07-29 18:27:28 -07:00
use rbml::io::SeekableMemWriter;
remove seek from std::io::MemWriter, add SeekableMemWriter to librustc Not all users of MemWriter need to seek, but having MemWriter seekable adds between 3-29% in overhead in certain circumstances. This fixes that performance gap by making a non-seekable MemWriter, and creating a new SeekableMemWriter for those circumstances when that functionality is actually needed. ``` test io::mem::test::bench_buf_reader ... bench: 682 ns/iter (+/- 85) test io::mem::test::bench_buf_writer ... bench: 580 ns/iter (+/- 57) test io::mem::test::bench_mem_reader ... bench: 793 ns/iter (+/- 99) test io::mem::test::bench_mem_writer_001_0000 ... bench: 48 ns/iter (+/- 27) test io::mem::test::bench_mem_writer_001_0010 ... bench: 65 ns/iter (+/- 27) = 153 MB/s test io::mem::test::bench_mem_writer_001_0100 ... bench: 132 ns/iter (+/- 12) = 757 MB/s test io::mem::test::bench_mem_writer_001_1000 ... bench: 802 ns/iter (+/- 151) = 1246 MB/s test io::mem::test::bench_mem_writer_100_0000 ... bench: 481 ns/iter (+/- 28) test io::mem::test::bench_mem_writer_100_0010 ... bench: 1957 ns/iter (+/- 126) = 510 MB/s test io::mem::test::bench_mem_writer_100_0100 ... bench: 8222 ns/iter (+/- 434) = 1216 MB/s test io::mem::test::bench_mem_writer_100_1000 ... bench: 82496 ns/iter (+/- 11191) = 1212 MB/s test io::mem::test::bench_seekable_mem_writer_001_0000 ... bench: 48 ns/iter (+/- 2) test io::mem::test::bench_seekable_mem_writer_001_0010 ... bench: 64 ns/iter (+/- 2) = 156 MB/s test io::mem::test::bench_seekable_mem_writer_001_0100 ... bench: 129 ns/iter (+/- 7) = 775 MB/s test io::mem::test::bench_seekable_mem_writer_001_1000 ... bench: 801 ns/iter (+/- 159) = 1248 MB/s test io::mem::test::bench_seekable_mem_writer_100_0000 ... bench: 711 ns/iter (+/- 51) test io::mem::test::bench_seekable_mem_writer_100_0010 ... bench: 2532 ns/iter (+/- 227) = 394 MB/s test io::mem::test::bench_seekable_mem_writer_100_0100 ... bench: 8962 ns/iter (+/- 947) = 1115 MB/s test io::mem::test::bench_seekable_mem_writer_100_1000 ... bench: 85086 ns/iter (+/- 11555) = 1175 MB/s ``` [breaking-change]
2014-07-29 16:31:39 -07:00
macro_rules! mywrite { ($($arg:tt)*) => ({ write!($($arg)*); }) }
2013-10-21 17:11:42 -07:00
pub struct ctxt<'a, 'tcx: 'a> {
pub diag: &'a SpanHandler,
2011-09-02 15:34:58 -07:00
// Def -> str Callback:
pub ds: fn(ast::DefId) -> String,
2011-09-02 15:34:58 -07:00
// The type context.
pub tcx: &'a ty::ctxt<'tcx>,
pub abbrevs: &'a abbrev_map<'tcx>
}
// Compact string representation for Ty values. API ty_str & parse_from_str.
// Extra parameters are for converting to/from def_ids in the string rep.
// Whatever format you choose should not contain pipe characters.
pub struct ty_abbrev {
s: String
}
pub type abbrev_map<'tcx> = RefCell<FnvHashMap<Ty<'tcx>, ty_abbrev>>;
pub fn enc_ty<'a, 'tcx>(w: &mut SeekableMemWriter, cx: &ctxt<'a, 'tcx>, t: Ty<'tcx>) {
2014-11-06 12:25:16 -05:00
match cx.abbrevs.borrow_mut().get(&t) {
Some(a) => { w.write(a.s.as_bytes()); return; }
None => {}
}
let pos = w.tell().unwrap();
match t.sty {
ty::ty_bool => mywrite!(w, "b"),
ty::ty_char => mywrite!(w, "c"),
ty::ty_int(t) => {
match t {
ast::TyI => mywrite!(w, "i"),
ast::TyI8 => mywrite!(w, "MB"),
ast::TyI16 => mywrite!(w, "MW"),
ast::TyI32 => mywrite!(w, "ML"),
ast::TyI64 => mywrite!(w, "MD")
}
}
ty::ty_uint(t) => {
match t {
ast::TyU => mywrite!(w, "u"),
ast::TyU8 => mywrite!(w, "Mb"),
ast::TyU16 => mywrite!(w, "Mw"),
ast::TyU32 => mywrite!(w, "Ml"),
ast::TyU64 => mywrite!(w, "Md")
}
}
ty::ty_float(t) => {
match t {
ast::TyF32 => mywrite!(w, "Mf"),
ast::TyF64 => mywrite!(w, "MF"),
}
}
2014-12-26 22:33:56 +11:00
ty::ty_enum(def, substs) => {
mywrite!(w, "t[{}|", (cx.ds)(def));
enc_substs(w, cx, substs);
mywrite!(w, "]");
}
ty::ty_trait(box ty::TyTrait { ref principal,
ref bounds }) => {
mywrite!(w, "x[");
enc_trait_ref(w, cx, &*principal.0);
enc_existential_bounds(w, cx, bounds);
mywrite!(w, "]");
}
ty::ty_tup(ref ts) => {
mywrite!(w, "T[");
for t in ts.iter() { enc_ty(w, cx, *t); }
mywrite!(w, "]");
}
ty::ty_uniq(typ) => { mywrite!(w, "~"); enc_ty(w, cx, typ); }
ty::ty_ptr(mt) => { mywrite!(w, "*"); enc_mt(w, cx, mt); }
ty::ty_rptr(r, mt) => {
mywrite!(w, "&");
2014-12-26 22:33:56 +11:00
enc_region(w, cx, *r);
enc_mt(w, cx, mt);
}
ty::ty_vec(t, sz) => {
mywrite!(w, "V");
enc_ty(w, cx, t);
mywrite!(w, "/");
match sz {
Some(n) => mywrite!(w, "{}|", n),
None => mywrite!(w, "|"),
}
}
ty::ty_str => {
mywrite!(w, "v");
}
ty::ty_closure(ref f) => {
mywrite!(w, "f");
enc_closure_ty(w, cx, &**f);
}
2014-12-26 22:33:56 +11:00
ty::ty_bare_fn(Some(def_id), f) => {
mywrite!(w, "F");
mywrite!(w, "{}|", (cx.ds)(def_id));
enc_bare_fn_ty(w, cx, f);
}
2014-12-26 22:33:56 +11:00
ty::ty_bare_fn(None, f) => {
mywrite!(w, "G");
enc_bare_fn_ty(w, cx, f);
}
ty::ty_infer(_) => {
cx.diag.handler().bug("cannot encode inference variable types");
}
ty::ty_param(ParamTy {space, idx: id, def_id: did}) => {
mywrite!(w, "p{}|{}|{}|", (cx.ds)(did), id, space.to_uint())
}
2014-12-26 22:33:56 +11:00
ty::ty_struct(def, substs) => {
mywrite!(w, "a[{}|", (cx.ds)(def));
enc_substs(w, cx, substs);
mywrite!(w, "]");
}
2014-12-26 22:33:56 +11:00
ty::ty_unboxed_closure(def, region, substs) => {
mywrite!(w, "k[{}|", (cx.ds)(def));
2014-12-26 22:33:56 +11:00
enc_region(w, cx, *region);
enc_substs(w, cx, substs);
mywrite!(w, "]");
}
ty::ty_projection(ref data) => {
mywrite!(w, "P[");
enc_trait_ref(w, cx, &*data.trait_ref);
mywrite!(w, "{}]", token::get_name(data.item_name));
}
ty::ty_err => {
mywrite!(w, "e");
}
ty::ty_open(_) => {
cx.diag.handler().bug("unexpected type in enc_sty (ty_open)");
}
}
let end = w.tell().unwrap();
let len = end - pos;
fn estimate_sz(u: u64) -> u64 {
let mut n = u;
let mut len = 0;
while n != 0 { len += 1; n = n >> 4; }
return len;
}
let abbrev_len = 3 + estimate_sz(pos) + estimate_sz(len);
if abbrev_len < len {
// I.e. it's actually an abbreviation.
cx.abbrevs.borrow_mut().insert(t, ty_abbrev {
s: format!("#{:x}:{:x}#", pos, len)
});
}
}
remove seek from std::io::MemWriter, add SeekableMemWriter to librustc Not all users of MemWriter need to seek, but having MemWriter seekable adds between 3-29% in overhead in certain circumstances. This fixes that performance gap by making a non-seekable MemWriter, and creating a new SeekableMemWriter for those circumstances when that functionality is actually needed. ``` test io::mem::test::bench_buf_reader ... bench: 682 ns/iter (+/- 85) test io::mem::test::bench_buf_writer ... bench: 580 ns/iter (+/- 57) test io::mem::test::bench_mem_reader ... bench: 793 ns/iter (+/- 99) test io::mem::test::bench_mem_writer_001_0000 ... bench: 48 ns/iter (+/- 27) test io::mem::test::bench_mem_writer_001_0010 ... bench: 65 ns/iter (+/- 27) = 153 MB/s test io::mem::test::bench_mem_writer_001_0100 ... bench: 132 ns/iter (+/- 12) = 757 MB/s test io::mem::test::bench_mem_writer_001_1000 ... bench: 802 ns/iter (+/- 151) = 1246 MB/s test io::mem::test::bench_mem_writer_100_0000 ... bench: 481 ns/iter (+/- 28) test io::mem::test::bench_mem_writer_100_0010 ... bench: 1957 ns/iter (+/- 126) = 510 MB/s test io::mem::test::bench_mem_writer_100_0100 ... bench: 8222 ns/iter (+/- 434) = 1216 MB/s test io::mem::test::bench_mem_writer_100_1000 ... bench: 82496 ns/iter (+/- 11191) = 1212 MB/s test io::mem::test::bench_seekable_mem_writer_001_0000 ... bench: 48 ns/iter (+/- 2) test io::mem::test::bench_seekable_mem_writer_001_0010 ... bench: 64 ns/iter (+/- 2) = 156 MB/s test io::mem::test::bench_seekable_mem_writer_001_0100 ... bench: 129 ns/iter (+/- 7) = 775 MB/s test io::mem::test::bench_seekable_mem_writer_001_1000 ... bench: 801 ns/iter (+/- 159) = 1248 MB/s test io::mem::test::bench_seekable_mem_writer_100_0000 ... bench: 711 ns/iter (+/- 51) test io::mem::test::bench_seekable_mem_writer_100_0010 ... bench: 2532 ns/iter (+/- 227) = 394 MB/s test io::mem::test::bench_seekable_mem_writer_100_0100 ... bench: 8962 ns/iter (+/- 947) = 1115 MB/s test io::mem::test::bench_seekable_mem_writer_100_1000 ... bench: 85086 ns/iter (+/- 11555) = 1175 MB/s ``` [breaking-change]
2014-07-29 16:31:39 -07:00
fn enc_mutability(w: &mut SeekableMemWriter, mt: ast::Mutability) {
match mt {
ast::MutImmutable => (),
ast::MutMutable => mywrite!(w, "m"),
}
}
fn enc_mt<'a, 'tcx>(w: &mut SeekableMemWriter, cx: &ctxt<'a, 'tcx>,
mt: ty::mt<'tcx>) {
enc_mutability(w, mt.mutbl);
enc_ty(w, cx, mt.ty);
}
2014-12-08 20:26:43 -05:00
fn enc_opt<T, F>(w: &mut SeekableMemWriter, t: Option<T>, enc_f: F) where
F: FnOnce(&mut SeekableMemWriter, T),
{
match t {
2013-10-21 17:11:42 -07:00
None => mywrite!(w, "n"),
Some(v) => {
mywrite!(w, "s");
enc_f(w, v);
2013-10-21 17:11:42 -07:00
}
}
}
2014-12-08 20:26:43 -05:00
fn enc_vec_per_param_space<'a, 'tcx, T, F>(w: &mut SeekableMemWriter,
cx: &ctxt<'a, 'tcx>,
v: &VecPerParamSpace<T>,
mut op: F) where
F: FnMut(&mut SeekableMemWriter, &ctxt<'a, 'tcx>, &T),
{
for &space in subst::ParamSpace::all().iter() {
mywrite!(w, "[");
for t in v.get_slice(space).iter() {
op(w, cx, t);
}
mywrite!(w, "]");
}
}
pub fn enc_substs<'a, 'tcx>(w: &mut SeekableMemWriter, cx: &ctxt<'a, 'tcx>,
substs: &subst::Substs<'tcx>) {
enc_region_substs(w, cx, &substs.regions);
enc_vec_per_param_space(w, cx, &substs.types,
|w, cx, &ty| enc_ty(w, cx, ty));
}
remove seek from std::io::MemWriter, add SeekableMemWriter to librustc Not all users of MemWriter need to seek, but having MemWriter seekable adds between 3-29% in overhead in certain circumstances. This fixes that performance gap by making a non-seekable MemWriter, and creating a new SeekableMemWriter for those circumstances when that functionality is actually needed. ``` test io::mem::test::bench_buf_reader ... bench: 682 ns/iter (+/- 85) test io::mem::test::bench_buf_writer ... bench: 580 ns/iter (+/- 57) test io::mem::test::bench_mem_reader ... bench: 793 ns/iter (+/- 99) test io::mem::test::bench_mem_writer_001_0000 ... bench: 48 ns/iter (+/- 27) test io::mem::test::bench_mem_writer_001_0010 ... bench: 65 ns/iter (+/- 27) = 153 MB/s test io::mem::test::bench_mem_writer_001_0100 ... bench: 132 ns/iter (+/- 12) = 757 MB/s test io::mem::test::bench_mem_writer_001_1000 ... bench: 802 ns/iter (+/- 151) = 1246 MB/s test io::mem::test::bench_mem_writer_100_0000 ... bench: 481 ns/iter (+/- 28) test io::mem::test::bench_mem_writer_100_0010 ... bench: 1957 ns/iter (+/- 126) = 510 MB/s test io::mem::test::bench_mem_writer_100_0100 ... bench: 8222 ns/iter (+/- 434) = 1216 MB/s test io::mem::test::bench_mem_writer_100_1000 ... bench: 82496 ns/iter (+/- 11191) = 1212 MB/s test io::mem::test::bench_seekable_mem_writer_001_0000 ... bench: 48 ns/iter (+/- 2) test io::mem::test::bench_seekable_mem_writer_001_0010 ... bench: 64 ns/iter (+/- 2) = 156 MB/s test io::mem::test::bench_seekable_mem_writer_001_0100 ... bench: 129 ns/iter (+/- 7) = 775 MB/s test io::mem::test::bench_seekable_mem_writer_001_1000 ... bench: 801 ns/iter (+/- 159) = 1248 MB/s test io::mem::test::bench_seekable_mem_writer_100_0000 ... bench: 711 ns/iter (+/- 51) test io::mem::test::bench_seekable_mem_writer_100_0010 ... bench: 2532 ns/iter (+/- 227) = 394 MB/s test io::mem::test::bench_seekable_mem_writer_100_0100 ... bench: 8962 ns/iter (+/- 947) = 1115 MB/s test io::mem::test::bench_seekable_mem_writer_100_1000 ... bench: 85086 ns/iter (+/- 11555) = 1175 MB/s ``` [breaking-change]
2014-07-29 16:31:39 -07:00
fn enc_region_substs(w: &mut SeekableMemWriter, cx: &ctxt, substs: &subst::RegionSubsts) {
match *substs {
subst::ErasedRegions => {
2013-10-21 17:11:42 -07:00
mywrite!(w, "e");
}
subst::NonerasedRegions(ref regions) => {
2013-10-21 17:11:42 -07:00
mywrite!(w, "n");
enc_vec_per_param_space(w, cx, regions,
|w, cx, &r| enc_region(w, cx, r));
}
}
}
pub fn enc_region(w: &mut SeekableMemWriter, cx: &ctxt, r: ty::Region) {
2012-08-06 12:34:08 -07:00
match r {
2013-10-29 10:34:11 -04:00
ty::ReLateBound(id, br) => {
mywrite!(w, "b[{}|", id.depth);
2013-10-21 17:11:42 -07:00
enc_bound_region(w, cx, br);
mywrite!(w, "]");
}
ty::ReEarlyBound(node_id, space, index, name) => {
mywrite!(w, "B[{}|{}|{}|{}]",
node_id,
space.to_uint(),
index,
token::get_name(name));
2013-10-21 17:11:42 -07:00
}
2013-10-29 10:34:11 -04:00
ty::ReFree(ref fr) => {
mywrite!(w, "f[");
enc_scope(w, cx, fr.scope);
mywrite!(w, "|");
2013-10-21 17:11:42 -07:00
enc_bound_region(w, cx, fr.bound_region);
mywrite!(w, "]");
}
ty::ReScope(scope) => {
mywrite!(w, "s");
enc_scope(w, cx, scope);
mywrite!(w, "|");
}
2013-10-29 10:34:11 -04:00
ty::ReStatic => {
mywrite!(w, "t");
}
2013-10-29 10:34:11 -04:00
ty::ReEmpty => {
mywrite!(w, "e");
}
2013-10-29 10:34:11 -04:00
ty::ReInfer(_) => {
2013-10-21 17:11:42 -07:00
// these should not crop up after typeck
cx.diag.handler().bug("cannot encode region variables");
2013-10-21 17:11:42 -07:00
}
}
}
fn enc_scope(w: &mut SeekableMemWriter, _cx: &ctxt, scope: region::CodeExtent) {
match scope {
region::CodeExtent::Misc(node_id) => mywrite!(w, "M{}", node_id)
}
}
remove seek from std::io::MemWriter, add SeekableMemWriter to librustc Not all users of MemWriter need to seek, but having MemWriter seekable adds between 3-29% in overhead in certain circumstances. This fixes that performance gap by making a non-seekable MemWriter, and creating a new SeekableMemWriter for those circumstances when that functionality is actually needed. ``` test io::mem::test::bench_buf_reader ... bench: 682 ns/iter (+/- 85) test io::mem::test::bench_buf_writer ... bench: 580 ns/iter (+/- 57) test io::mem::test::bench_mem_reader ... bench: 793 ns/iter (+/- 99) test io::mem::test::bench_mem_writer_001_0000 ... bench: 48 ns/iter (+/- 27) test io::mem::test::bench_mem_writer_001_0010 ... bench: 65 ns/iter (+/- 27) = 153 MB/s test io::mem::test::bench_mem_writer_001_0100 ... bench: 132 ns/iter (+/- 12) = 757 MB/s test io::mem::test::bench_mem_writer_001_1000 ... bench: 802 ns/iter (+/- 151) = 1246 MB/s test io::mem::test::bench_mem_writer_100_0000 ... bench: 481 ns/iter (+/- 28) test io::mem::test::bench_mem_writer_100_0010 ... bench: 1957 ns/iter (+/- 126) = 510 MB/s test io::mem::test::bench_mem_writer_100_0100 ... bench: 8222 ns/iter (+/- 434) = 1216 MB/s test io::mem::test::bench_mem_writer_100_1000 ... bench: 82496 ns/iter (+/- 11191) = 1212 MB/s test io::mem::test::bench_seekable_mem_writer_001_0000 ... bench: 48 ns/iter (+/- 2) test io::mem::test::bench_seekable_mem_writer_001_0010 ... bench: 64 ns/iter (+/- 2) = 156 MB/s test io::mem::test::bench_seekable_mem_writer_001_0100 ... bench: 129 ns/iter (+/- 7) = 775 MB/s test io::mem::test::bench_seekable_mem_writer_001_1000 ... bench: 801 ns/iter (+/- 159) = 1248 MB/s test io::mem::test::bench_seekable_mem_writer_100_0000 ... bench: 711 ns/iter (+/- 51) test io::mem::test::bench_seekable_mem_writer_100_0010 ... bench: 2532 ns/iter (+/- 227) = 394 MB/s test io::mem::test::bench_seekable_mem_writer_100_0100 ... bench: 8962 ns/iter (+/- 947) = 1115 MB/s test io::mem::test::bench_seekable_mem_writer_100_1000 ... bench: 85086 ns/iter (+/- 11555) = 1175 MB/s ``` [breaking-change]
2014-07-29 16:31:39 -07:00
fn enc_bound_region(w: &mut SeekableMemWriter, cx: &ctxt, br: ty::BoundRegion) {
2012-08-06 12:34:08 -07:00
match br {
2013-10-29 10:34:11 -04:00
ty::BrAnon(idx) => {
mywrite!(w, "a{}|", idx);
}
ty::BrNamed(d, name) => {
mywrite!(w, "[{}|{}]",
(cx.ds)(d),
token::get_name(name));
}
2013-10-29 10:34:11 -04:00
ty::BrFresh(id) => {
mywrite!(w, "f{}|", id);
}
Fix soundness bug in treatment of closure upvars by regionck - Unify the representations of `cat_upvar` and `cat_copied_upvar` - In `link_reborrowed_region`, account for the ability of upvars to change their mutability due to later processing. A map of recursive region links we may want to establish in the future is maintained, with the links being established when the kind of the borrow is adjusted. - When categorizing upvars, add an explicit deref that represents the closure environment pointer for closures that do not take the environment by value. The region for the implicit pointer is an anonymous free region type introduced for this purpose. This creates the necessary constraint to prevent unsound reborrows from the environment. - Add a note to categorizations to make it easier to tell when extra dereferences have been inserted by an upvar without having to perform deep pattern matching. - Adjust borrowck to deal with the changes. Where `cat_upvar` and `cat_copied_upvar` were previously treated differently, they are now both treated roughly like local variables within the closure body, as the explicit derefs now ensure proper behavior. However, error diagnostics had to be changed to explicitly look through the extra dereferences to avoid producing confusing messages about references not present in the source code. Closes issue #17403. Remaining work: - The error diagnostics that result from failed region inference are pretty inscrutible and should be improved. Code like the following is now rejected: let mut x = 0u; let f = || &mut x; let y = f(); let z = f(); // multiple mutable references to the same location This also breaks code that uses a similar construction even if it does not go on to violate aliasability semantics. Such code will need to be reworked in some way, such as by using a capture-by-value closure type. [breaking-change]
2014-10-07 20:04:45 -07:00
ty::BrEnv => {
mywrite!(w, "e|");
}
2012-03-08 14:05:16 -08:00
}
}
pub fn enc_trait_ref<'a, 'tcx>(w: &mut SeekableMemWriter, cx: &ctxt<'a, 'tcx>,
s: &ty::TraitRef<'tcx>) {
2013-10-21 17:11:42 -07:00
mywrite!(w, "{}|", (cx.ds)(s.def_id));
enc_substs(w, cx, s.substs);
}
remove seek from std::io::MemWriter, add SeekableMemWriter to librustc Not all users of MemWriter need to seek, but having MemWriter seekable adds between 3-29% in overhead in certain circumstances. This fixes that performance gap by making a non-seekable MemWriter, and creating a new SeekableMemWriter for those circumstances when that functionality is actually needed. ``` test io::mem::test::bench_buf_reader ... bench: 682 ns/iter (+/- 85) test io::mem::test::bench_buf_writer ... bench: 580 ns/iter (+/- 57) test io::mem::test::bench_mem_reader ... bench: 793 ns/iter (+/- 99) test io::mem::test::bench_mem_writer_001_0000 ... bench: 48 ns/iter (+/- 27) test io::mem::test::bench_mem_writer_001_0010 ... bench: 65 ns/iter (+/- 27) = 153 MB/s test io::mem::test::bench_mem_writer_001_0100 ... bench: 132 ns/iter (+/- 12) = 757 MB/s test io::mem::test::bench_mem_writer_001_1000 ... bench: 802 ns/iter (+/- 151) = 1246 MB/s test io::mem::test::bench_mem_writer_100_0000 ... bench: 481 ns/iter (+/- 28) test io::mem::test::bench_mem_writer_100_0010 ... bench: 1957 ns/iter (+/- 126) = 510 MB/s test io::mem::test::bench_mem_writer_100_0100 ... bench: 8222 ns/iter (+/- 434) = 1216 MB/s test io::mem::test::bench_mem_writer_100_1000 ... bench: 82496 ns/iter (+/- 11191) = 1212 MB/s test io::mem::test::bench_seekable_mem_writer_001_0000 ... bench: 48 ns/iter (+/- 2) test io::mem::test::bench_seekable_mem_writer_001_0010 ... bench: 64 ns/iter (+/- 2) = 156 MB/s test io::mem::test::bench_seekable_mem_writer_001_0100 ... bench: 129 ns/iter (+/- 7) = 775 MB/s test io::mem::test::bench_seekable_mem_writer_001_1000 ... bench: 801 ns/iter (+/- 159) = 1248 MB/s test io::mem::test::bench_seekable_mem_writer_100_0000 ... bench: 711 ns/iter (+/- 51) test io::mem::test::bench_seekable_mem_writer_100_0010 ... bench: 2532 ns/iter (+/- 227) = 394 MB/s test io::mem::test::bench_seekable_mem_writer_100_0100 ... bench: 8962 ns/iter (+/- 947) = 1115 MB/s test io::mem::test::bench_seekable_mem_writer_100_1000 ... bench: 85086 ns/iter (+/- 11555) = 1175 MB/s ``` [breaking-change]
2014-07-29 16:31:39 -07:00
pub fn enc_trait_store(w: &mut SeekableMemWriter, cx: &ctxt, s: ty::TraitStore) {
match s {
2013-10-21 17:11:42 -07:00
ty::UniqTraitStore => mywrite!(w, "~"),
ty::RegionTraitStore(re, m) => {
2013-10-21 17:11:42 -07:00
mywrite!(w, "&");
enc_region(w, cx, re);
enc_mutability(w, m);
}
}
}
2014-12-09 10:36:46 -05:00
fn enc_unsafety(w: &mut SeekableMemWriter, p: ast::Unsafety) {
2012-08-06 12:34:08 -07:00
match p {
2014-12-09 10:36:46 -05:00
ast::Unsafety::Normal => mywrite!(w, "n"),
ast::Unsafety::Unsafe => mywrite!(w, "u"),
2012-05-24 23:44:58 -07:00
}
}
remove seek from std::io::MemWriter, add SeekableMemWriter to librustc Not all users of MemWriter need to seek, but having MemWriter seekable adds between 3-29% in overhead in certain circumstances. This fixes that performance gap by making a non-seekable MemWriter, and creating a new SeekableMemWriter for those circumstances when that functionality is actually needed. ``` test io::mem::test::bench_buf_reader ... bench: 682 ns/iter (+/- 85) test io::mem::test::bench_buf_writer ... bench: 580 ns/iter (+/- 57) test io::mem::test::bench_mem_reader ... bench: 793 ns/iter (+/- 99) test io::mem::test::bench_mem_writer_001_0000 ... bench: 48 ns/iter (+/- 27) test io::mem::test::bench_mem_writer_001_0010 ... bench: 65 ns/iter (+/- 27) = 153 MB/s test io::mem::test::bench_mem_writer_001_0100 ... bench: 132 ns/iter (+/- 12) = 757 MB/s test io::mem::test::bench_mem_writer_001_1000 ... bench: 802 ns/iter (+/- 151) = 1246 MB/s test io::mem::test::bench_mem_writer_100_0000 ... bench: 481 ns/iter (+/- 28) test io::mem::test::bench_mem_writer_100_0010 ... bench: 1957 ns/iter (+/- 126) = 510 MB/s test io::mem::test::bench_mem_writer_100_0100 ... bench: 8222 ns/iter (+/- 434) = 1216 MB/s test io::mem::test::bench_mem_writer_100_1000 ... bench: 82496 ns/iter (+/- 11191) = 1212 MB/s test io::mem::test::bench_seekable_mem_writer_001_0000 ... bench: 48 ns/iter (+/- 2) test io::mem::test::bench_seekable_mem_writer_001_0010 ... bench: 64 ns/iter (+/- 2) = 156 MB/s test io::mem::test::bench_seekable_mem_writer_001_0100 ... bench: 129 ns/iter (+/- 7) = 775 MB/s test io::mem::test::bench_seekable_mem_writer_001_1000 ... bench: 801 ns/iter (+/- 159) = 1248 MB/s test io::mem::test::bench_seekable_mem_writer_100_0000 ... bench: 711 ns/iter (+/- 51) test io::mem::test::bench_seekable_mem_writer_100_0010 ... bench: 2532 ns/iter (+/- 227) = 394 MB/s test io::mem::test::bench_seekable_mem_writer_100_0100 ... bench: 8962 ns/iter (+/- 947) = 1115 MB/s test io::mem::test::bench_seekable_mem_writer_100_1000 ... bench: 85086 ns/iter (+/- 11555) = 1175 MB/s ``` [breaking-change]
2014-07-29 16:31:39 -07:00
fn enc_abi(w: &mut SeekableMemWriter, abi: Abi) {
2013-10-21 17:11:42 -07:00
mywrite!(w, "[");
mywrite!(w, "{}", abi.name());
2013-10-21 17:11:42 -07:00
mywrite!(w, "]")
}
fn enc_onceness(w: &mut SeekableMemWriter, o: ast::Onceness) {
match o {
ast::Once => mywrite!(w, "o"),
ast::Many => mywrite!(w, "m")
}
}
pub fn enc_bare_fn_ty<'a, 'tcx>(w: &mut SeekableMemWriter, cx: &ctxt<'a, 'tcx>,
ft: &ty::BareFnTy<'tcx>) {
2014-12-09 10:36:46 -05:00
enc_unsafety(w, ft.unsafety);
enc_abi(w, ft.abi);
enc_fn_sig(w, cx, &ft.sig);
}
pub fn enc_closure_ty<'a, 'tcx>(w: &mut SeekableMemWriter, cx: &ctxt<'a, 'tcx>,
ft: &ty::ClosureTy<'tcx>) {
2014-12-09 10:36:46 -05:00
enc_unsafety(w, ft.unsafety);
enc_onceness(w, ft.onceness);
enc_trait_store(w, cx, ft.store);
enc_existential_bounds(w, cx, &ft.bounds);
enc_fn_sig(w, cx, &ft.sig);
enc_abi(w, ft.abi);
}
fn enc_fn_sig<'a, 'tcx>(w: &mut SeekableMemWriter, cx: &ctxt<'a, 'tcx>,
fsig: &ty::PolyFnSig<'tcx>) {
mywrite!(w, "[");
for ty in fsig.0.inputs.iter() {
2013-04-26 19:13:38 -07:00
enc_ty(w, cx, *ty);
}
2013-10-21 17:11:42 -07:00
mywrite!(w, "]");
if fsig.0.variadic {
mywrite!(w, "V");
} else {
mywrite!(w, "N");
}
match fsig.0.output {
ty::FnConverging(result_type) => {
enc_ty(w, cx, result_type);
}
ty::FnDiverging => {
mywrite!(w, "z");
}
}
}
pub fn enc_builtin_bounds(w: &mut SeekableMemWriter, _cx: &ctxt, bs: &ty::BuiltinBounds) {
for bound in bs.iter() {
match bound {
2013-10-21 17:11:42 -07:00
ty::BoundSend => mywrite!(w, "S"),
ty::BoundSized => mywrite!(w, "Z"),
ty::BoundCopy => mywrite!(w, "P"),
ty::BoundSync => mywrite!(w, "T"),
}
2013-07-26 13:53:29 +09:00
}
mywrite!(w, ".");
}
pub fn enc_existential_bounds<'a,'tcx>(w: &mut SeekableMemWriter,
cx: &ctxt<'a,'tcx>,
bs: &ty::ExistentialBounds<'tcx>) {
let param_bounds = ty::ParamBounds { trait_bounds: vec!(),
region_bounds: vec!(bs.region_bound),
builtin_bounds: bs.builtin_bounds,
projection_bounds: bs.projection_bounds.clone() };
enc_bounds(w, cx, &param_bounds);
}
pub fn enc_bounds<'a, 'tcx>(w: &mut SeekableMemWriter, cx: &ctxt<'a, 'tcx>,
bs: &ty::ParamBounds<'tcx>) {
enc_builtin_bounds(w, cx, &bs.builtin_bounds);
for &r in bs.region_bounds.iter() {
mywrite!(w, "R");
enc_region(w, cx, r);
}
2014-04-22 02:21:52 +03:00
for tp in bs.trait_bounds.iter() {
2013-10-21 17:11:42 -07:00
mywrite!(w, "I");
enc_trait_ref(w, cx, &*tp.0);
}
for tp in bs.projection_bounds.iter() {
mywrite!(w, "P");
enc_projection_predicate(w, cx, &tp.0);
}
2013-10-21 17:11:42 -07:00
mywrite!(w, ".");
}
pub fn enc_type_param_def<'a, 'tcx>(w: &mut SeekableMemWriter, cx: &ctxt<'a, 'tcx>,
v: &ty::TypeParameterDef<'tcx>) {
mywrite!(w, "{}:{}|{}|{}|",
token::get_name(v.name), (cx.ds)(v.def_id),
v.space.to_uint(), v.index);
enc_bounds(w, cx, &v.bounds);
enc_opt(w, v.default, |w, t| enc_ty(w, cx, t));
}
pub fn enc_predicate<'a, 'tcx>(w: &mut SeekableMemWriter,
cx: &ctxt<'a, 'tcx>,
p: &ty::Predicate<'tcx>)
{
match *p {
ty::Predicate::Trait(ref trait_ref) => {
mywrite!(w, "t");
enc_trait_ref(w, cx, &*trait_ref.0.trait_ref);
}
ty::Predicate::Equate(ty::Binder(ty::EquatePredicate(a, b))) => {
mywrite!(w, "e");
enc_ty(w, cx, a);
enc_ty(w, cx, b);
}
ty::Predicate::RegionOutlives(ty::Binder(ty::OutlivesPredicate(a, b))) => {
mywrite!(w, "r");
enc_region(w, cx, a);
enc_region(w, cx, b);
}
ty::Predicate::TypeOutlives(ty::Binder(ty::OutlivesPredicate(a, b))) => {
mywrite!(w, "o");
enc_ty(w, cx, a);
enc_region(w, cx, b);
}
ty::Predicate::Projection(ty::Binder(ref data)) => {
mywrite!(w, "p");
enc_projection_predicate(w, cx, data)
}
}
}
fn enc_projection_predicate<'a, 'tcx>(w: &mut SeekableMemWriter,
cx: &ctxt<'a, 'tcx>,
data: &ty::ProjectionPredicate<'tcx>) {
enc_trait_ref(w, cx, &*data.projection_ty.trait_ref);
mywrite!(w, "{}|", token::get_name(data.projection_ty.item_name));
enc_ty(w, cx, data.ty);
}