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