From 7e5b9c3e92ce5052b947bb04eb2c5ab318d8b32b Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Tue, 15 Jan 2019 17:34:38 +1100 Subject: [PATCH] Use `SmallVec` in `ast::Path`. This is up to a 1% speedup on a few benchmark runs. --- Cargo.lock | 2 ++ src/librustc/hir/lowering.rs | 2 +- src/librustc_resolve/Cargo.toml | 2 ++ src/librustc_resolve/lib.rs | 12 ++++++++---- src/librustc_save_analysis/Cargo.toml | 1 + src/librustc_save_analysis/dump_visitor.rs | 3 ++- src/librustc_save_analysis/lib.rs | 1 + src/librustdoc/lib.rs | 1 + src/librustdoc/passes/collect_intra_doc_links.rs | 3 ++- src/libsyntax/ast.rs | 7 ++++--- src/libsyntax/attr/mod.rs | 4 +++- src/libsyntax/ext/build.rs | 3 ++- src/libsyntax/ext/placeholders.rs | 2 +- src/libsyntax/parse/parser.rs | 11 ++++++----- 14 files changed, 36 insertions(+), 18 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index d3c6054f4da37..65fc03592a0e3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2601,6 +2601,7 @@ dependencies = [ "rustc_data_structures 0.0.0", "rustc_errors 0.0.0", "rustc_metadata 0.0.0", + "smallvec 0.6.7 (registry+https://github.com/rust-lang/crates.io-index)", "syntax 0.0.0", "syntax_pos 0.0.0", ] @@ -2618,6 +2619,7 @@ dependencies = [ "rustc_data_structures 0.0.0", "rustc_target 0.0.0", "rustc_typeck 0.0.0", + "smallvec 0.6.7 (registry+https://github.com/rust-lang/crates.io-index)", "syntax 0.0.0", "syntax_pos 0.0.0", ] diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index 8badcbfc1b301..959cb7b27efec 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -2774,7 +2774,7 @@ impl<'a> LoweringContext<'a> { ItemKind::Use(ref use_tree) => { // Start with an empty prefix let prefix = Path { - segments: vec![], + segments: smallvec![], span: use_tree.span, }; diff --git a/src/librustc_resolve/Cargo.toml b/src/librustc_resolve/Cargo.toml index 3a8e84a3280c6..fc749b972f37e 100644 --- a/src/librustc_resolve/Cargo.toml +++ b/src/librustc_resolve/Cargo.toml @@ -19,3 +19,5 @@ rustc_errors = { path = "../librustc_errors" } syntax_pos = { path = "../libsyntax_pos" } rustc_data_structures = { path = "../librustc_data_structures" } rustc_metadata = { path = "../librustc_metadata" } +smallvec = { version = "0.6.7", features = ["union", "may_dangle"] } + diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index a25009ccfb49c..022b885e80caf 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -14,6 +14,7 @@ extern crate bitflags; #[macro_use] extern crate log; +extern crate smallvec; #[macro_use] extern crate syntax; extern crate syntax_pos; @@ -66,6 +67,7 @@ use syntax::ptr::P; use syntax_pos::{Span, DUMMY_SP, MultiSpan}; use errors::{Applicability, DiagnosticBuilder, DiagnosticId}; +use smallvec::SmallVec; use std::cell::{Cell, RefCell}; use std::{cmp, fmt, iter, mem, ptr}; use std::collections::BTreeSet; @@ -1677,7 +1679,7 @@ impl<'a> hir::lowering::Resolver for Resolver<'a> { crate_root.into_iter() .chain(components.iter().cloned()) .map(Ident::from_str) - ).map(|i| self.new_ast_path_segment(i)).collect::>(); + ).map(|i| self.new_ast_path_segment(i)).collect::>(); let path = ast::Path { @@ -4621,7 +4623,8 @@ impl<'a> Resolver<'a> { let mut candidates = Vec::new(); let mut seen_modules = FxHashSet::default(); let not_local_module = crate_name != keywords::Crate.ident(); - let mut worklist = vec![(start_module, Vec::::new(), not_local_module)]; + let mut worklist = + vec![(start_module, SmallVec::<[ast::PathSegment; 1]>::new(), not_local_module)]; while let Some((in_module, path_segments, @@ -4737,7 +4740,7 @@ impl<'a> Resolver<'a> { { let mut result = None; let mut seen_modules = FxHashSet::default(); - let mut worklist = vec![(self.graph_root, Vec::new())]; + let mut worklist = vec![(self.graph_root, SmallVec::new())]; while let Some((in_module, path_segments)) = worklist.pop() { // abort if the module is already found @@ -5214,9 +5217,10 @@ fn import_candidate_to_enum_paths(suggestion: &ImportSuggestion) -> (String, Str let variant_path_string = path_names_to_string(variant_path); let path_len = suggestion.path.segments.len(); + let segments = suggestion.path.segments[0..path_len - 1].iter().cloned().collect(); let enum_path = ast::Path { span: suggestion.path.span, - segments: suggestion.path.segments[0..path_len - 1].to_vec(), + segments, }; let enum_path_string = path_names_to_string(&enum_path); diff --git a/src/librustc_save_analysis/Cargo.toml b/src/librustc_save_analysis/Cargo.toml index e47f89c64ff07..97197a0ea3220 100644 --- a/src/librustc_save_analysis/Cargo.toml +++ b/src/librustc_save_analysis/Cargo.toml @@ -15,6 +15,7 @@ rustc_data_structures = { path = "../librustc_data_structures" } rustc_codegen_utils = { path = "../librustc_codegen_utils" } rustc_target = { path = "../librustc_target" } rustc_typeck = { path = "../librustc_typeck" } +smallvec = { version = "0.6.7", features = ["union", "may_dangle"] } syntax = { path = "../libsyntax" } syntax_pos = { path = "../libsyntax_pos" } rls-data = "0.18.1" diff --git a/src/librustc_save_analysis/dump_visitor.rs b/src/librustc_save_analysis/dump_visitor.rs index 0c9e443efe0db..c7bc3a1d9d590 100644 --- a/src/librustc_save_analysis/dump_visitor.rs +++ b/src/librustc_save_analysis/dump_visitor.rs @@ -36,6 +36,7 @@ use syntax_pos::*; use {escape, generated_code, lower_attributes, PathCollector, SaveContext}; use json_dumper::{Access, DumpOutput, JsonDumper}; +use smallvec::smallvec; use span_utils::SpanUtils; use sig; @@ -1338,7 +1339,7 @@ impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> Visitor<'l> for DumpVisitor<'l, 'tc match item.node { Use(ref use_tree) => { let prefix = ast::Path { - segments: vec![], + segments: smallvec![], span: DUMMY_SP, }; self.process_use_tree(use_tree, item.id, item, &prefix); diff --git a/src/librustc_save_analysis/lib.rs b/src/librustc_save_analysis/lib.rs index 132bd4f1430a0..09e3cf784a482 100644 --- a/src/librustc_save_analysis/lib.rs +++ b/src/librustc_save_analysis/lib.rs @@ -17,6 +17,7 @@ extern crate rustc_codegen_utils; extern crate rustc_serialize; extern crate rustc_target; extern crate rustc_typeck; +extern crate smallvec; #[macro_use] extern crate syntax; extern crate syntax_pos; diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index 1b6d7e87192d6..4c57db4e7f565 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -32,6 +32,7 @@ extern crate rustc_metadata; extern crate rustc_target; extern crate rustc_typeck; extern crate serialize; +extern crate smallvec; extern crate syntax; extern crate syntax_pos; extern crate test as testing; diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs index fdc1c0616187a..a5ff78907396e 100644 --- a/src/librustdoc/passes/collect_intra_doc_links.rs +++ b/src/librustdoc/passes/collect_intra_doc_links.rs @@ -2,6 +2,7 @@ use rustc::lint as lint; use rustc::hir; use rustc::hir::def::Def; use rustc::ty; +use smallvec::smallvec; use syntax; use syntax::ast::{self, Ident, NodeId}; use syntax::feature_gate::UnstableFeatures; @@ -425,7 +426,7 @@ impl<'a, 'tcx, 'rcx> DocFolder for LinkCollector<'a, 'tcx, 'rcx> { fn macro_resolve(cx: &DocContext, path_str: &str) -> Option { use syntax::ext::base::{MacroKind, SyntaxExtension}; let segment = ast::PathSegment::from_ident(Ident::from_str(path_str)); - let path = ast::Path { segments: vec![segment], span: DUMMY_SP }; + let path = ast::Path { segments: smallvec![segment], span: DUMMY_SP }; let mut resolver = cx.resolver.borrow_mut(); let parent_scope = resolver.dummy_parent_scope(); if let Ok(def) = resolver.resolve_macro_to_def_inner(&path, MacroKind::Bang, diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index 99ab9fbcf5fa0..51c4c2277a5d0 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -21,6 +21,7 @@ use ThinVec; use rustc_data_structures::fx::FxHashSet; use rustc_data_structures::sync::Lrc; use serialize::{self, Decoder, Encoder}; +use smallvec::SmallVec; use std::fmt; pub use rustc_target::abi::FloatTy; @@ -64,7 +65,7 @@ pub struct Path { pub span: Span, /// The segments in the path: the things separated by `::`. /// Global paths begin with `keywords::PathRoot`. - pub segments: Vec, + pub segments: SmallVec<[PathSegment; 1]>, } impl<'a> PartialEq<&'a str> for Path { @@ -90,7 +91,7 @@ impl Path { // one-segment path. pub fn from_ident(ident: Ident) -> Path { Path { - segments: vec![PathSegment::from_ident(ident)], + segments: smallvec![PathSegment::from_ident(ident)], span: ident.span, } } @@ -887,7 +888,7 @@ pub struct Expr { // `Expr` is used a lot. Make sure it doesn't unintentionally get bigger. #[cfg(target_arch = "x86_64")] -static_assert!(MEM_SIZE_OF_EXPR: std::mem::size_of::() == 88); +static_assert!(MEM_SIZE_OF_EXPR: std::mem::size_of::() == 96); impl Expr { /// Whether this expression would be valid somewhere that expects a value; for example, an `if` diff --git a/src/libsyntax/attr/mod.rs b/src/libsyntax/attr/mod.rs index d03563f8891aa..b494db0af3c59 100644 --- a/src/libsyntax/attr/mod.rs +++ b/src/libsyntax/attr/mod.rs @@ -22,6 +22,7 @@ use parse::parser::Parser; use parse::{self, ParseSess, PResult}; use parse::token::{self, Token}; use ptr::P; +use smallvec::{SmallVec, smallvec}; use symbol::Symbol; use ThinVec; use tokenstream::{TokenStream, TokenTree, DelimSpan}; @@ -483,7 +484,8 @@ impl MetaItem { let ident = match tokens.next() { Some(TokenTree::Token(span, Token::Ident(ident, _))) => { if let Some(TokenTree::Token(_, Token::ModSep)) = tokens.peek() { - let mut segments = vec![PathSegment::from_ident(ident.with_span_pos(span))]; + let mut segments: SmallVec<[_; 1]> = + smallvec![PathSegment::from_ident(ident.with_span_pos(span))]; tokens.next(); loop { if let Some(TokenTree::Token(span, diff --git a/src/libsyntax/ext/build.rs b/src/libsyntax/ext/build.rs index a8eec1a74dd2b..8180f099e018e 100644 --- a/src/libsyntax/ext/build.rs +++ b/src/libsyntax/ext/build.rs @@ -5,6 +5,7 @@ use syntax_pos::{Pos, Span, DUMMY_SP}; use source_map::{dummy_spanned, respan, Spanned}; use ext::base::ExtCtxt; use ptr::P; +use smallvec::SmallVec; use symbol::{Symbol, keywords}; use ThinVec; @@ -310,7 +311,7 @@ impl<'a> AstBuilder for ExtCtxt<'a> { -> ast::Path { assert!(!idents.is_empty()); let add_root = global && !idents[0].is_path_segment_keyword(); - let mut segments = Vec::with_capacity(idents.len() + add_root as usize); + let mut segments = SmallVec::with_capacity(idents.len() + add_root as usize); if add_root { segments.push(ast::PathSegment::path_root(span)); } diff --git a/src/libsyntax/ext/placeholders.rs b/src/libsyntax/ext/placeholders.rs index 3b0402d910a85..1e7112dd02c5d 100644 --- a/src/libsyntax/ext/placeholders.rs +++ b/src/libsyntax/ext/placeholders.rs @@ -16,7 +16,7 @@ use rustc_data_structures::fx::FxHashMap; pub fn placeholder(kind: AstFragmentKind, id: ast::NodeId) -> AstFragment { fn mac_placeholder() -> ast::Mac { dummy_spanned(ast::Mac_ { - path: ast::Path { span: DUMMY_SP, segments: Vec::new() }, + path: ast::Path { span: DUMMY_SP, segments: smallvec![] }, tts: TokenStream::empty().into(), delim: ast::MacDelimiter::Brace, }) diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 823c786bded26..9725ff725dd3c 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -47,6 +47,7 @@ use ptr::P; use parse::PResult; use ThinVec; use tokenstream::{self, DelimSpan, ThinTokenStream, TokenTree, TokenStream}; +use smallvec::SmallVec; use symbol::{Symbol, keywords}; use std::borrow::Cow; @@ -1738,7 +1739,7 @@ impl<'a> Parser<'a> { }; self.bump(); // `::` - let mut segments = Vec::new(); + let mut segments = smallvec![]; self.parse_path_segments(&mut segments, T::PATH_STYLE, true)?; let span = ty.span.to(self.prev_span); @@ -2075,7 +2076,7 @@ impl<'a> Parser<'a> { path = self.parse_path(PathStyle::Type)?; path_span = path_lo.to(self.prev_span); } else { - path = ast::Path { segments: Vec::new(), span: syntax_pos::DUMMY_SP }; + path = ast::Path { segments: smallvec![], span: syntax_pos::DUMMY_SP }; path_span = self.span.to(self.span); } @@ -2113,7 +2114,7 @@ impl<'a> Parser<'a> { }); let lo = self.meta_var_span.unwrap_or(self.span); - let mut segments = Vec::new(); + let mut segments = smallvec![]; let mod_sep_ctxt = self.span.ctxt(); if self.eat(&token::ModSep) { segments.push(PathSegment::path_root(lo.shrink_to_lo().with_ctxt(mod_sep_ctxt))); @@ -2144,7 +2145,7 @@ impl<'a> Parser<'a> { } fn parse_path_segments(&mut self, - segments: &mut Vec, + segments: &mut SmallVec<[PathSegment; 1]>, style: PathStyle, enable_warning: bool) -> PResult<'a, ()> { @@ -7822,7 +7823,7 @@ impl<'a> Parser<'a> { fn parse_use_tree(&mut self) -> PResult<'a, UseTree> { let lo = self.span; - let mut prefix = ast::Path { segments: Vec::new(), span: lo.shrink_to_lo() }; + let mut prefix = ast::Path { segments: smallvec![], span: lo.shrink_to_lo() }; let kind = if self.check(&token::OpenDelim(token::Brace)) || self.check(&token::BinOp(token::Star)) || self.is_import_coupler() {