github.com/vivi-app/lua@v1.5.0/_vm.go (about)

     1  package lua
     2  
     3  import (
     4  	"fmt"
     5  	"math"
     6  	"strings"
     7  )
     8  
     9  func mainLoop(L *LState, baseframe *callFrame) {
    10  	var inst uint32
    11  	var cf *callFrame
    12  
    13  	if L.stack.IsEmpty() {
    14  		return
    15  	}
    16  
    17  	L.currentFrame = L.stack.Last()
    18  	if L.currentFrame.Fn.IsG {
    19  		callGFunction(L, false)
    20  		return
    21  	}
    22  
    23  	for {
    24  		cf = L.currentFrame
    25  		inst = cf.Fn.Proto.Code[cf.Pc]
    26  		cf.Pc++
    27  		if jumpTable[int(inst>>26)](L, inst, baseframe) == 1 {
    28  			return
    29  		}
    30  	}
    31  }
    32  
    33  func mainLoopWithContext(L *LState, baseframe *callFrame) {
    34  	var inst uint32
    35  	var cf *callFrame
    36  
    37  	if L.stack.IsEmpty() {
    38  		return
    39  	}
    40  
    41  	L.currentFrame = L.stack.Last()
    42  	if L.currentFrame.Fn.IsG {
    43  		callGFunction(L, false)
    44  		return
    45  	}
    46  
    47  	for {
    48  		cf = L.currentFrame
    49  		inst = cf.Fn.Proto.Code[cf.Pc]
    50  		cf.Pc++
    51  		select {
    52  		case <-L.ctx.Done():
    53  			L.RaiseError(L.ctx.Err().Error())
    54  			return
    55  		default:
    56  			if jumpTable[int(inst>>26)](L, inst, baseframe) == 1 {
    57  				return
    58  			}
    59  		}
    60  	}
    61  }
    62  
    63  // regv is the first target register to copy the return values to.
    64  // It can be reg.top, indicating that the copied values are going into new registers, or it can be below reg.top
    65  // Indicating that the values should be within the existing registers.
    66  // b is the available number of return values + 1.
    67  // n is the desired number of return values.
    68  // If n more than the available return values then the extra values are set to nil.
    69  // When this function returns the top of the registry will be set to regv+n.
    70  func copyReturnValues(L *LState, regv, start, n, b int) { // +inline-start
    71  	if b == 1 {
    72  		// +inline-call L.reg.FillNil  regv n
    73  	} else {
    74  		// +inline-call L.reg.CopyRange regv start -1 n
    75  		if b > 1 && n > (b-1) {
    76  			// +inline-call L.reg.FillNil  regv+b-1 n-(b-1)
    77  		}
    78  	}
    79  } // +inline-end
    80  
    81  func switchToParentThread(L *LState, nargs int, haserror bool, kill bool) {
    82  	parent := L.Parent
    83  	if parent == nil {
    84  		L.RaiseError("can not yield from outside of a coroutine")
    85  	}
    86  	L.G.CurrentThread = parent
    87  	L.Parent = nil
    88  	if !L.wrapped {
    89  		if haserror {
    90  			parent.Push(LFalse)
    91  		} else {
    92  			parent.Push(LTrue)
    93  		}
    94  	}
    95  	L.XMoveTo(parent, nargs)
    96  	L.stack.Pop()
    97  	offset := L.currentFrame.LocalBase - L.currentFrame.ReturnBase
    98  	L.currentFrame = L.stack.Last()
    99  	L.reg.SetTop(L.reg.Top() - offset) // remove 'yield' function(including tailcalled functions)
   100  	if kill {
   101  		L.kill()
   102  	}
   103  }
   104  
   105  func callGFunction(L *LState, tailcall bool) bool {
   106  	frame := L.currentFrame
   107  	gfnret := frame.Fn.GFunction(L)
   108  	if tailcall {
   109  		L.currentFrame = L.RemoveCallerFrame()
   110  	}
   111  
   112  	if gfnret < 0 {
   113  		switchToParentThread(L, L.GetTop(), false, false)
   114  		return true
   115  	}
   116  
   117  	wantret := frame.NRet
   118  	if wantret == MultRet {
   119  		wantret = gfnret
   120  	}
   121  
   122  	if tailcall && L.Parent != nil && L.stack.Sp() == 1 {
   123  		switchToParentThread(L, wantret, false, true)
   124  		return true
   125  	}
   126  
   127  	// +inline-call L.reg.CopyRange frame.ReturnBase L.reg.Top()-gfnret -1 wantret
   128  	L.stack.Pop()
   129  	L.currentFrame = L.stack.Last()
   130  	return false
   131  }
   132  
   133  func threadRun(L *LState) {
   134  	if L.stack.IsEmpty() {
   135  		return
   136  	}
   137  
   138  	defer func() {
   139  		if rcv := recover(); rcv != nil {
   140  			var lv LValue
   141  			if v, ok := rcv.(*ApiError); ok {
   142  				lv = v.Object
   143  			} else {
   144  				lv = LString(fmt.Sprint(rcv))
   145  			}
   146  			if parent := L.Parent; parent != nil {
   147  				if L.wrapped {
   148  					L.Push(lv)
   149  					parent.Panic(L)
   150  				} else {
   151  					L.SetTop(0)
   152  					L.Push(lv)
   153  					switchToParentThread(L, 1, true, true)
   154  				}
   155  			} else {
   156  				panic(rcv)
   157  			}
   158  		}
   159  	}()
   160  	L.mainLoop(L, nil)
   161  }
   162  
   163  type instFunc func(*LState, uint32, *callFrame) int
   164  
   165  var jumpTable [opCodeMax + 1]instFunc
   166  
   167  func init() {
   168  	jumpTable = [opCodeMax + 1]instFunc{
   169  		func(L *LState, inst uint32, baseframe *callFrame) int { //OP_MOVE
   170  			reg := L.reg
   171  			cf := L.currentFrame
   172  			lbase := cf.LocalBase
   173  			A := int(inst>>18) & 0xff //GETA
   174  			RA := lbase + A
   175  			B := int(inst & 0x1ff) //GETB
   176  			reg.Set(RA, reg.Get(lbase+B))
   177  			return 0
   178  		},
   179  		func(L *LState, inst uint32, baseframe *callFrame) int { //OP_MOVEN
   180  			reg := L.reg
   181  			cf := L.currentFrame
   182  			lbase := cf.LocalBase
   183  			A := int(inst>>18) & 0xff //GETA
   184  			B := int(inst & 0x1ff)    //GETB
   185  			C := int(inst>>9) & 0x1ff //GETC
   186  			reg.Set(lbase+A, reg.Get(lbase+B))
   187  			code := cf.Fn.Proto.Code
   188  			pc := cf.Pc
   189  			for i := 0; i < C; i++ {
   190  				inst = code[pc]
   191  				pc++
   192  				A = int(inst>>18) & 0xff //GETA
   193  				B = int(inst & 0x1ff)    //GETB
   194  				reg.Set(lbase+A, reg.Get(lbase+B))
   195  			}
   196  			cf.Pc = pc
   197  			return 0
   198  		},
   199  		func(L *LState, inst uint32, baseframe *callFrame) int { //OP_LOADK
   200  			reg := L.reg
   201  			cf := L.currentFrame
   202  			lbase := cf.LocalBase
   203  			A := int(inst>>18) & 0xff //GETA
   204  			RA := lbase + A
   205  			Bx := int(inst & 0x3ffff) //GETBX
   206  			reg.Set(RA, cf.Fn.Proto.Constants[Bx])
   207  			return 0
   208  		},
   209  		func(L *LState, inst uint32, baseframe *callFrame) int { //OP_LOADBOOL
   210  			reg := L.reg
   211  			cf := L.currentFrame
   212  			lbase := cf.LocalBase
   213  			A := int(inst>>18) & 0xff //GETA
   214  			RA := lbase + A
   215  			B := int(inst & 0x1ff)    //GETB
   216  			C := int(inst>>9) & 0x1ff //GETC
   217  			if B != 0 {
   218  				reg.Set(RA, LTrue)
   219  			} else {
   220  				reg.Set(RA, LFalse)
   221  			}
   222  			if C != 0 {
   223  				cf.Pc++
   224  			}
   225  			return 0
   226  		},
   227  		func(L *LState, inst uint32, baseframe *callFrame) int { //OP_LOADNIL
   228  			reg := L.reg
   229  			cf := L.currentFrame
   230  			lbase := cf.LocalBase
   231  			A := int(inst>>18) & 0xff //GETA
   232  			RA := lbase + A
   233  			B := int(inst & 0x1ff) //GETB
   234  			for i := RA; i <= lbase+B; i++ {
   235  				reg.Set(i, LNil)
   236  			}
   237  			return 0
   238  		},
   239  		func(L *LState, inst uint32, baseframe *callFrame) int { //OP_GETUPVAL
   240  			reg := L.reg
   241  			cf := L.currentFrame
   242  			lbase := cf.LocalBase
   243  			A := int(inst>>18) & 0xff //GETA
   244  			RA := lbase + A
   245  			B := int(inst & 0x1ff) //GETB
   246  			reg.Set(RA, cf.Fn.Upvalues[B].Value())
   247  			return 0
   248  		},
   249  		func(L *LState, inst uint32, baseframe *callFrame) int { //OP_GETGLOBAL
   250  			reg := L.reg
   251  			cf := L.currentFrame
   252  			lbase := cf.LocalBase
   253  			A := int(inst>>18) & 0xff //GETA
   254  			RA := lbase + A
   255  			Bx := int(inst & 0x3ffff) //GETBX
   256  			//reg.Set(RA, L.getField(cf.Fn.Env, cf.Fn.Proto.Constants[Bx]))
   257  			reg.Set(RA, L.getFieldString(cf.Fn.Env, cf.Fn.Proto.stringConstants[Bx]))
   258  			return 0
   259  		},
   260  		func(L *LState, inst uint32, baseframe *callFrame) int { //OP_GETTABLE
   261  			reg := L.reg
   262  			cf := L.currentFrame
   263  			lbase := cf.LocalBase
   264  			A := int(inst>>18) & 0xff //GETA
   265  			RA := lbase + A
   266  			B := int(inst & 0x1ff)    //GETB
   267  			C := int(inst>>9) & 0x1ff //GETC
   268  			reg.Set(RA, L.getField(reg.Get(lbase+B), L.rkValue(C)))
   269  			return 0
   270  		},
   271  		func(L *LState, inst uint32, baseframe *callFrame) int { //OP_GETTABLEKS
   272  			reg := L.reg
   273  			cf := L.currentFrame
   274  			lbase := cf.LocalBase
   275  			A := int(inst>>18) & 0xff //GETA
   276  			RA := lbase + A
   277  			B := int(inst & 0x1ff)    //GETB
   278  			C := int(inst>>9) & 0x1ff //GETC
   279  			reg.Set(RA, L.getFieldString(reg.Get(lbase+B), L.rkString(C)))
   280  			return 0
   281  		},
   282  		func(L *LState, inst uint32, baseframe *callFrame) int { //OP_SETGLOBAL
   283  			reg := L.reg
   284  			cf := L.currentFrame
   285  			lbase := cf.LocalBase
   286  			A := int(inst>>18) & 0xff //GETA
   287  			RA := lbase + A
   288  			Bx := int(inst & 0x3ffff) //GETBX
   289  			//L.setField(cf.Fn.Env, cf.Fn.Proto.Constants[Bx], reg.Get(RA))
   290  			L.setFieldString(cf.Fn.Env, cf.Fn.Proto.stringConstants[Bx], reg.Get(RA))
   291  			return 0
   292  		},
   293  		func(L *LState, inst uint32, baseframe *callFrame) int { //OP_SETUPVAL
   294  			reg := L.reg
   295  			cf := L.currentFrame
   296  			lbase := cf.LocalBase
   297  			A := int(inst>>18) & 0xff //GETA
   298  			RA := lbase + A
   299  			B := int(inst & 0x1ff) //GETB
   300  			cf.Fn.Upvalues[B].SetValue(reg.Get(RA))
   301  			return 0
   302  		},
   303  		func(L *LState, inst uint32, baseframe *callFrame) int { //OP_SETTABLE
   304  			reg := L.reg
   305  			cf := L.currentFrame
   306  			lbase := cf.LocalBase
   307  			A := int(inst>>18) & 0xff //GETA
   308  			RA := lbase + A
   309  			B := int(inst & 0x1ff)    //GETB
   310  			C := int(inst>>9) & 0x1ff //GETC
   311  			L.setField(reg.Get(RA), L.rkValue(B), L.rkValue(C))
   312  			return 0
   313  		},
   314  		func(L *LState, inst uint32, baseframe *callFrame) int { //OP_SETTABLEKS
   315  			reg := L.reg
   316  			cf := L.currentFrame
   317  			lbase := cf.LocalBase
   318  			A := int(inst>>18) & 0xff //GETA
   319  			RA := lbase + A
   320  			B := int(inst & 0x1ff)    //GETB
   321  			C := int(inst>>9) & 0x1ff //GETC
   322  			L.setFieldString(reg.Get(RA), L.rkString(B), L.rkValue(C))
   323  			return 0
   324  		},
   325  		func(L *LState, inst uint32, baseframe *callFrame) int { //OP_NEWTABLE
   326  			reg := L.reg
   327  			cf := L.currentFrame
   328  			lbase := cf.LocalBase
   329  			A := int(inst>>18) & 0xff //GETA
   330  			RA := lbase + A
   331  			B := int(inst & 0x1ff)    //GETB
   332  			C := int(inst>>9) & 0x1ff //GETC
   333  			reg.Set(RA, newLTable(B, C))
   334  			return 0
   335  		},
   336  		func(L *LState, inst uint32, baseframe *callFrame) int { //OP_SELF
   337  			reg := L.reg
   338  			cf := L.currentFrame
   339  			lbase := cf.LocalBase
   340  			A := int(inst>>18) & 0xff //GETA
   341  			RA := lbase + A
   342  			B := int(inst & 0x1ff)    //GETB
   343  			C := int(inst>>9) & 0x1ff //GETC
   344  			selfobj := reg.Get(lbase + B)
   345  			reg.Set(RA, L.getFieldString(selfobj, L.rkString(C)))
   346  			reg.Set(RA+1, selfobj)
   347  			return 0
   348  		},
   349  		opArith, // OP_ADD
   350  		opArith, // OP_SUB
   351  		opArith, // OP_MUL
   352  		opArith, // OP_DIV
   353  		opArith, // OP_MOD
   354  		opArith, // OP_POW
   355  		func(L *LState, inst uint32, baseframe *callFrame) int { //OP_UNM
   356  			reg := L.reg
   357  			cf := L.currentFrame
   358  			lbase := cf.LocalBase
   359  			A := int(inst>>18) & 0xff //GETA
   360  			RA := lbase + A
   361  			B := int(inst & 0x1ff) //GETB
   362  			unaryv := L.rkValue(B)
   363  			if nm, ok := unaryv.(LNumber); ok {
   364  				reg.SetNumber(RA, -nm)
   365  			} else {
   366  				op := L.metaOp1(unaryv, "__unm")
   367  				if op.Type() == LTFunction {
   368  					reg.Push(op)
   369  					reg.Push(unaryv)
   370  					L.Call(1, 1)
   371  					reg.Set(RA, reg.Pop())
   372  				} else if str, ok1 := unaryv.(LString); ok1 {
   373  					if num, err := parseNumber(string(str)); err == nil {
   374  						reg.Set(RA, -num)
   375  					} else {
   376  						L.RaiseError("__unm undefined")
   377  					}
   378  				} else {
   379  					L.RaiseError("__unm undefined")
   380  				}
   381  			}
   382  			return 0
   383  		},
   384  		func(L *LState, inst uint32, baseframe *callFrame) int { //OP_NOT
   385  			reg := L.reg
   386  			cf := L.currentFrame
   387  			lbase := cf.LocalBase
   388  			A := int(inst>>18) & 0xff //GETA
   389  			RA := lbase + A
   390  			B := int(inst & 0x1ff) //GETB
   391  			if LVIsFalse(reg.Get(lbase + B)) {
   392  				reg.Set(RA, LTrue)
   393  			} else {
   394  				reg.Set(RA, LFalse)
   395  			}
   396  			return 0
   397  		},
   398  		func(L *LState, inst uint32, baseframe *callFrame) int { //OP_LEN
   399  			reg := L.reg
   400  			cf := L.currentFrame
   401  			lbase := cf.LocalBase
   402  			A := int(inst>>18) & 0xff //GETA
   403  			RA := lbase + A
   404  			B := int(inst & 0x1ff) //GETB
   405  			switch lv := L.rkValue(B).(type) {
   406  			case LString:
   407  				reg.SetNumber(RA, LNumber(len(lv)))
   408  			default:
   409  				op := L.metaOp1(lv, "__len")
   410  				if op.Type() == LTFunction {
   411  					reg.Push(op)
   412  					reg.Push(lv)
   413  					L.Call(1, 1)
   414  					ret := reg.Pop()
   415  					if ret.Type() == LTNumber {
   416  						reg.SetNumber(RA, ret.(LNumber))
   417  					} else {
   418  						reg.Set(RA, ret)
   419  					}
   420  				} else if lv.Type() == LTTable {
   421  					reg.SetNumber(RA, LNumber(lv.(*LTable).Len()))
   422  				} else {
   423  					L.RaiseError("__len undefined")
   424  				}
   425  			}
   426  			return 0
   427  		},
   428  		func(L *LState, inst uint32, baseframe *callFrame) int { //OP_CONCAT
   429  			reg := L.reg
   430  			cf := L.currentFrame
   431  			lbase := cf.LocalBase
   432  			A := int(inst>>18) & 0xff //GETA
   433  			RA := lbase + A
   434  			B := int(inst & 0x1ff)    //GETB
   435  			C := int(inst>>9) & 0x1ff //GETC
   436  			RC := lbase + C
   437  			RB := lbase + B
   438  			reg.Set(RA, stringConcat(L, RC-RB+1, RC))
   439  			return 0
   440  		},
   441  		func(L *LState, inst uint32, baseframe *callFrame) int { //OP_JMP
   442  			cf := L.currentFrame
   443  			Sbx := int(inst&0x3ffff) - opMaxArgSbx //GETSBX
   444  			cf.Pc += Sbx
   445  			return 0
   446  		},
   447  		func(L *LState, inst uint32, baseframe *callFrame) int { //OP_EQ
   448  			cf := L.currentFrame
   449  			A := int(inst>>18) & 0xff //GETA
   450  			B := int(inst & 0x1ff)    //GETB
   451  			C := int(inst>>9) & 0x1ff //GETC
   452  			ret := equals(L, L.rkValue(B), L.rkValue(C), false)
   453  			v := 1
   454  			if ret {
   455  				v = 0
   456  			}
   457  			if v == A {
   458  				cf.Pc++
   459  			}
   460  			return 0
   461  		},
   462  		func(L *LState, inst uint32, baseframe *callFrame) int { //OP_LT
   463  			cf := L.currentFrame
   464  			A := int(inst>>18) & 0xff //GETA
   465  			B := int(inst & 0x1ff)    //GETB
   466  			C := int(inst>>9) & 0x1ff //GETC
   467  			ret := lessThan(L, L.rkValue(B), L.rkValue(C))
   468  			v := 1
   469  			if ret {
   470  				v = 0
   471  			}
   472  			if v == A {
   473  				cf.Pc++
   474  			}
   475  			return 0
   476  		},
   477  		func(L *LState, inst uint32, baseframe *callFrame) int { //OP_LE
   478  			cf := L.currentFrame
   479  			A := int(inst>>18) & 0xff //GETA
   480  			B := int(inst & 0x1ff)    //GETB
   481  			C := int(inst>>9) & 0x1ff //GETC
   482  			lhs := L.rkValue(B)
   483  			rhs := L.rkValue(C)
   484  			ret := false
   485  
   486  			if v1, ok1 := lhs.assertFloat64(); ok1 {
   487  				if v2, ok2 := rhs.assertFloat64(); ok2 {
   488  					ret = v1 <= v2
   489  				} else {
   490  					L.RaiseError("attempt to compare %v with %v", lhs.Type().String(), rhs.Type().String())
   491  				}
   492  			} else {
   493  				if lhs.Type() != rhs.Type() {
   494  					L.RaiseError("attempt to compare %v with %v", lhs.Type().String(), rhs.Type().String())
   495  				}
   496  				switch lhs.Type() {
   497  				case LTString:
   498  					ret = strCmp(string(lhs.(LString)), string(rhs.(LString))) <= 0
   499  				default:
   500  					switch objectRational(L, lhs, rhs, "__le") {
   501  					case 1:
   502  						ret = true
   503  					case 0:
   504  						ret = false
   505  					default:
   506  						ret = !objectRationalWithError(L, rhs, lhs, "__lt")
   507  					}
   508  				}
   509  			}
   510  
   511  			v := 1
   512  			if ret {
   513  				v = 0
   514  			}
   515  			if v == A {
   516  				cf.Pc++
   517  			}
   518  			return 0
   519  		},
   520  		func(L *LState, inst uint32, baseframe *callFrame) int { //OP_TEST
   521  			reg := L.reg
   522  			cf := L.currentFrame
   523  			lbase := cf.LocalBase
   524  			A := int(inst>>18) & 0xff //GETA
   525  			RA := lbase + A
   526  			C := int(inst>>9) & 0x1ff //GETC
   527  			if LVAsBool(reg.Get(RA)) == (C == 0) {
   528  				cf.Pc++
   529  			}
   530  			return 0
   531  		},
   532  		func(L *LState, inst uint32, baseframe *callFrame) int { //OP_TESTSET
   533  			reg := L.reg
   534  			cf := L.currentFrame
   535  			lbase := cf.LocalBase
   536  			A := int(inst>>18) & 0xff //GETA
   537  			RA := lbase + A
   538  			B := int(inst & 0x1ff)    //GETB
   539  			C := int(inst>>9) & 0x1ff //GETC
   540  			if value := reg.Get(lbase + B); LVAsBool(value) != (C == 0) {
   541  				reg.Set(RA, value)
   542  			} else {
   543  				cf.Pc++
   544  			}
   545  			return 0
   546  		},
   547  		func(L *LState, inst uint32, baseframe *callFrame) int { //OP_CALL
   548  			reg := L.reg
   549  			cf := L.currentFrame
   550  			lbase := cf.LocalBase
   551  			A := int(inst>>18) & 0xff //GETA
   552  			RA := lbase + A
   553  			B := int(inst & 0x1ff)    //GETB
   554  			C := int(inst>>9) & 0x1ff //GETC
   555  			nargs := B - 1
   556  			if B == 0 {
   557  				nargs = reg.Top() - (RA + 1)
   558  			}
   559  			lv := reg.Get(RA)
   560  			nret := C - 1
   561  			var callable *LFunction
   562  			var meta bool
   563  			if fn, ok := lv.assertFunction(); ok {
   564  				callable = fn
   565  				meta = false
   566  			} else {
   567  				callable, meta = L.metaCall(lv)
   568  			}
   569  			// +inline-call L.pushCallFrame callFrame{Fn:callable,Pc:0,Base:RA,LocalBase:RA+1,ReturnBase:RA,NArgs:nargs,NRet:nret,Parent:cf,TailCall:0} lv meta
   570  			if callable.IsG && callGFunction(L, false) {
   571  				return 1
   572  			}
   573  			return 0
   574  		},
   575  		func(L *LState, inst uint32, baseframe *callFrame) int { //OP_TAILCALL
   576  			reg := L.reg
   577  			cf := L.currentFrame
   578  			lbase := cf.LocalBase
   579  			A := int(inst>>18) & 0xff //GETA
   580  			RA := lbase + A
   581  			B := int(inst & 0x1ff) //GETB
   582  			nargs := B - 1
   583  			if B == 0 {
   584  				nargs = reg.Top() - (RA + 1)
   585  			}
   586  			lv := reg.Get(RA)
   587  			var callable *LFunction
   588  			var meta bool
   589  			if fn, ok := lv.assertFunction(); ok {
   590  				callable = fn
   591  				meta = false
   592  			} else {
   593  				callable, meta = L.metaCall(lv)
   594  			}
   595  			if callable == nil {
   596  				L.RaiseError("attempt to call a non-function object")
   597  			}
   598  			// +inline-call L.closeUpvalues lbase
   599  			if callable.IsG {
   600  				luaframe := cf
   601  				L.pushCallFrame(callFrame{
   602  					Fn:         callable,
   603  					Pc:         0,
   604  					Base:       RA,
   605  					LocalBase:  RA + 1,
   606  					ReturnBase: cf.ReturnBase,
   607  					NArgs:      nargs,
   608  					NRet:       cf.NRet,
   609  					Parent:     cf,
   610  					TailCall:   0,
   611  				}, lv, meta)
   612  				if callGFunction(L, true) {
   613  					return 1
   614  				}
   615  				if L.currentFrame == nil || L.currentFrame.Fn.IsG || luaframe == baseframe {
   616  					return 1
   617  				}
   618  			} else {
   619  				base := cf.Base
   620  				cf.Fn = callable
   621  				cf.Pc = 0
   622  				cf.Base = RA
   623  				cf.LocalBase = RA + 1
   624  				cf.ReturnBase = cf.ReturnBase
   625  				cf.NArgs = nargs
   626  				cf.NRet = cf.NRet
   627  				cf.TailCall++
   628  				lbase := cf.LocalBase
   629  				if meta {
   630  					cf.NArgs++
   631  					L.reg.Insert(lv, cf.LocalBase)
   632  				}
   633  				// +inline-call L.initCallFrame cf
   634  				// +inline-call L.reg.CopyRange base RA -1 reg.Top()-RA-1
   635  				cf.Base = base
   636  				cf.LocalBase = base + (cf.LocalBase - lbase + 1)
   637  			}
   638  			return 0
   639  		},
   640  		func(L *LState, inst uint32, baseframe *callFrame) int { //OP_RETURN
   641  			reg := L.reg
   642  			cf := L.currentFrame
   643  			lbase := cf.LocalBase
   644  			A := int(inst>>18) & 0xff //GETA
   645  			RA := lbase + A
   646  			B := int(inst & 0x1ff) //GETB
   647  			// +inline-call L.closeUpvalues lbase
   648  			nret := B - 1
   649  			if B == 0 {
   650  				nret = reg.Top() - RA
   651  			}
   652  			n := cf.NRet
   653  			if cf.NRet == MultRet {
   654  				n = nret
   655  			}
   656  
   657  			if L.Parent != nil && L.stack.Sp() == 1 {
   658  				// +inline-call copyReturnValues L reg.Top() RA n B
   659  				switchToParentThread(L, n, false, true)
   660  				return 1
   661  			}
   662  			islast := baseframe == L.stack.Pop() || L.stack.IsEmpty()
   663  			// +inline-call copyReturnValues L cf.ReturnBase RA n B
   664  			L.currentFrame = L.stack.Last()
   665  			if islast || L.currentFrame == nil || L.currentFrame.Fn.IsG {
   666  				return 1
   667  			}
   668  			return 0
   669  		},
   670  		func(L *LState, inst uint32, baseframe *callFrame) int { //OP_FORLOOP
   671  			reg := L.reg
   672  			cf := L.currentFrame
   673  			lbase := cf.LocalBase
   674  			A := int(inst>>18) & 0xff //GETA
   675  			RA := lbase + A
   676  			if init, ok1 := reg.Get(RA).assertFloat64(); ok1 {
   677  				if limit, ok2 := reg.Get(RA + 1).assertFloat64(); ok2 {
   678  					if step, ok3 := reg.Get(RA + 2).assertFloat64(); ok3 {
   679  						init += step
   680  						reg.SetNumber(RA, LNumber(init))
   681  						if (step > 0 && init <= limit) || (step <= 0 && init >= limit) {
   682  							Sbx := int(inst&0x3ffff) - opMaxArgSbx //GETSBX
   683  							cf.Pc += Sbx
   684  							reg.SetNumber(RA+3, LNumber(init))
   685  						} else {
   686  							reg.SetTop(RA + 1)
   687  						}
   688  					} else {
   689  						L.RaiseError("for statement step must be a number")
   690  					}
   691  				} else {
   692  					L.RaiseError("for statement limit must be a number")
   693  				}
   694  			} else {
   695  				L.RaiseError("for statement init must be a number")
   696  			}
   697  			return 0
   698  		},
   699  		func(L *LState, inst uint32, baseframe *callFrame) int { //OP_FORPREP
   700  			reg := L.reg
   701  			cf := L.currentFrame
   702  			lbase := cf.LocalBase
   703  			A := int(inst>>18) & 0xff //GETA
   704  			RA := lbase + A
   705  			Sbx := int(inst&0x3ffff) - opMaxArgSbx //GETSBX
   706  			if init, ok1 := reg.Get(RA).assertFloat64(); ok1 {
   707  				if step, ok2 := reg.Get(RA + 2).assertFloat64(); ok2 {
   708  					reg.SetNumber(RA, LNumber(init-step))
   709  				} else {
   710  					L.RaiseError("for statement step must be a number")
   711  				}
   712  			} else {
   713  				L.RaiseError("for statement init must be a number")
   714  			}
   715  			cf.Pc += Sbx
   716  			return 0
   717  		},
   718  		func(L *LState, inst uint32, baseframe *callFrame) int { //OP_TFORLOOP
   719  			reg := L.reg
   720  			cf := L.currentFrame
   721  			lbase := cf.LocalBase
   722  			A := int(inst>>18) & 0xff //GETA
   723  			RA := lbase + A
   724  			C := int(inst>>9) & 0x1ff //GETC
   725  			nret := C
   726  			reg.SetTop(RA + 3 + 2)
   727  			reg.Set(RA+3+2, reg.Get(RA+2))
   728  			reg.Set(RA+3+1, reg.Get(RA+1))
   729  			reg.Set(RA+3, reg.Get(RA))
   730  			L.callR(2, nret, RA+3)
   731  			if value := reg.Get(RA + 3); value != LNil {
   732  				reg.Set(RA+2, value)
   733  				pc := cf.Fn.Proto.Code[cf.Pc]
   734  				cf.Pc += int(pc&0x3ffff) - opMaxArgSbx
   735  			}
   736  			cf.Pc++
   737  			return 0
   738  		},
   739  		func(L *LState, inst uint32, baseframe *callFrame) int { //OP_SETLIST
   740  			reg := L.reg
   741  			cf := L.currentFrame
   742  			lbase := cf.LocalBase
   743  			A := int(inst>>18) & 0xff //GETA
   744  			RA := lbase + A
   745  			B := int(inst & 0x1ff)    //GETB
   746  			C := int(inst>>9) & 0x1ff //GETC
   747  			if C == 0 {
   748  				C = int(cf.Fn.Proto.Code[cf.Pc])
   749  				cf.Pc++
   750  			}
   751  			offset := (C - 1) * FieldsPerFlush
   752  			table := reg.Get(RA).(*LTable)
   753  			nelem := B
   754  			if B == 0 {
   755  				nelem = reg.Top() - RA - 1
   756  			}
   757  			for i := 1; i <= nelem; i++ {
   758  				table.RawSetInt(offset+i, reg.Get(RA+i))
   759  			}
   760  			return 0
   761  		},
   762  		func(L *LState, inst uint32, baseframe *callFrame) int { //OP_CLOSE
   763  			cf := L.currentFrame
   764  			lbase := cf.LocalBase
   765  			A := int(inst>>18) & 0xff //GETA
   766  			RA := lbase + A
   767  			// +inline-call L.closeUpvalues RA
   768  			return 0
   769  		},
   770  		func(L *LState, inst uint32, baseframe *callFrame) int { //OP_CLOSURE
   771  			reg := L.reg
   772  			cf := L.currentFrame
   773  			lbase := cf.LocalBase
   774  			A := int(inst>>18) & 0xff //GETA
   775  			RA := lbase + A
   776  			Bx := int(inst & 0x3ffff) //GETBX
   777  			proto := cf.Fn.Proto.FunctionPrototypes[Bx]
   778  			closure := newLFunctionL(proto, cf.Fn.Env, int(proto.NumUpvalues))
   779  			reg.Set(RA, closure)
   780  			for i := 0; i < int(proto.NumUpvalues); i++ {
   781  				inst = cf.Fn.Proto.Code[cf.Pc]
   782  				cf.Pc++
   783  				B := opGetArgB(inst)
   784  				switch opGetOpCode(inst) {
   785  				case OP_MOVE:
   786  					closure.Upvalues[i] = L.findUpvalue(lbase + B)
   787  				case OP_GETUPVAL:
   788  					closure.Upvalues[i] = cf.Fn.Upvalues[B]
   789  				}
   790  			}
   791  			return 0
   792  		},
   793  		func(L *LState, inst uint32, baseframe *callFrame) int { //OP_VARARG
   794  			reg := L.reg
   795  			cf := L.currentFrame
   796  			lbase := cf.LocalBase
   797  			A := int(inst>>18) & 0xff //GETA
   798  			RA := lbase + A
   799  			B := int(inst & 0x1ff) //GETB
   800  			nparams := int(cf.Fn.Proto.NumParameters)
   801  			nvarargs := cf.NArgs - nparams
   802  			if nvarargs < 0 {
   803  				nvarargs = 0
   804  			}
   805  			nwant := B - 1
   806  			if B == 0 {
   807  				nwant = nvarargs
   808  			}
   809  			// +inline-call reg.CopyRange RA cf.Base+nparams+1 cf.LocalBase nwant
   810  			return 0
   811  		},
   812  		func(L *LState, inst uint32, baseframe *callFrame) int { //OP_NOP
   813  			return 0
   814  		},
   815  	}
   816  }
   817  
   818  func opArith(L *LState, inst uint32, baseframe *callFrame) int { //OP_ADD, OP_SUB, OP_MUL, OP_DIV, OP_MOD, OP_POW
   819  	reg := L.reg
   820  	cf := L.currentFrame
   821  	lbase := cf.LocalBase
   822  	A := int(inst>>18) & 0xff //GETA
   823  	RA := lbase + A
   824  	opcode := int(inst >> 26) //GETOPCODE
   825  	B := int(inst & 0x1ff)    //GETB
   826  	C := int(inst>>9) & 0x1ff //GETC
   827  	lhs := L.rkValue(B)
   828  	rhs := L.rkValue(C)
   829  	v1, ok1 := lhs.assertFloat64()
   830  	v2, ok2 := rhs.assertFloat64()
   831  	if ok1 && ok2 {
   832  		reg.SetNumber(RA, numberArith(L, opcode, LNumber(v1), LNumber(v2)))
   833  	} else {
   834  		reg.Set(RA, objectArith(L, opcode, lhs, rhs))
   835  	}
   836  	return 0
   837  }
   838  
   839  func luaModulo(lhs, rhs LNumber) LNumber {
   840  	flhs := float64(lhs)
   841  	frhs := float64(rhs)
   842  	v := math.Mod(flhs, frhs)
   843  	if frhs > 0 && v < 0 || frhs < 0 && v > 0 {
   844  		v += frhs
   845  	}
   846  	return LNumber(v)
   847  }
   848  
   849  func numberArith(L *LState, opcode int, lhs, rhs LNumber) LNumber {
   850  	switch opcode {
   851  	case OP_ADD:
   852  		return lhs + rhs
   853  	case OP_SUB:
   854  		return lhs - rhs
   855  	case OP_MUL:
   856  		return lhs * rhs
   857  	case OP_DIV:
   858  		return lhs / rhs
   859  	case OP_MOD:
   860  		return luaModulo(lhs, rhs)
   861  	case OP_POW:
   862  		flhs := float64(lhs)
   863  		frhs := float64(rhs)
   864  		return LNumber(math.Pow(flhs, frhs))
   865  	}
   866  	panic("should not reach here")
   867  	return LNumber(0)
   868  }
   869  
   870  func objectArith(L *LState, opcode int, lhs, rhs LValue) LValue {
   871  	event := ""
   872  	switch opcode {
   873  	case OP_ADD:
   874  		event = "__add"
   875  	case OP_SUB:
   876  		event = "__sub"
   877  	case OP_MUL:
   878  		event = "__mul"
   879  	case OP_DIV:
   880  		event = "__div"
   881  	case OP_MOD:
   882  		event = "__mod"
   883  	case OP_POW:
   884  		event = "__pow"
   885  	}
   886  	op := L.metaOp2(lhs, rhs, event)
   887  	if op.Type() == LTFunction {
   888  		L.reg.Push(op)
   889  		L.reg.Push(lhs)
   890  		L.reg.Push(rhs)
   891  		L.Call(2, 1)
   892  		return L.reg.Pop()
   893  	}
   894  	if str, ok := lhs.(LString); ok {
   895  		if lnum, err := parseNumber(string(str)); err == nil {
   896  			lhs = lnum
   897  		}
   898  	}
   899  	if str, ok := rhs.(LString); ok {
   900  		if rnum, err := parseNumber(string(str)); err == nil {
   901  			rhs = rnum
   902  		}
   903  	}
   904  	if v1, ok1 := lhs.assertFloat64(); ok1 {
   905  		if v2, ok2 := rhs.assertFloat64(); ok2 {
   906  			return numberArith(L, opcode, LNumber(v1), LNumber(v2))
   907  		}
   908  	}
   909  	L.RaiseError(fmt.Sprintf("cannot perform %v operation between %v and %v",
   910  		strings.TrimLeft(event, "_"), lhs.Type().String(), rhs.Type().String()))
   911  
   912  	return LNil
   913  }
   914  
   915  func stringConcat(L *LState, total, last int) LValue {
   916  	rhs := L.reg.Get(last)
   917  	total--
   918  	for i := last - 1; total > 0; {
   919  		lhs := L.reg.Get(i)
   920  		if !(LVCanConvToString(lhs) && LVCanConvToString(rhs)) {
   921  			op := L.metaOp2(lhs, rhs, "__concat")
   922  			if op.Type() == LTFunction {
   923  				L.reg.Push(op)
   924  				L.reg.Push(lhs)
   925  				L.reg.Push(rhs)
   926  				L.Call(2, 1)
   927  				rhs = L.reg.Pop()
   928  				total--
   929  				i--
   930  			} else {
   931  				L.RaiseError("cannot perform concat operation between %v and %v", lhs.Type().String(), rhs.Type().String())
   932  				return LNil
   933  			}
   934  		} else {
   935  			buf := make([]string, total+1)
   936  			buf[total] = LVAsString(rhs)
   937  			for total > 0 {
   938  				lhs = L.reg.Get(i)
   939  				if !LVCanConvToString(lhs) {
   940  					break
   941  				}
   942  				buf[total-1] = LVAsString(lhs)
   943  				i--
   944  				total--
   945  			}
   946  			rhs = LString(strings.Join(buf, ""))
   947  		}
   948  	}
   949  	return rhs
   950  }
   951  
   952  func lessThan(L *LState, lhs, rhs LValue) bool {
   953  	// optimization for numbers
   954  	if v1, ok1 := lhs.assertFloat64(); ok1 {
   955  		if v2, ok2 := rhs.assertFloat64(); ok2 {
   956  			return v1 < v2
   957  		}
   958  		L.RaiseError("attempt to compare %v with %v", lhs.Type().String(), rhs.Type().String())
   959  	}
   960  	if lhs.Type() != rhs.Type() {
   961  		L.RaiseError("attempt to compare %v with %v", lhs.Type().String(), rhs.Type().String())
   962  		return false
   963  	}
   964  	ret := false
   965  	switch lhs.Type() {
   966  	case LTString:
   967  		ret = strCmp(string(lhs.(LString)), string(rhs.(LString))) < 0
   968  	default:
   969  		ret = objectRationalWithError(L, lhs, rhs, "__lt")
   970  	}
   971  	return ret
   972  }
   973  
   974  func equals(L *LState, lhs, rhs LValue, raw bool) bool {
   975  	if lhs.Type() != rhs.Type() {
   976  		return false
   977  	}
   978  
   979  	ret := false
   980  	switch lhs.Type() {
   981  	case LTNil:
   982  		ret = true
   983  	case LTNumber:
   984  		v1, _ := lhs.assertFloat64()
   985  		v2, _ := rhs.assertFloat64()
   986  		ret = v1 == v2
   987  	case LTBool:
   988  		ret = bool(lhs.(LBool)) == bool(rhs.(LBool))
   989  	case LTString:
   990  		ret = string(lhs.(LString)) == string(rhs.(LString))
   991  	case LTUserData, LTTable:
   992  		if lhs == rhs {
   993  			ret = true
   994  		} else if !raw {
   995  			switch objectRational(L, lhs, rhs, "__eq") {
   996  			case 1:
   997  				ret = true
   998  			default:
   999  				ret = false
  1000  			}
  1001  		}
  1002  	default:
  1003  		ret = lhs == rhs
  1004  	}
  1005  	return ret
  1006  }
  1007  
  1008  func objectRationalWithError(L *LState, lhs, rhs LValue, event string) bool {
  1009  	switch objectRational(L, lhs, rhs, event) {
  1010  	case 1:
  1011  		return true
  1012  	case 0:
  1013  		return false
  1014  	}
  1015  	L.RaiseError("attempt to compare %v with %v", lhs.Type().String(), rhs.Type().String())
  1016  	return false
  1017  }
  1018  
  1019  func objectRational(L *LState, lhs, rhs LValue, event string) int {
  1020  	m1 := L.metaOp1(lhs, event)
  1021  	m2 := L.metaOp1(rhs, event)
  1022  	if m1.Type() == LTFunction && m1 == m2 {
  1023  		L.reg.Push(m1)
  1024  		L.reg.Push(lhs)
  1025  		L.reg.Push(rhs)
  1026  		L.Call(2, 1)
  1027  		if LVAsBool(L.reg.Pop()) {
  1028  			return 1
  1029  		}
  1030  		return 0
  1031  	}
  1032  	return -1
  1033  }