pub struct InterpCx<'mir, 'tcx, M: Machine<'mir, 'tcx>> {
    pub machine: M,
    pub tcx: TyCtxtAt<'tcx>,
    pub(crate) param_env: ParamEnv<'tcx>,
    pub memory: Memory<'mir, 'tcx, M>,
    pub recursion_limit: Limit,
}

Fields

machine: M

Stores the Machine instance.

Note: the stack is provided by the machine.

tcx: TyCtxtAt<'tcx>

The results of the type checker, from rustc. The span in this is the “root” of the evaluation, i.e., the const we are evaluating (if this is CTFE).

param_env: ParamEnv<'tcx>

Bounds in scope for polymorphic evaluations.

memory: Memory<'mir, 'tcx, M>

The virtual memory system.

recursion_limit: Limit

The recursion limit (cached from tcx.recursion_limit(()))

Implementations

“Intercept” a function call to a panic-related function because we have something special to do for it. If this returns successfully (Ok), the function should just be evaluated normally.

Call this on things you got out of the MIR (so it is as generic as the current stack frame), to bring it into the proper environment for this interpreter.

Call this on things you got out of the MIR (so it is as generic as the provided stack frame), to bring it into the proper environment for this interpreter.

The substs are assumed to already be in our interpreter “universe” (param_env).

Returns the actual dynamic size and alignment of the place at the given type. Only the “meta” (metadata) part of the place matters. This can fail to provide an answer for extern types.

Jump to the given block.

Return to the given target basic block. Do not use for unwinding! Use unwind_to_block instead.

If target is None, that indicates the function cannot return, so we raise UB.

Unwind to the given target basic block. Do not use for returning! Use return_to_block instead.

If target is StackPopUnwind::Skip, that indicates the function does not need cleanup during unwinding, and we will just keep propagating that upwards.

If target is StackPopUnwind::NotAllowed, that indicates the function does not allow unwinding, and doing so is UB.

Pops the current frame from the stack, deallocating the memory for allocated locals.

If unwinding is false, then we are performing a normal return from a function. In this case, we jump back into the frame of the caller, and continue execution as normal.

If unwinding is true, then we are in the middle of a panic, and need to unwind this frame. In this case, we jump to the cleanup block for the function, which is responsible for running Drop impls for any locals that have been initialized at this point. The cleanup block ends with a special Resume terminator, which will cause us to continue unwinding.

Mark a storage as live, killing the previous content.

A helper function that allocates memory for the layout given and gives you access to mutate it. Once your own mutation code is done, the backing Allocation is removed from the current Memory and returned.

Walks up the callstack from the intrinsic’s callsite, searching for the first callsite in a frame which is not #[track_caller].

Allocate a const core::panic::Location with the provided filename and line/column numbers.

Returns true if emulation happened. Here we implement the intrinsics that are common to all Miri instances; individual machines can add their own intrinsic handling.

Offsets a pointer by some multiple of its type, returning an error if the pointer leaves its allocation. For integer pointers, we consider each of them their own tiny allocation of size 0, so offset-by-0 (and only 0) is okay – except that null cannot be offset by any value.

Copy count*size_of::<T>() many bytes from *src to *dst.

Call this to turn untagged “global” pointers (obtained via tcx) into the machine pointer to the allocation. Must never be used for any other pointers, nor for TLS statics.

Using the resulting pointer represents a direct access to that memory (e.g. by directly using a static), as opposed to access through a pointer that was created by the program.

This function can fail only if ptr points to an extern static.

Internal helper function to determine the allocation and offset of a pointer (if any).

Check if the given pointer points to live memory of given size and align (ignoring M::enforce_alignment). The caller can control the error message for the out-of-bounds case.

Low-level helper function to check if a ptr is in-bounds and potentially return a reference to the allocation it points to. Supports both shared and mutable references, as the actual checking is offloaded to a helper closure. align defines whether and which alignment check is done. Returns None for size 0, and otherwise Some of what alloc_size returned.

Allocation accessors

Helper function to obtain a global (tcx) allocation. This attempts to return a reference to an existing allocation if one can be found in tcx. That, however, is only possible if tcx and this machine use the same pointer tag, so it is indirected through M::tag_allocation.

Gives raw access to the Allocation, without bounds or alignment checks. The caller is responsible for calling the access hooks!

“Safe” (bounds and align-checked) allocation access.

Return the extra field of the given allocation.

Gives raw mutable access to the Allocation, without bounds or alignment checks. The caller is responsible for calling the access hooks!

