From 5675e33b2d7d22645ce94008fe5d5a8cc95ce2c2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philip=20Dub=C3=A9?= Date: Tue, 12 Mar 2024 21:51:08 +0000 Subject: [PATCH 1/4] vm: replace jump table with switch A couple years ago the go compiler finally implemented jumptables for switch: https://go-review.googlesource.com/c/go/+/357330/8 --- _vm.go | 1215 +++++++--------- state.go | 412 +++--- vm.go | 4153 ++++++++++++++++++++++++++---------------------------- 3 files changed, 2719 insertions(+), 3061 deletions(-) diff --git a/_vm.go b/_vm.go index ee2be040..332502cc 100644 --- a/_vm.go +++ b/_vm.go @@ -6,6 +6,526 @@ import ( "strings" ) +func evalInstruction(L *LState, inst uint32, baseframe *callFrame) bool { + reg := L.reg + cf := L.currentFrame + lbase := cf.LocalBase + opcode := int(inst >> 26) + switch opcode { + case OP_MOVE: + A := int(inst>>18) & 0xff //GETA + RA := lbase + A + B := int(inst & 0x1ff) //GETB + v := reg.Get(lbase + B) + // +inline-call reg.Set RA v + case OP_MOVEN: + A := int(inst>>18) & 0xff //GETA + B := int(inst & 0x1ff) //GETB + C := int(inst>>9) & 0x1ff //GETC + v := reg.Get(lbase + B) + // +inline-call reg.Set lbase+A v + code := cf.Fn.Proto.Code + pc := cf.Pc + for i := 0; i < C; i++ { + inst = code[pc] + pc++ + A = int(inst>>18) & 0xff //GETA + B = int(inst & 0x1ff) //GETB + v := reg.Get(lbase + B) + // +inline-call reg.Set lbase+A v + } + cf.Pc = pc + case OP_LOADK: + A := int(inst>>18) & 0xff //GETA + RA := lbase + A + Bx := int(inst & 0x3ffff) //GETBX + v := cf.Fn.Proto.Constants[Bx] + // +inline-call reg.Set RA v + case OP_LOADBOOL: + A := int(inst>>18) & 0xff //GETA + RA := lbase + A + B := int(inst & 0x1ff) //GETB + C := int(inst>>9) & 0x1ff //GETC + if B != 0 { + // +inline-call reg.Set RA LTrue + } else { + // +inline-call reg.Set RA LFalse + } + if C != 0 { + cf.Pc++ + } + case OP_LOADNIL: + A := int(inst>>18) & 0xff //GETA + RA := lbase + A + B := int(inst & 0x1ff) //GETB + for i := RA; i <= lbase+B; i++ { + // +inline-call reg.Set i LNil + } + case OP_GETUPVAL: + reg := L.reg + cf := L.currentFrame + lbase := cf.LocalBase + A := int(inst>>18) & 0xff //GETA + RA := lbase + A + B := int(inst & 0x1ff) //GETB + v := cf.Fn.Upvalues[B].Value() + // +inline-call reg.Set RA v + case OP_GETGLOBAL: + A := int(inst>>18) & 0xff //GETA + RA := lbase + A + Bx := int(inst & 0x3ffff) //GETBX + //reg.Set(RA, L.getField(cf.Fn.Env, cf.Fn.Proto.Constants[Bx])) + v := L.getFieldString(cf.Fn.Env, cf.Fn.Proto.stringConstants[Bx]) + // +inline-call reg.Set RA v + case OP_GETTABLE: + A := int(inst>>18) & 0xff //GETA + RA := lbase + A + B := int(inst & 0x1ff) //GETB + C := int(inst>>9) & 0x1ff //GETC + v := L.getField(reg.Get(lbase+B), L.rkValue(C)) + // +inline-call reg.Set RA v + case OP_GETTABLEKS: + A := int(inst>>18) & 0xff //GETA + RA := lbase + A + B := int(inst & 0x1ff) //GETB + C := int(inst>>9) & 0x1ff //GETC + v := L.getFieldString(reg.Get(lbase+B), L.rkString(C)) + // +inline-call reg.Set RA v + case OP_SETGLOBAL: + A := int(inst>>18) & 0xff //GETA + RA := lbase + A + Bx := int(inst & 0x3ffff) //GETBX + //L.setField(cf.Fn.Env, cf.Fn.Proto.Constants[Bx], reg.Get(RA)) + L.setFieldString(cf.Fn.Env, cf.Fn.Proto.stringConstants[Bx], reg.Get(RA)) + case OP_SETUPVAL: + A := int(inst>>18) & 0xff //GETA + RA := lbase + A + B := int(inst & 0x1ff) //GETB + cf.Fn.Upvalues[B].SetValue(reg.Get(RA)) + case OP_SETTABLE: + A := int(inst>>18) & 0xff //GETA + RA := lbase + A + B := int(inst & 0x1ff) //GETB + C := int(inst>>9) & 0x1ff //GETC + L.setField(reg.Get(RA), L.rkValue(B), L.rkValue(C)) + case OP_SETTABLEKS: + A := int(inst>>18) & 0xff //GETA + RA := lbase + A + B := int(inst & 0x1ff) //GETB + C := int(inst>>9) & 0x1ff //GETC + L.setFieldString(reg.Get(RA), L.rkString(B), L.rkValue(C)) + case OP_NEWTABLE: + A := int(inst>>18) & 0xff //GETA + RA := lbase + A + B := int(inst & 0x1ff) //GETB + C := int(inst>>9) & 0x1ff //GETC + v := newLTable(B, C) + // +inline-call reg.Set RA v + case OP_SELF: + A := int(inst>>18) & 0xff //GETA + RA := lbase + A + B := int(inst & 0x1ff) //GETB + C := int(inst>>9) & 0x1ff //GETC + selfobj := reg.Get(lbase + B) + v := L.getFieldString(selfobj, L.rkString(C)) + // +inline-call reg.Set RA v + // +inline-call reg.Set RA+1 selfobj + case OP_ADD, OP_SUB, OP_MUL, OP_DIV, OP_MOD, OP_POW: + A := int(inst>>18) & 0xff //GETA + RA := lbase + A + B := int(inst & 0x1ff) //GETB + C := int(inst>>9) & 0x1ff //GETC + lhs := L.rkValue(B) + rhs := L.rkValue(C) + v1, ok1 := lhs.(LNumber) + v2, ok2 := rhs.(LNumber) + if ok1 && ok2 { + v := numberArith(L, opcode, LNumber(v1), LNumber(v2)) + // +inline-call reg.SetNumber RA v + } else { + v := objectArith(L, opcode, lhs, rhs) + // +inline-call reg.Set RA v + } + + case OP_UNM: + A := int(inst>>18) & 0xff //GETA + RA := lbase + A + B := int(inst & 0x1ff) //GETB + unaryv := L.rkValue(B) + if nm, ok := unaryv.(LNumber); ok { + // +inline-call reg.Set RA -nm + } else { + op := L.metaOp1(unaryv, "__unm") + if op.Type() == LTFunction { + reg.Push(op) + reg.Push(unaryv) + L.Call(1, 1) + // +inline-call reg.Set RA reg.Pop() + } else if str, ok1 := unaryv.(LString); ok1 { + if num, err := parseNumber(string(str)); err == nil { + // +inline-call reg.Set RA -num + } else { + L.RaiseError("__unm undefined") + } + } else { + L.RaiseError("__unm undefined") + } + } + case OP_NOT: + A := int(inst>>18) & 0xff //GETA + RA := lbase + A + B := int(inst & 0x1ff) //GETB + if LVIsFalse(reg.Get(lbase + B)) { + // +inline-call reg.Set RA LTrue + } else { + // +inline-call reg.Set RA LFalse + } + case OP_LEN: + A := int(inst>>18) & 0xff //GETA + RA := lbase + A + B := int(inst & 0x1ff) //GETB + switch lv := L.rkValue(B).(type) { + case LString: + // +inline-call reg.SetNumber RA LNumber(len(lv)) + default: + op := L.metaOp1(lv, "__len") + if op.Type() == LTFunction { + reg.Push(op) + reg.Push(lv) + L.Call(1, 1) + ret := reg.Pop() + if ret.Type() == LTNumber { + v, _ := ret.(LNumber) + // +inline-call reg.SetNumber RA v + } else { + // +inline-call reg.Set RA ret + } + } else if lv.Type() == LTTable { + // +inline-call reg.SetNumber RA LNumber(lv.(*LTable).Len()) + } else { + L.RaiseError("__len undefined") + } + } + case OP_CONCAT: + A := int(inst>>18) & 0xff //GETA + RA := lbase + A + B := int(inst & 0x1ff) //GETB + C := int(inst>>9) & 0x1ff //GETC + RC := lbase + C + RB := lbase + B + v := stringConcat(L, RC-RB+1, RC) + // +inline-call reg.Set RA v + case OP_JMP: + cf := L.currentFrame + Sbx := int(inst&0x3ffff) - opMaxArgSbx //GETSBX + cf.Pc += Sbx + case OP_EQ: + cf := L.currentFrame + A := int(inst>>18) & 0xff //GETA + B := int(inst & 0x1ff) //GETB + C := int(inst>>9) & 0x1ff //GETC + ret := equals(L, L.rkValue(B), L.rkValue(C), false) + v := 1 + if ret { + v = 0 + } + if v == A { + cf.Pc++ + } + case OP_LT: + A := int(inst>>18) & 0xff //GETA + B := int(inst & 0x1ff) //GETB + C := int(inst>>9) & 0x1ff //GETC + ret := lessThan(L, L.rkValue(B), L.rkValue(C)) + v := 1 + if ret { + v = 0 + } + if v == A { + cf.Pc++ + } + case OP_LE: + A := int(inst>>18) & 0xff //GETA + B := int(inst & 0x1ff) //GETB + C := int(inst>>9) & 0x1ff //GETC + lhs := L.rkValue(B) + rhs := L.rkValue(C) + ret := false + + if v1, ok1 := lhs.(LNumber); ok1 { + if v2, ok2 := rhs.(LNumber); ok2 { + ret = v1 <= v2 + } else { + L.RaiseError("attempt to compare %v with %v", lhs.Type().String(), rhs.Type().String()) + } + } else { + if lhs.Type() != rhs.Type() { + L.RaiseError("attempt to compare %v with %v", lhs.Type().String(), rhs.Type().String()) + } + switch lhs.Type() { + case LTString: + ret = strCmp(string(lhs.(LString)), string(rhs.(LString))) <= 0 + default: + switch objectRational(L, lhs, rhs, "__le") { + case 1: + ret = true + case 0: + ret = false + default: + ret = !objectRationalWithError(L, rhs, lhs, "__lt") + } + } + } + + v := 1 + if ret { + v = 0 + } + if v == A { + cf.Pc++ + } + case OP_TEST: + A := int(inst>>18) & 0xff //GETA + RA := lbase + A + C := int(inst>>9) & 0x1ff //GETC + if LVAsBool(reg.Get(RA)) == (C == 0) { + cf.Pc++ + } + case OP_TESTSET: + A := int(inst>>18) & 0xff //GETA + RA := lbase + A + B := int(inst & 0x1ff) //GETB + C := int(inst>>9) & 0x1ff //GETC + if value := reg.Get(lbase + B); LVAsBool(value) != (C == 0) { + // +inline-call reg.Set RA value + } else { + cf.Pc++ + } + case OP_CALL: + A := int(inst>>18) & 0xff //GETA + RA := lbase + A + B := int(inst & 0x1ff) //GETB + C := int(inst>>9) & 0x1ff //GETC + nargs := B - 1 + if B == 0 { + nargs = reg.Top() - (RA + 1) + } + lv := reg.Get(RA) + nret := C - 1 + var callable *LFunction + var meta bool + if fn, ok := lv.(*LFunction); ok { + callable = fn + meta = false + } else { + callable, meta = L.metaCall(lv) + } + // +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 + if callable.IsG && callGFunction(L, false) { + return true + } + case OP_TAILCALL: + reg := L.reg + cf := L.currentFrame + lbase := cf.LocalBase + A := int(inst>>18) & 0xff //GETA + RA := lbase + A + B := int(inst & 0x1ff) //GETB + nargs := B - 1 + if B == 0 { + nargs = reg.Top() - (RA + 1) + } + lv := reg.Get(RA) + var callable *LFunction + var meta bool + if fn, ok := lv.(*LFunction); ok { + callable = fn + meta = false + } else { + callable, meta = L.metaCall(lv) + } + if callable == nil { + L.RaiseError("attempt to call a non-function object") + } + // +inline-call L.closeUpvalues lbase + if callable.IsG { + luaframe := cf + L.pushCallFrame(callFrame{ + Fn: callable, + Pc: 0, + Base: RA, + LocalBase: RA + 1, + ReturnBase: cf.ReturnBase, + NArgs: nargs, + NRet: cf.NRet, + Parent: cf, + TailCall: 0, + }, lv, meta) + if callGFunction(L, true) { + return true + } + if L.currentFrame == nil || L.currentFrame.Fn.IsG || luaframe == baseframe { + return true + } + } else { + base := cf.Base + cf.Fn = callable + cf.Pc = 0 + cf.Base = RA + cf.LocalBase = RA + 1 + cf.ReturnBase = cf.ReturnBase + cf.NArgs = nargs + cf.NRet = cf.NRet + cf.TailCall++ + lbase := cf.LocalBase + if meta { + cf.NArgs++ + L.reg.Insert(lv, cf.LocalBase) + } + // +inline-call L.initCallFrame cf + // +inline-call L.reg.CopyRange base RA -1 reg.Top()-RA-1 + cf.Base = base + cf.LocalBase = base + (cf.LocalBase - lbase + 1) + } + case OP_RETURN: + A := int(inst>>18) & 0xff //GETA + RA := lbase + A + B := int(inst & 0x1ff) //GETB + // +inline-call L.closeUpvalues lbase + nret := B - 1 + if B == 0 { + nret = reg.Top() - RA + } + n := cf.NRet + if cf.NRet == MultRet { + n = nret + } + + if L.Parent != nil && L.stack.Sp() == 1 { + // +inline-call copyReturnValues L reg.Top() RA n B + switchToParentThread(L, n, false, true) + return true + } + islast := baseframe == L.stack.Pop() || L.stack.IsEmpty() + // +inline-call copyReturnValues L cf.ReturnBase RA n B + L.currentFrame = L.stack.Last() + if islast || L.currentFrame == nil || L.currentFrame.Fn.IsG { + return true + } + case OP_FORLOOP: + A := int(inst>>18) & 0xff //GETA + RA := lbase + A + if init, ok1 := reg.Get(RA).(LNumber); ok1 { + if limit, ok2 := reg.Get(RA + 1).(LNumber); ok2 { + if step, ok3 := reg.Get(RA + 2).(LNumber); ok3 { + init += step + v := LNumber(init) + // +inline-call reg.SetNumber RA v + if (step > 0 && init <= limit) || (step <= 0 && init >= limit) { + Sbx := int(inst&0x3ffff) - opMaxArgSbx //GETSBX + cf.Pc += Sbx + // +inline-call reg.SetNumber RA+3 v + } else { + // +inline-call reg.SetTop RA+1 + } + } else { + L.RaiseError("for statement step must be a number") + } + } else { + L.RaiseError("for statement limit must be a number") + } + } else { + L.RaiseError("for statement init must be a number") + } + case OP_FORPREP: + A := int(inst>>18) & 0xff //GETA + RA := lbase + A + Sbx := int(inst&0x3ffff) - opMaxArgSbx //GETSBX + if init, ok1 := reg.Get(RA).(LNumber); ok1 { + if step, ok2 := reg.Get(RA + 2).(LNumber); ok2 { + // +inline-call reg.SetNumber RA LNumber(init-step) + } else { + L.RaiseError("for statement step must be a number") + } + } else { + L.RaiseError("for statement init must be a number") + } + cf.Pc += Sbx + case OP_TFORLOOP: + A := int(inst>>18) & 0xff //GETA + RA := lbase + A + C := int(inst>>9) & 0x1ff //GETC + nret := C + // +inline-call reg.SetTop RA+3+2 + // +inline-call reg.Set RA+3+2 reg.Get(RA+2) + // +inline-call reg.Set RA+3+1 reg.Get(RA+1) + // +inline-call reg.Set RA+3 reg.Get(RA) + L.callR(2, nret, RA+3) + if value := reg.Get(RA + 3); value != LNil { + // +inline-call reg.Set RA+2 value + pc := cf.Fn.Proto.Code[cf.Pc] + cf.Pc += int(pc&0x3ffff) - opMaxArgSbx + } + cf.Pc++ + case OP_SETLIST: + A := int(inst>>18) & 0xff //GETA + RA := lbase + A + B := int(inst & 0x1ff) //GETB + C := int(inst>>9) & 0x1ff //GETC + if C == 0 { + C = int(cf.Fn.Proto.Code[cf.Pc]) + cf.Pc++ + } + offset := (C - 1) * FieldsPerFlush + table := reg.Get(RA).(*LTable) + nelem := B + if B == 0 { + nelem = reg.Top() - RA - 1 + } + for i := 1; i <= nelem; i++ { + table.RawSetInt(offset+i, reg.Get(RA+i)) + } + case OP_CLOSE: + A := int(inst>>18) & 0xff //GETA + RA := lbase + A + // +inline-call L.closeUpvalues RA + case OP_CLOSURE: + A := int(inst>>18) & 0xff //GETA + RA := lbase + A + Bx := int(inst & 0x3ffff) //GETBX + proto := cf.Fn.Proto.FunctionPrototypes[Bx] + closure := newLFunctionL(proto, cf.Fn.Env, int(proto.NumUpvalues)) + // +inline-call reg.Set RA closure + for i := 0; i < int(proto.NumUpvalues); i++ { + inst = cf.Fn.Proto.Code[cf.Pc] + cf.Pc++ + B := opGetArgB(inst) + switch opGetOpCode(inst) { + case OP_MOVE: + closure.Upvalues[i] = L.findUpvalue(lbase + B) + case OP_GETUPVAL: + closure.Upvalues[i] = cf.Fn.Upvalues[B] + } + } + case OP_VARARG: + A := int(inst>>18) & 0xff //GETA + RA := lbase + A + B := int(inst & 0x1ff) //GETB + nparams := int(cf.Fn.Proto.NumParameters) + nvarargs := cf.NArgs - nparams + if nvarargs < 0 { + nvarargs = 0 + } + nwant := B - 1 + if B == 0 { + nwant = nvarargs + } + // +inline-call reg.CopyRange RA cf.Base+nparams+1 cf.LocalBase nwant + case OP_NOP: + } + return false +} + func mainLoop(L *LState, baseframe *callFrame) { var inst uint32 var cf *callFrame @@ -24,7 +544,7 @@ func mainLoop(L *LState, baseframe *callFrame) { cf = L.currentFrame inst = cf.Fn.Proto.Code[cf.Pc] cf.Pc++ - if jumpTable[int(inst>>26)](L, inst, baseframe) == 1 { + if evalInstruction(L, inst, baseframe) { return } } @@ -53,7 +573,7 @@ func mainLoopWithContext(L *LState, baseframe *callFrame) { L.RaiseError(L.ctx.Err().Error()) return default: - if jumpTable[int(inst>>26)](L, inst, baseframe) == 1 { + if evalInstruction(L, inst, baseframe) { return } } @@ -160,697 +680,6 @@ func threadRun(L *LState) { L.mainLoop(L, nil) } -type instFunc func(*LState, uint32, *callFrame) int - -var jumpTable [opCodeMax + 1]instFunc - -func init() { - jumpTable = [opCodeMax + 1]instFunc{ - func(L *LState, inst uint32, baseframe *callFrame) int { //OP_MOVE - reg := L.reg - cf := L.currentFrame - lbase := cf.LocalBase - A := int(inst>>18) & 0xff //GETA - RA := lbase + A - B := int(inst & 0x1ff) //GETB - v := reg.Get(lbase + B) - // +inline-call reg.Set RA v - return 0 - }, - func(L *LState, inst uint32, baseframe *callFrame) int { //OP_MOVEN - reg := L.reg - cf := L.currentFrame - lbase := cf.LocalBase - A := int(inst>>18) & 0xff //GETA - B := int(inst & 0x1ff) //GETB - C := int(inst>>9) & 0x1ff //GETC - v := reg.Get(lbase + B) - // +inline-call reg.Set lbase+A v - code := cf.Fn.Proto.Code - pc := cf.Pc - for i := 0; i < C; i++ { - inst = code[pc] - pc++ - A = int(inst>>18) & 0xff //GETA - B = int(inst & 0x1ff) //GETB - v := reg.Get(lbase + B) - // +inline-call reg.Set lbase+A v - } - cf.Pc = pc - return 0 - }, - func(L *LState, inst uint32, baseframe *callFrame) int { //OP_LOADK - reg := L.reg - cf := L.currentFrame - lbase := cf.LocalBase - A := int(inst>>18) & 0xff //GETA - RA := lbase + A - Bx := int(inst & 0x3ffff) //GETBX - v := cf.Fn.Proto.Constants[Bx] - // +inline-call reg.Set RA v - return 0 - }, - func(L *LState, inst uint32, baseframe *callFrame) int { //OP_LOADBOOL - reg := L.reg - cf := L.currentFrame - lbase := cf.LocalBase - A := int(inst>>18) & 0xff //GETA - RA := lbase + A - B := int(inst & 0x1ff) //GETB - C := int(inst>>9) & 0x1ff //GETC - if B != 0 { - // +inline-call reg.Set RA LTrue - } else { - // +inline-call reg.Set RA LFalse - } - if C != 0 { - cf.Pc++ - } - return 0 - }, - func(L *LState, inst uint32, baseframe *callFrame) int { //OP_LOADNIL - reg := L.reg - cf := L.currentFrame - lbase := cf.LocalBase - A := int(inst>>18) & 0xff //GETA - RA := lbase + A - B := int(inst & 0x1ff) //GETB - for i := RA; i <= lbase+B; i++ { - // +inline-call reg.Set i LNil - } - return 0 - }, - func(L *LState, inst uint32, baseframe *callFrame) int { //OP_GETUPVAL - reg := L.reg - cf := L.currentFrame - lbase := cf.LocalBase - A := int(inst>>18) & 0xff //GETA - RA := lbase + A - B := int(inst & 0x1ff) //GETB - v := cf.Fn.Upvalues[B].Value() - // +inline-call reg.Set RA v - return 0 - }, - func(L *LState, inst uint32, baseframe *callFrame) int { //OP_GETGLOBAL - reg := L.reg - cf := L.currentFrame - lbase := cf.LocalBase - A := int(inst>>18) & 0xff //GETA - RA := lbase + A - Bx := int(inst & 0x3ffff) //GETBX - //reg.Set(RA, L.getField(cf.Fn.Env, cf.Fn.Proto.Constants[Bx])) - v := L.getFieldString(cf.Fn.Env, cf.Fn.Proto.stringConstants[Bx]) - // +inline-call reg.Set RA v - return 0 - }, - func(L *LState, inst uint32, baseframe *callFrame) int { //OP_GETTABLE - reg := L.reg - cf := L.currentFrame - lbase := cf.LocalBase - A := int(inst>>18) & 0xff //GETA - RA := lbase + A - B := int(inst & 0x1ff) //GETB - C := int(inst>>9) & 0x1ff //GETC - v := L.getField(reg.Get(lbase+B), L.rkValue(C)) - // +inline-call reg.Set RA v - return 0 - }, - func(L *LState, inst uint32, baseframe *callFrame) int { //OP_GETTABLEKS - reg := L.reg - cf := L.currentFrame - lbase := cf.LocalBase - A := int(inst>>18) & 0xff //GETA - RA := lbase + A - B := int(inst & 0x1ff) //GETB - C := int(inst>>9) & 0x1ff //GETC - v := L.getFieldString(reg.Get(lbase+B), L.rkString(C)) - // +inline-call reg.Set RA v - return 0 - }, - func(L *LState, inst uint32, baseframe *callFrame) int { //OP_SETGLOBAL - reg := L.reg - cf := L.currentFrame - lbase := cf.LocalBase - A := int(inst>>18) & 0xff //GETA - RA := lbase + A - Bx := int(inst & 0x3ffff) //GETBX - //L.setField(cf.Fn.Env, cf.Fn.Proto.Constants[Bx], reg.Get(RA)) - L.setFieldString(cf.Fn.Env, cf.Fn.Proto.stringConstants[Bx], reg.Get(RA)) - return 0 - }, - func(L *LState, inst uint32, baseframe *callFrame) int { //OP_SETUPVAL - reg := L.reg - cf := L.currentFrame - lbase := cf.LocalBase - A := int(inst>>18) & 0xff //GETA - RA := lbase + A - B := int(inst & 0x1ff) //GETB - cf.Fn.Upvalues[B].SetValue(reg.Get(RA)) - return 0 - }, - func(L *LState, inst uint32, baseframe *callFrame) int { //OP_SETTABLE - reg := L.reg - cf := L.currentFrame - lbase := cf.LocalBase - A := int(inst>>18) & 0xff //GETA - RA := lbase + A - B := int(inst & 0x1ff) //GETB - C := int(inst>>9) & 0x1ff //GETC - L.setField(reg.Get(RA), L.rkValue(B), L.rkValue(C)) - return 0 - }, - func(L *LState, inst uint32, baseframe *callFrame) int { //OP_SETTABLEKS - reg := L.reg - cf := L.currentFrame - lbase := cf.LocalBase - A := int(inst>>18) & 0xff //GETA - RA := lbase + A - B := int(inst & 0x1ff) //GETB - C := int(inst>>9) & 0x1ff //GETC - L.setFieldString(reg.Get(RA), L.rkString(B), L.rkValue(C)) - return 0 - }, - func(L *LState, inst uint32, baseframe *callFrame) int { //OP_NEWTABLE - reg := L.reg - cf := L.currentFrame - lbase := cf.LocalBase - A := int(inst>>18) & 0xff //GETA - RA := lbase + A - B := int(inst & 0x1ff) //GETB - C := int(inst>>9) & 0x1ff //GETC - v := newLTable(B, C) - // +inline-call reg.Set RA v - return 0 - }, - func(L *LState, inst uint32, baseframe *callFrame) int { //OP_SELF - reg := L.reg - cf := L.currentFrame - lbase := cf.LocalBase - A := int(inst>>18) & 0xff //GETA - RA := lbase + A - B := int(inst & 0x1ff) //GETB - C := int(inst>>9) & 0x1ff //GETC - selfobj := reg.Get(lbase + B) - v := L.getFieldString(selfobj, L.rkString(C)) - // +inline-call reg.Set RA v - // +inline-call reg.Set RA+1 selfobj - return 0 - }, - opArith, // OP_ADD - opArith, // OP_SUB - opArith, // OP_MUL - opArith, // OP_DIV - opArith, // OP_MOD - opArith, // OP_POW - func(L *LState, inst uint32, baseframe *callFrame) int { //OP_UNM - reg := L.reg - cf := L.currentFrame - lbase := cf.LocalBase - A := int(inst>>18) & 0xff //GETA - RA := lbase + A - B := int(inst & 0x1ff) //GETB - unaryv := L.rkValue(B) - if nm, ok := unaryv.(LNumber); ok { - // +inline-call reg.Set RA -nm - } else { - op := L.metaOp1(unaryv, "__unm") - if op.Type() == LTFunction { - reg.Push(op) - reg.Push(unaryv) - L.Call(1, 1) - // +inline-call reg.Set RA reg.Pop() - } else if str, ok1 := unaryv.(LString); ok1 { - if num, err := parseNumber(string(str)); err == nil { - // +inline-call reg.Set RA -num - } else { - L.RaiseError("__unm undefined") - } - } else { - L.RaiseError("__unm undefined") - } - } - return 0 - }, - func(L *LState, inst uint32, baseframe *callFrame) int { //OP_NOT - reg := L.reg - cf := L.currentFrame - lbase := cf.LocalBase - A := int(inst>>18) & 0xff //GETA - RA := lbase + A - B := int(inst & 0x1ff) //GETB - if LVIsFalse(reg.Get(lbase + B)) { - // +inline-call reg.Set RA LTrue - } else { - // +inline-call reg.Set RA LFalse - } - return 0 - }, - func(L *LState, inst uint32, baseframe *callFrame) int { //OP_LEN - reg := L.reg - cf := L.currentFrame - lbase := cf.LocalBase - A := int(inst>>18) & 0xff //GETA - RA := lbase + A - B := int(inst & 0x1ff) //GETB - switch lv := L.rkValue(B).(type) { - case LString: - // +inline-call reg.SetNumber RA LNumber(len(lv)) - default: - op := L.metaOp1(lv, "__len") - if op.Type() == LTFunction { - reg.Push(op) - reg.Push(lv) - L.Call(1, 1) - ret := reg.Pop() - if ret.Type() == LTNumber { - v, _ := ret.(LNumber) - // +inline-call reg.SetNumber RA v - } else { - // +inline-call reg.Set RA ret - } - } else if lv.Type() == LTTable { - // +inline-call reg.SetNumber RA LNumber(lv.(*LTable).Len()) - } else { - L.RaiseError("__len undefined") - } - } - return 0 - }, - func(L *LState, inst uint32, baseframe *callFrame) int { //OP_CONCAT - reg := L.reg - cf := L.currentFrame - lbase := cf.LocalBase - A := int(inst>>18) & 0xff //GETA - RA := lbase + A - B := int(inst & 0x1ff) //GETB - C := int(inst>>9) & 0x1ff //GETC - RC := lbase + C - RB := lbase + B - v := stringConcat(L, RC-RB+1, RC) - // +inline-call reg.Set RA v - return 0 - }, - func(L *LState, inst uint32, baseframe *callFrame) int { //OP_JMP - cf := L.currentFrame - Sbx := int(inst&0x3ffff) - opMaxArgSbx //GETSBX - cf.Pc += Sbx - return 0 - }, - func(L *LState, inst uint32, baseframe *callFrame) int { //OP_EQ - cf := L.currentFrame - A := int(inst>>18) & 0xff //GETA - B := int(inst & 0x1ff) //GETB - C := int(inst>>9) & 0x1ff //GETC - ret := equals(L, L.rkValue(B), L.rkValue(C), false) - v := 1 - if ret { - v = 0 - } - if v == A { - cf.Pc++ - } - return 0 - }, - func(L *LState, inst uint32, baseframe *callFrame) int { //OP_LT - cf := L.currentFrame - A := int(inst>>18) & 0xff //GETA - B := int(inst & 0x1ff) //GETB - C := int(inst>>9) & 0x1ff //GETC - ret := lessThan(L, L.rkValue(B), L.rkValue(C)) - v := 1 - if ret { - v = 0 - } - if v == A { - cf.Pc++ - } - return 0 - }, - func(L *LState, inst uint32, baseframe *callFrame) int { //OP_LE - cf := L.currentFrame - A := int(inst>>18) & 0xff //GETA - B := int(inst & 0x1ff) //GETB - C := int(inst>>9) & 0x1ff //GETC - lhs := L.rkValue(B) - rhs := L.rkValue(C) - ret := false - - if v1, ok1 := lhs.(LNumber); ok1 { - if v2, ok2 := rhs.(LNumber); ok2 { - ret = v1 <= v2 - } else { - L.RaiseError("attempt to compare %v with %v", lhs.Type().String(), rhs.Type().String()) - } - } else { - if lhs.Type() != rhs.Type() { - L.RaiseError("attempt to compare %v with %v", lhs.Type().String(), rhs.Type().String()) - } - switch lhs.Type() { - case LTString: - ret = strCmp(string(lhs.(LString)), string(rhs.(LString))) <= 0 - default: - switch objectRational(L, lhs, rhs, "__le") { - case 1: - ret = true - case 0: - ret = false - default: - ret = !objectRationalWithError(L, rhs, lhs, "__lt") - } - } - } - - v := 1 - if ret { - v = 0 - } - if v == A { - cf.Pc++ - } - return 0 - }, - func(L *LState, inst uint32, baseframe *callFrame) int { //OP_TEST - reg := L.reg - cf := L.currentFrame - lbase := cf.LocalBase - A := int(inst>>18) & 0xff //GETA - RA := lbase + A - C := int(inst>>9) & 0x1ff //GETC - if LVAsBool(reg.Get(RA)) == (C == 0) { - cf.Pc++ - } - return 0 - }, - func(L *LState, inst uint32, baseframe *callFrame) int { //OP_TESTSET - reg := L.reg - cf := L.currentFrame - lbase := cf.LocalBase - A := int(inst>>18) & 0xff //GETA - RA := lbase + A - B := int(inst & 0x1ff) //GETB - C := int(inst>>9) & 0x1ff //GETC - if value := reg.Get(lbase + B); LVAsBool(value) != (C == 0) { - // +inline-call reg.Set RA value - } else { - cf.Pc++ - } - return 0 - }, - func(L *LState, inst uint32, baseframe *callFrame) int { //OP_CALL - reg := L.reg - cf := L.currentFrame - lbase := cf.LocalBase - A := int(inst>>18) & 0xff //GETA - RA := lbase + A - B := int(inst & 0x1ff) //GETB - C := int(inst>>9) & 0x1ff //GETC - nargs := B - 1 - if B == 0 { - nargs = reg.Top() - (RA + 1) - } - lv := reg.Get(RA) - nret := C - 1 - var callable *LFunction - var meta bool - if fn, ok := lv.(*LFunction); ok { - callable = fn - meta = false - } else { - callable, meta = L.metaCall(lv) - } - // +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 - if callable.IsG && callGFunction(L, false) { - return 1 - } - return 0 - }, - func(L *LState, inst uint32, baseframe *callFrame) int { //OP_TAILCALL - reg := L.reg - cf := L.currentFrame - lbase := cf.LocalBase - A := int(inst>>18) & 0xff //GETA - RA := lbase + A - B := int(inst & 0x1ff) //GETB - nargs := B - 1 - if B == 0 { - nargs = reg.Top() - (RA + 1) - } - lv := reg.Get(RA) - var callable *LFunction - var meta bool - if fn, ok := lv.(*LFunction); ok { - callable = fn - meta = false - } else { - callable, meta = L.metaCall(lv) - } - if callable == nil { - L.RaiseError("attempt to call a non-function object") - } - // +inline-call L.closeUpvalues lbase - if callable.IsG { - luaframe := cf - L.pushCallFrame(callFrame{ - Fn: callable, - Pc: 0, - Base: RA, - LocalBase: RA + 1, - ReturnBase: cf.ReturnBase, - NArgs: nargs, - NRet: cf.NRet, - Parent: cf, - TailCall: 0, - }, lv, meta) - if callGFunction(L, true) { - return 1 - } - if L.currentFrame == nil || L.currentFrame.Fn.IsG || luaframe == baseframe { - return 1 - } - } else { - base := cf.Base - cf.Fn = callable - cf.Pc = 0 - cf.Base = RA - cf.LocalBase = RA + 1 - cf.ReturnBase = cf.ReturnBase - cf.NArgs = nargs - cf.NRet = cf.NRet - cf.TailCall++ - lbase := cf.LocalBase - if meta { - cf.NArgs++ - L.reg.Insert(lv, cf.LocalBase) - } - // +inline-call L.initCallFrame cf - // +inline-call L.reg.CopyRange base RA -1 reg.Top()-RA-1 - cf.Base = base - cf.LocalBase = base + (cf.LocalBase - lbase + 1) - } - return 0 - }, - func(L *LState, inst uint32, baseframe *callFrame) int { //OP_RETURN - reg := L.reg - cf := L.currentFrame - lbase := cf.LocalBase - A := int(inst>>18) & 0xff //GETA - RA := lbase + A - B := int(inst & 0x1ff) //GETB - // +inline-call L.closeUpvalues lbase - nret := B - 1 - if B == 0 { - nret = reg.Top() - RA - } - n := cf.NRet - if cf.NRet == MultRet { - n = nret - } - - if L.Parent != nil && L.stack.Sp() == 1 { - // +inline-call copyReturnValues L reg.Top() RA n B - switchToParentThread(L, n, false, true) - return 1 - } - islast := baseframe == L.stack.Pop() || L.stack.IsEmpty() - // +inline-call copyReturnValues L cf.ReturnBase RA n B - L.currentFrame = L.stack.Last() - if islast || L.currentFrame == nil || L.currentFrame.Fn.IsG { - return 1 - } - return 0 - }, - func(L *LState, inst uint32, baseframe *callFrame) int { //OP_FORLOOP - reg := L.reg - cf := L.currentFrame - lbase := cf.LocalBase - A := int(inst>>18) & 0xff //GETA - RA := lbase + A - if init, ok1 := reg.Get(RA).(LNumber); ok1 { - if limit, ok2 := reg.Get(RA + 1).(LNumber); ok2 { - if step, ok3 := reg.Get(RA + 2).(LNumber); ok3 { - init += step - v := LNumber(init) - // +inline-call reg.SetNumber RA v - if (step > 0 && init <= limit) || (step <= 0 && init >= limit) { - Sbx := int(inst&0x3ffff) - opMaxArgSbx //GETSBX - cf.Pc += Sbx - // +inline-call reg.SetNumber RA+3 v - } else { - // +inline-call reg.SetTop RA+1 - } - } else { - L.RaiseError("for statement step must be a number") - } - } else { - L.RaiseError("for statement limit must be a number") - } - } else { - L.RaiseError("for statement init must be a number") - } - return 0 - }, - func(L *LState, inst uint32, baseframe *callFrame) int { //OP_FORPREP - reg := L.reg - cf := L.currentFrame - lbase := cf.LocalBase - A := int(inst>>18) & 0xff //GETA - RA := lbase + A - Sbx := int(inst&0x3ffff) - opMaxArgSbx //GETSBX - if init, ok1 := reg.Get(RA).(LNumber); ok1 { - if step, ok2 := reg.Get(RA + 2).(LNumber); ok2 { - // +inline-call reg.SetNumber RA LNumber(init-step) - } else { - L.RaiseError("for statement step must be a number") - } - } else { - L.RaiseError("for statement init must be a number") - } - cf.Pc += Sbx - return 0 - }, - func(L *LState, inst uint32, baseframe *callFrame) int { //OP_TFORLOOP - reg := L.reg - cf := L.currentFrame - lbase := cf.LocalBase - A := int(inst>>18) & 0xff //GETA - RA := lbase + A - C := int(inst>>9) & 0x1ff //GETC - nret := C - // +inline-call reg.SetTop RA+3+2 - // +inline-call reg.Set RA+3+2 reg.Get(RA+2) - // +inline-call reg.Set RA+3+1 reg.Get(RA+1) - // +inline-call reg.Set RA+3 reg.Get(RA) - L.callR(2, nret, RA+3) - if value := reg.Get(RA + 3); value != LNil { - // +inline-call reg.Set RA+2 value - pc := cf.Fn.Proto.Code[cf.Pc] - cf.Pc += int(pc&0x3ffff) - opMaxArgSbx - } - cf.Pc++ - return 0 - }, - func(L *LState, inst uint32, baseframe *callFrame) int { //OP_SETLIST - reg := L.reg - cf := L.currentFrame - lbase := cf.LocalBase - A := int(inst>>18) & 0xff //GETA - RA := lbase + A - B := int(inst & 0x1ff) //GETB - C := int(inst>>9) & 0x1ff //GETC - if C == 0 { - C = int(cf.Fn.Proto.Code[cf.Pc]) - cf.Pc++ - } - offset := (C - 1) * FieldsPerFlush - table := reg.Get(RA).(*LTable) - nelem := B - if B == 0 { - nelem = reg.Top() - RA - 1 - } - for i := 1; i <= nelem; i++ { - table.RawSetInt(offset+i, reg.Get(RA+i)) - } - return 0 - }, - func(L *LState, inst uint32, baseframe *callFrame) int { //OP_CLOSE - cf := L.currentFrame - lbase := cf.LocalBase - A := int(inst>>18) & 0xff //GETA - RA := lbase + A - // +inline-call L.closeUpvalues RA - return 0 - }, - func(L *LState, inst uint32, baseframe *callFrame) int { //OP_CLOSURE - reg := L.reg - cf := L.currentFrame - lbase := cf.LocalBase - A := int(inst>>18) & 0xff //GETA - RA := lbase + A - Bx := int(inst & 0x3ffff) //GETBX - proto := cf.Fn.Proto.FunctionPrototypes[Bx] - closure := newLFunctionL(proto, cf.Fn.Env, int(proto.NumUpvalues)) - // +inline-call reg.Set RA closure - for i := 0; i < int(proto.NumUpvalues); i++ { - inst = cf.Fn.Proto.Code[cf.Pc] - cf.Pc++ - B := opGetArgB(inst) - switch opGetOpCode(inst) { - case OP_MOVE: - closure.Upvalues[i] = L.findUpvalue(lbase + B) - case OP_GETUPVAL: - closure.Upvalues[i] = cf.Fn.Upvalues[B] - } - } - return 0 - }, - func(L *LState, inst uint32, baseframe *callFrame) int { //OP_VARARG - reg := L.reg - cf := L.currentFrame - lbase := cf.LocalBase - A := int(inst>>18) & 0xff //GETA - RA := lbase + A - B := int(inst & 0x1ff) //GETB - nparams := int(cf.Fn.Proto.NumParameters) - nvarargs := cf.NArgs - nparams - if nvarargs < 0 { - nvarargs = 0 - } - nwant := B - 1 - if B == 0 { - nwant = nvarargs - } - // +inline-call reg.CopyRange RA cf.Base+nparams+1 cf.LocalBase nwant - return 0 - }, - func(L *LState, inst uint32, baseframe *callFrame) int { //OP_NOP - return 0 - }, - } -} - -func opArith(L *LState, inst uint32, baseframe *callFrame) int { //OP_ADD, OP_SUB, OP_MUL, OP_DIV, OP_MOD, OP_POW - reg := L.reg - cf := L.currentFrame - lbase := cf.LocalBase - A := int(inst>>18) & 0xff //GETA - RA := lbase + A - opcode := int(inst >> 26) //GETOPCODE - B := int(inst & 0x1ff) //GETB - C := int(inst>>9) & 0x1ff //GETC - lhs := L.rkValue(B) - rhs := L.rkValue(C) - v1, ok1 := lhs.(LNumber) - v2, ok2 := rhs.(LNumber) - if ok1 && ok2 { - v := numberArith(L, opcode, LNumber(v1), LNumber(v2)) - // +inline-call reg.SetNumber RA v - } else { - v := objectArith(L, opcode, lhs, rhs) - // +inline-call reg.Set RA v - } - return 0 -} - func luaModulo(lhs, rhs LNumber) LNumber { flhs := float64(lhs) frhs := float64(rhs) diff --git a/state.go b/state.go index 292f93b4..eaf36e4f 100644 --- a/state.go +++ b/state.go @@ -1,5 +1,4 @@ package lua - //////////////////////////////////////////////////////// // This file was generated by go-inline. DO NOT EDIT. // //////////////////////////////////////////////////////// @@ -404,14 +403,14 @@ func (rg *registry) forceResize(newSize int) { } func (rg *registry) SetTop(topi int) { // +inline-start - // this section is inlined by go-inline - // source function is 'func (rg *registry) checkSize(requiredSize int) ' in '_state.go' - { - requiredSize := topi - if requiredSize > cap(rg.array) { - rg.resize(requiredSize) - } +// this section is inlined by go-inline +// source function is 'func (rg *registry) checkSize(requiredSize int) ' in '_state.go' +{ +requiredSize := topi + if requiredSize > cap(rg.array) { + rg.resize(requiredSize) } +} oldtopi := rg.top rg.top = topi for i := oldtopi; i < rg.top; i++ { @@ -436,14 +435,14 @@ func (rg *registry) Top() int { func (rg *registry) Push(v LValue) { newSize := rg.top + 1 - // this section is inlined by go-inline - // source function is 'func (rg *registry) checkSize(requiredSize int) ' in '_state.go' - { - requiredSize := newSize - if requiredSize > cap(rg.array) { - rg.resize(requiredSize) - } +// this section is inlined by go-inline +// source function is 'func (rg *registry) checkSize(requiredSize int) ' in '_state.go' +{ +requiredSize := newSize + if requiredSize > cap(rg.array) { + rg.resize(requiredSize) } +} rg.array[rg.top] = v rg.top++ } @@ -470,14 +469,14 @@ func (rg *registry) Get(reg int) LValue { // CopyRange should ideally be renamed to MoveRange. func (rg *registry) CopyRange(regv, start, limit, n int) { // +inline-start newSize := regv + n - // this section is inlined by go-inline - // source function is 'func (rg *registry) checkSize(requiredSize int) ' in '_state.go' - { - requiredSize := newSize - if requiredSize > cap(rg.array) { - rg.resize(requiredSize) - } +// this section is inlined by go-inline +// source function is 'func (rg *registry) checkSize(requiredSize int) ' in '_state.go' +{ +requiredSize := newSize + if requiredSize > cap(rg.array) { + rg.resize(requiredSize) } +} if limit == -1 || limit > rg.top { limit = rg.top } @@ -505,14 +504,14 @@ func (rg *registry) CopyRange(regv, start, limit, n int) { // +inline-start // FillNil fills the registry with nil values from regm to regm+n and then sets the registry top to regm+n func (rg *registry) FillNil(regm, n int) { // +inline-start newSize := regm + n - // this section is inlined by go-inline - // source function is 'func (rg *registry) checkSize(requiredSize int) ' in '_state.go' - { - requiredSize := newSize - if requiredSize > cap(rg.array) { - rg.resize(requiredSize) - } +// this section is inlined by go-inline +// source function is 'func (rg *registry) checkSize(requiredSize int) ' in '_state.go' +{ +requiredSize := newSize + if requiredSize > cap(rg.array) { + rg.resize(requiredSize) } +} for i := 0; i < n; i++ { rg.array[regm+i] = LNil } @@ -531,81 +530,81 @@ func (rg *registry) FillNil(regm, n int) { // +inline-start func (rg *registry) Insert(value LValue, reg int) { top := rg.Top() if reg >= top { - // this section is inlined by go-inline - // source function is 'func (rg *registry) Set(regi int, vali LValue) ' in '_state.go' - { - regi := reg - vali := value - newSize := regi + 1 - // this section is inlined by go-inline - // source function is 'func (rg *registry) checkSize(requiredSize int) ' in '_state.go' - { - requiredSize := newSize - if requiredSize > cap(rg.array) { - rg.resize(requiredSize) - } - } - rg.array[regi] = vali - if regi >= rg.top { - rg.top = regi + 1 - } - } +// this section is inlined by go-inline +// source function is 'func (rg *registry) Set(regi int, vali LValue) ' in '_state.go' +{ +regi := reg +vali := value + newSize := regi + 1 +// this section is inlined by go-inline +// source function is 'func (rg *registry) checkSize(requiredSize int) ' in '_state.go' +{ +requiredSize := newSize + if requiredSize > cap(rg.array) { + rg.resize(requiredSize) + } +} + rg.array[regi] = vali + if regi >= rg.top { + rg.top = regi + 1 + } +} return } top-- for ; top >= reg; top-- { // FIXME consider using copy() here if Insert() is called enough - // this section is inlined by go-inline - // source function is 'func (rg *registry) Set(regi int, vali LValue) ' in '_state.go' - { - regi := top + 1 - vali := rg.Get(top) - newSize := regi + 1 - // this section is inlined by go-inline - // source function is 'func (rg *registry) checkSize(requiredSize int) ' in '_state.go' - { - requiredSize := newSize - if requiredSize > cap(rg.array) { - rg.resize(requiredSize) - } - } - rg.array[regi] = vali - if regi >= rg.top { - rg.top = regi + 1 - } - } +// this section is inlined by go-inline +// source function is 'func (rg *registry) Set(regi int, vali LValue) ' in '_state.go' +{ +regi := top+1 +vali := rg.Get(top) + newSize := regi + 1 +// this section is inlined by go-inline +// source function is 'func (rg *registry) checkSize(requiredSize int) ' in '_state.go' +{ +requiredSize := newSize + if requiredSize > cap(rg.array) { + rg.resize(requiredSize) } - // this section is inlined by go-inline - // source function is 'func (rg *registry) Set(regi int, vali LValue) ' in '_state.go' - { - regi := reg - vali := value - newSize := regi + 1 - // this section is inlined by go-inline - // source function is 'func (rg *registry) checkSize(requiredSize int) ' in '_state.go' - { - requiredSize := newSize - if requiredSize > cap(rg.array) { - rg.resize(requiredSize) - } - } - rg.array[regi] = vali - if regi >= rg.top { - rg.top = regi + 1 - } +} + rg.array[regi] = vali + if regi >= rg.top { + rg.top = regi + 1 } +} + } +// this section is inlined by go-inline +// source function is 'func (rg *registry) Set(regi int, vali LValue) ' in '_state.go' +{ +regi := reg +vali := value + newSize := regi + 1 +// this section is inlined by go-inline +// source function is 'func (rg *registry) checkSize(requiredSize int) ' in '_state.go' +{ +requiredSize := newSize + if requiredSize > cap(rg.array) { + rg.resize(requiredSize) + } +} + rg.array[regi] = vali + if regi >= rg.top { + rg.top = regi + 1 + } +} } func (rg *registry) Set(regi int, vali LValue) { // +inline-start newSize := regi + 1 - // this section is inlined by go-inline - // source function is 'func (rg *registry) checkSize(requiredSize int) ' in '_state.go' - { - requiredSize := newSize - if requiredSize > cap(rg.array) { - rg.resize(requiredSize) - } +// this section is inlined by go-inline +// source function is 'func (rg *registry) checkSize(requiredSize int) ' in '_state.go' +{ +requiredSize := newSize + if requiredSize > cap(rg.array) { + rg.resize(requiredSize) } +} rg.array[regi] = vali if regi >= rg.top { rg.top = regi + 1 @@ -614,14 +613,14 @@ func (rg *registry) Set(regi int, vali LValue) { // +inline-start func (rg *registry) SetNumber(regi int, vali LNumber) { // +inline-start newSize := regi + 1 - // this section is inlined by go-inline - // source function is 'func (rg *registry) checkSize(requiredSize int) ' in '_state.go' - { - requiredSize := newSize - if requiredSize > cap(rg.array) { - rg.resize(requiredSize) - } +// this section is inlined by go-inline +// source function is 'func (rg *registry) checkSize(requiredSize int) ' in '_state.go' +{ +requiredSize := newSize + if requiredSize > cap(rg.array) { + rg.resize(requiredSize) } +} rg.array[regi] = rg.alloc.LNumber2I(vali) if regi >= rg.top { rg.top = regi + 1 @@ -1043,15 +1042,15 @@ func (ls *LState) initCallFrame(cf *callFrame) { // +inline-start if nargs < np { // default any missing arguments to nil newSize := cf.LocalBase + np - // this section is inlined by go-inline - // source function is 'func (rg *registry) checkSize(requiredSize int) ' in '_state.go' - { - rg := ls.reg - requiredSize := newSize - if requiredSize > cap(rg.array) { - rg.resize(requiredSize) - } - } +// this section is inlined by go-inline +// source function is 'func (rg *registry) checkSize(requiredSize int) ' in '_state.go' +{ +rg := ls.reg +requiredSize := newSize + if requiredSize > cap(rg.array) { + rg.resize(requiredSize) + } +} for i := nargs; i < np; i++ { ls.reg.array[cf.LocalBase+i] = LNil } @@ -1064,15 +1063,15 @@ func (ls *LState) initCallFrame(cf *callFrame) { // +inline-start nargs = int(proto.NumUsedRegisters) } newSize := cf.LocalBase + nargs - // this section is inlined by go-inline - // source function is 'func (rg *registry) checkSize(requiredSize int) ' in '_state.go' - { - rg := ls.reg - requiredSize := newSize - if requiredSize > cap(rg.array) { - rg.resize(requiredSize) - } - } +// this section is inlined by go-inline +// source function is 'func (rg *registry) checkSize(requiredSize int) ' in '_state.go' +{ +rg := ls.reg +requiredSize := newSize + if requiredSize > cap(rg.array) { + rg.resize(requiredSize) + } +} for i := np; i < nargs; i++ { ls.reg.array[cf.LocalBase+i] = LNil } @@ -1142,104 +1141,104 @@ func (ls *LState) pushCallFrame(cf callFrame, fn LValue, meta bool) { // +inline } ls.stack.Push(cf) newcf := ls.stack.Last() - // this section is inlined by go-inline - // source function is 'func (ls *LState) initCallFrame(cf *callFrame) ' in '_state.go' - { - cf := newcf - if cf.Fn.IsG { - ls.reg.SetTop(cf.LocalBase + cf.NArgs) - } else { - proto := cf.Fn.Proto - nargs := cf.NArgs - np := int(proto.NumParameters) - if nargs < np { - // default any missing arguments to nil - newSize := cf.LocalBase + np - // this section is inlined by go-inline - // source function is 'func (rg *registry) checkSize(requiredSize int) ' in '_state.go' - { - rg := ls.reg - requiredSize := newSize - if requiredSize > cap(rg.array) { - rg.resize(requiredSize) - } - } - for i := nargs; i < np; i++ { - ls.reg.array[cf.LocalBase+i] = LNil - } - nargs = np - ls.reg.top = newSize +// this section is inlined by go-inline +// source function is 'func (ls *LState) initCallFrame(cf *callFrame) ' in '_state.go' +{ +cf := newcf + if cf.Fn.IsG { + ls.reg.SetTop(cf.LocalBase + cf.NArgs) + } else { + proto := cf.Fn.Proto + nargs := cf.NArgs + np := int(proto.NumParameters) + if nargs < np { + // default any missing arguments to nil + newSize := cf.LocalBase + np +// this section is inlined by go-inline +// source function is 'func (rg *registry) checkSize(requiredSize int) ' in '_state.go' +{ +rg := ls.reg +requiredSize := newSize + if requiredSize > cap(rg.array) { + rg.resize(requiredSize) + } +} + for i := nargs; i < np; i++ { + ls.reg.array[cf.LocalBase+i] = LNil } + nargs = np + ls.reg.top = newSize + } - if (proto.IsVarArg & VarArgIsVarArg) == 0 { - if nargs < int(proto.NumUsedRegisters) { - nargs = int(proto.NumUsedRegisters) - } - newSize := cf.LocalBase + nargs - // this section is inlined by go-inline - // source function is 'func (rg *registry) checkSize(requiredSize int) ' in '_state.go' - { - rg := ls.reg - requiredSize := newSize - if requiredSize > cap(rg.array) { - rg.resize(requiredSize) - } - } - for i := np; i < nargs; i++ { - ls.reg.array[cf.LocalBase+i] = LNil - } - ls.reg.top = cf.LocalBase + int(proto.NumUsedRegisters) - } else { - /* swap vararg positions: - closure - namedparam1 <- lbase - namedparam2 - vararg1 - vararg2 - - TO - - closure - nil - nil - vararg1 - vararg2 - namedparam1 <- lbase - namedparam2 - */ - nvarargs := nargs - np - if nvarargs < 0 { - nvarargs = 0 - } + if (proto.IsVarArg & VarArgIsVarArg) == 0 { + if nargs < int(proto.NumUsedRegisters) { + nargs = int(proto.NumUsedRegisters) + } + newSize := cf.LocalBase + nargs +// this section is inlined by go-inline +// source function is 'func (rg *registry) checkSize(requiredSize int) ' in '_state.go' +{ +rg := ls.reg +requiredSize := newSize + if requiredSize > cap(rg.array) { + rg.resize(requiredSize) + } +} + for i := np; i < nargs; i++ { + ls.reg.array[cf.LocalBase+i] = LNil + } + ls.reg.top = cf.LocalBase + int(proto.NumUsedRegisters) + } else { + /* swap vararg positions: + closure + namedparam1 <- lbase + namedparam2 + vararg1 + vararg2 - ls.reg.SetTop(cf.LocalBase + nargs + np) - for i := 0; i < np; i++ { - //ls.reg.Set(cf.LocalBase+nargs+i, ls.reg.Get(cf.LocalBase+i)) - ls.reg.array[cf.LocalBase+nargs+i] = ls.reg.array[cf.LocalBase+i] - //ls.reg.Set(cf.LocalBase+i, LNil) - ls.reg.array[cf.LocalBase+i] = LNil - } + TO - if CompatVarArg { - ls.reg.SetTop(cf.LocalBase + nargs + np + 1) - if (proto.IsVarArg & VarArgNeedsArg) != 0 { - argtb := newLTable(nvarargs, 0) - for i := 0; i < nvarargs; i++ { - argtb.RawSetInt(i+1, ls.reg.Get(cf.LocalBase+np+i)) - } - argtb.RawSetString("n", LNumber(nvarargs)) - //ls.reg.Set(cf.LocalBase+nargs+np, argtb) - ls.reg.array[cf.LocalBase+nargs+np] = argtb - } else { - ls.reg.array[cf.LocalBase+nargs+np] = LNil + closure + nil + nil + vararg1 + vararg2 + namedparam1 <- lbase + namedparam2 + */ + nvarargs := nargs - np + if nvarargs < 0 { + nvarargs = 0 + } + + ls.reg.SetTop(cf.LocalBase + nargs + np) + for i := 0; i < np; i++ { + //ls.reg.Set(cf.LocalBase+nargs+i, ls.reg.Get(cf.LocalBase+i)) + ls.reg.array[cf.LocalBase+nargs+i] = ls.reg.array[cf.LocalBase+i] + //ls.reg.Set(cf.LocalBase+i, LNil) + ls.reg.array[cf.LocalBase+i] = LNil + } + + if CompatVarArg { + ls.reg.SetTop(cf.LocalBase + nargs + np + 1) + if (proto.IsVarArg & VarArgNeedsArg) != 0 { + argtb := newLTable(nvarargs, 0) + for i := 0; i < nvarargs; i++ { + argtb.RawSetInt(i+1, ls.reg.Get(cf.LocalBase+np+i)) } + argtb.RawSetString("n", LNumber(nvarargs)) + //ls.reg.Set(cf.LocalBase+nargs+np, argtb) + ls.reg.array[cf.LocalBase+nargs+np] = argtb + } else { + ls.reg.array[cf.LocalBase+nargs+np] = LNil } - cf.LocalBase += nargs - maxreg := cf.LocalBase + int(proto.NumUsedRegisters) - ls.reg.SetTop(maxreg) } + cf.LocalBase += nargs + maxreg := cf.LocalBase + int(proto.NumUsedRegisters) + ls.reg.SetTop(maxreg) } } +} ls.currentFrame = newcf } // +inline-end @@ -2304,3 +2303,4 @@ func (ls *LState) RemoveCallerFrame() *callFrame { /* }}} */ // + diff --git a/vm.go b/vm.go index 97335a75..d29d7535 100644 --- a/vm.go +++ b/vm.go @@ -1,5 +1,4 @@ package lua - //////////////////////////////////////////////////////// // This file was generated by go-inline. DO NOT EDIT. // //////////////////////////////////////////////////////// @@ -10,2261 +9,2090 @@ import ( "strings" ) -func mainLoop(L *LState, baseframe *callFrame) { - var inst uint32 - var cf *callFrame - - if L.stack.IsEmpty() { - return +func evalInstruction(L *LState, inst uint32, baseframe *callFrame) bool { + reg := L.reg + cf := L.currentFrame + lbase := cf.LocalBase + opcode := int(inst >> 26) + switch opcode { + case OP_MOVE: + A := int(inst>>18) & 0xff //GETA + RA := lbase + A + B := int(inst & 0x1ff) //GETB + v := reg.Get(lbase + B) +// this section is inlined by go-inline +// source function is 'func (rg *registry) Set(regi int, vali LValue) ' in '_state.go' +{ +rg := reg +regi := RA +vali := v + newSize := regi + 1 +// this section is inlined by go-inline +// source function is 'func (rg *registry) checkSize(requiredSize int) ' in '_state.go' +{ +requiredSize := newSize + if requiredSize > cap(rg.array) { + rg.resize(requiredSize) } - - L.currentFrame = L.stack.Last() - if L.currentFrame.Fn.IsG { - callGFunction(L, false) - return +} + rg.array[regi] = vali + if regi >= rg.top { + rg.top = regi + 1 } - - for { - cf = L.currentFrame - inst = cf.Fn.Proto.Code[cf.Pc] - cf.Pc++ - if jumpTable[int(inst>>26)](L, inst, baseframe) == 1 { - return - } +} + case OP_MOVEN: + A := int(inst>>18) & 0xff //GETA + B := int(inst & 0x1ff) //GETB + C := int(inst>>9) & 0x1ff //GETC + v := reg.Get(lbase + B) +// this section is inlined by go-inline +// source function is 'func (rg *registry) Set(regi int, vali LValue) ' in '_state.go' +{ +rg := reg +regi := lbase+A +vali := v + newSize := regi + 1 +// this section is inlined by go-inline +// source function is 'func (rg *registry) checkSize(requiredSize int) ' in '_state.go' +{ +requiredSize := newSize + if requiredSize > cap(rg.array) { + rg.resize(requiredSize) } } - -func mainLoopWithContext(L *LState, baseframe *callFrame) { - var inst uint32 - var cf *callFrame - - if L.stack.IsEmpty() { - return + rg.array[regi] = vali + if regi >= rg.top { + rg.top = regi + 1 } - - L.currentFrame = L.stack.Last() - if L.currentFrame.Fn.IsG { - callGFunction(L, false) - return +} + code := cf.Fn.Proto.Code + pc := cf.Pc + for i := 0; i < C; i++ { + inst = code[pc] + pc++ + A = int(inst>>18) & 0xff //GETA + B = int(inst & 0x1ff) //GETB + v := reg.Get(lbase + B) +// this section is inlined by go-inline +// source function is 'func (rg *registry) Set(regi int, vali LValue) ' in '_state.go' +{ +rg := reg +regi := lbase+A +vali := v + newSize := regi + 1 +// this section is inlined by go-inline +// source function is 'func (rg *registry) checkSize(requiredSize int) ' in '_state.go' +{ +requiredSize := newSize + if requiredSize > cap(rg.array) { + rg.resize(requiredSize) } - - for { - cf = L.currentFrame - inst = cf.Fn.Proto.Code[cf.Pc] - cf.Pc++ - select { - case <-L.ctx.Done(): - L.RaiseError(L.ctx.Err().Error()) - return - default: - if jumpTable[int(inst>>26)](L, inst, baseframe) == 1 { - return - } +} + rg.array[regi] = vali + if regi >= rg.top { + rg.top = regi + 1 + } +} } + cf.Pc = pc + case OP_LOADK: + A := int(inst>>18) & 0xff //GETA + RA := lbase + A + Bx := int(inst & 0x3ffff) //GETBX + v := cf.Fn.Proto.Constants[Bx] +// this section is inlined by go-inline +// source function is 'func (rg *registry) Set(regi int, vali LValue) ' in '_state.go' +{ +rg := reg +regi := RA +vali := v + newSize := regi + 1 +// this section is inlined by go-inline +// source function is 'func (rg *registry) checkSize(requiredSize int) ' in '_state.go' +{ +requiredSize := newSize + if requiredSize > cap(rg.array) { + rg.resize(requiredSize) + } +} + rg.array[regi] = vali + if regi >= rg.top { + rg.top = regi + 1 + } +} + case OP_LOADBOOL: + A := int(inst>>18) & 0xff //GETA + RA := lbase + A + B := int(inst & 0x1ff) //GETB + C := int(inst>>9) & 0x1ff //GETC + if B != 0 { +// this section is inlined by go-inline +// source function is 'func (rg *registry) Set(regi int, vali LValue) ' in '_state.go' +{ +rg := reg +regi := RA +vali := LTrue + newSize := regi + 1 +// this section is inlined by go-inline +// source function is 'func (rg *registry) checkSize(requiredSize int) ' in '_state.go' +{ +requiredSize := newSize + if requiredSize > cap(rg.array) { + rg.resize(requiredSize) + } +} + rg.array[regi] = vali + if regi >= rg.top { + rg.top = regi + 1 + } +} + } else { +// this section is inlined by go-inline +// source function is 'func (rg *registry) Set(regi int, vali LValue) ' in '_state.go' +{ +rg := reg +regi := RA +vali := LFalse + newSize := regi + 1 +// this section is inlined by go-inline +// source function is 'func (rg *registry) checkSize(requiredSize int) ' in '_state.go' +{ +requiredSize := newSize + if requiredSize > cap(rg.array) { + rg.resize(requiredSize) + } +} + rg.array[regi] = vali + if regi >= rg.top { + rg.top = regi + 1 } } - -// regv is the first target register to copy the return values to. -// It can be reg.top, indicating that the copied values are going into new registers, or it can be below reg.top -// Indicating that the values should be within the existing registers. -// b is the available number of return values + 1. -// n is the desired number of return values. -// If n more than the available return values then the extra values are set to nil. -// When this function returns the top of the registry will be set to regv+n. -func copyReturnValues(L *LState, regv, start, n, b int) { // +inline-start - if b == 1 { - // this section is inlined by go-inline - // source function is 'func (rg *registry) FillNil(regm, n int) ' in '_state.go' - { - rg := L.reg - regm := regv - newSize := regm + n - // this section is inlined by go-inline - // source function is 'func (rg *registry) checkSize(requiredSize int) ' in '_state.go' - { - requiredSize := newSize - if requiredSize > cap(rg.array) { - rg.resize(requiredSize) - } - } - for i := 0; i < n; i++ { - rg.array[regm+i] = LNil - } - // values beyond top don't need to be valid LValues, so setting them to nil is fine - // setting them to nil rather than LNil lets us invoke the golang memclr opto - oldtop := rg.top - rg.top = regm + n - if rg.top < oldtop { - nilRange := rg.array[rg.top:oldtop] - for i := range nilRange { - nilRange[i] = nil - } - } } - } else { - // this section is inlined by go-inline - // source function is 'func (rg *registry) CopyRange(regv, start, limit, n int) ' in '_state.go' - { - rg := L.reg - limit := -1 - newSize := regv + n - // this section is inlined by go-inline - // source function is 'func (rg *registry) checkSize(requiredSize int) ' in '_state.go' - { - requiredSize := newSize - if requiredSize > cap(rg.array) { - rg.resize(requiredSize) - } - } - if limit == -1 || limit > rg.top { - limit = rg.top - } - for i := 0; i < n; i++ { - srcIdx := start + i - if srcIdx >= limit || srcIdx < 0 { - rg.array[regv+i] = LNil - } else { - rg.array[regv+i] = rg.array[srcIdx] - } - } - - // values beyond top don't need to be valid LValues, so setting them to nil is fine - // setting them to nil rather than LNil lets us invoke the golang memclr opto - oldtop := rg.top - rg.top = regv + n - if rg.top < oldtop { - nilRange := rg.array[rg.top:oldtop] - for i := range nilRange { - nilRange[i] = nil - } - } + if C != 0 { + cf.Pc++ } - if b > 1 && n > (b-1) { - // this section is inlined by go-inline - // source function is 'func (rg *registry) FillNil(regm, n int) ' in '_state.go' - { - rg := L.reg - regm := regv + b - 1 - n := n - (b - 1) - newSize := regm + n - // this section is inlined by go-inline - // source function is 'func (rg *registry) checkSize(requiredSize int) ' in '_state.go' - { - requiredSize := newSize - if requiredSize > cap(rg.array) { - rg.resize(requiredSize) - } - } - for i := 0; i < n; i++ { - rg.array[regm+i] = LNil - } - // values beyond top don't need to be valid LValues, so setting them to nil is fine - // setting them to nil rather than LNil lets us invoke the golang memclr opto - oldtop := rg.top - rg.top = regm + n - if rg.top < oldtop { - nilRange := rg.array[rg.top:oldtop] - for i := range nilRange { - nilRange[i] = nil - } - } - } + case OP_LOADNIL: + A := int(inst>>18) & 0xff //GETA + RA := lbase + A + B := int(inst & 0x1ff) //GETB + for i := RA; i <= lbase+B; i++ { +// this section is inlined by go-inline +// source function is 'func (rg *registry) Set(regi int, vali LValue) ' in '_state.go' +{ +rg := reg +regi := i +vali := LNil + newSize := regi + 1 +// this section is inlined by go-inline +// source function is 'func (rg *registry) checkSize(requiredSize int) ' in '_state.go' +{ +requiredSize := newSize + if requiredSize > cap(rg.array) { + rg.resize(requiredSize) + } +} + rg.array[regi] = vali + if regi >= rg.top { + rg.top = regi + 1 + } +} } + case OP_GETUPVAL: + reg := L.reg + cf := L.currentFrame + lbase := cf.LocalBase + A := int(inst>>18) & 0xff //GETA + RA := lbase + A + B := int(inst & 0x1ff) //GETB + v := cf.Fn.Upvalues[B].Value() +// this section is inlined by go-inline +// source function is 'func (rg *registry) Set(regi int, vali LValue) ' in '_state.go' +{ +rg := reg +regi := RA +vali := v + newSize := regi + 1 +// this section is inlined by go-inline +// source function is 'func (rg *registry) checkSize(requiredSize int) ' in '_state.go' +{ +requiredSize := newSize + if requiredSize > cap(rg.array) { + rg.resize(requiredSize) } -} // +inline-end - -func switchToParentThread(L *LState, nargs int, haserror bool, kill bool) { - parent := L.Parent - if parent == nil { - L.RaiseError("can not yield from outside of a coroutine") +} + rg.array[regi] = vali + if regi >= rg.top { + rg.top = regi + 1 } - L.G.CurrentThread = parent - L.Parent = nil - if !L.wrapped { - if haserror { - parent.Push(LFalse) +} + case OP_GETGLOBAL: + A := int(inst>>18) & 0xff //GETA + RA := lbase + A + Bx := int(inst & 0x3ffff) //GETBX + //reg.Set(RA, L.getField(cf.Fn.Env, cf.Fn.Proto.Constants[Bx])) + v := L.getFieldString(cf.Fn.Env, cf.Fn.Proto.stringConstants[Bx]) +// this section is inlined by go-inline +// source function is 'func (rg *registry) Set(regi int, vali LValue) ' in '_state.go' +{ +rg := reg +regi := RA +vali := v + newSize := regi + 1 +// this section is inlined by go-inline +// source function is 'func (rg *registry) checkSize(requiredSize int) ' in '_state.go' +{ +requiredSize := newSize + if requiredSize > cap(rg.array) { + rg.resize(requiredSize) + } +} + rg.array[regi] = vali + if regi >= rg.top { + rg.top = regi + 1 + } +} + case OP_GETTABLE: + A := int(inst>>18) & 0xff //GETA + RA := lbase + A + B := int(inst & 0x1ff) //GETB + C := int(inst>>9) & 0x1ff //GETC + v := L.getField(reg.Get(lbase+B), L.rkValue(C)) +// this section is inlined by go-inline +// source function is 'func (rg *registry) Set(regi int, vali LValue) ' in '_state.go' +{ +rg := reg +regi := RA +vali := v + newSize := regi + 1 +// this section is inlined by go-inline +// source function is 'func (rg *registry) checkSize(requiredSize int) ' in '_state.go' +{ +requiredSize := newSize + if requiredSize > cap(rg.array) { + rg.resize(requiredSize) + } +} + rg.array[regi] = vali + if regi >= rg.top { + rg.top = regi + 1 + } +} + case OP_GETTABLEKS: + A := int(inst>>18) & 0xff //GETA + RA := lbase + A + B := int(inst & 0x1ff) //GETB + C := int(inst>>9) & 0x1ff //GETC + v := L.getFieldString(reg.Get(lbase+B), L.rkString(C)) +// this section is inlined by go-inline +// source function is 'func (rg *registry) Set(regi int, vali LValue) ' in '_state.go' +{ +rg := reg +regi := RA +vali := v + newSize := regi + 1 +// this section is inlined by go-inline +// source function is 'func (rg *registry) checkSize(requiredSize int) ' in '_state.go' +{ +requiredSize := newSize + if requiredSize > cap(rg.array) { + rg.resize(requiredSize) + } +} + rg.array[regi] = vali + if regi >= rg.top { + rg.top = regi + 1 + } +} + case OP_SETGLOBAL: + A := int(inst>>18) & 0xff //GETA + RA := lbase + A + Bx := int(inst & 0x3ffff) //GETBX + //L.setField(cf.Fn.Env, cf.Fn.Proto.Constants[Bx], reg.Get(RA)) + L.setFieldString(cf.Fn.Env, cf.Fn.Proto.stringConstants[Bx], reg.Get(RA)) + case OP_SETUPVAL: + A := int(inst>>18) & 0xff //GETA + RA := lbase + A + B := int(inst & 0x1ff) //GETB + cf.Fn.Upvalues[B].SetValue(reg.Get(RA)) + case OP_SETTABLE: + A := int(inst>>18) & 0xff //GETA + RA := lbase + A + B := int(inst & 0x1ff) //GETB + C := int(inst>>9) & 0x1ff //GETC + L.setField(reg.Get(RA), L.rkValue(B), L.rkValue(C)) + case OP_SETTABLEKS: + A := int(inst>>18) & 0xff //GETA + RA := lbase + A + B := int(inst & 0x1ff) //GETB + C := int(inst>>9) & 0x1ff //GETC + L.setFieldString(reg.Get(RA), L.rkString(B), L.rkValue(C)) + case OP_NEWTABLE: + A := int(inst>>18) & 0xff //GETA + RA := lbase + A + B := int(inst & 0x1ff) //GETB + C := int(inst>>9) & 0x1ff //GETC + v := newLTable(B, C) +// this section is inlined by go-inline +// source function is 'func (rg *registry) Set(regi int, vali LValue) ' in '_state.go' +{ +rg := reg +regi := RA +vali := v + newSize := regi + 1 +// this section is inlined by go-inline +// source function is 'func (rg *registry) checkSize(requiredSize int) ' in '_state.go' +{ +requiredSize := newSize + if requiredSize > cap(rg.array) { + rg.resize(requiredSize) + } +} + rg.array[regi] = vali + if regi >= rg.top { + rg.top = regi + 1 + } +} + case OP_SELF: + A := int(inst>>18) & 0xff //GETA + RA := lbase + A + B := int(inst & 0x1ff) //GETB + C := int(inst>>9) & 0x1ff //GETC + selfobj := reg.Get(lbase + B) + v := L.getFieldString(selfobj, L.rkString(C)) +// this section is inlined by go-inline +// source function is 'func (rg *registry) Set(regi int, vali LValue) ' in '_state.go' +{ +rg := reg +regi := RA +vali := v + newSize := regi + 1 +// this section is inlined by go-inline +// source function is 'func (rg *registry) checkSize(requiredSize int) ' in '_state.go' +{ +requiredSize := newSize + if requiredSize > cap(rg.array) { + rg.resize(requiredSize) + } +} + rg.array[regi] = vali + if regi >= rg.top { + rg.top = regi + 1 + } +} +// this section is inlined by go-inline +// source function is 'func (rg *registry) Set(regi int, vali LValue) ' in '_state.go' +{ +rg := reg +regi := RA+1 +vali := selfobj + newSize := regi + 1 +// this section is inlined by go-inline +// source function is 'func (rg *registry) checkSize(requiredSize int) ' in '_state.go' +{ +requiredSize := newSize + if requiredSize > cap(rg.array) { + rg.resize(requiredSize) + } +} + rg.array[regi] = vali + if regi >= rg.top { + rg.top = regi + 1 + } +} + case OP_ADD, OP_SUB, OP_MUL, OP_DIV, OP_MOD, OP_POW: + A := int(inst>>18) & 0xff //GETA + RA := lbase + A + B := int(inst & 0x1ff) //GETB + C := int(inst>>9) & 0x1ff //GETC + lhs := L.rkValue(B) + rhs := L.rkValue(C) + v1, ok1 := lhs.(LNumber) + v2, ok2 := rhs.(LNumber) + if ok1 && ok2 { + v := numberArith(L, opcode, LNumber(v1), LNumber(v2)) +// this section is inlined by go-inline +// source function is 'func (rg *registry) SetNumber(regi int, vali LNumber) ' in '_state.go' +{ +rg := reg +regi := RA +vali := v + newSize := regi + 1 +// this section is inlined by go-inline +// source function is 'func (rg *registry) checkSize(requiredSize int) ' in '_state.go' +{ +requiredSize := newSize + if requiredSize > cap(rg.array) { + rg.resize(requiredSize) + } +} + rg.array[regi] = rg.alloc.LNumber2I(vali) + if regi >= rg.top { + rg.top = regi + 1 + } +} } else { - parent.Push(LTrue) - } + v := objectArith(L, opcode, lhs, rhs) +// this section is inlined by go-inline +// source function is 'func (rg *registry) Set(regi int, vali LValue) ' in '_state.go' +{ +rg := reg +regi := RA +vali := v + newSize := regi + 1 +// this section is inlined by go-inline +// source function is 'func (rg *registry) checkSize(requiredSize int) ' in '_state.go' +{ +requiredSize := newSize + if requiredSize > cap(rg.array) { + rg.resize(requiredSize) } - L.XMoveTo(parent, nargs) - L.stack.Pop() - offset := L.currentFrame.LocalBase - L.currentFrame.ReturnBase - L.currentFrame = L.stack.Last() - L.reg.SetTop(L.reg.Top() - offset) // remove 'yield' function(including tailcalled functions) - if kill { - L.kill() +} + rg.array[regi] = vali + if regi >= rg.top { + rg.top = regi + 1 } } + } -func callGFunction(L *LState, tailcall bool) bool { - frame := L.currentFrame - gfnret := frame.Fn.GFunction(L) - if tailcall { - L.currentFrame = L.RemoveCallerFrame() + case OP_UNM: + A := int(inst>>18) & 0xff //GETA + RA := lbase + A + B := int(inst & 0x1ff) //GETB + unaryv := L.rkValue(B) + if nm, ok := unaryv.(LNumber); ok { +// this section is inlined by go-inline +// source function is 'func (rg *registry) Set(regi int, vali LValue) ' in '_state.go' +{ +rg := reg +regi := RA +vali := -nm + newSize := regi + 1 +// this section is inlined by go-inline +// source function is 'func (rg *registry) checkSize(requiredSize int) ' in '_state.go' +{ +requiredSize := newSize + if requiredSize > cap(rg.array) { + rg.resize(requiredSize) } - - if gfnret < 0 { - switchToParentThread(L, L.GetTop(), false, false) - return true +} + rg.array[regi] = vali + if regi >= rg.top { + rg.top = regi + 1 } - - wantret := frame.NRet - if wantret == MultRet { - wantret = gfnret +} + } else { + op := L.metaOp1(unaryv, "__unm") + if op.Type() == LTFunction { + reg.Push(op) + reg.Push(unaryv) + L.Call(1, 1) +// this section is inlined by go-inline +// source function is 'func (rg *registry) Set(regi int, vali LValue) ' in '_state.go' +{ +rg := reg +regi := RA +vali := reg.Pop() + newSize := regi + 1 +// this section is inlined by go-inline +// source function is 'func (rg *registry) checkSize(requiredSize int) ' in '_state.go' +{ +requiredSize := newSize + if requiredSize > cap(rg.array) { + rg.resize(requiredSize) } - - if tailcall && L.Parent != nil && L.stack.Sp() == 1 { - switchToParentThread(L, wantret, false, true) - return true +} + rg.array[regi] = vali + if regi >= rg.top { + rg.top = regi + 1 } - - // this section is inlined by go-inline - // source function is 'func (rg *registry) CopyRange(regv, start, limit, n int) ' in '_state.go' - { - rg := L.reg - regv := frame.ReturnBase - start := L.reg.Top() - gfnret - limit := -1 - n := wantret - newSize := regv + n - // this section is inlined by go-inline - // source function is 'func (rg *registry) checkSize(requiredSize int) ' in '_state.go' - { - requiredSize := newSize - if requiredSize > cap(rg.array) { - rg.resize(requiredSize) +} + } else if str, ok1 := unaryv.(LString); ok1 { + if num, err := parseNumber(string(str)); err == nil { +// this section is inlined by go-inline +// source function is 'func (rg *registry) Set(regi int, vali LValue) ' in '_state.go' +{ +rg := reg +regi := RA +vali := -num + newSize := regi + 1 +// this section is inlined by go-inline +// source function is 'func (rg *registry) checkSize(requiredSize int) ' in '_state.go' +{ +requiredSize := newSize + if requiredSize > cap(rg.array) { + rg.resize(requiredSize) + } +} + rg.array[regi] = vali + if regi >= rg.top { + rg.top = regi + 1 + } +} + } else { + L.RaiseError("__unm undefined") + } + } else { + L.RaiseError("__unm undefined") } } - if limit == -1 || limit > rg.top { - limit = rg.top + case OP_NOT: + A := int(inst>>18) & 0xff //GETA + RA := lbase + A + B := int(inst & 0x1ff) //GETB + if LVIsFalse(reg.Get(lbase + B)) { +// this section is inlined by go-inline +// source function is 'func (rg *registry) Set(regi int, vali LValue) ' in '_state.go' +{ +rg := reg +regi := RA +vali := LTrue + newSize := regi + 1 +// this section is inlined by go-inline +// source function is 'func (rg *registry) checkSize(requiredSize int) ' in '_state.go' +{ +requiredSize := newSize + if requiredSize > cap(rg.array) { + rg.resize(requiredSize) + } +} + rg.array[regi] = vali + if regi >= rg.top { + rg.top = regi + 1 + } +} + } else { +// this section is inlined by go-inline +// source function is 'func (rg *registry) Set(regi int, vali LValue) ' in '_state.go' +{ +rg := reg +regi := RA +vali := LFalse + newSize := regi + 1 +// this section is inlined by go-inline +// source function is 'func (rg *registry) checkSize(requiredSize int) ' in '_state.go' +{ +requiredSize := newSize + if requiredSize > cap(rg.array) { + rg.resize(requiredSize) + } +} + rg.array[regi] = vali + if regi >= rg.top { + rg.top = regi + 1 + } +} } - for i := 0; i < n; i++ { - srcIdx := start + i - if srcIdx >= limit || srcIdx < 0 { - rg.array[regv+i] = LNil + case OP_LEN: + A := int(inst>>18) & 0xff //GETA + RA := lbase + A + B := int(inst & 0x1ff) //GETB + switch lv := L.rkValue(B).(type) { + case LString: +// this section is inlined by go-inline +// source function is 'func (rg *registry) SetNumber(regi int, vali LNumber) ' in '_state.go' +{ +rg := reg +regi := RA +vali := LNumber(len(lv)) + newSize := regi + 1 +// this section is inlined by go-inline +// source function is 'func (rg *registry) checkSize(requiredSize int) ' in '_state.go' +{ +requiredSize := newSize + if requiredSize > cap(rg.array) { + rg.resize(requiredSize) + } +} + rg.array[regi] = rg.alloc.LNumber2I(vali) + if regi >= rg.top { + rg.top = regi + 1 + } +} + default: + op := L.metaOp1(lv, "__len") + if op.Type() == LTFunction { + reg.Push(op) + reg.Push(lv) + L.Call(1, 1) + ret := reg.Pop() + if ret.Type() == LTNumber { + v, _ := ret.(LNumber) +// this section is inlined by go-inline +// source function is 'func (rg *registry) SetNumber(regi int, vali LNumber) ' in '_state.go' +{ +rg := reg +regi := RA +vali := v + newSize := regi + 1 +// this section is inlined by go-inline +// source function is 'func (rg *registry) checkSize(requiredSize int) ' in '_state.go' +{ +requiredSize := newSize + if requiredSize > cap(rg.array) { + rg.resize(requiredSize) + } +} + rg.array[regi] = rg.alloc.LNumber2I(vali) + if regi >= rg.top { + rg.top = regi + 1 + } +} + } else { +// this section is inlined by go-inline +// source function is 'func (rg *registry) Set(regi int, vali LValue) ' in '_state.go' +{ +rg := reg +regi := RA +vali := ret + newSize := regi + 1 +// this section is inlined by go-inline +// source function is 'func (rg *registry) checkSize(requiredSize int) ' in '_state.go' +{ +requiredSize := newSize + if requiredSize > cap(rg.array) { + rg.resize(requiredSize) + } +} + rg.array[regi] = vali + if regi >= rg.top { + rg.top = regi + 1 + } +} + } + } else if lv.Type() == LTTable { +// this section is inlined by go-inline +// source function is 'func (rg *registry) SetNumber(regi int, vali LNumber) ' in '_state.go' +{ +rg := reg +regi := RA +vali := LNumber(lv.(*LTable).Len()) + newSize := regi + 1 +// this section is inlined by go-inline +// source function is 'func (rg *registry) checkSize(requiredSize int) ' in '_state.go' +{ +requiredSize := newSize + if requiredSize > cap(rg.array) { + rg.resize(requiredSize) + } +} + rg.array[regi] = rg.alloc.LNumber2I(vali) + if regi >= rg.top { + rg.top = regi + 1 + } +} } else { - rg.array[regv+i] = rg.array[srcIdx] - } - } - - // values beyond top don't need to be valid LValues, so setting them to nil is fine - // setting them to nil rather than LNil lets us invoke the golang memclr opto - oldtop := rg.top - rg.top = regv + n - if rg.top < oldtop { - nilRange := rg.array[rg.top:oldtop] - for i := range nilRange { - nilRange[i] = nil + L.RaiseError("__len undefined") } } + case OP_CONCAT: + A := int(inst>>18) & 0xff //GETA + RA := lbase + A + B := int(inst & 0x1ff) //GETB + C := int(inst>>9) & 0x1ff //GETC + RC := lbase + C + RB := lbase + B + v := stringConcat(L, RC-RB+1, RC) +// this section is inlined by go-inline +// source function is 'func (rg *registry) Set(regi int, vali LValue) ' in '_state.go' +{ +rg := reg +regi := RA +vali := v + newSize := regi + 1 +// this section is inlined by go-inline +// source function is 'func (rg *registry) checkSize(requiredSize int) ' in '_state.go' +{ +requiredSize := newSize + if requiredSize > cap(rg.array) { + rg.resize(requiredSize) } - L.stack.Pop() - L.currentFrame = L.stack.Last() - return false } - -func threadRun(L *LState) { - if L.stack.IsEmpty() { - return + rg.array[regi] = vali + if regi >= rg.top { + rg.top = regi + 1 } +} + case OP_JMP: + cf := L.currentFrame + Sbx := int(inst&0x3ffff) - opMaxArgSbx //GETSBX + cf.Pc += Sbx + case OP_EQ: + cf := L.currentFrame + A := int(inst>>18) & 0xff //GETA + B := int(inst & 0x1ff) //GETB + C := int(inst>>9) & 0x1ff //GETC + ret := equals(L, L.rkValue(B), L.rkValue(C), false) + v := 1 + if ret { + v = 0 + } + if v == A { + cf.Pc++ + } + case OP_LT: + A := int(inst>>18) & 0xff //GETA + B := int(inst & 0x1ff) //GETB + C := int(inst>>9) & 0x1ff //GETC + ret := lessThan(L, L.rkValue(B), L.rkValue(C)) + v := 1 + if ret { + v = 0 + } + if v == A { + cf.Pc++ + } + case OP_LE: + A := int(inst>>18) & 0xff //GETA + B := int(inst & 0x1ff) //GETB + C := int(inst>>9) & 0x1ff //GETC + lhs := L.rkValue(B) + rhs := L.rkValue(C) + ret := false - defer func() { - if rcv := recover(); rcv != nil { - var lv LValue - if v, ok := rcv.(*ApiError); ok { - lv = v.Object + if v1, ok1 := lhs.(LNumber); ok1 { + if v2, ok2 := rhs.(LNumber); ok2 { + ret = v1 <= v2 } else { - lv = LString(fmt.Sprint(rcv)) + L.RaiseError("attempt to compare %v with %v", lhs.Type().String(), rhs.Type().String()) } - if parent := L.Parent; parent != nil { - if L.wrapped { - L.Push(lv) - parent.Panic(L) - } else { - L.SetTop(0) - L.Push(lv) - switchToParentThread(L, 1, true, true) + } else { + if lhs.Type() != rhs.Type() { + L.RaiseError("attempt to compare %v with %v", lhs.Type().String(), rhs.Type().String()) + } + switch lhs.Type() { + case LTString: + ret = strCmp(string(lhs.(LString)), string(rhs.(LString))) <= 0 + default: + switch objectRational(L, lhs, rhs, "__le") { + case 1: + ret = true + case 0: + ret = false + default: + ret = !objectRationalWithError(L, rhs, lhs, "__lt") } - } else { - panic(rcv) } } - }() - L.mainLoop(L, nil) -} - -type instFunc func(*LState, uint32, *callFrame) int -var jumpTable [opCodeMax + 1]instFunc - -func init() { - jumpTable = [opCodeMax + 1]instFunc{ - func(L *LState, inst uint32, baseframe *callFrame) int { //OP_MOVE - reg := L.reg - cf := L.currentFrame - lbase := cf.LocalBase - A := int(inst>>18) & 0xff //GETA - RA := lbase + A - B := int(inst & 0x1ff) //GETB - v := reg.Get(lbase + B) - // this section is inlined by go-inline - // source function is 'func (rg *registry) Set(regi int, vali LValue) ' in '_state.go' - { - rg := reg - regi := RA - vali := v - newSize := regi + 1 - // this section is inlined by go-inline - // source function is 'func (rg *registry) checkSize(requiredSize int) ' in '_state.go' - { - requiredSize := newSize - if requiredSize > cap(rg.array) { - rg.resize(requiredSize) - } - } - rg.array[regi] = vali - if regi >= rg.top { - rg.top = regi + 1 - } + v := 1 + if ret { + v = 0 + } + if v == A { + cf.Pc++ + } + case OP_TEST: + A := int(inst>>18) & 0xff //GETA + RA := lbase + A + C := int(inst>>9) & 0x1ff //GETC + if LVAsBool(reg.Get(RA)) == (C == 0) { + cf.Pc++ + } + case OP_TESTSET: + A := int(inst>>18) & 0xff //GETA + RA := lbase + A + B := int(inst & 0x1ff) //GETB + C := int(inst>>9) & 0x1ff //GETC + if value := reg.Get(lbase + B); LVAsBool(value) != (C == 0) { +// this section is inlined by go-inline +// source function is 'func (rg *registry) Set(regi int, vali LValue) ' in '_state.go' +{ +rg := reg +regi := RA +vali := value + newSize := regi + 1 +// this section is inlined by go-inline +// source function is 'func (rg *registry) checkSize(requiredSize int) ' in '_state.go' +{ +requiredSize := newSize + if requiredSize > cap(rg.array) { + rg.resize(requiredSize) + } +} + rg.array[regi] = vali + if regi >= rg.top { + rg.top = regi + 1 + } +} + } else { + cf.Pc++ + } + case OP_CALL: + A := int(inst>>18) & 0xff //GETA + RA := lbase + A + B := int(inst & 0x1ff) //GETB + C := int(inst>>9) & 0x1ff //GETC + nargs := B - 1 + if B == 0 { + nargs = reg.Top() - (RA + 1) + } + lv := reg.Get(RA) + nret := C - 1 + var callable *LFunction + var meta bool + if fn, ok := lv.(*LFunction); ok { + callable = fn + meta = false + } else { + callable, meta = L.metaCall(lv) + } +// this section is inlined by go-inline +// source function is 'func (ls *LState) pushCallFrame(cf callFrame, fn LValue, meta bool) ' in '_state.go' +{ +ls := L +cf := callFrame{Fn:callable,Pc:0,Base:RA,LocalBase:RA+1,ReturnBase:RA,NArgs:nargs,NRet:nret,Parent:cf,TailCall:0} +fn := lv + if meta { + cf.NArgs++ + ls.reg.Insert(fn, cf.LocalBase) + } + if cf.Fn == nil { + ls.RaiseError("attempt to call a non-function object") + } + if ls.stack.IsFull() { + ls.RaiseError("stack overflow") + } + ls.stack.Push(cf) + newcf := ls.stack.Last() +// this section is inlined by go-inline +// source function is 'func (ls *LState) initCallFrame(cf *callFrame) ' in '_state.go' +{ +cf := newcf + if cf.Fn.IsG { + ls.reg.SetTop(cf.LocalBase + cf.NArgs) + } else { + proto := cf.Fn.Proto + nargs := cf.NArgs + np := int(proto.NumParameters) + if nargs < np { + // default any missing arguments to nil + newSize := cf.LocalBase + np +// this section is inlined by go-inline +// source function is 'func (rg *registry) checkSize(requiredSize int) ' in '_state.go' +{ +rg := ls.reg +requiredSize := newSize + if requiredSize > cap(rg.array) { + rg.resize(requiredSize) + } +} + for i := nargs; i < np; i++ { + ls.reg.array[cf.LocalBase+i] = LNil } - return 0 - }, - func(L *LState, inst uint32, baseframe *callFrame) int { //OP_MOVEN - reg := L.reg - cf := L.currentFrame - lbase := cf.LocalBase - A := int(inst>>18) & 0xff //GETA - B := int(inst & 0x1ff) //GETB - C := int(inst>>9) & 0x1ff //GETC - v := reg.Get(lbase + B) - // this section is inlined by go-inline - // source function is 'func (rg *registry) Set(regi int, vali LValue) ' in '_state.go' - { - rg := reg - regi := lbase + A - vali := v - newSize := regi + 1 - // this section is inlined by go-inline - // source function is 'func (rg *registry) checkSize(requiredSize int) ' in '_state.go' - { - requiredSize := newSize - if requiredSize > cap(rg.array) { - rg.resize(requiredSize) - } - } - rg.array[regi] = vali - if regi >= rg.top { - rg.top = regi + 1 - } + nargs = np + ls.reg.top = newSize + } + + if (proto.IsVarArg & VarArgIsVarArg) == 0 { + if nargs < int(proto.NumUsedRegisters) { + nargs = int(proto.NumUsedRegisters) + } + newSize := cf.LocalBase + nargs +// this section is inlined by go-inline +// source function is 'func (rg *registry) checkSize(requiredSize int) ' in '_state.go' +{ +rg := ls.reg +requiredSize := newSize + if requiredSize > cap(rg.array) { + rg.resize(requiredSize) + } +} + for i := np; i < nargs; i++ { + ls.reg.array[cf.LocalBase+i] = LNil } - code := cf.Fn.Proto.Code - pc := cf.Pc - for i := 0; i < C; i++ { - inst = code[pc] - pc++ - A = int(inst>>18) & 0xff //GETA - B = int(inst & 0x1ff) //GETB - v := reg.Get(lbase + B) - // this section is inlined by go-inline - // source function is 'func (rg *registry) Set(regi int, vali LValue) ' in '_state.go' - { - rg := reg - regi := lbase + A - vali := v - newSize := regi + 1 - // this section is inlined by go-inline - // source function is 'func (rg *registry) checkSize(requiredSize int) ' in '_state.go' - { - requiredSize := newSize - if requiredSize > cap(rg.array) { - rg.resize(requiredSize) - } - } - rg.array[regi] = vali - if regi >= rg.top { - rg.top = regi + 1 - } - } + ls.reg.top = cf.LocalBase + int(proto.NumUsedRegisters) + } else { + /* swap vararg positions: + closure + namedparam1 <- lbase + namedparam2 + vararg1 + vararg2 + + TO + + closure + nil + nil + vararg1 + vararg2 + namedparam1 <- lbase + namedparam2 + */ + nvarargs := nargs - np + if nvarargs < 0 { + nvarargs = 0 } - cf.Pc = pc - return 0 - }, - func(L *LState, inst uint32, baseframe *callFrame) int { //OP_LOADK - reg := L.reg - cf := L.currentFrame - lbase := cf.LocalBase - A := int(inst>>18) & 0xff //GETA - RA := lbase + A - Bx := int(inst & 0x3ffff) //GETBX - v := cf.Fn.Proto.Constants[Bx] - // this section is inlined by go-inline - // source function is 'func (rg *registry) Set(regi int, vali LValue) ' in '_state.go' - { - rg := reg - regi := RA - vali := v - newSize := regi + 1 - // this section is inlined by go-inline - // source function is 'func (rg *registry) checkSize(requiredSize int) ' in '_state.go' - { - requiredSize := newSize - if requiredSize > cap(rg.array) { - rg.resize(requiredSize) - } - } - rg.array[regi] = vali - if regi >= rg.top { - rg.top = regi + 1 - } + + ls.reg.SetTop(cf.LocalBase + nargs + np) + for i := 0; i < np; i++ { + //ls.reg.Set(cf.LocalBase+nargs+i, ls.reg.Get(cf.LocalBase+i)) + ls.reg.array[cf.LocalBase+nargs+i] = ls.reg.array[cf.LocalBase+i] + //ls.reg.Set(cf.LocalBase+i, LNil) + ls.reg.array[cf.LocalBase+i] = LNil } - return 0 - }, - func(L *LState, inst uint32, baseframe *callFrame) int { //OP_LOADBOOL - reg := L.reg - cf := L.currentFrame - lbase := cf.LocalBase - A := int(inst>>18) & 0xff //GETA - RA := lbase + A - B := int(inst & 0x1ff) //GETB - C := int(inst>>9) & 0x1ff //GETC - if B != 0 { - // this section is inlined by go-inline - // source function is 'func (rg *registry) Set(regi int, vali LValue) ' in '_state.go' - { - rg := reg - regi := RA - vali := LTrue - newSize := regi + 1 - // this section is inlined by go-inline - // source function is 'func (rg *registry) checkSize(requiredSize int) ' in '_state.go' - { - requiredSize := newSize - if requiredSize > cap(rg.array) { - rg.resize(requiredSize) - } - } - rg.array[regi] = vali - if regi >= rg.top { - rg.top = regi + 1 - } - } - } else { - // this section is inlined by go-inline - // source function is 'func (rg *registry) Set(regi int, vali LValue) ' in '_state.go' - { - rg := reg - regi := RA - vali := LFalse - newSize := regi + 1 - // this section is inlined by go-inline - // source function is 'func (rg *registry) checkSize(requiredSize int) ' in '_state.go' - { - requiredSize := newSize - if requiredSize > cap(rg.array) { - rg.resize(requiredSize) - } - } - rg.array[regi] = vali - if regi >= rg.top { - rg.top = regi + 1 + + if CompatVarArg { + ls.reg.SetTop(cf.LocalBase + nargs + np + 1) + if (proto.IsVarArg & VarArgNeedsArg) != 0 { + argtb := newLTable(nvarargs, 0) + for i := 0; i < nvarargs; i++ { + argtb.RawSetInt(i+1, ls.reg.Get(cf.LocalBase+np+i)) } + argtb.RawSetString("n", LNumber(nvarargs)) + //ls.reg.Set(cf.LocalBase+nargs+np, argtb) + ls.reg.array[cf.LocalBase+nargs+np] = argtb + } else { + ls.reg.array[cf.LocalBase+nargs+np] = LNil } } - if C != 0 { - cf.Pc++ - } - return 0 - }, - func(L *LState, inst uint32, baseframe *callFrame) int { //OP_LOADNIL - reg := L.reg - cf := L.currentFrame - lbase := cf.LocalBase - A := int(inst>>18) & 0xff //GETA - RA := lbase + A - B := int(inst & 0x1ff) //GETB - for i := RA; i <= lbase+B; i++ { - // this section is inlined by go-inline - // source function is 'func (rg *registry) Set(regi int, vali LValue) ' in '_state.go' - { - rg := reg - regi := i - vali := LNil - newSize := regi + 1 - // this section is inlined by go-inline - // source function is 'func (rg *registry) checkSize(requiredSize int) ' in '_state.go' - { - requiredSize := newSize - if requiredSize > cap(rg.array) { - rg.resize(requiredSize) - } - } - rg.array[regi] = vali - if regi >= rg.top { - rg.top = regi + 1 - } + cf.LocalBase += nargs + maxreg := cf.LocalBase + int(proto.NumUsedRegisters) + ls.reg.SetTop(maxreg) + } + } +} + ls.currentFrame = newcf +} + if callable.IsG && callGFunction(L, false) { + return true + } + case OP_TAILCALL: + reg := L.reg + cf := L.currentFrame + lbase := cf.LocalBase + A := int(inst>>18) & 0xff //GETA + RA := lbase + A + B := int(inst & 0x1ff) //GETB + nargs := B - 1 + if B == 0 { + nargs = reg.Top() - (RA + 1) + } + lv := reg.Get(RA) + var callable *LFunction + var meta bool + if fn, ok := lv.(*LFunction); ok { + callable = fn + meta = false + } else { + callable, meta = L.metaCall(lv) + } + if callable == nil { + L.RaiseError("attempt to call a non-function object") + } +// this section is inlined by go-inline +// source function is 'func (ls *LState) closeUpvalues(idx int) ' in '_state.go' +{ +ls := L +idx := lbase + if ls.uvcache != nil { + var prev *Upvalue + for uv := ls.uvcache; uv != nil; uv = uv.next { + if uv.index >= idx { + if prev != nil { + prev.next = nil + } else { + ls.uvcache = nil } + uv.Close() } - return 0 - }, - func(L *LState, inst uint32, baseframe *callFrame) int { //OP_GETUPVAL - reg := L.reg - cf := L.currentFrame - lbase := cf.LocalBase - A := int(inst>>18) & 0xff //GETA - RA := lbase + A - B := int(inst & 0x1ff) //GETB - v := cf.Fn.Upvalues[B].Value() - // this section is inlined by go-inline - // source function is 'func (rg *registry) Set(regi int, vali LValue) ' in '_state.go' - { - rg := reg - regi := RA - vali := v - newSize := regi + 1 - // this section is inlined by go-inline - // source function is 'func (rg *registry) checkSize(requiredSize int) ' in '_state.go' - { - requiredSize := newSize - if requiredSize > cap(rg.array) { - rg.resize(requiredSize) - } - } - rg.array[regi] = vali - if regi >= rg.top { - rg.top = regi + 1 - } + prev = uv + } + } +} + if callable.IsG { + luaframe := cf + L.pushCallFrame(callFrame{ + Fn: callable, + Pc: 0, + Base: RA, + LocalBase: RA + 1, + ReturnBase: cf.ReturnBase, + NArgs: nargs, + NRet: cf.NRet, + Parent: cf, + TailCall: 0, + }, lv, meta) + if callGFunction(L, true) { + return true + } + if L.currentFrame == nil || L.currentFrame.Fn.IsG || luaframe == baseframe { + return true } - return 0 - }, - func(L *LState, inst uint32, baseframe *callFrame) int { //OP_GETGLOBAL - reg := L.reg - cf := L.currentFrame + } else { + base := cf.Base + cf.Fn = callable + cf.Pc = 0 + cf.Base = RA + cf.LocalBase = RA + 1 + cf.ReturnBase = cf.ReturnBase + cf.NArgs = nargs + cf.NRet = cf.NRet + cf.TailCall++ lbase := cf.LocalBase - A := int(inst>>18) & 0xff //GETA - RA := lbase + A - Bx := int(inst & 0x3ffff) //GETBX - //reg.Set(RA, L.getField(cf.Fn.Env, cf.Fn.Proto.Constants[Bx])) - v := L.getFieldString(cf.Fn.Env, cf.Fn.Proto.stringConstants[Bx]) - // this section is inlined by go-inline - // source function is 'func (rg *registry) Set(regi int, vali LValue) ' in '_state.go' - { - rg := reg - regi := RA - vali := v - newSize := regi + 1 - // this section is inlined by go-inline - // source function is 'func (rg *registry) checkSize(requiredSize int) ' in '_state.go' - { - requiredSize := newSize - if requiredSize > cap(rg.array) { - rg.resize(requiredSize) - } - } - rg.array[regi] = vali - if regi >= rg.top { - rg.top = regi + 1 - } + if meta { + cf.NArgs++ + L.reg.Insert(lv, cf.LocalBase) + } +// this section is inlined by go-inline +// source function is 'func (ls *LState) initCallFrame(cf *callFrame) ' in '_state.go' +{ +ls := L + if cf.Fn.IsG { + ls.reg.SetTop(cf.LocalBase + cf.NArgs) + } else { + proto := cf.Fn.Proto + nargs := cf.NArgs + np := int(proto.NumParameters) + if nargs < np { + // default any missing arguments to nil + newSize := cf.LocalBase + np +// this section is inlined by go-inline +// source function is 'func (rg *registry) checkSize(requiredSize int) ' in '_state.go' +{ +rg := ls.reg +requiredSize := newSize + if requiredSize > cap(rg.array) { + rg.resize(requiredSize) + } +} + for i := nargs; i < np; i++ { + ls.reg.array[cf.LocalBase+i] = LNil } - return 0 - }, - func(L *LState, inst uint32, baseframe *callFrame) int { //OP_GETTABLE - reg := L.reg - cf := L.currentFrame - lbase := cf.LocalBase - A := int(inst>>18) & 0xff //GETA - RA := lbase + A - B := int(inst & 0x1ff) //GETB - C := int(inst>>9) & 0x1ff //GETC - v := L.getField(reg.Get(lbase+B), L.rkValue(C)) - // this section is inlined by go-inline - // source function is 'func (rg *registry) Set(regi int, vali LValue) ' in '_state.go' - { - rg := reg - regi := RA - vali := v - newSize := regi + 1 - // this section is inlined by go-inline - // source function is 'func (rg *registry) checkSize(requiredSize int) ' in '_state.go' - { - requiredSize := newSize - if requiredSize > cap(rg.array) { - rg.resize(requiredSize) - } - } - rg.array[regi] = vali - if regi >= rg.top { - rg.top = regi + 1 - } + nargs = np + ls.reg.top = newSize + } + + if (proto.IsVarArg & VarArgIsVarArg) == 0 { + if nargs < int(proto.NumUsedRegisters) { + nargs = int(proto.NumUsedRegisters) + } + newSize := cf.LocalBase + nargs +// this section is inlined by go-inline +// source function is 'func (rg *registry) checkSize(requiredSize int) ' in '_state.go' +{ +rg := ls.reg +requiredSize := newSize + if requiredSize > cap(rg.array) { + rg.resize(requiredSize) + } +} + for i := np; i < nargs; i++ { + ls.reg.array[cf.LocalBase+i] = LNil } - return 0 - }, - func(L *LState, inst uint32, baseframe *callFrame) int { //OP_GETTABLEKS - reg := L.reg - cf := L.currentFrame - lbase := cf.LocalBase - A := int(inst>>18) & 0xff //GETA - RA := lbase + A - B := int(inst & 0x1ff) //GETB - C := int(inst>>9) & 0x1ff //GETC - v := L.getFieldString(reg.Get(lbase+B), L.rkString(C)) - // this section is inlined by go-inline - // source function is 'func (rg *registry) Set(regi int, vali LValue) ' in '_state.go' - { - rg := reg - regi := RA - vali := v - newSize := regi + 1 - // this section is inlined by go-inline - // source function is 'func (rg *registry) checkSize(requiredSize int) ' in '_state.go' - { - requiredSize := newSize - if requiredSize > cap(rg.array) { - rg.resize(requiredSize) - } - } - rg.array[regi] = vali - if regi >= rg.top { - rg.top = regi + 1 - } + ls.reg.top = cf.LocalBase + int(proto.NumUsedRegisters) + } else { + /* swap vararg positions: + closure + namedparam1 <- lbase + namedparam2 + vararg1 + vararg2 + + TO + + closure + nil + nil + vararg1 + vararg2 + namedparam1 <- lbase + namedparam2 + */ + nvarargs := nargs - np + if nvarargs < 0 { + nvarargs = 0 } - return 0 - }, - func(L *LState, inst uint32, baseframe *callFrame) int { //OP_SETGLOBAL - reg := L.reg - cf := L.currentFrame - lbase := cf.LocalBase - A := int(inst>>18) & 0xff //GETA - RA := lbase + A - Bx := int(inst & 0x3ffff) //GETBX - //L.setField(cf.Fn.Env, cf.Fn.Proto.Constants[Bx], reg.Get(RA)) - L.setFieldString(cf.Fn.Env, cf.Fn.Proto.stringConstants[Bx], reg.Get(RA)) - return 0 - }, - func(L *LState, inst uint32, baseframe *callFrame) int { //OP_SETUPVAL - reg := L.reg - cf := L.currentFrame - lbase := cf.LocalBase - A := int(inst>>18) & 0xff //GETA - RA := lbase + A - B := int(inst & 0x1ff) //GETB - cf.Fn.Upvalues[B].SetValue(reg.Get(RA)) - return 0 - }, - func(L *LState, inst uint32, baseframe *callFrame) int { //OP_SETTABLE - reg := L.reg - cf := L.currentFrame - lbase := cf.LocalBase - A := int(inst>>18) & 0xff //GETA - RA := lbase + A - B := int(inst & 0x1ff) //GETB - C := int(inst>>9) & 0x1ff //GETC - L.setField(reg.Get(RA), L.rkValue(B), L.rkValue(C)) - return 0 - }, - func(L *LState, inst uint32, baseframe *callFrame) int { //OP_SETTABLEKS - reg := L.reg - cf := L.currentFrame - lbase := cf.LocalBase - A := int(inst>>18) & 0xff //GETA - RA := lbase + A - B := int(inst & 0x1ff) //GETB - C := int(inst>>9) & 0x1ff //GETC - L.setFieldString(reg.Get(RA), L.rkString(B), L.rkValue(C)) - return 0 - }, - func(L *LState, inst uint32, baseframe *callFrame) int { //OP_NEWTABLE - reg := L.reg - cf := L.currentFrame - lbase := cf.LocalBase - A := int(inst>>18) & 0xff //GETA - RA := lbase + A - B := int(inst & 0x1ff) //GETB - C := int(inst>>9) & 0x1ff //GETC - v := newLTable(B, C) - // this section is inlined by go-inline - // source function is 'func (rg *registry) Set(regi int, vali LValue) ' in '_state.go' - { - rg := reg - regi := RA - vali := v - newSize := regi + 1 - // this section is inlined by go-inline - // source function is 'func (rg *registry) checkSize(requiredSize int) ' in '_state.go' - { - requiredSize := newSize - if requiredSize > cap(rg.array) { - rg.resize(requiredSize) - } - } - rg.array[regi] = vali - if regi >= rg.top { - rg.top = regi + 1 - } + + ls.reg.SetTop(cf.LocalBase + nargs + np) + for i := 0; i < np; i++ { + //ls.reg.Set(cf.LocalBase+nargs+i, ls.reg.Get(cf.LocalBase+i)) + ls.reg.array[cf.LocalBase+nargs+i] = ls.reg.array[cf.LocalBase+i] + //ls.reg.Set(cf.LocalBase+i, LNil) + ls.reg.array[cf.LocalBase+i] = LNil } - return 0 - }, - func(L *LState, inst uint32, baseframe *callFrame) int { //OP_SELF - reg := L.reg - cf := L.currentFrame - lbase := cf.LocalBase - A := int(inst>>18) & 0xff //GETA - RA := lbase + A - B := int(inst & 0x1ff) //GETB - C := int(inst>>9) & 0x1ff //GETC - selfobj := reg.Get(lbase + B) - v := L.getFieldString(selfobj, L.rkString(C)) - // this section is inlined by go-inline - // source function is 'func (rg *registry) Set(regi int, vali LValue) ' in '_state.go' - { - rg := reg - regi := RA - vali := v - newSize := regi + 1 - // this section is inlined by go-inline - // source function is 'func (rg *registry) checkSize(requiredSize int) ' in '_state.go' - { - requiredSize := newSize - if requiredSize > cap(rg.array) { - rg.resize(requiredSize) + + if CompatVarArg { + ls.reg.SetTop(cf.LocalBase + nargs + np + 1) + if (proto.IsVarArg & VarArgNeedsArg) != 0 { + argtb := newLTable(nvarargs, 0) + for i := 0; i < nvarargs; i++ { + argtb.RawSetInt(i+1, ls.reg.Get(cf.LocalBase+np+i)) } - } - rg.array[regi] = vali - if regi >= rg.top { - rg.top = regi + 1 + argtb.RawSetString("n", LNumber(nvarargs)) + //ls.reg.Set(cf.LocalBase+nargs+np, argtb) + ls.reg.array[cf.LocalBase+nargs+np] = argtb + } else { + ls.reg.array[cf.LocalBase+nargs+np] = LNil } } - // this section is inlined by go-inline - // source function is 'func (rg *registry) Set(regi int, vali LValue) ' in '_state.go' - { - rg := reg - regi := RA + 1 - vali := selfobj - newSize := regi + 1 - // this section is inlined by go-inline - // source function is 'func (rg *registry) checkSize(requiredSize int) ' in '_state.go' - { - requiredSize := newSize - if requiredSize > cap(rg.array) { - rg.resize(requiredSize) - } - } - rg.array[regi] = vali - if regi >= rg.top { - rg.top = regi + 1 + cf.LocalBase += nargs + maxreg := cf.LocalBase + int(proto.NumUsedRegisters) + ls.reg.SetTop(maxreg) + } + } +} +// this section is inlined by go-inline +// source function is 'func (rg *registry) CopyRange(regv, start, limit, n int) ' in '_state.go' +{ +rg := L.reg +regv := base +start := RA +limit := -1 +n := reg.Top()-RA-1 + newSize := regv + n +// this section is inlined by go-inline +// source function is 'func (rg *registry) checkSize(requiredSize int) ' in '_state.go' +{ +requiredSize := newSize + if requiredSize > cap(rg.array) { + rg.resize(requiredSize) + } +} + if limit == -1 || limit > rg.top { + limit = rg.top + } + for i := 0; i < n; i++ { + srcIdx := start + i + if srcIdx >= limit || srcIdx < 0 { + rg.array[regv+i] = LNil + } else { + rg.array[regv+i] = rg.array[srcIdx] + } + } + + // values beyond top don't need to be valid LValues, so setting them to nil is fine + // setting them to nil rather than LNil lets us invoke the golang memclr opto + oldtop := rg.top + rg.top = regv + n + if rg.top < oldtop { + nilRange := rg.array[rg.top:oldtop] + for i := range nilRange { + nilRange[i] = nil + } + } +} + cf.Base = base + cf.LocalBase = base + (cf.LocalBase - lbase + 1) + } + case OP_RETURN: + A := int(inst>>18) & 0xff //GETA + RA := lbase + A + B := int(inst & 0x1ff) //GETB +// this section is inlined by go-inline +// source function is 'func (ls *LState) closeUpvalues(idx int) ' in '_state.go' +{ +ls := L +idx := lbase + if ls.uvcache != nil { + var prev *Upvalue + for uv := ls.uvcache; uv != nil; uv = uv.next { + if uv.index >= idx { + if prev != nil { + prev.next = nil + } else { + ls.uvcache = nil } + uv.Close() } - return 0 - }, - opArith, // OP_ADD - opArith, // OP_SUB - opArith, // OP_MUL - opArith, // OP_DIV - opArith, // OP_MOD - opArith, // OP_POW - func(L *LState, inst uint32, baseframe *callFrame) int { //OP_UNM - reg := L.reg - cf := L.currentFrame - lbase := cf.LocalBase - A := int(inst>>18) & 0xff //GETA - RA := lbase + A - B := int(inst & 0x1ff) //GETB - unaryv := L.rkValue(B) - if nm, ok := unaryv.(LNumber); ok { - // this section is inlined by go-inline - // source function is 'func (rg *registry) Set(regi int, vali LValue) ' in '_state.go' - { - rg := reg - regi := RA - vali := -nm - newSize := regi + 1 - // this section is inlined by go-inline - // source function is 'func (rg *registry) checkSize(requiredSize int) ' in '_state.go' - { - requiredSize := newSize - if requiredSize > cap(rg.array) { - rg.resize(requiredSize) - } - } - rg.array[regi] = vali - if regi >= rg.top { - rg.top = regi + 1 - } - } - } else { - op := L.metaOp1(unaryv, "__unm") - if op.Type() == LTFunction { - reg.Push(op) - reg.Push(unaryv) - L.Call(1, 1) - // this section is inlined by go-inline - // source function is 'func (rg *registry) Set(regi int, vali LValue) ' in '_state.go' - { - rg := reg - regi := RA - vali := reg.Pop() - newSize := regi + 1 - // this section is inlined by go-inline - // source function is 'func (rg *registry) checkSize(requiredSize int) ' in '_state.go' - { - requiredSize := newSize - if requiredSize > cap(rg.array) { - rg.resize(requiredSize) - } - } - rg.array[regi] = vali - if regi >= rg.top { - rg.top = regi + 1 - } - } - } else if str, ok1 := unaryv.(LString); ok1 { - if num, err := parseNumber(string(str)); err == nil { - // this section is inlined by go-inline - // source function is 'func (rg *registry) Set(regi int, vali LValue) ' in '_state.go' - { - rg := reg - regi := RA - vali := -num - newSize := regi + 1 - // this section is inlined by go-inline - // source function is 'func (rg *registry) checkSize(requiredSize int) ' in '_state.go' - { - requiredSize := newSize - if requiredSize > cap(rg.array) { - rg.resize(requiredSize) - } - } - rg.array[regi] = vali - if regi >= rg.top { - rg.top = regi + 1 - } - } + prev = uv + } + } +} + nret := B - 1 + if B == 0 { + nret = reg.Top() - RA + } + n := cf.NRet + if cf.NRet == MultRet { + n = nret + } + + if L.Parent != nil && L.stack.Sp() == 1 { +// this section is inlined by go-inline +// source function is 'func copyReturnValues(L *LState, regv, start, n, b int) ' in '_vm.go' +{ +regv := reg.Top() +start := RA +b := B + if b == 1 { +// this section is inlined by go-inline +// source function is 'func (rg *registry) FillNil(regm, n int) ' in '_state.go' +{ +rg := L.reg +regm := regv + newSize := regm + n +// this section is inlined by go-inline +// source function is 'func (rg *registry) checkSize(requiredSize int) ' in '_state.go' +{ +requiredSize := newSize + if requiredSize > cap(rg.array) { + rg.resize(requiredSize) + } +} + for i := 0; i < n; i++ { + rg.array[regm+i] = LNil + } + // values beyond top don't need to be valid LValues, so setting them to nil is fine + // setting them to nil rather than LNil lets us invoke the golang memclr opto + oldtop := rg.top + rg.top = regm + n + if rg.top < oldtop { + nilRange := rg.array[rg.top:oldtop] + for i := range nilRange { + nilRange[i] = nil + } + } +} + } else { +// this section is inlined by go-inline +// source function is 'func (rg *registry) CopyRange(regv, start, limit, n int) ' in '_state.go' +{ +rg := L.reg +limit := -1 + newSize := regv + n +// this section is inlined by go-inline +// source function is 'func (rg *registry) checkSize(requiredSize int) ' in '_state.go' +{ +requiredSize := newSize + if requiredSize > cap(rg.array) { + rg.resize(requiredSize) + } +} + if limit == -1 || limit > rg.top { + limit = rg.top + } + for i := 0; i < n; i++ { + srcIdx := start + i + if srcIdx >= limit || srcIdx < 0 { + rg.array[regv+i] = LNil + } else { + rg.array[regv+i] = rg.array[srcIdx] + } + } + + // values beyond top don't need to be valid LValues, so setting them to nil is fine + // setting them to nil rather than LNil lets us invoke the golang memclr opto + oldtop := rg.top + rg.top = regv + n + if rg.top < oldtop { + nilRange := rg.array[rg.top:oldtop] + for i := range nilRange { + nilRange[i] = nil + } + } +} + if b > 1 && n > (b-1) { +// this section is inlined by go-inline +// source function is 'func (rg *registry) FillNil(regm, n int) ' in '_state.go' +{ +rg := L.reg +regm := regv+b-1 +n := n-(b-1) + newSize := regm + n +// this section is inlined by go-inline +// source function is 'func (rg *registry) checkSize(requiredSize int) ' in '_state.go' +{ +requiredSize := newSize + if requiredSize > cap(rg.array) { + rg.resize(requiredSize) + } +} + for i := 0; i < n; i++ { + rg.array[regm+i] = LNil + } + // values beyond top don't need to be valid LValues, so setting them to nil is fine + // setting them to nil rather than LNil lets us invoke the golang memclr opto + oldtop := rg.top + rg.top = regm + n + if rg.top < oldtop { + nilRange := rg.array[rg.top:oldtop] + for i := range nilRange { + nilRange[i] = nil + } + } +} + } + } +} + switchToParentThread(L, n, false, true) + return true + } + islast := baseframe == L.stack.Pop() || L.stack.IsEmpty() +// this section is inlined by go-inline +// source function is 'func copyReturnValues(L *LState, regv, start, n, b int) ' in '_vm.go' +{ +regv := cf.ReturnBase +start := RA +b := B + if b == 1 { +// this section is inlined by go-inline +// source function is 'func (rg *registry) FillNil(regm, n int) ' in '_state.go' +{ +rg := L.reg +regm := regv + newSize := regm + n +// this section is inlined by go-inline +// source function is 'func (rg *registry) checkSize(requiredSize int) ' in '_state.go' +{ +requiredSize := newSize + if requiredSize > cap(rg.array) { + rg.resize(requiredSize) + } +} + for i := 0; i < n; i++ { + rg.array[regm+i] = LNil + } + // values beyond top don't need to be valid LValues, so setting them to nil is fine + // setting them to nil rather than LNil lets us invoke the golang memclr opto + oldtop := rg.top + rg.top = regm + n + if rg.top < oldtop { + nilRange := rg.array[rg.top:oldtop] + for i := range nilRange { + nilRange[i] = nil + } + } +} + } else { +// this section is inlined by go-inline +// source function is 'func (rg *registry) CopyRange(regv, start, limit, n int) ' in '_state.go' +{ +rg := L.reg +limit := -1 + newSize := regv + n +// this section is inlined by go-inline +// source function is 'func (rg *registry) checkSize(requiredSize int) ' in '_state.go' +{ +requiredSize := newSize + if requiredSize > cap(rg.array) { + rg.resize(requiredSize) + } +} + if limit == -1 || limit > rg.top { + limit = rg.top + } + for i := 0; i < n; i++ { + srcIdx := start + i + if srcIdx >= limit || srcIdx < 0 { + rg.array[regv+i] = LNil + } else { + rg.array[regv+i] = rg.array[srcIdx] + } + } + + // values beyond top don't need to be valid LValues, so setting them to nil is fine + // setting them to nil rather than LNil lets us invoke the golang memclr opto + oldtop := rg.top + rg.top = regv + n + if rg.top < oldtop { + nilRange := rg.array[rg.top:oldtop] + for i := range nilRange { + nilRange[i] = nil + } + } +} + if b > 1 && n > (b-1) { +// this section is inlined by go-inline +// source function is 'func (rg *registry) FillNil(regm, n int) ' in '_state.go' +{ +rg := L.reg +regm := regv+b-1 +n := n-(b-1) + newSize := regm + n +// this section is inlined by go-inline +// source function is 'func (rg *registry) checkSize(requiredSize int) ' in '_state.go' +{ +requiredSize := newSize + if requiredSize > cap(rg.array) { + rg.resize(requiredSize) + } +} + for i := 0; i < n; i++ { + rg.array[regm+i] = LNil + } + // values beyond top don't need to be valid LValues, so setting them to nil is fine + // setting them to nil rather than LNil lets us invoke the golang memclr opto + oldtop := rg.top + rg.top = regm + n + if rg.top < oldtop { + nilRange := rg.array[rg.top:oldtop] + for i := range nilRange { + nilRange[i] = nil + } + } +} + } + } +} + L.currentFrame = L.stack.Last() + if islast || L.currentFrame == nil || L.currentFrame.Fn.IsG { + return true + } + case OP_FORLOOP: + A := int(inst>>18) & 0xff //GETA + RA := lbase + A + if init, ok1 := reg.Get(RA).(LNumber); ok1 { + if limit, ok2 := reg.Get(RA + 1).(LNumber); ok2 { + if step, ok3 := reg.Get(RA + 2).(LNumber); ok3 { + init += step + v := LNumber(init) +// this section is inlined by go-inline +// source function is 'func (rg *registry) SetNumber(regi int, vali LNumber) ' in '_state.go' +{ +rg := reg +regi := RA +vali := v + newSize := regi + 1 +// this section is inlined by go-inline +// source function is 'func (rg *registry) checkSize(requiredSize int) ' in '_state.go' +{ +requiredSize := newSize + if requiredSize > cap(rg.array) { + rg.resize(requiredSize) + } +} + rg.array[regi] = rg.alloc.LNumber2I(vali) + if regi >= rg.top { + rg.top = regi + 1 + } +} + if (step > 0 && init <= limit) || (step <= 0 && init >= limit) { + Sbx := int(inst&0x3ffff) - opMaxArgSbx //GETSBX + cf.Pc += Sbx +// this section is inlined by go-inline +// source function is 'func (rg *registry) SetNumber(regi int, vali LNumber) ' in '_state.go' +{ +rg := reg +regi := RA+3 +vali := v + newSize := regi + 1 +// this section is inlined by go-inline +// source function is 'func (rg *registry) checkSize(requiredSize int) ' in '_state.go' +{ +requiredSize := newSize + if requiredSize > cap(rg.array) { + rg.resize(requiredSize) + } +} + rg.array[regi] = rg.alloc.LNumber2I(vali) + if regi >= rg.top { + rg.top = regi + 1 + } +} } else { - L.RaiseError("__unm undefined") +// this section is inlined by go-inline +// source function is 'func (rg *registry) SetTop(topi int) ' in '_state.go' +{ +rg := reg +topi := RA+1 +// this section is inlined by go-inline +// source function is 'func (rg *registry) checkSize(requiredSize int) ' in '_state.go' +{ +requiredSize := topi + if requiredSize > cap(rg.array) { + rg.resize(requiredSize) + } +} + oldtopi := rg.top + rg.top = topi + for i := oldtopi; i < rg.top; i++ { + rg.array[i] = LNil + } + // values beyond top don't need to be valid LValues, so setting them to nil is fine + // setting them to nil rather than LNil lets us invoke the golang memclr opto + if rg.top < oldtopi { + nilRange := rg.array[rg.top:oldtopi] + for i := range nilRange { + nilRange[i] = nil + } + } + //for i := rg.top; i < oldtop; i++ { + // rg.array[i] = LNil + //} +} } } else { - L.RaiseError("__unm undefined") + L.RaiseError("for statement step must be a number") } + } else { + L.RaiseError("for statement limit must be a number") } - return 0 - }, - func(L *LState, inst uint32, baseframe *callFrame) int { //OP_NOT - reg := L.reg - cf := L.currentFrame - lbase := cf.LocalBase - A := int(inst>>18) & 0xff //GETA - RA := lbase + A - B := int(inst & 0x1ff) //GETB - if LVIsFalse(reg.Get(lbase + B)) { - // this section is inlined by go-inline - // source function is 'func (rg *registry) Set(regi int, vali LValue) ' in '_state.go' - { - rg := reg - regi := RA - vali := LTrue - newSize := regi + 1 - // this section is inlined by go-inline - // source function is 'func (rg *registry) checkSize(requiredSize int) ' in '_state.go' - { - requiredSize := newSize - if requiredSize > cap(rg.array) { - rg.resize(requiredSize) - } - } - rg.array[regi] = vali - if regi >= rg.top { - rg.top = regi + 1 - } - } + } else { + L.RaiseError("for statement init must be a number") + } + case OP_FORPREP: + A := int(inst>>18) & 0xff //GETA + RA := lbase + A + Sbx := int(inst&0x3ffff) - opMaxArgSbx //GETSBX + if init, ok1 := reg.Get(RA).(LNumber); ok1 { + if step, ok2 := reg.Get(RA + 2).(LNumber); ok2 { +// this section is inlined by go-inline +// source function is 'func (rg *registry) SetNumber(regi int, vali LNumber) ' in '_state.go' +{ +rg := reg +regi := RA +vali := LNumber(init-step) + newSize := regi + 1 +// this section is inlined by go-inline +// source function is 'func (rg *registry) checkSize(requiredSize int) ' in '_state.go' +{ +requiredSize := newSize + if requiredSize > cap(rg.array) { + rg.resize(requiredSize) + } +} + rg.array[regi] = rg.alloc.LNumber2I(vali) + if regi >= rg.top { + rg.top = regi + 1 + } +} } else { - // this section is inlined by go-inline - // source function is 'func (rg *registry) Set(regi int, vali LValue) ' in '_state.go' - { - rg := reg - regi := RA - vali := LFalse - newSize := regi + 1 - // this section is inlined by go-inline - // source function is 'func (rg *registry) checkSize(requiredSize int) ' in '_state.go' - { - requiredSize := newSize - if requiredSize > cap(rg.array) { - rg.resize(requiredSize) - } - } - rg.array[regi] = vali - if regi >= rg.top { - rg.top = regi + 1 - } - } + L.RaiseError("for statement step must be a number") } - return 0 - }, - func(L *LState, inst uint32, baseframe *callFrame) int { //OP_LEN - reg := L.reg - cf := L.currentFrame - lbase := cf.LocalBase - A := int(inst>>18) & 0xff //GETA - RA := lbase + A - B := int(inst & 0x1ff) //GETB - switch lv := L.rkValue(B).(type) { - case LString: - // this section is inlined by go-inline - // source function is 'func (rg *registry) SetNumber(regi int, vali LNumber) ' in '_state.go' - { - rg := reg - regi := RA - vali := LNumber(len(lv)) - newSize := regi + 1 - // this section is inlined by go-inline - // source function is 'func (rg *registry) checkSize(requiredSize int) ' in '_state.go' - { - requiredSize := newSize - if requiredSize > cap(rg.array) { - rg.resize(requiredSize) - } - } - rg.array[regi] = rg.alloc.LNumber2I(vali) - if regi >= rg.top { - rg.top = regi + 1 - } - } - default: - op := L.metaOp1(lv, "__len") - if op.Type() == LTFunction { - reg.Push(op) - reg.Push(lv) - L.Call(1, 1) - ret := reg.Pop() - if ret.Type() == LTNumber { - v, _ := ret.(LNumber) - // this section is inlined by go-inline - // source function is 'func (rg *registry) SetNumber(regi int, vali LNumber) ' in '_state.go' - { - rg := reg - regi := RA - vali := v - newSize := regi + 1 - // this section is inlined by go-inline - // source function is 'func (rg *registry) checkSize(requiredSize int) ' in '_state.go' - { - requiredSize := newSize - if requiredSize > cap(rg.array) { - rg.resize(requiredSize) - } - } - rg.array[regi] = rg.alloc.LNumber2I(vali) - if regi >= rg.top { - rg.top = regi + 1 - } - } - } else { - // this section is inlined by go-inline - // source function is 'func (rg *registry) Set(regi int, vali LValue) ' in '_state.go' - { - rg := reg - regi := RA - vali := ret - newSize := regi + 1 - // this section is inlined by go-inline - // source function is 'func (rg *registry) checkSize(requiredSize int) ' in '_state.go' - { - requiredSize := newSize - if requiredSize > cap(rg.array) { - rg.resize(requiredSize) - } - } - rg.array[regi] = vali - if regi >= rg.top { - rg.top = regi + 1 - } - } - } - } else if lv.Type() == LTTable { - // this section is inlined by go-inline - // source function is 'func (rg *registry) SetNumber(regi int, vali LNumber) ' in '_state.go' - { - rg := reg - regi := RA - vali := LNumber(lv.(*LTable).Len()) - newSize := regi + 1 - // this section is inlined by go-inline - // source function is 'func (rg *registry) checkSize(requiredSize int) ' in '_state.go' - { - requiredSize := newSize - if requiredSize > cap(rg.array) { - rg.resize(requiredSize) - } - } - rg.array[regi] = rg.alloc.LNumber2I(vali) - if regi >= rg.top { - rg.top = regi + 1 - } - } + } else { + L.RaiseError("for statement init must be a number") + } + cf.Pc += Sbx + case OP_TFORLOOP: + A := int(inst>>18) & 0xff //GETA + RA := lbase + A + C := int(inst>>9) & 0x1ff //GETC + nret := C +// this section is inlined by go-inline +// source function is 'func (rg *registry) SetTop(topi int) ' in '_state.go' +{ +rg := reg +topi := RA+3+2 +// this section is inlined by go-inline +// source function is 'func (rg *registry) checkSize(requiredSize int) ' in '_state.go' +{ +requiredSize := topi + if requiredSize > cap(rg.array) { + rg.resize(requiredSize) + } +} + oldtopi := rg.top + rg.top = topi + for i := oldtopi; i < rg.top; i++ { + rg.array[i] = LNil + } + // values beyond top don't need to be valid LValues, so setting them to nil is fine + // setting them to nil rather than LNil lets us invoke the golang memclr opto + if rg.top < oldtopi { + nilRange := rg.array[rg.top:oldtopi] + for i := range nilRange { + nilRange[i] = nil + } + } + //for i := rg.top; i < oldtop; i++ { + // rg.array[i] = LNil + //} +} +// this section is inlined by go-inline +// source function is 'func (rg *registry) Set(regi int, vali LValue) ' in '_state.go' +{ +rg := reg +regi := RA+3+2 +vali := reg.Get(RA+2) + newSize := regi + 1 +// this section is inlined by go-inline +// source function is 'func (rg *registry) checkSize(requiredSize int) ' in '_state.go' +{ +requiredSize := newSize + if requiredSize > cap(rg.array) { + rg.resize(requiredSize) + } +} + rg.array[regi] = vali + if regi >= rg.top { + rg.top = regi + 1 + } +} +// this section is inlined by go-inline +// source function is 'func (rg *registry) Set(regi int, vali LValue) ' in '_state.go' +{ +rg := reg +regi := RA+3+1 +vali := reg.Get(RA+1) + newSize := regi + 1 +// this section is inlined by go-inline +// source function is 'func (rg *registry) checkSize(requiredSize int) ' in '_state.go' +{ +requiredSize := newSize + if requiredSize > cap(rg.array) { + rg.resize(requiredSize) + } +} + rg.array[regi] = vali + if regi >= rg.top { + rg.top = regi + 1 + } +} +// this section is inlined by go-inline +// source function is 'func (rg *registry) Set(regi int, vali LValue) ' in '_state.go' +{ +rg := reg +regi := RA+3 +vali := reg.Get(RA) + newSize := regi + 1 +// this section is inlined by go-inline +// source function is 'func (rg *registry) checkSize(requiredSize int) ' in '_state.go' +{ +requiredSize := newSize + if requiredSize > cap(rg.array) { + rg.resize(requiredSize) + } +} + rg.array[regi] = vali + if regi >= rg.top { + rg.top = regi + 1 + } +} + L.callR(2, nret, RA+3) + if value := reg.Get(RA + 3); value != LNil { +// this section is inlined by go-inline +// source function is 'func (rg *registry) Set(regi int, vali LValue) ' in '_state.go' +{ +rg := reg +regi := RA+2 +vali := value + newSize := regi + 1 +// this section is inlined by go-inline +// source function is 'func (rg *registry) checkSize(requiredSize int) ' in '_state.go' +{ +requiredSize := newSize + if requiredSize > cap(rg.array) { + rg.resize(requiredSize) + } +} + rg.array[regi] = vali + if regi >= rg.top { + rg.top = regi + 1 + } +} + pc := cf.Fn.Proto.Code[cf.Pc] + cf.Pc += int(pc&0x3ffff) - opMaxArgSbx + } + cf.Pc++ + case OP_SETLIST: + A := int(inst>>18) & 0xff //GETA + RA := lbase + A + B := int(inst & 0x1ff) //GETB + C := int(inst>>9) & 0x1ff //GETC + if C == 0 { + C = int(cf.Fn.Proto.Code[cf.Pc]) + cf.Pc++ + } + offset := (C - 1) * FieldsPerFlush + table := reg.Get(RA).(*LTable) + nelem := B + if B == 0 { + nelem = reg.Top() - RA - 1 + } + for i := 1; i <= nelem; i++ { + table.RawSetInt(offset+i, reg.Get(RA+i)) + } + case OP_CLOSE: + A := int(inst>>18) & 0xff //GETA + RA := lbase + A +// this section is inlined by go-inline +// source function is 'func (ls *LState) closeUpvalues(idx int) ' in '_state.go' +{ +ls := L +idx := RA + if ls.uvcache != nil { + var prev *Upvalue + for uv := ls.uvcache; uv != nil; uv = uv.next { + if uv.index >= idx { + if prev != nil { + prev.next = nil } else { - L.RaiseError("__len undefined") - } - } - return 0 - }, - func(L *LState, inst uint32, baseframe *callFrame) int { //OP_CONCAT - reg := L.reg - cf := L.currentFrame - lbase := cf.LocalBase - A := int(inst>>18) & 0xff //GETA - RA := lbase + A - B := int(inst & 0x1ff) //GETB - C := int(inst>>9) & 0x1ff //GETC - RC := lbase + C - RB := lbase + B - v := stringConcat(L, RC-RB+1, RC) - // this section is inlined by go-inline - // source function is 'func (rg *registry) Set(regi int, vali LValue) ' in '_state.go' - { - rg := reg - regi := RA - vali := v - newSize := regi + 1 - // this section is inlined by go-inline - // source function is 'func (rg *registry) checkSize(requiredSize int) ' in '_state.go' - { - requiredSize := newSize - if requiredSize > cap(rg.array) { - rg.resize(requiredSize) - } + ls.uvcache = nil } - rg.array[regi] = vali - if regi >= rg.top { - rg.top = regi + 1 - } - } - return 0 - }, - func(L *LState, inst uint32, baseframe *callFrame) int { //OP_JMP - cf := L.currentFrame - Sbx := int(inst&0x3ffff) - opMaxArgSbx //GETSBX - cf.Pc += Sbx - return 0 - }, - func(L *LState, inst uint32, baseframe *callFrame) int { //OP_EQ - cf := L.currentFrame - A := int(inst>>18) & 0xff //GETA - B := int(inst & 0x1ff) //GETB - C := int(inst>>9) & 0x1ff //GETC - ret := equals(L, L.rkValue(B), L.rkValue(C), false) - v := 1 - if ret { - v = 0 - } - if v == A { - cf.Pc++ + uv.Close() } - return 0 - }, - func(L *LState, inst uint32, baseframe *callFrame) int { //OP_LT - cf := L.currentFrame - A := int(inst>>18) & 0xff //GETA - B := int(inst & 0x1ff) //GETB - C := int(inst>>9) & 0x1ff //GETC - ret := lessThan(L, L.rkValue(B), L.rkValue(C)) - v := 1 - if ret { - v = 0 - } - if v == A { - cf.Pc++ + prev = uv + } + } +} + case OP_CLOSURE: + A := int(inst>>18) & 0xff //GETA + RA := lbase + A + Bx := int(inst & 0x3ffff) //GETBX + proto := cf.Fn.Proto.FunctionPrototypes[Bx] + closure := newLFunctionL(proto, cf.Fn.Env, int(proto.NumUpvalues)) +// this section is inlined by go-inline +// source function is 'func (rg *registry) Set(regi int, vali LValue) ' in '_state.go' +{ +rg := reg +regi := RA +vali := closure + newSize := regi + 1 +// this section is inlined by go-inline +// source function is 'func (rg *registry) checkSize(requiredSize int) ' in '_state.go' +{ +requiredSize := newSize + if requiredSize > cap(rg.array) { + rg.resize(requiredSize) + } +} + rg.array[regi] = vali + if regi >= rg.top { + rg.top = regi + 1 + } +} + for i := 0; i < int(proto.NumUpvalues); i++ { + inst = cf.Fn.Proto.Code[cf.Pc] + cf.Pc++ + B := opGetArgB(inst) + switch opGetOpCode(inst) { + case OP_MOVE: + closure.Upvalues[i] = L.findUpvalue(lbase + B) + case OP_GETUPVAL: + closure.Upvalues[i] = cf.Fn.Upvalues[B] } - return 0 - }, - func(L *LState, inst uint32, baseframe *callFrame) int { //OP_LE - cf := L.currentFrame - A := int(inst>>18) & 0xff //GETA - B := int(inst & 0x1ff) //GETB - C := int(inst>>9) & 0x1ff //GETC - lhs := L.rkValue(B) - rhs := L.rkValue(C) - ret := false + } + case OP_VARARG: + A := int(inst>>18) & 0xff //GETA + RA := lbase + A + B := int(inst & 0x1ff) //GETB + nparams := int(cf.Fn.Proto.NumParameters) + nvarargs := cf.NArgs - nparams + if nvarargs < 0 { + nvarargs = 0 + } + nwant := B - 1 + if B == 0 { + nwant = nvarargs + } +// this section is inlined by go-inline +// source function is 'func (rg *registry) CopyRange(regv, start, limit, n int) ' in '_state.go' +{ +rg := reg +regv := RA +start := cf.Base+nparams+1 +limit := cf.LocalBase +n := nwant + newSize := regv + n +// this section is inlined by go-inline +// source function is 'func (rg *registry) checkSize(requiredSize int) ' in '_state.go' +{ +requiredSize := newSize + if requiredSize > cap(rg.array) { + rg.resize(requiredSize) + } +} + if limit == -1 || limit > rg.top { + limit = rg.top + } + for i := 0; i < n; i++ { + srcIdx := start + i + if srcIdx >= limit || srcIdx < 0 { + rg.array[regv+i] = LNil + } else { + rg.array[regv+i] = rg.array[srcIdx] + } + } - if v1, ok1 := lhs.(LNumber); ok1 { - if v2, ok2 := rhs.(LNumber); ok2 { - ret = v1 <= v2 - } else { - L.RaiseError("attempt to compare %v with %v", lhs.Type().String(), rhs.Type().String()) - } - } else { - if lhs.Type() != rhs.Type() { - L.RaiseError("attempt to compare %v with %v", lhs.Type().String(), rhs.Type().String()) - } - switch lhs.Type() { - case LTString: - ret = strCmp(string(lhs.(LString)), string(rhs.(LString))) <= 0 - default: - switch objectRational(L, lhs, rhs, "__le") { - case 1: - ret = true - case 0: - ret = false - default: - ret = !objectRationalWithError(L, rhs, lhs, "__lt") - } - } - } + // values beyond top don't need to be valid LValues, so setting them to nil is fine + // setting them to nil rather than LNil lets us invoke the golang memclr opto + oldtop := rg.top + rg.top = regv + n + if rg.top < oldtop { + nilRange := rg.array[rg.top:oldtop] + for i := range nilRange { + nilRange[i] = nil + } + } +} + case OP_NOP: + } + return false +} - v := 1 - if ret { - v = 0 - } - if v == A { - cf.Pc++ - } - return 0 - }, - func(L *LState, inst uint32, baseframe *callFrame) int { //OP_TEST - reg := L.reg - cf := L.currentFrame - lbase := cf.LocalBase - A := int(inst>>18) & 0xff //GETA - RA := lbase + A - C := int(inst>>9) & 0x1ff //GETC - if LVAsBool(reg.Get(RA)) == (C == 0) { - cf.Pc++ - } - return 0 - }, - func(L *LState, inst uint32, baseframe *callFrame) int { //OP_TESTSET - reg := L.reg - cf := L.currentFrame - lbase := cf.LocalBase - A := int(inst>>18) & 0xff //GETA - RA := lbase + A - B := int(inst & 0x1ff) //GETB - C := int(inst>>9) & 0x1ff //GETC - if value := reg.Get(lbase + B); LVAsBool(value) != (C == 0) { - // this section is inlined by go-inline - // source function is 'func (rg *registry) Set(regi int, vali LValue) ' in '_state.go' - { - rg := reg - regi := RA - vali := value - newSize := regi + 1 - // this section is inlined by go-inline - // source function is 'func (rg *registry) checkSize(requiredSize int) ' in '_state.go' - { - requiredSize := newSize - if requiredSize > cap(rg.array) { - rg.resize(requiredSize) - } - } - rg.array[regi] = vali - if regi >= rg.top { - rg.top = regi + 1 - } - } - } else { - cf.Pc++ - } - return 0 - }, - func(L *LState, inst uint32, baseframe *callFrame) int { //OP_CALL - reg := L.reg - cf := L.currentFrame - lbase := cf.LocalBase - A := int(inst>>18) & 0xff //GETA - RA := lbase + A - B := int(inst & 0x1ff) //GETB - C := int(inst>>9) & 0x1ff //GETC - nargs := B - 1 - if B == 0 { - nargs = reg.Top() - (RA + 1) - } - lv := reg.Get(RA) - nret := C - 1 - var callable *LFunction - var meta bool - if fn, ok := lv.(*LFunction); ok { - callable = fn - meta = false - } else { - callable, meta = L.metaCall(lv) - } - // this section is inlined by go-inline - // source function is 'func (ls *LState) pushCallFrame(cf callFrame, fn LValue, meta bool) ' in '_state.go' - { - ls := L - cf := callFrame{Fn: callable, Pc: 0, Base: RA, LocalBase: RA + 1, ReturnBase: RA, NArgs: nargs, NRet: nret, Parent: cf, TailCall: 0} - fn := lv - if meta { - cf.NArgs++ - ls.reg.Insert(fn, cf.LocalBase) - } - if cf.Fn == nil { - ls.RaiseError("attempt to call a non-function object") - } - if ls.stack.IsFull() { - ls.RaiseError("stack overflow") - } - ls.stack.Push(cf) - newcf := ls.stack.Last() - // this section is inlined by go-inline - // source function is 'func (ls *LState) initCallFrame(cf *callFrame) ' in '_state.go' - { - cf := newcf - if cf.Fn.IsG { - ls.reg.SetTop(cf.LocalBase + cf.NArgs) - } else { - proto := cf.Fn.Proto - nargs := cf.NArgs - np := int(proto.NumParameters) - if nargs < np { - // default any missing arguments to nil - newSize := cf.LocalBase + np - // this section is inlined by go-inline - // source function is 'func (rg *registry) checkSize(requiredSize int) ' in '_state.go' - { - rg := ls.reg - requiredSize := newSize - if requiredSize > cap(rg.array) { - rg.resize(requiredSize) - } - } - for i := nargs; i < np; i++ { - ls.reg.array[cf.LocalBase+i] = LNil - } - nargs = np - ls.reg.top = newSize - } +func mainLoop(L *LState, baseframe *callFrame) { + var inst uint32 + var cf *callFrame - if (proto.IsVarArg & VarArgIsVarArg) == 0 { - if nargs < int(proto.NumUsedRegisters) { - nargs = int(proto.NumUsedRegisters) - } - newSize := cf.LocalBase + nargs - // this section is inlined by go-inline - // source function is 'func (rg *registry) checkSize(requiredSize int) ' in '_state.go' - { - rg := ls.reg - requiredSize := newSize - if requiredSize > cap(rg.array) { - rg.resize(requiredSize) - } - } - for i := np; i < nargs; i++ { - ls.reg.array[cf.LocalBase+i] = LNil - } - ls.reg.top = cf.LocalBase + int(proto.NumUsedRegisters) - } else { - /* swap vararg positions: - closure - namedparam1 <- lbase - namedparam2 - vararg1 - vararg2 + if L.stack.IsEmpty() { + return + } + + L.currentFrame = L.stack.Last() + if L.currentFrame.Fn.IsG { + callGFunction(L, false) + return + } + + for { + cf = L.currentFrame + inst = cf.Fn.Proto.Code[cf.Pc] + cf.Pc++ + if evalInstruction(L, inst, baseframe) { + return + } + } +} - TO +func mainLoopWithContext(L *LState, baseframe *callFrame) { + var inst uint32 + var cf *callFrame - closure - nil - nil - vararg1 - vararg2 - namedparam1 <- lbase - namedparam2 - */ - nvarargs := nargs - np - if nvarargs < 0 { - nvarargs = 0 - } + if L.stack.IsEmpty() { + return + } - ls.reg.SetTop(cf.LocalBase + nargs + np) - for i := 0; i < np; i++ { - //ls.reg.Set(cf.LocalBase+nargs+i, ls.reg.Get(cf.LocalBase+i)) - ls.reg.array[cf.LocalBase+nargs+i] = ls.reg.array[cf.LocalBase+i] - //ls.reg.Set(cf.LocalBase+i, LNil) - ls.reg.array[cf.LocalBase+i] = LNil - } + L.currentFrame = L.stack.Last() + if L.currentFrame.Fn.IsG { + callGFunction(L, false) + return + } - if CompatVarArg { - ls.reg.SetTop(cf.LocalBase + nargs + np + 1) - if (proto.IsVarArg & VarArgNeedsArg) != 0 { - argtb := newLTable(nvarargs, 0) - for i := 0; i < nvarargs; i++ { - argtb.RawSetInt(i+1, ls.reg.Get(cf.LocalBase+np+i)) - } - argtb.RawSetString("n", LNumber(nvarargs)) - //ls.reg.Set(cf.LocalBase+nargs+np, argtb) - ls.reg.array[cf.LocalBase+nargs+np] = argtb - } else { - ls.reg.array[cf.LocalBase+nargs+np] = LNil - } - } - cf.LocalBase += nargs - maxreg := cf.LocalBase + int(proto.NumUsedRegisters) - ls.reg.SetTop(maxreg) - } - } - } - ls.currentFrame = newcf - } - if callable.IsG && callGFunction(L, false) { - return 1 - } - return 0 - }, - func(L *LState, inst uint32, baseframe *callFrame) int { //OP_TAILCALL - reg := L.reg - cf := L.currentFrame - lbase := cf.LocalBase - A := int(inst>>18) & 0xff //GETA - RA := lbase + A - B := int(inst & 0x1ff) //GETB - nargs := B - 1 - if B == 0 { - nargs = reg.Top() - (RA + 1) - } - lv := reg.Get(RA) - var callable *LFunction - var meta bool - if fn, ok := lv.(*LFunction); ok { - callable = fn - meta = false - } else { - callable, meta = L.metaCall(lv) - } - if callable == nil { - L.RaiseError("attempt to call a non-function object") - } - // this section is inlined by go-inline - // source function is 'func (ls *LState) closeUpvalues(idx int) ' in '_state.go' - { - ls := L - idx := lbase - if ls.uvcache != nil { - var prev *Upvalue - for uv := ls.uvcache; uv != nil; uv = uv.next { - if uv.index >= idx { - if prev != nil { - prev.next = nil - } else { - ls.uvcache = nil - } - uv.Close() - } - prev = uv - } - } + for { + cf = L.currentFrame + inst = cf.Fn.Proto.Code[cf.Pc] + cf.Pc++ + select { + case <-L.ctx.Done(): + L.RaiseError(L.ctx.Err().Error()) + return + default: + if evalInstruction(L, inst, baseframe) { + return } - if callable.IsG { - luaframe := cf - L.pushCallFrame(callFrame{ - Fn: callable, - Pc: 0, - Base: RA, - LocalBase: RA + 1, - ReturnBase: cf.ReturnBase, - NArgs: nargs, - NRet: cf.NRet, - Parent: cf, - TailCall: 0, - }, lv, meta) - if callGFunction(L, true) { - return 1 - } - if L.currentFrame == nil || L.currentFrame.Fn.IsG || luaframe == baseframe { - return 1 - } - } else { - base := cf.Base - cf.Fn = callable - cf.Pc = 0 - cf.Base = RA - cf.LocalBase = RA + 1 - cf.ReturnBase = cf.ReturnBase - cf.NArgs = nargs - cf.NRet = cf.NRet - cf.TailCall++ - lbase := cf.LocalBase - if meta { - cf.NArgs++ - L.reg.Insert(lv, cf.LocalBase) - } - // this section is inlined by go-inline - // source function is 'func (ls *LState) initCallFrame(cf *callFrame) ' in '_state.go' - { - ls := L - if cf.Fn.IsG { - ls.reg.SetTop(cf.LocalBase + cf.NArgs) - } else { - proto := cf.Fn.Proto - nargs := cf.NArgs - np := int(proto.NumParameters) - if nargs < np { - // default any missing arguments to nil - newSize := cf.LocalBase + np - // this section is inlined by go-inline - // source function is 'func (rg *registry) checkSize(requiredSize int) ' in '_state.go' - { - rg := ls.reg - requiredSize := newSize - if requiredSize > cap(rg.array) { - rg.resize(requiredSize) - } - } - for i := nargs; i < np; i++ { - ls.reg.array[cf.LocalBase+i] = LNil - } - nargs = np - ls.reg.top = newSize - } - - if (proto.IsVarArg & VarArgIsVarArg) == 0 { - if nargs < int(proto.NumUsedRegisters) { - nargs = int(proto.NumUsedRegisters) - } - newSize := cf.LocalBase + nargs - // this section is inlined by go-inline - // source function is 'func (rg *registry) checkSize(requiredSize int) ' in '_state.go' - { - rg := ls.reg - requiredSize := newSize - if requiredSize > cap(rg.array) { - rg.resize(requiredSize) - } - } - for i := np; i < nargs; i++ { - ls.reg.array[cf.LocalBase+i] = LNil - } - ls.reg.top = cf.LocalBase + int(proto.NumUsedRegisters) - } else { - /* swap vararg positions: - closure - namedparam1 <- lbase - namedparam2 - vararg1 - vararg2 + } + } +} - TO +// regv is the first target register to copy the return values to. +// It can be reg.top, indicating that the copied values are going into new registers, or it can be below reg.top +// Indicating that the values should be within the existing registers. +// b is the available number of return values + 1. +// n is the desired number of return values. +// If n more than the available return values then the extra values are set to nil. +// When this function returns the top of the registry will be set to regv+n. +func copyReturnValues(L *LState, regv, start, n, b int) { // +inline-start + if b == 1 { +// this section is inlined by go-inline +// source function is 'func (rg *registry) FillNil(regm, n int) ' in '_state.go' +{ +rg := L.reg +regm := regv + newSize := regm + n +// this section is inlined by go-inline +// source function is 'func (rg *registry) checkSize(requiredSize int) ' in '_state.go' +{ +requiredSize := newSize + if requiredSize > cap(rg.array) { + rg.resize(requiredSize) + } +} + for i := 0; i < n; i++ { + rg.array[regm+i] = LNil + } + // values beyond top don't need to be valid LValues, so setting them to nil is fine + // setting them to nil rather than LNil lets us invoke the golang memclr opto + oldtop := rg.top + rg.top = regm + n + if rg.top < oldtop { + nilRange := rg.array[rg.top:oldtop] + for i := range nilRange { + nilRange[i] = nil + } + } +} + } else { +// this section is inlined by go-inline +// source function is 'func (rg *registry) CopyRange(regv, start, limit, n int) ' in '_state.go' +{ +rg := L.reg +limit := -1 + newSize := regv + n +// this section is inlined by go-inline +// source function is 'func (rg *registry) checkSize(requiredSize int) ' in '_state.go' +{ +requiredSize := newSize + if requiredSize > cap(rg.array) { + rg.resize(requiredSize) + } +} + if limit == -1 || limit > rg.top { + limit = rg.top + } + for i := 0; i < n; i++ { + srcIdx := start + i + if srcIdx >= limit || srcIdx < 0 { + rg.array[regv+i] = LNil + } else { + rg.array[regv+i] = rg.array[srcIdx] + } + } - closure - nil - nil - vararg1 - vararg2 - namedparam1 <- lbase - namedparam2 - */ - nvarargs := nargs - np - if nvarargs < 0 { - nvarargs = 0 - } + // values beyond top don't need to be valid LValues, so setting them to nil is fine + // setting them to nil rather than LNil lets us invoke the golang memclr opto + oldtop := rg.top + rg.top = regv + n + if rg.top < oldtop { + nilRange := rg.array[rg.top:oldtop] + for i := range nilRange { + nilRange[i] = nil + } + } +} + if b > 1 && n > (b-1) { +// this section is inlined by go-inline +// source function is 'func (rg *registry) FillNil(regm, n int) ' in '_state.go' +{ +rg := L.reg +regm := regv+b-1 +n := n-(b-1) + newSize := regm + n +// this section is inlined by go-inline +// source function is 'func (rg *registry) checkSize(requiredSize int) ' in '_state.go' +{ +requiredSize := newSize + if requiredSize > cap(rg.array) { + rg.resize(requiredSize) + } +} + for i := 0; i < n; i++ { + rg.array[regm+i] = LNil + } + // values beyond top don't need to be valid LValues, so setting them to nil is fine + // setting them to nil rather than LNil lets us invoke the golang memclr opto + oldtop := rg.top + rg.top = regm + n + if rg.top < oldtop { + nilRange := rg.array[rg.top:oldtop] + for i := range nilRange { + nilRange[i] = nil + } + } +} + } + } +} // +inline-end - ls.reg.SetTop(cf.LocalBase + nargs + np) - for i := 0; i < np; i++ { - //ls.reg.Set(cf.LocalBase+nargs+i, ls.reg.Get(cf.LocalBase+i)) - ls.reg.array[cf.LocalBase+nargs+i] = ls.reg.array[cf.LocalBase+i] - //ls.reg.Set(cf.LocalBase+i, LNil) - ls.reg.array[cf.LocalBase+i] = LNil - } +func switchToParentThread(L *LState, nargs int, haserror bool, kill bool) { + parent := L.Parent + if parent == nil { + L.RaiseError("can not yield from outside of a coroutine") + } + L.G.CurrentThread = parent + L.Parent = nil + if !L.wrapped { + if haserror { + parent.Push(LFalse) + } else { + parent.Push(LTrue) + } + } + L.XMoveTo(parent, nargs) + L.stack.Pop() + offset := L.currentFrame.LocalBase - L.currentFrame.ReturnBase + L.currentFrame = L.stack.Last() + L.reg.SetTop(L.reg.Top() - offset) // remove 'yield' function(including tailcalled functions) + if kill { + L.kill() + } +} - if CompatVarArg { - ls.reg.SetTop(cf.LocalBase + nargs + np + 1) - if (proto.IsVarArg & VarArgNeedsArg) != 0 { - argtb := newLTable(nvarargs, 0) - for i := 0; i < nvarargs; i++ { - argtb.RawSetInt(i+1, ls.reg.Get(cf.LocalBase+np+i)) - } - argtb.RawSetString("n", LNumber(nvarargs)) - //ls.reg.Set(cf.LocalBase+nargs+np, argtb) - ls.reg.array[cf.LocalBase+nargs+np] = argtb - } else { - ls.reg.array[cf.LocalBase+nargs+np] = LNil - } - } - cf.LocalBase += nargs - maxreg := cf.LocalBase + int(proto.NumUsedRegisters) - ls.reg.SetTop(maxreg) - } - } - } - // this section is inlined by go-inline - // source function is 'func (rg *registry) CopyRange(regv, start, limit, n int) ' in '_state.go' - { - rg := L.reg - regv := base - start := RA - limit := -1 - n := reg.Top() - RA - 1 - newSize := regv + n - // this section is inlined by go-inline - // source function is 'func (rg *registry) checkSize(requiredSize int) ' in '_state.go' - { - requiredSize := newSize - if requiredSize > cap(rg.array) { - rg.resize(requiredSize) - } - } - if limit == -1 || limit > rg.top { - limit = rg.top - } - for i := 0; i < n; i++ { - srcIdx := start + i - if srcIdx >= limit || srcIdx < 0 { - rg.array[regv+i] = LNil - } else { - rg.array[regv+i] = rg.array[srcIdx] - } - } +func callGFunction(L *LState, tailcall bool) bool { + frame := L.currentFrame + gfnret := frame.Fn.GFunction(L) + if tailcall { + L.currentFrame = L.RemoveCallerFrame() + } - // values beyond top don't need to be valid LValues, so setting them to nil is fine - // setting them to nil rather than LNil lets us invoke the golang memclr opto - oldtop := rg.top - rg.top = regv + n - if rg.top < oldtop { - nilRange := rg.array[rg.top:oldtop] - for i := range nilRange { - nilRange[i] = nil - } - } - } - cf.Base = base - cf.LocalBase = base + (cf.LocalBase - lbase + 1) - } - return 0 - }, - func(L *LState, inst uint32, baseframe *callFrame) int { //OP_RETURN - reg := L.reg - cf := L.currentFrame - lbase := cf.LocalBase - A := int(inst>>18) & 0xff //GETA - RA := lbase + A - B := int(inst & 0x1ff) //GETB - // this section is inlined by go-inline - // source function is 'func (ls *LState) closeUpvalues(idx int) ' in '_state.go' - { - ls := L - idx := lbase - if ls.uvcache != nil { - var prev *Upvalue - for uv := ls.uvcache; uv != nil; uv = uv.next { - if uv.index >= idx { - if prev != nil { - prev.next = nil - } else { - ls.uvcache = nil - } - uv.Close() - } - prev = uv - } - } - } - nret := B - 1 - if B == 0 { - nret = reg.Top() - RA - } - n := cf.NRet - if cf.NRet == MultRet { - n = nret - } + if gfnret < 0 { + switchToParentThread(L, L.GetTop(), false, false) + return true + } - if L.Parent != nil && L.stack.Sp() == 1 { - // this section is inlined by go-inline - // source function is 'func copyReturnValues(L *LState, regv, start, n, b int) ' in '_vm.go' - { - regv := reg.Top() - start := RA - b := B - if b == 1 { - // this section is inlined by go-inline - // source function is 'func (rg *registry) FillNil(regm, n int) ' in '_state.go' - { - rg := L.reg - regm := regv - newSize := regm + n - // this section is inlined by go-inline - // source function is 'func (rg *registry) checkSize(requiredSize int) ' in '_state.go' - { - requiredSize := newSize - if requiredSize > cap(rg.array) { - rg.resize(requiredSize) - } - } - for i := 0; i < n; i++ { - rg.array[regm+i] = LNil - } - // values beyond top don't need to be valid LValues, so setting them to nil is fine - // setting them to nil rather than LNil lets us invoke the golang memclr opto - oldtop := rg.top - rg.top = regm + n - if rg.top < oldtop { - nilRange := rg.array[rg.top:oldtop] - for i := range nilRange { - nilRange[i] = nil - } - } - } - } else { - // this section is inlined by go-inline - // source function is 'func (rg *registry) CopyRange(regv, start, limit, n int) ' in '_state.go' - { - rg := L.reg - limit := -1 - newSize := regv + n - // this section is inlined by go-inline - // source function is 'func (rg *registry) checkSize(requiredSize int) ' in '_state.go' - { - requiredSize := newSize - if requiredSize > cap(rg.array) { - rg.resize(requiredSize) - } - } - if limit == -1 || limit > rg.top { - limit = rg.top - } - for i := 0; i < n; i++ { - srcIdx := start + i - if srcIdx >= limit || srcIdx < 0 { - rg.array[regv+i] = LNil - } else { - rg.array[regv+i] = rg.array[srcIdx] - } - } + wantret := frame.NRet + if wantret == MultRet { + wantret = gfnret + } - // values beyond top don't need to be valid LValues, so setting them to nil is fine - // setting them to nil rather than LNil lets us invoke the golang memclr opto - oldtop := rg.top - rg.top = regv + n - if rg.top < oldtop { - nilRange := rg.array[rg.top:oldtop] - for i := range nilRange { - nilRange[i] = nil - } - } - } - if b > 1 && n > (b-1) { - // this section is inlined by go-inline - // source function is 'func (rg *registry) FillNil(regm, n int) ' in '_state.go' - { - rg := L.reg - regm := regv + b - 1 - n := n - (b - 1) - newSize := regm + n - // this section is inlined by go-inline - // source function is 'func (rg *registry) checkSize(requiredSize int) ' in '_state.go' - { - requiredSize := newSize - if requiredSize > cap(rg.array) { - rg.resize(requiredSize) - } - } - for i := 0; i < n; i++ { - rg.array[regm+i] = LNil - } - // values beyond top don't need to be valid LValues, so setting them to nil is fine - // setting them to nil rather than LNil lets us invoke the golang memclr opto - oldtop := rg.top - rg.top = regm + n - if rg.top < oldtop { - nilRange := rg.array[rg.top:oldtop] - for i := range nilRange { - nilRange[i] = nil - } - } - } - } - } - } - switchToParentThread(L, n, false, true) - return 1 - } - islast := baseframe == L.stack.Pop() || L.stack.IsEmpty() - // this section is inlined by go-inline - // source function is 'func copyReturnValues(L *LState, regv, start, n, b int) ' in '_vm.go' - { - regv := cf.ReturnBase - start := RA - b := B - if b == 1 { - // this section is inlined by go-inline - // source function is 'func (rg *registry) FillNil(regm, n int) ' in '_state.go' - { - rg := L.reg - regm := regv - newSize := regm + n - // this section is inlined by go-inline - // source function is 'func (rg *registry) checkSize(requiredSize int) ' in '_state.go' - { - requiredSize := newSize - if requiredSize > cap(rg.array) { - rg.resize(requiredSize) - } - } - for i := 0; i < n; i++ { - rg.array[regm+i] = LNil - } - // values beyond top don't need to be valid LValues, so setting them to nil is fine - // setting them to nil rather than LNil lets us invoke the golang memclr opto - oldtop := rg.top - rg.top = regm + n - if rg.top < oldtop { - nilRange := rg.array[rg.top:oldtop] - for i := range nilRange { - nilRange[i] = nil - } - } - } - } else { - // this section is inlined by go-inline - // source function is 'func (rg *registry) CopyRange(regv, start, limit, n int) ' in '_state.go' - { - rg := L.reg - limit := -1 - newSize := regv + n - // this section is inlined by go-inline - // source function is 'func (rg *registry) checkSize(requiredSize int) ' in '_state.go' - { - requiredSize := newSize - if requiredSize > cap(rg.array) { - rg.resize(requiredSize) - } - } - if limit == -1 || limit > rg.top { - limit = rg.top - } - for i := 0; i < n; i++ { - srcIdx := start + i - if srcIdx >= limit || srcIdx < 0 { - rg.array[regv+i] = LNil - } else { - rg.array[regv+i] = rg.array[srcIdx] - } - } + if tailcall && L.Parent != nil && L.stack.Sp() == 1 { + switchToParentThread(L, wantret, false, true) + return true + } - // values beyond top don't need to be valid LValues, so setting them to nil is fine - // setting them to nil rather than LNil lets us invoke the golang memclr opto - oldtop := rg.top - rg.top = regv + n - if rg.top < oldtop { - nilRange := rg.array[rg.top:oldtop] - for i := range nilRange { - nilRange[i] = nil - } - } - } - if b > 1 && n > (b-1) { - // this section is inlined by go-inline - // source function is 'func (rg *registry) FillNil(regm, n int) ' in '_state.go' - { - rg := L.reg - regm := regv + b - 1 - n := n - (b - 1) - newSize := regm + n - // this section is inlined by go-inline - // source function is 'func (rg *registry) checkSize(requiredSize int) ' in '_state.go' - { - requiredSize := newSize - if requiredSize > cap(rg.array) { - rg.resize(requiredSize) - } - } - for i := 0; i < n; i++ { - rg.array[regm+i] = LNil - } - // values beyond top don't need to be valid LValues, so setting them to nil is fine - // setting them to nil rather than LNil lets us invoke the golang memclr opto - oldtop := rg.top - rg.top = regm + n - if rg.top < oldtop { - nilRange := rg.array[rg.top:oldtop] - for i := range nilRange { - nilRange[i] = nil - } - } - } - } - } - } - L.currentFrame = L.stack.Last() - if islast || L.currentFrame == nil || L.currentFrame.Fn.IsG { - return 1 - } - return 0 - }, - func(L *LState, inst uint32, baseframe *callFrame) int { //OP_FORLOOP - reg := L.reg - cf := L.currentFrame - lbase := cf.LocalBase - A := int(inst>>18) & 0xff //GETA - RA := lbase + A - if init, ok1 := reg.Get(RA).(LNumber); ok1 { - if limit, ok2 := reg.Get(RA + 1).(LNumber); ok2 { - if step, ok3 := reg.Get(RA + 2).(LNumber); ok3 { - init += step - v := LNumber(init) - // this section is inlined by go-inline - // source function is 'func (rg *registry) SetNumber(regi int, vali LNumber) ' in '_state.go' - { - rg := reg - regi := RA - vali := v - newSize := regi + 1 - // this section is inlined by go-inline - // source function is 'func (rg *registry) checkSize(requiredSize int) ' in '_state.go' - { - requiredSize := newSize - if requiredSize > cap(rg.array) { - rg.resize(requiredSize) - } - } - rg.array[regi] = rg.alloc.LNumber2I(vali) - if regi >= rg.top { - rg.top = regi + 1 - } - } - if (step > 0 && init <= limit) || (step <= 0 && init >= limit) { - Sbx := int(inst&0x3ffff) - opMaxArgSbx //GETSBX - cf.Pc += Sbx - // this section is inlined by go-inline - // source function is 'func (rg *registry) SetNumber(regi int, vali LNumber) ' in '_state.go' - { - rg := reg - regi := RA + 3 - vali := v - newSize := regi + 1 - // this section is inlined by go-inline - // source function is 'func (rg *registry) checkSize(requiredSize int) ' in '_state.go' - { - requiredSize := newSize - if requiredSize > cap(rg.array) { - rg.resize(requiredSize) - } - } - rg.array[regi] = rg.alloc.LNumber2I(vali) - if regi >= rg.top { - rg.top = regi + 1 - } - } - } else { - // this section is inlined by go-inline - // source function is 'func (rg *registry) SetTop(topi int) ' in '_state.go' - { - rg := reg - topi := RA + 1 - // this section is inlined by go-inline - // source function is 'func (rg *registry) checkSize(requiredSize int) ' in '_state.go' - { - requiredSize := topi - if requiredSize > cap(rg.array) { - rg.resize(requiredSize) - } - } - oldtopi := rg.top - rg.top = topi - for i := oldtopi; i < rg.top; i++ { - rg.array[i] = LNil - } - // values beyond top don't need to be valid LValues, so setting them to nil is fine - // setting them to nil rather than LNil lets us invoke the golang memclr opto - if rg.top < oldtopi { - nilRange := rg.array[rg.top:oldtopi] - for i := range nilRange { - nilRange[i] = nil - } - } - //for i := rg.top; i < oldtop; i++ { - // rg.array[i] = LNil - //} - } - } - } else { - L.RaiseError("for statement step must be a number") - } - } else { - L.RaiseError("for statement limit must be a number") - } - } else { - L.RaiseError("for statement init must be a number") - } - return 0 - }, - func(L *LState, inst uint32, baseframe *callFrame) int { //OP_FORPREP - reg := L.reg - cf := L.currentFrame - lbase := cf.LocalBase - A := int(inst>>18) & 0xff //GETA - RA := lbase + A - Sbx := int(inst&0x3ffff) - opMaxArgSbx //GETSBX - if init, ok1 := reg.Get(RA).(LNumber); ok1 { - if step, ok2 := reg.Get(RA + 2).(LNumber); ok2 { - // this section is inlined by go-inline - // source function is 'func (rg *registry) SetNumber(regi int, vali LNumber) ' in '_state.go' - { - rg := reg - regi := RA - vali := LNumber(init - step) - newSize := regi + 1 - // this section is inlined by go-inline - // source function is 'func (rg *registry) checkSize(requiredSize int) ' in '_state.go' - { - requiredSize := newSize - if requiredSize > cap(rg.array) { - rg.resize(requiredSize) - } - } - rg.array[regi] = rg.alloc.LNumber2I(vali) - if regi >= rg.top { - rg.top = regi + 1 - } - } - } else { - L.RaiseError("for statement step must be a number") - } - } else { - L.RaiseError("for statement init must be a number") - } - cf.Pc += Sbx - return 0 - }, - func(L *LState, inst uint32, baseframe *callFrame) int { //OP_TFORLOOP - reg := L.reg - cf := L.currentFrame - lbase := cf.LocalBase - A := int(inst>>18) & 0xff //GETA - RA := lbase + A - C := int(inst>>9) & 0x1ff //GETC - nret := C - // this section is inlined by go-inline - // source function is 'func (rg *registry) SetTop(topi int) ' in '_state.go' - { - rg := reg - topi := RA + 3 + 2 - // this section is inlined by go-inline - // source function is 'func (rg *registry) checkSize(requiredSize int) ' in '_state.go' - { - requiredSize := topi - if requiredSize > cap(rg.array) { - rg.resize(requiredSize) - } - } - oldtopi := rg.top - rg.top = topi - for i := oldtopi; i < rg.top; i++ { - rg.array[i] = LNil - } - // values beyond top don't need to be valid LValues, so setting them to nil is fine - // setting them to nil rather than LNil lets us invoke the golang memclr opto - if rg.top < oldtopi { - nilRange := rg.array[rg.top:oldtopi] - for i := range nilRange { - nilRange[i] = nil - } - } - //for i := rg.top; i < oldtop; i++ { - // rg.array[i] = LNil - //} - } - // this section is inlined by go-inline - // source function is 'func (rg *registry) Set(regi int, vali LValue) ' in '_state.go' - { - rg := reg - regi := RA + 3 + 2 - vali := reg.Get(RA + 2) - newSize := regi + 1 - // this section is inlined by go-inline - // source function is 'func (rg *registry) checkSize(requiredSize int) ' in '_state.go' - { - requiredSize := newSize - if requiredSize > cap(rg.array) { - rg.resize(requiredSize) - } - } - rg.array[regi] = vali - if regi >= rg.top { - rg.top = regi + 1 - } - } - // this section is inlined by go-inline - // source function is 'func (rg *registry) Set(regi int, vali LValue) ' in '_state.go' - { - rg := reg - regi := RA + 3 + 1 - vali := reg.Get(RA + 1) - newSize := regi + 1 - // this section is inlined by go-inline - // source function is 'func (rg *registry) checkSize(requiredSize int) ' in '_state.go' - { - requiredSize := newSize - if requiredSize > cap(rg.array) { - rg.resize(requiredSize) - } - } - rg.array[regi] = vali - if regi >= rg.top { - rg.top = regi + 1 - } - } - // this section is inlined by go-inline - // source function is 'func (rg *registry) Set(regi int, vali LValue) ' in '_state.go' - { - rg := reg - regi := RA + 3 - vali := reg.Get(RA) - newSize := regi + 1 - // this section is inlined by go-inline - // source function is 'func (rg *registry) checkSize(requiredSize int) ' in '_state.go' - { - requiredSize := newSize - if requiredSize > cap(rg.array) { - rg.resize(requiredSize) - } - } - rg.array[regi] = vali - if regi >= rg.top { - rg.top = regi + 1 - } - } - L.callR(2, nret, RA+3) - if value := reg.Get(RA + 3); value != LNil { - // this section is inlined by go-inline - // source function is 'func (rg *registry) Set(regi int, vali LValue) ' in '_state.go' - { - rg := reg - regi := RA + 2 - vali := value - newSize := regi + 1 - // this section is inlined by go-inline - // source function is 'func (rg *registry) checkSize(requiredSize int) ' in '_state.go' - { - requiredSize := newSize - if requiredSize > cap(rg.array) { - rg.resize(requiredSize) - } - } - rg.array[regi] = vali - if regi >= rg.top { - rg.top = regi + 1 - } - } - pc := cf.Fn.Proto.Code[cf.Pc] - cf.Pc += int(pc&0x3ffff) - opMaxArgSbx - } - cf.Pc++ - return 0 - }, - func(L *LState, inst uint32, baseframe *callFrame) int { //OP_SETLIST - reg := L.reg - cf := L.currentFrame - lbase := cf.LocalBase - A := int(inst>>18) & 0xff //GETA - RA := lbase + A - B := int(inst & 0x1ff) //GETB - C := int(inst>>9) & 0x1ff //GETC - if C == 0 { - C = int(cf.Fn.Proto.Code[cf.Pc]) - cf.Pc++ - } - offset := (C - 1) * FieldsPerFlush - table := reg.Get(RA).(*LTable) - nelem := B - if B == 0 { - nelem = reg.Top() - RA - 1 - } - for i := 1; i <= nelem; i++ { - table.RawSetInt(offset+i, reg.Get(RA+i)) - } - return 0 - }, - func(L *LState, inst uint32, baseframe *callFrame) int { //OP_CLOSE - cf := L.currentFrame - lbase := cf.LocalBase - A := int(inst>>18) & 0xff //GETA - RA := lbase + A - // this section is inlined by go-inline - // source function is 'func (ls *LState) closeUpvalues(idx int) ' in '_state.go' - { - ls := L - idx := RA - if ls.uvcache != nil { - var prev *Upvalue - for uv := ls.uvcache; uv != nil; uv = uv.next { - if uv.index >= idx { - if prev != nil { - prev.next = nil - } else { - ls.uvcache = nil - } - uv.Close() - } - prev = uv - } - } - } - return 0 - }, - func(L *LState, inst uint32, baseframe *callFrame) int { //OP_CLOSURE - reg := L.reg - cf := L.currentFrame - lbase := cf.LocalBase - A := int(inst>>18) & 0xff //GETA - RA := lbase + A - Bx := int(inst & 0x3ffff) //GETBX - proto := cf.Fn.Proto.FunctionPrototypes[Bx] - closure := newLFunctionL(proto, cf.Fn.Env, int(proto.NumUpvalues)) - // this section is inlined by go-inline - // source function is 'func (rg *registry) Set(regi int, vali LValue) ' in '_state.go' - { - rg := reg - regi := RA - vali := closure - newSize := regi + 1 - // this section is inlined by go-inline - // source function is 'func (rg *registry) checkSize(requiredSize int) ' in '_state.go' - { - requiredSize := newSize - if requiredSize > cap(rg.array) { - rg.resize(requiredSize) - } - } - rg.array[regi] = vali - if regi >= rg.top { - rg.top = regi + 1 - } - } - for i := 0; i < int(proto.NumUpvalues); i++ { - inst = cf.Fn.Proto.Code[cf.Pc] - cf.Pc++ - B := opGetArgB(inst) - switch opGetOpCode(inst) { - case OP_MOVE: - closure.Upvalues[i] = L.findUpvalue(lbase + B) - case OP_GETUPVAL: - closure.Upvalues[i] = cf.Fn.Upvalues[B] - } - } - return 0 - }, - func(L *LState, inst uint32, baseframe *callFrame) int { //OP_VARARG - reg := L.reg - cf := L.currentFrame - lbase := cf.LocalBase - A := int(inst>>18) & 0xff //GETA - RA := lbase + A - B := int(inst & 0x1ff) //GETB - nparams := int(cf.Fn.Proto.NumParameters) - nvarargs := cf.NArgs - nparams - if nvarargs < 0 { - nvarargs = 0 - } - nwant := B - 1 - if B == 0 { - nwant = nvarargs - } - // this section is inlined by go-inline - // source function is 'func (rg *registry) CopyRange(regv, start, limit, n int) ' in '_state.go' - { - rg := reg - regv := RA - start := cf.Base + nparams + 1 - limit := cf.LocalBase - n := nwant - newSize := regv + n - // this section is inlined by go-inline - // source function is 'func (rg *registry) checkSize(requiredSize int) ' in '_state.go' - { - requiredSize := newSize - if requiredSize > cap(rg.array) { - rg.resize(requiredSize) - } - } - if limit == -1 || limit > rg.top { - limit = rg.top - } - for i := 0; i < n; i++ { - srcIdx := start + i - if srcIdx >= limit || srcIdx < 0 { - rg.array[regv+i] = LNil - } else { - rg.array[regv+i] = rg.array[srcIdx] - } - } +// this section is inlined by go-inline +// source function is 'func (rg *registry) CopyRange(regv, start, limit, n int) ' in '_state.go' +{ +rg := L.reg +regv := frame.ReturnBase +start := L.reg.Top()-gfnret +limit := -1 +n := wantret + newSize := regv + n +// this section is inlined by go-inline +// source function is 'func (rg *registry) checkSize(requiredSize int) ' in '_state.go' +{ +requiredSize := newSize + if requiredSize > cap(rg.array) { + rg.resize(requiredSize) + } +} + if limit == -1 || limit > rg.top { + limit = rg.top + } + for i := 0; i < n; i++ { + srcIdx := start + i + if srcIdx >= limit || srcIdx < 0 { + rg.array[regv+i] = LNil + } else { + rg.array[regv+i] = rg.array[srcIdx] + } + } - // values beyond top don't need to be valid LValues, so setting them to nil is fine - // setting them to nil rather than LNil lets us invoke the golang memclr opto - oldtop := rg.top - rg.top = regv + n - if rg.top < oldtop { - nilRange := rg.array[rg.top:oldtop] - for i := range nilRange { - nilRange[i] = nil - } - } - } - return 0 - }, - func(L *LState, inst uint32, baseframe *callFrame) int { //OP_NOP - return 0 - }, + // values beyond top don't need to be valid LValues, so setting them to nil is fine + // setting them to nil rather than LNil lets us invoke the golang memclr opto + oldtop := rg.top + rg.top = regv + n + if rg.top < oldtop { + nilRange := rg.array[rg.top:oldtop] + for i := range nilRange { + nilRange[i] = nil + } } } + L.stack.Pop() + L.currentFrame = L.stack.Last() + return false +} -func opArith(L *LState, inst uint32, baseframe *callFrame) int { //OP_ADD, OP_SUB, OP_MUL, OP_DIV, OP_MOD, OP_POW - reg := L.reg - cf := L.currentFrame - lbase := cf.LocalBase - A := int(inst>>18) & 0xff //GETA - RA := lbase + A - opcode := int(inst >> 26) //GETOPCODE - B := int(inst & 0x1ff) //GETB - C := int(inst>>9) & 0x1ff //GETC - lhs := L.rkValue(B) - rhs := L.rkValue(C) - v1, ok1 := lhs.(LNumber) - v2, ok2 := rhs.(LNumber) - if ok1 && ok2 { - v := numberArith(L, opcode, LNumber(v1), LNumber(v2)) - // this section is inlined by go-inline - // source function is 'func (rg *registry) SetNumber(regi int, vali LNumber) ' in '_state.go' - { - rg := reg - regi := RA - vali := v - newSize := regi + 1 - // this section is inlined by go-inline - // source function is 'func (rg *registry) checkSize(requiredSize int) ' in '_state.go' - { - requiredSize := newSize - if requiredSize > cap(rg.array) { - rg.resize(requiredSize) - } - } - rg.array[regi] = rg.alloc.LNumber2I(vali) - if regi >= rg.top { - rg.top = regi + 1 +func threadRun(L *LState) { + if L.stack.IsEmpty() { + return + } + + defer func() { + if rcv := recover(); rcv != nil { + var lv LValue + if v, ok := rcv.(*ApiError); ok { + lv = v.Object + } else { + lv = LString(fmt.Sprint(rcv)) } - } - } else { - v := objectArith(L, opcode, lhs, rhs) - // this section is inlined by go-inline - // source function is 'func (rg *registry) Set(regi int, vali LValue) ' in '_state.go' - { - rg := reg - regi := RA - vali := v - newSize := regi + 1 - // this section is inlined by go-inline - // source function is 'func (rg *registry) checkSize(requiredSize int) ' in '_state.go' - { - requiredSize := newSize - if requiredSize > cap(rg.array) { - rg.resize(requiredSize) + if parent := L.Parent; parent != nil { + if L.wrapped { + L.Push(lv) + parent.Panic(L) + } else { + L.SetTop(0) + L.Push(lv) + switchToParentThread(L, 1, true, true) } - } - rg.array[regi] = vali - if regi >= rg.top { - rg.top = regi + 1 + } else { + panic(rcv) } } - } - return 0 + }() + L.mainLoop(L, nil) } func luaModulo(lhs, rhs LNumber) LNumber { @@ -2463,3 +2291,4 @@ func objectRational(L *LState, lhs, rhs LValue, event string) int { } return -1 } + From 8d31a7bde0ad1309911325981f89fe453996f928 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philip=20Dub=C3=A9?= Date: Tue, 12 Mar 2024 22:07:07 +0000 Subject: [PATCH 2/4] Combine mainLoop/mainLoopWithContext to inline evalInstruction --- _state.go | 10 +++------- _vm.go | 34 +++------------------------------- state.go | 10 +++------- value.go | 1 - vm.go | 34 +++------------------------------- 5 files changed, 12 insertions(+), 77 deletions(-) diff --git a/_state.go b/_state.go index 6e9febfb..5de19267 100644 --- a/_state.go +++ b/_state.go @@ -576,7 +576,6 @@ func newLState(options Options) *LState { wrapped: false, uvcache: nil, hasErrorFunc: false, - mainLoop: mainLoop, ctx: nil, } if options.MinimizeStackMemory { @@ -1051,9 +1050,9 @@ func (ls *LState) callR(nargs, nret, rbase int) { if ls.G.MainThread == nil { ls.G.MainThread = ls ls.G.CurrentThread = ls - ls.mainLoop(ls, nil) + mainLoop(ls, nil) } else { - ls.mainLoop(ls, ls.currentFrame) + mainLoop(ls, ls.currentFrame) } if nret != MultRet { ls.reg.SetTop(rbase + nret) @@ -1404,7 +1403,6 @@ func (ls *LState) NewThread() (*LState, context.CancelFunc) { thread.Env = ls.Env var f context.CancelFunc = nil if ls.ctx != nil { - thread.mainLoop = mainLoopWithContext thread.ctx, f = context.WithCancel(ls.ctx) thread.ctxCancelFn = f } @@ -2044,9 +2042,8 @@ func (ls *LState) SetMx(mx int) { }() } -// SetContext set a context ctx to this LState. The provided ctx must be non-nil. +// SetContext set a context ctx to this LState. func (ls *LState) SetContext(ctx context.Context) { - ls.mainLoop = mainLoopWithContext ls.ctx = ctx } @@ -2058,7 +2055,6 @@ func (ls *LState) Context() context.Context { // RemoveContext removes the context associated with this LState and returns this context. func (ls *LState) RemoveContext() context.Context { oldctx := ls.ctx - ls.mainLoop = mainLoop ls.ctx = nil return oldctx } diff --git a/_vm.go b/_vm.go index 332502cc..a7a95580 100644 --- a/_vm.go +++ b/_vm.go @@ -540,7 +540,7 @@ func mainLoop(L *LState, baseframe *callFrame) { return } - for { + for L.ctx == nil || L.ctx.Err() == nil { cf = L.currentFrame inst = cf.Fn.Proto.Code[cf.Pc] cf.Pc++ @@ -548,36 +548,8 @@ func mainLoop(L *LState, baseframe *callFrame) { return } } -} - -func mainLoopWithContext(L *LState, baseframe *callFrame) { - var inst uint32 - var cf *callFrame - - if L.stack.IsEmpty() { - return - } - - L.currentFrame = L.stack.Last() - if L.currentFrame.Fn.IsG { - callGFunction(L, false) - return - } - for { - cf = L.currentFrame - inst = cf.Fn.Proto.Code[cf.Pc] - cf.Pc++ - select { - case <-L.ctx.Done(): - L.RaiseError(L.ctx.Err().Error()) - return - default: - if evalInstruction(L, inst, baseframe) { - return - } - } - } + L.RaiseError(L.ctx.Err().Error()) } // regv is the first target register to copy the return values to. @@ -677,7 +649,7 @@ func threadRun(L *LState) { } } }() - L.mainLoop(L, nil) + mainLoop(L, nil) } func luaModulo(lhs, rhs LNumber) LNumber { diff --git a/state.go b/state.go index eaf36e4f..fa50dcaf 100644 --- a/state.go +++ b/state.go @@ -675,7 +675,6 @@ func newLState(options Options) *LState { wrapped: false, uvcache: nil, hasErrorFunc: false, - mainLoop: mainLoop, ctx: nil, } if options.MinimizeStackMemory { @@ -1263,9 +1262,9 @@ func (ls *LState) callR(nargs, nret, rbase int) { if ls.G.MainThread == nil { ls.G.MainThread = ls ls.G.CurrentThread = ls - ls.mainLoop(ls, nil) + mainLoop(ls, nil) } else { - ls.mainLoop(ls, ls.currentFrame) + mainLoop(ls, ls.currentFrame) } if nret != MultRet { ls.reg.SetTop(rbase + nret) @@ -1616,7 +1615,6 @@ func (ls *LState) NewThread() (*LState, context.CancelFunc) { thread.Env = ls.Env var f context.CancelFunc = nil if ls.ctx != nil { - thread.mainLoop = mainLoopWithContext thread.ctx, f = context.WithCancel(ls.ctx) thread.ctxCancelFn = f } @@ -2256,9 +2254,8 @@ func (ls *LState) SetMx(mx int) { }() } -// SetContext set a context ctx to this LState. The provided ctx must be non-nil. +// SetContext set a context ctx to this LState. func (ls *LState) SetContext(ctx context.Context) { - ls.mainLoop = mainLoopWithContext ls.ctx = ctx } @@ -2270,7 +2267,6 @@ func (ls *LState) Context() context.Context { // RemoveContext removes the context associated with this LState and returns this context. func (ls *LState) RemoveContext() context.Context { oldctx := ls.ctx - ls.mainLoop = mainLoop ls.ctx = nil return oldctx } diff --git a/value.go b/value.go index 4156e9d5..3044f1b4 100644 --- a/value.go +++ b/value.go @@ -192,7 +192,6 @@ type LState struct { wrapped bool uvcache *Upvalue hasErrorFunc bool - mainLoop func(*LState, *callFrame) ctx context.Context ctxCancelFn context.CancelFunc } diff --git a/vm.go b/vm.go index d29d7535..2894f586 100644 --- a/vm.go +++ b/vm.go @@ -1825,7 +1825,7 @@ func mainLoop(L *LState, baseframe *callFrame) { return } - for { + for L.ctx == nil || L.ctx.Err() == nil { cf = L.currentFrame inst = cf.Fn.Proto.Code[cf.Pc] cf.Pc++ @@ -1833,36 +1833,8 @@ func mainLoop(L *LState, baseframe *callFrame) { return } } -} - -func mainLoopWithContext(L *LState, baseframe *callFrame) { - var inst uint32 - var cf *callFrame - - if L.stack.IsEmpty() { - return - } - - L.currentFrame = L.stack.Last() - if L.currentFrame.Fn.IsG { - callGFunction(L, false) - return - } - for { - cf = L.currentFrame - inst = cf.Fn.Proto.Code[cf.Pc] - cf.Pc++ - select { - case <-L.ctx.Done(): - L.RaiseError(L.ctx.Err().Error()) - return - default: - if evalInstruction(L, inst, baseframe) { - return - } - } - } + L.RaiseError(L.ctx.Err().Error()) } // regv is the first target register to copy the return values to. @@ -2092,7 +2064,7 @@ func threadRun(L *LState) { } } }() - L.mainLoop(L, nil) + mainLoop(L, nil) } func luaModulo(lhs, rhs LNumber) LNumber { From 3dc75ff0c5e160c81a0bda09aa8c34dd622d0c78 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philip=20Dub=C3=A9?= Date: Tue, 12 Mar 2024 22:29:22 +0000 Subject: [PATCH 3/4] Move switch into function body --- _vm.go | 998 ++++++++++++++++++++++++++++----------------------------- vm.go | 924 ++++++++++++++++++++++++++-------------------------- 2 files changed, 943 insertions(+), 979 deletions(-) diff --git a/_vm.go b/_vm.go index a7a95580..e6770213 100644 --- a/_vm.go +++ b/_vm.go @@ -6,546 +6,528 @@ import ( "strings" ) -func evalInstruction(L *LState, inst uint32, baseframe *callFrame) bool { +func mainLoop(L *LState, baseframe *callFrame) { + if L.stack.IsEmpty() { + return + } + + L.currentFrame = L.stack.Last() + if L.currentFrame.Fn.IsG { + callGFunction(L, false) + return + } + reg := L.reg - cf := L.currentFrame - lbase := cf.LocalBase - opcode := int(inst >> 26) - switch opcode { - case OP_MOVE: - A := int(inst>>18) & 0xff //GETA - RA := lbase + A - B := int(inst & 0x1ff) //GETB - v := reg.Get(lbase + B) - // +inline-call reg.Set RA v - case OP_MOVEN: - A := int(inst>>18) & 0xff //GETA - B := int(inst & 0x1ff) //GETB - C := int(inst>>9) & 0x1ff //GETC - v := reg.Get(lbase + B) - // +inline-call reg.Set lbase+A v - code := cf.Fn.Proto.Code - pc := cf.Pc - for i := 0; i < C; i++ { - inst = code[pc] - pc++ - A = int(inst>>18) & 0xff //GETA - B = int(inst & 0x1ff) //GETB - v := reg.Get(lbase + B) - // +inline-call reg.Set lbase+A v - } - cf.Pc = pc - case OP_LOADK: - A := int(inst>>18) & 0xff //GETA - RA := lbase + A - Bx := int(inst & 0x3ffff) //GETBX - v := cf.Fn.Proto.Constants[Bx] - // +inline-call reg.Set RA v - case OP_LOADBOOL: - A := int(inst>>18) & 0xff //GETA - RA := lbase + A - B := int(inst & 0x1ff) //GETB - C := int(inst>>9) & 0x1ff //GETC - if B != 0 { - // +inline-call reg.Set RA LTrue - } else { - // +inline-call reg.Set RA LFalse - } - if C != 0 { - cf.Pc++ - } - case OP_LOADNIL: - A := int(inst>>18) & 0xff //GETA - RA := lbase + A - B := int(inst & 0x1ff) //GETB - for i := RA; i <= lbase+B; i++ { - // +inline-call reg.Set i LNil - } - case OP_GETUPVAL: - reg := L.reg + for L.ctx == nil || L.ctx.Err() == nil { cf := L.currentFrame + inst := cf.Fn.Proto.Code[cf.Pc] lbase := cf.LocalBase - A := int(inst>>18) & 0xff //GETA - RA := lbase + A - B := int(inst & 0x1ff) //GETB - v := cf.Fn.Upvalues[B].Value() - // +inline-call reg.Set RA v - case OP_GETGLOBAL: - A := int(inst>>18) & 0xff //GETA - RA := lbase + A - Bx := int(inst & 0x3ffff) //GETBX - //reg.Set(RA, L.getField(cf.Fn.Env, cf.Fn.Proto.Constants[Bx])) - v := L.getFieldString(cf.Fn.Env, cf.Fn.Proto.stringConstants[Bx]) - // +inline-call reg.Set RA v - case OP_GETTABLE: - A := int(inst>>18) & 0xff //GETA - RA := lbase + A - B := int(inst & 0x1ff) //GETB - C := int(inst>>9) & 0x1ff //GETC - v := L.getField(reg.Get(lbase+B), L.rkValue(C)) - // +inline-call reg.Set RA v - case OP_GETTABLEKS: - A := int(inst>>18) & 0xff //GETA - RA := lbase + A - B := int(inst & 0x1ff) //GETB - C := int(inst>>9) & 0x1ff //GETC - v := L.getFieldString(reg.Get(lbase+B), L.rkString(C)) - // +inline-call reg.Set RA v - case OP_SETGLOBAL: - A := int(inst>>18) & 0xff //GETA - RA := lbase + A - Bx := int(inst & 0x3ffff) //GETBX - //L.setField(cf.Fn.Env, cf.Fn.Proto.Constants[Bx], reg.Get(RA)) - L.setFieldString(cf.Fn.Env, cf.Fn.Proto.stringConstants[Bx], reg.Get(RA)) - case OP_SETUPVAL: - A := int(inst>>18) & 0xff //GETA - RA := lbase + A - B := int(inst & 0x1ff) //GETB - cf.Fn.Upvalues[B].SetValue(reg.Get(RA)) - case OP_SETTABLE: - A := int(inst>>18) & 0xff //GETA - RA := lbase + A - B := int(inst & 0x1ff) //GETB - C := int(inst>>9) & 0x1ff //GETC - L.setField(reg.Get(RA), L.rkValue(B), L.rkValue(C)) - case OP_SETTABLEKS: - A := int(inst>>18) & 0xff //GETA - RA := lbase + A - B := int(inst & 0x1ff) //GETB - C := int(inst>>9) & 0x1ff //GETC - L.setFieldString(reg.Get(RA), L.rkString(B), L.rkValue(C)) - case OP_NEWTABLE: - A := int(inst>>18) & 0xff //GETA - RA := lbase + A - B := int(inst & 0x1ff) //GETB - C := int(inst>>9) & 0x1ff //GETC - v := newLTable(B, C) - // +inline-call reg.Set RA v - case OP_SELF: - A := int(inst>>18) & 0xff //GETA - RA := lbase + A - B := int(inst & 0x1ff) //GETB - C := int(inst>>9) & 0x1ff //GETC - selfobj := reg.Get(lbase + B) - v := L.getFieldString(selfobj, L.rkString(C)) - // +inline-call reg.Set RA v - // +inline-call reg.Set RA+1 selfobj - case OP_ADD, OP_SUB, OP_MUL, OP_DIV, OP_MOD, OP_POW: - A := int(inst>>18) & 0xff //GETA - RA := lbase + A - B := int(inst & 0x1ff) //GETB - C := int(inst>>9) & 0x1ff //GETC - lhs := L.rkValue(B) - rhs := L.rkValue(C) - v1, ok1 := lhs.(LNumber) - v2, ok2 := rhs.(LNumber) - if ok1 && ok2 { - v := numberArith(L, opcode, LNumber(v1), LNumber(v2)) - // +inline-call reg.SetNumber RA v - } else { - v := objectArith(L, opcode, lhs, rhs) + cf.Pc++ + + opcode := int(inst >> 26) + switch opcode { + case OP_MOVE: + A := int(inst>>18) & 0xff //GETA + RA := lbase + A + B := int(inst & 0x1ff) //GETB + v := reg.Get(lbase + B) // +inline-call reg.Set RA v - } + case OP_MOVEN: + A := int(inst>>18) & 0xff //GETA + B := int(inst & 0x1ff) //GETB + C := int(inst>>9) & 0x1ff //GETC + v := reg.Get(lbase + B) + // +inline-call reg.Set lbase+A v + code := cf.Fn.Proto.Code + pc := cf.Pc + for i := 0; i < C; i++ { + inst = code[pc] + pc++ + A = int(inst>>18) & 0xff //GETA + B = int(inst & 0x1ff) //GETB + v := reg.Get(lbase + B) + // +inline-call reg.Set lbase+A v + } + cf.Pc = pc + case OP_LOADK: + A := int(inst>>18) & 0xff //GETA + RA := lbase + A + Bx := int(inst & 0x3ffff) //GETBX + v := cf.Fn.Proto.Constants[Bx] + // +inline-call reg.Set RA v + case OP_LOADBOOL: + A := int(inst>>18) & 0xff //GETA + RA := lbase + A + B := int(inst & 0x1ff) //GETB + C := int(inst>>9) & 0x1ff //GETC + if B != 0 { + // +inline-call reg.Set RA LTrue + } else { + // +inline-call reg.Set RA LFalse + } + if C != 0 { + cf.Pc++ + } + case OP_LOADNIL: + A := int(inst>>18) & 0xff //GETA + RA := lbase + A + B := int(inst & 0x1ff) //GETB + for i := RA; i <= lbase+B; i++ { + // +inline-call reg.Set i LNil + } + case OP_GETUPVAL: + A := int(inst>>18) & 0xff //GETA + RA := lbase + A + B := int(inst & 0x1ff) //GETB + v := cf.Fn.Upvalues[B].Value() + // +inline-call reg.Set RA v + case OP_GETGLOBAL: + A := int(inst>>18) & 0xff //GETA + RA := lbase + A + Bx := int(inst & 0x3ffff) //GETBX + //reg.Set(RA, L.getField(cf.Fn.Env, cf.Fn.Proto.Constants[Bx])) + v := L.getFieldString(cf.Fn.Env, cf.Fn.Proto.stringConstants[Bx]) + // +inline-call reg.Set RA v + case OP_GETTABLE: + A := int(inst>>18) & 0xff //GETA + RA := lbase + A + B := int(inst & 0x1ff) //GETB + C := int(inst>>9) & 0x1ff //GETC + v := L.getField(reg.Get(lbase+B), L.rkValue(C)) + // +inline-call reg.Set RA v + case OP_GETTABLEKS: + A := int(inst>>18) & 0xff //GETA + RA := lbase + A + B := int(inst & 0x1ff) //GETB + C := int(inst>>9) & 0x1ff //GETC + v := L.getFieldString(reg.Get(lbase+B), L.rkString(C)) + // +inline-call reg.Set RA v + case OP_SETGLOBAL: + A := int(inst>>18) & 0xff //GETA + RA := lbase + A + Bx := int(inst & 0x3ffff) //GETBX + //L.setField(cf.Fn.Env, cf.Fn.Proto.Constants[Bx], reg.Get(RA)) + L.setFieldString(cf.Fn.Env, cf.Fn.Proto.stringConstants[Bx], reg.Get(RA)) + case OP_SETUPVAL: + A := int(inst>>18) & 0xff //GETA + RA := lbase + A + B := int(inst & 0x1ff) //GETB + cf.Fn.Upvalues[B].SetValue(reg.Get(RA)) + case OP_SETTABLE: + A := int(inst>>18) & 0xff //GETA + RA := lbase + A + B := int(inst & 0x1ff) //GETB + C := int(inst>>9) & 0x1ff //GETC + L.setField(reg.Get(RA), L.rkValue(B), L.rkValue(C)) + case OP_SETTABLEKS: + A := int(inst>>18) & 0xff //GETA + RA := lbase + A + B := int(inst & 0x1ff) //GETB + C := int(inst>>9) & 0x1ff //GETC + L.setFieldString(reg.Get(RA), L.rkString(B), L.rkValue(C)) + case OP_NEWTABLE: + A := int(inst>>18) & 0xff //GETA + RA := lbase + A + B := int(inst & 0x1ff) //GETB + C := int(inst>>9) & 0x1ff //GETC + v := newLTable(B, C) + // +inline-call reg.Set RA v + case OP_SELF: + A := int(inst>>18) & 0xff //GETA + RA := lbase + A + B := int(inst & 0x1ff) //GETB + C := int(inst>>9) & 0x1ff //GETC + selfobj := reg.Get(lbase + B) + v := L.getFieldString(selfobj, L.rkString(C)) + // +inline-call reg.Set RA v + // +inline-call reg.Set RA+1 selfobj + case OP_ADD, OP_SUB, OP_MUL, OP_DIV, OP_MOD, OP_POW: + A := int(inst>>18) & 0xff //GETA + RA := lbase + A + B := int(inst & 0x1ff) //GETB + C := int(inst>>9) & 0x1ff //GETC + lhs := L.rkValue(B) + rhs := L.rkValue(C) + v1, ok1 := lhs.(LNumber) + v2, ok2 := rhs.(LNumber) + if ok1 && ok2 { + v := numberArith(L, opcode, LNumber(v1), LNumber(v2)) + // +inline-call reg.SetNumber RA v + } else { + v := objectArith(L, opcode, lhs, rhs) + // +inline-call reg.Set RA v + } - case OP_UNM: - A := int(inst>>18) & 0xff //GETA - RA := lbase + A - B := int(inst & 0x1ff) //GETB - unaryv := L.rkValue(B) - if nm, ok := unaryv.(LNumber); ok { - // +inline-call reg.Set RA -nm - } else { - op := L.metaOp1(unaryv, "__unm") - if op.Type() == LTFunction { - reg.Push(op) - reg.Push(unaryv) - L.Call(1, 1) - // +inline-call reg.Set RA reg.Pop() - } else if str, ok1 := unaryv.(LString); ok1 { - if num, err := parseNumber(string(str)); err == nil { - // +inline-call reg.Set RA -num + case OP_UNM: + A := int(inst>>18) & 0xff //GETA + RA := lbase + A + B := int(inst & 0x1ff) //GETB + unaryv := L.rkValue(B) + if nm, ok := unaryv.(LNumber); ok { + // +inline-call reg.Set RA -nm + } else { + op := L.metaOp1(unaryv, "__unm") + if op.Type() == LTFunction { + reg.Push(op) + reg.Push(unaryv) + L.Call(1, 1) + // +inline-call reg.Set RA reg.Pop() + } else if str, ok1 := unaryv.(LString); ok1 { + if num, err := parseNumber(string(str)); err == nil { + // +inline-call reg.Set RA -num + } else { + L.RaiseError("__unm undefined") + } } else { L.RaiseError("__unm undefined") } + } + case OP_NOT: + A := int(inst>>18) & 0xff //GETA + RA := lbase + A + B := int(inst & 0x1ff) //GETB + if LVIsFalse(reg.Get(lbase + B)) { + // +inline-call reg.Set RA LTrue } else { - L.RaiseError("__unm undefined") + // +inline-call reg.Set RA LFalse } - } - case OP_NOT: - A := int(inst>>18) & 0xff //GETA - RA := lbase + A - B := int(inst & 0x1ff) //GETB - if LVIsFalse(reg.Get(lbase + B)) { - // +inline-call reg.Set RA LTrue - } else { - // +inline-call reg.Set RA LFalse - } - case OP_LEN: - A := int(inst>>18) & 0xff //GETA - RA := lbase + A - B := int(inst & 0x1ff) //GETB - switch lv := L.rkValue(B).(type) { - case LString: - // +inline-call reg.SetNumber RA LNumber(len(lv)) - default: - op := L.metaOp1(lv, "__len") - if op.Type() == LTFunction { - reg.Push(op) - reg.Push(lv) - L.Call(1, 1) - ret := reg.Pop() - if ret.Type() == LTNumber { - v, _ := ret.(LNumber) - // +inline-call reg.SetNumber RA v + case OP_LEN: + A := int(inst>>18) & 0xff //GETA + RA := lbase + A + B := int(inst & 0x1ff) //GETB + switch lv := L.rkValue(B).(type) { + case LString: + // +inline-call reg.SetNumber RA LNumber(len(lv)) + default: + op := L.metaOp1(lv, "__len") + if op.Type() == LTFunction { + reg.Push(op) + reg.Push(lv) + L.Call(1, 1) + ret := reg.Pop() + if ret.Type() == LTNumber { + v, _ := ret.(LNumber) + // +inline-call reg.SetNumber RA v + } else { + // +inline-call reg.Set RA ret + } + } else if lv.Type() == LTTable { + // +inline-call reg.SetNumber RA LNumber(lv.(*LTable).Len()) } else { - // +inline-call reg.Set RA ret + L.RaiseError("__len undefined") + } + } + case OP_CONCAT: + A := int(inst>>18) & 0xff //GETA + RA := lbase + A + B := int(inst & 0x1ff) //GETB + C := int(inst>>9) & 0x1ff //GETC + RC := lbase + C + RB := lbase + B + v := stringConcat(L, RC-RB+1, RC) + // +inline-call reg.Set RA v + case OP_JMP: + Sbx := int(inst&0x3ffff) - opMaxArgSbx //GETSBX + cf.Pc += Sbx + case OP_EQ: + A := int(inst>>18) & 0xff //GETA + B := int(inst & 0x1ff) //GETB + C := int(inst>>9) & 0x1ff //GETC + ret := equals(L, L.rkValue(B), L.rkValue(C), false) + v := 1 + if ret { + v = 0 + } + if v == A { + cf.Pc++ + } + case OP_LT: + A := int(inst>>18) & 0xff //GETA + B := int(inst & 0x1ff) //GETB + C := int(inst>>9) & 0x1ff //GETC + ret := lessThan(L, L.rkValue(B), L.rkValue(C)) + v := 1 + if ret { + v = 0 + } + if v == A { + cf.Pc++ + } + case OP_LE: + A := int(inst>>18) & 0xff //GETA + B := int(inst & 0x1ff) //GETB + C := int(inst>>9) & 0x1ff //GETC + lhs := L.rkValue(B) + rhs := L.rkValue(C) + ret := false + + if v1, ok1 := lhs.(LNumber); ok1 { + if v2, ok2 := rhs.(LNumber); ok2 { + ret = v1 <= v2 + } else { + L.RaiseError("attempt to compare %v with %v", lhs.Type().String(), rhs.Type().String()) } - } else if lv.Type() == LTTable { - // +inline-call reg.SetNumber RA LNumber(lv.(*LTable).Len()) } else { - L.RaiseError("__len undefined") + if lhs.Type() != rhs.Type() { + L.RaiseError("attempt to compare %v with %v", lhs.Type().String(), rhs.Type().String()) + } + switch lhs.Type() { + case LTString: + ret = strCmp(string(lhs.(LString)), string(rhs.(LString))) <= 0 + default: + switch objectRational(L, lhs, rhs, "__le") { + case 1: + ret = true + case 0: + ret = false + default: + ret = !objectRationalWithError(L, rhs, lhs, "__lt") + } + } } - } - case OP_CONCAT: - A := int(inst>>18) & 0xff //GETA - RA := lbase + A - B := int(inst & 0x1ff) //GETB - C := int(inst>>9) & 0x1ff //GETC - RC := lbase + C - RB := lbase + B - v := stringConcat(L, RC-RB+1, RC) - // +inline-call reg.Set RA v - case OP_JMP: - cf := L.currentFrame - Sbx := int(inst&0x3ffff) - opMaxArgSbx //GETSBX - cf.Pc += Sbx - case OP_EQ: - cf := L.currentFrame - A := int(inst>>18) & 0xff //GETA - B := int(inst & 0x1ff) //GETB - C := int(inst>>9) & 0x1ff //GETC - ret := equals(L, L.rkValue(B), L.rkValue(C), false) - v := 1 - if ret { - v = 0 - } - if v == A { - cf.Pc++ - } - case OP_LT: - A := int(inst>>18) & 0xff //GETA - B := int(inst & 0x1ff) //GETB - C := int(inst>>9) & 0x1ff //GETC - ret := lessThan(L, L.rkValue(B), L.rkValue(C)) - v := 1 - if ret { - v = 0 - } - if v == A { - cf.Pc++ - } - case OP_LE: - A := int(inst>>18) & 0xff //GETA - B := int(inst & 0x1ff) //GETB - C := int(inst>>9) & 0x1ff //GETC - lhs := L.rkValue(B) - rhs := L.rkValue(C) - ret := false - if v1, ok1 := lhs.(LNumber); ok1 { - if v2, ok2 := rhs.(LNumber); ok2 { - ret = v1 <= v2 + v := 1 + if ret { + v = 0 + } + if v == A { + cf.Pc++ + } + case OP_TEST: + A := int(inst>>18) & 0xff //GETA + RA := lbase + A + C := int(inst>>9) & 0x1ff //GETC + if LVAsBool(reg.Get(RA)) == (C == 0) { + cf.Pc++ + } + case OP_TESTSET: + A := int(inst>>18) & 0xff //GETA + RA := lbase + A + B := int(inst & 0x1ff) //GETB + C := int(inst>>9) & 0x1ff //GETC + if value := reg.Get(lbase + B); LVAsBool(value) != (C == 0) { + // +inline-call reg.Set RA value } else { - L.RaiseError("attempt to compare %v with %v", lhs.Type().String(), rhs.Type().String()) + cf.Pc++ } - } else { - if lhs.Type() != rhs.Type() { - L.RaiseError("attempt to compare %v with %v", lhs.Type().String(), rhs.Type().String()) + case OP_CALL: + A := int(inst>>18) & 0xff //GETA + RA := lbase + A + B := int(inst & 0x1ff) //GETB + C := int(inst>>9) & 0x1ff //GETC + nargs := B - 1 + if B == 0 { + nargs = reg.Top() - (RA + 1) } - switch lhs.Type() { - case LTString: - ret = strCmp(string(lhs.(LString)), string(rhs.(LString))) <= 0 - default: - switch objectRational(L, lhs, rhs, "__le") { - case 1: - ret = true - case 0: - ret = false - default: - ret = !objectRationalWithError(L, rhs, lhs, "__lt") + lv := reg.Get(RA) + nret := C - 1 + var callable *LFunction + var meta bool + if fn, ok := lv.(*LFunction); ok { + callable = fn + meta = false + } else { + callable, meta = L.metaCall(lv) + } + // +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 + if callable.IsG && callGFunction(L, false) { + return + } + case OP_TAILCALL: + A := int(inst>>18) & 0xff //GETA + RA := lbase + A + B := int(inst & 0x1ff) //GETB + nargs := B - 1 + if B == 0 { + nargs = reg.Top() - (RA + 1) + } + lv := reg.Get(RA) + var callable *LFunction + var meta bool + if fn, ok := lv.(*LFunction); ok { + callable = fn + meta = false + } else { + callable, meta = L.metaCall(lv) + } + if callable == nil { + L.RaiseError("attempt to call a non-function object") + } + // +inline-call L.closeUpvalues lbase + if callable.IsG { + luaframe := cf + L.pushCallFrame(callFrame{ + Fn: callable, + Pc: 0, + Base: RA, + LocalBase: RA + 1, + ReturnBase: cf.ReturnBase, + NArgs: nargs, + NRet: cf.NRet, + Parent: cf, + TailCall: 0, + }, lv, meta) + if callGFunction(L, true) { + return + } + if L.currentFrame == nil || L.currentFrame.Fn.IsG || luaframe == baseframe { + return + } + } else { + base := cf.Base + cf.Fn = callable + cf.Pc = 0 + cf.Base = RA + cf.LocalBase = RA + 1 + cf.ReturnBase = cf.ReturnBase + cf.NArgs = nargs + cf.NRet = cf.NRet + cf.TailCall++ + lbase := cf.LocalBase + if meta { + cf.NArgs++ + L.reg.Insert(lv, cf.LocalBase) } + // +inline-call L.initCallFrame cf + // +inline-call L.reg.CopyRange base RA -1 reg.Top()-RA-1 + cf.Base = base + cf.LocalBase = base + (cf.LocalBase - lbase + 1) } - } - - v := 1 - if ret { - v = 0 - } - if v == A { - cf.Pc++ - } - case OP_TEST: - A := int(inst>>18) & 0xff //GETA - RA := lbase + A - C := int(inst>>9) & 0x1ff //GETC - if LVAsBool(reg.Get(RA)) == (C == 0) { - cf.Pc++ - } - case OP_TESTSET: - A := int(inst>>18) & 0xff //GETA - RA := lbase + A - B := int(inst & 0x1ff) //GETB - C := int(inst>>9) & 0x1ff //GETC - if value := reg.Get(lbase + B); LVAsBool(value) != (C == 0) { - // +inline-call reg.Set RA value - } else { - cf.Pc++ - } - case OP_CALL: - A := int(inst>>18) & 0xff //GETA - RA := lbase + A - B := int(inst & 0x1ff) //GETB - C := int(inst>>9) & 0x1ff //GETC - nargs := B - 1 - if B == 0 { - nargs = reg.Top() - (RA + 1) - } - lv := reg.Get(RA) - nret := C - 1 - var callable *LFunction - var meta bool - if fn, ok := lv.(*LFunction); ok { - callable = fn - meta = false - } else { - callable, meta = L.metaCall(lv) - } - // +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 - if callable.IsG && callGFunction(L, false) { - return true - } - case OP_TAILCALL: - reg := L.reg - cf := L.currentFrame - lbase := cf.LocalBase - A := int(inst>>18) & 0xff //GETA - RA := lbase + A - B := int(inst & 0x1ff) //GETB - nargs := B - 1 - if B == 0 { - nargs = reg.Top() - (RA + 1) - } - lv := reg.Get(RA) - var callable *LFunction - var meta bool - if fn, ok := lv.(*LFunction); ok { - callable = fn - meta = false - } else { - callable, meta = L.metaCall(lv) - } - if callable == nil { - L.RaiseError("attempt to call a non-function object") - } - // +inline-call L.closeUpvalues lbase - if callable.IsG { - luaframe := cf - L.pushCallFrame(callFrame{ - Fn: callable, - Pc: 0, - Base: RA, - LocalBase: RA + 1, - ReturnBase: cf.ReturnBase, - NArgs: nargs, - NRet: cf.NRet, - Parent: cf, - TailCall: 0, - }, lv, meta) - if callGFunction(L, true) { - return true - } - if L.currentFrame == nil || L.currentFrame.Fn.IsG || luaframe == baseframe { - return true + case OP_RETURN: + A := int(inst>>18) & 0xff //GETA + RA := lbase + A + B := int(inst & 0x1ff) //GETB + // +inline-call L.closeUpvalues lbase + nret := B - 1 + if B == 0 { + nret = reg.Top() - RA + } + n := cf.NRet + if cf.NRet == MultRet { + n = nret } - } else { - base := cf.Base - cf.Fn = callable - cf.Pc = 0 - cf.Base = RA - cf.LocalBase = RA + 1 - cf.ReturnBase = cf.ReturnBase - cf.NArgs = nargs - cf.NRet = cf.NRet - cf.TailCall++ - lbase := cf.LocalBase - if meta { - cf.NArgs++ - L.reg.Insert(lv, cf.LocalBase) - } - // +inline-call L.initCallFrame cf - // +inline-call L.reg.CopyRange base RA -1 reg.Top()-RA-1 - cf.Base = base - cf.LocalBase = base + (cf.LocalBase - lbase + 1) - } - case OP_RETURN: - A := int(inst>>18) & 0xff //GETA - RA := lbase + A - B := int(inst & 0x1ff) //GETB - // +inline-call L.closeUpvalues lbase - nret := B - 1 - if B == 0 { - nret = reg.Top() - RA - } - n := cf.NRet - if cf.NRet == MultRet { - n = nret - } - if L.Parent != nil && L.stack.Sp() == 1 { - // +inline-call copyReturnValues L reg.Top() RA n B - switchToParentThread(L, n, false, true) - return true - } - islast := baseframe == L.stack.Pop() || L.stack.IsEmpty() - // +inline-call copyReturnValues L cf.ReturnBase RA n B - L.currentFrame = L.stack.Last() - if islast || L.currentFrame == nil || L.currentFrame.Fn.IsG { - return true - } - case OP_FORLOOP: - A := int(inst>>18) & 0xff //GETA - RA := lbase + A - if init, ok1 := reg.Get(RA).(LNumber); ok1 { - if limit, ok2 := reg.Get(RA + 1).(LNumber); ok2 { - if step, ok3 := reg.Get(RA + 2).(LNumber); ok3 { - init += step - v := LNumber(init) - // +inline-call reg.SetNumber RA v - if (step > 0 && init <= limit) || (step <= 0 && init >= limit) { - Sbx := int(inst&0x3ffff) - opMaxArgSbx //GETSBX - cf.Pc += Sbx - // +inline-call reg.SetNumber RA+3 v + if L.Parent != nil && L.stack.Sp() == 1 { + // +inline-call copyReturnValues L reg.Top() RA n B + switchToParentThread(L, n, false, true) + return + } + islast := baseframe == L.stack.Pop() || L.stack.IsEmpty() + // +inline-call copyReturnValues L cf.ReturnBase RA n B + L.currentFrame = L.stack.Last() + if islast || L.currentFrame == nil || L.currentFrame.Fn.IsG { + return + } + case OP_FORLOOP: + A := int(inst>>18) & 0xff //GETA + RA := lbase + A + if init, ok1 := reg.Get(RA).(LNumber); ok1 { + if limit, ok2 := reg.Get(RA + 1).(LNumber); ok2 { + if step, ok3 := reg.Get(RA + 2).(LNumber); ok3 { + init += step + v := LNumber(init) + // +inline-call reg.SetNumber RA v + if (step > 0 && init <= limit) || (step <= 0 && init >= limit) { + Sbx := int(inst&0x3ffff) - opMaxArgSbx //GETSBX + cf.Pc += Sbx + // +inline-call reg.SetNumber RA+3 v + } else { + // +inline-call reg.SetTop RA+1 + } } else { - // +inline-call reg.SetTop RA+1 + L.RaiseError("for statement step must be a number") } } else { - L.RaiseError("for statement step must be a number") + L.RaiseError("for statement limit must be a number") } } else { - L.RaiseError("for statement limit must be a number") + L.RaiseError("for statement init must be a number") } - } else { - L.RaiseError("for statement init must be a number") - } - case OP_FORPREP: - A := int(inst>>18) & 0xff //GETA - RA := lbase + A - Sbx := int(inst&0x3ffff) - opMaxArgSbx //GETSBX - if init, ok1 := reg.Get(RA).(LNumber); ok1 { - if step, ok2 := reg.Get(RA + 2).(LNumber); ok2 { - // +inline-call reg.SetNumber RA LNumber(init-step) + case OP_FORPREP: + A := int(inst>>18) & 0xff //GETA + RA := lbase + A + Sbx := int(inst&0x3ffff) - opMaxArgSbx //GETSBX + if init, ok1 := reg.Get(RA).(LNumber); ok1 { + if step, ok2 := reg.Get(RA + 2).(LNumber); ok2 { + // +inline-call reg.SetNumber RA LNumber(init-step) + } else { + L.RaiseError("for statement step must be a number") + } } else { - L.RaiseError("for statement step must be a number") + L.RaiseError("for statement init must be a number") + } + cf.Pc += Sbx + case OP_TFORLOOP: + A := int(inst>>18) & 0xff //GETA + RA := lbase + A + C := int(inst>>9) & 0x1ff //GETC + nret := C + // +inline-call reg.SetTop RA+3+2 + // +inline-call reg.Set RA+3+2 reg.Get(RA+2) + // +inline-call reg.Set RA+3+1 reg.Get(RA+1) + // +inline-call reg.Set RA+3 reg.Get(RA) + L.callR(2, nret, RA+3) + if value := reg.Get(RA + 3); value != LNil { + // +inline-call reg.Set RA+2 value + pc := cf.Fn.Proto.Code[cf.Pc] + cf.Pc += int(pc&0x3ffff) - opMaxArgSbx } - } else { - L.RaiseError("for statement init must be a number") - } - cf.Pc += Sbx - case OP_TFORLOOP: - A := int(inst>>18) & 0xff //GETA - RA := lbase + A - C := int(inst>>9) & 0x1ff //GETC - nret := C - // +inline-call reg.SetTop RA+3+2 - // +inline-call reg.Set RA+3+2 reg.Get(RA+2) - // +inline-call reg.Set RA+3+1 reg.Get(RA+1) - // +inline-call reg.Set RA+3 reg.Get(RA) - L.callR(2, nret, RA+3) - if value := reg.Get(RA + 3); value != LNil { - // +inline-call reg.Set RA+2 value - pc := cf.Fn.Proto.Code[cf.Pc] - cf.Pc += int(pc&0x3ffff) - opMaxArgSbx - } - cf.Pc++ - case OP_SETLIST: - A := int(inst>>18) & 0xff //GETA - RA := lbase + A - B := int(inst & 0x1ff) //GETB - C := int(inst>>9) & 0x1ff //GETC - if C == 0 { - C = int(cf.Fn.Proto.Code[cf.Pc]) - cf.Pc++ - } - offset := (C - 1) * FieldsPerFlush - table := reg.Get(RA).(*LTable) - nelem := B - if B == 0 { - nelem = reg.Top() - RA - 1 - } - for i := 1; i <= nelem; i++ { - table.RawSetInt(offset+i, reg.Get(RA+i)) - } - case OP_CLOSE: - A := int(inst>>18) & 0xff //GETA - RA := lbase + A - // +inline-call L.closeUpvalues RA - case OP_CLOSURE: - A := int(inst>>18) & 0xff //GETA - RA := lbase + A - Bx := int(inst & 0x3ffff) //GETBX - proto := cf.Fn.Proto.FunctionPrototypes[Bx] - closure := newLFunctionL(proto, cf.Fn.Env, int(proto.NumUpvalues)) - // +inline-call reg.Set RA closure - for i := 0; i < int(proto.NumUpvalues); i++ { - inst = cf.Fn.Proto.Code[cf.Pc] cf.Pc++ - B := opGetArgB(inst) - switch opGetOpCode(inst) { - case OP_MOVE: - closure.Upvalues[i] = L.findUpvalue(lbase + B) - case OP_GETUPVAL: - closure.Upvalues[i] = cf.Fn.Upvalues[B] + case OP_SETLIST: + A := int(inst>>18) & 0xff //GETA + RA := lbase + A + B := int(inst & 0x1ff) //GETB + C := int(inst>>9) & 0x1ff //GETC + if C == 0 { + C = int(cf.Fn.Proto.Code[cf.Pc]) + cf.Pc++ } - } - case OP_VARARG: - A := int(inst>>18) & 0xff //GETA - RA := lbase + A - B := int(inst & 0x1ff) //GETB - nparams := int(cf.Fn.Proto.NumParameters) - nvarargs := cf.NArgs - nparams - if nvarargs < 0 { - nvarargs = 0 - } - nwant := B - 1 - if B == 0 { - nwant = nvarargs - } - // +inline-call reg.CopyRange RA cf.Base+nparams+1 cf.LocalBase nwant - case OP_NOP: - } - return false -} - -func mainLoop(L *LState, baseframe *callFrame) { - var inst uint32 - var cf *callFrame - - if L.stack.IsEmpty() { - return - } - - L.currentFrame = L.stack.Last() - if L.currentFrame.Fn.IsG { - callGFunction(L, false) - return - } - - for L.ctx == nil || L.ctx.Err() == nil { - cf = L.currentFrame - inst = cf.Fn.Proto.Code[cf.Pc] - cf.Pc++ - if evalInstruction(L, inst, baseframe) { - return + offset := (C - 1) * FieldsPerFlush + table := reg.Get(RA).(*LTable) + nelem := B + if B == 0 { + nelem = reg.Top() - RA - 1 + } + for i := 1; i <= nelem; i++ { + table.RawSetInt(offset+i, reg.Get(RA+i)) + } + case OP_CLOSE: + A := int(inst>>18) & 0xff //GETA + RA := lbase + A + // +inline-call L.closeUpvalues RA + case OP_CLOSURE: + A := int(inst>>18) & 0xff //GETA + RA := lbase + A + Bx := int(inst & 0x3ffff) //GETBX + proto := cf.Fn.Proto.FunctionPrototypes[Bx] + closure := newLFunctionL(proto, cf.Fn.Env, int(proto.NumUpvalues)) + // +inline-call reg.Set RA closure + for i := 0; i < int(proto.NumUpvalues); i++ { + inst = cf.Fn.Proto.Code[cf.Pc] + cf.Pc++ + B := opGetArgB(inst) + switch opGetOpCode(inst) { + case OP_MOVE: + closure.Upvalues[i] = L.findUpvalue(lbase + B) + case OP_GETUPVAL: + closure.Upvalues[i] = cf.Fn.Upvalues[B] + } + } + case OP_VARARG: + A := int(inst>>18) & 0xff //GETA + RA := lbase + A + B := int(inst & 0x1ff) //GETB + nparams := int(cf.Fn.Proto.NumParameters) + nvarargs := cf.NArgs - nparams + if nvarargs < 0 { + nvarargs = 0 + } + nwant := B - 1 + if B == 0 { + nwant = nvarargs + } + // +inline-call reg.CopyRange RA cf.Base+nparams+1 cf.LocalBase nwant + case OP_NOP: } } diff --git a/vm.go b/vm.go index 2894f586..4d96c004 100644 --- a/vm.go +++ b/vm.go @@ -9,17 +9,31 @@ import ( "strings" ) -func evalInstruction(L *LState, inst uint32, baseframe *callFrame) bool { +func mainLoop(L *LState, baseframe *callFrame) { + if L.stack.IsEmpty() { + return + } + + L.currentFrame = L.stack.Last() + if L.currentFrame.Fn.IsG { + callGFunction(L, false) + return + } + reg := L.reg - cf := L.currentFrame - lbase := cf.LocalBase - opcode := int(inst >> 26) - switch opcode { - case OP_MOVE: - A := int(inst>>18) & 0xff //GETA - RA := lbase + A - B := int(inst & 0x1ff) //GETB - v := reg.Get(lbase + B) + for L.ctx == nil || L.ctx.Err() == nil { + cf := L.currentFrame + inst := cf.Fn.Proto.Code[cf.Pc] + lbase := cf.LocalBase + cf.Pc++ + + opcode := int(inst >> 26) + switch opcode { + case OP_MOVE: + A := int(inst>>18) & 0xff //GETA + RA := lbase + A + B := int(inst & 0x1ff) //GETB + v := reg.Get(lbase + B) // this section is inlined by go-inline // source function is 'func (rg *registry) Set(regi int, vali LValue) ' in '_state.go' { @@ -40,11 +54,11 @@ requiredSize := newSize rg.top = regi + 1 } } - case OP_MOVEN: - A := int(inst>>18) & 0xff //GETA - B := int(inst & 0x1ff) //GETB - C := int(inst>>9) & 0x1ff //GETC - v := reg.Get(lbase + B) + case OP_MOVEN: + A := int(inst>>18) & 0xff //GETA + B := int(inst & 0x1ff) //GETB + C := int(inst>>9) & 0x1ff //GETC + v := reg.Get(lbase + B) // this section is inlined by go-inline // source function is 'func (rg *registry) Set(regi int, vali LValue) ' in '_state.go' { @@ -65,14 +79,14 @@ requiredSize := newSize rg.top = regi + 1 } } - code := cf.Fn.Proto.Code - pc := cf.Pc - for i := 0; i < C; i++ { - inst = code[pc] - pc++ - A = int(inst>>18) & 0xff //GETA - B = int(inst & 0x1ff) //GETB - v := reg.Get(lbase + B) + code := cf.Fn.Proto.Code + pc := cf.Pc + for i := 0; i < C; i++ { + inst = code[pc] + pc++ + A = int(inst>>18) & 0xff //GETA + B = int(inst & 0x1ff) //GETB + v := reg.Get(lbase + B) // this section is inlined by go-inline // source function is 'func (rg *registry) Set(regi int, vali LValue) ' in '_state.go' { @@ -93,13 +107,13 @@ requiredSize := newSize rg.top = regi + 1 } } - } - cf.Pc = pc - case OP_LOADK: - A := int(inst>>18) & 0xff //GETA - RA := lbase + A - Bx := int(inst & 0x3ffff) //GETBX - v := cf.Fn.Proto.Constants[Bx] + } + cf.Pc = pc + case OP_LOADK: + A := int(inst>>18) & 0xff //GETA + RA := lbase + A + Bx := int(inst & 0x3ffff) //GETBX + v := cf.Fn.Proto.Constants[Bx] // this section is inlined by go-inline // source function is 'func (rg *registry) Set(regi int, vali LValue) ' in '_state.go' { @@ -120,12 +134,12 @@ requiredSize := newSize rg.top = regi + 1 } } - case OP_LOADBOOL: - A := int(inst>>18) & 0xff //GETA - RA := lbase + A - B := int(inst & 0x1ff) //GETB - C := int(inst>>9) & 0x1ff //GETC - if B != 0 { + case OP_LOADBOOL: + A := int(inst>>18) & 0xff //GETA + RA := lbase + A + B := int(inst & 0x1ff) //GETB + C := int(inst>>9) & 0x1ff //GETC + if B != 0 { // this section is inlined by go-inline // source function is 'func (rg *registry) Set(regi int, vali LValue) ' in '_state.go' { @@ -146,7 +160,7 @@ requiredSize := newSize rg.top = regi + 1 } } - } else { + } else { // this section is inlined by go-inline // source function is 'func (rg *registry) Set(regi int, vali LValue) ' in '_state.go' { @@ -167,15 +181,15 @@ requiredSize := newSize rg.top = regi + 1 } } - } - if C != 0 { - cf.Pc++ - } - case OP_LOADNIL: - A := int(inst>>18) & 0xff //GETA - RA := lbase + A - B := int(inst & 0x1ff) //GETB - for i := RA; i <= lbase+B; i++ { + } + if C != 0 { + cf.Pc++ + } + case OP_LOADNIL: + A := int(inst>>18) & 0xff //GETA + RA := lbase + A + B := int(inst & 0x1ff) //GETB + for i := RA; i <= lbase+B; i++ { // this section is inlined by go-inline // source function is 'func (rg *registry) Set(regi int, vali LValue) ' in '_state.go' { @@ -196,15 +210,12 @@ requiredSize := newSize rg.top = regi + 1 } } - } - case OP_GETUPVAL: - reg := L.reg - cf := L.currentFrame - lbase := cf.LocalBase - A := int(inst>>18) & 0xff //GETA - RA := lbase + A - B := int(inst & 0x1ff) //GETB - v := cf.Fn.Upvalues[B].Value() + } + case OP_GETUPVAL: + A := int(inst>>18) & 0xff //GETA + RA := lbase + A + B := int(inst & 0x1ff) //GETB + v := cf.Fn.Upvalues[B].Value() // this section is inlined by go-inline // source function is 'func (rg *registry) Set(regi int, vali LValue) ' in '_state.go' { @@ -225,12 +236,12 @@ requiredSize := newSize rg.top = regi + 1 } } - case OP_GETGLOBAL: - A := int(inst>>18) & 0xff //GETA - RA := lbase + A - Bx := int(inst & 0x3ffff) //GETBX - //reg.Set(RA, L.getField(cf.Fn.Env, cf.Fn.Proto.Constants[Bx])) - v := L.getFieldString(cf.Fn.Env, cf.Fn.Proto.stringConstants[Bx]) + case OP_GETGLOBAL: + A := int(inst>>18) & 0xff //GETA + RA := lbase + A + Bx := int(inst & 0x3ffff) //GETBX + //reg.Set(RA, L.getField(cf.Fn.Env, cf.Fn.Proto.Constants[Bx])) + v := L.getFieldString(cf.Fn.Env, cf.Fn.Proto.stringConstants[Bx]) // this section is inlined by go-inline // source function is 'func (rg *registry) Set(regi int, vali LValue) ' in '_state.go' { @@ -251,12 +262,12 @@ requiredSize := newSize rg.top = regi + 1 } } - case OP_GETTABLE: - A := int(inst>>18) & 0xff //GETA - RA := lbase + A - B := int(inst & 0x1ff) //GETB - C := int(inst>>9) & 0x1ff //GETC - v := L.getField(reg.Get(lbase+B), L.rkValue(C)) + case OP_GETTABLE: + A := int(inst>>18) & 0xff //GETA + RA := lbase + A + B := int(inst & 0x1ff) //GETB + C := int(inst>>9) & 0x1ff //GETC + v := L.getField(reg.Get(lbase+B), L.rkValue(C)) // this section is inlined by go-inline // source function is 'func (rg *registry) Set(regi int, vali LValue) ' in '_state.go' { @@ -277,12 +288,12 @@ requiredSize := newSize rg.top = regi + 1 } } - case OP_GETTABLEKS: - A := int(inst>>18) & 0xff //GETA - RA := lbase + A - B := int(inst & 0x1ff) //GETB - C := int(inst>>9) & 0x1ff //GETC - v := L.getFieldString(reg.Get(lbase+B), L.rkString(C)) + case OP_GETTABLEKS: + A := int(inst>>18) & 0xff //GETA + RA := lbase + A + B := int(inst & 0x1ff) //GETB + C := int(inst>>9) & 0x1ff //GETC + v := L.getFieldString(reg.Get(lbase+B), L.rkString(C)) // this section is inlined by go-inline // source function is 'func (rg *registry) Set(regi int, vali LValue) ' in '_state.go' { @@ -303,35 +314,35 @@ requiredSize := newSize rg.top = regi + 1 } } - case OP_SETGLOBAL: - A := int(inst>>18) & 0xff //GETA - RA := lbase + A - Bx := int(inst & 0x3ffff) //GETBX - //L.setField(cf.Fn.Env, cf.Fn.Proto.Constants[Bx], reg.Get(RA)) - L.setFieldString(cf.Fn.Env, cf.Fn.Proto.stringConstants[Bx], reg.Get(RA)) - case OP_SETUPVAL: - A := int(inst>>18) & 0xff //GETA - RA := lbase + A - B := int(inst & 0x1ff) //GETB - cf.Fn.Upvalues[B].SetValue(reg.Get(RA)) - case OP_SETTABLE: - A := int(inst>>18) & 0xff //GETA - RA := lbase + A - B := int(inst & 0x1ff) //GETB - C := int(inst>>9) & 0x1ff //GETC - L.setField(reg.Get(RA), L.rkValue(B), L.rkValue(C)) - case OP_SETTABLEKS: - A := int(inst>>18) & 0xff //GETA - RA := lbase + A - B := int(inst & 0x1ff) //GETB - C := int(inst>>9) & 0x1ff //GETC - L.setFieldString(reg.Get(RA), L.rkString(B), L.rkValue(C)) - case OP_NEWTABLE: - A := int(inst>>18) & 0xff //GETA - RA := lbase + A - B := int(inst & 0x1ff) //GETB - C := int(inst>>9) & 0x1ff //GETC - v := newLTable(B, C) + case OP_SETGLOBAL: + A := int(inst>>18) & 0xff //GETA + RA := lbase + A + Bx := int(inst & 0x3ffff) //GETBX + //L.setField(cf.Fn.Env, cf.Fn.Proto.Constants[Bx], reg.Get(RA)) + L.setFieldString(cf.Fn.Env, cf.Fn.Proto.stringConstants[Bx], reg.Get(RA)) + case OP_SETUPVAL: + A := int(inst>>18) & 0xff //GETA + RA := lbase + A + B := int(inst & 0x1ff) //GETB + cf.Fn.Upvalues[B].SetValue(reg.Get(RA)) + case OP_SETTABLE: + A := int(inst>>18) & 0xff //GETA + RA := lbase + A + B := int(inst & 0x1ff) //GETB + C := int(inst>>9) & 0x1ff //GETC + L.setField(reg.Get(RA), L.rkValue(B), L.rkValue(C)) + case OP_SETTABLEKS: + A := int(inst>>18) & 0xff //GETA + RA := lbase + A + B := int(inst & 0x1ff) //GETB + C := int(inst>>9) & 0x1ff //GETC + L.setFieldString(reg.Get(RA), L.rkString(B), L.rkValue(C)) + case OP_NEWTABLE: + A := int(inst>>18) & 0xff //GETA + RA := lbase + A + B := int(inst & 0x1ff) //GETB + C := int(inst>>9) & 0x1ff //GETC + v := newLTable(B, C) // this section is inlined by go-inline // source function is 'func (rg *registry) Set(regi int, vali LValue) ' in '_state.go' { @@ -352,13 +363,13 @@ requiredSize := newSize rg.top = regi + 1 } } - case OP_SELF: - A := int(inst>>18) & 0xff //GETA - RA := lbase + A - B := int(inst & 0x1ff) //GETB - C := int(inst>>9) & 0x1ff //GETC - selfobj := reg.Get(lbase + B) - v := L.getFieldString(selfobj, L.rkString(C)) + case OP_SELF: + A := int(inst>>18) & 0xff //GETA + RA := lbase + A + B := int(inst & 0x1ff) //GETB + C := int(inst>>9) & 0x1ff //GETC + selfobj := reg.Get(lbase + B) + v := L.getFieldString(selfobj, L.rkString(C)) // this section is inlined by go-inline // source function is 'func (rg *registry) Set(regi int, vali LValue) ' in '_state.go' { @@ -399,17 +410,17 @@ requiredSize := newSize rg.top = regi + 1 } } - case OP_ADD, OP_SUB, OP_MUL, OP_DIV, OP_MOD, OP_POW: - A := int(inst>>18) & 0xff //GETA - RA := lbase + A - B := int(inst & 0x1ff) //GETB - C := int(inst>>9) & 0x1ff //GETC - lhs := L.rkValue(B) - rhs := L.rkValue(C) - v1, ok1 := lhs.(LNumber) - v2, ok2 := rhs.(LNumber) - if ok1 && ok2 { - v := numberArith(L, opcode, LNumber(v1), LNumber(v2)) + case OP_ADD, OP_SUB, OP_MUL, OP_DIV, OP_MOD, OP_POW: + A := int(inst>>18) & 0xff //GETA + RA := lbase + A + B := int(inst & 0x1ff) //GETB + C := int(inst>>9) & 0x1ff //GETC + lhs := L.rkValue(B) + rhs := L.rkValue(C) + v1, ok1 := lhs.(LNumber) + v2, ok2 := rhs.(LNumber) + if ok1 && ok2 { + v := numberArith(L, opcode, LNumber(v1), LNumber(v2)) // this section is inlined by go-inline // source function is 'func (rg *registry) SetNumber(regi int, vali LNumber) ' in '_state.go' { @@ -430,8 +441,8 @@ requiredSize := newSize rg.top = regi + 1 } } - } else { - v := objectArith(L, opcode, lhs, rhs) + } else { + v := objectArith(L, opcode, lhs, rhs) // this section is inlined by go-inline // source function is 'func (rg *registry) Set(regi int, vali LValue) ' in '_state.go' { @@ -452,14 +463,14 @@ requiredSize := newSize rg.top = regi + 1 } } - } + } - case OP_UNM: - A := int(inst>>18) & 0xff //GETA - RA := lbase + A - B := int(inst & 0x1ff) //GETB - unaryv := L.rkValue(B) - if nm, ok := unaryv.(LNumber); ok { + case OP_UNM: + A := int(inst>>18) & 0xff //GETA + RA := lbase + A + B := int(inst & 0x1ff) //GETB + unaryv := L.rkValue(B) + if nm, ok := unaryv.(LNumber); ok { // this section is inlined by go-inline // source function is 'func (rg *registry) Set(regi int, vali LValue) ' in '_state.go' { @@ -480,12 +491,12 @@ requiredSize := newSize rg.top = regi + 1 } } - } else { - op := L.metaOp1(unaryv, "__unm") - if op.Type() == LTFunction { - reg.Push(op) - reg.Push(unaryv) - L.Call(1, 1) + } else { + op := L.metaOp1(unaryv, "__unm") + if op.Type() == LTFunction { + reg.Push(op) + reg.Push(unaryv) + L.Call(1, 1) // this section is inlined by go-inline // source function is 'func (rg *registry) Set(regi int, vali LValue) ' in '_state.go' { @@ -506,8 +517,8 @@ requiredSize := newSize rg.top = regi + 1 } } - } else if str, ok1 := unaryv.(LString); ok1 { - if num, err := parseNumber(string(str)); err == nil { + } else if str, ok1 := unaryv.(LString); ok1 { + if num, err := parseNumber(string(str)); err == nil { // this section is inlined by go-inline // source function is 'func (rg *registry) Set(regi int, vali LValue) ' in '_state.go' { @@ -528,18 +539,18 @@ requiredSize := newSize rg.top = regi + 1 } } + } else { + L.RaiseError("__unm undefined") + } } else { L.RaiseError("__unm undefined") } - } else { - L.RaiseError("__unm undefined") } - } - case OP_NOT: - A := int(inst>>18) & 0xff //GETA - RA := lbase + A - B := int(inst & 0x1ff) //GETB - if LVIsFalse(reg.Get(lbase + B)) { + case OP_NOT: + A := int(inst>>18) & 0xff //GETA + RA := lbase + A + B := int(inst & 0x1ff) //GETB + if LVIsFalse(reg.Get(lbase + B)) { // this section is inlined by go-inline // source function is 'func (rg *registry) Set(regi int, vali LValue) ' in '_state.go' { @@ -560,7 +571,7 @@ requiredSize := newSize rg.top = regi + 1 } } - } else { + } else { // this section is inlined by go-inline // source function is 'func (rg *registry) Set(regi int, vali LValue) ' in '_state.go' { @@ -581,13 +592,13 @@ requiredSize := newSize rg.top = regi + 1 } } - } - case OP_LEN: - A := int(inst>>18) & 0xff //GETA - RA := lbase + A - B := int(inst & 0x1ff) //GETB - switch lv := L.rkValue(B).(type) { - case LString: + } + case OP_LEN: + A := int(inst>>18) & 0xff //GETA + RA := lbase + A + B := int(inst & 0x1ff) //GETB + switch lv := L.rkValue(B).(type) { + case LString: // this section is inlined by go-inline // source function is 'func (rg *registry) SetNumber(regi int, vali LNumber) ' in '_state.go' { @@ -608,15 +619,15 @@ requiredSize := newSize rg.top = regi + 1 } } - default: - op := L.metaOp1(lv, "__len") - if op.Type() == LTFunction { - reg.Push(op) - reg.Push(lv) - L.Call(1, 1) - ret := reg.Pop() - if ret.Type() == LTNumber { - v, _ := ret.(LNumber) + default: + op := L.metaOp1(lv, "__len") + if op.Type() == LTFunction { + reg.Push(op) + reg.Push(lv) + L.Call(1, 1) + ret := reg.Pop() + if ret.Type() == LTNumber { + v, _ := ret.(LNumber) // this section is inlined by go-inline // source function is 'func (rg *registry) SetNumber(regi int, vali LNumber) ' in '_state.go' { @@ -637,7 +648,7 @@ requiredSize := newSize rg.top = regi + 1 } } - } else { + } else { // this section is inlined by go-inline // source function is 'func (rg *registry) Set(regi int, vali LValue) ' in '_state.go' { @@ -658,8 +669,8 @@ requiredSize := newSize rg.top = regi + 1 } } - } - } else if lv.Type() == LTTable { + } + } else if lv.Type() == LTTable { // this section is inlined by go-inline // source function is 'func (rg *registry) SetNumber(regi int, vali LNumber) ' in '_state.go' { @@ -680,18 +691,18 @@ requiredSize := newSize rg.top = regi + 1 } } - } else { - L.RaiseError("__len undefined") + } else { + L.RaiseError("__len undefined") + } } - } - case OP_CONCAT: - A := int(inst>>18) & 0xff //GETA - RA := lbase + A - B := int(inst & 0x1ff) //GETB - C := int(inst>>9) & 0x1ff //GETC - RC := lbase + C - RB := lbase + B - v := stringConcat(L, RC-RB+1, RC) + case OP_CONCAT: + A := int(inst>>18) & 0xff //GETA + RA := lbase + A + B := int(inst & 0x1ff) //GETB + C := int(inst>>9) & 0x1ff //GETC + RC := lbase + C + RB := lbase + B + v := stringConcat(L, RC-RB+1, RC) // this section is inlined by go-inline // source function is 'func (rg *registry) Set(regi int, vali LValue) ' in '_state.go' { @@ -712,88 +723,86 @@ requiredSize := newSize rg.top = regi + 1 } } - case OP_JMP: - cf := L.currentFrame - Sbx := int(inst&0x3ffff) - opMaxArgSbx //GETSBX - cf.Pc += Sbx - case OP_EQ: - cf := L.currentFrame - A := int(inst>>18) & 0xff //GETA - B := int(inst & 0x1ff) //GETB - C := int(inst>>9) & 0x1ff //GETC - ret := equals(L, L.rkValue(B), L.rkValue(C), false) - v := 1 - if ret { - v = 0 - } - if v == A { - cf.Pc++ - } - case OP_LT: - A := int(inst>>18) & 0xff //GETA - B := int(inst & 0x1ff) //GETB - C := int(inst>>9) & 0x1ff //GETC - ret := lessThan(L, L.rkValue(B), L.rkValue(C)) - v := 1 - if ret { - v = 0 - } - if v == A { - cf.Pc++ - } - case OP_LE: - A := int(inst>>18) & 0xff //GETA - B := int(inst & 0x1ff) //GETB - C := int(inst>>9) & 0x1ff //GETC - lhs := L.rkValue(B) - rhs := L.rkValue(C) - ret := false - - if v1, ok1 := lhs.(LNumber); ok1 { - if v2, ok2 := rhs.(LNumber); ok2 { - ret = v1 <= v2 - } else { - L.RaiseError("attempt to compare %v with %v", lhs.Type().String(), rhs.Type().String()) + case OP_JMP: + Sbx := int(inst&0x3ffff) - opMaxArgSbx //GETSBX + cf.Pc += Sbx + case OP_EQ: + A := int(inst>>18) & 0xff //GETA + B := int(inst & 0x1ff) //GETB + C := int(inst>>9) & 0x1ff //GETC + ret := equals(L, L.rkValue(B), L.rkValue(C), false) + v := 1 + if ret { + v = 0 } - } else { - if lhs.Type() != rhs.Type() { - L.RaiseError("attempt to compare %v with %v", lhs.Type().String(), rhs.Type().String()) + if v == A { + cf.Pc++ } - switch lhs.Type() { - case LTString: - ret = strCmp(string(lhs.(LString)), string(rhs.(LString))) <= 0 - default: - switch objectRational(L, lhs, rhs, "__le") { - case 1: - ret = true - case 0: - ret = false + case OP_LT: + A := int(inst>>18) & 0xff //GETA + B := int(inst & 0x1ff) //GETB + C := int(inst>>9) & 0x1ff //GETC + ret := lessThan(L, L.rkValue(B), L.rkValue(C)) + v := 1 + if ret { + v = 0 + } + if v == A { + cf.Pc++ + } + case OP_LE: + A := int(inst>>18) & 0xff //GETA + B := int(inst & 0x1ff) //GETB + C := int(inst>>9) & 0x1ff //GETC + lhs := L.rkValue(B) + rhs := L.rkValue(C) + ret := false + + if v1, ok1 := lhs.(LNumber); ok1 { + if v2, ok2 := rhs.(LNumber); ok2 { + ret = v1 <= v2 + } else { + L.RaiseError("attempt to compare %v with %v", lhs.Type().String(), rhs.Type().String()) + } + } else { + if lhs.Type() != rhs.Type() { + L.RaiseError("attempt to compare %v with %v", lhs.Type().String(), rhs.Type().String()) + } + switch lhs.Type() { + case LTString: + ret = strCmp(string(lhs.(LString)), string(rhs.(LString))) <= 0 default: - ret = !objectRationalWithError(L, rhs, lhs, "__lt") + switch objectRational(L, lhs, rhs, "__le") { + case 1: + ret = true + case 0: + ret = false + default: + ret = !objectRationalWithError(L, rhs, lhs, "__lt") + } } } - } - v := 1 - if ret { - v = 0 - } - if v == A { - cf.Pc++ - } - case OP_TEST: - A := int(inst>>18) & 0xff //GETA - RA := lbase + A - C := int(inst>>9) & 0x1ff //GETC - if LVAsBool(reg.Get(RA)) == (C == 0) { - cf.Pc++ - } - case OP_TESTSET: - A := int(inst>>18) & 0xff //GETA - RA := lbase + A - B := int(inst & 0x1ff) //GETB - C := int(inst>>9) & 0x1ff //GETC - if value := reg.Get(lbase + B); LVAsBool(value) != (C == 0) { + v := 1 + if ret { + v = 0 + } + if v == A { + cf.Pc++ + } + case OP_TEST: + A := int(inst>>18) & 0xff //GETA + RA := lbase + A + C := int(inst>>9) & 0x1ff //GETC + if LVAsBool(reg.Get(RA)) == (C == 0) { + cf.Pc++ + } + case OP_TESTSET: + A := int(inst>>18) & 0xff //GETA + RA := lbase + A + B := int(inst & 0x1ff) //GETB + C := int(inst>>9) & 0x1ff //GETC + if value := reg.Get(lbase + B); LVAsBool(value) != (C == 0) { // this section is inlined by go-inline // source function is 'func (rg *registry) Set(regi int, vali LValue) ' in '_state.go' { @@ -814,28 +823,28 @@ requiredSize := newSize rg.top = regi + 1 } } - } else { - cf.Pc++ - } - case OP_CALL: - A := int(inst>>18) & 0xff //GETA - RA := lbase + A - B := int(inst & 0x1ff) //GETB - C := int(inst>>9) & 0x1ff //GETC - nargs := B - 1 - if B == 0 { - nargs = reg.Top() - (RA + 1) - } - lv := reg.Get(RA) - nret := C - 1 - var callable *LFunction - var meta bool - if fn, ok := lv.(*LFunction); ok { - callable = fn - meta = false - } else { - callable, meta = L.metaCall(lv) - } + } else { + cf.Pc++ + } + case OP_CALL: + A := int(inst>>18) & 0xff //GETA + RA := lbase + A + B := int(inst & 0x1ff) //GETB + C := int(inst>>9) & 0x1ff //GETC + nargs := B - 1 + if B == 0 { + nargs = reg.Top() - (RA + 1) + } + lv := reg.Get(RA) + nret := C - 1 + var callable *LFunction + var meta bool + if fn, ok := lv.(*LFunction); ok { + callable = fn + meta = false + } else { + callable, meta = L.metaCall(lv) + } // this section is inlined by go-inline // source function is 'func (ls *LState) pushCallFrame(cf callFrame, fn LValue, meta bool) ' in '_state.go' { @@ -954,32 +963,29 @@ requiredSize := newSize } ls.currentFrame = newcf } - if callable.IsG && callGFunction(L, false) { - return true - } - case OP_TAILCALL: - reg := L.reg - cf := L.currentFrame - lbase := cf.LocalBase - A := int(inst>>18) & 0xff //GETA - RA := lbase + A - B := int(inst & 0x1ff) //GETB - nargs := B - 1 - if B == 0 { - nargs = reg.Top() - (RA + 1) - } - lv := reg.Get(RA) - var callable *LFunction - var meta bool - if fn, ok := lv.(*LFunction); ok { - callable = fn - meta = false - } else { - callable, meta = L.metaCall(lv) - } - if callable == nil { - L.RaiseError("attempt to call a non-function object") - } + if callable.IsG && callGFunction(L, false) { + return + } + case OP_TAILCALL: + A := int(inst>>18) & 0xff //GETA + RA := lbase + A + B := int(inst & 0x1ff) //GETB + nargs := B - 1 + if B == 0 { + nargs = reg.Top() - (RA + 1) + } + lv := reg.Get(RA) + var callable *LFunction + var meta bool + if fn, ok := lv.(*LFunction); ok { + callable = fn + meta = false + } else { + callable, meta = L.metaCall(lv) + } + if callable == nil { + L.RaiseError("attempt to call a non-function object") + } // this section is inlined by go-inline // source function is 'func (ls *LState) closeUpvalues(idx int) ' in '_state.go' { @@ -1000,40 +1006,40 @@ idx := lbase } } } - if callable.IsG { - luaframe := cf - L.pushCallFrame(callFrame{ - Fn: callable, - Pc: 0, - Base: RA, - LocalBase: RA + 1, - ReturnBase: cf.ReturnBase, - NArgs: nargs, - NRet: cf.NRet, - Parent: cf, - TailCall: 0, - }, lv, meta) - if callGFunction(L, true) { - return true - } - if L.currentFrame == nil || L.currentFrame.Fn.IsG || luaframe == baseframe { - return true - } - } else { - base := cf.Base - cf.Fn = callable - cf.Pc = 0 - cf.Base = RA - cf.LocalBase = RA + 1 - cf.ReturnBase = cf.ReturnBase - cf.NArgs = nargs - cf.NRet = cf.NRet - cf.TailCall++ - lbase := cf.LocalBase - if meta { - cf.NArgs++ - L.reg.Insert(lv, cf.LocalBase) - } + if callable.IsG { + luaframe := cf + L.pushCallFrame(callFrame{ + Fn: callable, + Pc: 0, + Base: RA, + LocalBase: RA + 1, + ReturnBase: cf.ReturnBase, + NArgs: nargs, + NRet: cf.NRet, + Parent: cf, + TailCall: 0, + }, lv, meta) + if callGFunction(L, true) { + return + } + if L.currentFrame == nil || L.currentFrame.Fn.IsG || luaframe == baseframe { + return + } + } else { + base := cf.Base + cf.Fn = callable + cf.Pc = 0 + cf.Base = RA + cf.LocalBase = RA + 1 + cf.ReturnBase = cf.ReturnBase + cf.NArgs = nargs + cf.NRet = cf.NRet + cf.TailCall++ + lbase := cf.LocalBase + if meta { + cf.NArgs++ + L.reg.Insert(lv, cf.LocalBase) + } // this section is inlined by go-inline // source function is 'func (ls *LState) initCallFrame(cf *callFrame) ' in '_state.go' { @@ -1172,13 +1178,13 @@ requiredSize := newSize } } } - cf.Base = base - cf.LocalBase = base + (cf.LocalBase - lbase + 1) - } - case OP_RETURN: - A := int(inst>>18) & 0xff //GETA - RA := lbase + A - B := int(inst & 0x1ff) //GETB + cf.Base = base + cf.LocalBase = base + (cf.LocalBase - lbase + 1) + } + case OP_RETURN: + A := int(inst>>18) & 0xff //GETA + RA := lbase + A + B := int(inst & 0x1ff) //GETB // this section is inlined by go-inline // source function is 'func (ls *LState) closeUpvalues(idx int) ' in '_state.go' { @@ -1199,16 +1205,16 @@ idx := lbase } } } - nret := B - 1 - if B == 0 { - nret = reg.Top() - RA - } - n := cf.NRet - if cf.NRet == MultRet { - n = nret - } + nret := B - 1 + if B == 0 { + nret = reg.Top() - RA + } + n := cf.NRet + if cf.NRet == MultRet { + n = nret + } - if L.Parent != nil && L.stack.Sp() == 1 { + if L.Parent != nil && L.stack.Sp() == 1 { // this section is inlined by go-inline // source function is 'func copyReturnValues(L *LState, regv, start, n, b int) ' in '_vm.go' { @@ -1315,10 +1321,10 @@ requiredSize := newSize } } } - switchToParentThread(L, n, false, true) - return true - } - islast := baseframe == L.stack.Pop() || L.stack.IsEmpty() + switchToParentThread(L, n, false, true) + return + } + islast := baseframe == L.stack.Pop() || L.stack.IsEmpty() // this section is inlined by go-inline // source function is 'func copyReturnValues(L *LState, regv, start, n, b int) ' in '_vm.go' { @@ -1425,18 +1431,18 @@ requiredSize := newSize } } } - L.currentFrame = L.stack.Last() - if islast || L.currentFrame == nil || L.currentFrame.Fn.IsG { - return true - } - case OP_FORLOOP: - A := int(inst>>18) & 0xff //GETA - RA := lbase + A - if init, ok1 := reg.Get(RA).(LNumber); ok1 { - if limit, ok2 := reg.Get(RA + 1).(LNumber); ok2 { - if step, ok3 := reg.Get(RA + 2).(LNumber); ok3 { - init += step - v := LNumber(init) + L.currentFrame = L.stack.Last() + if islast || L.currentFrame == nil || L.currentFrame.Fn.IsG { + return + } + case OP_FORLOOP: + A := int(inst>>18) & 0xff //GETA + RA := lbase + A + if init, ok1 := reg.Get(RA).(LNumber); ok1 { + if limit, ok2 := reg.Get(RA + 1).(LNumber); ok2 { + if step, ok3 := reg.Get(RA + 2).(LNumber); ok3 { + init += step + v := LNumber(init) // this section is inlined by go-inline // source function is 'func (rg *registry) SetNumber(regi int, vali LNumber) ' in '_state.go' { @@ -1457,9 +1463,9 @@ requiredSize := newSize rg.top = regi + 1 } } - if (step > 0 && init <= limit) || (step <= 0 && init >= limit) { - Sbx := int(inst&0x3ffff) - opMaxArgSbx //GETSBX - cf.Pc += Sbx + if (step > 0 && init <= limit) || (step <= 0 && init >= limit) { + Sbx := int(inst&0x3ffff) - opMaxArgSbx //GETSBX + cf.Pc += Sbx // this section is inlined by go-inline // source function is 'func (rg *registry) SetNumber(regi int, vali LNumber) ' in '_state.go' { @@ -1480,7 +1486,7 @@ requiredSize := newSize rg.top = regi + 1 } } - } else { + } else { // this section is inlined by go-inline // source function is 'func (rg *registry) SetTop(topi int) ' in '_state.go' { @@ -1511,22 +1517,22 @@ requiredSize := topi // rg.array[i] = LNil //} } + } + } else { + L.RaiseError("for statement step must be a number") } } else { - L.RaiseError("for statement step must be a number") + L.RaiseError("for statement limit must be a number") } } else { - L.RaiseError("for statement limit must be a number") + L.RaiseError("for statement init must be a number") } - } else { - L.RaiseError("for statement init must be a number") - } - case OP_FORPREP: - A := int(inst>>18) & 0xff //GETA - RA := lbase + A - Sbx := int(inst&0x3ffff) - opMaxArgSbx //GETSBX - if init, ok1 := reg.Get(RA).(LNumber); ok1 { - if step, ok2 := reg.Get(RA + 2).(LNumber); ok2 { + case OP_FORPREP: + A := int(inst>>18) & 0xff //GETA + RA := lbase + A + Sbx := int(inst&0x3ffff) - opMaxArgSbx //GETSBX + if init, ok1 := reg.Get(RA).(LNumber); ok1 { + if step, ok2 := reg.Get(RA + 2).(LNumber); ok2 { // this section is inlined by go-inline // source function is 'func (rg *registry) SetNumber(regi int, vali LNumber) ' in '_state.go' { @@ -1547,18 +1553,18 @@ requiredSize := newSize rg.top = regi + 1 } } + } else { + L.RaiseError("for statement step must be a number") + } } else { - L.RaiseError("for statement step must be a number") + L.RaiseError("for statement init must be a number") } - } else { - L.RaiseError("for statement init must be a number") - } - cf.Pc += Sbx - case OP_TFORLOOP: - A := int(inst>>18) & 0xff //GETA - RA := lbase + A - C := int(inst>>9) & 0x1ff //GETC - nret := C + cf.Pc += Sbx + case OP_TFORLOOP: + A := int(inst>>18) & 0xff //GETA + RA := lbase + A + C := int(inst>>9) & 0x1ff //GETC + nret := C // this section is inlined by go-inline // source function is 'func (rg *registry) SetTop(topi int) ' in '_state.go' { @@ -1649,8 +1655,8 @@ requiredSize := newSize rg.top = regi + 1 } } - L.callR(2, nret, RA+3) - if value := reg.Get(RA + 3); value != LNil { + L.callR(2, nret, RA+3) + if value := reg.Get(RA + 3); value != LNil { // this section is inlined by go-inline // source function is 'func (rg *registry) Set(regi int, vali LValue) ' in '_state.go' { @@ -1671,31 +1677,31 @@ requiredSize := newSize rg.top = regi + 1 } } - pc := cf.Fn.Proto.Code[cf.Pc] - cf.Pc += int(pc&0x3ffff) - opMaxArgSbx - } - cf.Pc++ - case OP_SETLIST: - A := int(inst>>18) & 0xff //GETA - RA := lbase + A - B := int(inst & 0x1ff) //GETB - C := int(inst>>9) & 0x1ff //GETC - if C == 0 { - C = int(cf.Fn.Proto.Code[cf.Pc]) + pc := cf.Fn.Proto.Code[cf.Pc] + cf.Pc += int(pc&0x3ffff) - opMaxArgSbx + } cf.Pc++ - } - offset := (C - 1) * FieldsPerFlush - table := reg.Get(RA).(*LTable) - nelem := B - if B == 0 { - nelem = reg.Top() - RA - 1 - } - for i := 1; i <= nelem; i++ { - table.RawSetInt(offset+i, reg.Get(RA+i)) - } - case OP_CLOSE: - A := int(inst>>18) & 0xff //GETA - RA := lbase + A + case OP_SETLIST: + A := int(inst>>18) & 0xff //GETA + RA := lbase + A + B := int(inst & 0x1ff) //GETB + C := int(inst>>9) & 0x1ff //GETC + if C == 0 { + C = int(cf.Fn.Proto.Code[cf.Pc]) + cf.Pc++ + } + offset := (C - 1) * FieldsPerFlush + table := reg.Get(RA).(*LTable) + nelem := B + if B == 0 { + nelem = reg.Top() - RA - 1 + } + for i := 1; i <= nelem; i++ { + table.RawSetInt(offset+i, reg.Get(RA+i)) + } + case OP_CLOSE: + A := int(inst>>18) & 0xff //GETA + RA := lbase + A // this section is inlined by go-inline // source function is 'func (ls *LState) closeUpvalues(idx int) ' in '_state.go' { @@ -1716,12 +1722,12 @@ idx := RA } } } - case OP_CLOSURE: - A := int(inst>>18) & 0xff //GETA - RA := lbase + A - Bx := int(inst & 0x3ffff) //GETBX - proto := cf.Fn.Proto.FunctionPrototypes[Bx] - closure := newLFunctionL(proto, cf.Fn.Env, int(proto.NumUpvalues)) + case OP_CLOSURE: + A := int(inst>>18) & 0xff //GETA + RA := lbase + A + Bx := int(inst & 0x3ffff) //GETBX + proto := cf.Fn.Proto.FunctionPrototypes[Bx] + closure := newLFunctionL(proto, cf.Fn.Env, int(proto.NumUpvalues)) // this section is inlined by go-inline // source function is 'func (rg *registry) Set(regi int, vali LValue) ' in '_state.go' { @@ -1742,30 +1748,30 @@ requiredSize := newSize rg.top = regi + 1 } } - for i := 0; i < int(proto.NumUpvalues); i++ { - inst = cf.Fn.Proto.Code[cf.Pc] - cf.Pc++ - B := opGetArgB(inst) - switch opGetOpCode(inst) { - case OP_MOVE: - closure.Upvalues[i] = L.findUpvalue(lbase + B) - case OP_GETUPVAL: - closure.Upvalues[i] = cf.Fn.Upvalues[B] + for i := 0; i < int(proto.NumUpvalues); i++ { + inst = cf.Fn.Proto.Code[cf.Pc] + cf.Pc++ + B := opGetArgB(inst) + switch opGetOpCode(inst) { + case OP_MOVE: + closure.Upvalues[i] = L.findUpvalue(lbase + B) + case OP_GETUPVAL: + closure.Upvalues[i] = cf.Fn.Upvalues[B] + } + } + case OP_VARARG: + A := int(inst>>18) & 0xff //GETA + RA := lbase + A + B := int(inst & 0x1ff) //GETB + nparams := int(cf.Fn.Proto.NumParameters) + nvarargs := cf.NArgs - nparams + if nvarargs < 0 { + nvarargs = 0 + } + nwant := B - 1 + if B == 0 { + nwant = nvarargs } - } - case OP_VARARG: - A := int(inst>>18) & 0xff //GETA - RA := lbase + A - B := int(inst & 0x1ff) //GETB - nparams := int(cf.Fn.Proto.NumParameters) - nvarargs := cf.NArgs - nparams - if nvarargs < 0 { - nvarargs = 0 - } - nwant := B - 1 - if B == 0 { - nwant = nvarargs - } // this section is inlined by go-inline // source function is 'func (rg *registry) CopyRange(regv, start, limit, n int) ' in '_state.go' { @@ -1806,31 +1812,7 @@ requiredSize := newSize } } } - case OP_NOP: - } - return false -} - -func mainLoop(L *LState, baseframe *callFrame) { - var inst uint32 - var cf *callFrame - - if L.stack.IsEmpty() { - return - } - - L.currentFrame = L.stack.Last() - if L.currentFrame.Fn.IsG { - callGFunction(L, false) - return - } - - for L.ctx == nil || L.ctx.Err() == nil { - cf = L.currentFrame - inst = cf.Fn.Proto.Code[cf.Pc] - cf.Pc++ - if evalInstruction(L, inst, baseframe) { - return + case OP_NOP: } } From dbde1d3bb2e7f33de0a1c311d4a87493d28bab53 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philip=20Dub=C3=A9?= Date: Wed, 13 Mar 2024 11:31:51 +0000 Subject: [PATCH 4/4] Update README minimum go version --- README.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.rst b/README.rst index 1ac57dca..c20920de 100644 --- a/README.rst +++ b/README.rst @@ -56,7 +56,7 @@ Installation go get github.com/yuin/gopher-lua -GopherLua supports >= Go1.9. +GopherLua supports >= Go1.20. ---------------------------------------------------------------- Usage