Experimenting with ildasm to dive into CIL code it became obvious that CIL itself is working stack-based to support expressions like
IL_0001: ldc.i4.s 13 ; 1f 0d
IL_0003: stloc.0 ; 0a
IL_0004: ldc.i4.s 31 ; 1f 1f
IL_0006: stloc.1 ; 0b
IL_0007: ldloc.0 ; 06
IL_0008: ldloc.1 ; 07
IL_0009: add ; 58
Doing the same with float32
instead of int32
by using ldc.r4 <num>
there is no difference in calling add
thus making me wonder whether there are different stacks for different types or if there is only one stack which holds metadata which type a specific element has on the stack. Is there any information about the specific implementation in ECMA-335 or somewhere else?
This is specifically addressed in Partition I, part 12 (from e.g. this pdf), which discusses the Virtual Execution System (VES):
As described below, CIL instructions do not specify their operand types. Instead, the CLI keeps track of operand types based on data flow and aided by a stack consistency requirement described below. For example, the single
add
instruction will add two integers or two floats from the stack.
And:
Most CIL instructions that deal with numbers take their operands from the evaluation stack (see §I.12.3.2.1), and these inputs have an associated type that is known to the VES. As a result, a single operation like
add
can have inputs of any numeric data type, although not all instructions can deal with all combinations of operand types.
Where I.12.1.4 goes into considerably more detail also.
The JIT infers the types. It has to do this anyway to type-check your program. There is no need to parameterize operations for the types they operate on. The types and size of the stack are computable at any point in the IL instruction sequence. If they are not computable or ambiguous the program is unverifiable.
I believe Java IL does this differently but I might be mistaken.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With