C# 具有绝对返回路径的方法如何内联?
我主要使用C#进行开发,但我认为这个问题可能也适用于其他语言。C# 具有绝对返回路径的方法如何内联?,c#,inline,C#,Inline,我主要使用C#进行开发,但我认为这个问题可能也适用于其他语言。此外,这里似乎有很多代码,但问题非常简单 据我所知,内联是编译器(在虚拟机C#的情况下)通过在调用方法的每个位置插入方法体来替换方法调用 假设我有以下程序: static Main() { int number = 7; bool a; a = IsEven(number); Console.WriteLine(a); } 。。。方法的主体是: bool IsEven(int n)
此外,这里似乎有很多代码,但问题非常简单 据我所知,内联是编译器(在虚拟机C#的情况下)通过在调用方法的每个位置插入方法体来替换方法调用 假设我有以下程序:
static Main()
{
int number = 7;
bool a;
a = IsEven(number);
Console.WriteLine(a);
}
。。。方法的主体是:
bool IsEven(int n)
{
if (n % 2 == 0) // Two conditional return paths
return true;
else
return false;
}
我可以理解内联方法后代码的外观:
static Main()
{
int number = 7;
bool a;
if (number % 2 == 0)
a = true;
else
a = false;
Console.WriteLine(a); // Will print true if 'number' is even, otherwise false
}
static Main()
{
int number = 7;
bool a;
if (number % 2 == 0)
a = true;
a = false;
Console.WriteLine(a); // Will always print false!
}
一个明显简单正确的程序
但是如果我稍微调整的主体,使其包含一个绝对返回路径
bool IsEven(int n)
{
if (n % 2 == 0)
return true;
return false; // <- Absolute return path!
}
要问的问题:
编译器/虚拟机如何处理具有绝对返回路径的方法的内联问题?
这样的事情似乎不太可能真正阻止方法内联,所以我想知道如何处理这些事情。也许内联的过程没有这么简单?也许一个版本更可能被VM内联
编辑:
分析这两个方法(以及第一个方法的手动内联)在性能上没有任何差异,因此我只能假设这两个方法都内联并以相同或类似的方式工作(至少在我的VM上)。
此外,这些方法非常简单,看起来几乎可以互换,但具有绝对返回路径的复杂方法可能更难更改为没有绝对返回路径的版本。很难解释抖动在内联时会发生什么-它不会改变C代码来进行内联-它会(总是?)处理生成的字节(编译版本)——生成汇编代码(实际的机器代码字节)时使用的“工具”比C#(或IL)中使用的工具粒度要细得多
也就是说,你可以通过考虑break
关键字来了解它是如何工作的
考虑以下可能性:每个非平凡的内联函数都包含在一个while(true)
循环(或do-while(false)
循环)中,并且每个源返回都被转换为一组localVar=result;break;
语句
static Main()
{
int number = 7;
bool a;
while (true)
{
if (number % 2 == 0)
{
a = true;
break;
}
a = false;
break;
}
Console.WriteLine(a); // Will always print the right thing! Yey!
}
类似地,在生成程序集时,您将看到大量的jmp
s被生成-这些是break语句的道德等价物,但它们更灵活(将它们视为匿名goto之类)
因此您可以看到,jitter(以及任何编译为本机的编译器)手头有很多工具,可以用来做“正确的事情”。return
语句指出:
- 结果值
- 跳出函数
内联和文本替换之间的其他不同之处是对同名变量的处理。cpu执行的机器代码是一种非常简单的语言。它没有返回语句的概念,子例程有一个入口点和一个出口点。因此,您的IsEven()方法如下:
bool IsEven(int n)
{
if (n % 2 == 0)
return true;
return false;
}
需要通过抖动重写为类似于以下内容的内容(无效C#):
$retval变量在这里看起来可能是假的。事实并非如此,它是x86内核上的EAX寄存器。您现在可以看到,这段代码很容易内联,可以直接移植到Main()的主体中。通过简单的逻辑替换,$retval变量可以等同于
a
变量。顺便说一句:这是while的机制(对)break对于其他事情也很有用——我不经常使用它,但是当您有一组操作可能需要按顺序完成,但可以在任何给定时刻停止时,它是有用的。类似地,在本机语言中,当没有“finally”构造时,它被用来模拟“finally”构造(我在一些项目中使用了很多)
void IsEvent(int n)
{
if (n % 2 == 0) {
$retval = true;
goto exit;
}
$retval = false;
exit:
} // $retval becomes the function return value