/* ** Bytecode instruction format. ** Copyright (C) 2005-2022 Mike Pall. See Copyright Notice in luajit.h */ #ifndef _LJ_BC_H #define _LJ_BC_H #include "lj_def.h" #include "lj_arch.h" /* Bytecode instruction format, 32 bit wide, fields of 8 or 16 bit: ** ** +----+----+----+----+ ** | B | C | A | OP | Format ABC ** +----+----+----+----+ ** | D | A | OP | Format AD ** +-------------------- ** MSB LSB ** ** In-memory instructions are always stored in host byte order. */ /* Operand ranges and related constants. */ #define BCMAX_A 0xff #define BCMAX_B 0xff #define BCMAX_C 0xff #define BCMAX_D 0xffff #define BCBIAS_J 0x8000 #define NO_REG BCMAX_A #define NO_JMP (~(BCPos)0) /* Macros to get instruction fields. */ #define bc_op(i) ((BCOp)((i)&0xff)) #define bc_a(i) ((BCReg)(((i)>>8)&0xff)) #define bc_b(i) ((BCReg)((i)>>24)) #define bc_c(i) ((BCReg)(((i)>>16)&0xff)) #define bc_d(i) ((BCReg)((i)>>16)) #define bc_j(i) ((ptrdiff_t)bc_d(i)-BCBIAS_J) /* Macros to set instruction fields. */ #define setbc_byte(p, x, ofs) \ ((uint8_t *)(p))[LJ_ENDIAN_SELECT(ofs, 3-ofs)] = (uint8_t)(x) #define setbc_op(p, x) setbc_byte(p, (x), 0) #define setbc_a(p, x) setbc_byte(p, (x), 1) #define setbc_b(p, x) setbc_byte(p, (x), 3) #define setbc_c(p, x) setbc_byte(p, (x), 2) #define setbc_d(p, x) \ ((uint16_t *)(p))[LJ_ENDIAN_SELECT(1, 0)] = (uint16_t)(x) #define setbc_j(p, x) setbc_d(p, (BCPos)((int32_t)(x)+BCBIAS_J)) /* Macros to compose instructions. */ #define BCINS_ABC(o, a, b, c) \ (((BCIns)(o))|((BCIns)(a)<<8)|((BCIns)(b)<<24)|((BCIns)(c)<<16)) #define BCINS_AD(o, a, d) \ (((BCIns)(o))|((BCIns)(a)<<8)|((BCIns)(d)<<16)) #define BCINS_AJ(o, a, j) BCINS_AD(o, a, (BCPos)((int32_t)(j)+BCBIAS_J)) /* Bytecode instruction definition. Order matters, see below. ** ** (name, filler, Amode, Bmode, Cmode or Dmode, metamethod) ** ** The opcode name suffixes specify the type for RB/RC or RD: ** V = variable slot ** S = string const ** N = number const ** P = primitive type (~itype) ** B = unsigned byte literal ** M = multiple args/results */ #define BCDEF(_) \ /* Comparison ops. ORDER OPR. */ \ _(ISLT, var, ___, var, lt) \ _(ISGE, var, ___, var, lt) \ _(ISLE, var, ___, var, le) \ _(ISGT, var, ___, var, le) \ \ _(ISEQV, var, ___, var, eq) \ _(ISNEV, var, ___, var, eq) \ _(ISEQS, var, ___, str, eq) \ _(ISNES, var, ___, str, eq) \ _(ISEQN, var, ___, num, eq) \ _(ISNEN, var, ___, num, eq) \ _(ISEQP, var, ___, pri, eq) \ _(ISNEP, var, ___, pri, eq) \ \ /* Unary test and copy ops. */ \ _(ISTC, dst, ___, var, ___) \ _(ISFC, dst, ___, var, ___) \ _(IST, ___, ___, var, ___) \ _(ISF, ___, ___, var, ___) \ \ /* Unary ops. */ \ _(MOV, dst, ___, var, ___) \ _(NOT, dst, ___, var, ___) \ _(UNM, dst, ___, var, unm) \ _(LEN, dst, ___, var, len) \ \ /* Binary ops. ORDER OPR. VV last, POW must be next. */ \ _(ADDVN, dst, var, num, add) \ _(SUBVN, dst, var, num, sub) \ _(MULVN, dst, var, num, mul) \ _(DIVVN, dst, var, num, div) \ _(MODVN, dst, var, num, mod) \ \ _(ADDNV, dst, var, num, add) \ _(SUBNV, dst, var, num, sub) \ _(MULNV, dst, var, num, mul) \ _(DIVNV, dst, var, num, div) \ _(MODNV, dst, var, num, mod) \ \ _(ADDVV, dst, var, var, add) \ _(SUBVV, dst, var, var, sub) \ _(MULVV, dst, var, var, mul) \ _(DIVVV, dst, var, var, div) \ _(MODVV, dst, var, var, mod) \ \ _(POW, dst, var, var, pow) \ _(CAT, dst, rbase, rbase, concat) \ \ /* Constant ops. */ \ _(KSTR, dst, ___, str, ___) \ _(KCDATA, dst, ___, cdata, ___) \ _(KSHORT, dst, ___, lits, ___) \ _(KNUM, dst, ___, num, ___) \ _(KPRI, dst, ___, pri, ___) \ _(KNIL, base, ___, base, ___) \ \ /* Upvalue and function ops. */ \ _(UGET, dst, ___, uv, ___) \ _(USETV, uv, ___, var, ___) \ _(USETS, uv, ___, str, ___) \ _(USETN, uv, ___, num, ___) \ _(USETP, uv, ___, pri, ___) \ _(UCLO, rbase, ___, jump, ___) \ _(FNEW, dst, ___, func, gc) \ \ /* Table ops. */ \ _(TNEW, dst, ___, lit, gc) \ _(TDUP, dst, ___, tab, gc) \ _(GGET, dst, ___, str, index) \ _(GSET, var, ___, str, newindex) \ _(TGETV, dst, var, var, index) \ _(TGETS, dst, var, str, index) \ _(TGETB, dst, var, lit, index) \ _(TSETV, var, var, var, newindex) \ _(TSETS, var, var, str, newindex) \ _(TSETB, var, var, lit, newindex) \ _(TSETM, base, ___, num, newindex) \ \ /* Calls and vararg handling. T = tail call. */ \ _(CALLM, base, lit, lit, call) \ _(CALL, base, lit, lit, call) \ _(CALLMT, base, ___, lit, call) \ _(CALLT, base, ___, lit, call) \ _(ITERC, base, lit, lit, call) \ _(ITERN, base, lit, lit, call) \ _(VARG, base, lit, lit, ___) \ _(ISNEXT, base, ___, jump, ___) \ \ /* Returns. */ \ _(RETM, base, ___, lit, ___) \ _(RET, rbase, ___, lit, ___) \ _(RET0, rbase, ___, lit, ___) \ _(RET1, rbase, ___, lit, ___) \ \ /* Loops and branches. I/J = interp/JIT, I/C/L = init/call/loop. */ \ _(FORI, base, ___, jump, ___) \ _(JFORI, base, ___, jump, ___) \ \ _(FORL, base, ___, jump, ___) \ _(IFORL, base, ___, jump, ___) \ _(JFORL, base, ___, lit, ___) \ \ _(ITERL, base, ___, jump, ___) \ _(IITERL, base, ___, jump, ___) \ _(JITERL, base, ___, lit, ___) \ \ _(LOOP, rbase, ___, jump, ___) \ _(ILOOP, rbase, ___, jump, ___) \ _(JLOOP, rbase, ___, lit, ___) \ \ _(JMP, rbase, ___, jump, ___) \ \ /* Function headers. I/J = interp/JIT, F/V/C = fixarg/vararg/C func. */ \ _(FUNCF, rbase, ___, ___, ___) \ _(IFUNCF, rbase, ___, ___, ___) \ _(JFUNCF, rbase, ___, lit, ___) \ _(FUNCV, rbase, ___, ___, ___) \ _(IFUNCV, rbase, ___, ___, ___) \ _(JFUNCV, rbase, ___, lit, ___) \ _(FUNCC, rbase, ___, ___, ___) \ _(FUNCCW, rbase, ___, ___, ___) /* Bytecode opcode numbers. */ typedef enum { #define BCENUM(name, ma, mb, mc, mt) BC_##name, BCDEF(BCENUM) #undef BCENUM BC__MAX } BCOp; LJ_STATIC_ASSERT((int)BC_ISEQV+1 == (int)BC_ISNEV); LJ_STATIC_ASSERT(((int)BC_ISEQV^1) == (int)BC_ISNEV); LJ_STATIC_ASSERT(((int)BC_ISEQS^1) == (int)BC_ISNES); LJ_STATIC_ASSERT(((int)BC_ISEQN^1) == (int)BC_ISNEN); LJ_STATIC_ASSERT(((int)BC_ISEQP^1) == (int)BC_ISNEP); LJ_STATIC_ASSERT(((int)BC_ISLT^1) == (int)BC_ISGE); LJ_STATIC_ASSERT(((int)BC_ISLE^1) == (int)BC_ISGT); LJ_STATIC_ASSERT(((int)BC_ISLT^3) == (int)BC_ISGT); LJ_STATIC_ASSERT((int)BC_IST-(int)BC_ISTC == (int)BC_ISF-(int)BC_ISFC); LJ_STATIC_ASSERT((int)BC_CALLT-(int)BC_CALL == (int)BC_CALLMT-(int)BC_CALLM); LJ_STATIC_ASSERT((int)BC_CALLMT + 1 == (int)BC_CALLT); LJ_STATIC_ASSERT((int)BC_RETM + 1 == (int)BC_RET); LJ_STATIC_ASSERT((int)BC_FORL + 1 == (int)BC_IFORL); LJ_STATIC_ASSERT((int)BC_FORL + 2 == (int)BC_JFORL); LJ_STATIC_ASSERT((int)BC_ITERL + 1 == (int)BC_IITERL); LJ_STATIC_ASSERT((int)BC_ITERL + 2 == (int)BC_JITERL); LJ_STATIC_ASSERT((int)BC_LOOP + 1 == (int)BC_ILOOP); LJ_STATIC_ASSERT((int)BC_LOOP + 2 == (int)BC_JLOOP); LJ_STATIC_ASSERT((int)BC_FUNCF + 1 == (int)BC_IFUNCF); LJ_STATIC_ASSERT((int)BC_FUNCF + 2 == (int)BC_JFUNCF); LJ_STATIC_ASSERT((int)BC_FUNCV + 1 == (int)BC_IFUNCV); LJ_STATIC_ASSERT((int)BC_FUNCV + 2 == (int)BC_JFUNCV); /* This solves a circular dependency problem, change as needed. */ #define FF_next_N 4 /* Stack slots used by FORI/FORL, relative to operand A. */ enum { FORL_IDX, FORL_STOP, FORL_STEP, FORL_EXT }; /* Bytecode operand modes. ORDER BCMode */ typedef enum { BCMnone, BCMdst, BCMbase, BCMvar, BCMrbase, BCMuv, /* Mode A must be <= 7 */ BCMlit, BCMlits, BCMpri, BCMnum, BCMstr, BCMtab, BCMfunc, BCMjump, BCMcdata, BCM_max } BCMode; #define BCM___ BCMnone #define bcmode_a(op) ((BCMode)(lj_bc_mode[op] & 7)) #define bcmode_b(op) ((BCMode)((lj_bc_mode[op]>>3) & 15)) #define bcmode_c(op) ((BCMode)((lj_bc_mode[op]>>7) & 15)) #define bcmode_d(op) bcmode_c(op) #define bcmode_hasd(op) ((lj_bc_mode[op] & (15<<3)) == (BCMnone<<3)) #define bcmode_mm(op) ((MMS)(lj_bc_mode[op]>>11)) #define BCMODE(name, ma, mb, mc, mm) \ (BCM##ma|(BCM##mb<<3)|(BCM##mc<<7)|(MM_##mm<<11)), #define BCMODE_FF 0 static LJ_AINLINE int bc_isret(BCOp op) { return (op == BC_RETM || op == BC_RET || op == BC_RET0 || op == BC_RET1); } LJ_DATA const uint16_t lj_bc_mode[]; LJ_DATA const uint16_t lj_bc_ofs[]; #endif