| //! Internal memory allocator implementation for rustc_public. | |
| //! | |
| //! This module handles all direct interactions with rustc queries and performs | |
| //! the actual memory allocations. The stable interface in `rustc_public::alloc` | |
| //! delegates all query-related operations to this implementation. | |
| use rustc_abi::{Size, TyAndLayout}; | |
| use rustc_middle::mir::interpret::{ | |
| AllocId, AllocInit, AllocRange, Allocation, ConstAllocation, Pointer, Scalar, alloc_range, | |
| }; | |
| use rustc_middle::ty::{Ty, layout}; | |
| use super::{CompilerCtxt, Tables}; | |
| use crate::bridge::Allocation as _; | |
| use crate::{Bridge, Error}; | |
| pub fn create_ty_and_layout<'tcx, B: Bridge>( | |
| cx: &CompilerCtxt<'tcx, B>, | |
| ty: Ty<'tcx>, | |
| ) -> Result<TyAndLayout<'tcx, Ty<'tcx>>, &'tcx layout::LayoutError<'tcx>> { | |
| use crate::context::TypingEnvHelpers; | |
| cx.tcx.layout_of(cx.fully_monomorphized().as_query_input(ty)) | |
| } | |
| pub fn try_new_scalar<'tcx, B: Bridge>( | |
| layout: TyAndLayout<'tcx, Ty<'tcx>>, | |
| scalar: Scalar, | |
| cx: &CompilerCtxt<'tcx, B>, | |
| ) -> Result<Allocation, B::Error> { | |
| let size = scalar.size(); | |
| let mut allocation = Allocation::new(size, layout.align.abi, AllocInit::Uninit, ()); | |
| allocation | |
| .write_scalar(&cx.tcx, alloc_range(Size::ZERO, size), scalar) | |
| .map_err(|e| B::Error::from_internal(e))?; | |
| Ok(allocation) | |
| } | |
| pub fn try_new_slice<'tcx, B: Bridge>( | |
| layout: TyAndLayout<'tcx, Ty<'tcx>>, | |
| alloc_id: AllocId, | |
| meta: u64, | |
| cx: &CompilerCtxt<'tcx, B>, | |
| ) -> Result<Allocation, B::Error> { | |
| let ptr = Pointer::new(alloc_id.into(), Size::ZERO); | |
| let scalar_ptr = Scalar::from_pointer(ptr, &cx.tcx); | |
| let scalar_meta: Scalar = Scalar::from_target_usize(meta, &cx.tcx); | |
| let mut allocation = Allocation::new(layout.size, layout.align.abi, AllocInit::Uninit, ()); | |
| let ptr_size = cx.tcx.data_layout.pointer_size(); | |
| allocation | |
| .write_scalar(&cx.tcx, alloc_range(Size::ZERO, ptr_size), scalar_ptr) | |
| .map_err(|e| B::Error::from_internal(e))?; | |
| allocation | |
| .write_scalar(&cx.tcx, alloc_range(ptr_size, scalar_meta.size()), scalar_meta) | |
| .map_err(|e| B::Error::from_internal(e))?; | |
| Ok(allocation) | |
| } | |
| pub fn try_new_indirect<'tcx, B: Bridge>( | |
| alloc_id: AllocId, | |
| cx: &CompilerCtxt<'tcx, B>, | |
| ) -> ConstAllocation<'tcx> { | |
| let alloc = cx.tcx.global_alloc(alloc_id).unwrap_memory(); | |
| alloc | |
| } | |
| /// Creates an `Allocation` only from information within the `AllocRange`. | |
| pub fn allocation_filter<'tcx, B: Bridge>( | |
| alloc: &rustc_middle::mir::interpret::Allocation, | |
| alloc_range: AllocRange, | |
| tables: &mut Tables<'tcx, B>, | |
| cx: &CompilerCtxt<'tcx, B>, | |
| ) -> B::Allocation { | |
| let mut bytes: Vec<Option<u8>> = alloc | |
| .inspect_with_uninit_and_ptr_outside_interpreter( | |
| alloc_range.start.bytes_usize()..alloc_range.end().bytes_usize(), | |
| ) | |
| .iter() | |
| .copied() | |
| .map(Some) | |
| .collect(); | |
| for (i, b) in bytes.iter_mut().enumerate() { | |
| if !alloc.init_mask().get(Size::from_bytes(i + alloc_range.start.bytes_usize())) { | |
| *b = None; | |
| } | |
| } | |
| let mut ptrs = Vec::new(); | |
| for (offset, prov) in alloc | |
| .provenance() | |
| .ptrs() | |
| .iter() | |
| .filter(|a| a.0 >= alloc_range.start && a.0 <= alloc_range.end()) | |
| { | |
| ptrs.push((offset.bytes_usize() - alloc_range.start.bytes_usize(), prov.alloc_id())); | |
| } | |
| B::Allocation::new(bytes, ptrs, alloc.align.bytes(), alloc.mutability, tables, cx) | |
| } |