《Inside Microsoft IL Assembler》学习笔记2:让IL代码简短些

还是学习笔记1中的那个例子,可以改成如下的样子,功能不变,但运行时占用的资源会小一些。我在所有和笔记1中代码有了变化的位置加上了注释,如下:
 1《Inside Microsoft IL Assembler》学习笔记2:让IL代码简短些//----------- Program header
 2《Inside Microsoft IL Assembler》学习笔记2:让IL代码简短些《Inside Microsoft IL Assembler》学习笔记2:让IL代码简短些.assembly extern mscorlib 《Inside Microsoft IL Assembler》学习笔记2:让IL代码简短些{ }
 3《Inside Microsoft IL Assembler》学习笔记2:让IL代码简短些《Inside Microsoft IL Assembler》学习笔记2:让IL代码简短些.assembly OddOrEven  《Inside Microsoft IL Assembler》学习笔记2:让IL代码简短些{ }
 4《Inside Microsoft IL Assembler》学习笔记2:让IL代码简短些.module OddOrEven.exe
 5《Inside Microsoft IL Assembler》学习笔记2:让IL代码简短些//----------- Class declaration
 6《Inside Microsoft IL Assembler》学习笔记2:让IL代码简短些《Inside Microsoft IL Assembler》学习笔记2:让IL代码简短些.namespace Odd.or 《Inside Microsoft IL Assembler》学习笔记2:让IL代码简短些{
 7《Inside Microsoft IL Assembler》学习笔记2:让IL代码简短些《Inside Microsoft IL Assembler》学习笔记2:让IL代码简短些    .class public auto ansi Even extends [mscorlib]System.Object 《Inside Microsoft IL Assembler》学习笔记2:让IL代码简短些{
 8《Inside Microsoft IL Assembler》学习笔记2:让IL代码简短些//----------- Field declaration
 9《Inside Microsoft IL Assembler》学习笔记2:让IL代码简短些        .field public static int32 val
10《Inside Microsoft IL Assembler》学习笔记2:让IL代码简短些//----------- Method declaration
11《Inside Microsoft IL Assembler》学习笔记2:让IL代码简短些《Inside Microsoft IL Assembler》学习笔记2:让IL代码简短些        .method public static void check( ) cil managed 《Inside Microsoft IL Assembler》学习笔记2:让IL代码简短些{
12《Inside Microsoft IL Assembler》学习笔记2:让IL代码简短些            .entrypoint
13《Inside Microsoft IL Assembler》学习笔记2:让IL代码简短些            .locals init (int32 Retval)
14《Inside Microsoft IL Assembler》学习笔记2:让IL代码简短些        AskForNumber:
15《Inside Microsoft IL Assembler》学习笔记2:让IL代码简短些            ldstr "Enter a number"
16《Inside Microsoft IL Assembler》学习笔记2:让IL代码简短些            call void [mscorlib]System.Console::WriteLine(string)
17《Inside Microsoft IL Assembler》学习笔记2:让IL代码简短些            call string [mscorlib]System.Console::ReadLine()
18《Inside Microsoft IL Assembler》学习笔记2:让IL代码简短些            ldstr "%d" // 所有的字符串常量都不需要特殊的声明,il汇编器看到这样的字符串之后会自动将其加入到元数据中
19《Inside Microsoft IL Assembler》学习笔记2:让IL代码简短些            ldsflda int32 Odd.or.Even::val
20《Inside Microsoft IL Assembler》学习笔记2:让IL代码简短些            call vararg int32 sscanf(string,string,《Inside Microsoft IL Assembler》学习笔记2:让IL代码简短些,int32*
21《Inside Microsoft IL Assembler》学习笔记2:让IL代码简短些            stloc.0 // java的虚机和.net clr都使用0,1,2,3这样的编号来表示本地变量。这里的"0"就指向唯一的一个本地变量Retval
22《Inside Microsoft IL Assembler》学习笔记2:让IL代码简短些            ldloc.0 // 将第一个本地变量的值压栈
23《Inside Microsoft IL Assembler》学习笔记2:让IL代码简短些            brfalse.s Error  // brfalse.s指令是brfalse的简化指令。当指令被编译成操作码之后,brfalse接受的是一个4字节的参数,
24《Inside Microsoft IL Assembler》学习笔记2:让IL代码简短些        //而brfalse.s仅接受一个单字节的参数,这意味着只能在代码段的{-128字节~~+128字节}的范围内(相对于当前位置而言)跳转。
25《Inside Microsoft IL Assembler》学习笔记2:让IL代码简短些            ldsfld int32 Odd.or.Even::val
26《Inside Microsoft IL Assembler》学习笔记2:让IL代码简短些            ldc.i4.1  // 向栈顶压入一个单字节常量,值为1(ldc.i4 1也是向栈顶压入1,但要用4个字节)
27《Inside Microsoft IL Assembler》学习笔记2:让IL代码简短些            and
28《Inside Microsoft IL Assembler》学习笔记2:让IL代码简短些            brfalse.s ItsEven  
29《Inside Microsoft IL Assembler》学习笔记2:让IL代码简短些            ldstr "odd!"
30《Inside Microsoft IL Assembler》学习笔记2:让IL代码简短些            br.s PrintAndReturn 
31《Inside Microsoft IL Assembler》学习笔记2:让IL代码简短些        ItsEven:
32《Inside Microsoft IL Assembler》学习笔记2:让IL代码简短些            ldstr "even!"
33《Inside Microsoft IL Assembler》学习笔记2:让IL代码简短些            br.s PrintAndReturn  
34《Inside Microsoft IL Assembler》学习笔记2:让IL代码简短些        Error:
35《Inside Microsoft IL Assembler》学习笔记2:让IL代码简短些            ldstr "How rude!"
36《Inside Microsoft IL Assembler》学习笔记2:让IL代码简短些        PrintAndReturn:
37《Inside Microsoft IL Assembler》学习笔记2:让IL代码简短些            call void [mscorlib]System.Console::WriteLine(string)
38《Inside Microsoft IL Assembler》学习笔记2:让IL代码简短些            ldloc.0  
39《Inside Microsoft IL Assembler》学习笔记2:让IL代码简短些            brtrue.s AskForNumber  
40《Inside Microsoft IL Assembler》学习笔记2:让IL代码简短些            ret
41《Inside Microsoft IL Assembler》学习笔记2:让IL代码简短些        }
 // End of method
42《Inside Microsoft IL Assembler》学习笔记2:让IL代码简短些    }
 // End of class
43《Inside Microsoft IL Assembler》学习笔记2:让IL代码简短些}
 // End of namespace
44《Inside Microsoft IL Assembler》学习笔记2:让IL代码简短些//----------- Calling unmanaged code
45《Inside Microsoft IL Assembler》学习笔记2:让IL代码简短些.method public static pinvokeimpl("msvcrt.dll" cdecl) 
46《Inside Microsoft IL Assembler》学习笔记2:让IL代码简短些《Inside Microsoft IL Assembler》学习笔记2:让IL代码简短些    vararg int32 sscanf(string,string) cil managed 《Inside Microsoft IL Assembler》学习笔记2:让IL代码简短些{ }
47《Inside Microsoft IL Assembler》学习笔记2:让IL代码简短些

  另外,提起上文中的ldloc.0这样的指令,笔者一开始也是未明其意。其实,在clr执行程序的过程中,涉及到的内存使用主要有三类,除了我们常说的托管堆,每个线程都有自己专属的两个栈:计算栈(Evaluation Stack)和调用栈(Call Stack)。这两个栈都经常被提到,又都专属于clr线程,所以有的时候会混,其实它们的功能是完全不同的。调用栈就是最传统的用来记录方法调用次序的栈,每个线程会得到1MB的调用栈空间,每调用一个新的方法都会压栈,传入参数、临时变量等都会压入栈中,待方法执行完毕就完全释放。ldloc.0中的"0",所指的就是当前调用栈上的第一个临时变量。而计算栈在某种程度上可以视为clr虚拟机的寄存器(这么说只是因为它是和虚机上的计算功能直接交互的存储单位),我们常说的clr虚机是完全基于“栈”的,指的就是计算栈。虚机上的所有操作,都要从计算栈的参数,结果也都会压入到计算栈顶。计算栈的单位既不是字,也不是字节,而是slot(怎么翻译合适呢,咳咳),根据slot内所装数据类型的不同,slot的大小也不同。当clr栈顶的slot里取到数据之后,在运算之前会检验数据的类型,如果无法转换成运算期望的类型,会抛出异常。蔡学庸在msdn上有篇文章,里面的一个贴图看着很明白,就在这里借用一下吧:
《Inside Microsoft IL Assembler》学习笔记2:让IL代码简短些

 参考资料:MSIL instruction table

转载于:https://www.cnblogs.com/xingyukun/archive/2007/07/10/813102.html