前言 上一篇文章主要介紹了IL的概念以及基礎的示例代碼,在這一篇文章中我們將通過對象調用看IL。 創建對象與調用方法 class Program { static void Main(string[] args) { var obj = new MyClass(); Console.WriteLin ...
前言
上一篇文章主要介紹了IL的概念以及基礎的示例代碼,在這一篇文章中我們將通過對象調用看IL。
創建對象與調用方法
class Program
{
static void Main(string[] args)
{
var obj = new MyClass();
Console.WriteLine(obj.Say());
}
}
class MyClass
{
private const string Str = "Hello";
public string Say()
{
return Str;
}
}
實例欄位每次創建類型實例的時候都會進行創建,它們屬於這個類型的實例,而靜態欄位由類型的所有實例共用,並且它會在類型載入時創建。某些靜態欄位(文本欄位和映射欄位)從不分配。載入程式只需要記錄要映射的欄位的位置,併在欄位定址時定址這些位置。高級別的編譯器(IL assembler不執行此操作,將其會留給我們開發人員)把實例欄位和三種靜態欄位中的兩種靜態欄位(非文本靜態欄位)的類型,很容易從欄位標記中識別出引用欄位的類型。
當在IL中找到標記時,JIT編譯器不必深入元數據檢索並檢查欄位的標誌。此時所有IL有兩組用於欄位載入和存儲指令。實例欄位的指令為ldfld,ldflda和stfld;靜態欄位的指令是ldsfld,ldsflda和stsfld。嘗試將靜態欄位指令與stance欄位一起使用會導致JIT編譯失敗。逆向組合是可行的,但是它需要將實例指針載入到堆棧上,這當然對於靜態欄位是完全多餘的。對靜態欄位使用實例欄位指令的好處是,它允許以相同的方式訪問靜態欄位和實例欄位。
Callvirt 對象調用後期綁定方法,並且將返回值推送到計算堆棧上。
.field private static literal string Str = "Hello" //靜態公共欄位的定義
.method private hidebysig static void
Main(
string[] args
) cil managed
{
.entrypoint //主函數,程式的入口
.maxstack 1 //棧的最大深度
.locals init (
[0] class ConsoleApp1.MyClass obj //本地變數的定義
)
// [8 9 - 8 10]
IL_0000: nop //什麼都不做
// [9 13 - 9 37]
IL_0001: newobj instance void ConsoleApp1.MyClass::.ctor() //新建類型為MyClass的對象,並將對象放到堆棧
IL_0006: stloc.0 //把計算堆棧頂部的值(obj)放到調用堆棧索引0處
// [10 13 - 10 42]
IL_0007: ldloc.0 //把調用堆棧索引為0處的值複製到計算堆棧
IL_0008: callvirt instance string ConsoleApp1.MyClass::Say() //調用MyClass.Say方法
IL_000d: call void [System.Console]System.Console::WriteLine(string) //調用WriteLine
IL_0012: nop //什麼都不做
// [11 9 - 11 10]
IL_0013: ret //return
} // end of method Program::Main
.method public hidebysig specialname rtspecialname instance void
.ctor() cil managed
{
.maxstack 8 //棧的最大深度
IL_0000: ldarg.0 //將索引為 0 的參數(this)載入到計算堆棧上。
IL_0001: call instance void [System.Runtime]System.Object::.ctor() //從堆棧中取出對象,並調用基類(Object)的構造函數
IL_0006: nop //什麼都不做
IL_0007: ret //return
} // end of method Program::.ctor
class Program
{
static void Main(string[] args)
{
MyClass obj = new MyClass();
obj.Name = "Hello";
obj.Say();
}
}
public class MyClass
{
public string Name { get; set; }
public void Say()
{
Console.WriteLine(Name);
}
}
.class public auto ansi beforefieldinit
ConsoleApp1.MyClass
extends [System.Runtime]System.Object
{
.field private string '<Name>k__BackingField' //自動生成的欄位
//自動生成獲取屬性值的方法,帶有兩個屬性
.custom instance void [System.Runtime]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor()
= (01 00 00 00 )
.custom instance void [System.Diagnostics.Debug]System.Diagnostics.DebuggerBrowsableAttribute::.ctor(valuetype [System.Diagnostics.Debug]System.Diagnostics.DebuggerBrowsableState)
= (01 00 00 00 00 00 00 00 ) // ........
// int32(0) // 0x00000000
.method public hidebysig specialname instance string
get_Name() cil managed
{
.custom instance void [System.Runtime]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor()
= (01 00 00 00 )
.maxstack 8 //棧的最大深度
// [17 30 - 17 34]
IL_0000: ldarg.0 //將索引為 0 的參數(this)載入到計算堆棧上。
IL_0001: ldfld string ConsoleApp1.MyClass::'<Name>k__BackingField' //從堆棧取出對象,訪問對象的指定欄位,並把欄位值存入堆棧
IL_0006: ret //return
} // end of method MyClass::get_Name
.method public hidebysig specialname instance void
set_Name(
string 'value'
) cil managed
{
.custom instance void [System.Runtime]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor()
= (01 00 00 00 )
.maxstack 8 //棧的最大深度
// [17 35 - 17 39]
IL_0000: ldarg.0 //將第一個參數(this)載入到計算堆棧上。
IL_0001: ldarg.1 //將第二個參數載入到計算堆棧上。
IL_0002: stfld string ConsoleApp1.MyClass::'<Name>k__BackingField'
IL_0007: ret //return
} // end of method MyClass::set_Name
.method public hidebysig instance void
Say() cil managed
{
.maxstack 8 //棧的最大深度
// [20 9 - 20 10]
IL_0000: nop //什麼都不做
// [21 13 - 21 37]
IL_0001: ldarg.0 //將第一個參數(this)載入到計算堆棧上。
IL_0002: call instance string ConsoleApp1.MyClass::get_Name()
IL_0007: call void [System.Console]System.Console::WriteLine(string)
IL_000c: nop //什麼都不做
// [22 9 - 22 10]
IL_000d: ret
} // end of method MyClass::Say
.method public hidebysig specialname rtspecialname instance void
.ctor() cil managed
{
.maxstack 8
IL_0000: ldarg.0 // this
IL_0001: call instance void [System.Runtime]System.Object::.ctor()
IL_0006: nop //什麼都不做
IL_0007: ret //return
} // end of method MyClass::.ctor
.property instance string Name()
{
.get instance string ConsoleApp1.MyClass::get_Name() //標識getter
.set instance void ConsoleApp1.MyClass::set_Name(string) //標識setter
} // end of property MyClass::Name
} // end of class ConsoleApp1.MyClass
.method private hidebysig static void
Main(
string[] args
) cil managed
{
.entrypoint //主函數,程式的入口
.maxstack 2
.locals init (
[0] class ConsoleApp1.MyClass obj
) //本地變數定義
// [8 9 - 8 10]
IL_0000: nop //什麼都不做
// [9 13 - 9 41]
IL_0001: newobj instance void ConsoleApp1.MyClass::.ctor() //新建類型為MyClass的對象,並將對象放到堆棧
IL_0006: stloc.0 //把計算堆棧頂部的值(obj)放到調用堆棧索引0處
// [10 13 - 10 32]
IL_0007: ldloc.0 //把調用堆棧索引為0處的值複製到計算堆棧
IL_0008: ldstr "Hello" //將字元串"Hello"存入到堆棧
IL_000d: callvirt instance void ConsoleApp1.MyClass::set_Name(string) //從堆棧取出對象與參數,並調用對象的指定方法
IL_0012: nop
// [11 13 - 11 23]
IL_0013: ldloc.0 //把調用堆棧索引為0處的值複製到計算堆棧
IL_0014: callvirt instance void ConsoleApp1.MyClass::Say() //調用MyClass.Say方法
IL_0019: nop //什麼都不做
// [12 9 - 12 10]
IL_001a: ret //return
} // end of method Program::Main