]> git.lizzy.rs Git - rust.git/commitdiff
Rewrite `get_size_and_align` so it doesn't duplicate work
authorOliver Scherer <github35764891676564198441@oli-obk.de>
Thu, 25 Jul 2019 21:53:05 +0000 (23:53 +0200)
committerOliver Scherer <github35764891676564198441@oli-obk.de>
Thu, 25 Jul 2019 21:53:05 +0000 (23:53 +0200)
src/librustc_mir/interpret/memory.rs

index 674ae29070644f4ac866911e1a1ec9079a094583..c8e09ca4a1a47e4037fc8b3aa6490a63ebbe4a6e 100644 (file)
@@ -535,40 +535,41 @@ pub fn get_size_and_align(
         id: AllocId,
         liveness: AllocCheck,
     ) -> InterpResult<'static, (Size, Align)> {
-        // Allocations of `static` items
-        // Can't do this in the match argument, we may get cycle errors since the lock would
-        // be held throughout the match.
-        let alloc = self.tcx.alloc_map.lock().get(id);
-        match alloc {
-            Some(GlobalAlloc::Static(did)) => {
-                // Use size and align of the type
-                let ty = self.tcx.type_of(did);
-                let layout = self.tcx.layout_of(ParamEnv::empty().and(ty)).unwrap();
-                return Ok((layout.size, layout.align.abi));
-            }
-            _ => {}
-        }
-        // Regular allocations.
-        if let Ok(alloc) = self.get(id) {
-            return Ok((Size::from_bytes(alloc.bytes.len() as u64), alloc.align));
-        }
-        // Function pointers.
-        if let Ok(_) = self.get_fn_alloc(id) {
-            return if let AllocCheck::Dereferencable = liveness {
-                // The caller requested no function pointers.
-                err!(DerefFunctionPointer)
-            } else {
-                Ok((Size::ZERO, Align::from_bytes(1).unwrap()))
-            };
-        }
-        // The rest must be dead.
-        if let AllocCheck::MaybeDead = liveness {
-            // Deallocated pointers are allowed, we should be able to find
-            // them in the map.
-            Ok(*self.dead_alloc_map.get(&id)
-                .expect("deallocated pointers should all be recorded in `dead_alloc_map`"))
-        } else {
-            err!(DanglingPointerDeref)
+        let alloc_or_size_align = self.alloc_map.get_or(id, || -> Result<_, InterpResult<'static, (Size, Align)>> {
+            // Can't do this in the match argument, we may get cycle errors since the lock would
+            // be held throughout the match.
+            let alloc = self.tcx.alloc_map.lock().get(id);
+            Err(match alloc {
+                Some(GlobalAlloc::Static(did)) => {
+                    // Use size and align of the type
+                    let ty = self.tcx.type_of(did);
+                    let layout = self.tcx.layout_of(ParamEnv::empty().and(ty)).unwrap();
+                    Ok((layout.size, layout.align.abi))
+                },
+                Some(GlobalAlloc::Memory(alloc)) =>
+                    // this duplicates the logic on the `match alloc_or_size_align`, but due to the
+                    // API of `get_or` there's no way around that.
+                    Ok((Size::from_bytes(alloc.bytes.len() as u64), alloc.align)),
+                Some(GlobalAlloc::Function(_)) => if let AllocCheck::Dereferencable = liveness {
+                    // The caller requested no function pointers.
+                    err!(DerefFunctionPointer)
+                } else {
+                    Ok((Size::ZERO, Align::from_bytes(1).unwrap()))
+                },
+                // The rest must be dead.
+                None => if let AllocCheck::MaybeDead = liveness {
+                    // Deallocated pointers are allowed, we should be able to find
+                    // them in the map.
+                    Ok(*self.dead_alloc_map.get(&id)
+                        .expect("deallocated pointers should all be recorded in `dead_alloc_map`"))
+                } else {
+                    err!(DanglingPointerDeref)
+                },
+            })
+        });
+        match alloc_or_size_align {
+            Ok((_, alloc)) => Ok((Size::from_bytes(alloc.bytes.len() as u64), alloc.align)),
+            Err(done) => done,
         }
     }