1
Fork 0

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<str>`, 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.
This commit is contained in:
Nicholas Nethercote 2016-10-10 09:07:18 +11:00
parent 9d4d0da7af
commit b043e11de2
6 changed files with 13 additions and 11 deletions

View file

@ -32,6 +32,7 @@ use rustc_const_math::ConstInt;
use rustc::mir::repr::Mir; use rustc::mir::repr::Mir;
use std::borrow::Cow;
use std::cell::Ref; use std::cell::Ref;
use std::io; use std::io;
use std::mem; use std::mem;
@ -202,7 +203,7 @@ impl<'doc, 'tcx> Decoder for DecodeContext<'doc, 'tcx> {
read_f64 -> f64; read_f64 -> f64;
read_f32 -> f32; read_f32 -> f32;
read_char -> char; read_char -> char;
read_str -> String; read_str -> Cow<str>;
} }
fn error(&mut self, err: &str) -> Self::Error { fn error(&mut self, err: &str) -> Self::Error {

View file

@ -199,6 +199,7 @@ use self::DecoderError::*;
use self::ParserState::*; use self::ParserState::*;
use self::InternalStackElement::*; use self::InternalStackElement::*;
use std::borrow::Cow;
use std::collections::{HashMap, BTreeMap}; use std::collections::{HashMap, BTreeMap};
use std::io::prelude::*; use std::io::prelude::*;
use std::io; use std::io;
@ -2081,9 +2082,7 @@ impl Decoder {
pub fn new(json: Json) -> Decoder { pub fn new(json: Json) -> Decoder {
Decoder { stack: vec![json] } Decoder { stack: vec![json] }
} }
}
impl Decoder {
fn pop(&mut self) -> Json { fn pop(&mut self) -> Json {
self.stack.pop().unwrap() self.stack.pop().unwrap()
} }
@ -2182,8 +2181,8 @@ impl ::Decoder for Decoder {
Err(ExpectedError("single character string".to_owned(), format!("{}", s))) Err(ExpectedError("single character string".to_owned(), format!("{}", s)))
} }
fn read_str(&mut self) -> DecodeResult<string::String> { fn read_str(&mut self) -> DecodeResult<Cow<str>> {
expect!(self.pop(), String) expect!(self.pop(), String).map(Cow::Owned)
} }
fn read_enum<T, F>(&mut self, _name: &str, f: F) -> DecodeResult<T> where fn read_enum<T, F>(&mut self, _name: &str, f: F) -> DecodeResult<T> where

View file

@ -9,6 +9,7 @@
// except according to those terms. // except according to those terms.
use leb128::{read_signed_leb128, read_unsigned_leb128, write_signed_leb128, write_unsigned_leb128}; use leb128::{read_signed_leb128, read_unsigned_leb128, write_signed_leb128, write_unsigned_leb128};
use std::borrow::Cow;
use std::io::{self, Write}; use std::io::{self, Write};
use serialize; use serialize;
@ -246,11 +247,11 @@ impl<'a> serialize::Decoder for Decoder<'a> {
Ok(::std::char::from_u32(bits).unwrap()) Ok(::std::char::from_u32(bits).unwrap())
} }
fn read_str(&mut self) -> Result<String, Self::Error> { fn read_str(&mut self) -> Result<Cow<str>, Self::Error> {
let len = self.read_usize()?; let len = self.read_usize()?;
let s = ::std::str::from_utf8(&self.data[self.position..self.position + len]).unwrap(); let s = ::std::str::from_utf8(&self.data[self.position..self.position + len]).unwrap();
self.position += len; self.position += len;
Ok(s.to_string()) Ok(Cow::Borrowed(s))
} }
fn error(&mut self, err: &str) -> Self::Error { fn error(&mut self, err: &str) -> Self::Error {

View file

@ -14,6 +14,7 @@
Core encoding and decoding interfaces. Core encoding and decoding interfaces.
*/ */
use std::borrow::Cow;
use std::intrinsics; use std::intrinsics;
use std::path; use std::path;
use std::rc::Rc; use std::rc::Rc;
@ -156,7 +157,7 @@ pub trait Decoder {
fn read_f64(&mut self) -> Result<f64, Self::Error>; fn read_f64(&mut self) -> Result<f64, Self::Error>;
fn read_f32(&mut self) -> Result<f32, Self::Error>; fn read_f32(&mut self) -> Result<f32, Self::Error>;
fn read_char(&mut self) -> Result<char, Self::Error>; fn read_char(&mut self) -> Result<char, Self::Error>;
fn read_str(&mut self) -> Result<String, Self::Error>; fn read_str(&mut self) -> Result<Cow<str>, Self::Error>;
// Compound types: // Compound types:
fn read_enum<T, F>(&mut self, _name: &str, f: F) -> Result<T, Self::Error> fn read_enum<T, F>(&mut self, _name: &str, f: F) -> Result<T, Self::Error>
@ -401,7 +402,7 @@ impl Encodable for String {
impl Decodable for String { impl Decodable for String {
fn decode<D: Decoder>(d: &mut D) -> Result<String, D::Error> { fn decode<D: Decoder>(d: &mut D) -> Result<String, D::Error> {
d.read_str() Ok(d.read_str()?.into_owned())
} }
} }

View file

@ -71,7 +71,7 @@ impl Encodable for Name {
impl Decodable for Name { impl Decodable for Name {
fn decode<D: Decoder>(d: &mut D) -> Result<Name, D::Error> { fn decode<D: Decoder>(d: &mut D) -> Result<Name, D::Error> {
Ok(token::intern(&d.read_str()?[..])) Ok(token::intern(&d.read_str()?))
} }
} }

View file

@ -566,7 +566,7 @@ impl PartialEq<InternedString> for str {
impl Decodable for InternedString { impl Decodable for InternedString {
fn decode<D: Decoder>(d: &mut D) -> Result<InternedString, D::Error> { fn decode<D: Decoder>(d: &mut D) -> Result<InternedString, D::Error> {
Ok(intern(d.read_str()?.as_ref()).as_str()) Ok(intern(&d.read_str()?).as_str())
} }
} }