<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ThinkChat2.0新版上線,更智能更精彩,支持會話、畫圖、視頻、閱讀、搜索等,送10W Token,即刻開啟你的AI之旅 廣告
                # 探索Lua5.2內部實現:虛擬機指令(1) 概述 Lua一直把虛擬機執行代碼的效率作為一個非常重要的設計目標。而采用什么樣的指令系統的對于虛擬機的執行效率來說至關重要。 ## Stack based vs Register based VM 根據指令獲取操作數方式的不同,我們可以把虛擬機的實現分為stack based和register based。 ### Stack based vm 對于大多數的虛擬機,比如JVM,Python,都采用傳統的stack based vm。 Stack based vm的指令一般都是在當前stack中獲取和保存操作數的。比如一個簡單的加法賦值運算:a=b+c,對于stack based vm,一般會被轉化成如下的指令: ~~~ push?b;?//?將變量b的值壓入stack?? push?c;?//?將變量c的值壓入stack?? add;????//?將stack頂部的兩個值彈出后相加,將結果壓入stack?? mov?a;??//?將stack頂部結果放到a中?? ~~~ 由于Stack based vm的指令都是基于當前stack來查找操作數的,這就相當于所有操作數的存儲位置都是運行期決定的,在編譯器的代碼生成階段不需要額外為在哪里存儲操作數費心,所以stack based的編譯器實現起來相對比較簡單直接。也正因為這個原因,每條指令占用的存儲空間也比較小。 但是,對于一個簡單的運算,stack based vm會使用過多的指令組合來完成,這樣就增加了整體指令集合的長度。vm會使用同樣多的迭代次數來執行這些指令,這對于效率來說會有很大的影響。并且,由于操作數都要放到stack上面,使得移動這些操作數的內存復制大大增加,這也會影響到效率。 ### Register based vm Lua 采用的是register based vm。 Register based vm的指令都是在已經分配好的寄存器中存取操作數。對于上面的運算,register based vm一般會使用如下的指令: ` add?a?b?c;?//?將b與c對應的寄存器的值相加,將結果保存在a對應的寄存器中??` Register based vm的指令可以直接對應標準的3地址指令,用一條指令完成了上面多條指令的計算工作,并且有效地減少了內存復制操作。這樣的指令系統對于效率有很大的幫助。 不過,在編譯器設計上,就要在代碼生成階段對寄存器進行分配,增加了實現的復雜度。并且每條指令所占用的存儲空間也相應的增加了。 ## Lua虛擬機指令簡介 Lua的指令使用一個32bit的unsigned integer表示。所有指令的定義都在lopcodes.h文件中,使用一個enum OpCode代表指令類型。在lua5.2中,總共有40種指令(id從0到39)。根據指令參數的不同,可以將所有指令分為4類: ![](https://box.kancloud.cn/2016-01-15_56989af23409e.png) 除了sBx之外,所有的指令參數都是unsigned integer類型。sBx可以表示負數,但表示方法比較特殊。sBx的18bit可表示的最大整數為262143,這個數的一半131071用來表示0,所以-1可以表示為-1+131071,也就是131070,而+1可以表示為+1+131071,也就是131072。 ABC一般用來存放指令操作數據的地址,而地址可以分成3種: * 寄存器id * 常量表id * upvalue id Lua使用當前函數的stack作為寄存器使用,寄存器id從0開始。當前函數的stack與寄存器數組是相同的概念。stack(n)其實就是register(n)。 每一個函數prototype都有一個屬于本函數的常量表,用于存放編譯過程中函數所用到的常量。常量表可以存放nil,boolean,number和string類型的數據,id從1開始。 每一個函數prototype中都有一個upvalue描述表,用于存放在編譯過程中確定的本函數所使用的upvalue的描述。在運行期,通過OP_CLOSURE指令創建一個closure時,會根據prototype中的描述,為這個closure初始化upvalue表。upvalue本身不需要使用名稱,而是通過id進行訪問。 A被大多數指令用來指定計算結果的目標寄存器地址。很多指令使用B或C同時存放寄存器地址和常量地址,并通過最左面的一個bit來區分。在指令生成階段,如果B或C需要引用的常量地址超出了表示范圍,則首先會生成指令將常量裝載到臨時寄存器,然后再將B或C改為使用該寄存器地址。 在lopcodes.h中,對于每個指令,在源碼注釋中都有簡單的操作描述。本文接下來將針對每一個指令做更詳細的描述,并給出關于這個指令的示例代碼。示例代碼可以幫助我們構建出一個指令使用的具體上下文,有助于進一步理解指令的作用。對指令上下文的理解還可以作為進一步研究lua的編譯和代碼生成系統的基礎。 在分析過程中,我們使用luac來顯示示例代碼所生成的指令。luac的具體使用方式為: ` luac?-l?-l?test.lua??`
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看