【问题标题】:How are the call stack and the evaluation stack related?调用堆栈和评估堆栈如何相关?
【发布时间】:2023-03-11 10:05:17
【问题描述】:

第二次尝试措辞:

我目前正在逐步掌握一些 MSIL。

我经常听到“评估堆栈”被谈论为操作在加载、使用等时被推送和弹出的堆栈。

所以,给定以下代码:

public class Program
{
    public static void Main()
    {
        var message = GetMessage();

        Console.WriteLine(message);
    }

    public static string GetMessage()
    {
        return "Hello World!";
    }
}

MSIL 如下所示:

.class public auto ansi beforefieldinit Program
    extends [mscorlib]System.Object
{
    .method public hidebysig specialname rtspecialname instance void .ctor () cil managed 
    {
        IL_0000: ldarg.0
        IL_0001: call instance void [mscorlib]System.Object::.ctor()
        IL_0006: ret
    }

    .method public hidebysig static string GetMessage () cil managed 
    {
        .locals init (
            [0] string V_0
        )

        IL_0000: nop
        IL_0001: ldstr "Hello World!"
        IL_0006: stloc.0
        IL_0007: br.s IL_0009

        IL_0009: ldloc.0
        IL_000a: ret
    }

    .method public hidebysig static void Main () cil managed 
    {
        .entrypoint
        .locals init (
            [0] string V_0
        )

        IL_0000: nop
        IL_0001: call string Program::GetMessage()
        IL_0006: stloc.0
        IL_0007: ldloc.0
        IL_0008: call void [mscorlib]System.Console::WriteLine(string)
        IL_000d: nop
        IL_000e: ret
    }
}

认为IL_xxxx 开头的行是评估堆栈(如果我错了,请纠正我)。所以call string Program::GetMessage()这一行是调用另一个方法的那一行。

所以,我想我要问的问题是这样的:

  1. IL_0000 开头的每一行都是“新”评估堆栈吗?
  2. 我在运行时看到的调用堆栈是此 IL 的加入\串联\过滤吗?

【问题讨论】:

  • @CodeCaster 我认为call 操作码称为方法。至少,这就是我目前所读到的内容所暗示的。
  • 如果您引用 CLI 规范的相关部分可能会有所帮助,以便读者了解您的思路。
  • @CodeCaster 我现在只是在学习它,现在是视频和博客。我处于 MSIL 的“Hello World”阶段,因此很可能我的问题对任何有经验的人都没有意义。我会重新措辞并重试。
  • 记住 eval 堆栈是一个抽象非常重要。它为编译器为其生成 CIL 的虚拟机提供服务。它与处理器执行的真实代码完全无关。 jitter 的工作,它所做的最重要的事情是摆脱 eval 堆栈,因为它完全太低效了。但是,是的,每个方法的 CIL 都有一个从头开始的虚拟评估堆栈。而你在调试器中看到的堆栈跟踪,大致就是一堆堆栈。

标签: c# .net vb.net cil callstack


【解决方案1】:

我认为以 IL_xxxx 开头的行是评估堆栈

以 IL_0000 开头的每一行都是“新”评估堆栈吗?

没有。每种方法都有一个评估堆栈。将其视为Stack<object>。 IL 指令通过压入和弹出项目对该堆栈进行操作。 MSDN 文档准确地列出了每个 IL 操作码的堆栈行为。

调用堆栈与评估堆栈无关。调用堆栈是调用堆栈 Visual Studio 窗口向您显示的内容。

我在运行时看到的调用堆栈是这个 IL 的加入\串联\过滤吗?

没有。没有关系。

我觉得你对评估堆栈的想法太复杂了。这是一个很简单的概念。只要你脑子里有复杂的东西,你就没有掌握它。不过,我不确定误解究竟在哪里。

请注意,评估堆栈是一个逻辑概念,用于定义 IL 程序的含义。与(禁止内联)确实存在的调用堆栈相比,它在运行时不再存在。

【讨论】:

  • 是否存在以IL_0000 开头的一行而不是新方法的开始的情况?
  • 是的,这些是任意标签。它们不是 IL 的一部分,除了作为分支目标之外没有任何意义。您可以随意“标记线条”。它们也与堆栈没有任何关系。
  • “只要你脑子里有复杂的东西,你就没有掌握它”——金句!
【解决方案2】:

在 CIL 上下文中,这是抽象的(与在处理器上执行的物理代码相比)。

我会说调用堆栈是被调用方法“方法状态”的堆栈,评估堆栈包含在每个“方法状态”中并包含“执行数据”。 我们使用如下指令操作的数据:Pop / Ldarg...

每个方法 - “方法状态” - 都有自己的本地评估堆栈

参考:ECMA-335_6th_edition_june_2012.pdf - page: 108

OpCodes.Ldarg

【讨论】:

    猜你喜欢
    • 2021-05-02
    • 1970-01-01
    • 2015-02-14
    • 2015-01-01
    • 2012-05-01
    • 2013-05-02
    • 2012-10-07
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多