问题
There is a single add
command in MSIL to add two arguments (pop from stack, add, push into stack). How does it know whether it has to pop 2 bytes or 4 or 8 bytes?
In java different bytecodes (fadd, dadd, iadd, ...) but how do they handle this in .NET?
回答1:
Java bytecode was optimized to be executed by an interpreter, early JVMs did not have Hotspot yet. .NET msil was designed from day one to always be jitted, no special opcodes for different operand types were necessary.
The jitter knows the operand type from the stack state. Whatever opcode pushed a value onto the stack indicates the type as well. Say an Opcodes.Ldarg_0, the jitter knows the type from the method signature. Keeping track of the stack state is something you never want to have to do in an interpreter, it slows down code execution significantly, a jitter only has to do it once.
回答2:
From the Common Language Infrastructure (CLI) Partition I: Concepts and Architecture, Section 12.1:
... the CLI supports only a subset of these types in its operations upon values stored on its evaluation stack—
int32
,int64
, andnative int
. In addition, the CLI supports an internal data type to represent floating-point values on the internal evaluation stack....
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.
The "below" discussing stack consistency is referring to section 12.3.2.1:
The evaluation stack is made up of slots that can hold any data type, including an unboxed instance of a value type. The type state of the stack (the stack depth and types of each element on the stack) at any given point in a program shall be identical for all possible control flow paths. For example, a program that loops an unknown number of times and pushes a new element on the stack at each iteration would be prohibited.
That is, whenever it encounters an add
instruction, it always knows the "shape" of the stack at the point and can therefore construct the correct native instructions. And it's working with a limited set of types anyway.
(Other specs for the CLI can be found from this page)
回答3:
If you write a C# test program and decompile it to MSIL, you can see the size are set by ldc
or conv
instructions before add
is called.
来源:https://stackoverflow.com/questions/38608012/net-msil-how-commands-detect-size-of-operands