about summary refs log tree commit diff
diff options
context:
space:
mode:
authorLukas Wirth <lukastw97@gmail.com>2023-09-07 18:40:53 +0200
committerLukas Wirth <lukastw97@gmail.com>2023-09-07 18:41:50 +0200
commitcd53bd6b8edb4e71954f9964f72d8126d83f4627 (patch)
treee2132dfeae0671542c98f8f42eff2a325cdb532c
parent10b0cd7047184f29d8ecd5a4fd5864596f15ec19 (diff)
downloadrust-cd53bd6b8edb4e71954f9964f72d8126d83f4627.tar.gz
rust-cd53bd6b8edb4e71954f9964f72d8126d83f4627.zip
Remove allocation on mir eval memory write
-rw-r--r--crates/hir-ty/src/mir/eval.rs46
1 files changed, 43 insertions, 3 deletions
diff --git a/crates/hir-ty/src/mir/eval.rs b/crates/hir-ty/src/mir/eval.rs
index 3944feb128c..5b267641a3d 100644
--- a/crates/hir-ty/src/mir/eval.rs
+++ b/crates/hir-ty/src/mir/eval.rs
@@ -215,9 +215,7 @@ impl Interval {
     }
 
     fn write_from_interval(&self, memory: &mut Evaluator<'_>, interval: Interval) -> Result<()> {
-        // FIXME: this could be more efficient
-        let bytes = &interval.get(memory)?.to_vec();
-        memory.write_memory(self.addr, bytes)
+        memory.copy_from_interval(self.addr, interval)
     }
 
     fn slice(self, range: Range<usize>) -> Interval {
@@ -1760,6 +1758,48 @@ impl Evaluator<'_> {
         Ok(())
     }
 
+    fn copy_from_interval(&mut self, addr: Address, r: Interval) -> Result<()> {
+        if r.size == 0 {
+            return Ok(());
+        }
+
+        let oob = || MirEvalError::UndefinedBehavior("out of bounds memory write".to_string());
+
+        match (addr, r.addr) {
+            (Stack(dst), Stack(src)) => {
+                if self.stack.len() < src + r.size || self.stack.len() < dst + r.size {
+                    return Err(oob());
+                }
+                self.stack.copy_within(src..src + r.size, dst)
+            }
+            (Heap(dst), Heap(src)) => {
+                if self.stack.len() < src + r.size || self.stack.len() < dst + r.size {
+                    return Err(oob());
+                }
+                self.heap.copy_within(src..src + r.size, dst)
+            }
+            (Stack(dst), Heap(src)) => {
+                self.stack
+                    .get_mut(dst..dst + r.size)
+                    .ok_or_else(oob)?
+                    .copy_from_slice(self.heap.get(src..src + r.size).ok_or_else(oob)?);
+            }
+            (Heap(dst), Stack(src)) => {
+                self.heap
+                    .get_mut(dst..dst + r.size)
+                    .ok_or_else(oob)?
+                    .copy_from_slice(self.stack.get(src..src + r.size).ok_or_else(oob)?);
+            }
+            _ => {
+                return Err(MirEvalError::UndefinedBehavior(format!(
+                    "invalid memory write at address {addr:?}"
+                )))
+            }
+        }
+
+        Ok(())
+    }
+
     fn size_align_of(&self, ty: &Ty, locals: &Locals) -> Result<Option<(usize, usize)>> {
         if let Some(layout) = self.layout_cache.borrow().get(ty) {
             return Ok(layout