Skip to content

LuaJIT 2.x Bytecode dump format

viruscamp edited this page May 3, 2018 · 13 revisions
dump = header proto+ 0U // after read a proto, push it to state stack
    header = ESC 'L' 'J' versionB flagsU #if(!_STRIP)[namelenU nameB*]
    proto = lengthU flagsB numparamsB framesizeB numuvB numkgcU numknU numbcU
            #if(!_STRIP)[sizedbgU #if(sizedbgU)[firstlineU numlineU]]
            #len(numbcU)bcinsW* #len(numuvB)uvdataH* #len(numkgcU)kgc* #len(numknU)knum*
            #if(!_STRIP)[#len(sizedbgU)debugB*]
        kgc  = kgctypeU { ktab | (loU hiU) | (rloU rhiU iloU ihiU) | strB* }
            ktab = narrayU nhashU karray* khash*
                karray = ktabk
                khash  = ktabk ktabk
                    ktabk = ktabtypeU { intU | (loU hiU) | strB* }
        knum = intU0 | (loU1 hiU)
        uvdataH = GCproto.uv /* Upvalue list. local slot|0x8000 or parent uv idx. */

debugB* = lineinfo uvinfo varinfo
    lineinfo = #(numlineU) { lineB(numlineU <=255) | lineH(numlineU <=65535) | lineW }+
    uvinfo = #(numuvB) nullEndString+
    varinfo = var*\0
        lastpc = 0
        for (var = { \1 - \6 | nullEndString } n1U [n2U]) {
            startpc = lastpc + n1U; lastpc = startpc;
            if (startpc > pc) break;
            endpc = startpc + n2U;
        }

B = 8 bit, H = 16 bit, W = 32 bit, U = ULEB128 of W, U0/U1 = ULEB128 of W+1

versionB = 1(2.0.x) | 2(2.1.x)
flagsU = { // global flag, type is ULE128 but can read as byte, because it's always < 0x80
    #define BCDUMP_F_BE        0x01
    #define BCDUMP_F_STRIP     0x02
    #define BCDUMP_F_FFI       0x04
    #define BCDUMP_F_FR2       0x08  // new in 2.1.0
}
_STRIP = flagsU has BCDUMP_F_STRIP
flagsB = { // proto flag
    #define PROTO_CHILD        0x01  /* Has child prototypes. */
    #define PROTO_VARARG       0x02  /* Vararg function. */
    #define PROTO_FFI          0x04  /* Uses BC_KCDATA for FFI datatypes. */
    #define PROTO_NOJIT        0x08  /* JIT disabled for this function. */
    #define PROTO_ILOOP        0x10  /* Patched bytecode with ILOOP etc. */
    #define PROTO_HAS_RETURN   0x20  /* Already emitted a return. */
    #define PROTO_FIXUP_RETURN 0x40  /* Need to fixup emitted returns. */
}
kgctypeU = enum {
    BCDUMP_KGC_CHILD,   // child proto, when read this, pop a proto from state stack
    BCDUMP_KGC_TAB,     // ktab
    BCDUMP_KGC_I64,     // ffi i64 (loU hiU)
    BCDUMP_KGC_U64,     // ffi u64 (loU hiU)
    BCDUMP_KGC_COMPLEX, // ffi complex (rloU rhiU iloU ihiU)
    >= BCDUMP_KGC_STR   // sizeStr = kgctypeU - BCDUMP_KGC_STR
}
ktabtypeU = enum {
    BCDUMP_KTAB_NIL,   // nil
    BCDUMP_KTAB_FALSE, // false
    BCDUMP_KTAB_TRUE,  // true
    BCDUMP_KTAB_INT,   // int32 intU
    BCDUMP_KTAB_NUM,   // num (loU hiU)
    >= BCDUMP_KTAB_STR // sizeStr = ktabtypeU - BCDUMP_KTAB_STR
}

2.1.0 use -DLUAJIT_ENABLE_GC64 to enabled LJ_GC64 for arm64 ,
which also disable JIT and enable LJ_FR2, and add BCDUMP_F_FR2 for flagsU.
LJ_FR2 use one more reg for method call like CALLM CALL for_iter