Skip to content

Commit

Permalink
Use SmallVector for TtReader::stack.
Browse files Browse the repository at this point in the history
This avoids 800,000 heap allocations when compiling html5ever. It
requires tweaking `SmallVector` a little.
  • Loading branch information
nnethercote committed Oct 25, 2016
1 parent 0a16a11 commit 3fd90d8
Show file tree
Hide file tree
Showing 3 changed files with 45 additions and 13 deletions.
7 changes: 4 additions & 3 deletions src/libsyntax/ext/tt/transcribe.rs
Expand Up @@ -10,14 +10,15 @@
use self::LockstepIterSize::*;

use ast::Ident;
use syntax_pos::{Span, DUMMY_SP};
use errors::{Handler, DiagnosticBuilder};
use ext::tt::macro_parser::{NamedMatch, MatchedSeq, MatchedNonterminal};
use parse::token::{DocComment, MatchNt, SubstNt};
use parse::token::{Token, Interpolated, NtIdent, NtTT};
use parse::token;
use parse::lexer::TokenAndSpan;
use syntax_pos::{Span, DUMMY_SP};
use tokenstream::{self, TokenTree};
use util::small_vector::SmallVector;

use std::rc::Rc;
use std::ops::Add;
Expand All @@ -36,7 +37,7 @@ struct TtFrame {
pub struct TtReader<'a> {
pub sp_diag: &'a Handler,
/// the unzipped tree:
stack: Vec<TtFrame>,
stack: SmallVector<TtFrame>,
/* for MBE-style macro transcription */
interpolations: HashMap<Ident, Rc<NamedMatch>>,

Expand Down Expand Up @@ -74,7 +75,7 @@ pub fn new_tt_reader_with_doc_flag(sp_diag: &Handler,
-> TtReader {
let mut r = TtReader {
sp_diag: sp_diag,
stack: vec!(TtFrame {
stack: SmallVector::one(TtFrame {
forest: TokenTree::Sequence(DUMMY_SP, Rc::new(tokenstream::SequenceRepetition {
tts: src,
// doesn't matter. This merely holds the root unzipping.
Expand Down
1 change: 1 addition & 0 deletions src/libsyntax/lib.rs
Expand Up @@ -35,6 +35,7 @@
#![feature(rustc_diagnostic_macros)]
#![feature(specialization)]

extern crate core;
extern crate serialize;
extern crate term;
extern crate libc;
Expand Down
50 changes: 40 additions & 10 deletions src/libsyntax/util/small_vector.rs
Expand Up @@ -11,6 +11,7 @@
use self::SmallVectorRepr::*;
use self::IntoIterRepr::*;

use core::ops;
use std::iter::{IntoIterator, FromIterator};
use std::mem;
use std::slice;
Expand All @@ -19,10 +20,12 @@ use std::vec;
use util::move_map::MoveMap;

/// A vector type optimized for cases where the size is almost always 0 or 1
#[derive(Clone)]
pub struct SmallVector<T> {
repr: SmallVectorRepr<T>,
}

#[derive(Clone)]
enum SmallVectorRepr<T> {
Zero,
One(T),
Expand Down Expand Up @@ -75,16 +78,11 @@ impl<T> SmallVector<T> {
}

pub fn as_slice(&self) -> &[T] {
match self.repr {
Zero => {
let result: &[T] = &[];
result
}
One(ref v) => {
unsafe { slice::from_raw_parts(v, 1) }
}
Many(ref vs) => vs
}
self
}

pub fn as_mut_slice(&mut self) -> &mut [T] {
self
}

pub fn pop(&mut self) -> Option<T> {
Expand Down Expand Up @@ -163,6 +161,38 @@ impl<T> SmallVector<T> {
}
}

impl<T> ops::Deref for SmallVector<T> {
type Target = [T];

fn deref(&self) -> &[T] {
match self.repr {
Zero => {
let result: &[T] = &[];
result
}
One(ref v) => {
unsafe { slice::from_raw_parts(v, 1) }
}
Many(ref vs) => vs
}
}
}

impl<T> ops::DerefMut for SmallVector<T> {
fn deref_mut(&mut self) -> &mut [T] {
match self.repr {
Zero => {
let result: &mut [T] = &mut [];
result
}
One(ref mut v) => {
unsafe { slice::from_raw_parts_mut(v, 1) }
}
Many(ref mut vs) => vs
}
}
}

impl<T> IntoIterator for SmallVector<T> {
type Item = T;
type IntoIter = IntoIter<T>;
Expand Down

0 comments on commit 3fd90d8

Please sign in to comment.