/*! \file lua_bytecode.h * \brief Lua 5.4 bytecode structures — standalone deserializer. * * Our own Lua 5.4 bytecode structures. No Lua headers needed. * engine.so reads the output of lua_dump() from lua_mod.so and * lowers it through the HIR/RV64/x86-64 pipeline. */ #ifndef LUA_BYTECODE_H #define LUA_BYTECODE_H #include #include #include #include // --------------------------------------------------------------- // Lua 5.4 opcodes (all 83) // --------------------------------------------------------------- enum lua_bc_opcode { OP_LUA_MOVE, // 0 OP_LUA_LOADI, // 1 OP_LUA_LOADF, // 2 OP_LUA_LOADK, // 3 OP_LUA_LOADKX, // 4 OP_LUA_LOADFALSE, // 5 OP_LUA_LFALSESKIP, // 6 OP_LUA_LOADTRUE, // 7 OP_LUA_LOADNIL, // 8 OP_LUA_GETUPVAL, // 9 OP_LUA_SETUPVAL, // 10 OP_LUA_GETTABUP, // 11 OP_LUA_GETTABLE, // 12 OP_LUA_GETTABI, // 13 OP_LUA_GETFIELD, // 14 OP_LUA_SETTABUP, // 15 OP_LUA_SETTABLE, // 16 OP_LUA_SETTABI, // 17 OP_LUA_SETFIELD, // 18 OP_LUA_NEWTABLE, // 19 OP_LUA_SELF, // 20 OP_LUA_ADDI, // 21 OP_LUA_ADDK, // 22 OP_LUA_SUBK, // 23 OP_LUA_MULK, // 24 OP_LUA_MODK, // 25 OP_LUA_POWK, // 26 OP_LUA_DIVK, // 27 OP_LUA_IDIVK, // 28 OP_LUA_BANDK, // 29 OP_LUA_BORK, // 30 OP_LUA_BXORK, // 31 OP_LUA_SHRI, // 32 OP_LUA_SHLI, // 33 OP_LUA_ADD, // 34 OP_LUA_SUB, // 35 OP_LUA_MUL, // 36 OP_LUA_MOD, // 37 OP_LUA_POW, // 38 OP_LUA_DIV, // 39 OP_LUA_IDIV, // 40 OP_LUA_BAND, // 41 OP_LUA_BOR, // 42 OP_LUA_BXOR, // 43 OP_LUA_SHL, // 44 OP_LUA_SHR, // 45 OP_LUA_MMBIN, // 46 OP_LUA_MMBINI, // 47 OP_LUA_MMBINK, // 48 OP_LUA_UNM, // 49 OP_LUA_BNOT, // 50 OP_LUA_NOT, // 51 OP_LUA_LEN, // 52 OP_LUA_CONCAT, // 53 OP_LUA_CLOSE, // 54 OP_LUA_TBC, // 55 OP_LUA_JMP, // 56 OP_LUA_EQ, // 57 OP_LUA_LT, // 58 OP_LUA_LE, // 59 OP_LUA_EQK, // 60 OP_LUA_EQI, // 61 OP_LUA_LTI, // 62 OP_LUA_LEI, // 63 OP_LUA_GTI, // 64 OP_LUA_GEI, // 65 OP_LUA_TEST, // 66 OP_LUA_TESTSET, // 67 OP_LUA_CALL, // 68 OP_LUA_TAILCALL, // 69 OP_LUA_RETURN, // 70 OP_LUA_RETURN0, // 71 OP_LUA_RETURN1, // 72 OP_LUA_FORLOOP, // 73 OP_LUA_FORPREP, // 74 OP_LUA_TFORPREP, // 75 OP_LUA_TFORCALL, // 76 OP_LUA_TFORLOOP, // 77 OP_LUA_SETLIST, // 78 OP_LUA_CLOSURE, // 79 OP_LUA_VARARG, // 80 OP_LUA_VARARGPREP, // 81 OP_LUA_EXTRAARG, // 82 OP_LUA_NUM_OPCODES }; // --------------------------------------------------------------- // Instruction field accessors // --------------------------------------------------------------- // Lua 5.4 instruction format: 32-bit word // iABC: C:8 | B:8 | k:1 | A:8 | Op:7 // iABx: Bx:17 | A:8 | Op:7 (unsigned) // iAsBx: sBx:17 | A:8 | Op:7 (signed = Bx - offset) // iAx: Ax:25 | Op:7 // isJ: sJ:25 | Op:7 struct lua_bc_instruction { uint32_t raw; int opcode() const { return raw & 0x7F; } int A() const { return (raw >> 7) & 0xFF; } int k() const { return (raw >> 15) & 0x1; } int B() const { return (raw >> 16) & 0xFF; } int sB() const { return B() - 127; } // signed B field, OFFSET_sB int C() const { return (raw >> 24) & 0xFF; } // Lua's signed fields are excess-K with K = MAXARG_x >> 1, i.e. // ((1 << SIZE_x) - 1) >> 1 -- one LESS than 2^(SIZE_x - 1) // (lua54/lopcodes.h:72-92). Three of the four here used the power of // two instead and were each one too large (#1422): // // sC 128 -> 127 sB 128 -> 127 // sJ 1<<24 -> 16777215 sBx 65535, already correct // // sC made every immediate one low, so `i = i + 1` lowered as // `i = i + 0` and loop bodies appeared to have no effect. sJ is the // jump displacement, so every branch target was off by one instruction. int sC() const { return C() - 127; } // signed C field int Bx() const { return (raw >> 15) & 0x1FFFF; } // bits 15-31 int sBx() const { return Bx() - 65535; } // offset = (2^17 - 1) / 2 int Ax() const { return (raw >> 7) & 0x1FFFFFF; } int sJ() const { return static_cast((raw >> 7) & 0x1FFFFFF) - 16777215; } }; // --------------------------------------------------------------- // Constant types // --------------------------------------------------------------- enum lua_bc_const_type { LUA_BC_TNIL = 0, LUA_BC_TFALSE = 1, LUA_BC_TTRUE = 17, LUA_BC_TINT = 3, LUA_BC_TFLOAT = 19, LUA_BC_TSHRSTR = 4, LUA_BC_TLNGSTR = 20, }; struct lua_bc_constant { lua_bc_const_type type; int64_t ival; double fval; std::string sval; }; // --------------------------------------------------------------- // Upvalue descriptor // --------------------------------------------------------------- struct lua_bc_upvalue { uint8_t instack; uint8_t idx; uint8_t kind; }; // --------------------------------------------------------------- // Function prototype // --------------------------------------------------------------- struct lua_bc_proto { // Source info. std::string source; int linedefined; int lastlinedefined; uint8_t numparams; uint8_t is_vararg; uint8_t maxstacksize; // Code. std::vector code; // Constants. std::vector constants; // Upvalues. std::vector upvalues; // Nested protos. std::vector protos; // Debug info (line numbers, local names) — we skip these. }; // --------------------------------------------------------------- // Top-level chunk // --------------------------------------------------------------- struct lua_bc_chunk { // Header fields. uint8_t version; uint8_t format; uint8_t int_size; uint8_t size_t_size; uint8_t insn_size; uint8_t lua_int_size; uint8_t lua_num_size; // Main function prototype. lua_bc_proto main; // Number of upvalues in main proto (from header). uint8_t num_upvalues; }; // --------------------------------------------------------------- // Deserializer // --------------------------------------------------------------- // Load a Lua 5.4 bytecode dump into `out`. // Returns true on success, false on malformed input. // bool lua_bc_load(const uint8_t *data, size_t len, lua_bc_chunk *out); #endif // LUA_BYTECODE_H