<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      Head First IL中間語言之 實例深入經典詮釋

      在上一篇的博文中,我以一個具有代表性的IL base instruction, ldc 指令,來介紹了IL語言中最基本的一類指令及其參數的使用方法.大家反映還不錯.
      這里,就再寫一篇博文,用一個應用程序的實例來深入的說明一番CLR環境下的IL語言的語法,基本運行機制和原理.

      首先,找一段IL語言的例子,從codeproject找了一段IL程序修改了下
      .method static void main() cil managed
      {
          .maxstack 2
          .entrypoint
          .locals init (int32, temp)
          
          newobj instance void Donis.CSharpBook.ZClass::.ctor()
          dup
          call instance int32 Donis.CSharpBook.ZClass::AddFields()
          stloc.0
          ldstr "the total is {0}"
          ldloc.0
          box int32
          call void [mscorlib] System.Console::WriteLine(string,object)
          call instance int32 Donis.CSharpBook.ZClass::SubtractFields()
          stloc.0
          ldstr "The difference is {0}"
          ldloc.0
          box int32
         call void [mscorlib] System.Console::WriteLine(string,object)
          
        }

      這段程序,深究的程度不同,值得琢磨的地方也就越多;下面,我來一點一點的分析:

      我們跳過定義和開頭,從這一句開始:
      newobj instance void Donis.CSharpBook.ZClass::.ctor()
      這里,使用了一個newobj指令.這個指令用來分配生成一個未初始化的對象或者是值類型,并且call ctor()構造函數.
      這里,有的朋友會郁悶,為什么這個指令可以分配一個value type值類型.這的確是這個指令本分的功能而且是比較特別的地方.
      ECMA標準文檔對這個指令的描述如下:(請允許我引用一段E文那,呵呵,E文不好的詞霸調出來吧):
      --------------------------Reference--------------------------------
      The newobj instruction creates a new object or a new instance of a value type. ctor is a metadata token that indicates the name, class, and signature of the constructor to call. If a constructor exactly matching the indicated name, class and signature cannot be found, MissingMethodException is thrown.

      The newobj instruction allocates a new instance of the class associated with ctor and initializes all the fields in the new instance to 0 (of the proper type) or null as appropriate. It then calls the constructor with the given arguments along with the newly created instance. After the constructor has been called, the now initialized object reference is pushed on the stack.

      From the constructor’s point of view, the uninitialized object is argument 0 and the other arguments passed to newobj follow in order.Value types are not usually created using newobj. They are usually allocated either as arguments or local variables, using newarr (for zero-based, one-dimensional arrays), or as fields of objects. Once allocated, they are initialized using initobj. However, the newobj instruction can be used to create a new instance of a value type on the stack, that can then be passed as an argument, stored in a local, etc.
      --------------------------Reference--------------------------------
      這里,大家最好務必讀一下,有助于下面的理解.
      同時,特別提醒大家注意這一句:"After the constructor has been called, the now initialized object reference is pushed on the stack."
      這一句,有助于下面大家dup指令的理解,IL編譯器的指令優化和多方法調用的理解.

      OK,接下來就是dup指令.ECMA的CLR文檔的part 3對這個指令的解釋很簡單,只有一句:Duplicate the value on the top of the stack.實際上用法也的確很簡單.
      復雜的一部分,是中間語言Complier的一些指令優化拐了一點點小彎.

      接下來,我們來說明這一句:
      call instance int32 Donis.CSharpBook.ZClass::AddFields()
      不好意思哈,又要引用一段E文:
      --------------------------Reference--------------------------------
      The call instruction calls the method indicated by the descriptor method. method is a metadata token (a methodref, methoddef, or methodspec) that indicates the method to call, and the number, type, and order of the arguments that have been placed on the stack to be passed to that method, as well as the calling convention to be used. The call instruction can be immediately preceded by a tail. prefix to specify that the current method state should be released before transferring control .
      --------------------------Reference--------------------------------
      上面說的有必要再補充下,Call方法再執行的時候,計算堆棧,注意,這里說的是計算堆棧stack,不是托管堆heap,
      從棧頂開始,首先要放入instance的referece,也就是ZClass在托管堆里面的引用,然后依次放入需要傳入到AddFields方法里面的參數.我們的例子中,不傳遞參數.

      then:
          stloc.0
          ldstr "the total is {0}"
          ldloc.0
      第一句指令,把剛才call那句執行完畢以后的一個返回的類型為int32的變量pop到local變量集合的第一個中去.然后load一個字符串,最后,把local變量里面的第一個,也就是temp變量的值stack的最上面.
      這里需要特別提醒一下的是:ldstr這句中,字符串是保存在托管堆中的.load到stack中的,只是heap的一個引用.也就是說,這里只是一個引用類型.理解這點,有助于下面指令的理解.

      接下來,該是本文中精彩的部分到了:
      這里兩條指令一起介紹:
          box int32
          call void [mscorlib] System.Console::WriteLine(string,object)
      box指令用來執行裝箱操作,他防止了指令異常的發生.它從計算堆棧中復制一個值類型實例的所有的字段,然后在托管堆上面創建一個對值類型進行裝箱的對象,并且將新建對象的引用放回到計算堆棧當中去.此時,原來的值類型就被一個引用類型代替了.unbox指令執行相反的拆箱操作.
      為什么要用box指令呢?有人可能會問道這個.
      這里,是因為下面的WriteLine方法調用了兩個引用類型的參數,所以,需要把int32類型的一個值類型轉換成為一個Object的引用類型.
      注意:這里返回類型是void,讀者們可以思考一下,此時的stack的頂部,是什么呢??

      最后是這條指令特別介紹一下:
      call instance int32 Donis.CSharpBook.ZClass::SubtractFields()
      這個指令前面已經詳細介紹過一次,這里再次討論一下.
      這里可能有人會問道,call指令需要在stack的頂部放置ZClass的reference啊,這里為什么沒有用dup或者別的指令啊.
      啊哈,這里是因為在上面的指令中,newobj將ZClass的reference放置到了stack中,dup又把這個值復制了一次從新push到了stack中,這里stack中就有兩個引用啦.
      這也涉及到IL編譯器的編譯優化問題的相關的研究,這里就不深入討論這個話題了.

      值得一提的是,我在寫這篇文章之前,看到相當多類似話題的討論中,很多人對dup指令的用法感到很困惑,怎么有的時候要用,有的時候有不用呢?怎么前面用了后面又不用呢?然后各種猜想假設就接踵而來.........
      這里,和newobj指令和call指令的使用結合起來解釋這個問題就容易了.

      恩,不羅嗦了,over吧.敲累了.后續更多精彩內容奉上 ^_^

      posted on 2007-10-19 23:28  lbq1221119  閱讀(3327)  評論(18)    收藏  舉報

      導航

      主站蜘蛛池模板: 国产a级三级三级三级| 国内精品久久人妻无码不卡| 陆川县| 思思99热精品在线| 亚洲中文字幕日产无码成人片| 日本大片在线看黄a∨免费| 中文字幕av一区二区| 亚洲精品二区在线播放| 精品国产亚洲区久久露脸| 漂亮的保姆hd完整版免费韩国| 97精品亚成在人线免视频| 青青青国产在线观看免费| 天天做天天爱夜夜夜爽毛片| 成人无码潮喷在线观看| 桃花岛亚洲成在人线AV| 无码激情亚洲一区| 忻州市| 亚洲乱码国产乱码精品精| 色偷偷偷久久伊人大杳蕉| 国产精品伦人视频免费看| 国产精品无码素人福利不卡| 国产成人高清在线重口视频| 欧美亚洲另类 丝袜综合网| 思思久99久女女精品| 国产欧美日韩亚洲一区二区三区| 亚洲精品一区二区制服| 国产免费一区二区不卡| 深田えいみ禁欲后被隔壁人妻| 视频一区二区三区四区不卡| 国产精品久久国产三级国不卡顿 | 加勒比无码人妻东京热| 不卡乱辈伦在线看中文字幕| 国产成人啪精品午夜网站| 亚洲色拍拍噜噜噜最新网站| 欧洲精品一区二区三区久久| 国产jjizz女人多水喷水| 伊人春色激情综合激情网| 99久久伊人精品综合观看| 狠狠综合久久av一区二| 2018av天堂在线视频精品观看| 国产太嫩了在线观看|