github.com/qiniu/gopher-lua@v0.2017.11/_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  					reg.Set(RA, reg.Pop())
   406  				} else if lv.Type() == LTTable {
   407  					reg.SetNumber(RA, LNumber(lv.(*LTable).Len()))
   408  				} else {
   409  					L.RaiseError("__len undefined")
   410  				}
   411  			}
   412  			return 0
   413  		},
   414  		func(L *LState, inst uint32, baseframe *callFrame) int { //OP_CONCAT
   415  			reg := L.reg
   416  			cf := L.currentFrame
   417  			lbase := cf.LocalBase
   418  			A := int(inst>>18) & 0xff //GETA
   419  			RA := lbase + A
   420  			B := int(inst & 0x1ff)    //GETB
   421  			C := int(inst>>9) & 0x1ff //GETC
   422  			RC := lbase + C
   423  			RB := lbase + B
   424  			reg.Set(RA, stringConcat(L, RC-RB+1, RC))
   425  			return 0
   426  		},
   427  		func(L *LState, inst uint32, baseframe *callFrame) int { //OP_JMP
   428  			cf := L.currentFrame
   429  			Sbx := int(inst&0x3ffff) - opMaxArgSbx //GETSBX
   430  			cf.Pc += Sbx
   431  			return 0
   432  		},
   433  		func(L *LState, inst uint32, baseframe *callFrame) int { //OP_EQ
   434  			cf := L.currentFrame
   435  			A := int(inst>>18) & 0xff //GETA
   436  			B := int(inst & 0x1ff)    //GETB
   437  			C := int(inst>>9) & 0x1ff //GETC
   438  			ret := equals(L, L.rkValue(B), L.rkValue(C), false)
   439  			v := 1
   440  			if ret {
   441  				v = 0
   442  			}
   443  			if v == A {
   444  				cf.Pc++
   445  			}
   446  			return 0
   447  		},
   448  		func(L *LState, inst uint32, baseframe *callFrame) int { //OP_LT
   449  			cf := L.currentFrame
   450  			A := int(inst>>18) & 0xff //GETA
   451  			B := int(inst & 0x1ff)    //GETB
   452  			C := int(inst>>9) & 0x1ff //GETC
   453  			ret := lessThan(L, L.rkValue(B), L.rkValue(C))
   454  			v := 1
   455  			if ret {
   456  				v = 0
   457  			}
   458  			if v == A {
   459  				cf.Pc++
   460  			}
   461  			return 0
   462  		},
   463  		func(L *LState, inst uint32, baseframe *callFrame) int { //OP_LE
   464  			cf := L.currentFrame
   465  			A := int(inst>>18) & 0xff //GETA
   466  			B := int(inst & 0x1ff)    //GETB
   467  			C := int(inst>>9) & 0x1ff //GETC
   468  			lhs := L.rkValue(B)
   469  			rhs := L.rkValue(C)
   470  			ret := false
   471  
   472  			if v1, ok1 := lhs.assertFloat64(); ok1 {
   473  				if v2, ok2 := rhs.assertFloat64(); ok2 {
   474  					ret = v1 <= v2
   475  				} else {
   476  					L.RaiseError("attempt to compare %v with %v", lhs.Type().String(), rhs.Type().String())
   477  				}
   478  			} else {
   479  				if lhs.Type() != rhs.Type() {
   480  					L.RaiseError("attempt to compare %v with %v", lhs.Type().String(), rhs.Type().String())
   481  				}
   482  				switch lhs.Type() {
   483  				case LTString:
   484  					ret = strCmp(string(lhs.(LString)), string(rhs.(LString))) <= 0
   485  				default:
   486  					switch objectRational(L, lhs, rhs, "__le") {
   487  					case 1:
   488  						ret = true
   489  					case 0:
   490  						ret = false
   491  					default:
   492  						ret = !objectRationalWithError(L, rhs, lhs, "__lt")
   493  					}
   494  				}
   495  			}
   496  
   497  			v := 1
   498  			if ret {
   499  				v = 0
   500  			}
   501  			if v == A {
   502  				cf.Pc++
   503  			}
   504  			return 0
   505  		},
   506  		func(L *LState, inst uint32, baseframe *callFrame) int { //OP_TEST
   507  			reg := L.reg
   508  			cf := L.currentFrame
   509  			lbase := cf.LocalBase
   510  			A := int(inst>>18) & 0xff //GETA
   511  			RA := lbase + A
   512  			C := int(inst>>9) & 0x1ff //GETC
   513  			if LVAsBool(reg.Get(RA)) == (C == 0) {
   514  				cf.Pc++
   515  			}
   516  			return 0
   517  		},
   518  		func(L *LState, inst uint32, baseframe *callFrame) int { //OP_TESTSET
   519  			reg := L.reg
   520  			cf := L.currentFrame
   521  			lbase := cf.LocalBase
   522  			A := int(inst>>18) & 0xff //GETA
   523  			RA := lbase + A
   524  			B := int(inst & 0x1ff)    //GETB
   525  			C := int(inst>>9) & 0x1ff //GETC
   526  			if value := reg.Get(lbase + B); LVAsBool(value) != (C == 0) {
   527  				reg.Set(RA, value)
   528  			} else {
   529  				cf.Pc++
   530  			}
   531  			return 0
   532  		},
   533  		func(L *LState, inst uint32, baseframe *callFrame) int { //OP_CALL
   534  			reg := L.reg
   535  			cf := L.currentFrame
   536  			lbase := cf.LocalBase
   537  			A := int(inst>>18) & 0xff //GETA
   538  			RA := lbase + A
   539  			B := int(inst & 0x1ff)    //GETB
   540  			C := int(inst>>9) & 0x1ff //GETC
   541  			nargs := B - 1
   542  			if B == 0 {
   543  				nargs = reg.Top() - (RA + 1)
   544  			}
   545  			lv := reg.Get(RA)
   546  			nret := C - 1
   547  			var callable *LFunction
   548  			var meta bool
   549  			if fn, ok := lv.assertFunction(); ok {
   550  				callable = fn
   551  				meta = false
   552  			} else {
   553  				callable, meta = L.metaCall(lv)
   554  			}
   555  			// +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
   556  			if callable.IsG && callGFunction(L, false) {
   557  				return 1
   558  			}
   559  			return 0
   560  		},
   561  		func(L *LState, inst uint32, baseframe *callFrame) int { //OP_TAILCALL
   562  			reg := L.reg
   563  			cf := L.currentFrame
   564  			lbase := cf.LocalBase
   565  			A := int(inst>>18) & 0xff //GETA
   566  			RA := lbase + A
   567  			B := int(inst & 0x1ff) //GETB
   568  			nargs := B - 1
   569  			if B == 0 {
   570  				nargs = reg.Top() - (RA + 1)
   571  			}
   572  			lv := reg.Get(RA)
   573  			var callable *LFunction
   574  			var meta bool
   575  			if fn, ok := lv.assertFunction(); ok {
   576  				callable = fn
   577  				meta = false
   578  			} else {
   579  				callable, meta = L.metaCall(lv)
   580  			}
   581  			if callable == nil {
   582  				L.RaiseError("attempt to call a non-function object")
   583  			}
   584  			// +inline-call L.closeUpvalues lbase
   585  			if callable.IsG {
   586  				luaframe := cf
   587  				L.pushCallFrame(callFrame{
   588  					Fn:         callable,
   589  					Pc:         0,
   590  					Base:       RA,
   591  					LocalBase:  RA + 1,
   592  					ReturnBase: cf.ReturnBase,
   593  					NArgs:      nargs,
   594  					NRet:       cf.NRet,
   595  					Parent:     cf,
   596  					TailCall:   0,
   597  				}, lv, meta)
   598  				if callGFunction(L, true) {
   599  					return 1
   600  				}
   601  				if L.currentFrame == nil || L.currentFrame.Fn.IsG || luaframe == baseframe {
   602  					return 1
   603  				}
   604  			} else {
   605  				base := cf.Base
   606  				cf.Fn = callable
   607  				cf.Pc = 0
   608  				cf.Base = RA
   609  				cf.LocalBase = RA + 1
   610  				cf.ReturnBase = cf.ReturnBase
   611  				cf.NArgs = nargs
   612  				cf.NRet = cf.NRet
   613  				cf.TailCall++
   614  				lbase := cf.LocalBase
   615  				if meta {
   616  					cf.NArgs++
   617  					L.reg.Insert(lv, cf.LocalBase)
   618  				}
   619  				// +inline-call L.initCallFrame cf
   620  				// +inline-call L.reg.CopyRange base RA -1 reg.Top()-RA-1
   621  				cf.Base = base
   622  				cf.LocalBase = base + (cf.LocalBase - lbase + 1)
   623  			}
   624  			return 0
   625  		},
   626  		func(L *LState, inst uint32, baseframe *callFrame) int { //OP_RETURN
   627  			reg := L.reg
   628  			cf := L.currentFrame
   629  			lbase := cf.LocalBase
   630  			A := int(inst>>18) & 0xff //GETA
   631  			RA := lbase + A
   632  			B := int(inst & 0x1ff) //GETB
   633  			// +inline-call L.closeUpvalues lbase
   634  			nret := B - 1
   635  			if B == 0 {
   636  				nret = reg.Top() - RA
   637  			}
   638  			n := cf.NRet
   639  			if cf.NRet == MultRet {
   640  				n = nret
   641  			}
   642  
   643  			if L.Parent != nil && L.stack.Sp() == 1 {
   644  				// +inline-call copyReturnValues L reg.Top() RA n B
   645  				switchToParentThread(L, n, false, true)
   646  				return 1
   647  			}
   648  			islast := baseframe == L.stack.Pop() || L.stack.IsEmpty()
   649  			// +inline-call copyReturnValues L cf.ReturnBase RA n B
   650  			L.currentFrame = L.stack.Last()
   651  			if islast || L.currentFrame == nil || L.currentFrame.Fn.IsG {
   652  				return 1
   653  			}
   654  			return 0
   655  		},
   656  		func(L *LState, inst uint32, baseframe *callFrame) int { //OP_FORLOOP
   657  			reg := L.reg
   658  			cf := L.currentFrame
   659  			lbase := cf.LocalBase
   660  			A := int(inst>>18) & 0xff //GETA
   661  			RA := lbase + A
   662  			if init, ok1 := reg.Get(RA).assertFloat64(); ok1 {
   663  				if limit, ok2 := reg.Get(RA + 1).assertFloat64(); ok2 {
   664  					if step, ok3 := reg.Get(RA + 2).assertFloat64(); ok3 {
   665  						init += step
   666  						reg.SetNumber(RA, LNumber(init))
   667  						if (step > 0 && init <= limit) || (step <= 0 && init >= limit) {
   668  							Sbx := int(inst&0x3ffff) - opMaxArgSbx //GETSBX
   669  							cf.Pc += Sbx
   670  							reg.SetNumber(RA+3, LNumber(init))
   671  						} else {
   672  							reg.SetTop(RA + 1)
   673  						}
   674  					} else {
   675  						L.RaiseError("for statement step must be a number")
   676  					}
   677  				} else {
   678  					L.RaiseError("for statement limit must be a number")
   679  				}
   680  			} else {
   681  				L.RaiseError("for statement init must be a number")
   682  			}
   683  			return 0
   684  		},
   685  		func(L *LState, inst uint32, baseframe *callFrame) int { //OP_FORPREP
   686  			reg := L.reg
   687  			cf := L.currentFrame
   688  			lbase := cf.LocalBase
   689  			A := int(inst>>18) & 0xff //GETA
   690  			RA := lbase + A
   691  			Sbx := int(inst&0x3ffff) - opMaxArgSbx //GETSBX
   692  			if init, ok1 := reg.Get(RA).assertFloat64(); ok1 {
   693  				if step, ok2 := reg.Get(RA + 2).assertFloat64(); ok2 {
   694  					reg.SetNumber(RA, LNumber(init-step))
   695  				} else {
   696  					L.RaiseError("for statement step must be a number")
   697  				}
   698  			} else {
   699  				L.RaiseError("for statement init must be a number")
   700  			}
   701  			cf.Pc += Sbx
   702  			return 0
   703  		},
   704  		func(L *LState, inst uint32, baseframe *callFrame) int { //OP_TFORLOOP
   705  			reg := L.reg
   706  			cf := L.currentFrame
   707  			lbase := cf.LocalBase
   708  			A := int(inst>>18) & 0xff //GETA
   709  			RA := lbase + A
   710  			C := int(inst>>9) & 0x1ff //GETC
   711  			nret := C
   712  			reg.SetTop(RA + 3 + 2)
   713  			reg.Set(RA+3+2, reg.Get(RA+2))
   714  			reg.Set(RA+3+1, reg.Get(RA+1))
   715  			reg.Set(RA+3, reg.Get(RA))
   716  			L.callR(2, nret, RA+3)
   717  			if value := reg.Get(RA + 3); value != LNil {
   718  				reg.Set(RA+2, value)
   719  				pc := cf.Fn.Proto.Code[cf.Pc]
   720  				cf.Pc += int(pc&0x3ffff) - opMaxArgSbx
   721  			}
   722  			cf.Pc++
   723  			return 0
   724  		},
   725  		func(L *LState, inst uint32, baseframe *callFrame) int { //OP_SETLIST
   726  			reg := L.reg
   727  			cf := L.currentFrame
   728  			lbase := cf.LocalBase
   729  			A := int(inst>>18) & 0xff //GETA
   730  			RA := lbase + A
   731  			B := int(inst & 0x1ff)    //GETB
   732  			C := int(inst>>9) & 0x1ff //GETC
   733  			if C == 0 {
   734  				C = int(cf.Fn.Proto.Code[cf.Pc])
   735  				cf.Pc++
   736  			}
   737  			offset := (C - 1) * FieldsPerFlush
   738  			table := reg.Get(RA).(*LTable)
   739  			nelem := B
   740  			if B == 0 {
   741  				nelem = reg.Top() - RA - 1
   742  			}
   743  			for i := 1; i <= nelem; i++ {
   744  				table.RawSetInt(offset+i, reg.Get(RA+i))
   745  			}
   746  			return 0
   747  		},
   748  		func(L *LState, inst uint32, baseframe *callFrame) int { //OP_CLOSE
   749  			cf := L.currentFrame
   750  			lbase := cf.LocalBase
   751  			A := int(inst>>18) & 0xff //GETA
   752  			RA := lbase + A
   753  			// +inline-call L.closeUpvalues RA
   754  			return 0
   755  		},
   756  		func(L *LState, inst uint32, baseframe *callFrame) int { //OP_CLOSURE
   757  			reg := L.reg
   758  			cf := L.currentFrame
   759  			lbase := cf.LocalBase
   760  			A := int(inst>>18) & 0xff //GETA
   761  			RA := lbase + A
   762  			Bx := int(inst & 0x3ffff) //GETBX
   763  			proto := cf.Fn.Proto.FunctionPrototypes[Bx]
   764  			closure := newLFunctionL(proto, cf.Fn.Env, int(proto.NumUpvalues))
   765  			reg.Set(RA, closure)
   766  			for i := 0; i < int(proto.NumUpvalues); i++ {
   767  				inst = cf.Fn.Proto.Code[cf.Pc]
   768  				cf.Pc++
   769  				B := opGetArgB(inst)
   770  				switch opGetOpCode(inst) {
   771  				case OP_MOVE:
   772  					closure.Upvalues[i] = L.findUpvalue(lbase + B)
   773  				case OP_GETUPVAL:
   774  					closure.Upvalues[i] = cf.Fn.Upvalues[B]
   775  				}
   776  			}
   777  			return 0
   778  		},
   779  		func(L *LState, inst uint32, baseframe *callFrame) int { //OP_VARARG
   780  			reg := L.reg
   781  			cf := L.currentFrame
   782  			lbase := cf.LocalBase
   783  			A := int(inst>>18) & 0xff //GETA
   784  			RA := lbase + A
   785  			B := int(inst & 0x1ff) //GETB
   786  			nparams := int(cf.Fn.Proto.NumParameters)
   787  			nvarargs := cf.NArgs - nparams
   788  			if nvarargs < 0 {
   789  				nvarargs = 0
   790  			}
   791  			nwant := B - 1
   792  			if B == 0 {
   793  				nwant = nvarargs
   794  			}
   795  			// +inline-call reg.CopyRange RA cf.Base+nparams+1 cf.LocalBase nwant
   796  			return 0
   797  		},
   798  		func(L *LState, inst uint32, baseframe *callFrame) int { //OP_NOP
   799  			return 0
   800  		},
   801  	}
   802  }
   803  
   804  func opArith(L *LState, inst uint32, baseframe *callFrame) int { //OP_ADD, OP_SUB, OP_MUL, OP_DIV, OP_MOD, OP_POW
   805  	reg := L.reg
   806  	cf := L.currentFrame
   807  	lbase := cf.LocalBase
   808  	A := int(inst>>18) & 0xff //GETA
   809  	RA := lbase + A
   810  	opcode := int(inst >> 26) //GETOPCODE
   811  	B := int(inst & 0x1ff)    //GETB
   812  	C := int(inst>>9) & 0x1ff //GETC
   813  	lhs := L.rkValue(B)
   814  	rhs := L.rkValue(C)
   815  	v1, ok1 := lhs.assertFloat64()
   816  	v2, ok2 := rhs.assertFloat64()
   817  	if ok1 && ok2 {
   818  		reg.SetNumber(RA, numberArith(L, opcode, LNumber(v1), LNumber(v2)))
   819  	} else {
   820  		reg.Set(RA, objectArith(L, opcode, lhs, rhs))
   821  	}
   822  	return 0
   823  }
   824  
   825  func luaModulo(lhs, rhs LNumber) LNumber {
   826  	flhs := float64(lhs)
   827  	frhs := float64(rhs)
   828  	v := math.Mod(flhs, frhs)
   829  	if flhs < 0 || frhs < 0 && !(flhs < 0 && frhs < 0) {
   830  		v += frhs
   831  	}
   832  	return LNumber(v)
   833  }
   834  
   835  func numberArith(L *LState, opcode int, lhs, rhs LNumber) LNumber {
   836  	switch opcode {
   837  	case OP_ADD:
   838  		return lhs + rhs
   839  	case OP_SUB:
   840  		return lhs - rhs
   841  	case OP_MUL:
   842  		return lhs * rhs
   843  	case OP_DIV:
   844  		return lhs / rhs
   845  	case OP_MOD:
   846  		return luaModulo(lhs, rhs)
   847  	case OP_POW:
   848  		flhs := float64(lhs)
   849  		frhs := float64(rhs)
   850  		return LNumber(math.Pow(flhs, frhs))
   851  	}
   852  	panic("should not reach here")
   853  	return LNumber(0)
   854  }
   855  
   856  func objectArith(L *LState, opcode int, lhs, rhs LValue) LValue {
   857  	event := ""
   858  	switch opcode {
   859  	case OP_ADD:
   860  		event = "__add"
   861  	case OP_SUB:
   862  		event = "__sub"
   863  	case OP_MUL:
   864  		event = "__mul"
   865  	case OP_DIV:
   866  		event = "__div"
   867  	case OP_MOD:
   868  		event = "__mod"
   869  	case OP_POW:
   870  		event = "__pow"
   871  	}
   872  	op := L.metaOp2(lhs, rhs, event)
   873  	if op.Type() == LTFunction {
   874  		L.reg.Push(op)
   875  		L.reg.Push(lhs)
   876  		L.reg.Push(rhs)
   877  		L.Call(2, 1)
   878  		return L.reg.Pop()
   879  	}
   880  	if str, ok := lhs.(LString); ok {
   881  		if lnum, err := parseNumber(string(str)); err == nil {
   882  			lhs = lnum
   883  		}
   884  	}
   885  	if str, ok := rhs.(LString); ok {
   886  		if rnum, err := parseNumber(string(str)); err == nil {
   887  			rhs = rnum
   888  		}
   889  	}
   890  	if v1, ok1 := lhs.assertFloat64(); ok1 {
   891  		if v2, ok2 := rhs.assertFloat64(); ok2 {
   892  			return numberArith(L, opcode, LNumber(v1), LNumber(v2))
   893  		}
   894  	}
   895  	L.RaiseError(fmt.Sprintf("cannot perform %v operation between %v and %v",
   896  		strings.TrimLeft(event, "_"), lhs.Type().String(), rhs.Type().String()))
   897  
   898  	return LNil
   899  }
   900  
   901  func stringConcat(L *LState, total, last int) LValue {
   902  	rhs := L.reg.Get(last)
   903  	total--
   904  	for i := last - 1; total > 0; {
   905  		lhs := L.reg.Get(i)
   906  		if !(LVCanConvToString(lhs) && LVCanConvToString(rhs)) {
   907  			op := L.metaOp2(lhs, rhs, "__concat")
   908  			if op.Type() == LTFunction {
   909  				L.reg.Push(op)
   910  				L.reg.Push(lhs)
   911  				L.reg.Push(rhs)
   912  				L.Call(2, 1)
   913  				rhs = L.reg.Pop()
   914  				total--
   915  				i--
   916  			} else {
   917  				L.RaiseError("cannot perform concat operation between %v and %v", lhs.Type().String(), rhs.Type().String())
   918  				return LNil
   919  			}
   920  		} else {
   921  			buf := make([]string, total+1)
   922  			buf[total] = LVAsString(rhs)
   923  			for total > 0 {
   924  				lhs = L.reg.Get(i)
   925  				if !LVCanConvToString(lhs) {
   926  					break
   927  				}
   928  				buf[total-1] = LVAsString(lhs)
   929  				i--
   930  				total--
   931  			}
   932  			rhs = LString(strings.Join(buf, ""))
   933  		}
   934  	}
   935  	return rhs
   936  }
   937  
   938  func lessThan(L *LState, lhs, rhs LValue) bool {
   939  	// optimization for numbers
   940  	if v1, ok1 := lhs.assertFloat64(); ok1 {
   941  		if v2, ok2 := rhs.assertFloat64(); ok2 {
   942  			return v1 < v2
   943  		}
   944  		L.RaiseError("attempt to compare %v with %v", lhs.Type().String(), rhs.Type().String())
   945  	}
   946  	if lhs.Type() != rhs.Type() {
   947  		L.RaiseError("attempt to compare %v with %v", lhs.Type().String(), rhs.Type().String())
   948  		return false
   949  	}
   950  	ret := false
   951  	switch lhs.Type() {
   952  	case LTString:
   953  		ret = strCmp(string(lhs.(LString)), string(rhs.(LString))) < 0
   954  	default:
   955  		ret = objectRationalWithError(L, lhs, rhs, "__lt")
   956  	}
   957  	return ret
   958  }
   959  
   960  func equals(L *LState, lhs, rhs LValue, raw bool) bool {
   961  	if lhs.Type() != rhs.Type() {
   962  		return false
   963  	}
   964  
   965  	ret := false
   966  	switch lhs.Type() {
   967  	case LTNil:
   968  		ret = true
   969  	case LTNumber:
   970  		v1, _ := lhs.assertFloat64()
   971  		v2, _ := rhs.assertFloat64()
   972  		ret = v1 == v2
   973  	case LTBool:
   974  		ret = bool(lhs.(LBool)) == bool(rhs.(LBool))
   975  	case LTString:
   976  		ret = string(lhs.(LString)) == string(rhs.(LString))
   977  	case LTUserData, LTTable:
   978  		if lhs == rhs {
   979  			ret = true
   980  		} else if !raw {
   981  			switch objectRational(L, lhs, rhs, "__eq") {
   982  			case 1:
   983  				ret = true
   984  			default:
   985  				ret = false
   986  			}
   987  		}
   988  	default:
   989  		ret = lhs == rhs
   990  	}
   991  	return ret
   992  }
   993  
   994  func objectRationalWithError(L *LState, lhs, rhs LValue, event string) bool {
   995  	switch objectRational(L, lhs, rhs, event) {
   996  	case 1:
   997  		return true
   998  	case 0:
   999  		return false
  1000  	}
  1001  	L.RaiseError("attempt to compare %v with %v", lhs.Type().String(), rhs.Type().String())
  1002  	return false
  1003  }
  1004  
  1005  func objectRational(L *LState, lhs, rhs LValue, event string) int {
  1006  	m1 := L.metaOp1(lhs, event)
  1007  	m2 := L.metaOp1(rhs, event)
  1008  	if m1.Type() == LTFunction && m1 == m2 {
  1009  		L.reg.Push(m1)
  1010  		L.reg.Push(lhs)
  1011  		L.reg.Push(rhs)
  1012  		L.Call(2, 1)
  1013  		if LVAsBool(L.reg.Pop()) {
  1014  			return 1
  1015  		}
  1016  		return 0
  1017  	}
  1018  	return -1
  1019  }