]>
Commit | Line | Data |
---|---|---|
b7449926 XL |
1 | //! Computations on places -- field projections, going from mir::Place, and writing |
2 | //! into a place. | |
3 | //! All high-level functions to write to memory work on places as destinations. | |
4 | ||
487cf647 FG |
5 | use either::{Either, Left, Right}; |
6 | ||
17df50a5 | 7 | use rustc_ast::Mutability; |
49aad941 | 8 | use rustc_index::IndexSlice; |
ba9703b0 | 9 | use rustc_middle::mir; |
064997fb | 10 | use rustc_middle::ty; |
9ffffee4 | 11 | use rustc_middle::ty::layout::{LayoutOf, TyAndLayout}; |
353b0b11 | 12 | use rustc_target::abi::{self, Abi, Align, FieldIdx, HasDataLayout, Size, FIRST_VARIANT}; |
ff7c6d11 | 13 | |
0bf4aa26 | 14 | use super::{ |
136023e0 | 15 | alloc_range, mir_assign_valid_types, AllocId, AllocRef, AllocRefMut, CheckInAllocMsg, |
064997fb | 16 | ConstAlloc, ImmTy, Immediate, InterpCx, InterpResult, Machine, MemoryKind, OpTy, Operand, |
f2b60f7d | 17 | Pointer, Provenance, Scalar, |
b7449926 | 18 | }; |
ff7c6d11 | 19 | |
064997fb | 20 | #[derive(Copy, Clone, Hash, PartialEq, Eq, Debug)] |
dfeec247 | 21 | /// Information required for the sound usage of a `MemPlace`. |
064997fb | 22 | pub enum MemPlaceMeta<Prov: Provenance = AllocId> { |
dfeec247 | 23 | /// The unsized payload (e.g. length for slices or vtable pointer for trait objects). |
064997fb | 24 | Meta(Scalar<Prov>), |
dfeec247 XL |
25 | /// `Sized` types or unsized `extern type` |
26 | None, | |
dfeec247 XL |
27 | } |
28 | ||
064997fb | 29 | impl<Prov: Provenance> MemPlaceMeta<Prov> { |
9ffffee4 | 30 | #[cfg_attr(debug_assertions, track_caller)] // only in debug builds due to perf (see #98980) |
064997fb | 31 | pub fn unwrap_meta(self) -> Scalar<Prov> { |
dfeec247 XL |
32 | match self { |
33 | Self::Meta(s) => s, | |
064997fb | 34 | Self::None => { |
dfeec247 XL |
35 | bug!("expected wide pointer extra data (e.g. slice length or trait object vtable)") |
36 | } | |
37 | } | |
38 | } | |
064997fb FG |
39 | |
40 | pub fn has_meta(self) -> bool { | |
dfeec247 XL |
41 | match self { |
42 | Self::Meta(_) => true, | |
064997fb | 43 | Self::None => false, |
dfeec247 XL |
44 | } |
45 | } | |
dfeec247 XL |
46 | } |
47 | ||
064997fb FG |
48 | #[derive(Copy, Clone, Hash, PartialEq, Eq, Debug)] |
49 | pub struct MemPlace<Prov: Provenance = AllocId> { | |
50 | /// The pointer can be a pure integer, with the `None` provenance. | |
51 | pub ptr: Pointer<Option<Prov>>, | |
9fa01778 | 52 | /// Metadata for unsized places. Interpretation is up to the type. |
b7449926 | 53 | /// Must not be present for sized types, but can be missing for unsized types |
0731742a | 54 | /// (e.g., `extern type`). |
064997fb | 55 | pub meta: MemPlaceMeta<Prov>, |
b7449926 XL |
56 | } |
57 | ||
064997fb FG |
58 | /// A MemPlace with its layout. Constructing it is only possible in this module. |
59 | #[derive(Copy, Clone, Hash, Eq, PartialEq, Debug)] | |
60 | pub struct MPlaceTy<'tcx, Prov: Provenance = AllocId> { | |
61 | mplace: MemPlace<Prov>, | |
62 | pub layout: TyAndLayout<'tcx>, | |
63 | /// rustc does not have a proper way to represent the type of a field of a `repr(packed)` struct: | |
64 | /// it needs to have a different alignment than the field type would usually have. | |
65 | /// So we represent this here with a separate field that "overwrites" `layout.align`. | |
66 | /// This means `layout.align` should never be used for a `MPlaceTy`! | |
67 | pub align: Align, | |
68 | } | |
6a06907d | 69 | |
064997fb FG |
70 | #[derive(Copy, Clone, Debug)] |
71 | pub enum Place<Prov: Provenance = AllocId> { | |
2c00a5a8 | 72 | /// A place referring to a value allocated in the `Memory` system. |
064997fb | 73 | Ptr(MemPlace<Prov>), |
b7449926 XL |
74 | |
75 | /// To support alloc-free locals, we are able to write directly to a local. | |
76 | /// (Without that optimization, we'd just always be a `MemPlace`.) | |
dfeec247 | 77 | Local { frame: usize, local: mir::Local }, |
b7449926 XL |
78 | } |
79 | ||
064997fb FG |
80 | #[derive(Clone, Debug)] |
81 | pub struct PlaceTy<'tcx, Prov: Provenance = AllocId> { | |
82 | place: Place<Prov>, // Keep this private; it helps enforce invariants. | |
ba9703b0 | 83 | pub layout: TyAndLayout<'tcx>, |
064997fb FG |
84 | /// rustc does not have a proper way to represent the type of a field of a `repr(packed)` struct: |
85 | /// it needs to have a different alignment than the field type would usually have. | |
86 | /// So we represent this here with a separate field that "overwrites" `layout.align`. | |
87 | /// This means `layout.align` should never be used for a `PlaceTy`! | |
88 | pub align: Align, | |
ff7c6d11 XL |
89 | } |
90 | ||
064997fb FG |
91 | impl<'tcx, Prov: Provenance> std::ops::Deref for PlaceTy<'tcx, Prov> { |
92 | type Target = Place<Prov>; | |
b7449926 | 93 | #[inline(always)] |
064997fb | 94 | fn deref(&self) -> &Place<Prov> { |
b7449926 XL |
95 | &self.place |
96 | } | |
ff7c6d11 XL |
97 | } |
98 | ||
064997fb FG |
99 | impl<'tcx, Prov: Provenance> std::ops::Deref for MPlaceTy<'tcx, Prov> { |
100 | type Target = MemPlace<Prov>; | |
101 | #[inline(always)] | |
102 | fn deref(&self) -> &MemPlace<Prov> { | |
103 | &self.mplace | |
104 | } | |
b7449926 XL |
105 | } |
106 | ||
064997fb FG |
107 | impl<'tcx, Prov: Provenance> From<MPlaceTy<'tcx, Prov>> for PlaceTy<'tcx, Prov> { |
108 | #[inline(always)] | |
109 | fn from(mplace: MPlaceTy<'tcx, Prov>) -> Self { | |
110 | PlaceTy { place: Place::Ptr(*mplace), layout: mplace.layout, align: mplace.align } | |
111 | } | |
112 | } | |
6a06907d | 113 | |
064997fb | 114 | impl<'tcx, Prov: Provenance> From<&'_ MPlaceTy<'tcx, Prov>> for PlaceTy<'tcx, Prov> { |
b7449926 | 115 | #[inline(always)] |
064997fb FG |
116 | fn from(mplace: &MPlaceTy<'tcx, Prov>) -> Self { |
117 | PlaceTy { place: Place::Ptr(**mplace), layout: mplace.layout, align: mplace.align } | |
b7449926 XL |
118 | } |
119 | } | |
120 | ||
064997fb | 121 | impl<'tcx, Prov: Provenance> From<&'_ mut MPlaceTy<'tcx, Prov>> for PlaceTy<'tcx, Prov> { |
b7449926 | 122 | #[inline(always)] |
064997fb FG |
123 | fn from(mplace: &mut MPlaceTy<'tcx, Prov>) -> Self { |
124 | PlaceTy { place: Place::Ptr(**mplace), layout: mplace.layout, align: mplace.align } | |
ff7c6d11 | 125 | } |
b7449926 | 126 | } |
ff7c6d11 | 127 | |
064997fb | 128 | impl<Prov: Provenance> MemPlace<Prov> { |
b7449926 | 129 | #[inline(always)] |
064997fb FG |
130 | pub fn from_ptr(ptr: Pointer<Option<Prov>>) -> Self { |
131 | MemPlace { ptr, meta: MemPlaceMeta::None } | |
ff7c6d11 XL |
132 | } |
133 | ||
136023e0 | 134 | /// Adjust the provenance of the main pointer (metadata is unaffected). |
064997fb | 135 | pub fn map_provenance(self, f: impl FnOnce(Option<Prov>) -> Option<Prov>) -> Self { |
136023e0 | 136 | MemPlace { ptr: self.ptr.map_provenance(f), ..self } |
ff7c6d11 XL |
137 | } |
138 | ||
60c5eb7d | 139 | /// Turn a mplace into a (thin or wide) pointer, as a reference, pointing to the same space. |
a1dfa0c6 XL |
140 | /// This is the inverse of `ref_to_mplace`. |
141 | #[inline(always)] | |
064997fb | 142 | pub fn to_ref(self, cx: &impl HasDataLayout) -> Immediate<Prov> { |
a1dfa0c6 | 143 | match self.meta { |
136023e0 XL |
144 | MemPlaceMeta::None => Immediate::from(Scalar::from_maybe_pointer(self.ptr, cx)), |
145 | MemPlaceMeta::Meta(meta) => { | |
9c376795 | 146 | Immediate::ScalarPair(Scalar::from_maybe_pointer(self.ptr, cx), meta) |
136023e0 | 147 | } |
a1dfa0c6 XL |
148 | } |
149 | } | |
150 | ||
5869c6ff | 151 | #[inline] |
9ffffee4 | 152 | pub(super) fn offset_with_meta<'tcx>( |
a1dfa0c6 XL |
153 | self, |
154 | offset: Size, | |
064997fb | 155 | meta: MemPlaceMeta<Prov>, |
a1dfa0c6 | 156 | cx: &impl HasDataLayout, |
dc9dc135 | 157 | ) -> InterpResult<'tcx, Self> { |
9ffffee4 FG |
158 | debug_assert!( |
159 | !meta.has_meta() || self.meta.has_meta(), | |
160 | "cannot use `offset_with_meta` to add metadata to a place" | |
161 | ); | |
064997fb FG |
162 | Ok(MemPlace { ptr: self.ptr.offset(offset, cx)?, meta }) |
163 | } | |
164 | } | |
165 | ||
166 | impl<Prov: Provenance> Place<Prov> { | |
167 | /// Asserts that this points to some local variable. | |
168 | /// Returns the frame idx and the variable idx. | |
169 | #[inline] | |
170 | #[cfg_attr(debug_assertions, track_caller)] // only in debug builds due to perf (see #98980) | |
171 | pub fn assert_local(&self) -> (usize, mir::Local) { | |
172 | match self { | |
173 | Place::Local { frame, local } => (*frame, *local), | |
174 | _ => bug!("assert_local: expected Place::Local, got {:?}", self), | |
175 | } | |
a1dfa0c6 | 176 | } |
0bf4aa26 | 177 | } |
b7449926 | 178 | |
064997fb FG |
179 | impl<'tcx, Prov: Provenance> MPlaceTy<'tcx, Prov> { |
180 | /// Produces a MemPlace that works for ZST but nothing else. | |
181 | /// Conceptually this is a new allocation, but it doesn't actually create an allocation so you | |
182 | /// don't need to worry about memory leaks. | |
0bf4aa26 | 183 | #[inline] |
064997fb FG |
184 | pub fn fake_alloc_zst(layout: TyAndLayout<'tcx>) -> Self { |
185 | assert!(layout.is_zst()); | |
dfeec247 | 186 | let align = layout.align.abi; |
9ffffee4 | 187 | let ptr = Pointer::from_addr_invalid(align.bytes()); // no provenance, absolute address |
064997fb | 188 | MPlaceTy { mplace: MemPlace { ptr, meta: MemPlaceMeta::None }, layout, align } |
ff7c6d11 XL |
189 | } |
190 | ||
9ffffee4 FG |
191 | /// Offset the place in memory and change its metadata. |
192 | /// | |
193 | /// This can go wrong very easily if you give the wrong layout for the new place! | |
0731742a | 194 | #[inline] |
9ffffee4 | 195 | pub(crate) fn offset_with_meta( |
064997fb FG |
196 | &self, |
197 | offset: Size, | |
198 | meta: MemPlaceMeta<Prov>, | |
199 | layout: TyAndLayout<'tcx>, | |
200 | cx: &impl HasDataLayout, | |
201 | ) -> InterpResult<'tcx, Self> { | |
202 | Ok(MPlaceTy { | |
203 | mplace: self.mplace.offset_with_meta(offset, meta, cx)?, | |
204 | align: self.align.restrict_for_offset(offset), | |
205 | layout, | |
206 | }) | |
207 | } | |
208 | ||
9ffffee4 FG |
209 | /// Offset the place in memory. |
210 | /// | |
211 | /// This can go wrong very easily if you give the wrong layout for the new place! | |
a1dfa0c6 | 212 | pub fn offset( |
6a06907d | 213 | &self, |
a1dfa0c6 | 214 | offset: Size, |
ba9703b0 | 215 | layout: TyAndLayout<'tcx>, |
a1dfa0c6 | 216 | cx: &impl HasDataLayout, |
dc9dc135 | 217 | ) -> InterpResult<'tcx, Self> { |
487cf647 | 218 | assert!(layout.is_sized()); |
064997fb | 219 | self.offset_with_meta(offset, MemPlaceMeta::None, layout, cx) |
a1dfa0c6 XL |
220 | } |
221 | ||
b7449926 | 222 | #[inline] |
064997fb FG |
223 | pub fn from_aligned_ptr(ptr: Pointer<Option<Prov>>, layout: TyAndLayout<'tcx>) -> Self { |
224 | MPlaceTy { mplace: MemPlace::from_ptr(ptr), layout, align: layout.align.abi } | |
ff7c6d11 XL |
225 | } |
226 | ||
923072b8 FG |
227 | #[inline] |
228 | pub fn from_aligned_ptr_with_meta( | |
064997fb | 229 | ptr: Pointer<Option<Prov>>, |
923072b8 | 230 | layout: TyAndLayout<'tcx>, |
064997fb | 231 | meta: MemPlaceMeta<Prov>, |
923072b8 | 232 | ) -> Self { |
064997fb | 233 | let mut mplace = MemPlace::from_ptr(ptr); |
923072b8 FG |
234 | mplace.meta = meta; |
235 | ||
064997fb | 236 | MPlaceTy { mplace, layout, align: layout.align.abi } |
923072b8 FG |
237 | } |
238 | ||
b7449926 | 239 | #[inline] |
04454e1e | 240 | pub(crate) fn len(&self, cx: &impl HasDataLayout) -> InterpResult<'tcx, u64> { |
b7449926 | 241 | if self.layout.is_unsized() { |
0bf4aa26 | 242 | // We need to consult `meta` metadata |
1b1a35ee | 243 | match self.layout.ty.kind() { |
9ffffee4 | 244 | ty::Slice(..) | ty::Str => self.mplace.meta.unwrap_meta().to_target_usize(cx), |
b7449926 | 245 | _ => bug!("len not supported on unsized type {:?}", self.layout.ty), |
ff7c6d11 | 246 | } |
b7449926 | 247 | } else { |
9c376795 | 248 | // Go through the layout. There are lots of types that support a length, |
3c0e092e | 249 | // e.g., SIMD types. (But not all repr(simd) types even have FieldsShape::Array!) |
b7449926 | 250 | match self.layout.fields { |
064997fb | 251 | abi::FieldsShape::Array { count, .. } => Ok(count), |
b7449926 XL |
252 | _ => bug!("len not supported on sized type {:?}", self.layout.ty), |
253 | } | |
254 | } | |
255 | } | |
ff7c6d11 XL |
256 | } |
257 | ||
416331ca | 258 | // These are defined here because they produce a place. |
064997fb | 259 | impl<'tcx, Prov: Provenance> OpTy<'tcx, Prov> { |
b7449926 | 260 | #[inline(always)] |
487cf647 | 261 | pub fn as_mplace_or_imm(&self) -> Either<MPlaceTy<'tcx, Prov>, ImmTy<'tcx, Prov>> { |
6a06907d | 262 | match **self { |
064997fb | 263 | Operand::Indirect(mplace) => { |
487cf647 | 264 | Left(MPlaceTy { mplace, layout: self.layout, align: self.align.unwrap() }) |
064997fb | 265 | } |
487cf647 | 266 | Operand::Immediate(imm) => Right(ImmTy::from_immediate(imm, self.layout)), |
b7449926 XL |
267 | } |
268 | } | |
269 | ||
270 | #[inline(always)] | |
064997fb | 271 | #[cfg_attr(debug_assertions, track_caller)] // only in debug builds due to perf (see #98980) |
064997fb | 272 | pub fn assert_mem_place(&self) -> MPlaceTy<'tcx, Prov> { |
9ffffee4 FG |
273 | self.as_mplace_or_imm().left().unwrap_or_else(|| { |
274 | bug!( | |
275 | "OpTy of type {} was immediate when it was expected to be an MPlace", | |
276 | self.layout.ty | |
277 | ) | |
278 | }) | |
b7449926 XL |
279 | } |
280 | } | |
281 | ||
064997fb FG |
282 | impl<'tcx, Prov: Provenance> PlaceTy<'tcx, Prov> { |
283 | /// A place is either an mplace or some local. | |
b7449926 | 284 | #[inline] |
487cf647 | 285 | pub fn as_mplace_or_local(&self) -> Either<MPlaceTy<'tcx, Prov>, (usize, mir::Local)> { |
064997fb | 286 | match **self { |
487cf647 FG |
287 | Place::Ptr(mplace) => Left(MPlaceTy { mplace, layout: self.layout, align: self.align }), |
288 | Place::Local { frame, local } => Right((frame, local)), | |
b7449926 XL |
289 | } |
290 | } | |
b7449926 | 291 | |
064997fb FG |
292 | #[inline(always)] |
293 | #[cfg_attr(debug_assertions, track_caller)] // only in debug builds due to perf (see #98980) | |
2b03887a | 294 | pub fn assert_mem_place(&self) -> MPlaceTy<'tcx, Prov> { |
9ffffee4 FG |
295 | self.as_mplace_or_local().left().unwrap_or_else(|| { |
296 | bug!( | |
297 | "PlaceTy of type {} was a local when it was expected to be an MPlace", | |
298 | self.layout.ty | |
299 | ) | |
300 | }) | |
b7449926 XL |
301 | } |
302 | } | |
303 | ||
064997fb FG |
304 | // FIXME: Working around https://github.com/rust-lang/rust/issues/54385 |
305 | impl<'mir, 'tcx: 'mir, Prov, M> InterpCx<'mir, 'tcx, M> | |
0bf4aa26 | 306 | where |
f2b60f7d | 307 | Prov: Provenance + 'static, |
064997fb | 308 | M: Machine<'mir, 'tcx, Provenance = Prov>, |
0bf4aa26 | 309 | { |
60c5eb7d | 310 | /// Take a value, which represents a (thin or wide) reference, and make it a place. |
9c376795 | 311 | /// Alignment is just based on the type. This is the inverse of `MemPlace::to_ref()`. |
e1599b0c XL |
312 | /// |
313 | /// Only call this if you are sure the place is "valid" (aligned and inbounds), or do not | |
314 | /// want to ever use the place for memory access! | |
315 | /// Generally prefer `deref_operand`. | |
b7449926 | 316 | pub fn ref_to_mplace( |
0bf4aa26 | 317 | &self, |
064997fb FG |
318 | val: &ImmTy<'tcx, M::Provenance>, |
319 | ) -> InterpResult<'tcx, MPlaceTy<'tcx, M::Provenance>> { | |
dfeec247 XL |
320 | let pointee_type = |
321 | val.layout.ty.builtin_deref(true).expect("`ref_to_mplace` called on non-ptr type").ty; | |
b7449926 | 322 | let layout = self.layout_of(pointee_type)?; |
6a06907d | 323 | let (ptr, meta) = match **val { |
136023e0 | 324 | Immediate::Scalar(ptr) => (ptr, MemPlaceMeta::None), |
f2b60f7d | 325 | Immediate::ScalarPair(ptr, meta) => (ptr, MemPlaceMeta::Meta(meta)), |
064997fb | 326 | Immediate::Uninit => throw_ub!(InvalidUninitBytes(None)), |
60c5eb7d | 327 | }; |
0bf4aa26 | 328 | |
064997fb FG |
329 | let mplace = MemPlace { ptr: ptr.to_pointer(self)?, meta }; |
330 | // When deref'ing a pointer, the *static* alignment given by the type is what matters. | |
331 | let align = layout.align.abi; | |
332 | Ok(MPlaceTy { mplace, layout, align }) | |
b7449926 XL |
333 | } |
334 | ||
487cf647 | 335 | /// Take an operand, representing a pointer, and dereference it to a place. |
04454e1e | 336 | #[instrument(skip(self), level = "debug")] |
a1dfa0c6 XL |
337 | pub fn deref_operand( |
338 | &self, | |
064997fb FG |
339 | src: &OpTy<'tcx, M::Provenance>, |
340 | ) -> InterpResult<'tcx, MPlaceTy<'tcx, M::Provenance>> { | |
a1dfa0c6 XL |
341 | let val = self.read_immediate(src)?; |
342 | trace!("deref to {} on {:?}", val.layout.ty, *val); | |
923072b8 FG |
343 | |
344 | if val.layout.ty.is_box() { | |
345 | bug!("dereferencing {:?}", val.layout.ty); | |
346 | } | |
347 | ||
136023e0 | 348 | let mplace = self.ref_to_mplace(&val)?; |
487cf647 | 349 | self.check_mplace(mplace)?; |
136023e0 | 350 | Ok(mplace) |
0bf4aa26 XL |
351 | } |
352 | ||
416331ca | 353 | #[inline] |
04454e1e | 354 | pub(super) fn get_place_alloc( |
416331ca | 355 | &self, |
064997fb | 356 | place: &MPlaceTy<'tcx, M::Provenance>, |
9ffffee4 FG |
357 | ) -> InterpResult<'tcx, Option<AllocRef<'_, 'tcx, M::Provenance, M::AllocExtra, M::Bytes>>> |
358 | { | |
487cf647 | 359 | assert!(place.layout.is_sized()); |
17df50a5 XL |
360 | assert!(!place.meta.has_meta()); |
361 | let size = place.layout.size; | |
04454e1e | 362 | self.get_ptr_alloc(place.ptr, size, place.align) |
17df50a5 XL |
363 | } |
364 | ||
365 | #[inline] | |
04454e1e | 366 | pub(super) fn get_place_alloc_mut( |
17df50a5 | 367 | &mut self, |
064997fb | 368 | place: &MPlaceTy<'tcx, M::Provenance>, |
9ffffee4 FG |
369 | ) -> InterpResult<'tcx, Option<AllocRefMut<'_, 'tcx, M::Provenance, M::AllocExtra, M::Bytes>>> |
370 | { | |
487cf647 | 371 | assert!(place.layout.is_sized()); |
17df50a5 XL |
372 | assert!(!place.meta.has_meta()); |
373 | let size = place.layout.size; | |
04454e1e | 374 | self.get_ptr_alloc_mut(place.ptr, size, place.align) |
416331ca XL |
375 | } |
376 | ||
a2a8927a | 377 | /// Check if this mplace is dereferenceable and sufficiently aligned. |
487cf647 | 378 | pub fn check_mplace(&self, mplace: MPlaceTy<'tcx, M::Provenance>) -> InterpResult<'tcx> { |
dfeec247 | 379 | let (size, align) = self |
136023e0 XL |
380 | .size_and_align_of_mplace(&mplace)? |
381 | .unwrap_or((mplace.layout.size, mplace.layout.align.abi)); | |
064997fb | 382 | assert!(mplace.align <= align, "dynamic alignment less strict than static one?"); |
9c376795 FG |
383 | let align = if M::enforce_alignment(self).should_check() { align } else { Align::ONE }; |
384 | self.check_ptr_access_align(mplace.ptr, size, align, CheckInAllocMsg::DerefTest)?; | |
136023e0 | 385 | Ok(()) |
416331ca XL |
386 | } |
387 | ||
3c0e092e XL |
388 | /// Converts a repr(simd) place into a place where `place_index` accesses the SIMD elements. |
389 | /// Also returns the number of elements. | |
390 | pub fn mplace_to_simd( | |
391 | &self, | |
064997fb FG |
392 | mplace: &MPlaceTy<'tcx, M::Provenance>, |
393 | ) -> InterpResult<'tcx, (MPlaceTy<'tcx, M::Provenance>, u64)> { | |
3c0e092e XL |
394 | // Basically we just transmute this place into an array following simd_size_and_type. |
395 | // (Transmuting is okay since this is an in-memory place. We also double-check the size | |
396 | // stays the same.) | |
064997fb | 397 | let (len, e_ty) = mplace.layout.ty.simd_size_and_type(*self.tcx); |
3c0e092e XL |
398 | let array = self.tcx.mk_array(e_ty, len); |
399 | let layout = self.layout_of(array)?; | |
064997fb FG |
400 | assert_eq!(layout.size, mplace.layout.size); |
401 | Ok((MPlaceTy { layout, ..*mplace }, len)) | |
b7449926 | 402 | } |
ff7c6d11 | 403 | |
3c0e092e XL |
404 | /// Converts a repr(simd) place into a place where `place_index` accesses the SIMD elements. |
405 | /// Also returns the number of elements. | |
406 | pub fn place_to_simd( | |
407 | &mut self, | |
064997fb FG |
408 | place: &PlaceTy<'tcx, M::Provenance>, |
409 | ) -> InterpResult<'tcx, (MPlaceTy<'tcx, M::Provenance>, u64)> { | |
410 | let mplace = self.force_allocation(place)?; | |
3c0e092e XL |
411 | self.mplace_to_simd(&mplace) |
412 | } | |
413 | ||
064997fb FG |
414 | pub fn local_to_place( |
415 | &self, | |
416 | frame: usize, | |
417 | local: mir::Local, | |
418 | ) -> InterpResult<'tcx, PlaceTy<'tcx, M::Provenance>> { | |
419 | let layout = self.layout_of_local(&self.stack()[frame], local, None)?; | |
420 | let place = Place::Local { frame, local }; | |
421 | Ok(PlaceTy { place, layout, align: layout.align.abi }) | |
422 | } | |
423 | ||
9fa01778 | 424 | /// Computes a place. You should only use this if you intend to write into this |
04454e1e FG |
425 | /// place; for reading, a more efficient alternative is `eval_place_to_op`. |
426 | #[instrument(skip(self), level = "debug")] | |
0bf4aa26 XL |
427 | pub fn eval_place( |
428 | &mut self, | |
064997fb FG |
429 | mir_place: mir::Place<'tcx>, |
430 | ) -> InterpResult<'tcx, PlaceTy<'tcx, M::Provenance>> { | |
431 | let mut place = self.local_to_place(self.frame_idx(), mir_place.local)?; | |
432 | // Using `try_fold` turned out to be bad for performance, hence the loop. | |
433 | for elem in mir_place.projection.iter() { | |
434 | place = self.place_projection(&place, elem)? | |
e1599b0c | 435 | } |
ff7c6d11 | 436 | |
064997fb | 437 | trace!("{:?}", self.dump_place(place.place)); |
f9f354fc | 438 | // Sanity-check the type we ended up with. |
064997fb FG |
439 | debug_assert!( |
440 | mir_assign_valid_types( | |
441 | *self.tcx, | |
442 | self.param_env, | |
443 | self.layout_of(self.subst_from_current_frame_and_normalize_erasing_regions( | |
444 | mir_place.ty(&self.frame().body.local_decls, *self.tcx).ty | |
445 | )?)?, | |
446 | place.layout, | |
447 | ), | |
448 | "eval_place of a MIR place with type {:?} produced an interpreter place with type {:?}", | |
449 | mir_place.ty(&self.frame().body.local_decls, *self.tcx).ty, | |
450 | place.layout.ty, | |
451 | ); | |
452 | Ok(place) | |
ff7c6d11 XL |
453 | } |
454 | ||
a1dfa0c6 | 455 | /// Write an immediate to a place |
0bf4aa26 | 456 | #[inline(always)] |
04454e1e | 457 | #[instrument(skip(self), level = "debug")] |
a1dfa0c6 | 458 | pub fn write_immediate( |
b7449926 | 459 | &mut self, |
064997fb FG |
460 | src: Immediate<M::Provenance>, |
461 | dest: &PlaceTy<'tcx, M::Provenance>, | |
dc9dc135 | 462 | ) -> InterpResult<'tcx> { |
a1dfa0c6 | 463 | self.write_immediate_no_validate(src, dest)?; |
0bf4aa26 | 464 | |
353b0b11 | 465 | if M::enforce_validity(self, dest.layout) { |
0bf4aa26 | 466 | // Data got changed, better make sure it matches the type! |
6a06907d | 467 | self.validate_operand(&self.place_to_op(dest)?)?; |
dc9dc135 XL |
468 | } |
469 | ||
470 | Ok(()) | |
471 | } | |
472 | ||
136023e0 | 473 | /// Write a scalar to a place |
dc9dc135 | 474 | #[inline(always)] |
136023e0 | 475 | pub fn write_scalar( |
dc9dc135 | 476 | &mut self, |
f2b60f7d | 477 | val: impl Into<Scalar<M::Provenance>>, |
064997fb | 478 | dest: &PlaceTy<'tcx, M::Provenance>, |
dc9dc135 | 479 | ) -> InterpResult<'tcx> { |
136023e0 XL |
480 | self.write_immediate(Immediate::Scalar(val.into()), dest) |
481 | } | |
0bf4aa26 | 482 | |
136023e0 XL |
483 | /// Write a pointer to a place |
484 | #[inline(always)] | |
485 | pub fn write_pointer( | |
486 | &mut self, | |
064997fb FG |
487 | ptr: impl Into<Pointer<Option<M::Provenance>>>, |
488 | dest: &PlaceTy<'tcx, M::Provenance>, | |
136023e0 XL |
489 | ) -> InterpResult<'tcx> { |
490 | self.write_scalar(Scalar::from_maybe_pointer(ptr.into(), self), dest) | |
0bf4aa26 XL |
491 | } |
492 | ||
a1dfa0c6 | 493 | /// Write an immediate to a place. |
0bf4aa26 XL |
494 | /// If you use this you are responsible for validating that things got copied at the |
495 | /// right type. | |
a1dfa0c6 | 496 | fn write_immediate_no_validate( |
0bf4aa26 | 497 | &mut self, |
064997fb FG |
498 | src: Immediate<M::Provenance>, |
499 | dest: &PlaceTy<'tcx, M::Provenance>, | |
dc9dc135 | 500 | ) -> InterpResult<'tcx> { |
487cf647 | 501 | assert!(dest.layout.is_sized(), "Cannot write unsized data"); |
a1dfa0c6 | 502 | trace!("write_immediate: {:?} <- {:?}: {}", *dest, src, dest.layout.ty); |
0bf4aa26 | 503 | |
04454e1e | 504 | // See if we can avoid an allocation. This is the counterpart to `read_immediate_raw`, |
b7449926 XL |
505 | // but not factored as a separate function. |
506 | let mplace = match dest.place { | |
ff7c6d11 | 507 | Place::Local { frame, local } => { |
f035d41b | 508 | match M::access_local_mut(self, frame, local)? { |
064997fb | 509 | Operand::Immediate(local) => { |
48663c56 | 510 | // Local can be updated in-place. |
064997fb | 511 | *local = src; |
b7449926 | 512 | return Ok(()); |
48663c56 | 513 | } |
064997fb | 514 | Operand::Indirect(mplace) => { |
48663c56 | 515 | // The local is in memory, go on below. |
064997fb | 516 | *mplace |
48663c56 | 517 | } |
ff7c6d11 | 518 | } |
dfeec247 | 519 | } |
48663c56 | 520 | Place::Ptr(mplace) => mplace, // already referring to memory |
ff7c6d11 XL |
521 | }; |
522 | ||
b7449926 | 523 | // This is already in memory, write there. |
064997fb | 524 | self.write_immediate_to_mplace_no_validate(src, dest.layout, dest.align, mplace) |
ff7c6d11 XL |
525 | } |
526 | ||
a1dfa0c6 | 527 | /// Write an immediate to memory. |
dc9dc135 | 528 | /// If you use this you are responsible for validating that things got copied at the |
064997fb | 529 | /// right layout. |
a1dfa0c6 | 530 | fn write_immediate_to_mplace_no_validate( |
b7449926 | 531 | &mut self, |
064997fb FG |
532 | value: Immediate<M::Provenance>, |
533 | layout: TyAndLayout<'tcx>, | |
534 | align: Align, | |
535 | dest: MemPlace<M::Provenance>, | |
dc9dc135 | 536 | ) -> InterpResult<'tcx> { |
b7449926 | 537 | // Note that it is really important that the type here is the right one, and matches the |
04454e1e | 538 | // type things are read at. In case `value` is a `ScalarPair`, we don't do any magic here |
b7449926 XL |
539 | // to handle padding properly, which is only correct if we never look at this data with the |
540 | // wrong type. | |
541 | ||
17df50a5 | 542 | let tcx = *self.tcx; |
064997fb | 543 | let Some(mut alloc) = self.get_place_alloc_mut(&MPlaceTy { mplace: dest, layout, align })? else { |
5e7ed085 FG |
544 | // zero-sized access |
545 | return Ok(()); | |
dc9dc135 | 546 | }; |
b7449926 | 547 | |
b7449926 | 548 | match value { |
a1dfa0c6 | 549 | Immediate::Scalar(scalar) => { |
064997fb | 550 | let Abi::Scalar(s) = layout.abi else { span_bug!( |
f035d41b | 551 | self.cur_span(), |
064997fb | 552 | "write_immediate_to_mplace: invalid Scalar layout: {layout:#?}", |
04454e1e FG |
553 | ) |
554 | }; | |
555 | let size = s.size(&tcx); | |
064997fb | 556 | assert_eq!(size, layout.size, "abi::Scalar size does not match layout size"); |
04454e1e | 557 | alloc.write_scalar(alloc_range(Size::ZERO, size), scalar) |
ff7c6d11 | 558 | } |
a1dfa0c6 | 559 | Immediate::ScalarPair(a_val, b_val) => { |
dc9dc135 XL |
560 | // We checked `ptr_align` above, so all fields will have the alignment they need. |
561 | // We would anyway check against `ptr_align.restrict_for_offset(b_offset)`, | |
562 | // which `ptr.offset(b_offset)` cannot possibly fail to satisfy. | |
064997fb | 563 | let Abi::ScalarPair(a, b) = layout.abi else { span_bug!( |
f035d41b | 564 | self.cur_span(), |
dfeec247 | 565 | "write_immediate_to_mplace: invalid ScalarPair layout: {:#?}", |
064997fb | 566 | layout |
04454e1e | 567 | ) |
b7449926 | 568 | }; |
17df50a5 XL |
569 | let (a_size, b_size) = (a.size(&tcx), b.size(&tcx)); |
570 | let b_offset = a_size.align_to(b.align(&tcx).abi); | |
04454e1e | 571 | assert!(b_offset.bytes() > 0); // in `operand_field` we use the offset to tell apart the fields |
a1dfa0c6 | 572 | |
0bf4aa26 XL |
573 | // It is tempting to verify `b_offset` against `layout.fields.offset(1)`, |
574 | // but that does not work: We could be a newtype around a pair, then the | |
575 | // fields do not match the `ScalarPair` components. | |
576 | ||
17df50a5 XL |
577 | alloc.write_scalar(alloc_range(Size::ZERO, a_size), a_val)?; |
578 | alloc.write_scalar(alloc_range(b_offset, b_size), b_val) | |
ff7c6d11 | 579 | } |
064997fb | 580 | Immediate::Uninit => alloc.write_uninit(), |
b7449926 | 581 | } |
ff7c6d11 XL |
582 | } |
583 | ||
064997fb | 584 | pub fn write_uninit(&mut self, dest: &PlaceTy<'tcx, M::Provenance>) -> InterpResult<'tcx> { |
487cf647 FG |
585 | let mplace = match dest.as_mplace_or_local() { |
586 | Left(mplace) => mplace, | |
587 | Right((frame, local)) => { | |
04454e1e | 588 | match M::access_local_mut(self, frame, local)? { |
064997fb FG |
589 | Operand::Immediate(local) => { |
590 | *local = Immediate::Uninit; | |
591 | return Ok(()); | |
592 | } | |
593 | Operand::Indirect(mplace) => { | |
04454e1e | 594 | // The local is in memory, go on below. |
064997fb | 595 | MPlaceTy { mplace: *mplace, layout: dest.layout, align: dest.align } |
04454e1e FG |
596 | } |
597 | } | |
598 | } | |
599 | }; | |
600 | let Some(mut alloc) = self.get_place_alloc_mut(&mplace)? else { | |
601 | // Zero-sized access | |
602 | return Ok(()); | |
603 | }; | |
604 | alloc.write_uninit()?; | |
605 | Ok(()) | |
606 | } | |
607 | ||
064997fb FG |
608 | /// Copies the data from an operand to a place. |
609 | /// `allow_transmute` indicates whether the layouts may disagree. | |
0bf4aa26 | 610 | #[inline(always)] |
04454e1e | 611 | #[instrument(skip(self), level = "debug")] |
b7449926 | 612 | pub fn copy_op( |
ff7c6d11 | 613 | &mut self, |
064997fb FG |
614 | src: &OpTy<'tcx, M::Provenance>, |
615 | dest: &PlaceTy<'tcx, M::Provenance>, | |
616 | allow_transmute: bool, | |
dc9dc135 | 617 | ) -> InterpResult<'tcx> { |
064997fb | 618 | self.copy_op_no_validate(src, dest, allow_transmute)?; |
0bf4aa26 | 619 | |
353b0b11 | 620 | if M::enforce_validity(self, dest.layout) { |
0bf4aa26 | 621 | // Data got changed, better make sure it matches the type! |
6a06907d | 622 | self.validate_operand(&self.place_to_op(dest)?)?; |
0bf4aa26 XL |
623 | } |
624 | ||
625 | Ok(()) | |
626 | } | |
627 | ||
064997fb FG |
628 | /// Copies the data from an operand to a place. |
629 | /// `allow_transmute` indicates whether the layouts may disagree. | |
dc9dc135 | 630 | /// Also, if you use this you are responsible for validating that things get copied at the |
0bf4aa26 | 631 | /// right type. |
04454e1e | 632 | #[instrument(skip(self), level = "debug")] |
0bf4aa26 XL |
633 | fn copy_op_no_validate( |
634 | &mut self, | |
064997fb FG |
635 | src: &OpTy<'tcx, M::Provenance>, |
636 | dest: &PlaceTy<'tcx, M::Provenance>, | |
637 | allow_transmute: bool, | |
dc9dc135 | 638 | ) -> InterpResult<'tcx> { |
0bf4aa26 XL |
639 | // We do NOT compare the types for equality, because well-typed code can |
640 | // actually "transmute" `&mut T` to `&T` in an assignment without a cast. | |
064997fb FG |
641 | let layout_compat = |
642 | mir_assign_valid_types(*self.tcx, self.param_env, src.layout, dest.layout); | |
643 | if !allow_transmute && !layout_compat { | |
ba9703b0 | 644 | span_bug!( |
f035d41b | 645 | self.cur_span(), |
ba9703b0 XL |
646 | "type mismatch when copying!\nsrc: {:?},\ndest: {:?}", |
647 | src.layout.ty, | |
648 | dest.layout.ty, | |
649 | ); | |
650 | } | |
b7449926 | 651 | |
064997fb FG |
652 | // Let us see if the layout is simple so we take a shortcut, |
653 | // avoid force_allocation. | |
f2b60f7d | 654 | let src = match self.read_immediate_raw(src)? { |
487cf647 | 655 | Right(src_val) => { |
2b03887a FG |
656 | // FIXME(const_prop): Const-prop can possibly evaluate an |
657 | // unsized copy operation when it thinks that the type is | |
658 | // actually sized, due to a trivially false where-clause | |
659 | // predicate like `where Self: Sized` with `Self = dyn Trait`. | |
660 | // See #102553 for an example of such a predicate. | |
661 | if src.layout.is_unsized() { | |
662 | throw_inval!(SizeOfUnsizedType(src.layout.ty)); | |
663 | } | |
664 | if dest.layout.is_unsized() { | |
665 | throw_inval!(SizeOfUnsizedType(dest.layout.ty)); | |
666 | } | |
064997fb | 667 | assert_eq!(src.layout.size, dest.layout.size); |
0bf4aa26 | 668 | // Yay, we got a value that we can write directly. |
064997fb FG |
669 | return if layout_compat { |
670 | self.write_immediate_no_validate(*src_val, dest) | |
671 | } else { | |
672 | // This is tricky. The problematic case is `ScalarPair`: the `src_val` was | |
673 | // loaded using the offsets defined by `src.layout`. When we put this back into | |
674 | // the destination, we have to use the same offsets! So (a) we make sure we | |
675 | // write back to memory, and (b) we use `dest` *with the source layout*. | |
676 | let dest_mem = self.force_allocation(dest)?; | |
677 | self.write_immediate_to_mplace_no_validate( | |
678 | *src_val, | |
679 | src.layout, | |
680 | dest_mem.align, | |
681 | *dest_mem, | |
682 | ) | |
683 | }; | |
0bf4aa26 | 684 | } |
487cf647 | 685 | Left(mplace) => mplace, |
b7449926 XL |
686 | }; |
687 | // Slow path, this does not fit into an immediate. Just memcpy. | |
0bf4aa26 XL |
688 | trace!("copy_op: {:?} <- {:?}: {}", *dest, src, dest.layout.ty); |
689 | ||
064997fb FG |
690 | let dest = self.force_allocation(&dest)?; |
691 | let Some((dest_size, _)) = self.size_and_align_of_mplace(&dest)? else { | |
692 | span_bug!(self.cur_span(), "copy_op needs (dynamically) sized values") | |
693 | }; | |
694 | if cfg!(debug_assertions) { | |
695 | let src_size = self.size_and_align_of_mplace(&src)?.unwrap().0; | |
696 | assert_eq!(src_size, dest_size, "Cannot copy differently-sized data"); | |
697 | } else { | |
698 | // As a cheap approximation, we compare the fixed parts of the size. | |
699 | assert_eq!(src.layout.size, dest.layout.size); | |
0bf4aa26 XL |
700 | } |
701 | ||
064997fb FG |
702 | self.mem_copy( |
703 | src.ptr, src.align, dest.ptr, dest.align, dest_size, /*nonoverlapping*/ false, | |
704 | ) | |
ff7c6d11 XL |
705 | } |
706 | ||
9fa01778 | 707 | /// Ensures that a place is in memory, and returns where it is. |
a1dfa0c6 XL |
708 | /// If the place currently refers to a local that doesn't yet have a matching allocation, |
709 | /// create such an allocation. | |
b7449926 | 710 | /// This is essentially `force_to_memplace`. |
04454e1e | 711 | #[instrument(skip(self), level = "debug")] |
064997fb | 712 | pub fn force_allocation( |
ff7c6d11 | 713 | &mut self, |
064997fb FG |
714 | place: &PlaceTy<'tcx, M::Provenance>, |
715 | ) -> InterpResult<'tcx, MPlaceTy<'tcx, M::Provenance>> { | |
716 | let mplace = match place.place { | |
b7449926 | 717 | Place::Local { frame, local } => { |
f035d41b | 718 | match M::access_local_mut(self, frame, local)? { |
064997fb | 719 | &mut Operand::Immediate(local_val) => { |
b7449926 | 720 | // We need to make an allocation. |
48663c56 | 721 | |
9c376795 | 722 | // We need the layout of the local. We can NOT use the layout we got, |
0731742a | 723 | // that might e.g., be an inner field of a struct with `Scalar` layout, |
b7449926 | 724 | // that has different alignment than the outer field. |
ba9703b0 XL |
725 | let local_layout = |
726 | self.layout_of_local(&self.stack()[frame], local, None)?; | |
064997fb FG |
727 | if local_layout.is_unsized() { |
728 | throw_unsup_format!("unsized locals are not supported"); | |
729 | } | |
730 | let mplace = *self.allocate(local_layout, MemoryKind::Stack)?; | |
731 | if !matches!(local_val, Immediate::Uninit) { | |
732 | // Preserve old value. (As an optimization, we can skip this if it was uninit.) | |
48663c56 XL |
733 | // We don't have to validate as we can assume the local |
734 | // was already valid for its type. | |
064997fb FG |
735 | self.write_immediate_to_mplace_no_validate( |
736 | local_val, | |
737 | local_layout, | |
738 | local_layout.align.abi, | |
739 | mplace, | |
740 | )?; | |
48663c56 XL |
741 | } |
742 | // Now we can call `access_mut` again, asserting it goes well, | |
743 | // and actually overwrite things. | |
064997fb FG |
744 | *M::access_local_mut(self, frame, local).unwrap() = |
745 | Operand::Indirect(mplace); | |
746 | mplace | |
b7449926 | 747 | } |
064997fb | 748 | &mut Operand::Indirect(mplace) => mplace, // this already was an indirect local |
b7449926 XL |
749 | } |
750 | } | |
064997fb | 751 | Place::Ptr(mplace) => mplace, |
b7449926 XL |
752 | }; |
753 | // Return with the original layout, so that the caller can go on | |
064997fb | 754 | Ok(MPlaceTy { mplace, layout: place.layout, align: place.align }) |
ff7c6d11 XL |
755 | } |
756 | ||
b7449926 | 757 | pub fn allocate( |
ff7c6d11 | 758 | &mut self, |
ba9703b0 XL |
759 | layout: TyAndLayout<'tcx>, |
760 | kind: MemoryKind<M::MemoryKind>, | |
064997fb | 761 | ) -> InterpResult<'tcx, MPlaceTy<'tcx, M::Provenance>> { |
487cf647 | 762 | assert!(layout.is_sized()); |
04454e1e | 763 | let ptr = self.allocate_ptr(layout.size, layout.align.abi, kind)?; |
136023e0 | 764 | Ok(MPlaceTy::from_aligned_ptr(ptr.into(), layout)) |
b7449926 | 765 | } |
ff7c6d11 | 766 | |
17df50a5 | 767 | /// Returns a wide MPlace of type `&'static [mut] str` to a new 1-aligned allocation. |
60c5eb7d XL |
768 | pub fn allocate_str( |
769 | &mut self, | |
770 | str: &str, | |
ba9703b0 | 771 | kind: MemoryKind<M::MemoryKind>, |
17df50a5 | 772 | mutbl: Mutability, |
9ffffee4 FG |
773 | ) -> InterpResult<'tcx, MPlaceTy<'tcx, M::Provenance>> { |
774 | let ptr = self.allocate_bytes_ptr(str.as_bytes(), Align::ONE, kind, mutbl)?; | |
775 | let meta = Scalar::from_target_usize(u64::try_from(str.len()).unwrap(), self); | |
064997fb | 776 | let mplace = MemPlace { ptr: ptr.into(), meta: MemPlaceMeta::Meta(meta) }; |
60c5eb7d | 777 | |
17df50a5 XL |
778 | let ty = self.tcx.mk_ref( |
779 | self.tcx.lifetimes.re_static, | |
780 | ty::TypeAndMut { ty: self.tcx.types.str_, mutbl }, | |
781 | ); | |
782 | let layout = self.layout_of(ty).unwrap(); | |
9ffffee4 | 783 | Ok(MPlaceTy { mplace, layout, align: layout.align.abi }) |
60c5eb7d XL |
784 | } |
785 | ||
9ffffee4 FG |
786 | /// Writes the aggregate to the destination. |
787 | #[instrument(skip(self), level = "trace")] | |
788 | pub fn write_aggregate( | |
b7449926 | 789 | &mut self, |
9ffffee4 | 790 | kind: &mir::AggregateKind<'tcx>, |
353b0b11 | 791 | operands: &IndexSlice<FieldIdx, mir::Operand<'tcx>>, |
064997fb | 792 | dest: &PlaceTy<'tcx, M::Provenance>, |
dc9dc135 | 793 | ) -> InterpResult<'tcx> { |
9ffffee4 FG |
794 | self.write_uninit(&dest)?; |
795 | let (variant_index, variant_dest, active_field_index) = match *kind { | |
796 | mir::AggregateKind::Adt(_, variant_index, _, _, active_field_index) => { | |
797 | let variant_dest = self.place_downcast(&dest, variant_index)?; | |
798 | (variant_index, variant_dest, active_field_index) | |
b7449926 | 799 | } |
353b0b11 | 800 | _ => (FIRST_VARIANT, dest.clone(), None), |
9ffffee4 FG |
801 | }; |
802 | if active_field_index.is_some() { | |
803 | assert_eq!(operands.len(), 1); | |
b7449926 | 804 | } |
353b0b11 | 805 | for (field_index, operand) in operands.iter_enumerated() { |
9ffffee4 | 806 | let field_index = active_field_index.unwrap_or(field_index); |
353b0b11 | 807 | let field_dest = self.place_field(&variant_dest, field_index.as_usize())?; |
9ffffee4 FG |
808 | let op = self.eval_operand(operand, Some(field_dest.layout))?; |
809 | self.copy_op(&op, &field_dest, /*allow_transmute*/ false)?; | |
810 | } | |
811 | self.write_discriminant(variant_index, &dest) | |
b7449926 | 812 | } |
ff7c6d11 | 813 | |
a1dfa0c6 XL |
814 | pub fn raw_const_to_mplace( |
815 | &self, | |
1b1a35ee | 816 | raw: ConstAlloc<'tcx>, |
064997fb | 817 | ) -> InterpResult<'tcx, MPlaceTy<'tcx, M::Provenance>> { |
a1dfa0c6 | 818 | // This must be an allocation in `tcx` |
f9f354fc | 819 | let _ = self.tcx.global_alloc(raw.alloc_id); |
3dfed10e | 820 | let ptr = self.global_base_pointer(Pointer::from(raw.alloc_id))?; |
a1dfa0c6 | 821 | let layout = self.layout_of(raw.ty)?; |
136023e0 | 822 | Ok(MPlaceTy::from_aligned_ptr(ptr.into(), layout)) |
a1dfa0c6 XL |
823 | } |
824 | ||
b7449926 | 825 | /// Turn a place with a `dyn Trait` type into a place with the actual dynamic type. |
9ffffee4 | 826 | /// Aso returns the vtable. |
dfeec247 XL |
827 | pub(super) fn unpack_dyn_trait( |
828 | &self, | |
064997fb | 829 | mplace: &MPlaceTy<'tcx, M::Provenance>, |
9ffffee4 FG |
830 | ) -> InterpResult<'tcx, (MPlaceTy<'tcx, M::Provenance>, Pointer<Option<M::Provenance>>)> { |
831 | assert!( | |
832 | matches!(mplace.layout.ty.kind(), ty::Dynamic(_, _, ty::Dyn)), | |
833 | "`unpack_dyn_trait` only makes sense on `dyn*` types" | |
834 | ); | |
835 | let vtable = mplace.meta.unwrap_meta().to_pointer(self)?; | |
064997fb | 836 | let (ty, _) = self.get_ptr_vtable(vtable)?; |
b7449926 XL |
837 | let layout = self.layout_of(ty)?; |
838 | ||
064997fb FG |
839 | let mplace = MPlaceTy { |
840 | mplace: MemPlace { meta: MemPlaceMeta::None, ..**mplace }, | |
841 | layout, | |
842 | align: layout.align.abi, | |
843 | }; | |
9ffffee4 FG |
844 | Ok((mplace, vtable)) |
845 | } | |
846 | ||
847 | /// Turn an operand with a `dyn* Trait` type into an operand with the actual dynamic type. | |
848 | /// Aso returns the vtable. | |
849 | pub(super) fn unpack_dyn_star( | |
850 | &self, | |
851 | op: &OpTy<'tcx, M::Provenance>, | |
852 | ) -> InterpResult<'tcx, (OpTy<'tcx, M::Provenance>, Pointer<Option<M::Provenance>>)> { | |
853 | assert!( | |
854 | matches!(op.layout.ty.kind(), ty::Dynamic(_, _, ty::DynStar)), | |
855 | "`unpack_dyn_star` only makes sense on `dyn*` types" | |
856 | ); | |
857 | let data = self.operand_field(&op, 0)?; | |
858 | let vtable = self.operand_field(&op, 1)?; | |
859 | let vtable = self.read_pointer(&vtable)?; | |
860 | let (ty, _) = self.get_ptr_vtable(vtable)?; | |
861 | let layout = self.layout_of(ty)?; | |
862 | let data = data.transmute(layout); | |
863 | Ok((data, vtable)) | |
ff7c6d11 XL |
864 | } |
865 | } | |
064997fb FG |
866 | |
867 | // Some nodes are used a lot. Make sure they don't unintentionally get bigger. | |
868 | #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] | |
869 | mod size_asserts { | |
870 | use super::*; | |
f2b60f7d | 871 | use rustc_data_structures::static_assert_size; |
2b03887a | 872 | // tidy-alphabetical-start |
f2b60f7d | 873 | static_assert_size!(MemPlace, 40); |
2b03887a | 874 | static_assert_size!(MemPlaceMeta, 24); |
f2b60f7d | 875 | static_assert_size!(MPlaceTy<'_>, 64); |
f2b60f7d | 876 | static_assert_size!(Place, 40); |
f2b60f7d | 877 | static_assert_size!(PlaceTy<'_>, 64); |
2b03887a | 878 | // tidy-alphabetical-end |
064997fb | 879 | } |