github.com/coinstack/gopher-lua@v0.0.0-20180626044619-c9c62d4ee45e/vm.go (about)

     1  package lua
     2  
     3  ////////////////////////////////////////////////////////
     4  // This file was generated by go-inline. DO NOT EDIT. //
     5  ////////////////////////////////////////////////////////
     6  
     7  import (
     8  	"fmt"
     9  	"math"
    10  	"strings"
    11  )
    12  
    13  const (
    14  	errMaxInstStr = "exceeded the maximum instruction count"
    15  )
    16  
    17  func mainLoop(L *LState, baseframe *callFrame) {
    18  	var inst uint32
    19  	var cf *callFrame
    20  
    21  	if L.stack.IsEmpty() {
    22  		return
    23  	}
    24  
    25  	L.currentFrame = L.stack.Last()
    26  	if L.currentFrame.Fn.IsG {
    27  		callGFunction(L, false)
    28  		return
    29  	}
    30  
    31  	for {
    32  		cf = L.currentFrame
    33  		inst = cf.Fn.Proto.Code[cf.Pc]
    34  		cf.Pc++
    35  		opCode := int(inst >> 26)
    36  		if jumpTable[opCode](L, inst, baseframe) == 1 {
    37  			return
    38  		}
    39  		if L.Options.MaxInstSize > uint64(0) {
    40  			L.instCount += opProps[opCode].InstCount
    41  			if L.instCount > L.Options.MaxInstSize {
    42  				L.RaiseError(errMaxInstStr)
    43  				return
    44  			}
    45  		}
    46  	}
    47  }
    48  
    49  func mainLoopWithContext(L *LState, baseframe *callFrame) {
    50  	var inst uint32
    51  	var cf *callFrame
    52  
    53  	if L.stack.IsEmpty() {
    54  		return
    55  	}
    56  
    57  	L.currentFrame = L.stack.Last()
    58  	if L.currentFrame.Fn.IsG {
    59  		callGFunction(L, false)
    60  		return
    61  	}
    62  
    63  	for {
    64  		cf = L.currentFrame
    65  		inst = cf.Fn.Proto.Code[cf.Pc]
    66  		cf.Pc++
    67  		select {
    68  		case <-L.ctx.Done():
    69  			L.RaiseError(L.ctx.Err().Error())
    70  			return
    71  		default:
    72  			opCode := int(inst >> 26)
    73  			if jumpTable[opCode](L, inst, baseframe) == 1 {
    74  				return
    75  			}
    76  			if L.Options.MaxInstSize > uint64(0) {
    77  				L.instCount += opProps[opCode].InstCount
    78  				if L.instCount > L.Options.MaxInstSize {
    79  					L.RaiseError(errMaxInstStr)
    80  					return
    81  				}
    82  			}
    83  		}
    84  	}
    85  }
    86  
    87  func copyReturnValues(L *LState, regv, start, n, b int) { // +inline-start
    88  	if b == 1 {
    89  		// this section is inlined by go-inline
    90  		// source function is 'func (rg *registry) FillNil(regm, n int) ' in '_state.go'
    91  		{
    92  			rg := L.reg
    93  			regm := regv
    94  			for i := 0; i < n; i++ {
    95  				rg.array[regm+i] = LNil
    96  			}
    97  			rg.top = regm + n
    98  		}
    99  	} else {
   100  		// this section is inlined by go-inline
   101  		// source function is 'func (rg *registry) CopyRange(regv, start, limit, n int) ' in '_state.go'
   102  		{
   103  			rg := L.reg
   104  			limit := -1
   105  			for i := 0; i < n; i++ {
   106  				if tidx := start + i; tidx >= rg.top || limit > -1 && tidx >= limit || tidx < 0 {
   107  					rg.array[regv+i] = LNil
   108  				} else {
   109  					rg.array[regv+i] = rg.array[tidx]
   110  				}
   111  			}
   112  			rg.top = regv + n
   113  		}
   114  	}
   115  } // +inline-end
   116  
   117  func switchToParentThread(L *LState, nargs int, haserror bool, kill bool) {
   118  	parent := L.Parent
   119  	if parent == nil {
   120  		L.RaiseError("can not yield from outside of a coroutine")
   121  	}
   122  	L.G.CurrentThread = parent
   123  	L.Parent = nil
   124  	if !L.wrapped {
   125  		if haserror {
   126  			parent.Push(LFalse)
   127  		} else {
   128  			parent.Push(LTrue)
   129  		}
   130  	}
   131  	L.XMoveTo(parent, nargs)
   132  	L.stack.Pop()
   133  	offset := L.currentFrame.LocalBase - L.currentFrame.ReturnBase
   134  	L.currentFrame = L.stack.Last()
   135  	L.reg.SetTop(L.reg.Top() - offset) // remove 'yield' function(including tailcalled functions)
   136  	if kill {
   137  		L.kill()
   138  	}
   139  }
   140  
   141  func callGFunction(L *LState, tailcall bool) bool {
   142  	L.instCount += 40
   143  	frame := L.currentFrame
   144  	gfnret := frame.Fn.GFunction(L)
   145  	if tailcall {
   146  		L.stack.Remove(L.stack.Sp() - 2) // remove caller lua function frame
   147  		L.currentFrame = L.stack.Last()
   148  	}
   149  
   150  	if gfnret < 0 {
   151  		switchToParentThread(L, L.GetTop(), false, false)
   152  		return true
   153  	}
   154  
   155  	wantret := frame.NRet
   156  	if wantret == MultRet {
   157  		wantret = gfnret
   158  	}
   159  
   160  	if tailcall && L.Parent != nil && L.stack.Sp() == 1 {
   161  		switchToParentThread(L, wantret, false, true)
   162  		return true
   163  	}
   164  
   165  	// this section is inlined by go-inline
   166  	// source function is 'func (rg *registry) CopyRange(regv, start, limit, n int) ' in '_state.go'
   167  	{
   168  		rg := L.reg
   169  		regv := frame.ReturnBase
   170  		start := L.reg.Top() - gfnret
   171  		limit := -1
   172  		n := wantret
   173  		for i := 0; i < n; i++ {
   174  			if tidx := start + i; tidx >= rg.top || limit > -1 && tidx >= limit || tidx < 0 {
   175  				rg.array[regv+i] = LNil
   176  			} else {
   177  				rg.array[regv+i] = rg.array[tidx]
   178  			}
   179  		}
   180  		rg.top = regv + n
   181  	}
   182  	L.stack.Pop()
   183  	L.currentFrame = L.stack.Last()
   184  	return false
   185  }
   186  
   187  func threadRun(L *LState) {
   188  	if L.stack.IsEmpty() {
   189  		return
   190  	}
   191  
   192  	defer func() {
   193  		if rcv := recover(); rcv != nil {
   194  			var lv LValue
   195  			if v, ok := rcv.(*ApiError); ok {
   196  				lv = v.Object
   197  			} else {
   198  				lv = LString(fmt.Sprint(rcv))
   199  			}
   200  			if parent := L.Parent; parent != nil {
   201  				if L.wrapped {
   202  					L.Push(lv)
   203  					parent.Panic(L)
   204  				} else {
   205  					L.SetTop(0)
   206  					L.Push(lv)
   207  					switchToParentThread(L, 1, true, true)
   208  				}
   209  			} else {
   210  				panic(rcv)
   211  			}
   212  		}
   213  	}()
   214  	L.mainLoop(L, nil)
   215  }
   216  
   217  type instFunc func(*LState, uint32, *callFrame) int
   218  
   219  var jumpTable [opCodeMax + 1]instFunc
   220  
   221  func init() {
   222  	jumpTable = [opCodeMax + 1]instFunc{
   223  		func(L *LState, inst uint32, baseframe *callFrame) int { //OP_MOVE
   224  			reg := L.reg
   225  			cf := L.currentFrame
   226  			lbase := cf.LocalBase
   227  			A := int(inst>>18) & 0xff //GETA
   228  			RA := lbase + A
   229  			B := int(inst & 0x1ff) //GETB
   230  			reg.Set(RA, reg.Get(lbase+B))
   231  			return 0
   232  		},
   233  		func(L *LState, inst uint32, baseframe *callFrame) int { //OP_MOVEN
   234  			reg := L.reg
   235  			cf := L.currentFrame
   236  			lbase := cf.LocalBase
   237  			A := int(inst>>18) & 0xff //GETA
   238  			B := int(inst & 0x1ff)    //GETB
   239  			C := int(inst>>9) & 0x1ff //GETC
   240  			reg.Set(lbase+A, reg.Get(lbase+B))
   241  			code := cf.Fn.Proto.Code
   242  			pc := cf.Pc
   243  			for i := 0; i < C; i++ {
   244  				inst = code[pc]
   245  				pc++
   246  				A = int(inst>>18) & 0xff //GETA
   247  				B = int(inst & 0x1ff)    //GETB
   248  				reg.Set(lbase+A, reg.Get(lbase+B))
   249  			}
   250  			cf.Pc = pc
   251  			return 0
   252  		},
   253  		func(L *LState, inst uint32, baseframe *callFrame) int { //OP_LOADK
   254  			reg := L.reg
   255  			cf := L.currentFrame
   256  			lbase := cf.LocalBase
   257  			A := int(inst>>18) & 0xff //GETA
   258  			RA := lbase + A
   259  			Bx := int(inst & 0x3ffff) //GETBX
   260  			reg.Set(RA, cf.Fn.Proto.Constants[Bx])
   261  			return 0
   262  		},
   263  		func(L *LState, inst uint32, baseframe *callFrame) int { //OP_LOADBOOL
   264  			reg := L.reg
   265  			cf := L.currentFrame
   266  			lbase := cf.LocalBase
   267  			A := int(inst>>18) & 0xff //GETA
   268  			RA := lbase + A
   269  			B := int(inst & 0x1ff)    //GETB
   270  			C := int(inst>>9) & 0x1ff //GETC
   271  			if B != 0 {
   272  				reg.Set(RA, LTrue)
   273  			} else {
   274  				reg.Set(RA, LFalse)
   275  			}
   276  			if C != 0 {
   277  				cf.Pc++
   278  			}
   279  			return 0
   280  		},
   281  		func(L *LState, inst uint32, baseframe *callFrame) int { //OP_LOADNIL
   282  			reg := L.reg
   283  			cf := L.currentFrame
   284  			lbase := cf.LocalBase
   285  			A := int(inst>>18) & 0xff //GETA
   286  			RA := lbase + A
   287  			B := int(inst & 0x1ff) //GETB
   288  			for i := RA; i <= lbase+B; i++ {
   289  				reg.Set(i, LNil)
   290  			}
   291  			return 0
   292  		},
   293  		func(L *LState, inst uint32, baseframe *callFrame) int { //OP_GETUPVAL
   294  			reg := L.reg
   295  			cf := L.currentFrame
   296  			lbase := cf.LocalBase
   297  			A := int(inst>>18) & 0xff //GETA
   298  			RA := lbase + A
   299  			B := int(inst & 0x1ff) //GETB
   300  			reg.Set(RA, cf.Fn.Upvalues[B].Value())
   301  			return 0
   302  		},
   303  		func(L *LState, inst uint32, baseframe *callFrame) int { //OP_GETGLOBAL
   304  			reg := L.reg
   305  			cf := L.currentFrame
   306  			lbase := cf.LocalBase
   307  			A := int(inst>>18) & 0xff //GETA
   308  			RA := lbase + A
   309  			Bx := int(inst & 0x3ffff) //GETBX
   310  			//reg.Set(RA, L.getField(cf.Fn.Env, cf.Fn.Proto.Constants[Bx]))
   311  			reg.Set(RA, L.getFieldString(cf.Fn.Env, cf.Fn.Proto.stringConstants[Bx]))
   312  			return 0
   313  		},
   314  		func(L *LState, inst uint32, baseframe *callFrame) int { //OP_GETTABLE
   315  			reg := L.reg
   316  			cf := L.currentFrame
   317  			lbase := cf.LocalBase
   318  			A := int(inst>>18) & 0xff //GETA
   319  			RA := lbase + A
   320  			B := int(inst & 0x1ff)    //GETB
   321  			C := int(inst>>9) & 0x1ff //GETC
   322  			reg.Set(RA, L.getField(reg.Get(lbase+B), L.rkValue(C)))
   323  			return 0
   324  		},
   325  		func(L *LState, inst uint32, baseframe *callFrame) int { //OP_GETTABLEKS
   326  			reg := L.reg
   327  			cf := L.currentFrame
   328  			lbase := cf.LocalBase
   329  			A := int(inst>>18) & 0xff //GETA
   330  			RA := lbase + A
   331  			B := int(inst & 0x1ff)    //GETB
   332  			C := int(inst>>9) & 0x1ff //GETC
   333  			reg.Set(RA, L.getFieldString(reg.Get(lbase+B), L.rkString(C)))
   334  			return 0
   335  		},
   336  		func(L *LState, inst uint32, baseframe *callFrame) int { //OP_SETGLOBAL
   337  			reg := L.reg
   338  			cf := L.currentFrame
   339  			lbase := cf.LocalBase
   340  			A := int(inst>>18) & 0xff //GETA
   341  			RA := lbase + A
   342  			Bx := int(inst & 0x3ffff) //GETBX
   343  			//L.setField(cf.Fn.Env, cf.Fn.Proto.Constants[Bx], reg.Get(RA))
   344  			L.setFieldString(cf.Fn.Env, cf.Fn.Proto.stringConstants[Bx], reg.Get(RA))
   345  			return 0
   346  		},
   347  		func(L *LState, inst uint32, baseframe *callFrame) int { //OP_SETUPVAL
   348  			reg := L.reg
   349  			cf := L.currentFrame
   350  			lbase := cf.LocalBase
   351  			A := int(inst>>18) & 0xff //GETA
   352  			RA := lbase + A
   353  			B := int(inst & 0x1ff) //GETB
   354  			cf.Fn.Upvalues[B].SetValue(reg.Get(RA))
   355  			return 0
   356  		},
   357  		func(L *LState, inst uint32, baseframe *callFrame) int { //OP_SETTABLE
   358  			reg := L.reg
   359  			cf := L.currentFrame
   360  			lbase := cf.LocalBase
   361  			A := int(inst>>18) & 0xff //GETA
   362  			RA := lbase + A
   363  			B := int(inst & 0x1ff)    //GETB
   364  			C := int(inst>>9) & 0x1ff //GETC
   365  			L.setField(reg.Get(RA), L.rkValue(B), L.rkValue(C))
   366  			return 0
   367  		},
   368  		func(L *LState, inst uint32, baseframe *callFrame) int { //OP_SETTABLEKS
   369  			reg := L.reg
   370  			cf := L.currentFrame
   371  			lbase := cf.LocalBase
   372  			A := int(inst>>18) & 0xff //GETA
   373  			RA := lbase + A
   374  			B := int(inst & 0x1ff)    //GETB
   375  			C := int(inst>>9) & 0x1ff //GETC
   376  			L.setFieldString(reg.Get(RA), L.rkString(B), L.rkValue(C))
   377  			return 0
   378  		},
   379  		func(L *LState, inst uint32, baseframe *callFrame) int { //OP_NEWTABLE
   380  			reg := L.reg
   381  			cf := L.currentFrame
   382  			lbase := cf.LocalBase
   383  			A := int(inst>>18) & 0xff //GETA
   384  			RA := lbase + A
   385  			B := int(inst & 0x1ff)    //GETB
   386  			C := int(inst>>9) & 0x1ff //GETC
   387  			reg.Set(RA, newLTable(B, C))
   388  			return 0
   389  		},
   390  		func(L *LState, inst uint32, baseframe *callFrame) int { //OP_SELF
   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  			C := int(inst>>9) & 0x1ff //GETC
   398  			selfobj := reg.Get(lbase + B)
   399  			reg.Set(RA, L.getFieldString(selfobj, L.rkString(C)))
   400  			reg.Set(RA+1, selfobj)
   401  			return 0
   402  		},
   403  		opArith, // OP_ADD
   404  		opArith, // OP_SUB
   405  		opArith, // OP_MUL
   406  		opArith, // OP_DIV
   407  		opArith, // OP_MOD
   408  		opArith, // OP_POW
   409  		func(L *LState, inst uint32, baseframe *callFrame) int { //OP_UNM
   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  			unaryv := L.rkValue(B)
   417  			if nm, ok := unaryv.(LNumber); ok {
   418  				reg.SetNumber(RA, -nm)
   419  			} else {
   420  				op := L.metaOp1(unaryv, "__unm")
   421  				if op.Type() == LTFunction {
   422  					reg.Push(op)
   423  					reg.Push(unaryv)
   424  					L.Call(1, 1)
   425  					reg.Set(RA, reg.Pop())
   426  				} else if str, ok1 := unaryv.(LString); ok1 {
   427  					if num, err := parseNumber(string(str)); err == nil {
   428  						reg.Set(RA, -num)
   429  					} else {
   430  						L.RaiseError("__unm undefined")
   431  					}
   432  				} else {
   433  					L.RaiseError("__unm undefined")
   434  				}
   435  			}
   436  			return 0
   437  		},
   438  		func(L *LState, inst uint32, baseframe *callFrame) int { //OP_NOT
   439  			reg := L.reg
   440  			cf := L.currentFrame
   441  			lbase := cf.LocalBase
   442  			A := int(inst>>18) & 0xff //GETA
   443  			RA := lbase + A
   444  			B := int(inst & 0x1ff) //GETB
   445  			if LVIsFalse(reg.Get(lbase + B)) {
   446  				reg.Set(RA, LTrue)
   447  			} else {
   448  				reg.Set(RA, LFalse)
   449  			}
   450  			return 0
   451  		},
   452  		func(L *LState, inst uint32, baseframe *callFrame) int { //OP_LEN
   453  			reg := L.reg
   454  			cf := L.currentFrame
   455  			lbase := cf.LocalBase
   456  			A := int(inst>>18) & 0xff //GETA
   457  			RA := lbase + A
   458  			B := int(inst & 0x1ff) //GETB
   459  			switch lv := L.rkValue(B).(type) {
   460  			case LString:
   461  				reg.SetNumber(RA, LNumber(len(lv)))
   462  			default:
   463  				op := L.metaOp1(lv, "__len")
   464  				if op.Type() == LTFunction {
   465  					reg.Push(op)
   466  					reg.Push(lv)
   467  					L.Call(1, 1)
   468  					ret := reg.Pop()
   469  					if ret.Type() == LTNumber {
   470  						reg.SetNumber(RA, ret.(LNumber))
   471  					} else {
   472  						reg.SetNumber(RA, LNumber(0))
   473  					}
   474  				} else if lv.Type() == LTTable {
   475  					reg.SetNumber(RA, LNumber(lv.(*LTable).Len()))
   476  				} else {
   477  					L.RaiseError("__len undefined")
   478  				}
   479  			}
   480  			return 0
   481  		},
   482  		func(L *LState, inst uint32, baseframe *callFrame) int { //OP_CONCAT
   483  			reg := L.reg
   484  			cf := L.currentFrame
   485  			lbase := cf.LocalBase
   486  			A := int(inst>>18) & 0xff //GETA
   487  			RA := lbase + A
   488  			B := int(inst & 0x1ff)    //GETB
   489  			C := int(inst>>9) & 0x1ff //GETC
   490  			RC := lbase + C
   491  			RB := lbase + B
   492  			reg.Set(RA, stringConcat(L, RC-RB+1, RC))
   493  			return 0
   494  		},
   495  		func(L *LState, inst uint32, baseframe *callFrame) int { //OP_JMP
   496  			cf := L.currentFrame
   497  			Sbx := int(inst&0x3ffff) - opMaxArgSbx //GETSBX
   498  			cf.Pc += Sbx
   499  			return 0
   500  		},
   501  		func(L *LState, inst uint32, baseframe *callFrame) int { //OP_EQ
   502  			cf := L.currentFrame
   503  			A := int(inst>>18) & 0xff //GETA
   504  			B := int(inst & 0x1ff)    //GETB
   505  			C := int(inst>>9) & 0x1ff //GETC
   506  			ret := equals(L, L.rkValue(B), L.rkValue(C), false)
   507  			v := 1
   508  			if ret {
   509  				v = 0
   510  			}
   511  			if v == A {
   512  				cf.Pc++
   513  			}
   514  			return 0
   515  		},
   516  		func(L *LState, inst uint32, baseframe *callFrame) int { //OP_LT
   517  			cf := L.currentFrame
   518  			A := int(inst>>18) & 0xff //GETA
   519  			B := int(inst & 0x1ff)    //GETB
   520  			C := int(inst>>9) & 0x1ff //GETC
   521  			ret := lessThan(L, L.rkValue(B), L.rkValue(C))
   522  			v := 1
   523  			if ret {
   524  				v = 0
   525  			}
   526  			if v == A {
   527  				cf.Pc++
   528  			}
   529  			return 0
   530  		},
   531  		func(L *LState, inst uint32, baseframe *callFrame) int { //OP_LE
   532  			cf := L.currentFrame
   533  			A := int(inst>>18) & 0xff //GETA
   534  			B := int(inst & 0x1ff)    //GETB
   535  			C := int(inst>>9) & 0x1ff //GETC
   536  			lhs := L.rkValue(B)
   537  			rhs := L.rkValue(C)
   538  			ret := false
   539  
   540  			if v1, ok1 := lhs.assertFloat64(); ok1 {
   541  				if v2, ok2 := rhs.assertFloat64(); ok2 {
   542  					ret = v1 <= v2
   543  				} else {
   544  					L.RaiseError("attempt to compare %v with %v", lhs.Type().String(), rhs.Type().String())
   545  				}
   546  			} else {
   547  				if lhs.Type() != rhs.Type() {
   548  					L.RaiseError("attempt to compare %v with %v", lhs.Type().String(), rhs.Type().String())
   549  				}
   550  				switch lhs.Type() {
   551  				case LTString:
   552  					ret = strCmp(string(lhs.(LString)), string(rhs.(LString))) <= 0
   553  				default:
   554  					switch objectRational(L, lhs, rhs, "__le") {
   555  					case 1:
   556  						ret = true
   557  					case 0:
   558  						ret = false
   559  					default:
   560  						ret = !objectRationalWithError(L, rhs, lhs, "__lt")
   561  					}
   562  				}
   563  			}
   564  
   565  			v := 1
   566  			if ret {
   567  				v = 0
   568  			}
   569  			if v == A {
   570  				cf.Pc++
   571  			}
   572  			return 0
   573  		},
   574  		func(L *LState, inst uint32, baseframe *callFrame) int { //OP_TEST
   575  			reg := L.reg
   576  			cf := L.currentFrame
   577  			lbase := cf.LocalBase
   578  			A := int(inst>>18) & 0xff //GETA
   579  			RA := lbase + A
   580  			C := int(inst>>9) & 0x1ff //GETC
   581  			if LVAsBool(reg.Get(RA)) == (C == 0) {
   582  				cf.Pc++
   583  			}
   584  			return 0
   585  		},
   586  		func(L *LState, inst uint32, baseframe *callFrame) int { //OP_TESTSET
   587  			reg := L.reg
   588  			cf := L.currentFrame
   589  			lbase := cf.LocalBase
   590  			A := int(inst>>18) & 0xff //GETA
   591  			RA := lbase + A
   592  			B := int(inst & 0x1ff)    //GETB
   593  			C := int(inst>>9) & 0x1ff //GETC
   594  			if value := reg.Get(lbase + B); LVAsBool(value) != (C == 0) {
   595  				reg.Set(RA, value)
   596  			} else {
   597  				cf.Pc++
   598  			}
   599  			return 0
   600  		},
   601  		func(L *LState, inst uint32, baseframe *callFrame) int { //OP_CALL
   602  			reg := L.reg
   603  			cf := L.currentFrame
   604  			lbase := cf.LocalBase
   605  			A := int(inst>>18) & 0xff //GETA
   606  			RA := lbase + A
   607  			B := int(inst & 0x1ff)    //GETB
   608  			C := int(inst>>9) & 0x1ff //GETC
   609  			nargs := B - 1
   610  			if B == 0 {
   611  				nargs = reg.Top() - (RA + 1)
   612  			}
   613  			lv := reg.Get(RA)
   614  			nret := C - 1
   615  			var callable *LFunction
   616  			var meta bool
   617  			if fn, ok := lv.assertFunction(); ok {
   618  				callable = fn
   619  				meta = false
   620  			} else {
   621  				callable, meta = L.metaCall(lv)
   622  			}
   623  			// this section is inlined by go-inline
   624  			// source function is 'func (ls *LState) pushCallFrame(cf callFrame, fn LValue, meta bool) ' in '_state.go'
   625  			{
   626  				ls := L
   627  				cf := callFrame{Fn: callable, Pc: 0, Base: RA, LocalBase: RA + 1, ReturnBase: RA, NArgs: nargs, NRet: nret, Parent: cf, TailCall: 0}
   628  				fn := lv
   629  				if meta {
   630  					cf.NArgs++
   631  					ls.reg.Insert(fn, cf.LocalBase)
   632  				}
   633  				if cf.Fn == nil {
   634  					ls.RaiseError("attempt to call a non-function object")
   635  				}
   636  				if ls.stack.sp == ls.Options.CallStackSize {
   637  					ls.RaiseError("stack overflow")
   638  				}
   639  				// this section is inlined by go-inline
   640  				// source function is 'func (cs *callFrameStack) Push(v callFrame) ' in '_state.go'
   641  				{
   642  					cs := ls.stack
   643  					v := cf
   644  					cs.array[cs.sp] = v
   645  					cs.array[cs.sp].Idx = cs.sp
   646  					cs.sp++
   647  				}
   648  				newcf := ls.stack.Last()
   649  				// this section is inlined by go-inline
   650  				// source function is 'func (ls *LState) initCallFrame(cf *callFrame) ' in '_state.go'
   651  				{
   652  					cf := newcf
   653  					if cf.Fn.IsG {
   654  						ls.reg.SetTop(cf.LocalBase + cf.NArgs)
   655  					} else {
   656  						proto := cf.Fn.Proto
   657  						nargs := cf.NArgs
   658  						np := int(proto.NumParameters)
   659  						for i := nargs; i < np; i++ {
   660  							ls.reg.array[cf.LocalBase+i] = LNil
   661  							nargs = np
   662  						}
   663  
   664  						if (proto.IsVarArg & VarArgIsVarArg) == 0 {
   665  							if nargs < int(proto.NumUsedRegisters) {
   666  								nargs = int(proto.NumUsedRegisters)
   667  							}
   668  							for i := np; i < nargs; i++ {
   669  								ls.reg.array[cf.LocalBase+i] = LNil
   670  							}
   671  							ls.reg.top = cf.LocalBase + int(proto.NumUsedRegisters)
   672  						} else {
   673  							/* swap vararg positions:
   674  									   closure
   675  									   namedparam1 <- lbase
   676  									   namedparam2
   677  									   vararg1
   678  									   vararg2
   679  
   680  							           TO
   681  
   682  									   closure
   683  									   nil
   684  									   nil
   685  									   vararg1
   686  									   vararg2
   687  									   namedparam1 <- lbase
   688  									   namedparam2
   689  							*/
   690  							nvarargs := nargs - np
   691  							if nvarargs < 0 {
   692  								nvarargs = 0
   693  							}
   694  
   695  							ls.reg.SetTop(cf.LocalBase + nargs + np)
   696  							for i := 0; i < np; i++ {
   697  								//ls.reg.Set(cf.LocalBase+nargs+i, ls.reg.Get(cf.LocalBase+i))
   698  								ls.reg.array[cf.LocalBase+nargs+i] = ls.reg.array[cf.LocalBase+i]
   699  								//ls.reg.Set(cf.LocalBase+i, LNil)
   700  								ls.reg.array[cf.LocalBase+i] = LNil
   701  							}
   702  
   703  							if CompatVarArg {
   704  								ls.reg.SetTop(cf.LocalBase + nargs + np + 1)
   705  								if (proto.IsVarArg & VarArgNeedsArg) != 0 {
   706  									argtb := newLTable(nvarargs, 0)
   707  									for i := 0; i < nvarargs; i++ {
   708  										argtb.RawSetInt(i+1, ls.reg.Get(cf.LocalBase+np+i))
   709  									}
   710  									argtb.RawSetString("n", LNumber(nvarargs))
   711  									//ls.reg.Set(cf.LocalBase+nargs+np, argtb)
   712  									ls.reg.array[cf.LocalBase+nargs+np] = argtb
   713  								} else {
   714  									ls.reg.array[cf.LocalBase+nargs+np] = LNil
   715  								}
   716  							}
   717  							cf.LocalBase += nargs
   718  							maxreg := cf.LocalBase + int(proto.NumUsedRegisters)
   719  							ls.reg.SetTop(maxreg)
   720  						}
   721  					}
   722  				}
   723  				ls.currentFrame = newcf
   724  			}
   725  			if callable.IsG && callGFunction(L, false) {
   726  				return 1
   727  			}
   728  			return 0
   729  		},
   730  		func(L *LState, inst uint32, baseframe *callFrame) int { //OP_TAILCALL
   731  			reg := L.reg
   732  			cf := L.currentFrame
   733  			lbase := cf.LocalBase
   734  			A := int(inst>>18) & 0xff //GETA
   735  			RA := lbase + A
   736  			B := int(inst & 0x1ff) //GETB
   737  			nargs := B - 1
   738  			if B == 0 {
   739  				nargs = reg.Top() - (RA + 1)
   740  			}
   741  			lv := reg.Get(RA)
   742  			var callable *LFunction
   743  			var meta bool
   744  			if fn, ok := lv.assertFunction(); ok {
   745  				callable = fn
   746  				meta = false
   747  			} else {
   748  				callable, meta = L.metaCall(lv)
   749  			}
   750  			if callable == nil {
   751  				L.RaiseError("attempt to call a non-function object")
   752  			}
   753  			// this section is inlined by go-inline
   754  			// source function is 'func (ls *LState) closeUpvalues(idx int) ' in '_state.go'
   755  			{
   756  				ls := L
   757  				idx := lbase
   758  				if ls.uvcache != nil {
   759  					var prev *Upvalue
   760  					for uv := ls.uvcache; uv != nil; uv = uv.next {
   761  						if uv.index >= idx {
   762  							if prev != nil {
   763  								prev.next = nil
   764  							} else {
   765  								ls.uvcache = nil
   766  							}
   767  							uv.Close()
   768  						}
   769  						prev = uv
   770  					}
   771  				}
   772  			}
   773  			if callable.IsG {
   774  				luaframe := cf
   775  				L.pushCallFrame(callFrame{
   776  					Fn:         callable,
   777  					Pc:         0,
   778  					Base:       RA,
   779  					LocalBase:  RA + 1,
   780  					ReturnBase: cf.ReturnBase,
   781  					NArgs:      nargs,
   782  					NRet:       cf.NRet,
   783  					Parent:     cf,
   784  					TailCall:   0,
   785  				}, lv, meta)
   786  				if callGFunction(L, true) {
   787  					return 1
   788  				}
   789  				if L.currentFrame == nil || L.currentFrame.Fn.IsG || luaframe == baseframe {
   790  					return 1
   791  				}
   792  			} else {
   793  				base := cf.Base
   794  				cf.Fn = callable
   795  				cf.Pc = 0
   796  				cf.Base = RA
   797  				cf.LocalBase = RA + 1
   798  				cf.ReturnBase = cf.ReturnBase
   799  				cf.NArgs = nargs
   800  				cf.NRet = cf.NRet
   801  				cf.TailCall++
   802  				lbase := cf.LocalBase
   803  				if meta {
   804  					cf.NArgs++
   805  					L.reg.Insert(lv, cf.LocalBase)
   806  				}
   807  				// this section is inlined by go-inline
   808  				// source function is 'func (ls *LState) initCallFrame(cf *callFrame) ' in '_state.go'
   809  				{
   810  					ls := L
   811  					if cf.Fn.IsG {
   812  						ls.reg.SetTop(cf.LocalBase + cf.NArgs)
   813  					} else {
   814  						proto := cf.Fn.Proto
   815  						nargs := cf.NArgs
   816  						np := int(proto.NumParameters)
   817  						for i := nargs; i < np; i++ {
   818  							ls.reg.array[cf.LocalBase+i] = LNil
   819  							nargs = np
   820  						}
   821  
   822  						if (proto.IsVarArg & VarArgIsVarArg) == 0 {
   823  							if nargs < int(proto.NumUsedRegisters) {
   824  								nargs = int(proto.NumUsedRegisters)
   825  							}
   826  							for i := np; i < nargs; i++ {
   827  								ls.reg.array[cf.LocalBase+i] = LNil
   828  							}
   829  							ls.reg.top = cf.LocalBase + int(proto.NumUsedRegisters)
   830  						} else {
   831  							/* swap vararg positions:
   832  									   closure
   833  									   namedparam1 <- lbase
   834  									   namedparam2
   835  									   vararg1
   836  									   vararg2
   837  
   838  							           TO
   839  
   840  									   closure
   841  									   nil
   842  									   nil
   843  									   vararg1
   844  									   vararg2
   845  									   namedparam1 <- lbase
   846  									   namedparam2
   847  							*/
   848  							nvarargs := nargs - np
   849  							if nvarargs < 0 {
   850  								nvarargs = 0
   851  							}
   852  
   853  							ls.reg.SetTop(cf.LocalBase + nargs + np)
   854  							for i := 0; i < np; i++ {
   855  								//ls.reg.Set(cf.LocalBase+nargs+i, ls.reg.Get(cf.LocalBase+i))
   856  								ls.reg.array[cf.LocalBase+nargs+i] = ls.reg.array[cf.LocalBase+i]
   857  								//ls.reg.Set(cf.LocalBase+i, LNil)
   858  								ls.reg.array[cf.LocalBase+i] = LNil
   859  							}
   860  
   861  							if CompatVarArg {
   862  								ls.reg.SetTop(cf.LocalBase + nargs + np + 1)
   863  								if (proto.IsVarArg & VarArgNeedsArg) != 0 {
   864  									argtb := newLTable(nvarargs, 0)
   865  									for i := 0; i < nvarargs; i++ {
   866  										argtb.RawSetInt(i+1, ls.reg.Get(cf.LocalBase+np+i))
   867  									}
   868  									argtb.RawSetString("n", LNumber(nvarargs))
   869  									//ls.reg.Set(cf.LocalBase+nargs+np, argtb)
   870  									ls.reg.array[cf.LocalBase+nargs+np] = argtb
   871  								} else {
   872  									ls.reg.array[cf.LocalBase+nargs+np] = LNil
   873  								}
   874  							}
   875  							cf.LocalBase += nargs
   876  							maxreg := cf.LocalBase + int(proto.NumUsedRegisters)
   877  							ls.reg.SetTop(maxreg)
   878  						}
   879  					}
   880  				}
   881  				// this section is inlined by go-inline
   882  				// source function is 'func (rg *registry) CopyRange(regv, start, limit, n int) ' in '_state.go'
   883  				{
   884  					rg := L.reg
   885  					regv := base
   886  					start := RA
   887  					limit := -1
   888  					n := reg.Top() - RA - 1
   889  					for i := 0; i < n; i++ {
   890  						if tidx := start + i; tidx >= rg.top || limit > -1 && tidx >= limit || tidx < 0 {
   891  							rg.array[regv+i] = LNil
   892  						} else {
   893  							rg.array[regv+i] = rg.array[tidx]
   894  						}
   895  					}
   896  					rg.top = regv + n
   897  				}
   898  				cf.Base = base
   899  				cf.LocalBase = base + (cf.LocalBase - lbase + 1)
   900  			}
   901  			return 0
   902  		},
   903  		func(L *LState, inst uint32, baseframe *callFrame) int { //OP_RETURN
   904  			reg := L.reg
   905  			cf := L.currentFrame
   906  			lbase := cf.LocalBase
   907  			A := int(inst>>18) & 0xff //GETA
   908  			RA := lbase + A
   909  			B := int(inst & 0x1ff) //GETB
   910  			// this section is inlined by go-inline
   911  			// source function is 'func (ls *LState) closeUpvalues(idx int) ' in '_state.go'
   912  			{
   913  				ls := L
   914  				idx := lbase
   915  				if ls.uvcache != nil {
   916  					var prev *Upvalue
   917  					for uv := ls.uvcache; uv != nil; uv = uv.next {
   918  						if uv.index >= idx {
   919  							if prev != nil {
   920  								prev.next = nil
   921  							} else {
   922  								ls.uvcache = nil
   923  							}
   924  							uv.Close()
   925  						}
   926  						prev = uv
   927  					}
   928  				}
   929  			}
   930  			nret := B - 1
   931  			if B == 0 {
   932  				nret = reg.Top() - RA
   933  			}
   934  			n := cf.NRet
   935  			if cf.NRet == MultRet {
   936  				n = nret
   937  			}
   938  
   939  			if L.Parent != nil && L.stack.Sp() == 1 {
   940  				// this section is inlined by go-inline
   941  				// source function is 'func copyReturnValues(L *LState, regv, start, n, b int) ' in '_vm.go'
   942  				{
   943  					regv := reg.Top()
   944  					start := RA
   945  					b := B
   946  					if b == 1 {
   947  						// this section is inlined by go-inline
   948  						// source function is 'func (rg *registry) FillNil(regm, n int) ' in '_state.go'
   949  						{
   950  							rg := L.reg
   951  							regm := regv
   952  							for i := 0; i < n; i++ {
   953  								rg.array[regm+i] = LNil
   954  							}
   955  							rg.top = regm + n
   956  						}
   957  					} else {
   958  						// this section is inlined by go-inline
   959  						// source function is 'func (rg *registry) CopyRange(regv, start, limit, n int) ' in '_state.go'
   960  						{
   961  							rg := L.reg
   962  							limit := -1
   963  							for i := 0; i < n; i++ {
   964  								if tidx := start + i; tidx >= rg.top || limit > -1 && tidx >= limit || tidx < 0 {
   965  									rg.array[regv+i] = LNil
   966  								} else {
   967  									rg.array[regv+i] = rg.array[tidx]
   968  								}
   969  							}
   970  							rg.top = regv + n
   971  						}
   972  					}
   973  				}
   974  				switchToParentThread(L, n, false, true)
   975  				return 1
   976  			}
   977  			islast := baseframe == L.stack.Pop() || L.stack.IsEmpty()
   978  			// this section is inlined by go-inline
   979  			// source function is 'func copyReturnValues(L *LState, regv, start, n, b int) ' in '_vm.go'
   980  			{
   981  				regv := cf.ReturnBase
   982  				start := RA
   983  				b := B
   984  				if b == 1 {
   985  					// this section is inlined by go-inline
   986  					// source function is 'func (rg *registry) FillNil(regm, n int) ' in '_state.go'
   987  					{
   988  						rg := L.reg
   989  						regm := regv
   990  						for i := 0; i < n; i++ {
   991  							rg.array[regm+i] = LNil
   992  						}
   993  						rg.top = regm + n
   994  					}
   995  				} else {
   996  					// this section is inlined by go-inline
   997  					// source function is 'func (rg *registry) CopyRange(regv, start, limit, n int) ' in '_state.go'
   998  					{
   999  						rg := L.reg
  1000  						limit := -1
  1001  						for i := 0; i < n; i++ {
  1002  							if tidx := start + i; tidx >= rg.top || limit > -1 && tidx >= limit || tidx < 0 {
  1003  								rg.array[regv+i] = LNil
  1004  							} else {
  1005  								rg.array[regv+i] = rg.array[tidx]
  1006  							}
  1007  						}
  1008  						rg.top = regv + n
  1009  					}
  1010  				}
  1011  			}
  1012  			L.currentFrame = L.stack.Last()
  1013  			if islast || L.currentFrame == nil || L.currentFrame.Fn.IsG {
  1014  				return 1
  1015  			}
  1016  			return 0
  1017  		},
  1018  		func(L *LState, inst uint32, baseframe *callFrame) int { //OP_FORLOOP
  1019  			reg := L.reg
  1020  			cf := L.currentFrame
  1021  			lbase := cf.LocalBase
  1022  			A := int(inst>>18) & 0xff //GETA
  1023  			RA := lbase + A
  1024  			if init, ok1 := reg.Get(RA).assertFloat64(); ok1 {
  1025  				if limit, ok2 := reg.Get(RA + 1).assertFloat64(); ok2 {
  1026  					if step, ok3 := reg.Get(RA + 2).assertFloat64(); ok3 {
  1027  						init += step
  1028  						reg.SetNumber(RA, LNumber(init))
  1029  						if (step > 0 && init <= limit) || (step <= 0 && init >= limit) {
  1030  							Sbx := int(inst&0x3ffff) - opMaxArgSbx //GETSBX
  1031  							cf.Pc += Sbx
  1032  							reg.SetNumber(RA+3, LNumber(init))
  1033  						} else {
  1034  							reg.SetTop(RA + 1)
  1035  						}
  1036  					} else {
  1037  						L.RaiseError("for statement step must be a number")
  1038  					}
  1039  				} else {
  1040  					L.RaiseError("for statement limit must be a number")
  1041  				}
  1042  			} else {
  1043  				L.RaiseError("for statement init must be a number")
  1044  			}
  1045  			return 0
  1046  		},
  1047  		func(L *LState, inst uint32, baseframe *callFrame) int { //OP_FORPREP
  1048  			reg := L.reg
  1049  			cf := L.currentFrame
  1050  			lbase := cf.LocalBase
  1051  			A := int(inst>>18) & 0xff //GETA
  1052  			RA := lbase + A
  1053  			Sbx := int(inst&0x3ffff) - opMaxArgSbx //GETSBX
  1054  			if init, ok1 := reg.Get(RA).assertFloat64(); ok1 {
  1055  				if step, ok2 := reg.Get(RA + 2).assertFloat64(); ok2 {
  1056  					reg.SetNumber(RA, LNumber(init-step))
  1057  				} else {
  1058  					L.RaiseError("for statement step must be a number")
  1059  				}
  1060  			} else {
  1061  				L.RaiseError("for statement init must be a number")
  1062  			}
  1063  			cf.Pc += Sbx
  1064  			return 0
  1065  		},
  1066  		func(L *LState, inst uint32, baseframe *callFrame) int { //OP_TFORLOOP
  1067  			reg := L.reg
  1068  			cf := L.currentFrame
  1069  			lbase := cf.LocalBase
  1070  			A := int(inst>>18) & 0xff //GETA
  1071  			RA := lbase + A
  1072  			C := int(inst>>9) & 0x1ff //GETC
  1073  			nret := C
  1074  			reg.SetTop(RA + 3 + 2)
  1075  			reg.Set(RA+3+2, reg.Get(RA+2))
  1076  			reg.Set(RA+3+1, reg.Get(RA+1))
  1077  			reg.Set(RA+3, reg.Get(RA))
  1078  			L.callR(2, nret, RA+3)
  1079  			if value := reg.Get(RA + 3); value != LNil {
  1080  				reg.Set(RA+2, value)
  1081  				pc := cf.Fn.Proto.Code[cf.Pc]
  1082  				cf.Pc += int(pc&0x3ffff) - opMaxArgSbx
  1083  			}
  1084  			cf.Pc++
  1085  			return 0
  1086  		},
  1087  		func(L *LState, inst uint32, baseframe *callFrame) int { //OP_SETLIST
  1088  			reg := L.reg
  1089  			cf := L.currentFrame
  1090  			lbase := cf.LocalBase
  1091  			A := int(inst>>18) & 0xff //GETA
  1092  			RA := lbase + A
  1093  			B := int(inst & 0x1ff)    //GETB
  1094  			C := int(inst>>9) & 0x1ff //GETC
  1095  			if C == 0 {
  1096  				C = int(cf.Fn.Proto.Code[cf.Pc])
  1097  				cf.Pc++
  1098  			}
  1099  			offset := (C - 1) * FieldsPerFlush
  1100  			table := reg.Get(RA).(*LTable)
  1101  			nelem := B
  1102  			if B == 0 {
  1103  				nelem = reg.Top() - RA - 1
  1104  			}
  1105  			for i := 1; i <= nelem; i++ {
  1106  				table.RawSetInt(offset+i, reg.Get(RA+i))
  1107  			}
  1108  			return 0
  1109  		},
  1110  		func(L *LState, inst uint32, baseframe *callFrame) int { //OP_CLOSE
  1111  			cf := L.currentFrame
  1112  			lbase := cf.LocalBase
  1113  			A := int(inst>>18) & 0xff //GETA
  1114  			RA := lbase + A
  1115  			// this section is inlined by go-inline
  1116  			// source function is 'func (ls *LState) closeUpvalues(idx int) ' in '_state.go'
  1117  			{
  1118  				ls := L
  1119  				idx := RA
  1120  				if ls.uvcache != nil {
  1121  					var prev *Upvalue
  1122  					for uv := ls.uvcache; uv != nil; uv = uv.next {
  1123  						if uv.index >= idx {
  1124  							if prev != nil {
  1125  								prev.next = nil
  1126  							} else {
  1127  								ls.uvcache = nil
  1128  							}
  1129  							uv.Close()
  1130  						}
  1131  						prev = uv
  1132  					}
  1133  				}
  1134  			}
  1135  			return 0
  1136  		},
  1137  		func(L *LState, inst uint32, baseframe *callFrame) int { //OP_CLOSURE
  1138  			reg := L.reg
  1139  			cf := L.currentFrame
  1140  			lbase := cf.LocalBase
  1141  			A := int(inst>>18) & 0xff //GETA
  1142  			RA := lbase + A
  1143  			Bx := int(inst & 0x3ffff) //GETBX
  1144  			proto := cf.Fn.Proto.FunctionPrototypes[Bx]
  1145  			closure := newLFunctionL(proto, cf.Fn.Env, int(proto.NumUpvalues))
  1146  			reg.Set(RA, closure)
  1147  			for i := 0; i < int(proto.NumUpvalues); i++ {
  1148  				inst = cf.Fn.Proto.Code[cf.Pc]
  1149  				cf.Pc++
  1150  				B := opGetArgB(inst)
  1151  				switch opGetOpCode(inst) {
  1152  				case OP_MOVE:
  1153  					closure.Upvalues[i] = L.findUpvalue(lbase + B)
  1154  				case OP_GETUPVAL:
  1155  					closure.Upvalues[i] = cf.Fn.Upvalues[B]
  1156  				}
  1157  			}
  1158  			return 0
  1159  		},
  1160  		func(L *LState, inst uint32, baseframe *callFrame) int { //OP_VARARG
  1161  			reg := L.reg
  1162  			cf := L.currentFrame
  1163  			lbase := cf.LocalBase
  1164  			A := int(inst>>18) & 0xff //GETA
  1165  			RA := lbase + A
  1166  			B := int(inst & 0x1ff) //GETB
  1167  			nparams := int(cf.Fn.Proto.NumParameters)
  1168  			nvarargs := cf.NArgs - nparams
  1169  			if nvarargs < 0 {
  1170  				nvarargs = 0
  1171  			}
  1172  			nwant := B - 1
  1173  			if B == 0 {
  1174  				nwant = nvarargs
  1175  			}
  1176  			// this section is inlined by go-inline
  1177  			// source function is 'func (rg *registry) CopyRange(regv, start, limit, n int) ' in '_state.go'
  1178  			{
  1179  				rg := reg
  1180  				regv := RA
  1181  				start := cf.Base + nparams + 1
  1182  				limit := cf.LocalBase
  1183  				n := nwant
  1184  				for i := 0; i < n; i++ {
  1185  					if tidx := start + i; tidx >= rg.top || limit > -1 && tidx >= limit || tidx < 0 {
  1186  						rg.array[regv+i] = LNil
  1187  					} else {
  1188  						rg.array[regv+i] = rg.array[tidx]
  1189  					}
  1190  				}
  1191  				rg.top = regv + n
  1192  			}
  1193  			return 0
  1194  		},
  1195  		func(L *LState, inst uint32, baseframe *callFrame) int { //OP_NOP
  1196  			return 0
  1197  		},
  1198  	}
  1199  }
  1200  
  1201  func opArith(L *LState, inst uint32, baseframe *callFrame) int { //OP_ADD, OP_SUB, OP_MUL, OP_DIV, OP_MOD, OP_POW
  1202  	reg := L.reg
  1203  	cf := L.currentFrame
  1204  	lbase := cf.LocalBase
  1205  	A := int(inst>>18) & 0xff //GETA
  1206  	RA := lbase + A
  1207  	opcode := int(inst >> 26) //GETOPCODE
  1208  	B := int(inst & 0x1ff)    //GETB
  1209  	C := int(inst>>9) & 0x1ff //GETC
  1210  	lhs := L.rkValue(B)
  1211  	rhs := L.rkValue(C)
  1212  	v1, ok1 := lhs.assertFloat64()
  1213  	v2, ok2 := rhs.assertFloat64()
  1214  	if ok1 && ok2 {
  1215  		reg.SetNumber(RA, numberArith(L, opcode, LNumber(v1), LNumber(v2)))
  1216  	} else {
  1217  		reg.Set(RA, objectArith(L, opcode, lhs, rhs))
  1218  	}
  1219  	return 0
  1220  }
  1221  
  1222  func luaModulo(lhs, rhs LNumber) LNumber {
  1223  	flhs := float64(lhs)
  1224  	frhs := float64(rhs)
  1225  	v := math.Mod(flhs, frhs)
  1226  	if flhs < 0 || frhs < 0 && !(flhs < 0 && frhs < 0) {
  1227  		v += frhs
  1228  	}
  1229  	return LNumber(v)
  1230  }
  1231  
  1232  func numberArith(L *LState, opcode int, lhs, rhs LNumber) LNumber {
  1233  	switch opcode {
  1234  	case OP_ADD:
  1235  		return lhs + rhs
  1236  	case OP_SUB:
  1237  		return lhs - rhs
  1238  	case OP_MUL:
  1239  		return lhs * rhs
  1240  	case OP_DIV:
  1241  		return lhs / rhs
  1242  	case OP_MOD:
  1243  		return luaModulo(lhs, rhs)
  1244  	case OP_POW:
  1245  		flhs := float64(lhs)
  1246  		frhs := float64(rhs)
  1247  		return LNumber(math.Pow(flhs, frhs))
  1248  	}
  1249  	panic("should not reach here")
  1250  	return LNumber(0)
  1251  }
  1252  
  1253  func objectArith(L *LState, opcode int, lhs, rhs LValue) LValue {
  1254  	event := ""
  1255  	switch opcode {
  1256  	case OP_ADD:
  1257  		event = "__add"
  1258  	case OP_SUB:
  1259  		event = "__sub"
  1260  	case OP_MUL:
  1261  		event = "__mul"
  1262  	case OP_DIV:
  1263  		event = "__div"
  1264  	case OP_MOD:
  1265  		event = "__mod"
  1266  	case OP_POW:
  1267  		event = "__pow"
  1268  	}
  1269  	op := L.metaOp2(lhs, rhs, event)
  1270  	if op.Type() == LTFunction {
  1271  		L.reg.Push(op)
  1272  		L.reg.Push(lhs)
  1273  		L.reg.Push(rhs)
  1274  		L.Call(2, 1)
  1275  		return L.reg.Pop()
  1276  	}
  1277  	if str, ok := lhs.(LString); ok {
  1278  		if lnum, err := parseNumber(string(str)); err == nil {
  1279  			lhs = lnum
  1280  		}
  1281  	}
  1282  	if str, ok := rhs.(LString); ok {
  1283  		if rnum, err := parseNumber(string(str)); err == nil {
  1284  			rhs = rnum
  1285  		}
  1286  	}
  1287  	if v1, ok1 := lhs.assertFloat64(); ok1 {
  1288  		if v2, ok2 := rhs.assertFloat64(); ok2 {
  1289  			return numberArith(L, opcode, LNumber(v1), LNumber(v2))
  1290  		}
  1291  	}
  1292  	L.RaiseError(fmt.Sprintf("cannot perform %v operation between %v and %v",
  1293  		strings.TrimLeft(event, "_"), lhs.Type().String(), rhs.Type().String()))
  1294  
  1295  	return LNil
  1296  }
  1297  
  1298  func stringConcat(L *LState, total, last int) LValue {
  1299  	rhs := L.reg.Get(last)
  1300  	total--
  1301  	for i := last - 1; total > 0; {
  1302  		lhs := L.reg.Get(i)
  1303  		if !(LVCanConvToString(lhs) && LVCanConvToString(rhs)) {
  1304  			op := L.metaOp2(lhs, rhs, "__concat")
  1305  			if op.Type() == LTFunction {
  1306  				L.reg.Push(op)
  1307  				L.reg.Push(lhs)
  1308  				L.reg.Push(rhs)
  1309  				L.Call(2, 1)
  1310  				rhs = L.reg.Pop()
  1311  				total--
  1312  				i--
  1313  			} else {
  1314  				L.RaiseError("cannot perform concat operation between %v and %v", lhs.Type().String(), rhs.Type().String())
  1315  				return LNil
  1316  			}
  1317  		} else {
  1318  			buf := make([]string, total+1)
  1319  			buf[total] = LVAsString(rhs)
  1320  			for total > 0 {
  1321  				lhs = L.reg.Get(i)
  1322  				if !LVCanConvToString(lhs) {
  1323  					break
  1324  				}
  1325  				buf[total-1] = LVAsString(lhs)
  1326  				i--
  1327  				total--
  1328  			}
  1329  			rhs = LString(strings.Join(buf, ""))
  1330  		}
  1331  	}
  1332  	return rhs
  1333  }
  1334  
  1335  func lessThan(L *LState, lhs, rhs LValue) bool {
  1336  	// optimization for numbers
  1337  	if v1, ok1 := lhs.assertFloat64(); ok1 {
  1338  		if v2, ok2 := rhs.assertFloat64(); ok2 {
  1339  			return v1 < v2
  1340  		}
  1341  		L.RaiseError("attempt to compare %v with %v", lhs.Type().String(), rhs.Type().String())
  1342  	}
  1343  	if lhs.Type() != rhs.Type() {
  1344  		L.RaiseError("attempt to compare %v with %v", lhs.Type().String(), rhs.Type().String())
  1345  		return false
  1346  	}
  1347  	ret := false
  1348  	switch lhs.Type() {
  1349  	case LTString:
  1350  		ret = strCmp(string(lhs.(LString)), string(rhs.(LString))) < 0
  1351  	default:
  1352  		ret = objectRationalWithError(L, lhs, rhs, "__lt")
  1353  	}
  1354  	return ret
  1355  }
  1356  
  1357  func equals(L *LState, lhs, rhs LValue, raw bool) bool {
  1358  	if lhs.Type() != rhs.Type() {
  1359  		return false
  1360  	}
  1361  
  1362  	ret := false
  1363  	switch lhs.Type() {
  1364  	case LTNil:
  1365  		ret = true
  1366  	case LTNumber:
  1367  		v1, _ := lhs.assertFloat64()
  1368  		v2, _ := rhs.assertFloat64()
  1369  		ret = v1 == v2
  1370  	case LTBool:
  1371  		ret = bool(lhs.(LBool)) == bool(rhs.(LBool))
  1372  	case LTString:
  1373  		ret = string(lhs.(LString)) == string(rhs.(LString))
  1374  	case LTUserData, LTTable:
  1375  		if lhs == rhs {
  1376  			ret = true
  1377  		} else if !raw {
  1378  			switch objectRational(L, lhs, rhs, "__eq") {
  1379  			case 1:
  1380  				ret = true
  1381  			default:
  1382  				ret = false
  1383  			}
  1384  		}
  1385  	default:
  1386  		ret = lhs == rhs
  1387  	}
  1388  	return ret
  1389  }
  1390  
  1391  func objectRationalWithError(L *LState, lhs, rhs LValue, event string) bool {
  1392  	switch objectRational(L, lhs, rhs, event) {
  1393  	case 1:
  1394  		return true
  1395  	case 0:
  1396  		return false
  1397  	}
  1398  	L.RaiseError("attempt to compare %v with %v", lhs.Type().String(), rhs.Type().String())
  1399  	return false
  1400  }
  1401  
  1402  func objectRational(L *LState, lhs, rhs LValue, event string) int {
  1403  	m1 := L.metaOp1(lhs, event)
  1404  	m2 := L.metaOp1(rhs, event)
  1405  	if m1.Type() == LTFunction && m1 == m2 {
  1406  		L.reg.Push(m1)
  1407  		L.reg.Push(lhs)
  1408  		L.reg.Push(rhs)
  1409  		L.Call(2, 1)
  1410  		if LVAsBool(L.reg.Pop()) {
  1411  			return 1
  1412  		}
  1413  		return 0
  1414  	}
  1415  	return -1
  1416  }