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