提交 dcb4378e 编写于 作者: B bors

Auto merge of #44646 - petrochenkov:scompress, r=michaelwoerister

Compress most of spans to 32 bits

As described in https://internals.rust-lang.org/t/rfc-compiler-refactoring-spans/1357/28

Closes https://github.com/rust-lang/rust/issues/15594
r? @michaelwoerister
......@@ -221,7 +221,7 @@ fn try_get_with<F, R>(tcx: TyCtxt<'a, $tcx, 'lcx>,
profq_msg!(tcx,
ProfileQueriesMsg::QueryBegin(
span.clone(),
span.data(),
QueryMsg::$name(profq_key!(tcx, key))
)
);
......
......@@ -20,7 +20,7 @@
use std::time::{Duration, Instant};
use std::sync::mpsc::{Sender};
use syntax_pos::{Span};
use syntax_pos::{SpanData};
use ty::maps::{QueryMsg};
use dep_graph::{DepNode};
......@@ -61,7 +61,8 @@ pub enum ProfileQueriesMsg {
/// end a task
TaskEnd,
/// begin a new query
QueryBegin(Span, QueryMsg),
/// can't use `Span` because queries are sent to other thread
QueryBegin(SpanData, QueryMsg),
/// query is satisfied by using an already-known value for the given key
CacheHit,
/// query requires running a provider; providers may nest, permitting queries to nest.
......
......@@ -9,7 +9,7 @@
// except according to those terms.
use super::*;
use syntax_pos::Span;
use syntax_pos::SpanData;
use rustc::ty::maps::QueryMsg;
use std::fs::File;
use std::time::{Duration, Instant};
......@@ -18,7 +18,7 @@
#[derive(Debug, Clone, Eq, PartialEq)]
pub struct Query {
pub span: Span,
pub span: SpanData,
pub msg: QueryMsg,
}
pub enum Effect {
......
......@@ -25,7 +25,7 @@
/// A SyntaxContext represents a chain of macro expansions (represented by marks).
#[derive(Clone, Copy, PartialEq, Eq, Default, PartialOrd, Ord, Hash)]
pub struct SyntaxContext(u32);
pub struct SyntaxContext(pub(super) u32);
#[derive(Copy, Clone, Default)]
pub struct SyntaxContextData {
......
......@@ -25,11 +25,10 @@
#![feature(optin_builtin_traits)]
#![allow(unused_attributes)]
#![feature(specialization)]
#![feature(staged_api)]
use std::borrow::Cow;
use std::cell::{Cell, RefCell};
use std::cmp;
use std::cmp::{self, Ordering};
use std::fmt;
use std::hash::Hasher;
use std::ops::{Add, Sub};
......@@ -47,6 +46,9 @@
pub mod hygiene;
pub use hygiene::{SyntaxContext, ExpnInfo, ExpnFormat, NameAndSpan, CompilerDesugaringKind};
mod span_encoding;
pub use span_encoding::{Span, DUMMY_SP};
pub mod symbol;
pub type FileName = String;
......@@ -59,23 +61,33 @@
/// able to use many of the functions on spans in codemap and you cannot assume
/// that the length of the span = hi - lo; there may be space in the BytePos
/// range between files.
///
/// `SpanData` is public because `Span` uses a thread-local interner and can't be
/// sent to other threads, but some pieces of performance infra run in a separate thread.
/// Using `Span` is generally preferred.
#[derive(Clone, Copy, Hash, PartialEq, Eq, Ord, PartialOrd)]
pub struct Span {
#[unstable(feature = "rustc_private", issue = "27812")]
#[rustc_deprecated(since = "1.21", reason = "use getters/setters instead")]
pub struct SpanData {
pub lo: BytePos,
#[unstable(feature = "rustc_private", issue = "27812")]
#[rustc_deprecated(since = "1.21", reason = "use getters/setters instead")]
pub hi: BytePos,
/// Information about where the macro came from, if this piece of
/// code was created by a macro expansion.
#[unstable(feature = "rustc_private", issue = "27812")]
#[rustc_deprecated(since = "1.21", reason = "use getters/setters instead")]
pub ctxt: SyntaxContext,
}
#[allow(deprecated)]
pub const DUMMY_SP: Span = Span { lo: BytePos(0), hi: BytePos(0), ctxt: NO_EXPANSION };
// The interner in thread-local, so `Span` shouldn't move between threads.
impl !Send for Span {}
impl !Sync for Span {}
impl PartialOrd for Span {
fn partial_cmp(&self, rhs: &Self) -> Option<Ordering> {
PartialOrd::partial_cmp(&self.data(), &rhs.data())
}
}
impl Ord for Span {
fn cmp(&self, rhs: &Self) -> Ordering {
Ord::cmp(&self.data(), &rhs.data())
}
}
/// A collection of spans. Spans have two orthogonal attributes:
///
......@@ -90,38 +102,32 @@ pub struct MultiSpan {
}
impl Span {
#[allow(deprecated)]
#[inline]
pub fn new(lo: BytePos, hi: BytePos, ctxt: SyntaxContext) -> Self {
if lo <= hi { Span { lo, hi, ctxt } } else { Span { lo: hi, hi: lo, ctxt } }
}
#[allow(deprecated)]
#[inline]
pub fn lo(self) -> BytePos {
self.lo
self.data().lo
}
#[inline]
pub fn with_lo(self, lo: BytePos) -> Span {
Span::new(lo, self.hi(), self.ctxt())
let base = self.data();
Span::new(lo, base.hi, base.ctxt)
}
#[allow(deprecated)]
#[inline]
pub fn hi(self) -> BytePos {
self.hi
self.data().hi
}
#[inline]
pub fn with_hi(self, hi: BytePos) -> Span {
Span::new(self.lo(), hi, self.ctxt())
let base = self.data();
Span::new(base.lo, hi, base.ctxt)
}
#[allow(deprecated)]
#[inline]
pub fn ctxt(self) -> SyntaxContext {
self.ctxt
self.data().ctxt
}
#[inline]
pub fn with_ctxt(self, ctxt: SyntaxContext) -> Span {
Span::new(self.lo(), self.hi(), ctxt)
let base = self.data();
Span::new(base.lo, base.hi, ctxt)
}
/// Returns a new span representing just the end-point of this span
......@@ -342,6 +348,12 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
}
}
impl fmt::Debug for SpanData {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
SPAN_DEBUG.with(|span_debug| span_debug.get()(Span::new(self.lo, self.hi, self.ctxt), f))
}
}
impl MultiSpan {
pub fn new() -> MultiSpan {
MultiSpan {
......
// Copyright 2017 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.
// Spans are encoded using 1-bit tag and 2 different encoding formats (one for each tag value).
// One format is used for keeping span data inline,
// another contains index into an out-of-line span interner.
// The encoding format for inline spans were obtained by optimizing over crates in rustc/libstd.
// See https://internals.rust-lang.org/t/rfc-compiler-refactoring-spans/1357/28
use {BytePos, SpanData};
use hygiene::SyntaxContext;
use rustc_data_structures::fx::FxHashMap;
use std::cell::RefCell;
/// A compressed span.
/// Contains either fields of `SpanData` inline if they are small, or index into span interner.
/// The primary goal of `Span` is to be as small as possible and fit into other structures
/// (that's why it uses `packed` as well). Decoding speed is the second priority.
/// See `SpanData` for the info on span fields in decoded representation.
#[derive(Clone, Copy, PartialEq, Eq, Hash)]
#[repr(packed)]
pub struct Span(u32);
/// Dummy span, both position and length are zero, syntax context is zero as well.
/// This span is kept inline and encoded with format 0.
pub const DUMMY_SP: Span = Span(0);
impl Span {
#[inline]
pub fn new(lo: BytePos, hi: BytePos, ctxt: SyntaxContext) -> Self {
encode(&match lo <= hi {
true => SpanData { lo, hi, ctxt },
false => SpanData { lo: hi, hi: lo, ctxt },
})
}
#[inline]
pub fn data(self) -> SpanData {
decode(self)
}
}
// Tags
const TAG_INLINE: u32 = 0;
const TAG_INTERNED: u32 = 1;
const TAG_MASK: u32 = 1;
// Fields indexes
const BASE_INDEX: usize = 0;
const LEN_INDEX: usize = 1;
const CTXT_INDEX: usize = 2;
// Tag = 0, inline format.
// -----------------------------------
// | base 31:8 | len 7:1 | tag 0:0 |
// -----------------------------------
const INLINE_SIZES: [u32; 3] = [24, 7, 0];
const INLINE_OFFSETS: [u32; 3] = [8, 1, 1];
// Tag = 1, interned format.
// ------------------------
// | index 31:1 | tag 0:0 |
// ------------------------
const INTERNED_INDEX_SIZE: u32 = 31;
const INTERNED_INDEX_OFFSET: u32 = 1;
#[inline]
fn encode(sd: &SpanData) -> Span {
let (base, len, ctxt) = (sd.lo.0, sd.hi.0 - sd.lo.0, sd.ctxt.0);
let val = if (base >> INLINE_SIZES[BASE_INDEX]) == 0 &&
(len >> INLINE_SIZES[LEN_INDEX]) == 0 &&
(ctxt >> INLINE_SIZES[CTXT_INDEX]) == 0 {
(base << INLINE_OFFSETS[BASE_INDEX]) | (len << INLINE_OFFSETS[LEN_INDEX]) |
(ctxt << INLINE_OFFSETS[CTXT_INDEX]) | TAG_INLINE
} else {
let index = with_span_interner(|interner| interner.intern(sd));
(index << INTERNED_INDEX_OFFSET) | TAG_INTERNED
};
Span(val)
}
#[inline]
fn decode(span: Span) -> SpanData {
let val = span.0;
// Extract a field at position `pos` having size `size`.
let extract = |pos: u32, size: u32| {
let mask = ((!0u32) as u64 >> (32 - size)) as u32; // Can't shift u32 by 32
(val >> pos) & mask
};
let (base, len, ctxt) = if val & TAG_MASK == TAG_INLINE {(
extract(INLINE_OFFSETS[BASE_INDEX], INLINE_SIZES[BASE_INDEX]),
extract(INLINE_OFFSETS[LEN_INDEX], INLINE_SIZES[LEN_INDEX]),
extract(INLINE_OFFSETS[CTXT_INDEX], INLINE_SIZES[CTXT_INDEX]),
)} else {
let index = extract(INTERNED_INDEX_OFFSET, INTERNED_INDEX_SIZE);
return with_span_interner(|interner| *interner.get(index));
};
SpanData { lo: BytePos(base), hi: BytePos(base + len), ctxt: SyntaxContext(ctxt) }
}
#[derive(Default)]
struct SpanInterner {
spans: FxHashMap<SpanData, u32>,
span_data: Vec<SpanData>,
}
impl SpanInterner {
fn intern(&mut self, span_data: &SpanData) -> u32 {
if let Some(index) = self.spans.get(span_data) {
return *index;
}
let index = self.spans.len() as u32;
self.span_data.push(*span_data);
self.spans.insert(*span_data, index);
index
}
#[inline]
fn get(&self, index: u32) -> &SpanData {
&self.span_data[index as usize]
}
}
// If an interner exists in TLS, return it. Otherwise, prepare a fresh one.
#[inline]
fn with_span_interner<T, F: FnOnce(&mut SpanInterner) -> T>(f: F) -> T {
thread_local!(static INTERNER: RefCell<SpanInterner> = {
RefCell::new(SpanInterner::default())
});
INTERNER.with(|interner| f(&mut *interner.borrow_mut()))
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册