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  }