From 6ffd7005c150dac4a99eea73eeb72189e0f5f694 Mon Sep 17 00:00:00 2001 From: Scott Olson Date: Fri, 10 Feb 2017 13:35:33 -0800 Subject: [PATCH] Cache string and bytestring literal allocs. --- src/eval_context.rs | 12 +++--------- src/memory.rs | 17 +++++++++++++++++ 2 files changed, 20 insertions(+), 9 deletions(-) diff --git a/src/eval_context.rs b/src/eval_context.rs index d2d33610f284..6ed6b6bebc06 100644 --- a/src/eval_context.rs +++ b/src/eval_context.rs @@ -168,11 +168,8 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { &self.stack } - pub(super) fn str_to_value(&mut self, s: &str) -> EvalResult<'tcx, Value> { - // FIXME: cache these allocs - let ptr = self.memory.allocate(s.len() as u64, 1)?; - self.memory.write_bytes(ptr, s.as_bytes())?; - self.memory.mark_static_initalized(ptr.alloc_id, false)?; + pub(crate) fn str_to_value(&mut self, s: &str) -> EvalResult<'tcx, Value> { + let ptr = self.memory.allocate_cached(s.as_bytes())?; Ok(Value::ByValPair(PrimVal::Ptr(ptr), PrimVal::from_u128(s.len() as u128))) } @@ -194,10 +191,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { Str(ref s) => return self.str_to_value(s), ByteStr(ref bs) => { - // FIXME: cache these allocs - let ptr = self.memory.allocate(bs.len() as u64, 1)?; - self.memory.write_bytes(ptr, bs)?; - self.memory.mark_static_initalized(ptr.alloc_id, false)?; + let ptr = self.memory.allocate_cached(bs)?; PrimVal::Ptr(ptr) } diff --git a/src/memory.rs b/src/memory.rs index 835c7bca7f60..0d3bec62e993 100644 --- a/src/memory.rs +++ b/src/memory.rs @@ -180,6 +180,10 @@ pub struct Memory<'a, 'tcx> { /// the normal struct access will succeed even though it shouldn't. /// But even with mir optimizations, that situation is hard/impossible to produce. packed: BTreeSet, + + /// A cache for basic byte allocations keyed by their contents. This is used to deduplicate + /// allocations for string and bytestring literals. + literal_alloc_cache: HashMap, AllocId>, } const ZST_ALLOC_ID: AllocId = AllocId(0); @@ -197,6 +201,7 @@ impl<'a, 'tcx> Memory<'a, 'tcx> { memory_usage: 0, packed: BTreeSet::new(), static_alloc: HashSet::new(), + literal_alloc_cache: HashMap::new(), } } @@ -263,6 +268,18 @@ impl<'a, 'tcx> Memory<'a, 'tcx> { Pointer::new(id, 0) } + pub fn allocate_cached(&mut self, bytes: &[u8]) -> EvalResult<'tcx, Pointer> { + if let Some(&alloc_id) = self.literal_alloc_cache.get(bytes) { + return Ok(Pointer::new(alloc_id, 0)); + } + + let ptr = self.allocate(bytes.len() as u64, 1)?; + self.write_bytes(ptr, bytes)?; + self.mark_static_initalized(ptr.alloc_id, false)?; + self.literal_alloc_cache.insert(bytes.to_vec(), ptr.alloc_id); + Ok(ptr) + } + pub fn allocate(&mut self, size: u64, align: u64) -> EvalResult<'tcx, Pointer> { if size == 0 { return Ok(Pointer::zst_ptr());