From b043e11de2eb2c60f7bfec5e15960f537b229e20 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Mon, 10 Oct 2016 09:07:18 +1100 Subject: [PATCH] Avoid allocations in `Decoder::read_str`. `opaque::Decoder::read_str` is very hot within `rustc` due to its use in the reading of crate metadata, and it currently returns a `String`. This commit changes it to instead return a `Cow`, which avoids a heap allocation. This change reduces the number of calls to `malloc` by almost 10% in some benchmarks. This is a [breaking-change] to libserialize. --- src/librustc_metadata/decoder.rs | 3 ++- src/libserialize/json.rs | 7 +++---- src/libserialize/opaque.rs | 5 +++-- src/libserialize/serialize.rs | 5 +++-- src/libsyntax/ast.rs | 2 +- src/libsyntax/parse/token.rs | 2 +- 6 files changed, 13 insertions(+), 11 deletions(-) diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs index 579a97138f250..bdb4d383cee7d 100644 --- a/src/librustc_metadata/decoder.rs +++ b/src/librustc_metadata/decoder.rs @@ -32,6 +32,7 @@ use rustc_const_math::ConstInt; use rustc::mir::repr::Mir; +use std::borrow::Cow; use std::cell::Ref; use std::io; use std::mem; @@ -202,7 +203,7 @@ impl<'doc, 'tcx> Decoder for DecodeContext<'doc, 'tcx> { read_f64 -> f64; read_f32 -> f32; read_char -> char; - read_str -> String; + read_str -> Cow; } fn error(&mut self, err: &str) -> Self::Error { diff --git a/src/libserialize/json.rs b/src/libserialize/json.rs index 5e25c61bae995..3e976c9062830 100644 --- a/src/libserialize/json.rs +++ b/src/libserialize/json.rs @@ -199,6 +199,7 @@ use self::DecoderError::*; use self::ParserState::*; use self::InternalStackElement::*; +use std::borrow::Cow; use std::collections::{HashMap, BTreeMap}; use std::io::prelude::*; use std::io; @@ -2081,9 +2082,7 @@ impl Decoder { pub fn new(json: Json) -> Decoder { Decoder { stack: vec![json] } } -} -impl Decoder { fn pop(&mut self) -> Json { self.stack.pop().unwrap() } @@ -2182,8 +2181,8 @@ impl ::Decoder for Decoder { Err(ExpectedError("single character string".to_owned(), format!("{}", s))) } - fn read_str(&mut self) -> DecodeResult { - expect!(self.pop(), String) + fn read_str(&mut self) -> DecodeResult> { + expect!(self.pop(), String).map(Cow::Owned) } fn read_enum(&mut self, _name: &str, f: F) -> DecodeResult where diff --git a/src/libserialize/opaque.rs b/src/libserialize/opaque.rs index e97834f63cee4..a2c0ca954472c 100644 --- a/src/libserialize/opaque.rs +++ b/src/libserialize/opaque.rs @@ -9,6 +9,7 @@ // except according to those terms. use leb128::{read_signed_leb128, read_unsigned_leb128, write_signed_leb128, write_unsigned_leb128}; +use std::borrow::Cow; use std::io::{self, Write}; use serialize; @@ -246,11 +247,11 @@ impl<'a> serialize::Decoder for Decoder<'a> { Ok(::std::char::from_u32(bits).unwrap()) } - fn read_str(&mut self) -> Result { + fn read_str(&mut self) -> Result, Self::Error> { let len = self.read_usize()?; let s = ::std::str::from_utf8(&self.data[self.position..self.position + len]).unwrap(); self.position += len; - Ok(s.to_string()) + Ok(Cow::Borrowed(s)) } fn error(&mut self, err: &str) -> Self::Error { diff --git a/src/libserialize/serialize.rs b/src/libserialize/serialize.rs index 6650a981884d8..c4613c661a84b 100644 --- a/src/libserialize/serialize.rs +++ b/src/libserialize/serialize.rs @@ -14,6 +14,7 @@ Core encoding and decoding interfaces. */ +use std::borrow::Cow; use std::intrinsics; use std::path; use std::rc::Rc; @@ -156,7 +157,7 @@ pub trait Decoder { fn read_f64(&mut self) -> Result; fn read_f32(&mut self) -> Result; fn read_char(&mut self) -> Result; - fn read_str(&mut self) -> Result; + fn read_str(&mut self) -> Result, Self::Error>; // Compound types: fn read_enum(&mut self, _name: &str, f: F) -> Result @@ -401,7 +402,7 @@ impl Encodable for String { impl Decodable for String { fn decode(d: &mut D) -> Result { - d.read_str() + Ok(d.read_str()?.into_owned()) } } diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index fcf2d32ded960..30fc4c3dd8045 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -71,7 +71,7 @@ impl Encodable for Name { impl Decodable for Name { fn decode(d: &mut D) -> Result { - Ok(token::intern(&d.read_str()?[..])) + Ok(token::intern(&d.read_str()?)) } } diff --git a/src/libsyntax/parse/token.rs b/src/libsyntax/parse/token.rs index 09bc5607946de..73d9695a9906b 100644 --- a/src/libsyntax/parse/token.rs +++ b/src/libsyntax/parse/token.rs @@ -566,7 +566,7 @@ impl PartialEq for str { impl Decodable for InternedString { fn decode(d: &mut D) -> Result { - Ok(intern(d.read_str()?.as_ref()).as_str()) + Ok(intern(&d.read_str()?).as_str()) } }