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