Skip to content

Commit 9029fa4

Browse files
committed
Auto merge of #2021 - RalfJung:write-fields-refactor, r=RalfJung
add write_int_fields to replace write_packed_immediates This avoids having to explicitly list the types of all fields -- we derive them from the type of the struct instead. Also add write_int_fields_named, to give the fields by name instead of ordered by index.
2 parents 9e41650 + 47f8218 commit 9029fa4

File tree

3 files changed

+175
-188
lines changed

3 files changed

+175
-188
lines changed

src/helpers.rs

Lines changed: 70 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -57,8 +57,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
5757

5858
/// Evaluates the scalar at the specified path. Returns Some(val)
5959
/// if the path could be resolved, and None otherwise
60-
fn eval_path_scalar(&mut self, path: &[&str]) -> InterpResult<'tcx, Scalar<Tag>> {
61-
let this = self.eval_context_mut();
60+
fn eval_path_scalar(&self, path: &[&str]) -> InterpResult<'tcx, Scalar<Tag>> {
61+
let this = self.eval_context_ref();
6262
let instance = this.resolve_path(path);
6363
let cid = GlobalId { instance, promoted: None };
6464
let const_val = this.eval_to_allocation(cid)?;
@@ -67,46 +67,103 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
6767
}
6868

6969
/// Helper function to get a `libc` constant as a `Scalar`.
70-
fn eval_libc(&mut self, name: &str) -> InterpResult<'tcx, Scalar<Tag>> {
71-
self.eval_context_mut().eval_path_scalar(&["libc", name])
70+
fn eval_libc(&self, name: &str) -> InterpResult<'tcx, Scalar<Tag>> {
71+
self.eval_path_scalar(&["libc", name])
7272
}
7373

7474
/// Helper function to get a `libc` constant as an `i32`.
75-
fn eval_libc_i32(&mut self, name: &str) -> InterpResult<'tcx, i32> {
75+
fn eval_libc_i32(&self, name: &str) -> InterpResult<'tcx, i32> {
7676
// TODO: Cache the result.
7777
self.eval_libc(name)?.to_i32()
7878
}
7979

8080
/// Helper function to get a `windows` constant as a `Scalar`.
81-
fn eval_windows(&mut self, module: &str, name: &str) -> InterpResult<'tcx, Scalar<Tag>> {
82-
self.eval_context_mut().eval_path_scalar(&["std", "sys", "windows", module, name])
81+
fn eval_windows(&self, module: &str, name: &str) -> InterpResult<'tcx, Scalar<Tag>> {
82+
self.eval_context_ref().eval_path_scalar(&["std", "sys", "windows", module, name])
8383
}
8484

8585
/// Helper function to get a `windows` constant as a `u64`.
86-
fn eval_windows_u64(&mut self, module: &str, name: &str) -> InterpResult<'tcx, u64> {
86+
fn eval_windows_u64(&self, module: &str, name: &str) -> InterpResult<'tcx, u64> {
8787
// TODO: Cache the result.
8888
self.eval_windows(module, name)?.to_u64()
8989
}
9090