Also returns a ptr to self.extra so that the caller can use it in parallel with the allocation.

“Safe” (bounds and align-checked) allocation access.

Return the extra field of the given allocation.

Obtain the size and alignment of an allocation, even if that allocation has been deallocated.

If liveness is AllocCheck::MaybeDead, this function always returns Ok.

Create a lazy debug printer that prints the given allocation and all allocations it points to, recursively.

Create a lazy debug printer for a list of allocations and all allocations they point to, recursively.

Print leaked memory. Allocations reachable from static_roots or a Global allocation are not considered leaked. Leaks whose kind may_leak() returns true are not reported.

Reads the given number of bytes from memory. Returns them as a slice.

Performs appropriate bounds checks.

Writes the given stream of bytes into memory.

Performs appropriate bounds checks.

Machine pointer introspection.

Test if this value might be null. If the machine does not support ptr-to-int casts, this is conservative.

Turning a “maybe pointer” into a proper pointer (and some information about where it points), or an absolute address.

Turning a “maybe pointer” into a proper pointer (and some information about where it points).

Try reading an immediate in memory; this is interesting particularly for ScalarPair. Returns None if the layout does not permit loading this as a value.

This is an internal function; call read_immediate instead.

Try returning an immediate for the operand. If the layout does not permit loading this as an immediate, return where in memory we can find the data. Note that for a given layout, this operation will either always fail or always succeed! Whether it succeeds depends on whether the layout can be represented in an Immediate, not on which data is stored there currently.

If force is true, then even scalars with fields that can be ununit will be read. This means the load is lossy and should not be written back! This flag exists only for validity checking.

This is an internal function that should not usually be used; call read_immediate instead.

Read an immediate from a place, asserting that that is possible with the given layout.

Read a scalar from a place

Read a pointer from a place.

Projection functions

Converts a repr(simd) operand into an operand where place_index accesses the SIMD elements. Also returns the number of elements.

Read from a local. Will not actually access the local if reading from a ZST. Will not access memory, instead an indirect Operand is returned.

This is public because it is used by priroda to get an OpTy from a local

Every place can be read from, so we can turn them into an operand. This will definitely return Indirect if the place is a Ptr, i.e., this will never actually read from memory.

Evaluate a place with the goal of reading from it. This lets us sometimes avoid allocations.

Evaluate the operand, returning a place where you can then find the data. If you already know the layout, you can save two table lookups by passing it in here.

Evaluate a bunch of operands at once

The val and layout are assumed to already be in our interpreter “universe” (param_env).

Read discriminant, return the runtime value as well as the variant index. Can also legally be called on non-enums (e.g. through the discriminant_value intrinsic)!

Applies the binary operation op to the two operands and writes a tuple of the result and a boolean signifying the potential overflow to the destination.

Applies the binary operation op to the arguments and writes the result to the destination.

Returns the result of the specified operation, whether it overflowed, and the result type.

Typed version of overflowing_binary_op, returning an ImmTy. Also ignores overflows.

Returns the result of the specified operation, whether it overflowed, and the result type.

Take a value, which represents a (thin or wide) reference, and make it a place. Alignment is just based on the type. This is the inverse of MemPlace::to_ref().

Only call this if you are sure the place is “valid” (aligned and inbounds), or do not want to ever use the place for memory access! Generally prefer deref_operand.

Take an operand, representing a pointer, and dereference it to a place – that will always be a MemPlace. Lives in place.rs because it creates a place.

Check if this mplace is dereferenceable and sufficiently aligned.

Offset a pointer to project to a field of a struct/union. Unlike place_field, this is always possible without allocating, so it can take &self. Also return the field’s layout. This supports both struct and array fields.

This also works for arrays, but then the usize index type is restricting. For indexing into arrays, use mplace_index.

Index into an array.

Project into an mplace

Converts a repr(simd) place into a place where place_index accesses the SIMD elements. Also returns the number of elements.

Gets the place of a field inside the place, and also the field’s type. Just a convenience function, but used quite a bit. This is the only projection that might have a side-effect: We cannot project into the field of a local ScalarPair, we have to first allocate it.

Projects into a place.

Converts a repr(simd) place into a place where place_index accesses the SIMD elements. Also returns the number of elements.

Computes a place. You should only use this if you intend to write into this place; for reading, a more efficient alternative is eval_place_to_op.

Write an immediate to a place

Write a scalar to a place

Write a pointer to a place

