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