<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內部實現:編譯系統(2) 跳轉的處理 跳轉用來控制程序的指令流程。Lua使用OP_JMP指令來執行一個跳轉,有關OP_JMP的詳細介紹,可以參見《[虛擬機指令](http://blog.csdn.net/yuanlin2008/article/details/8504200)》。跳轉可以分為條件跳轉和非條件跳轉。非條件跳轉比較簡單,我們可以先從這里入手。 ## goto 在Lua5.2中,goto和label是新加入的statement,用來執行非條件跳轉。這兩個statement分別在lparser.c中的gotostat和labelstat函數中被解析。上一篇中講過,在全局數據Dyndata中,保存著一個goto列表和一個label列表,goto和label使用一個相同的數據結構Labeldesc表示。 ~~~ /*?description?of?pending?goto?statements?and?label?statements?*/?? typedef?struct?Labeldesc?{?? ??TString?*name;??/*?label?identifier?*/?? ??int?pc;??/*?position?in?code?*/?? ??int?line;??/*?line?where?it?appeared?*/?? ??lu_byte?nactvar;??/*?local?level?where?it?appears?in?current?block?*/?? }?Labeldesc;?? ~~~ name用來表示label的名稱,用來相互查找。如果是label,pc表示這個label對應的當前函數指令集合的位置,也就是待跳轉的指令位置;如果是goto,則代表為這個goto生成的OP_JMP指令的位置。nactvar代表解析此goto或者label時,函數有多少個有效的局部變量,用來在跳轉時決定需要關閉哪些upvalue。 gotostat接受一個已經為之生成好了的OP_JMP指令的位置,首先通過newlabelentry為這個goto在ls->dyd->gt中生成一個Labeldesc,用來表示未處理的goto,然后調用findlabel嘗試處理這個goto。findlabel會在當前的block中查找已經定義了的label。如果找到,就調用closegoto,將這個goto對應的OP_JMP指令的跳轉位置設置成label的pc,并且還要決定是否需要在OP_JMP指令中關閉一些局部變量對應的upvalue;如果沒有找到,這個goto對應的OP_JMP指令的跳轉位置就是一個NO_JUMP,表示未決位置,等待后面再處理。 與gotostat的處理類似,labelstat在處理label時,也會首先查找已經定義但未決的goto。如果找到了goto,也要修改其OP_JMP指令的跳轉位置。整個goto和label語法分析的代碼比較直接,并不難理解。而這里比較晦澀的是Lua對OP_JMP指令的處理方法。對于OP_JMP的處理還會在后面的關系和邏輯運算,以及條件跳轉中使用。所以,理解Lua對OP_JMP指令的處理是理解其他編譯部分的基礎。 ## OP_JMP 前面講過,由于Lua是一編編譯,所以在真正生成指令時,很多東西是沒法決定的。比如OP_JMP指令,要跳轉的位置可能還沒有定義,所以不能知道具體的跳轉位置。Lua會將這些指令先生成到函數proto的指令列表中,然后記錄下他們在指令列表的位置。當可以確定時,再通過這個位置找到生成好的指令,對其進行修改。這就是指令回填。 對于一個OP_JMP指令,有兩個指令參數需要回填:待關閉的upvalue起始id A和跳轉偏移量sBx。當通過luaK_jump函數生成一個OP_JMP指令時,這個指令的A會被初始化成0,而sBx被初始化成NO_JUMP,并返回一個int代表這個OP_JMP指令的位置。我們保存這個返回值就可以找到這個指令,對其進行回填。 在語法分析過程中(比如后面要講到的關系和邏輯運算),有可能會生成一系列的OP_JMP指令,他們的跳轉目標是一致的,從而形成一個跳轉指令集合。Lua使用了鏈表的方式保存這種指令集合。這個鏈表每個節點就是OP_JMP指令本身,使用sBx來指向鏈表的下一個OP_JMP指令。如果sBx為NO_JUMP,表示鏈表的尾節點。所以我們只需要一個指向頭節點的位置,就可以遍歷整個OP_JMP指令鏈表。lcode.c中對于OP_JMP指令的處理函數,都是基于一個跳轉鏈表的,只不過在一些情況下,鏈表中只有一個節點而已。如果需要回填一個具體的跳轉地址,就會遍歷鏈表,將每個節點的跳轉地址都修正到目標位置。 ![](https://box.kancloud.cn/2016-01-15_56989af29c954.png) 回填跳轉地址可以分為兩類處理: 一種是已經生成的指令位置,Lua會立即將這些跳轉指令修改成目標位置。 另一種是當前位置,也就是接下來要生成的指令的位置。在處理當前位置時,Lua并沒有立即修改,而是將待修改的跳轉指令串接到當前FuncState中的jpc鏈表上。當使用luaK_code生成下一條指令時,首先會調用dischargejpc函數,將jpc鏈表上的所有跳轉指令修改到這個位置。這等于是延遲回填。之所以這樣處理,其實是為了跳轉的優化。我們回頭看一下luaK_jump函數,它在生成OP_JMP指令時,會將當前jpc串接到新生成的jpc上,并且將jpc清空。這個處理實際的意思是,當生成一個OP_JMP指令時,如果有其他的OP_JMP指令需要跳轉到此處,其實就等于間接跳轉到新生成的跳轉指令的目標位置。所以這些跳轉指令不用再跳轉到此處,而是直接跳轉到新生成的OP_JMP的目標位置,將兩步跳轉合并成一步。這些指令與新生成跳轉指令的目標是一致的,所以可以合并成一個跳轉指令集合,等待后面一起回填。 我們接下來在來回顧一下與跳轉相關的指令生成api。 luaK_jump用來生成一個新的跳轉指令。luaK_concat函數用來將兩個鏈表連接起來合成一個鏈表。luaK_patchlist用來回填一個鏈表的跳轉位置。luaK_patchtohere用來將一個鏈表準備回填到當前位置。luaK_patchclose用來回填一個鏈表中的A,也就是需要關閉的upvalue id,具體可以查看goto的處理。 以上是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>

                              哎呀哎呀视频在线观看