Write an immediate to a place. If you use this you are responsible for validating that things got copied at the right type.

Write an immediate to memory. If you use this you are responsible for validating that things got copied at the right type.

Copies the data from an operand to a place. This does not support transmuting! Use copy_op_transmute if the layouts could disagree.

Copies the data from an operand to a place. This does not support transmuting! Use copy_op_transmute if the layouts could disagree. Also, if you use this you are responsible for validating that things get copied at the right type.

Copies the data from an operand to a place. The layouts may disagree, but they must have the same size.

Ensures that a place is in memory, and returns where it is. If the place currently refers to a local that doesn’t yet have a matching allocation, create such an allocation. This is essentially force_to_memplace.

This supports unsized types and returns the computed size to avoid some redundant computation when copying; use force_allocation for a simpler, sized-only version.

Returns a wide MPlace of type &'static [mut] str to a new 1-aligned allocation.

Writes the discriminant of the given variant.

Turn a place with a dyn Trait type into a place with the actual dynamic type. Also return some more information so drop doesn’t have to run the same code twice.

Returns true as long as there are more things to do.

This is used by priroda

This is marked #inline(always) to work around adversarial codegen when opt-level = 3

Runs the interpretation logic for the given mir::Statement at the current frame and statement counter. This also moves the statement counter forward.

Evaluate an assignment statement.

There is no separate eval_rvalue function. Instead, the code for handling each rvalue type writes its results directly into the memory specified by the place.

Initialize a single callee argument, checking the types for compatibility.

Call this function – pushing the stack frame and initializing the arguments.

caller_fn_abi is used to determine if all the arguments are passed the proper way. However, we also need caller_abi to determine if we need to do untupling of arguments.

with_caller_location indicates whether the caller passed a caller location. Miri implements caller locations without argument passing, but to match FnAbi we need to know when those arguments are present.

Creates a dynamic vtable for the given type and vtable origin. This is used only for objects.

The trait_ref encodes the erased self type. Hence, if we are making an object Foo<Trait> from a value of type Foo<T>, then trait_ref would map T: Trait.

Resolves the function at the specified slot in the provided vtable. Currently an index of ‘3’ (COMMON_VTABLE_ENTRIES.len()) corresponds to the first method declared in the trait of the provided vtable.

Returns the drop fn instance as well as the actual dynamic type.

This function checks the data at op to be const-valid. op is assumed to cover valid memory if it is an indirect operand. It will error if the bits at the destination do not match the ones described by the layout.

ref_tracking is used to record references that we encounter so that they can be checked recursively by an outside driving loop.

constant controls whether this must satisfy the rules for constants:

  • no pointers to statics.
  • no UnsafeCell or non-ZST &mut.

This function checks the data at op to be runtime-valid. op is assumed to cover valid memory if it is an indirect operand. It will error if the bits at the destination do not match the ones described by the layout.

Trait Implementations

The &FnAbi-wrapping type (or &FnAbi itself), which will be returned from fn_abi_of_* (see also handle_fn_abi_err). Read more

Helper used for fn_abi_of_*, to adapt tcx.fn_abi_of_*(...) into a Self::FnAbiOfResult (which does not need to be a Result<...>). Read more

The TyAndLayout-wrapping type (or TyAndLayout itself), which will be returned from layout_of (see also handle_layout_err). Read more

Span to use for tcx.at(span), from layout_of.

Helper used for layout_of, to adapt tcx.layout_of(...) into a Self::LayoutOfResult (which does not need to be a Result<...>). Read more

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more

Immutably borrows from an owned value. Read more

Mutably borrows from an owned value. Read more

Compute a FnAbi suitable for indirect calls, i.e. to fn pointers. Read more

Compute a FnAbi suitable for declaring/defining an fn instance, and for direct calls to an fn. Read more

Returns the argument unchanged.

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Computes the layout of a type. Note that this implicitly executes in “reveal all” mode, and will normalize the input type. Read more

Computes the layout of a type, at span. Note that this implicitly executes in “reveal all” mode, and will normalize the input type. Read more

Helper function: truncate given value-“overflowed flag” pair to pointer size and update “overflowed flag” if there was an overflow. This should be called by all the other methods before returning! Read more

The type returned in the event of a conversion error.

Performs the conversion.

The type returned in the event of a conversion error.

Performs the conversion.

Layout

Note: Unable to compute type layout, possibly due to this type having generic parameters. Layout can only be computed for concrete, fully-instantiated types.