9191
/// Helper function to get the `TyAndLayout` of a `libc` type
92-
fn libc_ty_layout(&mut self, name: &str) -> InterpResult<'tcx, TyAndLayout<'tcx>> {
93-
let this = self.eval_context_mut();
92+
fn libc_ty_layout(&self, name: &str) -> InterpResult<'tcx, TyAndLayout<'tcx>> {
93+
let this = self.eval_context_ref();
9494
let ty = this.resolve_path(&["libc", name]).ty(*this.tcx, ty::ParamEnv::reveal_all());
9595
this.layout_of(ty)
9696
}
9797

9898
/// Helper function to get the `TyAndLayout` of a `windows` type
99-
fn windows_ty_layout(&mut self, name: &str) -> InterpResult<'tcx, TyAndLayout<'tcx>> {
100-
let this = self.eval_context_mut();
99+
fn windows_ty_layout(&self, name: &str) -> InterpResult<'tcx, TyAndLayout<'tcx>> {
100+
let this = self.eval_context_ref();
101101
let ty = this
102102
.resolve_path(&["std", "sys", "windows", "c", name])
103103
.ty(*this.tcx, ty::ParamEnv::reveal_all());
104104
this.layout_of(ty)
105105
}
106106

107+
/// Project to the given *named* field of the mplace (which must be a struct or union type).
108+
fn mplace_field_named(
109+
&self,
110+
mplace: &MPlaceTy<'tcx, Tag>,
111+
name: &str,
112+
) -> InterpResult<'tcx, MPlaceTy<'tcx, Tag>> {
113+
let this = self.eval_context_ref();
114+
let adt = mplace.layout.ty.ty_adt_def().unwrap();
115+
for (idx, field) in adt.non_enum_variant().fields.iter().enumerate() {
116+
if field.name.as_str() == name {
117+
return this.mplace_field(mplace, idx);
118+
}
119+
}
120+
bug!("No field named {} in type {}", name, mplace.layout.ty);
121+
}
122+
123+
/// Write an int of the appropriate size to `dest`. The target type may be signed or unsigned,
124+
/// we try to do the right thing anyway. `i128` can fit all integer types except for `u128` so
125+
/// this method is fine for almost all integer types.
126+
fn write_int(&mut self, i: impl Into<i128>, dest: &PlaceTy<'tcx, Tag>) -> InterpResult<'tcx> {
127+
assert!(dest.layout.abi.is_scalar(), "write_int on non-scalar type {}", dest.layout.ty);
128+
let val = if dest.layout.abi.is_signed() {
129+
Scalar::from_int(i, dest.layout.size)
130+
} else {
131+
Scalar::from_uint(u64::try_from(i.into()).unwrap(), dest.layout.size)
132+
};
133+
self.eval_context_mut().write_scalar(val, dest)
134+
}
135+
136+
/// Write the first N fields of the given place.
137+
fn write_int_fields(
138+
&mut self,
139+
values: &[i128],
140+
dest: &MPlaceTy<'tcx, Tag>,
141+
) -> InterpResult<'tcx> {
142+
let this = self.eval_context_mut();
143+
for (idx, &val) in values.iter().enumerate() {
144+
let field = this.mplace_field(dest, idx)?;
145+
this.write_int(val, &field.into())?;
146+
}
147+
Ok(())
148+
}
149+
150+
/// Write the given fields of the given place.
151+
fn write_int_fields_named(
152+
&mut self,
153+
values: &[(&str, i128)],
154+
dest: &MPlaceTy<'tcx, Tag>,
155+
) -> InterpResult<'tcx> {
156+
let this = self.eval_context_mut();
157+
for &(name, val) in values.iter() {
158+
let field = this.mplace_field_named(dest, name)?;
159+
this.write_int(val, &field.into())?;
160+
}
161+
Ok(())
162+
}
163+
107164
/// Write a 0 of the appropriate size to `dest`.
108165
fn write_null(&mut self, dest: &PlaceTy<'tcx, Tag>) -> InterpResult<'tcx> {
109-
self.eval_context_mut().write_scalar(Scalar::from_int(0, dest.layout.size), dest)
166+
self.write_int(0, dest)
110167
}
111168

112169
/// Test if this pointer equals 0.
@@ -373,27 +430,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
373430
}
374431
}
375432

376-
// Writes several `ImmTy`s contiguously into memory. This is useful when you have to pack
377-
// different values into a struct.
378-
fn write_packed_immediates(
379-
&mut self,
380-
place: &MPlaceTy<'tcx, Tag>,
381-
imms: &[ImmTy<'tcx, Tag>],
382-
) -> InterpResult<'tcx> {
383-
let this = self.eval_context_mut();
384-
385-
let mut offset = Size::from_bytes(0);
386-
387-
for &imm in imms {
388-
this.write_immediate(
389-
*imm,
390-
&place.offset(offset, MemPlaceMeta::None, imm.layout, &*this.tcx)?.into(),
391-
)?;
392-
offset += imm.layout.size;
393-
}
394-
Ok(())
395-
}
396-
397433
/// Helper function used inside the shims of foreign functions to check that isolation is
398434
/// disabled. It returns an error using the `name` of the foreign function if this is not the
399435
/// case.
@@ -740,26 +776,6 @@ pub fn isolation_abort_error(name: &str) -> InterpResult<'static> {
740776
)))
741777
}
742778

743-
pub fn immty_from_int_checked<'tcx>(
744-
int: impl Into<i128>,
745-
layout: TyAndLayout<'tcx>,
746-
) -> InterpResult<'tcx, ImmTy<'tcx, Tag>> {
747-
let int = int.into();
748-
Ok(ImmTy::try_from_int(int, layout).ok_or_else(|| {
749-
err_unsup_format!("signed value {:#x} does not fit in {} bits", int, layout.size.bits())
750-
})?)
751-
}
752-
753-
pub fn immty_from_uint_checked<'tcx>(
754-
int: impl Into<u128>,
755-
layout: TyAndLayout<'tcx>,
756-
) -> InterpResult<'tcx, ImmTy<'tcx, Tag>> {
757-
let int = int.into();
758-
Ok(ImmTy::try_from_uint(int, layout).ok_or_else(|| {
759-
err_unsup_format!("unsigned value {:#x} does not fit in {} bits", int, layout.size.bits())
760-
})?)
761-
}
762-
763779
pub fn bool_to_simd_element(b: bool, size: Size) -> Scalar<Tag> {
764780
// SIMD uses all-1 as pattern for "true"
765781
let val = if b { -1 } else { 0 };

0 commit comments

Comments
 (0)