]> git.proxmox.com Git - rustc.git/blame - compiler/rustc_middle/src/mir/interpret/mod.rs
New upstream version 1.69.0+dfsg1
[rustc.git] / compiler / rustc_middle / src / mir / interpret / mod.rs
CommitLineData
e1599b0c 1//! An interpreter for MIR used in CTFE and by miri.
ff7c6d11
XL
2
3#[macro_export]
416331ca
XL
4macro_rules! err_unsup {
5 ($($tt:tt)*) => {
6 $crate::mir::interpret::InterpError::Unsupported(
7 $crate::mir::interpret::UnsupportedOpInfo::$($tt)*
8 )
9 };
10}
11
12#[macro_export]
13macro_rules! err_unsup_format {
14 ($($tt:tt)*) => { err_unsup!(Unsupported(format!($($tt)*))) };
15}
16
17#[macro_export]
18macro_rules! err_inval {
19 ($($tt:tt)*) => {
20 $crate::mir::interpret::InterpError::InvalidProgram(
21 $crate::mir::interpret::InvalidProgramInfo::$($tt)*
22 )
23 };
24}
25
26#[macro_export]
27macro_rules! err_ub {
28 ($($tt:tt)*) => {
29 $crate::mir::interpret::InterpError::UndefinedBehavior(
30 $crate::mir::interpret::UndefinedBehaviorInfo::$($tt)*
31 )
32 };
33}
34
35#[macro_export]
36macro_rules! err_ub_format {
37 ($($tt:tt)*) => { err_ub!(Ub(format!($($tt)*))) };
38}
39
416331ca
XL
40#[macro_export]
41macro_rules! err_exhaust {
42 ($($tt:tt)*) => {
43 $crate::mir::interpret::InterpError::ResourceExhaustion(
44 $crate::mir::interpret::ResourceExhaustionInfo::$($tt)*
45 )
46 };
47}
48
ba9703b0
XL
49#[macro_export]
50macro_rules! err_machine_stop {
51 ($($tt:tt)*) => {
52 $crate::mir::interpret::InterpError::MachineStop(Box::new($($tt)*))
53 };
54}
55
56// In the `throw_*` macros, avoid `return` to make them work with `try {}`.
416331ca
XL
57#[macro_export]
58macro_rules! throw_unsup {
923072b8 59 ($($tt:tt)*) => { do yeet err_unsup!($($tt)*) };
416331ca
XL
60}
61
62#[macro_export]
63macro_rules! throw_unsup_format {
64 ($($tt:tt)*) => { throw_unsup!(Unsupported(format!($($tt)*))) };
65}
66
67#[macro_export]
68macro_rules! throw_inval {
923072b8 69 ($($tt:tt)*) => { do yeet err_inval!($($tt)*) };
416331ca
XL
70}
71
72#[macro_export]
73macro_rules! throw_ub {
923072b8 74 ($($tt:tt)*) => { do yeet err_ub!($($tt)*) };
416331ca
XL
75}
76
77#[macro_export]
78macro_rules! throw_ub_format {
79 ($($tt:tt)*) => { throw_ub!(Ub(format!($($tt)*))) };
80}
81
416331ca
XL
82#[macro_export]
83macro_rules! throw_exhaust {
923072b8 84 ($($tt:tt)*) => { do yeet err_exhaust!($($tt)*) };
ff7c6d11
XL
85}
86
60c5eb7d
XL
87#[macro_export]
88macro_rules! throw_machine_stop {
923072b8 89 ($($tt:tt)*) => { do yeet err_machine_stop!($($tt)*) };
60c5eb7d
XL
90}
91
a1dfa0c6 92mod allocation;
dfeec247 93mod error;
a1dfa0c6 94mod pointer;
dfeec247
XL
95mod queries;
96mod value;
ff7c6d11 97
ba9703b0
XL
98use std::fmt;
99use std::io;
1b1a35ee 100use std::io::{Read, Write};
136023e0 101use std::num::{NonZeroU32, NonZeroU64};
ba9703b0 102use std::sync::atomic::{AtomicU32, Ordering};
ff7c6d11 103
3dfed10e 104use rustc_ast::LitKind;
94b46f34 105use rustc_data_structures::fx::FxHashMap;
dfeec247 106use rustc_data_structures::sync::{HashMapExt, Lock};
94b46f34 107use rustc_data_structures::tiny_list::TinyList;
487cf647 108use rustc_errors::ErrorGuaranteed;
dfeec247 109use rustc_hir::def_id::DefId;
532ac7d7 110use rustc_macros::HashStable;
1b1a35ee 111use rustc_middle::ty::print::with_no_trimmed_paths;
3dfed10e 112use rustc_serialize::{Decodable, Encodable};
9ffffee4 113use rustc_target::abi::{AddressSpace, Endian, HasDataLayout};
ba9703b0
XL
114
115use crate::mir;
3dfed10e 116use crate::ty::codec::{TyDecoder, TyEncoder};
ba9703b0
XL
117use crate::ty::subst::GenericArgKind;
118use crate::ty::{self, Instance, Ty, TyCtxt};
119
120pub use self::error::{
1b1a35ee 121 struct_error, CheckInAllocMsg, ErrorHandled, EvalToAllocationRawResult, EvalToConstValueResult,
923072b8
FG
122 EvalToValTreeResult, InterpError, InterpErrorInfo, InterpResult, InvalidProgramInfo,
123 MachineStopType, ResourceExhaustionInfo, ScalarSizeMismatch, UndefinedBehaviorInfo,
124 UninitBytesAccess, UnsupportedOpInfo,
ba9703b0
XL
125};
126
f2b60f7d 127pub use self::value::{get_slice_bytes, ConstAlloc, ConstValue, Scalar};
ba9703b0 128
94222f64 129pub use self::allocation::{
9ffffee4
FG
130 alloc_range, AllocBytes, AllocError, AllocRange, AllocResult, Allocation, ConstAllocation,
131 InitChunk, InitChunkIter,
94222f64 132};
ba9703b0 133
136023e0 134pub use self::pointer::{Pointer, PointerArithmetic, Provenance};
ff7c6d11 135
60c5eb7d
XL
136/// Uniquely identifies one of the following:
137/// - A constant
138/// - A static
3dfed10e 139#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, TyEncodable, TyDecodable)]
f2b60f7d 140#[derive(HashStable, Lift, TypeFoldable, TypeVisitable)]
ff7c6d11
XL
141pub struct GlobalId<'tcx> {
142 /// For a constant or static, the `Instance` of the item itself.
143 /// For a promoted global, the `Instance` of the function they belong to.
144 pub instance: ty::Instance<'tcx>,
145
dc9dc135 146 /// The index for promoted globals within their function's `mir::Body`.
ff7c6d11
XL
147 pub promoted: Option<mir::Promoted>,
148}
149
a2a8927a 150impl<'tcx> GlobalId<'tcx> {
3dfed10e 151 pub fn display(self, tcx: TyCtxt<'tcx>) -> String {
5e7ed085 152 let instance_name = with_no_trimmed_paths!(tcx.def_path_str(self.instance.def.def_id()));
3dfed10e
XL
153 if let Some(promoted) = self.promoted {
154 format!("{}::{:?}", instance_name, promoted)
155 } else {
156 instance_name
157 }
158 }
159}
160
dfeec247
XL
161/// Input argument for `tcx.lit_to_const`.
162#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, HashStable)]
163pub struct LitToConstInput<'tcx> {
164 /// The absolute value of the resultant constant.
165 pub lit: &'tcx LitKind,
166 /// The type of the constant.
167 pub ty: Ty<'tcx>,
168 /// If the constant is negative.
169 pub neg: bool,
170}
171
172/// Error type for `tcx.lit_to_const`.
173#[derive(Copy, Clone, Debug, Eq, PartialEq, HashStable)]
174pub enum LitToConstError {
175 /// The literal's inferred type did not match the expected `ty` in the input.
176 /// This is used for graceful error handling (`delay_span_bug`) in
ba9703b0 177 /// type checking (`Const::from_anon_const`).
dfeec247 178 TypeError,
487cf647 179 Reported(ErrorGuaranteed),
dfeec247
XL
180}
181
182#[derive(Copy, Clone, Eq, Hash, Ord, PartialEq, PartialOrd)]
136023e0 183pub struct AllocId(pub NonZeroU64);
ff7c6d11 184
f9f354fc
XL
185// We want the `Debug` output to be readable as it is used by `derive(Debug)` for
186// all the Miri types.
dfeec247 187impl fmt::Debug for AllocId {
f9f354fc
XL
188 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
189 if f.alternate() { write!(f, "a{}", self.0) } else { write!(f, "alloc{}", self.0) }
ba9703b0
XL
190 }
191}
192
064997fb 193// No "Display" since AllocIds are not usually user-visible.
dfeec247 194
3dfed10e 195#[derive(TyDecodable, TyEncodable)]
0731742a 196enum AllocDiscriminant {
0531ce1d
XL
197 Alloc,
198 Fn,
064997fb 199 VTable,
0531ce1d
XL
200 Static,
201}
202
923072b8 203pub fn specialized_encode_alloc_id<'tcx, E: TyEncoder<I = TyCtxt<'tcx>>>(
0531ce1d 204 encoder: &mut E,
dc9dc135 205 tcx: TyCtxt<'tcx>,
0531ce1d 206 alloc_id: AllocId,
923072b8 207) {
f9f354fc 208 match tcx.global_alloc(alloc_id) {
dc9dc135 209 GlobalAlloc::Memory(alloc) => {
94b46f34 210 trace!("encoding {:?} with {:#?}", alloc_id, alloc);
923072b8
FG
211 AllocDiscriminant::Alloc.encode(encoder);
212 alloc.encode(encoder);
94b46f34 213 }
dc9dc135 214 GlobalAlloc::Function(fn_instance) => {
94b46f34 215 trace!("encoding {:?} with {:#?}", alloc_id, fn_instance);
923072b8
FG
216 AllocDiscriminant::Fn.encode(encoder);
217 fn_instance.encode(encoder);
94b46f34 218 }
064997fb
FG
219 GlobalAlloc::VTable(ty, poly_trait_ref) => {
220 trace!("encoding {:?} with {ty:#?}, {poly_trait_ref:#?}", alloc_id);
221 AllocDiscriminant::VTable.encode(encoder);
222 ty.encode(encoder);
223 poly_trait_ref.encode(encoder);
224 }
dc9dc135 225 GlobalAlloc::Static(did) => {
f9f354fc 226 assert!(!tcx.is_thread_local_static(did));
e1599b0c
XL
227 // References to statics doesn't need to know about their allocations,
228 // just about its `DefId`.
923072b8
FG
229 AllocDiscriminant::Static.encode(encoder);
230 did.encode(encoder);
94b46f34 231 }
0531ce1d 232 }
0531ce1d
XL
233}
234
94b46f34
XL
235// Used to avoid infinite recursion when decoding cyclic allocations.
236type DecodingSessionId = NonZeroU32;
237
238#[derive(Clone)]
239enum State {
240 Empty,
241 InProgressNonAlloc(TinyList<DecodingSessionId>),
242 InProgress(TinyList<DecodingSessionId>, AllocId),
243 Done(AllocId),
244}
245
246pub struct AllocDecodingState {
e1599b0c
XL
247 // For each `AllocId`, we keep track of which decoding state it's currently in.
248 decoding_state: Vec<Lock<State>>,
94b46f34
XL
249 // The offsets of each allocation in the data stream.
250 data_offsets: Vec<u32>,
251}
252
253impl AllocDecodingState {
17df50a5 254 #[inline]
0bf4aa26 255 pub fn new_decoding_session(&self) -> AllocDecodingSession<'_> {
94b46f34
XL
256 static DECODER_SESSION_ID: AtomicU32 = AtomicU32::new(0);
257 let counter = DECODER_SESSION_ID.fetch_add(1, Ordering::SeqCst);
258
e1599b0c 259 // Make sure this is never zero.
94b46f34
XL
260 let session_id = DecodingSessionId::new((counter & 0x7FFFFFFF) + 1).unwrap();
261
dfeec247 262 AllocDecodingSession { state: self, session_id }
94b46f34
XL
263 }
264
e1599b0c
XL
265 pub fn new(data_offsets: Vec<u32>) -> Self {
266 let decoding_state = vec![Lock::new(State::Empty); data_offsets.len()];
94b46f34 267
dfeec247 268 Self { decoding_state, data_offsets }
94b46f34
XL
269 }
270}
271
272#[derive(Copy, Clone)]
273pub struct AllocDecodingSession<'s> {
274 state: &'s AllocDecodingState,
275 session_id: DecodingSessionId,
276}
277
278impl<'s> AllocDecodingSession<'s> {
e1599b0c 279 /// Decodes an `AllocId` in a thread-safe way.
5099ac24 280 pub fn decode_alloc_id<'tcx, D>(&self, decoder: &mut D) -> AllocId
dc9dc135 281 where
923072b8 282 D: TyDecoder<I = TyCtxt<'tcx>>,
94b46f34 283 {
e1599b0c 284 // Read the index of the allocation.
5099ac24 285 let idx = usize::try_from(decoder.read_u32()).unwrap();
ba9703b0 286 let pos = usize::try_from(self.state.data_offsets[idx]).unwrap();
94b46f34 287
e1599b0c
XL
288 // Decode the `AllocDiscriminant` now so that we know if we have to reserve an
289 // `AllocId`.
94b46f34 290 let (alloc_kind, pos) = decoder.with_position(pos, |decoder| {
5099ac24
FG
291 let alloc_kind = AllocDiscriminant::decode(decoder);
292 (alloc_kind, decoder.position())
293 });
94b46f34 294
e1599b0c 295 // Check the decoding state to see if it's already decoded or if we should
94b46f34
XL
296 // decode it here.
297 let alloc_id = {
298 let mut entry = self.state.decoding_state[idx].lock();
299
300 match *entry {
301 State::Done(alloc_id) => {
5099ac24 302 return alloc_id;
94b46f34
XL
303 }
304 ref mut entry @ State::Empty => {
e1599b0c 305 // We are allowed to decode.
94b46f34 306 match alloc_kind {
0731742a 307 AllocDiscriminant::Alloc => {
94b46f34 308 // If this is an allocation, we need to reserve an
e1599b0c 309 // `AllocId` so we can decode cyclic graphs.
923072b8 310 let alloc_id = decoder.interner().reserve_alloc_id();
dfeec247
XL
311 *entry =
312 State::InProgress(TinyList::new_single(self.session_id), alloc_id);
94b46f34 313 Some(alloc_id)
dfeec247 314 }
064997fb
FG
315 AllocDiscriminant::Fn
316 | AllocDiscriminant::Static
317 | AllocDiscriminant::VTable => {
e1599b0c
XL
318 // Fns and statics cannot be cyclic, and their `AllocId`
319 // is determined later by interning.
dfeec247
XL
320 *entry =
321 State::InProgressNonAlloc(TinyList::new_single(self.session_id));
94b46f34
XL
322 None
323 }
324 }
325 }
326 State::InProgressNonAlloc(ref mut sessions) => {
327 if sessions.contains(&self.session_id) {
e1599b0c 328 bug!("this should be unreachable");
94b46f34 329 } else {
e1599b0c 330 // Start decoding concurrently.
94b46f34
XL
331 sessions.insert(self.session_id);
332 None
333 }
334 }
335 State::InProgress(ref mut sessions, alloc_id) => {
336 if sessions.contains(&self.session_id) {
337 // Don't recurse.
5099ac24 338 return alloc_id;
94b46f34 339 } else {
e1599b0c 340 // Start decoding concurrently.
94b46f34
XL
341 sessions.insert(self.session_id);
342 Some(alloc_id)
343 }
344 }
345 }
346 };
347
e1599b0c 348 // Now decode the actual data.
94b46f34
XL
349 let alloc_id = decoder.with_position(pos, |decoder| {
350 match alloc_kind {
0731742a 351 AllocDiscriminant::Alloc => {
5e7ed085 352 let alloc = <ConstAllocation<'tcx> as Decodable<_>>::decode(decoder);
e1599b0c 353 // We already have a reserved `AllocId`.
94b46f34 354 let alloc_id = alloc_id.unwrap();
e1599b0c 355 trace!("decoded alloc {:?}: {:#?}", alloc_id, alloc);
923072b8 356 decoder.interner().set_alloc_id_same_memory(alloc_id, alloc);
5099ac24 357 alloc_id
dfeec247 358 }
0731742a 359 AllocDiscriminant::Fn => {
94b46f34 360 assert!(alloc_id.is_none());
e1599b0c 361 trace!("creating fn alloc ID");
5099ac24 362 let instance = ty::Instance::decode(decoder);
94b46f34 363 trace!("decoded fn alloc instance: {:?}", instance);
923072b8 364 let alloc_id = decoder.interner().create_fn_alloc(instance);
5099ac24 365 alloc_id
dfeec247 366 }
064997fb
FG
367 AllocDiscriminant::VTable => {
368 assert!(alloc_id.is_none());
369 trace!("creating vtable alloc ID");
370 let ty = <Ty<'_> as Decodable<D>>::decode(decoder);
371 let poly_trait_ref =
372 <Option<ty::PolyExistentialTraitRef<'_>> as Decodable<D>>::decode(decoder);
373 trace!("decoded vtable alloc instance: {ty:?}, {poly_trait_ref:?}");
374 let alloc_id = decoder.interner().create_vtable_alloc(ty, poly_trait_ref);
375 alloc_id
376 }
0731742a 377 AllocDiscriminant::Static => {
94b46f34 378 assert!(alloc_id.is_none());
e1599b0c 379 trace!("creating extern static alloc ID");
5099ac24 380 let did = <DefId as Decodable<D>>::decode(decoder);
e1599b0c 381 trace!("decoded static def-ID: {:?}", did);
923072b8 382 let alloc_id = decoder.interner().create_static_alloc(did);
5099ac24 383 alloc_id
94b46f34
XL
384 }
385 }
5099ac24 386 });
94b46f34
XL
387
388 self.state.decoding_state[idx].with_lock(|entry| {
389 *entry = State::Done(alloc_id);
390 });
391
5099ac24 392 alloc_id
0531ce1d
XL
393 }
394}
395
dc9dc135
XL
396/// An allocation in the global (tcx-managed) memory can be either a function pointer,
397/// a static, or a "real" allocation with some data in it.
3dfed10e 398#[derive(Debug, Clone, Eq, PartialEq, Hash, TyDecodable, TyEncodable, HashStable)]
dc9dc135 399pub enum GlobalAlloc<'tcx> {
e1599b0c 400 /// The alloc ID is used as a function pointer.
94b46f34 401 Function(Instance<'tcx>),
064997fb
FG
402 /// This alloc ID points to a symbolic (not-reified) vtable.
403 VTable(Ty<'tcx>, Option<ty::PolyExistentialTraitRef<'tcx>>),
9fa01778 404 /// The alloc ID points to a "lazy" static variable that did not get computed (yet).
b7449926 405 /// This is also used to break the cycle in recursive statics.
94b46f34 406 Static(DefId),
9fa01778 407 /// The alloc ID points to memory.
5e7ed085 408 Memory(ConstAllocation<'tcx>),
94b46f34
XL
409}
410
a2a8927a 411impl<'tcx> GlobalAlloc<'tcx> {
f9f354fc
XL
412 /// Panics if the `GlobalAlloc` does not refer to an `GlobalAlloc::Memory`
413 #[track_caller]
414 #[inline]
5e7ed085 415 pub fn unwrap_memory(&self) -> ConstAllocation<'tcx> {
f9f354fc
XL
416 match *self {
417 GlobalAlloc::Memory(mem) => mem,
418 _ => bug!("expected memory, got {:?}", self),
419 }
420 }
421
422 /// Panics if the `GlobalAlloc` is not `GlobalAlloc::Function`
423 #[track_caller]
424 #[inline]
425 pub fn unwrap_fn(&self) -> Instance<'tcx> {
426 match *self {
427 GlobalAlloc::Function(instance) => instance,
428 _ => bug!("expected function, got {:?}", self),
429 }
430 }
064997fb
FG
431
432 /// Panics if the `GlobalAlloc` is not `GlobalAlloc::VTable`
433 #[track_caller]
434 #[inline]
435 pub fn unwrap_vtable(&self) -> (Ty<'tcx>, Option<ty::PolyExistentialTraitRef<'tcx>>) {
436 match *self {
437 GlobalAlloc::VTable(ty, poly_trait_ref) => (ty, poly_trait_ref),
438 _ => bug!("expected vtable, got {:?}", self),
439 }
440 }
9ffffee4
FG
441
442 /// The address space that this `GlobalAlloc` should be placed in.
443 #[inline]
444 pub fn address_space(&self, cx: &impl HasDataLayout) -> AddressSpace {
445 match self {
446 GlobalAlloc::Function(..) => cx.data_layout().instruction_address_space,
447 GlobalAlloc::Static(..) | GlobalAlloc::Memory(..) | GlobalAlloc::VTable(..) => {
448 AddressSpace::DATA
449 }
450 }
451 }
f9f354fc
XL
452}
453
923072b8 454pub(crate) struct AllocMap<'tcx> {
e1599b0c 455 /// Maps `AllocId`s to their corresponding allocations.
dc9dc135 456 alloc_map: FxHashMap<AllocId, GlobalAlloc<'tcx>>,
94b46f34 457
dc9dc135
XL
458 /// Used to ensure that statics and functions only get one associated `AllocId`.
459 /// Should never contain a `GlobalAlloc::Memory`!
e1599b0c
XL
460 //
461 // FIXME: Should we just have two separate dedup maps for statics and functions each?
dc9dc135 462 dedup: FxHashMap<GlobalAlloc<'tcx>, AllocId>,
94b46f34 463
9fa01778 464 /// The `AllocId` to assign to the next requested ID.
e1599b0c 465 /// Always incremented; never gets smaller.
94b46f34
XL
466 next_id: AllocId,
467}
468
0731742a 469impl<'tcx> AllocMap<'tcx> {
923072b8 470 pub(crate) fn new() -> Self {
136023e0
XL
471 AllocMap {
472 alloc_map: Default::default(),
473 dedup: Default::default(),
474 next_id: AllocId(NonZeroU64::new(1).unwrap()),
475 }
94b46f34 476 }
f9f354fc 477 fn reserve(&mut self) -> AllocId {
94b46f34 478 let next = self.next_id;
dfeec247
XL
479 self.next_id.0 = self.next_id.0.checked_add(1).expect(
480 "You overflowed a u64 by incrementing by 1... \
481 You've just earned yourself a free drink if we ever meet. \
482 Seriously, how did you do that?!",
483 );
94b46f34
XL
484 next
485 }
f9f354fc
XL
486}
487
488impl<'tcx> TyCtxt<'tcx> {
489 /// Obtains a new allocation ID that can be referenced but does not
490 /// yet have an allocation backing it.
491 ///
492 /// Make sure to call `set_alloc_id_memory` or `set_alloc_id_same_memory` before returning such
493 /// an `AllocId` from a query.
1b1a35ee 494 pub fn reserve_alloc_id(self) -> AllocId {
f9f354fc
XL
495 self.alloc_map.lock().reserve()
496 }
94b46f34 497
e1599b0c 498 /// Reserves a new ID *if* this allocation has not been dedup-reserved before.
064997fb
FG
499 /// Should only be used for "symbolic" allocations (function pointers, vtables, statics), we
500 /// don't want to dedup IDs for "real" memory!
1b1a35ee 501 fn reserve_and_set_dedup(self, alloc: GlobalAlloc<'tcx>) -> AllocId {
f9f354fc 502 let mut alloc_map = self.alloc_map.lock();
dc9dc135 503 match alloc {
064997fb 504 GlobalAlloc::Function(..) | GlobalAlloc::Static(..) | GlobalAlloc::VTable(..) => {}
dc9dc135
XL
505 GlobalAlloc::Memory(..) => bug!("Trying to dedup-reserve memory with real data!"),
506 }
f9f354fc 507 if let Some(&alloc_id) = alloc_map.dedup.get(&alloc) {
94b46f34
XL
508 return alloc_id;
509 }
f9f354fc 510 let id = alloc_map.reserve();
064997fb 511 debug!("creating alloc {alloc:?} with id {id:?}");
f9f354fc
XL
512 alloc_map.alloc_map.insert(id, alloc.clone());
513 alloc_map.dedup.insert(alloc, id);
94b46f34
XL
514 id
515 }
516
dc9dc135
XL
517 /// Generates an `AllocId` for a static or return a cached one in case this function has been
518 /// called on the same static before.
1b1a35ee 519 pub fn create_static_alloc(self, static_id: DefId) -> AllocId {
dc9dc135
XL
520 self.reserve_and_set_dedup(GlobalAlloc::Static(static_id))
521 }
522
9c376795 523 /// Generates an `AllocId` for a function. Depending on the function type,
dc9dc135 524 /// this might get deduplicated or assigned a new ID each time.
1b1a35ee 525 pub fn create_fn_alloc(self, instance: Instance<'tcx>) -> AllocId {
9fa01778
XL
526 // Functions cannot be identified by pointers, as asm-equal functions can get deduplicated
527 // by the linker (we set the "unnamed_addr" attribute for LLVM) and functions can be
528 // duplicated across crates.
529 // We thus generate a new `AllocId` for every mention of a function. This means that
530 // `main as fn() == main as fn()` is false, while `let x = main as fn(); x == x` is true.
531 // However, formatting code relies on function identity (see #58320), so we only do
9c376795 532 // this for generic functions. Lifetime parameters are ignored.
29967ef6
XL
533 let is_generic = instance
534 .substs
535 .into_iter()
536 .any(|kind| !matches!(kind.unpack(), GenericArgKind::Lifetime(_)));
9fa01778 537 if is_generic {
e1599b0c 538 // Get a fresh ID.
f9f354fc
XL
539 let mut alloc_map = self.alloc_map.lock();
540 let id = alloc_map.reserve();
541 alloc_map.alloc_map.insert(id, GlobalAlloc::Function(instance));
9fa01778
XL
542 id
543 } else {
e1599b0c 544 // Deduplicate.
dc9dc135 545 self.reserve_and_set_dedup(GlobalAlloc::Function(instance))
9fa01778 546 }
94b46f34
XL
547 }
548
9c376795 549 /// Generates an `AllocId` for a (symbolic, not-reified) vtable. Will get deduplicated.
064997fb
FG
550 pub fn create_vtable_alloc(
551 self,
552 ty: Ty<'tcx>,
553 poly_trait_ref: Option<ty::PolyExistentialTraitRef<'tcx>>,
554 ) -> AllocId {
555 self.reserve_and_set_dedup(GlobalAlloc::VTable(ty, poly_trait_ref))
556 }
557
e1599b0c 558 /// Interns the `Allocation` and return a new `AllocId`, even if there's already an identical
dc9dc135
XL
559 /// `Allocation` with a different `AllocId`.
560 /// Statics with identical content will still point to the same `Allocation`, i.e.,
561 /// their data will be deduplicated through `Allocation` interning -- but they
562 /// are different places in memory and as such need different IDs.
5e7ed085 563 pub fn create_memory_alloc(self, mem: ConstAllocation<'tcx>) -> AllocId {
f9f354fc 564 let id = self.reserve_alloc_id();
dc9dc135
XL
565 self.set_alloc_id_memory(id, mem);
566 id
567 }
568
532ac7d7 569 /// Returns `None` in case the `AllocId` is dangling. An `InterpretCx` can still have a
0731742a
XL
570 /// local `Allocation` for that `AllocId`, but having such an `AllocId` in a constant is
571 /// illegal and will likely ICE.
572 /// This function exists to allow const eval to detect the difference between evaluation-
573 /// local dangling pointers and allocations in constants/statics.
dc9dc135 574 #[inline]
064997fb 575 pub fn try_get_global_alloc(self, id: AllocId) -> Option<GlobalAlloc<'tcx>> {
f9f354fc 576 self.alloc_map.lock().alloc_map.get(&id).cloned()
94b46f34
XL
577 }
578
f9f354fc
XL
579 #[inline]
580 #[track_caller]
581 /// Panics in case the `AllocId` is dangling. Since that is impossible for `AllocId`s in
582 /// constants (as all constants must pass interning and validation that check for dangling
583 /// ids), this function is frequently used throughout rustc, but should not be used within
584 /// the miri engine.
1b1a35ee 585 pub fn global_alloc(self, id: AllocId) -> GlobalAlloc<'tcx> {
064997fb 586 match self.try_get_global_alloc(id) {
f9f354fc 587 Some(alloc) => alloc,
064997fb 588 None => bug!("could not find allocation for {id:?}"),
e74abb32
XL
589 }
590 }
591
e1599b0c 592 /// Freezes an `AllocId` created with `reserve` by pointing it at an `Allocation`. Trying to
0731742a 593 /// call this function twice, even with the same `Allocation` will ICE the compiler.
5e7ed085 594 pub fn set_alloc_id_memory(self, id: AllocId, mem: ConstAllocation<'tcx>) {
f9f354fc 595 if let Some(old) = self.alloc_map.lock().alloc_map.insert(id, GlobalAlloc::Memory(mem)) {
064997fb 596 bug!("tried to set allocation ID {id:?}, but it was already existing as {old:#?}");
94b46f34
XL
597 }
598 }
599
e1599b0c 600 /// Freezes an `AllocId` created with `reserve` by pointing it at an `Allocation`. May be called
0731742a 601 /// twice for the same `(AllocId, Allocation)` pair.
5e7ed085 602 fn set_alloc_id_same_memory(self, id: AllocId, mem: ConstAllocation<'tcx>) {
f9f354fc 603 self.alloc_map.lock().alloc_map.insert_same(id, GlobalAlloc::Memory(mem));
94b46f34
XL
604 }
605}
606
94b46f34
XL
607////////////////////////////////////////////////////////////////////////////////
608// Methods to access integers in the target endianness
609////////////////////////////////////////////////////////////////////////////////
610
dc9dc135 611#[inline]
94b46f34 612pub fn write_target_uint(
ba9703b0 613 endianness: Endian,
94b46f34
XL
614 mut target: &mut [u8],
615 data: u128,
616) -> Result<(), io::Error> {
1b1a35ee
XL
617 // This u128 holds an "any-size uint" (since smaller uints can fits in it)
618 // So we do not write all bytes of the u128, just the "payload".
94b46f34 619 match endianness {
1b1a35ee
XL
620 Endian::Little => target.write(&data.to_le_bytes())?,
621 Endian::Big => target.write(&data.to_be_bytes()[16 - target.len()..])?,
622 };
623 debug_assert!(target.len() == 0); // We should have filled the target buffer.
624 Ok(())
94b46f34
XL
625}
626
dc9dc135 627#[inline]
ba9703b0 628pub fn read_target_uint(endianness: Endian, mut source: &[u8]) -> Result<u128, io::Error> {
1b1a35ee
XL
629 // This u128 holds an "any-size uint" (since smaller uints can fits in it)
630 let mut buf = [0u8; std::mem::size_of::<u128>()];
631 // So we do not read exactly 16 bytes into the u128, just the "payload".
632 let uint = match endianness {
633 Endian::Little => {
634 source.read(&mut buf)?;
635 Ok(u128::from_le_bytes(buf))
636 }
637 Endian::Big => {
638 source.read(&mut buf[16 - source.len()..])?;
639 Ok(u128::from_be_bytes(buf))
640 }
641 };
642 debug_assert!(source.len() == 0); // We should have consumed the source buffer.
643 uint
94b46f34 644}