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.
This commit is contained in:
bors 2022-03-12 17:18:24 +00:00
commit 9029fa4aa9
3 changed files with 175 additions and 188 deletions

View File

@ -57,8 +57,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
/// Evaluates the scalar at the specified path. Returns Some(val)
/// if the path could be resolved, and None otherwise
fn eval_path_scalar(&mut self, path: &[&str]) -> InterpResult<'tcx, Scalar<Tag>> {
let this = self.eval_context_mut();
fn eval_path_scalar(&self, path: &[&str]) -> InterpResult<'tcx, Scalar<Tag>> {
let this = self.eval_context_ref();
let instance = this.resolve_path(path);
let cid = GlobalId { instance, promoted: None };
let const_val = this.eval_to_allocation(cid)?;
@ -67,46 +67,103 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
}
/// Helper function to get a `libc` constant as a `Scalar`.
fn eval_libc(&mut self, name: &str) -> InterpResult<'tcx, Scalar<Tag>> {
self.eval_context_mut().eval_path_scalar(&["libc", name])
fn eval_libc(&self, name: &str) -> InterpResult<'tcx, Scalar<Tag>> {
self.eval_path_scalar(&["libc", name])
}
/// Helper function to get a `libc` constant as an `i32`.
fn eval_libc_i32(&mut self, name: &str) -> InterpResult<'tcx, i32> {
fn eval_libc_i32(&self, name: &str) -> InterpResult<'tcx, i32> {
// TODO: Cache the result.
self.eval_libc(name)?.to_i32()
}
/// Helper function to get a `windows` constant as a `Scalar`.
fn eval_windows(&mut self, module: &str, name: &str) -> InterpResult<'tcx, Scalar<Tag>> {
self.eval_context_mut().eval_path_scalar(&["std", "sys", "windows", module, name])
fn eval_windows(&self, module: &str, name: &str) -> InterpResult<'tcx, Scalar<Tag>> {
self.eval_context_ref().eval_path_scalar(&["std", "sys", "windows", module, name])
}
/// Helper function to get a `windows` constant as a `u64`.
fn eval_windows_u64(&mut self, module: &str, name: &str) -> InterpResult<'tcx, u64> {
fn eval_windows_u64(&self, module: &str, name: &str) -> InterpResult<'tcx, u64> {
// TODO: Cache the result.
self.eval_windows(module, name)?.to_u64()
}
/// Helper function to get the `TyAndLayout` of a `libc` type
fn libc_ty_layout(&mut self, name: &str) -> InterpResult<'tcx, TyAndLayout<'tcx>> {
let this = self.eval_context_mut();
fn libc_ty_layout(&self, name: &str) -> InterpResult<'tcx, TyAndLayout<'tcx>> {
let this = self.eval_context_ref();
let ty = this.resolve_path(&["libc", name]).ty(*this.tcx, ty::ParamEnv::reveal_all());
this.layout_of(ty)
}
/// Helper function to get the `TyAndLayout` of a `windows` type
fn windows_ty_layout(&mut self, name: &str) -> InterpResult<'tcx, TyAndLayout<'tcx>> {
let this = self.eval_context_mut();
fn windows_ty_layout(&self, name: &str) -> InterpResult<'tcx, TyAndLayout<'tcx>> {
let this = self.eval_context_ref();
let ty = this
.resolve_path(&["std", "sys", "windows", "c", name])
.ty(*this.tcx, ty::ParamEnv::reveal_all());
this.layout_of(ty)
}
/// Project to the given *named* field of the mplace (which must be a struct or union type).
fn mplace_field_named(
&self,
mplace: &MPlaceTy<'tcx, Tag>,
name: &str,
) -> InterpResult<'tcx, MPlaceTy<'tcx, Tag>> {
let this = self.eval_context_ref();
let adt = mplace.layout.ty.ty_adt_def().unwrap();
for (idx, field) in adt.non_enum_variant().fields.iter().enumerate() {
if field.name.as_str() == name {
return this.mplace_field(mplace, idx);
}
}
bug!("No field named {} in type {}", name, mplace.layout.ty);
}
/// Write an int of the appropriate size to `dest`. The target type may be signed or unsigned,
/// we try to do the right thing anyway. `i128` can fit all integer types except for `u128` so
/// this method is fine for almost all integer types.
fn write_int(&mut self, i: impl Into<i128>, dest: &PlaceTy<'tcx, Tag>) -> InterpResult<'tcx> {
assert!(dest.layout.abi.is_scalar(), "write_int on non-scalar type {}", dest.layout.ty);
let val = if dest.layout.abi.is_signed() {
Scalar::from_int(i, dest.layout.size)
} else {
Scalar::from_uint(u64::try_from(i.into()).unwrap(), dest.layout.size)
};
self.eval_context_mut().write_scalar(val, dest)
}
/// Write the first N fields of the given place.
fn write_int_fields(
&mut self,
values: &[i128],
dest: &MPlaceTy<'tcx, Tag>,
) -> InterpResult<'tcx> {
let this = self.eval_context_mut();
for (idx, &val) in values.iter().enumerate() {
let field = this.mplace_field(dest, idx)?;
this.write_int(val, &field.into())?;
}
Ok(())
}
/// Write the given fields of the given place.
fn write_int_fields_named(
&mut self,
values: &[(&str, i128)],
dest: &MPlaceTy<'tcx, Tag>,
) -> InterpResult<'tcx> {
let this = self.eval_context_mut();
for &(name, val) in values.iter() {
let field = this.mplace_field_named(dest, name)?;
this.write_int(val, &field.into())?;
}
Ok(())
}
/// Write a 0 of the appropriate size to `dest`.
fn write_null(&mut self, dest: &PlaceTy<'tcx, Tag>) -> InterpResult<'tcx> {
self.eval_context_mut().write_scalar(Scalar::from_int(0, dest.layout.size), dest)
self.write_int(0, dest)
}
/// Test if this pointer equals 0.
@ -373,27 +430,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
}
}
// Writes several `ImmTy`s contiguously into memory. This is useful when you have to pack
// different values into a struct.
fn write_packed_immediates(
&mut self,
place: &MPlaceTy<'tcx, Tag>,
imms: &[ImmTy<'tcx, Tag>],
) -> InterpResult<'tcx> {
let this = self.eval_context_mut();
let mut offset = Size::from_bytes(0);
for &imm in imms {
this.write_immediate(
*imm,
&place.offset(offset, MemPlaceMeta::None, imm.layout, &*this.tcx)?.into(),
)?;
offset += imm.layout.size;
}
Ok(())
}
/// Helper function used inside the shims of foreign functions to check that isolation is
/// disabled. It returns an error using the `name` of the foreign function if this is not the
/// case.
@ -740,26 +776,6 @@ pub fn isolation_abort_error(name: &str) -> InterpResult<'static> {
)))
}
pub fn immty_from_int_checked<'tcx>(
int: impl Into<i128>,
layout: TyAndLayout<'tcx>,
) -> InterpResult<'tcx, ImmTy<'tcx, Tag>> {
let int = int.into();
Ok(ImmTy::try_from_int(int, layout).ok_or_else(|| {
err_unsup_format!("signed value {:#x} does not fit in {} bits", int, layout.size.bits())
})?)
}
pub fn immty_from_uint_checked<'tcx>(
int: impl Into<u128>,
layout: TyAndLayout<'tcx>,
) -> InterpResult<'tcx, ImmTy<'tcx, Tag>> {
let int = int.into();
Ok(ImmTy::try_from_uint(int, layout).ok_or_else(|| {
err_unsup_format!("unsigned value {:#x} does not fit in {} bits", int, layout.size.bits())
})?)
}
pub fn bool_to_simd_element(b: bool, size: Size) -> Scalar<Tag> {
// SIMD uses all-1 as pattern for "true"
let val = if b { -1 } else { 0 };

View File

@ -15,7 +15,7 @@ use rustc_middle::ty::{self, layout::LayoutOf};
use rustc_target::abi::{Align, Size};
use crate::*;
use helpers::{check_arg_count, immty_from_int_checked, immty_from_uint_checked};
use helpers::check_arg_count;
use shims::os_str::os_str_to_bytes;
use shims::time::system_time_to_duration;
@ -318,45 +318,32 @@ trait EvalContextExtPrivate<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, '
let (created_sec, created_nsec) = metadata.created.unwrap_or((0, 0));
let (modified_sec, modified_nsec) = metadata.modified.unwrap_or((0, 0));
let dev_t_layout = this.libc_ty_layout("dev_t")?;
let mode_t_layout = this.libc_ty_layout("mode_t")?;
let nlink_t_layout = this.libc_ty_layout("nlink_t")?;
let ino_t_layout = this.libc_ty_layout("ino_t")?;
let uid_t_layout = this.libc_ty_layout("uid_t")?;
let gid_t_layout = this.libc_ty_layout("gid_t")?;
let time_t_layout = this.libc_ty_layout("time_t")?;
let long_layout = this.libc_ty_layout("c_long")?;
let off_t_layout = this.libc_ty_layout("off_t")?;
let blkcnt_t_layout = this.libc_ty_layout("blkcnt_t")?;
let blksize_t_layout = this.libc_ty_layout("blksize_t")?;
let uint32_t_layout = this.libc_ty_layout("uint32_t")?;
let imms = [
immty_from_uint_checked(0u128, dev_t_layout)?, // st_dev
immty_from_uint_checked(mode, mode_t_layout)?, // st_mode
immty_from_uint_checked(0u128, nlink_t_layout)?, // st_nlink
immty_from_uint_checked(0u128, ino_t_layout)?, // st_ino
immty_from_uint_checked(0u128, uid_t_layout)?, // st_uid
immty_from_uint_checked(0u128, gid_t_layout)?, // st_gid
immty_from_uint_checked(0u128, dev_t_layout)?, // st_rdev
immty_from_uint_checked(0u128, uint32_t_layout)?, // padding
immty_from_uint_checked(access_sec, time_t_layout)?, // st_atime
immty_from_uint_checked(access_nsec, long_layout)?, // st_atime_nsec
immty_from_uint_checked(modified_sec, time_t_layout)?, // st_mtime
immty_from_uint_checked(modified_nsec, long_layout)?, // st_mtime_nsec
immty_from_uint_checked(0u128, time_t_layout)?, // st_ctime
immty_from_uint_checked(0u128, long_layout)?, // st_ctime_nsec
immty_from_uint_checked(created_sec, time_t_layout)?, // st_birthtime
immty_from_uint_checked(created_nsec, long_layout)?, // st_birthtime_nsec
immty_from_uint_checked(metadata.size, off_t_layout)?, // st_size
immty_from_uint_checked(0u128, blkcnt_t_layout)?, // st_blocks
immty_from_uint_checked(0u128, blksize_t_layout)?, // st_blksize
immty_from_uint_checked(0u128, uint32_t_layout)?, // st_flags
immty_from_uint_checked(0u128, uint32_t_layout)?, // st_gen
];
let buf = this.deref_operand(buf_op)?;
this.write_packed_immediates(&buf, &imms)?;
this.write_int_fields_named(
&[
("st_dev", 0),
("st_mode", mode.into()),
("st_nlink", 0),
("st_ino", 0),
("st_uid", 0),
("st_gid", 0),
("st_rdev", 0),
("st_atime", access_sec.into()),
("st_atime_nsec", access_nsec.into()),
("st_mtime", modified_sec.into()),
("st_mtime_nsec", modified_nsec.into()),
("st_ctime", 0),
("st_ctime_nsec", 0),
("st_birthtime", created_sec.into()),
("st_birthtime_nsec", created_nsec.into()),
("st_size", metadata.size.into()),
("st_blocks", 0),
("st_blksize", 0),
("st_flags", 0),
("st_gen", 0),
],
&buf,
)?;
Ok(0)
}
@ -954,7 +941,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
// `syscall` function is untyped. This means that all the `statx` parameters are provided
// as `isize`s instead of having the proper types. Thus, we have to recover the layout of
// `statxbuf_op` by using the `libc::statx` struct type.
let statxbuf_place = {
let statxbuf = {
// FIXME: This long path is required because `libc::statx` is an struct and also a
// function and `resolve_path` is returning the latter.
let statx_ty = this
@ -1064,44 +1051,55 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
})
.unwrap_or(Ok((0, 0)))?;
let __u32_layout = this.libc_ty_layout("__u32")?;
let __u64_layout = this.libc_ty_layout("__u64")?;
let __u16_layout = this.libc_ty_layout("__u16")?;
// Now we transform all this fields into `ImmTy`s and write them to `statxbuf`. We write a
// zero for the unavailable fields.
let imms = [
immty_from_uint_checked(mask, __u32_layout)?, // stx_mask
immty_from_uint_checked(0u128, __u32_layout)?, // stx_blksize
immty_from_uint_checked(0u128, __u64_layout)?, // stx_attributes
immty_from_uint_checked(0u128, __u32_layout)?, // stx_nlink
immty_from_uint_checked(0u128, __u32_layout)?, // stx_uid
immty_from_uint_checked(0u128, __u32_layout)?, // stx_gid
immty_from_uint_checked(mode, __u16_layout)?, // stx_mode
immty_from_uint_checked(0u128, __u16_layout)?, // statx padding
immty_from_uint_checked(0u128, __u64_layout)?, // stx_ino
immty_from_uint_checked(metadata.size, __u64_layout)?, // stx_size
immty_from_uint_checked(0u128, __u64_layout)?, // stx_blocks
immty_from_uint_checked(0u128, __u64_layout)?, // stx_attributes
immty_from_uint_checked(access_sec, __u64_layout)?, // stx_atime.tv_sec
immty_from_uint_checked(access_nsec, __u32_layout)?, // stx_atime.tv_nsec
immty_from_uint_checked(0u128, __u32_layout)?, // statx_timestamp padding
immty_from_uint_checked(created_sec, __u64_layout)?, // stx_btime.tv_sec
immty_from_uint_checked(created_nsec, __u32_layout)?, // stx_btime.tv_nsec
immty_from_uint_checked(0u128, __u32_layout)?, // statx_timestamp padding
immty_from_uint_checked(0u128, __u64_layout)?, // stx_ctime.tv_sec
immty_from_uint_checked(0u128, __u32_layout)?, // stx_ctime.tv_nsec
immty_from_uint_checked(0u128, __u32_layout)?, // statx_timestamp padding
immty_from_uint_checked(modified_sec, __u64_layout)?, // stx_mtime.tv_sec
immty_from_uint_checked(modified_nsec, __u32_layout)?, // stx_mtime.tv_nsec
immty_from_uint_checked(0u128, __u32_layout)?, // statx_timestamp padding
immty_from_uint_checked(0u128, __u64_layout)?, // stx_rdev_major
immty_from_uint_checked(0u128, __u64_layout)?, // stx_rdev_minor
immty_from_uint_checked(0u128, __u64_layout)?, // stx_dev_major
immty_from_uint_checked(0u128, __u64_layout)?, // stx_dev_minor
];
this.write_packed_immediates(&statxbuf_place, &imms)?;
// Now we write everything to `statxbuf`. We write a zero for the unavailable fields.
this.write_int_fields_named(
&[
("stx_mask", mask.into()),
("stx_blksize", 0),
("stx_attributes", 0),
("stx_nlink", 0),
("stx_uid", 0),
("stx_gid", 0),
("stx_mode", mode.into()),
("stx_ino", 0),
("stx_size", metadata.size.into()),
("stx_blocks", 0),
("stx_attributes_mask", 0),
("stx_rdev_major", 0),
("stx_rdev_minor", 0),
("stx_dev_major", 0),
("stx_dev_minor", 0),
],
&statxbuf,
)?;
this.write_int_fields(
&[
access_sec.into(), // stx_atime.tv_sec
access_nsec.into(), // stx_atime.tv_nsec
],
&this.mplace_field_named(&statxbuf, "stx_atime")?,
)?;
this.write_int_fields(
&[
created_sec.into(), // stx_btime.tv_sec
created_nsec.into(), // stx_btime.tv_nsec
],
&this.mplace_field_named(&statxbuf, "stx_btime")?,
)?;
this.write_int_fields(
&[
0.into(), // stx_ctime.tv_sec
0.into(), // stx_ctime.tv_nsec
],
&this.mplace_field_named(&statxbuf, "stx_ctime")?,
)?;
this.write_int_fields(
&[
modified_sec.into(), // stx_mtime.tv_sec
modified_nsec.into(), // stx_mtime.tv_nsec
],
&this.mplace_field_named(&statxbuf, "stx_mtime")?,
)?;
Ok(0)
}
@ -1247,7 +1245,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
Some(Ok(dir_entry)) => {
// Write the directory entry into a newly allocated buffer.
// The name is written with write_bytes, while the rest of the
// dirent64 struct is written using write_packed_immediates.
// dirent64 struct is written using write_int_fields.
// For reference:
// pub struct dirent64 {
@ -1270,12 +1268,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
let entry =
this.malloc(size, /*zero_init:*/ false, MiriMemoryKind::Runtime)?;
// FIXME: make use of dirent64_layout
let ino64_t_layout = this.libc_ty_layout("ino64_t")?;
let off64_t_layout = this.libc_ty_layout("off64_t")?;
let c_ushort_layout = this.libc_ty_layout("c_ushort")?;
let c_uchar_layout = this.libc_ty_layout("c_uchar")?;
// If the host is a Unix system, fill in the inode number with its real value.
// If not, use 0 as a fallback value.
#[cfg(unix)]
@ -1285,15 +1277,15 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
let file_type = this.file_type_to_d_type(dir_entry.file_type())?;
let imms = [
immty_from_uint_checked(ino, ino64_t_layout)?, // d_ino
immty_from_uint_checked(0u128, off64_t_layout)?, // d_off
immty_from_uint_checked(size, c_ushort_layout)?, // d_reclen
immty_from_int_checked(file_type, c_uchar_layout)?, // d_type
];
let entry_layout = this.layout_of(this.tcx.mk_array(this.tcx.types.u8, size))?;
let entry_place = MPlaceTy::from_aligned_ptr(entry, entry_layout);
this.write_packed_immediates(&entry_place, &imms)?;
this.write_int_fields(
&[
ino.into(), // d_ino
0, // d_off
size.into(), // d_reclen
file_type.into(), // d_type
],
&MPlaceTy::from_aligned_ptr(entry, dirent64_layout),
)?;
let name_ptr = entry.offset(Size::from_bytes(d_name_offset), this)?;
this.memory.write_bytes(name_ptr, name_bytes.iter().copied())?;
@ -1343,7 +1335,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
Some(Ok(dir_entry)) => {
// Write into entry, write pointer to result, return 0 on success.
// The name is written with write_os_str_to_c_str, while the rest of the
// dirent struct is written using write_packed_Immediates.
// dirent struct is written using write_int_fields.
// For reference:
// pub struct dirent {
@ -1371,10 +1363,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
}
let entry_place = this.deref_operand(entry_op)?;
let ino_t_layout = this.libc_ty_layout("ino_t")?;
let off_t_layout = this.libc_ty_layout("off_t")?;
let c_ushort_layout = this.libc_ty_layout("c_ushort")?;
let c_uchar_layout = this.libc_ty_layout("c_uchar")?;
// If the host is a Unix system, fill in the inode number with its real value.
// If not, use 0 as a fallback value.
@ -1385,14 +1373,16 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
let file_type = this.file_type_to_d_type(dir_entry.file_type())?;
let imms = [
immty_from_uint_checked(ino, ino_t_layout)?, // d_ino
immty_from_uint_checked(0u128, off_t_layout)?, // d_seekoff
immty_from_uint_checked(0u128, c_ushort_layout)?, // d_reclen
immty_from_uint_checked(file_name_len, c_ushort_layout)?, // d_namlen
immty_from_int_checked(file_type, c_uchar_layout)?, // d_type
];
this.write_packed_immediates(&entry_place, &imms)?;
this.write_int_fields(
&[
ino.into(), // d_ino
0, // d_seekoff
0, // d_reclen
file_name_len.into(), // d_namlen
file_type.into(), // d_type
],
&entry_place,
)?;
let result_place = this.deref_operand(result_op)?;
this.write_scalar(this.read_scalar(entry_op)?, &result_place.into())?;

View File

@ -2,7 +2,6 @@ use std::convert::TryFrom;
use std::time::{Duration, Instant, SystemTime};
use crate::*;
use helpers::{immty_from_int_checked, immty_from_uint_checked};
use thread::Time;
/// Returns the time elapsed between the provided time and the unix epoch as a `Duration`.
@ -24,7 +23,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
this.check_no_isolation("`clock_gettime`")?;
let clk_id = this.read_scalar(clk_id_op)?.to_i32()?;
let tp = this.deref_operand(tp_op)?;
let duration = if clk_id == this.eval_libc_i32("CLOCK_REALTIME")? {
system_time_to_duration(&SystemTime::now())?
@ -41,12 +39,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
let tv_sec = duration.as_secs();
let tv_nsec = duration.subsec_nanos();
let imms = [
immty_from_int_checked(tv_sec, this.libc_ty_layout("time_t")?)?,
immty_from_int_checked(tv_nsec, this.libc_ty_layout("c_long")?)?,
];
this.write_packed_immediates(&tp, &imms)?;
this.write_int_fields(&[tv_sec.into(), tv_nsec.into()], &this.deref_operand(tp_op)?)?;
Ok(0)
}
@ -69,18 +62,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
return Ok(-1);
}
let tv = this.deref_operand(tv_op)?;
let duration = system_time_to_duration(&SystemTime::now())?;
let tv_sec = duration.as_secs();
let tv_usec = duration.subsec_micros();
let imms = [
immty_from_int_checked(tv_sec, this.libc_ty_layout("time_t")?)?,
immty_from_int_checked(tv_usec, this.libc_ty_layout("suseconds_t")?)?,
];
this.write_packed_immediates(&tv, &imms)?;
this.write_int_fields(&[tv_sec.into(), tv_usec.into()], &this.deref_operand(tv_op)?)?;
Ok(0)
}
@ -105,12 +91,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
let dwLowDateTime = u32::try_from(duration_ticks & 0x00000000FFFFFFFF).unwrap();
let dwHighDateTime = u32::try_from((duration_ticks & 0xFFFFFFFF00000000) >> 32).unwrap();
let DWORD_tylayout = this.machine.layouts.u32;
let imms = [
immty_from_uint_checked(dwLowDateTime, DWORD_tylayout)?,
immty_from_uint_checked(dwHighDateTime, DWORD_tylayout)?,
];
this.write_packed_immediates(&this.deref_operand(LPFILETIME_op)?, &imms)?;
this.write_int_fields(
&[dwLowDateTime.into(), dwHighDateTime.into()],
&this.deref_operand(LPFILETIME_op)?,
)?;
Ok(())
}
@ -185,12 +170,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
// Since our emulated ticks in `mach_absolute_time` *are* nanoseconds,
// no scaling needs to happen.
let (numer, denom) = (1, 1);
let imms = [
immty_from_int_checked(numer, this.machine.layouts.u32)?,
immty_from_int_checked(denom, this.machine.layouts.u32)?,
];
this.write_int_fields(&[numer.into(), denom.into()], &info)?;
this.write_packed_immediates(&info, &imms)?;
Ok(0) // KERN_SUCCESS
}