From d9ac0c67ed5a3ea7d708894a4636a6e83c5aec49 Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Thu, 25 Jul 2019 23:53:05 +0200 Subject: [PATCH] Rewrite `get_size_and_align` so it doesn't duplicate work --- src/librustc_mir/interpret/memory.rs | 69 ++++++++++++++-------------- 1 file changed, 35 insertions(+), 34 deletions(-) diff --git a/src/librustc_mir/interpret/memory.rs b/src/librustc_mir/interpret/memory.rs index 674ae290706..c8e09ca4a1a 100644 --- a/src/librustc_mir/interpret/memory.rs +++ b/src/librustc_mir/interpret/memory.rs @@ -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, } } -- 2.44.0