lua源碼:開始


文件根據實現功能的不同,可以分為四部分:

 

1虛擬機運轉的核心功能

lapi.c            C語言接口
lctype.c        C標准庫中ctype相關實現
ldebug.c      Debug接口
ldo.c            函數調用以及棧管理
lfunc.c         函數原型及閉包管理
lgc.c            垃圾回收
lmem.c        內存管理接口
lobject.c      對象操作的一些函數
lopcodes.c  虛擬機的字節碼定義
lstate.c        全局狀態機
lstring.c       字符串池
ltable.c        表類型的相關操作
ltm.c            元方法
lvm.c            虛擬機

lzio.c            輸入流接口

 

2源代碼解析以及預編譯字節碼

lcode.c         代碼生成器
ldump.c       序列化預編譯的 lua 字節碼
llex.c            詞法分析器
lparser.c       解析器

lundump.c   還原預編譯的字節碼

 

3內嵌庫

lauxlib.c        庫編寫用到的輔助函數庫
lbaselib.c      基礎庫
lbitlib.c         位操作庫
lcorolib.c      協程庫
ldblib.c         Debug庫
linit.c            內嵌庫的初始化
liolib.c          IO庫
lmathlib.c     數學庫
loadlib.c       動態擴展庫管理
loslib.c         OS庫
lstrlib.c         字符串庫
ltablib.c        表處理庫 

4可執行的解析器,字節碼編譯器

lua.c              解釋器
luac.c            字節碼編譯器
lua核心部分僅包括lua虛擬機的運轉。lua虛擬機的外在數據形式是一個lua_State結構體,取名State大概

意為lua虛擬機的當前狀態。

 

閱讀源代碼的次序(從外到內)

首先、閱讀外圍的庫是如何實現功能擴展的,這樣可以熟悉Lua公開API。不必陷入功能細節。
然后、閱讀API的具體實現。

Lua對外暴露的API可以說是一個對內部模塊的一層封裝,這個層次尚未觸及核心,但可以對核心代碼有個初步的了解。
之后、可以開始了解LuaVM的實現。
接下來就是分別理解函數調用、返回,string 、table 、metatable 等
如何實現。
debug 模塊是一個額外的設施,但可以幫助你理解 Lua 內部細節。
最后是 parser 等等編譯相關的部分。

垃圾收集將是最難的部分,可能會花掉最多的時間去理解細節。

 

Lua的C函數以堆棧的形式和Lua虛擬機交換數據,由一系列API從L中取出值,經過一番處理,壓回L中的堆棧。

Lua棧給C函數留的默認空間很小,默認情況下只有20。當你要在Lua的棧上留下大量值時,務必用luaL_checkstack擴展堆棧。因為處於性能考慮,Lua和棧有關的API都是不檢查棧溢出的情況的。

在實現上,UserData只是對象結構從TString換成了Udate

 

Lua使用table作為統一的數據結構。 用 table來表示Lua中的一切數據結構是Lua語言的一大特色。 為了效率,Lua的官方實現,又把table的儲存分為數組部分和哈希表部分。 

Table按照Lua語言的定義,需要實現四種基本操作:讀、寫、迭代和獲取長度。Lua中並沒有刪除操作,而僅僅是把對應鍵位的值設置為nil

Table的數組部分操作和C語言數組沒有什么不同,不需要特別處理。 

Lua實現復雜數據結構,大量依賴給table附加一個元表(metatable)來實現。

 

你可以很容易的創建出一個Lua虛擬機對象,不同的Lua虛擬機之間的工作是線程安全的,因為一切和虛擬機相關的內存操作都被關聯到虛擬機對象中,而沒有利用任何其它共享變量。 

Lua的虛擬機核心部分,沒有任何的系統調用,是一個純粹的黑盒子,正確的使用Lua,不會對系統造成任何干擾。這其中最關鍵的一點是,Lua讓用戶自行定義內存管理器,在創建Lua虛擬機時傳入,這保證了Lua的整個運行狀態是用戶可控的。

從Lua的使用者的角度看,global_state 是不可見的。我們無法用公開的API取到它的指針,也不需要引用它。global_State里面有對主線程的引用,有注冊表管理所有全局數據,有全局字符串表,有內存管理函數,有GC需要的把所有對象串聯起來的相關信息,以及一切Lua在工作時需要的工作內存。 通過lua_newstate創建一個新的lua虛擬機時,第一塊申請的內存將用來保存主線程和這個全局狀態機。 Lua的實現盡可能的避免內存碎片,同時也減少內存分配和釋放的次數。它采用了一個小技巧,利用一個LG結構,把主線程 lua_State 和 global_state 分配在一起。 

Lua中的數據可以這樣分為兩類:值類型和引用類型。值類型可以被任意復制,而引用類型共享一份數據,由GC負責維護生命期。Lua使用一個聯合 union value來保存數據。 

Lua的程序運行是以線程為單位的。每個Lua線程可以獨立運行直到自行中斷,把中斷的信息留在狀態機中。每條線程的執行互不干擾,可以獨立延續之前中斷的執行過程。Lua的線程和系統線程無關,所以不會為每條Lua線程創建獨立的系統堆棧,而是利用自己維護的線程棧,內存開銷也就遠小於系統線程。 

lua是用longjmp處理與c互相函數調用的問題。

 

如果說C++式的面向對象編程是把一組函數綁定到特定數據類型上的話,那么閉包可以說是把一組數據綁定到特定函數上。 閉包是函數和upvalue的結合體。



Lua中的函數調用有兩種,一種是標准的函數調用,它會需要生成新的一層調用棧,執行函數流程,然后彈出調用棧返回。另一種叫做尾調用,它是對標准函數調用的優化。尾調用不生成新的調用棧,而不復用當前的。在大多數函數式編程語言中,都需要對尾調用做特別優化。因為函數式語言特別依賴函數的層層調用,甚至用尾調用的方式來做循環。傳統方式每次函數調用都需要生成新的棧幀,容易造成棧溢出。 尾調用可以看作C中的goto。

參考:

《lua源碼賞析》

如何學習 Lua VM 的源碼?https://www.zhihu.com/question/20617406

《 Structure and Interpretation of Computer Programs 》

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM