Question

I'm a little confused about value types and the CIL evaluation stack. ECMA-335, Partition III, §1.1 says that the CLI deals with these "Basic CLI types":

  • A subset of the full numeric types (int32, int64, native int, and F).

  • Object references (O) without distinction between the type of object referenced.

  • Pointer types (native unsigned int and &) without distinction as to the type pointed to.

Partition II, §12.1 also provides a similar list which excludes value types, and states:

However, the CLI supports only a subset of these types in its operations upon values stored on its evaluation stack— int32 , int64 , and native int.

This makes no mention of value types other than through managed pointer types. Yet the specification for ldfld, for example, says:

The ldfld instruction pushes onto the stack the value of a field of obj. obj shall be an object (type O), a managed pointer (type &), an unmanaged pointer (type native int), or an instance of a value type.

Does this mean value types can be pushed directly on the evaluation stack (as opposed to via a managed pointer)? If so, can I assume that the value type being pushed is a memberwise copy of the original (the field value, for example)?

Was it helpful?

Solution 2

Section I.12.3.2.1 of ISO/IEC 23271:2012 (CLI Specification) states the following:

While the CLI, in general, supports the full set of types described in §I.12.1, the CLI treats the evaluation stack in a special way. While some JIT compilers might track the types on the stack in more detail, the CLI only requires that values be one of:

  • int64, an 8-byte signed integer
  • int32, a 4-byte signed integer
  • native int, a signed integer of either 4 or 8 bytes, whichever is more convenient for the target architecture
  • F, a floating point value (float32, float64, or other representation supported by the underlying hardware)
  • &, a managed pointer
  • O, an object reference
  • *, a “transient pointer,” which can be used only within the body of a single method, that points to a value known to be in unmanaged memory (see the CIL Instruction Set specification for more details. * types are generated internally within the CLI; they are not created by the user).
  • A user-defined value type

So, yes, the evaluation stack can contain a value type. And that value type is copied.

OTHER TIPS

See the introduction to III.1.1 (emphasis mine):

While the CTS defines a rich type system and the CLS specifies a subset that can be used for language interoperability, the CLI itself deals with a much simpler set of types. These types include user-defined value types and a subset of the built-in types. The subset, collectively called the “basic CLI types”, contains the following types:

Yes, ldfld definitely copies a value type value onto the eval stack. The "basic CLR types" are the ones that can appear as an operand to its operations. Review table III.2 for example, shows you want kind of operands can be used for the add instruction for example. Just int32, int64, native int, F, O and & appear there.

Also the core reason why C# requires a cast to copy the result of adding to byte values back into a value of type byte. Not a basic CLR type so it gets converted to int32 and produces an int32 result. Fitting it back into a byte is a non-trivial conversion.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top