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

     1  package lua
     2  
     3  import (
     4  	"fmt"
     5  	"math"
     6  	"strings"
     7  )
     8  
     9  const (
    10  	errMaxInstStr = "exceeded the maximum instruction count"
    11  )
    12  
    13  func mainLoop(L *LState, baseframe *callFrame) {
    14  	var inst uint32
    15  	var cf *callFrame
    16  
    17  	if L.stack.IsEmpty() {
    18  		return
    19  	}
    20  
    21  	L.currentFrame = L.stack.Last()
    22  	if L.currentFrame.Fn.IsG {
    23  		callGFunction(L, false)
    24  		return
    25  	}
    26  
    27  	for {
    28  		cf = L.currentFrame
    29  		inst = cf.Fn.Proto.Code[cf.Pc]
    30  		cf.Pc++
    31  		opCode := int(inst >> 26)
    32  		if jumpTable[opCode](L, inst, baseframe) == 1 {
    33  			return
    34  		}
    35  		if L.Options.MaxInstSize > uint64(0) {
    36  			L.instCount += opProps[opCode].InstCount
    37  			if L.instCount > L.Options.MaxInstSize {
    38  				L.RaiseError(errMaxInstStr)
    39  				return
    40  			}
    41  		}
    42  	}
    43  }
    44  
    45  func mainLoopWithContext(L *LState, baseframe *callFrame) {
    46  	var inst uint32
    47  	var cf *callFrame
    48  
    49  	if L.stack.IsEmpty() {
    50  		return
    51  	}
    52  
    53  	L.currentFrame = L.stack.Last()
    54  	if L.currentFrame.Fn.IsG {
    55  		callGFunction(L, false)
    56  		return
    57  	}
    58  
    59  	for {
    60  		cf = L.currentFrame
    61  		inst = cf.Fn.Proto.Code[cf.Pc]
    62  		cf.Pc++
    63  		select {
    64  		case <-L.ctx.Done():
    65  			L.RaiseError(L.ctx.Err().Error())
    66  			return
    67  		default:
    68  			opCode := int(inst >> 26)
    69  			if jumpTable[opCode](L, inst, baseframe) == 1 {
    70  				return
    71  			}
    72  			if L.Options.MaxInstSize > uint64(0) {
    73  				L.instCount += opProps[opCode].InstCount
    74  				if L.instCount > L.Options.MaxInstSize {
    75  					L.RaiseError(errMaxInstStr)
    76  					return
    77  				}
    78  			}
    79  		}
    80  	}
    81  }
    82  
    83  func copyReturnValues(L *LState, regv, start, n, b int) { // +inline-start
    84  	if b == 1 {
    85  		// +inline-call L.reg.FillNil  regv n
    86  	} else {
    87  		// +inline-call L.reg.CopyRange regv start -1 n
    88  	}
    89  } // +inline-end
    90  
    91  func switchToParentThread(L *LState, nargs int, haserror bool, kill bool) {
    92  	parent := L.Parent
    93  	if parent == nil {
    94  		L.RaiseError("can not yield from outside of a coroutine")
    95  	}
    96  	L.G.CurrentThread = parent
    97  	L.Parent = nil
    98  	if !L.wrapped {
    99  		if haserror {
   100  			parent.Push(LFalse)
   101  		} else {
   102  			parent.Push(LTrue)
   103  		}
   104  	}
   105  	L.XMoveTo(parent, nargs)
   106  	L.stack.Pop()
   107  	offset := L.currentFrame.LocalBase - L.currentFrame.ReturnBase
   108  	L.currentFrame = L.stack.Last()
   109  	L.reg.SetTop(L.reg.Top() - offset) // remove 'yield' function(including tailcalled functions)
   110  	if kill {
   111  		L.kill()
   112  	}
   113  }
   114  
   115  func callGFunction(L *LState, tailcall bool) bool {
   116  	L.instCount += 40
   117  	frame := L.currentFrame
   118  	gfnret := frame.Fn.GFunction(L)
   119  	if tailcall {
   120  		L.stack.Remove(L.stack.Sp() - 2) // remove caller lua function frame
   121  		L.currentFrame = L.stack.Last()
   122  	}
   123  
   124  	if gfnret < 0 {
   125  		switchToParentThread(L, L.GetTop(), false, false)
   126  		return true
   127  	}
   128  
   129  	wantret := frame.NRet
   130  	if wantret == MultRet {
   131  		wantret = gfnret
   132  	}
   133  
   134  	if tailcall && L.Parent != nil && L.stack.Sp() == 1 {
   135  		switchToParentThread(L, wantret, false, true)
   136  		return true
   137  	}
   138  
   139  	// +inline-call L.reg.CopyRange frame.ReturnBase L.reg.Top()-gfnret -1 wantret
   140  	L.stack.Pop()
   141  	L.currentFrame = L.stack.Last()
   142  	return false
   143  }
   144  
   145  func threadRun(L *LState) {
   146  	if L.stack.IsEmpty() {
   147  		return
   148  	}
   149  
   150  	defer func() {
   151  		if rcv := recover(); rcv != nil {
   152  			var lv LValue
   153  			if v, ok := rcv.(*ApiError); ok {
   154  				lv = v.Object
   155  			} else {
   156  				lv = LString(fmt.Sprint(rcv))
   157  			}
   158  			if parent := L.Parent; parent != nil {
   159  				if L.wrapped {
   160  					L.Push(lv)
   161  					parent.Panic(L)
   162  				} else {
   163  					L.SetTop(0)
   164  					L.Push(lv)
   165  					switchToParentThread(L, 1, true, true)
   166  				}
   167  			} else {
   168  				panic(rcv)
   169  			}
   170  		}
   171  	}()
   172  	L.mainLoop(L, nil)
   173  }
   174  
   175  type instFunc func(*LState, uint32, *callFrame) int
   176  
   177  var jumpTable [opCodeMax + 1]instFunc
   178  
   179  func init() {
   180  	jumpTable = [opCodeMax + 1]instFunc{
   181  		func(L *LState, inst uint32, baseframe *callFrame) int { //OP_MOVE
   182  			reg := L.reg
   183  			cf := L.currentFrame
   184  			lbase := cf.LocalBase
   185  			A := int(inst>>18) & 0xff //GETA
   186  			RA := lbase + A
   187  			B := int(inst & 0x1ff) //GETB
   188  			reg.Set(RA, reg.Get(lbase+B))
   189  			return 0
   190  		},
   191  		func(L *LState, inst uint32, baseframe *callFrame) int { //OP_MOVEN
   192  			reg := L.reg
   193  			cf := L.currentFrame
   194  			lbase := cf.LocalBase
   195  			A := int(inst>>18) & 0xff //GETA
   196  			B := int(inst & 0x1ff)    //GETB
   197  			C := int(inst>>9) & 0x1ff //GETC
   198  			reg.Set(lbase+A, reg.Get(lbase+B))
   199  			code := cf.Fn.Proto.Code
   200  			pc := cf.Pc
   201  			for i := 0; i < C; i++ {
   202  				inst = code[pc]
   203  				pc++
   204  				A = int(inst>>18) & 0xff //GETA
   205  				B = int(inst & 0x1ff)    //GETB
   206  				reg.Set(lbase+A, reg.Get(lbase+B))
   207  			}
   208  			cf.Pc = pc
   209  			return 0
   210  		},
   211  		func(L *LState, inst uint32, baseframe *callFrame) int { //OP_LOADK
   212  			reg := L.reg
   213  			cf := L.currentFrame
   214  			lbase := cf.LocalBase
   215  			A := int(inst>>18) & 0xff //GETA
   216  			RA := lbase + A
   217  			Bx := int(inst & 0x3ffff) //GETBX
   218  			reg.Set(RA, cf.Fn.Proto.Constants[Bx])
   219  			return 0
   220  		},
   221  		func(L *LState, inst uint32, baseframe *callFrame) int { //OP_LOADBOOL
   222  			reg := L.reg
   223  			cf := L.currentFrame
   224  			lbase := cf.LocalBase
   225  			A := int(inst>>18) & 0xff //GETA
   226  			RA := lbase + A
   227  			B := int(inst & 0x1ff)    //GETB
   228  			C := int(inst>>9) & 0x1ff //GETC
   229  			if B != 0 {
   230  				reg.Set(RA, LTrue)
   231  			} else {
   232  				reg.Set(RA, LFalse)
   233  			}
   234  			if C != 0 {
   235  				cf.Pc++
   236  			}
   237  			return 0
   238  		},
   239  		func(L *LState, inst uint32, baseframe *callFrame) int { //OP_LOADNIL
   240  			reg := L.reg
   241  			cf := L.currentFrame
   242  			lbase := cf.LocalBase
   243  			A := int(inst>>18) & 0xff //GETA
   244  			RA := lbase + A
   245  			B := int(inst & 0x1ff) //GETB
   246  			for i := RA; i <= lbase+B; i++ {
   247  				reg.Set(i, LNil)
   248  			}
   249  			return 0
   250  		},
   251  		func(L *LState, inst uint32, baseframe *callFrame) int { //OP_GETUPVAL
   252  			reg := L.reg
   253  			cf := L.currentFrame
   254  			lbase := cf.LocalBase
   255  			A := int(inst>>18) & 0xff //GETA
   256  			RA := lbase + A
   257  			B := int(inst & 0x1ff) //GETB
   258  			reg.Set(RA, cf.Fn.Upvalues[B].Value())
   259  			return 0
   260  		},
   261  		func(L *LState, inst uint32, baseframe *callFrame) int { //OP_GETGLOBAL
   262  			reg := L.reg
   263  			cf := L.currentFrame
   264  			lbase := cf.LocalBase
   265  			A := int(inst>>18) & 0xff //GETA
   266  			RA := lbase + A
   267  			Bx := int(inst & 0x3ffff) //GETBX
   268  			//reg.Set(RA, L.getField(cf.Fn.Env, cf.Fn.Proto.Constants[Bx]))
   269  			reg.Set(RA, L.getFieldString(cf.Fn.Env, cf.Fn.Proto.stringConstants[Bx]))
   270  			return 0
   271  		},
   272  		func(L *LState, inst uint32, baseframe *callFrame) int { //OP_GETTABLE
   273  			reg := L.reg
   274  			cf := L.currentFrame
   275  			lbase := cf.LocalBase
   276  			A := int(inst>>18) & 0xff //GETA
   277  			RA := lbase + A
   278  			B := int(inst & 0x1ff)    //GETB
   279  			C := int(inst>>9) & 0x1ff //GETC
   280  			reg.Set(RA, L.getField(reg.Get(lbase+B), L.rkValue(C)))
   281  			return 0
   282  		},
   283  		func(L *LState, inst uint32, baseframe *callFrame) int { //OP_GETTABLEKS
   284  			reg := L.reg
   285  			cf := L.currentFrame
   286  			lbase := cf.LocalBase
   287  			A := int(inst>>18) & 0xff //GETA
   288  			RA := lbase + A
   289  			B := int(inst & 0x1ff)    //GETB
   290  			C := int(inst>>9) & 0x1ff //GETC
   291  			reg.Set(RA, L.getFieldString(reg.Get(lbase+B), L.rkString(C)))
   292  			return 0
   293  		},
   294  		func(L *LState, inst uint32, baseframe *callFrame) int { //OP_SETGLOBAL
   295  			reg := L.reg
   296  			cf := L.currentFrame
   297  			lbase := cf.LocalBase
   298  			A := int(inst>>18) & 0xff //GETA
   299  			RA := lbase + A
   300  			Bx := int(inst & 0x3ffff) //GETBX
   301  			//L.setField(cf.Fn.Env, cf.Fn.Proto.Constants[Bx], reg.Get(RA))
   302  			L.setFieldString(cf.Fn.Env, cf.Fn.Proto.stringConstants[Bx], reg.Get(RA))
   303  			return 0
   304  		},
   305  		func(L *LState, inst uint32, baseframe *callFrame) int { //OP_SETUPVAL
   306  			reg := L.reg
   307  			cf := L.currentFrame
   308  			lbase := cf.LocalBase
   309  			A := int(inst>>18) & 0xff //GETA
   310  			RA := lbase + A
   311  			B := int(inst & 0x1ff) //GETB
   312  			cf.Fn.Upvalues[B].SetValue(reg.Get(RA))
   313  			return 0
   314  		},
   315  		func(L *LState, inst uint32, baseframe *callFrame) int { //OP_SETTABLE
   316  			reg := L.reg
   317  			cf := L.currentFrame
   318  			lbase := cf.LocalBase
   319  			A := int(inst>>18) & 0xff //GETA
   320  			RA := lbase + A
   321  			B := int(inst & 0x1ff)    //GETB
   322  			C := int(inst>>9) & 0x1ff //GETC
   323  			L.setField(reg.Get(RA), L.rkValue(B), L.rkValue(C))
   324  			return 0
   325  		},
   326  		func(L *LState, inst uint32, baseframe *callFrame) int { //OP_SETTABLEKS
   327  			reg := L.reg
   328  			cf := L.currentFrame
   329  			lbase := cf.LocalBase
   330  			A := int(inst>>18) & 0xff //GETA
   331  			RA := lbase + A
   332  			B := int(inst & 0x1ff)    //GETB
   333  			C := int(inst>>9) & 0x1ff //GETC
   334  			L.setFieldString(reg.Get(RA), L.rkString(B), L.rkValue(C))
   335  			return 0
   336  		},
   337  		func(L *LState, inst uint32, baseframe *callFrame) int { //OP_NEWTABLE
   338  			reg := L.reg
   339  			cf := L.currentFrame
   340  			lbase := cf.LocalBase
   341  			A := int(inst>>18) & 0xff //GETA
   342  			RA := lbase + A
   343  			B := int(inst & 0x1ff)    //GETB
   344  			C := int(inst>>9) & 0x1ff //GETC
   345  			reg.Set(RA, newLTable(B, C))
   346  			return 0
   347  		},
   348  		func(L *LState, inst uint32, baseframe *callFrame) int { //OP_SELF
   349  			reg := L.reg
   350  			cf := L.currentFrame
   351  			lbase := cf.LocalBase
   352  			A := int(inst>>18) & 0xff //GETA
   353  			RA := lbase + A
   354  			B := int(inst & 0x1ff)    //GETB
   355  			C := int(inst>>9) & 0x1ff //GETC
   356  			selfobj := reg.Get(lbase + B)
   357  			reg.Set(RA, L.getFieldString(selfobj, L.rkString(C)))
   358  			reg.Set(RA+1, selfobj)
   359  			return 0
   360  		},
   361  		opArith, // OP_ADD
   362  		opArith, // OP_SUB
   363  		opArith, // OP_MUL
   364  		opArith, // OP_DIV
   365  		opArith, // OP_MOD
   366  		opArith, // OP_POW
   367  		func(L *LState, inst uint32, baseframe *callFrame) int { //OP_UNM
   368  			reg := L.reg
   369  			cf := L.currentFrame
   370  			lbase := cf.LocalBase
   371  			A := int(inst>>18) & 0xff //GETA
   372  			RA := lbase + A
   373  			B := int(inst & 0x1ff) //GETB
   374  			unaryv := L.rkValue(B)
   375  			if nm, ok := unaryv.(LNumber); ok {
   376  				reg.SetNumber(RA, -nm)
   377  			} else {
   378  				op := L.metaOp1(unaryv, "__unm")
   379  				if op.Type() == LTFunction {
   380  					reg.Push(op)
   381  					reg.Push(unaryv)
   382  					L.Call(1, 1)
   383  					reg.Set(RA, reg.Pop())
   384  				} else if str, ok1 := unaryv.(LString); ok1 {
   385  					if num, err := parseNumber(string(str)); err == nil {
   386  						reg.Set(RA, -num)
   387  					} else {
   388  						L.RaiseError("__unm undefined")
   389  					}
   390  				} else {
   391  					L.RaiseError("__unm undefined")
   392  				}
   393  			}
   394  			return 0
   395  		},
   396  		func(L *LState, inst uint32, baseframe *callFrame) int { //OP_NOT
   397  			reg := L.reg
   398  			cf := L.currentFrame
   399  			lbase := cf.LocalBase
   400  			A := int(inst>>18) & 0xff //GETA
   401  			RA := lbase + A
   402  			B := int(inst & 0x1ff) //GETB
   403  			if LVIsFalse(reg.Get(lbase + B)) {
   404  				reg.Set(RA, LTrue)
   405  			} else {
   406  				reg.Set(RA, LFalse)
   407  			}
   408  			return 0
   409  		},
   410  		func(L *LState, inst uint32, baseframe *callFrame) int { //OP_LEN
   411  			reg := L.reg
   412  			cf := L.currentFrame
   413  			lbase := cf.LocalBase
   414  			A := int(inst>>18) & 0xff //GETA
   415  			RA := lbase + A
   416  			B := int(inst & 0x1ff) //GETB
   417  			switch lv := L.rkValue(B).(type) {
   418  			case LString:
   419  				reg.SetNumber(RA, LNumber(len(lv)))
   420  			default:
   421  				op := L.metaOp1(lv, "__len")
   422  				if op.Type() == LTFunction {
   423  					reg.Push(op)
   424  					reg.Push(lv)
   425  					L.Call(1, 1)
   426  					ret := reg.Pop()
   427  					if ret.Type() == LTNumber {
   428  						reg.SetNumber(RA, ret.(LNumber))
   429  					} else {
   430  						reg.SetNumber(RA, LNumber(0))
   431  					}
   432  				} else if lv.Type() == LTTable {
   433  					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  			reg.Set(RA, stringConcat(L, RC-RB+1, RC))
   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.assertFloat64(); ok1 {
   499  				if v2, ok2 := rhs.assertFloat64(); 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  				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.assertFunction(); 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.assertFunction(); 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).assertFloat64(); ok1 {
   689  				if limit, ok2 := reg.Get(RA + 1).assertFloat64(); ok2 {
   690  					if step, ok3 := reg.Get(RA + 2).assertFloat64(); ok3 {
   691  						init += step
   692  						reg.SetNumber(RA, LNumber(init))
   693  						if (step > 0 && init <= limit) || (step <= 0 && init >= limit) {
   694  							Sbx := int(inst&0x3ffff) - opMaxArgSbx //GETSBX
   695  							cf.Pc += Sbx
   696  							reg.SetNumber(RA+3, LNumber(init))
   697  						} else {
   698  							reg.SetTop(RA + 1)
   699  						}
   700  					} else {
   701  						L.RaiseError("for statement step must be a number")
   702  					}
   703  				} else {
   704  					L.RaiseError("for statement limit must be a number")
   705  				}
   706  			} else {
   707  				L.RaiseError("for statement init must be a number")
   708  			}
   709  			return 0
   710  		},
   711  		func(L *LState, inst uint32, baseframe *callFrame) int { //OP_FORPREP
   712  			reg := L.reg
   713  			cf := L.currentFrame
   714  			lbase := cf.LocalBase
   715  			A := int(inst>>18) & 0xff //GETA
   716  			RA := lbase + A
   717  			Sbx := int(inst&0x3ffff) - opMaxArgSbx //GETSBX
   718  			if init, ok1 := reg.Get(RA).assertFloat64(); ok1 {
   719  				if step, ok2 := reg.Get(RA + 2).assertFloat64(); ok2 {
   720  					reg.SetNumber(RA, LNumber(init-step))
   721  				} else {
   722  					L.RaiseError("for statement step must be a number")
   723  				}
   724  			} else {
   725  				L.RaiseError("for statement init must be a number")
   726  			}
   727  			cf.Pc += Sbx
   728  			return 0
   729  		},
   730  		func(L *LState, inst uint32, baseframe *callFrame) int { //OP_TFORLOOP
   731  			reg := L.reg
   732  			cf := L.currentFrame
   733  			lbase := cf.LocalBase
   734  			A := int(inst>>18) & 0xff //GETA
   735  			RA := lbase + A
   736  			C := int(inst>>9) & 0x1ff //GETC
   737  			nret := C
   738  			reg.SetTop(RA + 3 + 2)
   739  			reg.Set(RA+3+2, reg.Get(RA+2))
   740  			reg.Set(RA+3+1, reg.Get(RA+1))
   741  			reg.Set(RA+3, reg.Get(RA))
   742  			L.callR(2, nret, RA+3)
   743  			if value := reg.Get(RA + 3); value != LNil {
   744  				reg.Set(RA+2, value)
   745  				pc := cf.Fn.Proto.Code[cf.Pc]
   746  				cf.Pc += int(pc&0x3ffff) - opMaxArgSbx
   747  			}
   748  			cf.Pc++
   749  			return 0
   750  		},
   751  		func(L *LState, inst uint32, baseframe *callFrame) int { //OP_SETLIST
   752  			reg := L.reg
   753  			cf := L.currentFrame
   754  			lbase := cf.LocalBase
   755  			A := int(inst>>18) & 0xff //GETA
   756  			RA := lbase + A
   757  			B := int(inst & 0x1ff)    //GETB
   758  			C := int(inst>>9) & 0x1ff //GETC
   759  			if C == 0 {
   760  				C = int(cf.Fn.Proto.Code[cf.Pc])
   761  				cf.Pc++
   762  			}
   763  			offset := (C - 1) * FieldsPerFlush
   764  			table := reg.Get(RA).(*LTable)
   765  			nelem := B
   766  			if B == 0 {
   767  				nelem = reg.Top() - RA - 1
   768  			}
   769  			for i := 1; i <= nelem; i++ {
   770  				table.RawSetInt(offset+i, reg.Get(RA+i))
   771  			}
   772  			return 0
   773  		},
   774  		func(L *LState, inst uint32, baseframe *callFrame) int { //OP_CLOSE
   775  			cf := L.currentFrame
   776  			lbase := cf.LocalBase
   777  			A := int(inst>>18) & 0xff //GETA
   778  			RA := lbase + A
   779  			// +inline-call L.closeUpvalues RA
   780  			return 0
   781  		},
   782  		func(L *LState, inst uint32, baseframe *callFrame) int { //OP_CLOSURE
   783  			reg := L.reg
   784  			cf := L.currentFrame
   785  			lbase := cf.LocalBase
   786  			A := int(inst>>18) & 0xff //GETA
   787  			RA := lbase + A
   788  			Bx := int(inst & 0x3ffff) //GETBX
   789  			proto := cf.Fn.Proto.FunctionPrototypes[Bx]
   790  			closure := newLFunctionL(proto, cf.Fn.Env, int(proto.NumUpvalues))
   791  			reg.Set(RA, closure)
   792  			for i := 0; i < int(proto.NumUpvalues); i++ {
   793  				inst = cf.Fn.Proto.Code[cf.Pc]
   794  				cf.Pc++
   795  				B := opGetArgB(inst)
   796  				switch opGetOpCode(inst) {
   797  				case OP_MOVE:
   798  					closure.Upvalues[i] = L.findUpvalue(lbase + B)
   799  				case OP_GETUPVAL:
   800  					closure.Upvalues[i] = cf.Fn.Upvalues[B]
   801  				}
   802  			}
   803  			return 0
   804  		},
   805  		func(L *LState, inst uint32, baseframe *callFrame) int { //OP_VARARG
   806  			reg := L.reg
   807  			cf := L.currentFrame
   808  			lbase := cf.LocalBase
   809  			A := int(inst>>18) & 0xff //GETA
   810  			RA := lbase + A
   811  			B := int(inst & 0x1ff) //GETB
   812  			nparams := int(cf.Fn.Proto.NumParameters)
   813  			nvarargs := cf.NArgs - nparams
   814  			if nvarargs < 0 {
   815  				nvarargs = 0
   816  			}
   817  			nwant := B - 1
   818  			if B == 0 {
   819  				nwant = nvarargs
   820  			}
   821  			// +inline-call reg.CopyRange RA cf.Base+nparams+1 cf.LocalBase nwant
   822  			return 0
   823  		},
   824  		func(L *LState, inst uint32, baseframe *callFrame) int { //OP_NOP
   825  			return 0
   826  		},
   827  	}
   828  }
   829  
   830  func opArith(L *LState, inst uint32, baseframe *callFrame) int { //OP_ADD, OP_SUB, OP_MUL, OP_DIV, OP_MOD, OP_POW
   831  	reg := L.reg
   832  	cf := L.currentFrame
   833  	lbase := cf.LocalBase
   834  	A := int(inst>>18) & 0xff //GETA
   835  	RA := lbase + A
   836  	opcode := int(inst >> 26) //GETOPCODE
   837  	B := int(inst & 0x1ff)    //GETB
   838  	C := int(inst>>9) & 0x1ff //GETC
   839  	lhs := L.rkValue(B)
   840  	rhs := L.rkValue(C)
   841  	v1, ok1 := lhs.assertFloat64()
   842  	v2, ok2 := rhs.assertFloat64()
   843  	if ok1 && ok2 {
   844  		reg.SetNumber(RA, numberArith(L, opcode, LNumber(v1), LNumber(v2)))
   845  	} else {
   846  		reg.Set(RA, objectArith(L, opcode, lhs, rhs))
   847  	}
   848  	return 0
   849  }
   850  
   851  func luaModulo(lhs, rhs LNumber) LNumber {
   852  	flhs := float64(lhs)
   853  	frhs := float64(rhs)
   854  	v := math.Mod(flhs, frhs)
   855  	if flhs < 0 || frhs < 0 && !(flhs < 0 && frhs < 0) {
   856  		v += frhs
   857  	}
   858  	return LNumber(v)
   859  }
   860  
   861  func numberArith(L *LState, opcode int, lhs, rhs LNumber) LNumber {
   862  	switch opcode {
   863  	case OP_ADD:
   864  		return lhs + rhs
   865  	case OP_SUB:
   866  		return lhs - rhs
   867  	case OP_MUL:
   868  		return lhs * rhs
   869  	case OP_DIV:
   870  		return lhs / rhs
   871  	case OP_MOD:
   872  		return luaModulo(lhs, rhs)
   873  	case OP_POW:
   874  		flhs := float64(lhs)
   875  		frhs := float64(rhs)
   876  		return LNumber(math.Pow(flhs, frhs))
   877  	}
   878  	panic("should not reach here")
   879  	return LNumber(0)
   880  }
   881  
   882  func objectArith(L *LState, opcode int, lhs, rhs LValue) LValue {
   883  	event := ""
   884  	switch opcode {
   885  	case OP_ADD:
   886  		event = "__add"
   887  	case OP_SUB:
   888  		event = "__sub"
   889  	case OP_MUL:
   890  		event = "__mul"
   891  	case OP_DIV:
   892  		event = "__div"
   893  	case OP_MOD:
   894  		event = "__mod"
   895  	case OP_POW:
   896  		event = "__pow"
   897  	}
   898  	op := L.metaOp2(lhs, rhs, event)
   899  	if op.Type() == LTFunction {
   900  		L.reg.Push(op)
   901  		L.reg.Push(lhs)
   902  		L.reg.Push(rhs)
   903  		L.Call(2, 1)
   904  		return L.reg.Pop()
   905  	}
   906  	if str, ok := lhs.(LString); ok {
   907  		if lnum, err := parseNumber(string(str)); err == nil {
   908  			lhs = lnum
   909  		}
   910  	}
   911  	if str, ok := rhs.(LString); ok {
   912  		if rnum, err := parseNumber(string(str)); err == nil {
   913  			rhs = rnum
   914  		}
   915  	}
   916  	if v1, ok1 := lhs.assertFloat64(); ok1 {
   917  		if v2, ok2 := rhs.assertFloat64(); ok2 {
   918  			return numberArith(L, opcode, LNumber(v1), LNumber(v2))
   919  		}
   920  	}
   921  	L.RaiseError(fmt.Sprintf("cannot perform %v operation between %v and %v",
   922  		strings.TrimLeft(event, "_"), lhs.Type().String(), rhs.Type().String()))
   923  
   924  	return LNil
   925  }
   926  
   927  func stringConcat(L *LState, total, last int) LValue {
   928  	rhs := L.reg.Get(last)
   929  	total--
   930  	for i := last - 1; total > 0; {
   931  		lhs := L.reg.Get(i)
   932  		if !(LVCanConvToString(lhs) && LVCanConvToString(rhs)) {
   933  			op := L.metaOp2(lhs, rhs, "__concat")
   934  			if op.Type() == LTFunction {
   935  				L.reg.Push(op)
   936  				L.reg.Push(lhs)
   937  				L.reg.Push(rhs)
   938  				L.Call(2, 1)
   939  				rhs = L.reg.Pop()
   940  				total--
   941  				i--
   942  			} else {
   943  				L.RaiseError("cannot perform concat operation between %v and %v", lhs.Type().String(), rhs.Type().String())
   944  				return LNil
   945  			}
   946  		} else {
   947  			buf := make([]string, total+1)
   948  			buf[total] = LVAsString(rhs)
   949  			for total > 0 {
   950  				lhs = L.reg.Get(i)
   951  				if !LVCanConvToString(lhs) {
   952  					break
   953  				}
   954  				buf[total-1] = LVAsString(lhs)
   955  				i--
   956  				total--
   957  			}
   958  			rhs = LString(strings.Join(buf, ""))
   959  		}
   960  	}
   961  	return rhs
   962  }
   963  
   964  func lessThan(L *LState, lhs, rhs LValue) bool {
   965  	// optimization for numbers
   966  	if v1, ok1 := lhs.assertFloat64(); ok1 {
   967  		if v2, ok2 := rhs.assertFloat64(); ok2 {
   968  			return v1 < v2
   969  		}
   970  		L.RaiseError("attempt to compare %v with %v", lhs.Type().String(), rhs.Type().String())
   971  	}
   972  	if lhs.Type() != rhs.Type() {
   973  		L.RaiseError("attempt to compare %v with %v", lhs.Type().String(), rhs.Type().String())
   974  		return false
   975  	}
   976  	ret := false
   977  	switch lhs.Type() {
   978  	case LTString:
   979  		ret = strCmp(string(lhs.(LString)), string(rhs.(LString))) < 0
   980  	default:
   981  		ret = objectRationalWithError(L, lhs, rhs, "__lt")
   982  	}
   983  	return ret
   984  }
   985  
   986  func equals(L *LState, lhs, rhs LValue, raw bool) bool {
   987  	if lhs.Type() != rhs.Type() {
   988  		return false
   989  	}
   990  
   991  	ret := false
   992  	switch lhs.Type() {
   993  	case LTNil:
   994  		ret = true
   995  	case LTNumber:
   996  		v1, _ := lhs.assertFloat64()
   997  		v2, _ := rhs.assertFloat64()
   998  		ret = v1 == v2
   999  	case LTBool:
  1000  		ret = bool(lhs.(LBool)) == bool(rhs.(LBool))
  1001  	case LTString:
  1002  		ret = string(lhs.(LString)) == string(rhs.(LString))
  1003  	case LTUserData, LTTable:
  1004  		if lhs == rhs {
  1005  			ret = true
  1006  		} else if !raw {
  1007  			switch objectRational(L, lhs, rhs, "__eq") {
  1008  			case 1:
  1009  				ret = true
  1010  			default:
  1011  				ret = false
  1012  			}
  1013  		}
  1014  	default:
  1015  		ret = lhs == rhs
  1016  	}
  1017  	return ret
  1018  }
  1019  
  1020  func objectRationalWithError(L *LState, lhs, rhs LValue, event string) bool {
  1021  	switch objectRational(L, lhs, rhs, event) {
  1022  	case 1:
  1023  		return true
  1024  	case 0:
  1025  		return false
  1026  	}
  1027  	L.RaiseError("attempt to compare %v with %v", lhs.Type().String(), rhs.Type().String())
  1028  	return false
  1029  }
  1030  
  1031  func objectRational(L *LState, lhs, rhs LValue, event string) int {
  1032  	m1 := L.metaOp1(lhs, event)
  1033  	m2 := L.metaOp1(rhs, event)
  1034  	if m1.Type() == LTFunction && m1 == m2 {
  1035  		L.reg.Push(m1)
  1036  		L.reg.Push(lhs)
  1037  		L.reg.Push(rhs)
  1038  		L.Call(2, 1)
  1039  		if LVAsBool(L.reg.Pop()) {
  1040  			return 1
  1041  		}
  1042  		return 0
  1043  	}
  1044  	return -1
  1045  }