2

值类型可能存储在线程的堆栈中,IL 在执行堆栈中运行(抽象概念)。

int y=0;
int a=0;
int b=0;

int x = y + (a - b);

IL_0001:  ldc.i4.0    
IL_0002:  stloc.0     // y
IL_0003:  ldc.i4.0    
IL_0004:  stloc.1     // a
IL_0005:  ldc.i4.0    
IL_0006:  stloc.2     // b
IL_0007:  ldloc.0     // y
IL_0008:  ldloc.1     // a
IL_0009:  ldloc.2     // b
IL_000A:  sub         
IL_000B:  add         
IL_000C:  stloc.3     // x

现在stloc.0从执行堆栈中弹出值并存储到局部变量列表中。因此,局部变量列表必须存储在与执行堆栈不同的空间中。什么是局部变量列表?它是一个线程的堆栈吗?

.maxstack = 3另外,方法指的是哪个堆栈?是局部变量列表的大小吗?还是推入执行堆栈的附加存储的最大大小?

在我看来,执行堆栈是正确的堆栈,因为它只支持pushpop. 局部变量列表支持load从一个索引store到一个索引。这与堆栈有什么关系?

更新:

ECMA 335 I.12.3 机器状态清楚地回答了我的问题。

4

2 回答 2

7

Lasse's answer is quite good; I just want to emphasize a few of his points.

First, C# is translated into an equivalent IL program, and then the IL program is translated into an equivalent machine code program. The IL language has the concept of an evaluation stack; this is purely a concept in the IL language. All that is required is that the jitter translate that IL into machine code that has the same final result. There is no requirement whatsoever that the jitter actually use the "real" stack just because the IL program was written to use an "evaluation stack".

Basically, IL is a language which assumes an extremely simplified kind of processor; there are no "registers" in IL, only stack. In a real processor of course there are registers, and so of course the machine-code translation of the IL will not slavishly follow its usage of an evaluation stack; that would be silly.

The "max stack" refers to the "abstract" stack of the IL language; it has no particular connection to the actual thread's stack in the machine code.

I've written a number of articles about the meaning of "the stack" and why we use IL; you might want to check them out if this subject interests you:

于 2013-05-16T16:58:49.173 回答
5

局部变量通常存储在堆栈中。发生的情况是,在方法开始时,堆栈中保留了一些字节,并且局部变量存在于这些字节中。在方法返回之前,保留的堆栈空间是“未保留的”,因此变量从堆栈中删除。

“局部变量列表”是那些存在于该保留空间内的变量。

这样做的好处是,一个方法可以调用自己,而不必担心在之前的方法调用中绊倒变量,这大概在内部方法调用返回时仍然需要。

然而,这里还有其他的东西在起作用。您指的是 IL 代码,它是为虚拟计算机编写的“机器代码”。不是在 VMware 或类似设备下运行的那种虚拟计算机,而是实际上并不存在的虚拟计算机。没有可用的 CPU 可以运行 IL 代码,就像您在问题中发布的那样,未经修改。

相反,在第一次执行方法之前,JITter 会介入并将 IL 代码转换为将在实际 CPU 上运行的真正二进制机器代码,通常是 x86 兼容指令。

The final binary code might not actually use a stack to hold local variables, it might use CPU registers. The virtual machine that the IL is targetting uses the stack as its registers, the x86 compatible cpus have multiple registers available.

As such, the code you posted might be translated into binary code that uses those registers instead of the stack, since those registers are faster than accessing memory.

于 2013-05-16T16:14:57.150 回答