2011-03-21 55 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放在那里的值。

都没有真正被传递,它只是推入与弹出,关闭和堆栈。