值类型可以存储在线程的堆栈中,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引用的是哪个堆栈?是局部变量列表的大小吗?还是插入到执行堆栈中的附加存储的最大大小?
在我看来,执行堆栈是正确的堆栈,因为它只支持push和pop。局部变量列表支持从索引和load到索引的store。这与堆栈有什么关系?
更新:
ECMA 335 I.12.3机器状态清楚地回答了我的问题。
发布于 2013-05-16 16:58:49
拉塞的回答很好,我只想强调他的几点。
首先,将C#转换为等效的IL程序,然后将IL程序转换为等效的机器代码程序。IL语言有计算堆栈的概念;,这纯粹是IL语言中的一个概念。所需要的就是抖动将IL转换为具有相同最终结果的机器代码。根本不要求抖动实际上使用“真实”堆栈,仅仅因为IL程序是为了使用“评估堆栈”编写的。
基本上,IL是一种假定一个极其简化的处理器的语言;在IL中没有“寄存器”,只有堆栈。当然,在一个真正的处理器中有寄存器,因此IL的机器代码转换当然不会盲目地遵循计算堆栈的用法;这将是愚蠢的。
"max堆栈“指IL语言的”抽象“堆栈;它与机器代码中的实际线程堆栈没有特定的连接。
我已经写了许多关于“堆栈”的含义以及为什么我们使用IL的文章;如果您对这个主题感兴趣,您可能需要查看它们:
发布于 2013-05-16 16:14:57
局部变量通常存储在堆栈上。结果是,在方法开始时,堆栈上保留了许多字节,并且局部变量驻留在这些字节中。在方法返回之前,保留的堆栈空间是“非保留的”,因此变量将从堆栈中移除。
“局部变量列表”是存在于保留空间中的那些变量。
这样做的好处是,一个方法可以调用自己,而不必担心被前一个方法调用中的变量绊倒,当内部方法调用返回时仍然需要这个变量。
然而,这里也有其他的东西在起作用。您指的是IL代码,它是为虚拟计算机编写的“机器代码”。不是在VMware或类似环境下运行的虚拟计算机,而是不存在的虚拟计算机。没有CPU可以运行IL代码,就像您在问题中发布的代码一样。
相反,在第一次执行方法之前,JITter将执行IL代码并将其转换为将在实际CPU上运行的实际二进制机器代码,通常是在x86兼容指令中运行。
最后的二进制代码可能实际上不使用堆栈来保存局部变量,它可能使用CPU寄存器。IL正在获取的虚拟机使用堆栈作为其寄存器,x86兼容的cpus具有多个可用寄存器。
因此,您提交的代码可能被转换为二进制代码,使用这些寄存器而不是堆栈,因为这些寄存器比访问内存更快。
https://stackoverflow.com/questions/16592299
复制相似问题