2011-03-21 54 views
3

我想學習CIL代碼,但不能去除和如何返回一個函數的值作爲參數傳遞給另一個函數。對於下面的函數參數如何在CIL函數調用中傳遞?

我已經生成的CIL代碼:

public bool TestWebPage() 
    { 
    WebRequest request = WebRequest.Create("http://www.costco.com"); 
    request.Proxy.Credentials = CredentialCache.DefaultCredentials; 
    } 

CIL代碼:

//000021:  public void TestWebPage() 
//000022:  { 
    IL_0000: /* 00 |     */ nop 
    .line 23,23 : 7,71 '' 
//000023:  WebRequest request = WebRequest.Create("http://www.costco.com"); 
IL_0001: /* 72 | (70)000001  */ ldstr  "http://www.costco.com" /* 70000001 */ 
    IL_0006: /* 28 | (0A)000012  */ call  class [System/*23000003*/]System.Net.WebRequest/*01000016*/ [System/*23000003*/]System.Net.WebRequest/*01000016*/::Create(string) /* 0A000012 */ 
    IL_000b: /* 0A |     */ stloc.0 
.line 24,24 : 7,70 '' 
//000024:  request.Proxy.Credentials = CredentialCache.DefaultCredentials; 
IL_000c: /* 06 |     */ ldloc.0 
IL_000d: /* 6F | (0A)000013  */ callvirt instance class [System/*23000003*/]System.Net.IWebProxy/*01000017*/ [System/*23000003*/]System.Net.WebRequest/*01000016*/::get_Proxy() /* 0A000013 */ 
IL_0012: /* 28 | (0A)000014  */ call  class [System/*23000003*/]System.Net.ICredentials/*01000019*/ [System/*23000003*/]System.Net.CredentialCache/*01000018*/::get_DefaultCredentials() /* 0A000014 */ 
IL_0017: /* 6F | (0A)000015  */ callvirt instance void [System/*23000003*/]System.Net.IWebProxy/*01000017*/::set_Credentials(class [System/*23000003*/]System.Net.ICredentials/*01000019*/) /* 0A000015 */ 
IL_001c: /* 00 |     */ nop 
.line 25,25 : 7,73 '' 

具體來說,我無法理解在CIL代碼以下的事情:

  1. CLR運行時如何知道set_Credentials要傳遞從get_Defa返回的值ultCredentials,因爲除了註釋部分「/ /」之外似乎沒有任何鏈接。

  2. CLR如何在System.Net.WebRequest的當前實例上調用get_Proxy,即在CIL代碼中是否存在指向實例編號的指針?

回答

1
  1. call指令上IL_0012推動get_DefaultCredentials的返回值壓入堆棧和下一行的set_Credentials方法參數傳遞的值到計算堆棧。
  2. WebRequest.Create方法返回的request變量被存儲爲索引0(stloc.0)的局部變量,然後通過ldloc.0所以get_Proxy方法裝上線IL_000d被稱爲其上已經裝載到評價此局部變量變量疊加。
2

通常,它們被傳遞到堆棧 - 但請注意,這在很大程度上是一個實現細節; p

1:疊層被建立起來,使得目標是在堆棧上第一=具體:

  • ldloc.0負載請求到堆棧
  • callvirt get_Proxy()消耗請求(因爲虛擬)和離開堆疊上的代理(從返回值)
  • call get_DefaultCredentials()不消耗任何東西,並追加默認憑據
  • callvirt set_Credentials消耗2個值;第一個(代理)被用作實例(因爲虛擬);第二(憑證)被用作所述第一參數值

2:在這種情況下,實例在「本地」保持在方法(即保留相對於堆棧幀中的時隙);在這種情況下,loc 0.在發佈版本中,我實際上期望刪除loc 0,並且這一切都是在沒有預留插槽的情況下處理的; 「dup」(根據需要複製引用)最有可能被使用,而不是stloc/ldloc。

0

它都是基於堆棧的。會發生什麼情況是將調用返回值get_DefaultCredentials的方法的結果推送到評估堆棧。

沒有什麼神奇的鏈接,該值恰好駐留在堆棧的頂部。

試想一下,在構造函數調用,這種情況發生的第一件事就是該字符串"http://www.costco.com"是在頂部的評價壓入堆棧。然後調用構造函數。構造函數然後彈出評估堆棧的值。推到棧頂的最後一個值是最後一個參數。 ldstr只在堆棧頂部推送一個值。構造函數調用的結果也就是現在的頂部,然後將該參考被彈出並存儲在位置0 stloc.0(局部變量)。

調用實例的方法略有不同,在這種情況下,第一個參數始終是對象,以便你在這裏看到的第一個電話是ldloc.0。這將WebRequest對象實例推到評估堆棧的頂部。從這裏我們稱之爲get_Proxy方法,它消耗在上面的數值計算堆棧由ldloc.0放在那裏,並返回返回的對象實例。這實際上取代了評估堆棧頂部的值。然而,現在堆棧的頂端不再是ldloc.0放在那裏的值。

都沒有真正被傳遞,它只是推入與彈出,關閉和堆棧。