返回首页

摘要
微软#8217;。NET Framework是一个新的平台,旨在简化 分布式应用程序的发展。位于底部的。NET的 CLR中,所谓的公共语言运行库。 CLR提供了一个环境 控制。NET代码,如内存管理,线程执行,代码, 检查,安全服务和垃圾收集。 CLR还实行了严格的 基础设施要求检查代码中旅(普通型子系统) 可以安全地使用和类型,即在一种语言中创建的类型,并提到 在另一种语言。托管执行环境解决某些问题 与传统的本机代码的执行。 CLR会自动处理 安排的对象和它们的引用,释放他们时,他们没有 不再需要,从而避免无效引用和内存泄漏。 CLR会 不依赖于本机x86指令集。相反,微软已经创建  ; 支持所有的编译器生成的中间语言(IL)  60;。NET平台。微软中间语言(MSIL)是一个处理器 独立的指令集,包括执行控制指令, 直接内存访问,异常处理,逻辑和算术运算,如 以及装卸,储存和对象初始化的说明。 " MSIL代码不能直接执行,它必须被转换成一个特定处理器 代码由一个JIT编译器(时间)。任何支持的体系结构必须 提供其特定的JIT编译器。
当我在写三角洲代码生成等等。NET编译器() 我发现,IL可以在一定程度上的改善。本文 建议加强为Microsoft中间语言。Microsoft中间语言
MSIL是从我们对传统的汇编语言的认识不同。 虽然赋与低级别的指令,语言也与 高层次的概念,如异常处理和内存管理。 " 白细胞介素也有一个虚拟的参数堆栈,可以容纳不同类型的对象, 堆栈的纪律是如字符串,整数,浮点数,指针等。 & #160; 严格,这意味着在执行命令时,堆栈必须 持有所需的参数的确切人数。在另一侧,在x86  ; 汇编语言允许在堆栈上参数的随机数,甚至 提供和清洗后留下一个程序的堆栈指令(见 RET ñ)。
的指示处理堆栈操作: 推值的LOAD指令(ldarg,ldloc,ldnull等) 入堆栈 关闭弹出值的存储指令(starg,stloc,stind等) 堆栈 复制栈顶元素的DUP指令#8211; POP指令#8211;删除栈顶元素
IL指令集的有关信息,在[2]看看。
虽然足以实现其目标,IL指令集似乎 导致低效的代码生成。在发展过程中 为第四。NET平台编译器,我发现多次 生成的代码是更长的时间比它应该是事实由于缺乏一些简单的 说明。为了使读者在理解的代码序列 遵循,这是适当的去了解一些堆栈处理原​​语 第四编程语言: 0;
第四原始 &# 160;
堆栈过渡
说明
的DUP & #160;
(#8211;大)
重复的顶级元素 堆栈   ;
 0;
(A B#8211; A B A)
复制第二个元素 栈顶  60;
以物易物   ;
(A B#8211;乙一)
互换最上面的两个元素 在栈上 & #160;
腐  0;
(A B C#8211; B C A)
旋转三个最顶层的元素 在栈上   ;
1   ;
(#8211; 1)
递增1的元素& #160; 栈顶  0;
2
(#8211; 2)
递增2的元素   ; 栈顶
栈过渡列显示前和执行后的堆栈状态 的本原。这两种状态是由破折号签署分隔。
解决在第四的数学表达式是相当复杂的程序员 使用传统的命令式语言,但是有#8217;没有什么特别的 0; 除了使用逆波兰表示法(RPN)。进一步阅读&# 160; 我建议[3]。
让#8217;例如,表达式:
(二)*(#8211;二):
后缀相当于是: 60;
A B A B -
第四原语序列,解决了表达(假设 A和B都已经在这个顺序栈上的值)是:
(A B#8211; A B A)
结束(A B#8211; A B A B)
(A B A B#8211; A B C),其中C = A B
 0; ROT(A B C#8211; B C A)
ROT(C A#8211,C A B)
- (C A B#8211; C D),其中D = C#8211,B
*(C D#8211,E),其中E = C * D
了解上面的代码将帮助你理解IL代码片段 遵循。让#8217;的举动,并期待#8230; 引擎盖下
有趣的是,在编译程序的生成的IL代码 写在一个。NET支持的语言。我选择的语言是C#的这 似乎非常有前途的。为了下面你重复实验需要Visual Studio NET和。NET Framework的IL反汇编。
进行测试的类,我们将使用非常简单,很容易理解 即使是初学者:

class UnderTheHood

{

    private static int[] x = new int [] {1, 2, 3};

    private static int i = 0, j = 0, t = 0;

  

    static void Main(string[] args)

    {

        // Here we will insert code snippets

    }

}

让#8217;采取的第一个例子:
X [I 1 = I 2;
功能主要由编译器生成的代码是:{C}
第一行和第二行推栈上的静态值 变量x和我分别。我的价值得到增加(推 1,执行加法)。增量操作(这2次) 重复行IL_000c和IL_0012。最终结果是存储 在其目的地行IL_0013。
乍一看,我们看到的代码序列计算两个索引I 1 I 2分别。如果我们还记得从以前的1第四原始 段,我们看到,使用它会导致更大的效益,特别是 因为大多数现代处理器INC和DEC指令。翻译从 本机代码的IL是显而易见的。修改后的顺序可能看起来像 如下:
IL_0000:	ldsfld		int32[] CallTest.UnderTheHood::x

IL_0005:	ldsfld		int32 CallTest.UnderTheHood::i

IL_000a:	ldc.i4.1

IL_000b:	add

IL_000c:	dup

IL_000d:	inc.1		// Non-existent mnemonic, see text

IL_000e:	stelem.i4

IL_000f:	ret

我选择的助记符inc.1,这意味着堆栈顶部的值递增   ;1。同样,我们可以写inc.2,12月1日,12月2日的其他业务。 " & #160; 增益是7个字节。
让#8217;重做实验,这一次与下列顺序:
X [我1] = 1;
在这种情况下,IL顺序是:
.locals (	[0] int32[] CS$00000002$00000000,

	[1] int32 CS$00000002$00000001)

	

IL_0000:  ldsfld		int32[] CallTest.UnderTheHood::x

IL_0005:  dup

IL_0006:  stloc.0

IL_0007:  ldsfld		int32 CallTest.UnderTheHood::i

IL_000c:  ldc.i4.1

IL_000d:  add

IL_000e:  dup

IL_000f:  stloc.1

IL_0010:  ldloc.0

IL_0011:  ldloc.1

IL_0012:  ldelem.i4

IL_0013:  ldc.i4.1

IL_0014:  add

IL_0015:  stelem.i4

IL_0016:  ret

我们可以看到,编译器自动生成了两个匿名当地 变量的值保持为X(线IL_0006),我1(行IL_000f)。 这个序列,就可以大大优化使用过第四原始, 复制堆栈上的第二个最顶端的元素。重写的IL 代码看起来像这样:
IL_0000:  ldsfld		int32[] CallTest.UnderTheHood::x

IL_0005:  dup

IL_0006:  stloc.0

IL_0007:  ldsfld		int32 CallTest.UnderTheHood::i

IL_000c:  inc.1		// Non-existent mnemonic, see text

IL_000d:  over		// Non-existent mnemonic, see text

IL_000e:  over

IL_000f:  ldelem.i4

IL_0010:  ldc.i4.1

IL_0011:  add

IL_0012:  stelem.i4

IL_0013:  ret

的收益是6个字节。
一个,而通常的顺序是交换两个变量的发现的元素。在C# 程序看起来像这样:
t = i;

i = j;

j = t;
等效的IL代码是:
IL_0000:	ldsfld	int32 CallTest.UnderTheHood::i

IL_0005:	stsfld	int32 CallTest.UnderTheHood::t

IL_000a:	ldsfld	int32 CallTest.UnderTheHood::j

IL_000f:	stsfld	int32 CallTest.UnderTheHood::i

IL_0014:	ldsfld	int32 CallTest.UnderTheHood::t

IL_0019:	stsfld	int32 CallTest.UnderTheHood::j

IL_001e:	ret

注意,IL顺序如下C#程序的紧密合作。这将是有趣 如果高层次的语言本身提供的程序员交换指令, 所以,前面的代码片段可以改写如下:
IL_0000:	ldsfld	int32 CallTest.UnderTheHood::i

IL_0005:	ldsfld	int32 CallTest.UnderTheHood::j

IL_000a:	swap	// Non-existent mnemonic, see text

IL_000f:	stsfld	int32 CallTest.UnderTheHood::j

IL_0014:	stsfld	int32 CallTest.UnderTheHood::i

IL_0019:	ret

获得9个字节,不考虑节省空间 不宣布一个中间的临时变量(T)。该代码可以进一步 完全取代了交换操作的细化:
IL_0000:  ldsfld     int32 CallTest.UnderTheHood::i

IL_0005:  ldsfld     int32 CallTest.UnderTheHood::j

IL_000a:  stsfld     int32 CallTest.UnderTheHood::i

IL_000f:  stsfld     int32 CallTest.UnderTheHood::j

IL_0014:  ret
结论
即使在乍看之下增益是空间小,在现实中的事情 略有不同。这样的代码序列在每一天的比较频繁 应用。如果我们认为,一个中等规模的应用程序可能包含约 这种优化的结构和200个中等增益大约是8个字节   ; 每构造,我们节省代码空间,这不是可以忽略不计为嵌入式1.6KB 系统。
空间增益是不是唯一的参数,在使用新的IL指令的青睐。 由JIT生成的本地代码可能会受益于使用这些指令 更高效的转换,因为一些专用处理器指令 可以使用。&# 160; 传记
[1]的Microsoft Developer Network,
[2]通用语言文字基础设施,三分区(CIL的指令集)
[3]所列的表达式,Valer BOCAN,净 报告显示,2002年1月(罗马尼亚)
[4]三角洲等等。NET开发系统,(三)1997-2002年Valer BOCAN,

回答

评论会员:标记FOCAS 时间:2011/11/29
multumesc frumos,电子foarte interesant

少数一,不会使你疯狂
(乔治奥威尔,我觉得)
评论会员:马克克利夫顿 时间:2011/11/29
优化是一个有趣的的问题,我不认为MS已经把足够的努力至于它与白细胞介素。一方面,已产生相当的通用语法,另一方面,它似乎是有没有"背景"优化正在进行。例如,C项目的优化开关在VS6是检测以前加载的索引寄存器和再利用。

我认为在IL优化的问题之一是,它应该是独立的处理器。不幸的是,将与一个处理器的指令集的优化,可能无法正常工作与另一个。这就是说,有没有任何借口的MS不优化层somwhere,无论是在前面的IL发生器之间的IL和最终汇编语言输出。{BR​​}
在Il简要地看着,我想,它提供了CPU的指令集的一面镜子(是的,这使得它特定于处理器)。我真的很喜欢在C _asm能力,让我创造一些真正优化的代码。但话又说回来,这违背"托管"的概念,我总是可以链接到一块非托管代码。噢,世界似乎充满不满妥协与IL。这是一个伟大的想法,能够统一到CLR的语言,但在成本

此外,纠正我,如果我错了,提出的,所以栈的基础,应该不是一个实现真正维护两个栈 - "数据"和所有其他的东西之一 - 返回地址,登记保存等?

马克



评论会员:丹尼尔图里尼 时间:2011/11/29
马克克利夫顿写道:
似乎有没有"背景"优化。例如,C项目的优化开关在VS6是检测以前加载的索引寄存器和再利用。

事实并非如此。从白细胞介素生成的。NET优化ASM。而且它可以做一个更好的工作比VC6.0优化阶段,因为:
1。它可以看到整个应用程序,不仅是单一的。OBJ文件(我知道,VC7 ...){ BR}2。它可以做特定环境下的优化,像使用特定的处理器操作码,因为它是用户的机器上,而不是开发人员的一个。它甚至可以改变的寄存器,它提供基于调用约定。

克利夫顿马克写道:
有没有理由不为MS有一个优化层somwhere
这就是为什么他们把它的JIT编译器上。为什么你会认为他们称之为"中级"语言???

克利夫顿马克写道:
我真的很喜欢在C _asm能力,让我创造一些真正优化的代码。但话又说回来,这违背"托管"的概念,我总是可以链接到一块非托管代码。噢,世界似乎充满不满妥协与IL。这是一个伟大的想法,能够统一到CLR的语言,但在成本

在CodeProject上搜索IJW和MC



评论会员:马克克利夫顿 时间:2011/11/29
哇。这篇文章是大开眼界。当然教育的天真OL"我!谢谢!

马克



评论会员:戈兰米特罗维奇 时间:2011/11/29
马克克利夫顿写道:
>>有没有理由不为MS优化层?BR}>> somwhere
>这就是为什么他们把JIT编译器。你为什么
认为他们称之为"中级"语言???

虽然我完全同意你的意见,这是错误的 - 高层次的优化和琐碎的低级别的(跳消除,消除不必要的指令等),应该在编译时 - 平凡的低级的,因为它们在运行时保存时间,而
良性足够的和高层次的,因为他们根本就没有可能在JIT。
目前没有。NET语言功能的任何优化,即使是有它的开关。不过,如果我没有记错的话,那将改变与未来的MC版本(不是CS,例如)。


- 戈兰
评论会员:丹尼尔图里尼 时间:2011/11/29
戈兰米特罗维奇说:
应该在编译时完成高层次的优化和琐碎的低级别的(跳消除,消除不必要的指令等)

为什么?这将使生成的本地代码没有区别,不仅会影响IL代码大小位。即使你"JIT时间",这样的优化,在编译时,你仍然需要再次创建一个控制流图,并再次申请此类优化...


懒惰是不是我的中间名..我的第一..人们只是不断叫我梅尔事业,这就是他们把我的驾驶执照。 - 梅尔Feik
评论会员:ValerBOCAN 时间:2011/11/29

克利夫顿马克写道:
我认为在IL优化的问题之一是,它应该是独立的处理器。不幸的是,将与一个处理器的指令集的优化,可能无法正常工作与另一个。
在我的文章,我只讨论了在空间上的优势。我所描述的优化,它有可能在一定程度上减少PE可执行文件的大小。这已无关的处理器独立性。所有相关的JIT本身。
克利夫顿马克写道:
此外,纠正我,如果我错了,提出的,所以栈的基础,应该不是一个实现真正维护两个栈 - "数据"和所有其他的东西之一 - 返回地址,登记保存等?
这是正确的。四有一个值栈和返回栈。他们在每一个方面,除原语移动值从一个到另一个独立。

三角洲等等。NET
世界上第一个提出了NET平台的编译器
评论会员:丹尼尔图里尼 时间:2011/11/29
无法由JIT编译器做?在生成代码时,不能在JIT优化这段代码和消除这些序列? IL指令和本地的汇编指令的1x1之间没有必然的关系。是的IL是一个独立于平台的ASM,所以你将有什么保证,例如,在目标平台上的ASM指令堆栈上的交换?是不是更好让JIT优化阶段这个决定呢?一个简单的流程优化的编译器可以照顾这个。除此之外,你假设ldsfld和最不发达国家将转化为推动指示? ,JIT编译器将分配给寄存器。
这些建筑似乎更适合比其他语言,如C#,VB.NET,J#,COBOL,到第四的,因为这样的建设是非常频繁,对第四,因为正确的我,如果我错了,Forth是一个面向堆栈语言(噢,我的好老forgoten ZX81天),但不能在新的结构化或面向对象编程语言,这种建设更是罕见。这难道不是延长。NET的IL,以适应一个特定的语言?如果MS每一种语言,不久的IL将变得臃肿和生成的代码将变得更大。
掘到的。NET生成的代码,你总是可以找到更多的IL指令来创建,但一定要有一个的指令数和生成的代码的大小之间的最佳平衡。

关于TUCOWS问题:要小心,有些人讨厌的控制台应用程序,太:

评论会员:游客 时间:2011/11/29
马克克利夫顿。挖掘NET生成的代码,你总是可以找到更多的IL指令来创建,但一定要有一个的指令数和生成的代码的大小之间的最佳平衡这使我想起我更多的指令,在昔日的微处理器参数:平衡所需的晶体管数量更多的指令。微码之前的日子里,我猜。还记得,当我们可以微处理器执行"非法"的指示,有时他们实际上做了有益的事情呢?马克imgsrc=http://www.orcode.com/upimg/2011_11_29_05_57_37_3.gif
Valer BOCAN
评论会员:游客 时间:2011/11/29
丹尼尔图里尼写道:这是由JIT编译器完成?在生成代码时,不能在JIT优化这段代码和消除这些序列?IL指令和本地的汇编指令的1x1之间没有必然的关系。是的IL是一个独立于平台的ASM,所以你将有什么保证,例如,对堆栈的汇编指令在目标平台上的交换?正如我在以前的帖子中提到的,萎缩的PE可执行文件的大小的文章,即IL代码本身的大小。事实上,我们不需要白细胞介素和原生的ASM之间有一个1:1的关系,但是有一些(简单)的IL指令导致一个较短的IL代码。丹尼尔图里尼说:这些建筑似乎更适合比其他语言,如C#,VB.NET,J#,COBOL,到第四的,因为这样的建设是非常频繁,对第四,因为正确的我,如果我错了,Forth是一个面向堆栈语言(噢,我的好老forgotenZX81天),但不能在新的结构化或面向对象编程语言的这种建设更是罕见。我们正在谈论这样的结构:X[我1]=I2;X[我1]=1;T=我;i=j时,J=T......相似。我不知道你,但我已经看到了这样的序列,如C和C语言编写的许多方案。丹尼尔图里尼说:关于TUCOWS问题:要小心,有些人讨厌的控制台应用程序,太:然后,他们肯定恨csc.exe的工具,它的方式是非常的C#编译器{S0}{S1}这是没有借口"两狂牛"团队,他们可以简单地说,他们不会接受一个控制台应用程序。三角洲等等。NET世界上第一个NET平台第四编译器
若瓦斯
评论会员:游客 时间:2011/11/29
。后,我去你的网站,因为我在编译器和NETIL代,和你的编译器似乎一个不错的工作,我阅读本imgsrc=http://www.orcode.com/upimg/2011_11_29_05_57_37_8.gif]我感到非常震惊TUCOWS工作人员,什么白痴!!!!!他们不尊重程序员的辛勤工作。DOS应用程序{S2},海恩,geeeeeeez....哎哟{S3}欢呼声,若瓦斯,如果你的梦想是照顾你的家人,放在桌子上的食物,为他们提供教育和良好的家庭通过无尽的,毫无意义的,枯燥的工作,那么也许痛苦会显得有目的。你会发现怎么连一块石头可以改变世界,根本其余硬是stationary.Shog9
若瓦斯
评论会员:游客 时间:2011/11/29
{S4}什么白痴!Valer:只是出于兴趣,图像修改捅乐趣在TUCOWS,IIRC,imgsrc=http://www.orcode.com/upimg/2011_11_29_05_57_37_9.gif]根据美国版权法允许。如果该图像是为了调侃TUCOWS*是完全合法的。这可能会抵消你的编译器添加到TUCOWS的任何企图。{五}*我不是律师,所以你可能想寻求法律帮助,然后才将图像备份[编辑]改变了我的措辞,一点点,不能让人们以为我一个律师{S0}[/编辑]"詹姆斯SIG代码被盗大卫乌尔夫
Valer BOCAN
评论会员:游客 时间:2011/11/29
詹姆斯T.约翰逊写道:它可能会抵消得到你的编译器的任何企图,TUCOWS。在此之后,我怀疑,他想......詹姆斯T.约翰逊写道:编辑]一个改变我的措辞的一点,不能让人们以为我是一个律师[/编辑]您莱尔,你是一个律师,你的耻辱{七}欢呼声,若瓦斯,如果你的梦想是照顾你的家人,放在桌子上的食物,为他们提供教育和良好的家庭通过无尽的,毫无意义的,枯燥的工作,那么也许痛苦会显得有目的。你会发现怎么连一块石头可以改变世界,只需其余硬是stationary.-Shog9
若瓦斯
评论会员:游客 时间:2011/11/29
我的感谢。我已经收到了一些类似的信件:山姆亨利,Micorosft公​​司:只是想让你知道,你的第四约TUCOWS的故事破获我。我的VisualStudio。NET技术产品经理。布拉德美林,微软:对不起,我没有听到你的TUCOWS早期的问题。我们将与他们联系,看看我们是否可以理解的问题是什么??/ITUCOWS是不是有唯一的共享目录,所以我列出我的软件的一些地方。三角洲等等。NETdacris
|:世界上第一个提出了NET平台
的编译器也许,布拉德美林,可以帮助你,毕竟它从微软的

Valer BOCAN写道:
所以我的清单我的软件的一些地方。

当然,还有一个很多其他地方,把你的好工作{S8}

欢呼声,若瓦斯
,如果你的梦想是照顾你的家人,放在桌子上的食物,为他们提供教育和良好的家庭通过无尽的,毫无意义的,枯燥的工作,那么也许痛苦会显得有目的。你会发现怎么连一块石头可以改变世界,只需其余硬是stationary. Shog9
评论会员:游客 时间:2011/11/29
Merlinbl​​ack
TUCOWS jackasses。我知道我自己的亲身经历。 {S9}

我有我的电脑的共生关系
评论会员:。若瓦斯 时间:2011/11/29
!圣TU奶牛{S4}的

评论可能要检讨的软件堆,你会希望有更多的。但话又说回来最non-programmer/database人我知道在工作中仍引用到Cmd.exe"DOS窗口"。他们看我面无表情,当我提到的"控制台"。当然,所有的* nix的家伙,加仑,确切地知道什么我就约了。
我听说它称为"Windows终端"一次或两次!


奈杰尔阿特金森

"土地a'hoy!" * CRASH *"我应该AV说,迟早是吗?" - Eckles,笨蛋显示