github.com/shawnclovie/gopher-lua@v0.0.0-20200520092726-90b44ec0e2f2/opcode.go (about) 1 package lua 2 3 import ( 4 "fmt" 5 ) 6 7 /* 8 gopherlua uses Lua 5.1.4's opcodes. 9 Lua 5.1.4 opcodes layout: 10 11 instruction = 32bit(fixed length) 12 13 +---------------------------------------------+ 14 |0-5(6bits)|6-13(8bit)|14-22(9bit)|23-31(9bit)| 15 |==========+==========+===========+===========| 16 | opcode | A | C | B | 17 |----------+----------+-----------+-----------| 18 | opcode | A | Bx(unsigned) | 19 |----------+----------+-----------+-----------| 20 | opcode | A | sBx(signed) | 21 +---------------------------------------------+ 22 */ 23 24 const opInvalidInstruction = ^uint32(0) 25 26 const opSizeCode = 6 27 const opSizeA = 8 28 const opSizeB = 9 29 const opSizeC = 9 30 const opSizeBx = 18 31 const opSizesBx = 18 32 33 const opMaxArgsA = (1 << opSizeA) - 1 34 const opMaxArgsB = (1 << opSizeB) - 1 35 const opMaxArgsC = (1 << opSizeC) - 1 36 const opMaxArgBx = (1 << opSizeBx) - 1 37 const opMaxArgSbx = opMaxArgBx >> 1 38 39 const ( 40 OP_MOVE int = iota /* A B R(A) := R(B) */ 41 OP_MOVEN /* A B R(A) := R(B); followed by R(C) MOVE ops */ 42 OP_LOADK /* A Bx R(A) := Kst(Bx) */ 43 OP_LOADBOOL /* A B C R(A) := (Bool)B; if (C) pc++ */ 44 OP_LOADNIL /* A B R(A) := ... := R(B) := nil */ 45 OP_GETUPVAL /* A B R(A) := UpValue[B] */ 46 47 OP_GETGLOBAL /* A Bx R(A) := Gbl[Kst(Bx)] */ 48 OP_GETTABLE /* A B C R(A) := R(B)[RK(C)] */ 49 OP_GETTABLEKS /* A B C R(A) := R(B)[RK(C)] ; RK(C) is constant string */ 50 51 OP_SETGLOBAL /* A Bx Gbl[Kst(Bx)] := R(A) */ 52 OP_SETUPVAL /* A B UpValue[B] := R(A) */ 53 OP_SETTABLE /* A B C R(A)[RK(B)] := RK(C) */ 54 OP_SETTABLEKS /* A B C R(A)[RK(B)] := RK(C) ; RK(B) is constant string */ 55 56 OP_NEWTABLE /* A B C R(A) := {} (size = BC) */ 57 58 OP_SELF /* A B C R(A+1) := R(B); R(A) := R(B)[RK(C)] */ 59 60 OP_ADD /* A B C R(A) := RK(B) + RK(C) */ 61 OP_SUB /* A B C R(A) := RK(B) - RK(C) */ 62 OP_MUL /* A B C R(A) := RK(B) * RK(C) */ 63 OP_DIV /* A B C R(A) := RK(B) / RK(C) */ 64 OP_MOD /* A B C R(A) := RK(B) % RK(C) */ 65 OP_POW /* A B C R(A) := RK(B) ^ RK(C) */ 66 OP_UNM /* A B R(A) := -R(B) */ 67 OP_NOT /* A B R(A) := not R(B) */ 68 OP_LEN /* A B R(A) := length of R(B) */ 69 70 OP_CONCAT /* A B C R(A) := R(B).. ... ..R(C) */ 71 72 OP_JMP /* sBx pc+=sBx */ 73 74 OP_EQ /* A B C if ((RK(B) == RK(C)) ~= A) then pc++ */ 75 OP_LT /* A B C if ((RK(B) < RK(C)) ~= A) then pc++ */ 76 OP_LE /* A B C if ((RK(B) <= RK(C)) ~= A) then pc++ */ 77 78 OP_TEST /* A C if not (R(A) <=> C) then pc++ */ 79 OP_TESTSET /* A B C if (R(B) <=> C) then R(A) := R(B) else pc++ */ 80 81 OP_CALL /* A B C R(A) ... R(A+C-2) := R(A)(R(A+1) ... R(A+B-1)) */ 82 OP_TAILCALL /* A B C return R(A)(R(A+1) ... R(A+B-1)) */ 83 OP_RETURN /* A B return R(A) ... R(A+B-2) (see note) */ 84 85 OP_FORLOOP /* A sBx R(A)+=R(A+2); 86 if R(A) <?= R(A+1) then { pc+=sBx; R(A+3)=R(A) }*/ 87 OP_FORPREP /* A sBx R(A)-=R(A+2); pc+=sBx */ 88 89 OP_TFORLOOP /* A C R(A+3) ... R(A+3+C) := R(A)(R(A+1) R(A+2)); 90 if R(A+3) ~= nil then { pc++; R(A+2)=R(A+3); } */ 91 OP_SETLIST /* A B C R(A)[(C-1)*FPF+i] := R(A+i) 1 <= i <= B */ 92 93 OP_CLOSE /* A close all variables in the stack up to (>=) R(A)*/ 94 OP_CLOSURE /* A Bx R(A) := closure(KPROTO[Bx] R(A) ... R(A+n)) */ 95 96 OP_VARARG /* A B R(A) R(A+1) ... R(A+B-1) = vararg */ 97 98 OP_NOP /* NOP */ 99 ) 100 const opCodeMax = OP_NOP 101 102 type opArgMode int 103 104 const ( 105 opArgModeN opArgMode = iota 106 opArgModeU 107 opArgModeR 108 opArgModeK 109 ) 110 111 type opType int 112 113 const ( 114 opTypeABC = iota 115 opTypeABx 116 opTypeASbx 117 ) 118 119 type opProp struct { 120 Name string 121 IsTest bool 122 SetRegA bool 123 ModeArgB opArgMode 124 ModeArgC opArgMode 125 Type opType 126 } 127 128 var opProps = []opProp{ 129 opProp{"MOVE", false, true, opArgModeR, opArgModeN, opTypeABC}, 130 opProp{"MOVEN", false, true, opArgModeR, opArgModeN, opTypeABC}, 131 opProp{"LOADK", false, true, opArgModeK, opArgModeN, opTypeABx}, 132 opProp{"LOADBOOL", false, true, opArgModeU, opArgModeU, opTypeABC}, 133 opProp{"LOADNIL", false, true, opArgModeR, opArgModeN, opTypeABC}, 134 opProp{"GETUPVAL", false, true, opArgModeU, opArgModeN, opTypeABC}, 135 opProp{"GETGLOBAL", false, true, opArgModeK, opArgModeN, opTypeABx}, 136 opProp{"GETTABLE", false, true, opArgModeR, opArgModeK, opTypeABC}, 137 opProp{"GETTABLEKS", false, true, opArgModeR, opArgModeK, opTypeABC}, 138 opProp{"SETGLOBAL", false, false, opArgModeK, opArgModeN, opTypeABx}, 139 opProp{"SETUPVAL", false, false, opArgModeU, opArgModeN, opTypeABC}, 140 opProp{"SETTABLE", false, false, opArgModeK, opArgModeK, opTypeABC}, 141 opProp{"SETTABLEKS", false, false, opArgModeK, opArgModeK, opTypeABC}, 142 opProp{"NEWTABLE", false, true, opArgModeU, opArgModeU, opTypeABC}, 143 opProp{"SELF", false, true, opArgModeR, opArgModeK, opTypeABC}, 144 opProp{"ADD", false, true, opArgModeK, opArgModeK, opTypeABC}, 145 opProp{"SUB", false, true, opArgModeK, opArgModeK, opTypeABC}, 146 opProp{"MUL", false, true, opArgModeK, opArgModeK, opTypeABC}, 147 opProp{"DIV", false, true, opArgModeK, opArgModeK, opTypeABC}, 148 opProp{"MOD", false, true, opArgModeK, opArgModeK, opTypeABC}, 149 opProp{"POW", false, true, opArgModeK, opArgModeK, opTypeABC}, 150 opProp{"UNM", false, true, opArgModeR, opArgModeN, opTypeABC}, 151 opProp{"NOT", false, true, opArgModeR, opArgModeN, opTypeABC}, 152 opProp{"LEN", false, true, opArgModeR, opArgModeN, opTypeABC}, 153 opProp{"CONCAT", false, true, opArgModeR, opArgModeR, opTypeABC}, 154 opProp{"JMP", false, false, opArgModeR, opArgModeN, opTypeASbx}, 155 opProp{"EQ", true, false, opArgModeK, opArgModeK, opTypeABC}, 156 opProp{"LT", true, false, opArgModeK, opArgModeK, opTypeABC}, 157 opProp{"LE", true, false, opArgModeK, opArgModeK, opTypeABC}, 158 opProp{"TEST", true, true, opArgModeR, opArgModeU, opTypeABC}, 159 opProp{"TESTSET", true, true, opArgModeR, opArgModeU, opTypeABC}, 160 opProp{"CALL", false, true, opArgModeU, opArgModeU, opTypeABC}, 161 opProp{"TAILCALL", false, true, opArgModeU, opArgModeU, opTypeABC}, 162 opProp{"RETURN", false, false, opArgModeU, opArgModeN, opTypeABC}, 163 opProp{"FORLOOP", false, true, opArgModeR, opArgModeN, opTypeASbx}, 164 opProp{"FORPREP", false, true, opArgModeR, opArgModeN, opTypeASbx}, 165 opProp{"TFORLOOP", true, false, opArgModeN, opArgModeU, opTypeABC}, 166 opProp{"SETLIST", false, false, opArgModeU, opArgModeU, opTypeABC}, 167 opProp{"CLOSE", false, false, opArgModeN, opArgModeN, opTypeABC}, 168 opProp{"CLOSURE", false, true, opArgModeU, opArgModeN, opTypeABx}, 169 opProp{"VARARG", false, true, opArgModeU, opArgModeN, opTypeABC}, 170 opProp{"NOP", false, false, opArgModeR, opArgModeN, opTypeASbx}, 171 } 172 173 func opGetOpCode(inst uint32) int { 174 return int(inst >> 26) 175 } 176 177 func opSetOpCode(inst *uint32, opcode int) { 178 *inst = (*inst & 0x3ffffff) | uint32(opcode<<26) 179 } 180 181 func opGetArgA(inst uint32) int { 182 return int(inst>>18) & 0xff 183 } 184 185 func opSetArgA(inst *uint32, arg int) { 186 *inst = (*inst & 0xfc03ffff) | uint32((arg&0xff)<<18) 187 } 188 189 func opGetArgB(inst uint32) int { 190 return int(inst & 0x1ff) 191 } 192 193 func opSetArgB(inst *uint32, arg int) { 194 *inst = (*inst & 0xfffffe00) | uint32(arg&0x1ff) 195 } 196 197 func opGetArgC(inst uint32) int { 198 return int(inst>>9) & 0x1ff 199 } 200 201 func opSetArgC(inst *uint32, arg int) { 202 *inst = (*inst & 0xfffc01ff) | uint32((arg&0x1ff)<<9) 203 } 204 205 func opGetArgBx(inst uint32) int { 206 return int(inst & 0x3ffff) 207 } 208 209 func opSetArgBx(inst *uint32, arg int) { 210 *inst = (*inst & 0xfffc0000) | uint32(arg&0x3ffff) 211 } 212 213 func opGetArgSbx(inst uint32) int { 214 return opGetArgBx(inst) - opMaxArgSbx 215 } 216 217 func opSetArgSbx(inst *uint32, arg int) { 218 opSetArgBx(inst, arg+opMaxArgSbx) 219 } 220 221 func opCreateABC(op int, a int, b int, c int) uint32 { 222 var inst uint32 = 0 223 opSetOpCode(&inst, op) 224 opSetArgA(&inst, a) 225 opSetArgB(&inst, b) 226 opSetArgC(&inst, c) 227 return inst 228 } 229 230 func opCreateABx(op int, a int, bx int) uint32 { 231 var inst uint32 = 0 232 opSetOpCode(&inst, op) 233 opSetArgA(&inst, a) 234 opSetArgBx(&inst, bx) 235 return inst 236 } 237 238 func opCreateASbx(op int, a int, sbx int) uint32 { 239 var inst uint32 = 0 240 opSetOpCode(&inst, op) 241 opSetArgA(&inst, a) 242 opSetArgSbx(&inst, sbx) 243 return inst 244 } 245 246 const opBitRk = 1 << (opSizeB - 1) 247 const opMaxIndexRk = opBitRk - 1 248 249 func opIsK(value int) bool { 250 return bool((value & opBitRk) != 0) 251 } 252 253 func opIndexK(value int) int { 254 return value & ^opBitRk 255 } 256 257 func opRkAsk(value int) int { 258 return value | opBitRk 259 } 260 261 func opToString(inst uint32) string { 262 op := opGetOpCode(inst) 263 if op > opCodeMax { 264 return "" 265 } 266 prop := &(opProps[op]) 267 268 arga := opGetArgA(inst) 269 argb := opGetArgB(inst) 270 argc := opGetArgC(inst) 271 argbx := opGetArgBx(inst) 272 argsbx := opGetArgSbx(inst) 273 274 buf := "" 275 switch prop.Type { 276 case opTypeABC: 277 buf = fmt.Sprintf("%s | %d, %d, %d", prop.Name, arga, argb, argc) 278 case opTypeABx: 279 buf = fmt.Sprintf("%s | %d, %d", prop.Name, arga, argbx) 280 case opTypeASbx: 281 buf = fmt.Sprintf("%s | %d, %d", prop.Name, arga, argsbx) 282 } 283 284 switch op { 285 case OP_MOVE: 286 buf += fmt.Sprintf("; R(%v) := R(%v)", arga, argb) 287 case OP_MOVEN: 288 buf += fmt.Sprintf("; R(%v) := R(%v); followed by %v MOVE ops", arga, argb, argc) 289 case OP_LOADK: 290 buf += fmt.Sprintf("; R(%v) := Kst(%v)", arga, argbx) 291 case OP_LOADBOOL: 292 buf += fmt.Sprintf("; R(%v) := (Bool)%v; if (%v) pc++", arga, argb, argc) 293 case OP_LOADNIL: 294 buf += fmt.Sprintf("; R(%v) := ... := R(%v) := nil", arga, argb) 295 case OP_GETUPVAL: 296 buf += fmt.Sprintf("; R(%v) := UpValue[%v]", arga, argb) 297 case OP_GETGLOBAL: 298 buf += fmt.Sprintf("; R(%v) := Gbl[Kst(%v)]", arga, argbx) 299 case OP_GETTABLE: 300 buf += fmt.Sprintf("; R(%v) := R(%v)[RK(%v)]", arga, argb, argc) 301 case OP_GETTABLEKS: 302 buf += fmt.Sprintf("; R(%v) := R(%v)[RK(%v)] ; RK(%v) is constant string", arga, argb, argc, argc) 303 case OP_SETGLOBAL: 304 buf += fmt.Sprintf("; Gbl[Kst(%v)] := R(%v)", argbx, arga) 305 case OP_SETUPVAL: 306 buf += fmt.Sprintf("; UpValue[%v] := R(%v)", argb, arga) 307 case OP_SETTABLE: 308 buf += fmt.Sprintf("; R(%v)[RK(%v)] := RK(%v)", arga, argb, argc) 309 case OP_SETTABLEKS: 310 buf += fmt.Sprintf("; R(%v)[RK(%v)] := RK(%v) ; RK(%v) is constant string", arga, argb, argc, argb) 311 case OP_NEWTABLE: 312 buf += fmt.Sprintf("; R(%v) := {} (size = BC)", arga) 313 case OP_SELF: 314 buf += fmt.Sprintf("; R(%v+1) := R(%v); R(%v) := R(%v)[RK(%v)]", arga, argb, arga, argb, argc) 315 case OP_ADD: 316 buf += fmt.Sprintf("; R(%v) := RK(%v) + RK(%v)", arga, argb, argc) 317 case OP_SUB: 318 buf += fmt.Sprintf("; R(%v) := RK(%v) - RK(%v)", arga, argb, argc) 319 case OP_MUL: 320 buf += fmt.Sprintf("; R(%v) := RK(%v) * RK(%v)", arga, argb, argc) 321 case OP_DIV: 322 buf += fmt.Sprintf("; R(%v) := RK(%v) / RK(%v)", arga, argb, argc) 323 case OP_MOD: 324 buf += fmt.Sprintf("; R(%v) := RK(%v) %% RK(%v)", arga, argb, argc) 325 case OP_POW: 326 buf += fmt.Sprintf("; R(%v) := RK(%v) ^ RK(%v)", arga, argb, argc) 327 case OP_UNM: 328 buf += fmt.Sprintf("; R(%v) := -R(%v)", arga, argb) 329 case OP_NOT: 330 buf += fmt.Sprintf("; R(%v) := not R(%v)", arga, argb) 331 case OP_LEN: 332 buf += fmt.Sprintf("; R(%v) := length of R(%v)", arga, argb) 333 case OP_CONCAT: 334 buf += fmt.Sprintf("; R(%v) := R(%v).. ... ..R(%v)", arga, argb, argc) 335 case OP_JMP: 336 buf += fmt.Sprintf("; pc+=%v", argsbx) 337 case OP_EQ: 338 buf += fmt.Sprintf("; if ((RK(%v) == RK(%v)) ~= %v) then pc++", argb, argc, arga) 339 case OP_LT: 340 buf += fmt.Sprintf("; if ((RK(%v) < RK(%v)) ~= %v) then pc++", argb, argc, arga) 341 case OP_LE: 342 buf += fmt.Sprintf("; if ((RK(%v) <= RK(%v)) ~= %v) then pc++", argb, argc, arga) 343 case OP_TEST: 344 buf += fmt.Sprintf("; if not (R(%v) <=> %v) then pc++", arga, argc) 345 case OP_TESTSET: 346 buf += fmt.Sprintf("; if (R(%v) <=> %v) then R(%v) := R(%v) else pc++", argb, argc, arga, argb) 347 case OP_CALL: 348 buf += fmt.Sprintf("; R(%v) ... R(%v+%v-2) := R(%v)(R(%v+1) ... R(%v+%v-1))", arga, arga, argc, arga, arga, arga, argb) 349 case OP_TAILCALL: 350 buf += fmt.Sprintf("; return R(%v)(R(%v+1) ... R(%v+%v-1))", arga, arga, arga, argb) 351 case OP_RETURN: 352 buf += fmt.Sprintf("; return R(%v) ... R(%v+%v-2)", arga, arga, argb) 353 case OP_FORLOOP: 354 buf += fmt.Sprintf("; R(%v)+=R(%v+2); if R(%v) <?= R(%v+1) then { pc+=%v; R(%v+3)=R(%v) }", arga, arga, arga, arga, argsbx, arga, arga) 355 case OP_FORPREP: 356 buf += fmt.Sprintf("; R(%v)-=R(%v+2); pc+=%v", arga, arga, argsbx) 357 case OP_TFORLOOP: 358 buf += fmt.Sprintf("; R(%v+3) ... R(%v+3+%v) := R(%v)(R(%v+1) R(%v+2)); if R(%v+3) ~= nil then { pc++; R(%v+2)=R(%v+3); }", arga, arga, argc, arga, arga, arga, arga, arga, arga) 359 case OP_SETLIST: 360 buf += fmt.Sprintf("; R(%v)[(%v-1)*FPF+i] := R(%v+i) 1 <= i <= %v", arga, argc, arga, argb) 361 case OP_CLOSE: 362 buf += fmt.Sprintf("; close all variables in the stack up to (>=) R(%v)", arga) 363 case OP_CLOSURE: 364 buf += fmt.Sprintf("; R(%v) := closure(KPROTO[%v] R(%v) ... R(%v+n))", arga, argbx, arga, arga) 365 case OP_VARARG: 366 buf += fmt.Sprintf("; R(%v) R(%v+1) ... R(%v+%v-1) = vararg", arga, arga, arga, argb) 367 case OP_NOP: 368 /* nothing to do */ 369 } 370 return buf 371 }