lua中可以這樣賦值:
local a = 0;
local b = 1;
local c = 2;
local d,e = a, b , c;
也就是多個值給多個變數賦值。
這篇文章就是分析這個賦值的效率的。
前面寫過一篇文章,叫「
lua原始碼分析」,裡面講了lua怎麼解析定義區域性變數並生成指令的。
這篇文章內容基於那篇文章,但那篇文章更注重原始碼分析,這篇文章重點是介紹一件事情。
首先,講一些東西。不知道怎麼安排語言,隨便說了。
lua程式是執行在lua虛擬機器上的。當虛擬機器執行lua程式時,會接受乙個lua_state資料結構的物件。這個東西相當於乙個執行緒,裡面記載了lua程式所需要的所有資訊。當然,lua解析器生成的中間碼也儲存在這個lua_state物件中。具體說來, 是當通過do_file()函式或do_string()函式執行一段lua**的時候,lua會把這一整塊**當作乙個函式。對的,比如,lua要執行乙個a.lua檔案,lua會把這個檔案裡的所有**當作乙個函式來解析和執行。在解析之前,lua會呼叫open_func()來建立乙個func_state的資料結構,這個資料結構是lua解析器進行語法分析時的東西,代表乙個函式。lua建立了這個代表函式的資料結構,然後把要執行的**生成的指令儲存在這個資料結構中。
lua每解析乙個函式,都會建立乙個func_state資料結構的物件,然後將這個函式生成的指令存在這個資料結構中。這個資料結構是乙個鍊錶的形式,也就是說,每個func_state資料結構中都包含乙個陣列,這個陣列裡儲存著在這個函式裡定義的區域性函式。因為前面說了,lua會在解析之前建立乙個func_state資料結構物件,那麼,在**裡定義的區域性函式(以local開頭)都是這個函式的區域性函式,儲存在這個函式資料結構中(語言組織的實在一塌糊塗,而且還沒有表達清楚,好像還有誤,不管了)。
在lua執行期間,有乙個棧,是lua_state資料結構的乙個成員,由lua_state->base、lua_state->stack、lua_state->top組成。其中,lua_state->stack指向棧底,lua_state->top指向棧頂,lua_state->base指向當前執行函式的棧底,就像intel指令執行時,ebp指向當前指向函式的棧底。intel指令呼叫函式的時候,會首先將函式的棧底儲存在ebp中,然後移動esp在棧中開闢一段空間,用於儲存函式的區域性變數。在lua中類似,區域性變數是貯存在棧裡的。而且每個函式都有自己對應的棧空間。而且,在lua的棧中,只貯存函式的區域性變數。比如:乙個函式的棧開始處假設在base處,那麼,從base開始,lua解析這個函式的時候,沒遇到乙個由local定義的區域性變數或區域性函式,就會在棧裡對應位置將其保留,也就是,如果第乙個遇到的區域性變數是a,那麼base處儲存的就是a,lua並不會在內部指明乙個函式的每個區域性變數放在棧的哪個位置,而是通過乙個預設值,就是,如果乙個函式在棧裡的開始位置在base,那麼base+n處就對應這個函式的第n+1個區域性變數。
前面講了那麼多,也就想說明乙個問題,那就是lua中的函式的區域性變數存在棧裡。
好了,進入正題,比如我們最前面那個例子。假設這個函式開始在棧中的位置是0。那麼,區域性變數a就存在棧的0號位置,b在1號,c在2號,也就是會生成以下**(loadk是指載入乙個常量到乙個暫存器中):
1、local a = 0; ------ loadk 0 0
2、local b = 1; ------ loadk 1 1
3、local c = 2; ------ loadk 2 2
對於第4句,新建兩個區域性變數,並用3個區域性變數給其賦值,這時候,其實是用前兩個給其賦值的,第3個賦值的會被忽略掉。但是lua怎麼處理這種情況呢?
lua 會遍歷等號「=」右邊的東西,遇到乙個東西,就生成一條賦值指令,也就是,在我們的例子中,lua會生成:
4、local d , e = a , b ,c
--------- op_move 3 0(這裡因為不是用常量賦值,而是用已定義的區域性變數賦值,所以用move,把第乙個暫存器中的值賦值到第4個暫存器中,同理,如下)
--------- op_move 4 1
--------- op_move 5 2
這裡注意!問題來了!
發現這裡生成了3條指令,但是給2個變數賦值!所以多出來了一條指令!lua這時候是不管的,這條多出來的指令也會被執行!lua在這裡的處理是,這條指令是會被執行,但是,暫存器4,也就是第5個暫存器還是被當作空閒暫存器用的,也就是,lua會忽略這個賦值操作,就當沒使用過那個暫存器一樣。
其實,在解析**的時候,完全可以不生成多餘的指令,只要乙個簡單的判斷就可以了。希望lua後續的版本會增加:)。
Lua 原始碼分析 lprefix h
lua 原始碼裡面很小的乙個標頭檔案,沒什麼東西,會預先進行一些設定,每個 c 檔案都會引用.ifndef lprefix h define lprefix h posix xsi if defined lua use c89 有關移植性 if defined xopen source define...
Lua 簡單Lua直譯器原始碼分析
include include include lua.h include lauxlib.h include lualib.h int main void lua close l return 0 lua.h定義了lua提供的基礎函式,包括建立lua環境 呼叫lua函式,它的定義是以lua 開頭的...
cvDilate 原始碼分析 1
在cv.h檔案中對cvdilate的定義如下 cvapi void cvdilate const cvarr src,cvarr dst,iplconvkernel element cv default null int iterations cv default 1 iplconvkernel 指...