zoukankan      html  css  js  c++  java
  • 初识Luajit

    转自:http://www.cppblog.com/pwq1989/archive/2013/11/28/204487.html

    大家可以从官网下载到源码(http://luajit.org/),也可以从Github(https://github.com/LuaDist/luajit)down下来,顺便还可以看下commit记录。

    大家对着luajit的wiki结合源码看的话会更好些,因为。。文档太特么少了!!

    目录结构:
    -- src
        -- host
        -- jit
        *.c
        *.h
        *.dasc
    等等,别的不是很重要

    最开始我是从main函数开始看的,然后。。碰了一鼻子灰,后来研究下他的makefile,发现他是这样子的编译的,贴一下关键的msvcbuild.bat的代码(这个更容易看懂)

    :X64
    minilua %DASM% -LN %DASMFLAGS% -o hostuildvm_arch.h vm_x86.dasc
    @if errorlevel 1 goto :BAD
    
    %LJCOMPILE% /I "." /I %DASMDIR% hostuildvm*.c
    @if errorlevel 1 goto :BAD
    %LJLINK% /out:buildvm.exe buildvm*.obj
    @if errorlevel 1 goto :BAD
    if exist buildvm.exe.manifest^
      %LJMT% -manifest buildvm.exe.manifest -outputresource:buildvm.exe
    
    buildvm -m peobj -o lj_vm.obj
    @if errorlevel 1 goto :BAD
    buildvm -m bcdef -o lj_bcdef.h %ALL_LIB%
    @if errorlevel 1 goto :BAD
    buildvm -m ffdef -o lj_ffdef.h %ALL_LIB%
    @if errorlevel 1 goto :BAD
    buildvm -m libdef -o lj_libdef.h %ALL_LIB%
    @if errorlevel 1 goto :BAD
    buildvm -m recdef -o lj_recdef.h %ALL_LIB%
    @if errorlevel 1 goto :BAD
    buildvm -m vmdef -o jitvmdef.lua %ALL_LIB%
    @if errorlevel 1 goto :BAD
    buildvm -m folddef -o lj_folddef.h lj_opt_fold.c
    @if errorlevel 1 goto :BAD

    先创建了一个buildvm.exe的中间工具,来自动生成代码,分别生成了lj_vm.obj,lj_bcdef.h,lj_ffdef.h ,lj_recdef.h ,jitvmdef.lua,lj_folddef.h, lj_libdef.h

    其中lv_vm.obj是依赖于hostuildvm_arch.h的,这个是用DynASM预处理vm_x86.dasc生成的,这个工具的具体分析会在下一篇博客提及。

    先来看下上面自动生成的代码:
    lj_bcdef.h:

    LJ_DATADEF const uint16_t lj_bc_ofs[] = {
    0,
    71,
    142,
    213,
    284,
    
    };
    
    LJ_DATADEF const uint16_t lj_bc_mode[] = {
    BCDEF(BCMODE)
    BCMODE_FF,
    BCMODE_FF,
    BCMODE_FF,
    BCMODE_FF,
    BCMODE_FF,
    
    };

    lj_bc_ofs[]可能是bc在vm代码段中的偏移量(这个我还没深入进去调试一下),vm的一部分是用DynASM直接撸汇编撸出来的,wiki中也有提到下一步jit化的opcode等等。

    lj_bc_mode[]的用来根据压缩后的bytecode构造,分离出操作数,第一行的两个宏的定义是
    #define BCMODE(name, ma, mb, mc, mm) 
      (BCM##ma|(BCM##mb<<3)|(BCM##mc<<7)|(MM_##mm<<11)),
    #define BCMODE_FF    0
    
    #define BCDEF(_) 
      /* Comparison ops. ORDER OPR. */ 
      _(ISLT,    var,    ___,    var,    lt) 
      _(ISGE,    var,    ___,    var,    lt) 
      _(ISLE,    var,    ___,    var,    le) 
      _(ISGT,    var,    ___,    var,    le) 
    ...
    总之就是充斥着各种拼接起来的宏

    lj_ffdef.h:
    FFDEF(assert)
    FFDEF(type)
    FFDEF(next)
    FFDEF(pairs)
    FFDEF(ipairs_aux)
    ...

    FFDEF的定义是在

    /* Fast function ID. */
    typedef enum {
      FF_LUA_ = FF_LUA,    /* Lua function (must be 0). */
      FF_C_ = FF_C,        /* Regular C function (must be 1). */
    #define FFDEF(name)    FF_##name,
    #include "lj_ffdef.h"
      FF__MAX
    } FastFunc;

    差不多就是用FF_##name把上面的名字拼接起来,然后生成在enum里面,这样就能当成是数字,在数组中迅速找到入口了

    vmdef.lua:
    这个里面内容就不贴了,包括bcname,irname,irfpm,irfield,ircall 的定义,在jit文件夹下面,用于调试等,比如在dump.lua中就有用到

    local jit = require("jit")
    assert(jit.version_num == 20002, "LuaJIT core/library version mismatch")
    local jutil = require("jit.util")
    local vmdef = require("jit.vmdef")  // ← ← ← ←

    当你用luajit -jdump的时候,就是调用的lua的jit库里面的lua函数

    lj_recdef.h:

    static const uint16_t recff_idmap[] = {
    0,
    0x0100,
    0x0200,
    0x0300,
    0,
    0,
    0x0400,
    
    };
    
    static const RecordFunc recff_func[] = {
    recff_nyi,
    recff_c,
    recff_assert,
    recff_type,
    recff_ipairs_aux,
    
    };

    其中recff_func[]是被注册的被traced jit 跟踪的函数,具体可是在lj_ffrecord.c里面看到
    recff_idmap[]被用在lj_ffrecord_func这个函数中,有一个关键的数据结构RecordFFData,用来记录在trace过程中被调用函数的参数和返回值个数,和一些辅助数据,opcode,literal等等。通过recff_idmap[]保存的值来区分函数(待仔细研究)


    lj_folddef.h:

    static const FoldFunc fold_func[] = {
      fold_kfold_numarith,
      fold_kfold_ldexp,
      fold_kfold_fpmath,
      fold_kfold_numpow,
    
    };
    
    static const uint32_t fold_hash[916] = {
    0xffffffff,
    0xffffffff,
    0x5b4c8016,
    
    };

    用在FOLD optimization中,见lj_opt_fold.c,主要在

    if ((fh & 0xffffff) == k || (fh = fold_hash[h+1], (fh & 0xffffff) == k)) {
          ref = (IRRef)tref_ref(fold_func[fh >> 24](J));
          if (ref != NEXTFOLD)
        break;
        }

    是根据数组偏移获取函数,直接执行。
    (这个Optimation略复杂,以后的博文中再说)

    ----------------------------------------分割线-------------------------------------------

    以上就是buildvm生成代码,在很多.c的文件中,他加入了一些无意义的MARCO,目的是为了能被buildvm识别出

    下面说说src根目录下面的文件:

    lauxlib.h:
    用户开发扩展和与C交互的时候的头文件

    lib_*.h /.c:
    顾名思义,就是利用LuaAPI写的内部标准库,会在方法上表明是否会被trace ( LJLIB_REC(.) )。

    ljamalg.c:
    文件的合并

    lj_alloc.h /.c:
    定制的Memory Allocator

    lj_api.c:

    Public Lua/C API.


    lj_arch.h:

    Target architecture selection

    lj_jit.h:
    jit编译器里面数据结构的定义


    lj_asm.h/ .c  lj_asm_*.c lj_emit_*.h lj_target_*.h/.c :
    将IR编译成Machine Code,关键的数据结构ASMState,线性扫描的O(n2)分配算法

    lj_bc.h/ .c:
    Luajit字节码的定义和内存布局

    lj_bcdump.c lj_bcread.c  lj_bcwrite.c:
    围绕着字节码的操作

    lj_carith.c:

    C实现的一些数字运算


    lj_ccall.h/ .c  lj_ccallback.h / .c :
    FFI C语言函数调用和回调绑定

    lj_debug.h/.c :
    调试与自省用

    lj_def.h:
    这个很重要,重要的类型和一些宏定义在这里

    lj_c*.h/ .c:
    和C语言先关的,比如类型转化,char管理,数据管理

    lj_frame.h:
    Luajit的栈帧管理

    lj_func.h/.c:
    Function handle和闭包有关的upvalue数据结构

    lj_gc.h/.c:
    GC相关,GC可以看下luajit的wiki,里面涉及不少增量式GC的paper和作者的看法

    lj_gdbjit.h/.c :
    对gdb的支持

    lj_ir*.h/.c:
    SSA,IR相关(这个和bytecode还是不一样的)操作和优化

    lj_lex.h/.c  lj_parse.h/.c:
    lexer和parser

    lj_mcode.h/.c:
    Machine Code管理

    lj_opt_*.h:
    各种bytecode层面上的优化

    lj_snap.h/.c:
    快照支持

    lj_state.h/.c:
    LuaState和Stack的操作

    lj_str*.h/.c  lj_tab.h/.c:
    原生类型string和table操作

    lj_udata.h/.c:
    类型user data的操作

    lj_vm.h/.c  lj_vmevent.h/.c:
    vm的API和事件注册(lj_vmevent_send)

    lj_vmmath.h/.c:
    对vm支持的math库

    lua.h:
    luaState等基本的Lua结构

    lualib.h:
    和Lua一样,标准库的API

    luajit.h:
    luajit 的public API

    vm_*.dasc:
    编译期被DynASM预处理的源文件,下一篇讲DynASM时候介绍dasc文件

    wmain.c:
    windows下面的main入口

    和Trace相关的:
    lj_crecord.h/.c  : C操作的trace record
    lj_dispatch.h/.c :  指令分发,调用ASMFuction,处理指令前的hook和记录trace用的hot count,有一个重要的数据结构 GG_State
    lj_ff*.h/.c: 上面讲lj_ffdef.h的时候提过,trace的时候 记录Fast Function的调用记数
    lj_trace.h/.c: trace的具体过程
    lj_traceerr.h : trace error

  • 相关阅读:
    Jenkins权限控制-Role Strategy Plugin插件使用
    迁移一个仓库到新的Gitlab
    Gitlab备份以及恢复
    10.使用nexus3配置golang私有仓库
    9.使用nexus3配置Python私有仓库
    8.maven上传jar包以及SNAPSHOT的一个坑
    7.nexus版本升级
    6.使用nexus3配置yum私有仓库
    5.使用nexus3配置npm私有仓库
    4.maven私服nexus2迁移到nexus3
  • 原文地址:https://www.cnblogs.com/sevenyuan/p/4527488.html
Copyright © 2011-2022 走看看