github.com/yuin/gopher-lua@v1.1.2-0.20231212122839-2348fd042596/_vm.go (about)

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