lua 源代码解析
lua 源代碼解析?
源代碼版本:lua-5.2.0?
一、概覽?
1、lua腳本中暴露的庫相關?
lbaselib.c - 基礎函數庫(方便使用lua內部的功能)?
lbitlib.c - 位運算庫?
lcorolib.c - 協程庫?
lstrlib.c - 字符串庫,提供通用字符串處理功能?
? lstring.c - 字符串表(保存所有由Lua操作的字符串集合)?
lmathlib.c - 數學庫?
loslib.c - 操作系統相關庫,時間、環境、語言、執行程序等?
liolib.c - 輸入輸出庫?
loadlib.c - 模塊庫(實現require函數,package函數)?
ldblib.c - 調試庫?
? ldebug.c - 調試接口:包含訪問調試鉤子的函數(lua_sethook/lua_gethook/lua_gethookcount),訪問運行時堆棧信息的函數(lua_getstatck/lua_getlocal/lua_setlocal),檢查字節碼函數(luaG_checkopenop/luaG_checkcode),和拋出錯誤的函數(luaG_typeerror/luaG_concaterror/luaG_aritherror/luaG_ordererror/luaG_errormsg/luaG_runerror)?
lapi.c - Lua的API.實現Lua C API(lua_*函數)集合?
lauxlib.c - 定義所有的luaL_*函數集?
2、lua runtime的數據結構相關?
lfunc.c - 包裝原型和閉包的輔助函數?
ltable.c - Lua表實現(哈希)?
lobject.c - 一些針對Lua對象的通用函數。包括數據類型到字符串轉換函數,純數據相等測試函數(luaO_rawequalObj),和日志基礎2(luaO_log2)?
ltm.c - 標記原語方法。實現對象訪問原語方法(metathods)?
3、編譯前端?
llex.c - 詞法分析器,被lparser.c使用,接口LUAI_FUNC void luaX_next (LexState *ls);?
lparser.c - Lua語法檢查器,接口 Proto *luaY_parser (lua_State *L, ZIO *z, Mbuffer *buff, Dyndata *dyd, const char *name, int firstchar);?
lundump.c - 加載預編譯后的Lua代碼塊,函數luaU_undump,加載一個預編譯后的代碼塊;luaU_header(被luaU_undump使用的內部函數),用來檢查函數頭部。?
ldump.c - 保存預編譯后的Lua代碼塊。函數luaU_dump,使用預編譯后的代碼字符串展示一個函數;?
lcode.c - Lua的代碼生成器。被lparser.c使用,static int luaK_code (FuncState *fs, Instruction i) 用于寫入一條指令?
? 順序:lex--parse--code--dump?
4、虛擬機、運行時相關?
lopcodes.c - Lua虛擬機的操作碼。定義所有操作符的名稱和信息(使用luaP_opnames和luaP_opmodes兩個表保存)?
lvm.c - Lua虛擬機。執行字節碼(luaV_execute)。也暴漏一些lapi.c可能用到的函數(例如:luaV_concat)?
ldo.c - Lua的棧和調用結構。控制函數調用(luaD_call/luaD_pcall),棧增長,協同代碼的同步?
lstate.c - 全局上下文信息即 符號表(函數表、變量表、線程等). 包括打開和關閉LUA上線文的函數(lua_newstate/lua_close)和lua線程函數(luaE_newthread/luaE_freethread)?
lmem.c - 內存管理的接口.通過封裝內存分配函數,實現了luaM_realloc / luaM_growaux_兩個函數.?
lgc.c -? 垃圾回收器(內存管理)?
5、外部封裝?
lua.c - Lua獨立解釋器?
luac.c - Lua編譯器(保存字節碼到一個文件,也可以列出字節碼)?
6、其他?
lzio.c -? 一個通用的帶緩沖區的輸入流接口?
linit.c - 實現luaL_openlibs方法,便于在C語言中加載上述模塊?
lctype.c 判斷類型?
二、主流程?
第一階段:main---load----詞法、語法解析、parser內會生成需要的指令集?
第二階段:docall----虛擬機內的luaV_execute?
三、runtime的實現?
? 1、vc中的一個典型調用棧信息如下:?
> lua1.exe!luaV_execute(lua_State * L=0x00035c28)? Line 521 C?
lua1.exe!luaD_call(lua_State * L=0x00035c28, lua_TValue * func=0x00035e00, int nResults=-1, int allowyield=0)? Line 393 + 0x9 bytes C?
lua1.exe!f_call(lua_State * L=0x00035c28, void * ud=0x0013f4a0)? Line 920 + 0x18 bytes C?
lua1.exe!luaD_rawrunprotected(lua_State * L=0x00035c28, void (lua_State *, void *)* f=0x00424a60, void * ud=0x0013f4a0)? Line 133 + 0x1f bytes C?
lua1.exe!luaD_pcall(lua_State * L=0x00035c28, void (lua_State *, void *)* func=0x00424a60, void * u=0x0013f4a0, int old_top=40, int ef=32)? Line 591 + 0x11 bytes C?
lua1.exe!lua_pcallk(lua_State * L=0x00035c28, int nargs=0, int nresults=-1, int errfunc=3, int ctx=0, int (lua_State *)* k=0x00000000)? Line 946 + 0x20 bytes C?
lua1.exe!docall(lua_State * L=0x00035c28, int narg=0, int nres=-1)? Line 179 + 0x19 bytes C?
lua1.exe!handle_script(lua_State * L=0x00035c28, char * * argv=0x00035ba0, int n=1)? Line 341 + 0xf bytes C?
lua1.exe!pmain(lua_State * L=0x00035c28)? Line 469 + 0x17 bytes C?
lua1.exe!luaD_precall(lua_State * L=0x00035c28, lua_TValue * func=0x00035de0, int nresults=1)? Line 317 + 0x9 bytes C?
lua1.exe!luaD_call(lua_State * L=0x00035c28, lua_TValue * func=0x00035de0, int nResults=1, int allowyield=0)? Line 392 + 0x11 bytes C?
lua1.exe!f_call(lua_State * L=0x00035c28, void * ud=0x0013fe48)? Line 920 + 0x18 bytes C?
lua1.exe!luaD_rawrunprotected(lua_State * L=0x00035c28, void (lua_State *, void *)* f=0x00424a60, void * ud=0x0013fe48)? Line 133 + 0x1f bytes C?
lua1.exe!luaD_pcall(lua_State * L=0x00035c28, void (lua_State *, void *)* func=0x00424a60, void * u=0x0013fe48, int old_top=8, int ef=0)? Line 591 + 0x11 bytes C?
lua1.exe!lua_pcallk(lua_State * L=0x00035c28, int nargs=2, int nresults=1, int errfunc=0, int ctx=0, int (lua_State *)* k=0x00000000)? Line 946 + 0x20 bytes C?
lua1.exe!main(int argc=2, char * * argv=0x00035ba0)? Line 495 + 0x13 bytes C?
? 2、基本交互邏輯?
? vm循環取出一個一個的Instruction,之后一個巨大的switch來解釋這個Instruction(lua 5.2是基于寄存器的指令集),即經典的fetch---execute循環。?
特殊的指令:?
1》函數調用指令:遇到函數調用時(lua中調用),要用c代碼模擬出硬件執行代碼時的棧結構。?
基本上每次增加一個活動記錄時要設置好相應的閉包信息和執行環境,設置好相應的符號表,做好參數的檢查,必要時GC一下?
2》協程指令?? :每次有create調用時就新建一個lua_state,全局棧維護這些stack信息?
? resume時 luaB_coresume---auxresume---lua_resume---luaB_yield?
?? lua1.exe!lua_yieldk(lua_State * L=0x0003e698, int nresults=1, int ctx=0, int (lua_State *)* k=0x00000000)? Line 556 C?
lua1.exe!luaB_yield(lua_State * L=0x0003e698)? Line 99 + 0x1a bytes C?
lua1.exe!luaD_precall(lua_State * L=0x0003e698, lua_TValue * func=0x0003f3f8, int nresults=-1)? Line 317 + 0x9 bytes C?
lua1.exe!luaV_execute(lua_State * L=0x0003e698)? Line 744 + 0x34 bytes C?
lua1.exe!resume(lua_State * L=0x0003e698, void * ud=0x0003f3d8)? Line 496 + 0x9 bytes C?
lua1.exe!luaD_rawrunprotected(lua_State * L=0x0003e698, void (lua_State *, void *)* f=0x004348d0, void * ud=0x0003f3d8)? Line 133 + 0x1f bytes C?
lua1.exe!lua_resume(lua_State * L=0x0003e698, lua_State * from=0x00035c28, int nargs=2)? Line 531 + 0x1d bytes C?
> lua1.exe!auxresume(lua_State * L=0x00035c28, lua_State * co=0x0003e698, int narg=2)? Line 31 + 0x11 bytes C?
lua1.exe!luaB_coresume(lua_State * L=0x00035c28)? Line 53 + 0x1d bytes C?
四、解釋器?
1、main函數?
line484: lua.c?
lua_newstate:全局和線程棧狀態的初始化?
lua_State *L = luaL_newstate();? // 創建全局的運行時信息?
lua_pushcfunction(L, &pmain);??? // 創建當前棧頂的函數閉包?
lua_pushinteger(L, argc);? // 參數入棧?
lua_pushlightuserdata(L, argv); /* 2nd argument */?
status = lua_pcall(L, 2, 1, 0); // 運行時執行一個lua函數?
result = lua_toboolean(L, -1);? /* get result */?
finalreport(L, status);?
lua_close(L);?????????????? // 釋放內存等掃尾工作?
2、lua_pcall詳情?
1》參數檢查?
2》luaD_pcall --------luaD_rawrunprotected---f_call----luaD_call---luaD_precall---pmain?
luaL_checkversion(L); // 驗證虛擬機?
lua_gc(L, LUA_GCSTOP, 0);? /* stop collector during initialization */?
luaL_openlibs(L);???? // 初始化內置庫 loadedlibs是默認打開的功能表?
lua_gc(L, LUA_GCRESTART, 0);?
handle_script -------執行主腳本?
luaL_loadfile------docall(一堆的棧操作)----luaV_execute:lvm.c // 虛擬機的執行引擎
源代碼版本:lua-5.2.0?
一、概覽?
1、lua腳本中暴露的庫相關?
lbaselib.c - 基礎函數庫(方便使用lua內部的功能)?
lbitlib.c - 位運算庫?
lcorolib.c - 協程庫?
lstrlib.c - 字符串庫,提供通用字符串處理功能?
? lstring.c - 字符串表(保存所有由Lua操作的字符串集合)?
lmathlib.c - 數學庫?
loslib.c - 操作系統相關庫,時間、環境、語言、執行程序等?
liolib.c - 輸入輸出庫?
loadlib.c - 模塊庫(實現require函數,package函數)?
ldblib.c - 調試庫?
? ldebug.c - 調試接口:包含訪問調試鉤子的函數(lua_sethook/lua_gethook/lua_gethookcount),訪問運行時堆棧信息的函數(lua_getstatck/lua_getlocal/lua_setlocal),檢查字節碼函數(luaG_checkopenop/luaG_checkcode),和拋出錯誤的函數(luaG_typeerror/luaG_concaterror/luaG_aritherror/luaG_ordererror/luaG_errormsg/luaG_runerror)?
lapi.c - Lua的API.實現Lua C API(lua_*函數)集合?
lauxlib.c - 定義所有的luaL_*函數集?
2、lua runtime的數據結構相關?
lfunc.c - 包裝原型和閉包的輔助函數?
ltable.c - Lua表實現(哈希)?
lobject.c - 一些針對Lua對象的通用函數。包括數據類型到字符串轉換函數,純數據相等測試函數(luaO_rawequalObj),和日志基礎2(luaO_log2)?
ltm.c - 標記原語方法。實現對象訪問原語方法(metathods)?
3、編譯前端?
llex.c - 詞法分析器,被lparser.c使用,接口LUAI_FUNC void luaX_next (LexState *ls);?
lparser.c - Lua語法檢查器,接口 Proto *luaY_parser (lua_State *L, ZIO *z, Mbuffer *buff, Dyndata *dyd, const char *name, int firstchar);?
lundump.c - 加載預編譯后的Lua代碼塊,函數luaU_undump,加載一個預編譯后的代碼塊;luaU_header(被luaU_undump使用的內部函數),用來檢查函數頭部。?
ldump.c - 保存預編譯后的Lua代碼塊。函數luaU_dump,使用預編譯后的代碼字符串展示一個函數;?
lcode.c - Lua的代碼生成器。被lparser.c使用,static int luaK_code (FuncState *fs, Instruction i) 用于寫入一條指令?
? 順序:lex--parse--code--dump?
4、虛擬機、運行時相關?
lopcodes.c - Lua虛擬機的操作碼。定義所有操作符的名稱和信息(使用luaP_opnames和luaP_opmodes兩個表保存)?
lvm.c - Lua虛擬機。執行字節碼(luaV_execute)。也暴漏一些lapi.c可能用到的函數(例如:luaV_concat)?
ldo.c - Lua的棧和調用結構。控制函數調用(luaD_call/luaD_pcall),棧增長,協同代碼的同步?
lstate.c - 全局上下文信息即 符號表(函數表、變量表、線程等). 包括打開和關閉LUA上線文的函數(lua_newstate/lua_close)和lua線程函數(luaE_newthread/luaE_freethread)?
lmem.c - 內存管理的接口.通過封裝內存分配函數,實現了luaM_realloc / luaM_growaux_兩個函數.?
lgc.c -? 垃圾回收器(內存管理)?
5、外部封裝?
lua.c - Lua獨立解釋器?
luac.c - Lua編譯器(保存字節碼到一個文件,也可以列出字節碼)?
6、其他?
lzio.c -? 一個通用的帶緩沖區的輸入流接口?
linit.c - 實現luaL_openlibs方法,便于在C語言中加載上述模塊?
lctype.c 判斷類型?
二、主流程?
第一階段:main---load----詞法、語法解析、parser內會生成需要的指令集?
第二階段:docall----虛擬機內的luaV_execute?
三、runtime的實現?
? 1、vc中的一個典型調用棧信息如下:?
> lua1.exe!luaV_execute(lua_State * L=0x00035c28)? Line 521 C?
lua1.exe!luaD_call(lua_State * L=0x00035c28, lua_TValue * func=0x00035e00, int nResults=-1, int allowyield=0)? Line 393 + 0x9 bytes C?
lua1.exe!f_call(lua_State * L=0x00035c28, void * ud=0x0013f4a0)? Line 920 + 0x18 bytes C?
lua1.exe!luaD_rawrunprotected(lua_State * L=0x00035c28, void (lua_State *, void *)* f=0x00424a60, void * ud=0x0013f4a0)? Line 133 + 0x1f bytes C?
lua1.exe!luaD_pcall(lua_State * L=0x00035c28, void (lua_State *, void *)* func=0x00424a60, void * u=0x0013f4a0, int old_top=40, int ef=32)? Line 591 + 0x11 bytes C?
lua1.exe!lua_pcallk(lua_State * L=0x00035c28, int nargs=0, int nresults=-1, int errfunc=3, int ctx=0, int (lua_State *)* k=0x00000000)? Line 946 + 0x20 bytes C?
lua1.exe!docall(lua_State * L=0x00035c28, int narg=0, int nres=-1)? Line 179 + 0x19 bytes C?
lua1.exe!handle_script(lua_State * L=0x00035c28, char * * argv=0x00035ba0, int n=1)? Line 341 + 0xf bytes C?
lua1.exe!pmain(lua_State * L=0x00035c28)? Line 469 + 0x17 bytes C?
lua1.exe!luaD_precall(lua_State * L=0x00035c28, lua_TValue * func=0x00035de0, int nresults=1)? Line 317 + 0x9 bytes C?
lua1.exe!luaD_call(lua_State * L=0x00035c28, lua_TValue * func=0x00035de0, int nResults=1, int allowyield=0)? Line 392 + 0x11 bytes C?
lua1.exe!f_call(lua_State * L=0x00035c28, void * ud=0x0013fe48)? Line 920 + 0x18 bytes C?
lua1.exe!luaD_rawrunprotected(lua_State * L=0x00035c28, void (lua_State *, void *)* f=0x00424a60, void * ud=0x0013fe48)? Line 133 + 0x1f bytes C?
lua1.exe!luaD_pcall(lua_State * L=0x00035c28, void (lua_State *, void *)* func=0x00424a60, void * u=0x0013fe48, int old_top=8, int ef=0)? Line 591 + 0x11 bytes C?
lua1.exe!lua_pcallk(lua_State * L=0x00035c28, int nargs=2, int nresults=1, int errfunc=0, int ctx=0, int (lua_State *)* k=0x00000000)? Line 946 + 0x20 bytes C?
lua1.exe!main(int argc=2, char * * argv=0x00035ba0)? Line 495 + 0x13 bytes C?
? 2、基本交互邏輯?
? vm循環取出一個一個的Instruction,之后一個巨大的switch來解釋這個Instruction(lua 5.2是基于寄存器的指令集),即經典的fetch---execute循環。?
特殊的指令:?
1》函數調用指令:遇到函數調用時(lua中調用),要用c代碼模擬出硬件執行代碼時的棧結構。?
基本上每次增加一個活動記錄時要設置好相應的閉包信息和執行環境,設置好相應的符號表,做好參數的檢查,必要時GC一下?
2》協程指令?? :每次有create調用時就新建一個lua_state,全局棧維護這些stack信息?
? resume時 luaB_coresume---auxresume---lua_resume---luaB_yield?
?? lua1.exe!lua_yieldk(lua_State * L=0x0003e698, int nresults=1, int ctx=0, int (lua_State *)* k=0x00000000)? Line 556 C?
lua1.exe!luaB_yield(lua_State * L=0x0003e698)? Line 99 + 0x1a bytes C?
lua1.exe!luaD_precall(lua_State * L=0x0003e698, lua_TValue * func=0x0003f3f8, int nresults=-1)? Line 317 + 0x9 bytes C?
lua1.exe!luaV_execute(lua_State * L=0x0003e698)? Line 744 + 0x34 bytes C?
lua1.exe!resume(lua_State * L=0x0003e698, void * ud=0x0003f3d8)? Line 496 + 0x9 bytes C?
lua1.exe!luaD_rawrunprotected(lua_State * L=0x0003e698, void (lua_State *, void *)* f=0x004348d0, void * ud=0x0003f3d8)? Line 133 + 0x1f bytes C?
lua1.exe!lua_resume(lua_State * L=0x0003e698, lua_State * from=0x00035c28, int nargs=2)? Line 531 + 0x1d bytes C?
> lua1.exe!auxresume(lua_State * L=0x00035c28, lua_State * co=0x0003e698, int narg=2)? Line 31 + 0x11 bytes C?
lua1.exe!luaB_coresume(lua_State * L=0x00035c28)? Line 53 + 0x1d bytes C?
四、解釋器?
1、main函數?
line484: lua.c?
lua_newstate:全局和線程棧狀態的初始化?
lua_State *L = luaL_newstate();? // 創建全局的運行時信息?
lua_pushcfunction(L, &pmain);??? // 創建當前棧頂的函數閉包?
lua_pushinteger(L, argc);? // 參數入棧?
lua_pushlightuserdata(L, argv); /* 2nd argument */?
status = lua_pcall(L, 2, 1, 0); // 運行時執行一個lua函數?
result = lua_toboolean(L, -1);? /* get result */?
finalreport(L, status);?
lua_close(L);?????????????? // 釋放內存等掃尾工作?
2、lua_pcall詳情?
1》參數檢查?
2》luaD_pcall --------luaD_rawrunprotected---f_call----luaD_call---luaD_precall---pmain?
luaL_checkversion(L); // 驗證虛擬機?
lua_gc(L, LUA_GCSTOP, 0);? /* stop collector during initialization */?
luaL_openlibs(L);???? // 初始化內置庫 loadedlibs是默認打開的功能表?
lua_gc(L, LUA_GCRESTART, 0);?
handle_script -------執行主腳本?
luaL_loadfile------docall(一堆的棧操作)----luaV_execute:lvm.c // 虛擬機的執行引擎
總結
- 上一篇: ErWin简单使用说明
- 下一篇: Basic脚本解释器移植到STM32