rustc_public_bridge/
alloc.rs

1//! Internal memory allocator implementation for rustc_public.
2//!
3//! This module handles all direct interactions with rustc queries and performs
4//! the actual memory allocations. The stable interface in `rustc_public::alloc`
5//! delegates all query-related operations to this implementation.
6
7use rustc_abi::{Size, TyAndLayout};
8use rustc_middle::mir::interpret::{
9    AllocId, AllocInit, AllocRange, Allocation, ConstAllocation, Pointer, Scalar, alloc_range,
10};
11use rustc_middle::ty::{Ty, layout};
12
13use super::{CompilerCtxt, Tables};
14use crate::bridge::Allocation as _;
15use crate::{Bridge, Error};
16
17pub fn create_ty_and_layout<'tcx, B: Bridge>(
18    cx: &CompilerCtxt<'tcx, B>,
19    ty: Ty<'tcx>,
20) -> Result<TyAndLayout<'tcx, Ty<'tcx>>, &'tcx layout::LayoutError<'tcx>> {
21    use crate::context::TypingEnvHelpers;
22    cx.tcx.layout_of(cx.fully_monomorphized().as_query_input(ty))
23}
24
25pub fn try_new_scalar<'tcx, B: Bridge>(
26    layout: TyAndLayout<'tcx, Ty<'tcx>>,
27    scalar: Scalar,
28    cx: &CompilerCtxt<'tcx, B>,
29) -> Result<Allocation, B::Error> {
30    let size = scalar.size();
31    let mut allocation = Allocation::new(size, layout.align.abi, AllocInit::Uninit, ());
32    allocation
33        .write_scalar(&cx.tcx, alloc_range(Size::ZERO, size), scalar)
34        .map_err(|e| B::Error::from_internal(e))?;
35
36    Ok(allocation)
37}
38
39pub fn try_new_slice<'tcx, B: Bridge>(
40    layout: TyAndLayout<'tcx, Ty<'tcx>>,
41    alloc_id: AllocId,
42    meta: u64,
43    cx: &CompilerCtxt<'tcx, B>,
44) -> Result<Allocation, B::Error> {
45    let ptr = Pointer::new(alloc_id.into(), Size::ZERO);
46    let scalar_ptr = Scalar::from_pointer(ptr, &cx.tcx);
47    let scalar_meta: Scalar = Scalar::from_target_usize(meta, &cx.tcx);
48    let mut allocation = Allocation::new(layout.size, layout.align.abi, AllocInit::Uninit, ());
49    let ptr_size = cx.tcx.data_layout.pointer_size();
50    allocation
51        .write_scalar(&cx.tcx, alloc_range(Size::ZERO, ptr_size), scalar_ptr)
52        .map_err(|e| B::Error::from_internal(e))?;
53    allocation
54        .write_scalar(&cx.tcx, alloc_range(ptr_size, scalar_meta.size()), scalar_meta)
55        .map_err(|e| B::Error::from_internal(e))?;
56
57    Ok(allocation)
58}
59
60pub fn try_new_indirect<'tcx, B: Bridge>(
61    alloc_id: AllocId,
62    cx: &CompilerCtxt<'tcx, B>,
63) -> ConstAllocation<'tcx> {
64    let alloc = cx.tcx.global_alloc(alloc_id).unwrap_memory();
65
66    alloc
67}
68
69/// Creates an `Allocation` only from information within the `AllocRange`.
70pub fn allocation_filter<'tcx, B: Bridge>(
71    alloc: &rustc_middle::mir::interpret::Allocation,
72    alloc_range: AllocRange,
73    tables: &mut Tables<'tcx, B>,
74    cx: &CompilerCtxt<'tcx, B>,
75) -> B::Allocation {
76    let mut bytes: Vec<Option<u8>> = alloc
77        .inspect_with_uninit_and_ptr_outside_interpreter(
78            alloc_range.start.bytes_usize()..alloc_range.end().bytes_usize(),
79        )
80        .iter()
81        .copied()
82        .map(Some)
83        .collect();
84    for (i, b) in bytes.iter_mut().enumerate() {
85        if !alloc.init_mask().get(Size::from_bytes(i + alloc_range.start.bytes_usize())) {
86            *b = None;
87        }
88    }
89    let mut ptrs = Vec::new();
90    for (offset, prov) in alloc
91        .provenance()
92        .ptrs()
93        .iter()
94        .filter(|a| a.0 >= alloc_range.start && a.0 <= alloc_range.end())
95    {
96        ptrs.push((offset.bytes_usize() - alloc_range.start.bytes_usize(), prov.alloc_id()));
97    }
98
99    B::Allocation::new(bytes, ptrs, alloc.align.bytes(), alloc.mutability, tables, cx)
100}