Skip to content

Commit b043e11

Browse files
committed
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.
1 parent 9d4d0da commit b043e11

File tree

6 files changed

+13
-11
lines changed

6 files changed

+13
-11
lines changed

src/librustc_metadata/decoder.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ use rustc_const_math::ConstInt;
3232

3333
use rustc::mir::repr::Mir;
3434

35+
use std::borrow::Cow;
3536
use std::cell::Ref;
3637
use std::io;
3738
use std::mem;
@@ -202,7 +203,7 @@ impl<'doc, 'tcx> Decoder for DecodeContext<'doc, 'tcx> {
202203
read_f64 -> f64;
203204
read_f32 -> f32;
204205
read_char -> char;
205-
read_str -> String;
206+
read_str -> Cow<str>;
206207
}
207208

208209
fn error(&mut self, err: &str) -> Self::Error {

src/libserialize/json.rs

+3-4
Original file line numberDiff line numberDiff line change
@@ -199,6 +199,7 @@ use self::DecoderError::*;
199199
use self::ParserState::*;
200200
use self::InternalStackElement::*;
201201

202+
use std::borrow::Cow;
202203
use std::collections::{HashMap, BTreeMap};
203204
use std::io::prelude::*;
204205
use std::io;
@@ -2081,9 +2082,7 @@ impl Decoder {
20812082
pub fn new(json: Json) -> Decoder {
20822083
Decoder { stack: vec![json] }
20832084
}
2084-
}
20852085

2086-
impl Decoder {
20872086
fn pop(&mut self) -> Json {
20882087
self.stack.pop().unwrap()
20892088
}
@@ -2182,8 +2181,8 @@ impl ::Decoder for Decoder {
21822181
Err(ExpectedError("single character string".to_owned(), format!("{}", s)))
21832182
}
21842183

2185-
fn read_str(&mut self) -> DecodeResult<string::String> {
2186-
expect!(self.pop(), String)
2184+
fn read_str(&mut self) -> DecodeResult<Cow<str>> {
2185+
expect!(self.pop(), String).map(Cow::Owned)
21872186
}
21882187

21892188
fn read_enum<T, F>(&mut self, _name: &str, f: F) -> DecodeResult<T> where

src/libserialize/opaque.rs

+3-2
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
// except according to those terms.
1010

1111
use leb128::{read_signed_leb128, read_unsigned_leb128, write_signed_leb128, write_unsigned_leb128};
12+
use std::borrow::Cow;
1213
use std::io::{self, Write};
1314
use serialize;
1415

@@ -246,11 +247,11 @@ impl<'a> serialize::Decoder for Decoder<'a> {
246247
Ok(::std::char::from_u32(bits).unwrap())
247248
}
248249

249-
fn read_str(&mut self) -> Result<String, Self::Error> {
250+
fn read_str(&mut self) -> Result<Cow<str>, Self::Error> {
250251
let len = self.read_usize()?;
251252
let s = ::std::str::from_utf8(&self.data[self.position..self.position + len]).unwrap();
252253
self.position += len;
253-
Ok(s.to_string())
254+
Ok(Cow::Borrowed(s))
254255
}
255256

256257
fn error(&mut self, err: &str) -> Self::Error {

src/libserialize/serialize.rs

+3-2
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
Core encoding and decoding interfaces.
1515
*/
1616

17+
use std::borrow::Cow;
1718
use std::intrinsics;
1819
use std::path;
1920
use std::rc::Rc;
@@ -156,7 +157,7 @@ pub trait Decoder {
156157
fn read_f64(&mut self) -> Result<f64, Self::Error>;
157158
fn read_f32(&mut self) -> Result<f32, Self::Error>;
158159
fn read_char(&mut self) -> Result<char, Self::Error>;
159-
fn read_str(&mut self) -> Result<String, Self::Error>;
160+
fn read_str(&mut self) -> Result<Cow<str>, Self::Error>;
160161

161162
// Compound types:
162163
fn read_enum<T, F>(&mut self, _name: &str, f: F) -> Result<T, Self::Error>
@@ -401,7 +402,7 @@ impl Encodable for String {
401402

402403
impl Decodable for String {
403404
fn decode<D: Decoder>(d: &mut D) -> Result<String, D::Error> {
404-
d.read_str()
405+
Ok(d.read_str()?.into_owned())
405406
}
406407
}
407408

src/libsyntax/ast.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ impl Encodable for Name {
7171

7272
impl Decodable for Name {
7373
fn decode<D: Decoder>(d: &mut D) -> Result<Name, D::Error> {
74-
Ok(token::intern(&d.read_str()?[..]))
74+
Ok(token::intern(&d.read_str()?))
7575
}
7676
}
7777

src/libsyntax/parse/token.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -566,7 +566,7 @@ impl PartialEq<InternedString> for str {
566566

567567
impl Decodable for InternedString {
568568
fn decode<D: Decoder>(d: &mut D) -> Result<InternedString, D::Error> {
569-
Ok(intern(d.read_str()?.as_ref()).as_str())
569+
Ok(intern(&d.read_str()?).as_str())
570570
}
571571
}
572572

0 commit comments

Comments
 (0)