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