private void DumpConstants(LuaProto proto) { DumpVector(proto.K, (k) => { var t = k.V.Tt; DumpByte((byte)t); switch (t) { case (int)LuaType.LUA_TNIL: break; case (int)LuaType.LUA_TBOOLEAN: DumpBool(k.V.BValue()); break; case (int)LuaType.LUA_TNUMBER: DumpBlock(BitConverter.GetBytes(k.V.NValue)); break; case (int)LuaType.LUA_TSTRING: DumpString(k.V.SValue()); break; default: Utl.Assert(false); break; } }); DumpVector(proto.P, (p) => { DumpFunction(p); }); }
internal int GetCurrentLine(CallInfo ci) { Utl.Assert(ci.IsLua); var cl = Stack[ci.FuncIndex].V.ClLValue(); return(cl.Proto.GetFuncLine(ci.CurrentPc)); }
private int ComputeSizes(ref int[] nums, ref int nasize) { int a = 0; int na = 0; int n = 0; for (int i = 0, tti = 1; tti / 2 < nasize; ++i, tti *= 2) { if (nums[i] > 0) { a += nums[i]; if (a > tti / 2) { n = tti; na = a; } } if (a == nasize) { break; } // all elements already conted } nasize = n; Utl.Assert(nasize / 2 <= na && na <= nasize); return(na); }
private static void FreeReg(FuncState fs, int reg) { if (!Instruction.ISK(reg) && reg >= fs.NumActVar) { fs.FreeReg--; Utl.Assert(reg == fs.FreeReg); } }
private static void InvertJump(FuncState fs, ExpDesc e) { InstructionPtr pc = GetJumpControl(fs, e.Info); Utl.Assert(TestTMode(pc.Value.GET_OPCODE()) && pc.Value.GET_OPCODE() != OpCode.OP_TESTSET && pc.Value.GET_OPCODE() != OpCode.OP_TEST); pc.Value = pc.Value.SETARG_A(pc.Value.GETARG_A() == 0 ? 1 : 0); }
private StkId NewTableKey(ref TValue k) { if (k.TtIsNil()) { L.G_RunError("table index is nil"); } if (k.TtIsNumber() && System.Double.IsNaN(k.NValue)) { L.G_RunError("table index is NaN"); } var mp = GetHashNode(ref k); // if main position is taken if (!mp.Val.V.TtIsNil() || mp == DummyNode) { var n = GetFreePos(); if (n == null) { Rehash(ref k); var cell = Get(ref k); if (cell != TheNilValue) { return(cell); } return(NewTableKey(ref k)); } Utl.Assert(n != DummyNode); var othern = GetHashNode(ref mp.Key.V); // is colliding node out of its main position? if (othern != mp) { while (othern.Next != mp) { othern = othern.Next; } othern.Next = n; n.CopyFrom(mp); mp.Next = null; mp.Val.V.SetNilValue(); } // colliding node is in its own main position else { n.Next = mp.Next; mp.Next = n; mp = n; } } mp.Key.V.SetObj(ref k); Utl.Assert(mp.Val.V.TtIsNil()); return(mp.Val); }
public static int CodeABx(FuncState fs, OpCode op, int a, uint bc) { var mode = OpCodeInfo.GetMode(op); Utl.Assert(mode.OpMode == OpMode.iABx || mode.OpMode == OpMode.iAsBx); Utl.Assert(mode.CMode == OpArgMask.OpArgN); Utl.Assert(a < Instruction.MAXARG_A & bc <= Instruction.MAXARG_Bx); return(Code(fs, Instruction.CreateABx(op, a, bc))); }
private void V_Concat(int total) { Utl.Assert(total >= 2); do { var top = Top; int n = 2; var lhs = Stack[top.Index - 2]; var rhs = Stack[top.Index - 1]; if (!(lhs.V.TtIsString() || lhs.V.TtIsNumber()) || !ToString(ref rhs.V)) { if (!CallBinTM(lhs, rhs, lhs, TMS.TM_CONCAT)) { G_ConcatError(lhs, rhs); } } else if (rhs.V.SValue().Length == 0) { ToString(ref lhs.V); } else if (lhs.V.TtIsString() && lhs.V.SValue().Length == 0) { lhs.V.SetObj(ref rhs.V); } else { StringBuilder sb = new StringBuilder(); n = 0; for ( ; n < total; ++n) { var cur = Stack[top.Index - (n + 1)]; if (cur.V.TtIsString()) { sb.Insert(0, cur.V.SValue()); } else if (cur.V.TtIsNumber()) { sb.Insert(0, cur.V.NValue.ToString()); } else { break; } } var dest = Stack[top.Index - n]; dest.V.SetSValue(sb.ToString()); } total -= n - 1; Top = Stack[Top.Index - (n - 1)]; } while(total > 1); }
public static void PatchList(FuncState fs, int list, int target) { if (target == fs.Pc) { PatchToHere(fs, list); } else { Utl.Assert(target < fs.Pc); PatchListAux(fs, list, target, NO_REG, target); } }
private int CeilLog2(int x) { Utl.Assert(x > 0); int l = 0; x--; while (x >= 256) { l += 8; x >>= 8; } return(l + Log2_[x]); }
private static void FixJump(FuncState fs, int pc, int dest) { Instruction jmp = fs.Proto.Code[pc]; int offset = dest - (pc + 1); Utl.Assert(dest != NO_JUMP); if (Math.Abs(offset) > Instruction.MAXARG_sBx) { fs.Lexer.SyntaxError("control structure too long"); } jmp.SETARG_sBx(offset); fs.Proto.Code[pc] = jmp; }
public static void PatchClose(FuncState fs, int list, int level) { level++; // argument is +1 to reserve 0 as non-op while (list != NO_JUMP) { int next = GetJump(fs, list); var pi = new InstructionPtr(fs.Proto.Code, list);; Utl.Assert(pi.Value.GET_OPCODE() == OpCode.OP_JMP && (pi.Value.GETARG_A() == 0 || pi.Value.GETARG_A() >= level)); pi.Value = pi.Value.SETARG_A(level); list = next; } }
private static void Discharge2Reg(FuncState fs, ExpDesc e, int reg) { DischargeVars(fs, e); switch (e.Kind) { case ExpKind.VNIL: { CodeNil(fs, reg, 1); break; } case ExpKind.VFALSE: case ExpKind.VTRUE: { CodeABC(fs, OpCode.OP_LOADBOOL, reg, (e.Kind == ExpKind.VTRUE ? 1 : 0), 0); break; } case ExpKind.VK: { CodeK(fs, reg, e.Info); break; } case ExpKind.VKNUM: { CodeK(fs, reg, NumberK(fs, e.NumberValue)); break; } case ExpKind.VRELOCABLE: { InstructionPtr pi = fs.GetCode(e); pi.Value = pi.Value.SETARG_A(reg); break; } case ExpKind.VNONRELOC: { if (reg != e.Info) { CodeABC(fs, OpCode.OP_MOVE, reg, e.Info, 0); } break; } default: { Utl.Assert(e.Kind == ExpKind.VVOID || e.Kind == ExpKind.VJMP); return; // nothing to do... } } e.Info = reg; e.Kind = ExpKind.VNONRELOC; }
private double _ReadNumber() { var expo = new char[] { 'E', 'e' }; Utl.Assert(_CurrentIsDigit()); var first = Current; _SaveAndNext(); if (first == '0' && (Current == 'X' || Current == 'x')) { expo = new char[] { 'P', 'p' }; _SaveAndNext(); } for (;;) { if (Current == expo[0] || Current == expo[1]) { _SaveAndNext(); if (Current == '+' || Current == '-') { _SaveAndNext(); } } if (_CurrentIsXDigit() || Current == '.') { _SaveAndNext(); } else { break; } } double ret; var str = _GetSavedString(); if (LuaState.O_Str2Decimal(str, out ret)) { return(ret); } else { _Error("malformed number: " + str); return(0.0); } }
private void SetArraryVector(int size) { Utl.Assert(size >= ArrayPart.Length); var newArrayPart = new StkId[size]; int i = 0; for ( ; i < ArrayPart.Length; ++i) { newArrayPart[i] = ArrayPart[i]; } for ( ; i < size; ++i) { newArrayPart[i] = new StkId(); newArrayPart[i].V.SetNilValue(); } ArrayPart = newArrayPart; }
private void D_ReallocStack(int size) { Utl.Assert(size <= LuaConf.LUAI_MAXSTACK || size == ERRORSTACKSIZE); var newStack = new StkId[size]; int i = 0; for ( ; i < Stack.Length; ++i) { newStack[i] = Stack[i]; newStack[i].SetList(newStack); } for ( ; i < size; ++i) { newStack[i] = new StkId(); newStack[i].SetList(newStack); newStack[i].SetIndex(i); newStack[i].V.SetNilValue(); } Top = newStack[Top.Index]; Stack = newStack; StackLast = size - LuaDef.EXTRA_STACK; }
private int AdjustVarargs(LuaProto p, int actual) { // 有 `...' 的情况 // 调用前: func (base)fixed-p1 fixed-p2 var-p1 var-p2 top // 调用后: func nil nil var-p1 var-p2 (base)fixed-p1 fixed-p2 (reserved...) top // // 没有 `...' 的情况 // func (base)fixed-p1 fixed-p2 (reserved...) top int NumFixArgs = p.NumParams; Utl.Assert(actual >= NumFixArgs, "AdjustVarargs (actual >= NumFixArgs) is false"); int fixedArg = Top.Index - actual; // first fixed argument int stackBase = Top.Index; // final position of first argument for (int i = stackBase; i < stackBase + NumFixArgs; ++i) { Stack[i].V.SetObj(ref Stack[fixedArg].V); Stack[fixedArg++].V.SetNilValue(); } Top = Stack[stackBase + NumFixArgs]; return(stackBase); }
public static void SetList(FuncState fs, int t, int nelems, int tostore) { int c = (nelems - 1) / LuaDef.LFIELDS_PER_FLUSH + 1; int b = (tostore == LuaDef.LUA_MULTRET) ? 0 : tostore; Utl.Assert(tostore != 0); if (c <= Instruction.MAXARG_C) { CodeABC(fs, OpCode.OP_SETLIST, t, b, c); } else if (c <= Instruction.MAXARG_Ax) { CodeABC(fs, OpCode.OP_SETLIST, t, b, 0); CodeExtraArg(fs, c); } else { fs.Lexer.SyntaxError("constructor too long"); } // free registers with list values fs.FreeReg = t + 1; }
private static int CodeExtraArg(FuncState fs, int a) { Utl.Assert(a <= Instruction.MAXARG_Ax); return(Code(fs, Instruction.CreateAx(OpCode.OP_EXTRAARG, a))); }
/// <summary> /// return true if function has been executed /// </summary> private bool D_PreCall(StkId func, int nResults) { // prepare for Lua call #if DEBUG_D_PRE_CALL ULDebug.Log("============================ D_PreCall func:" + func); #endif int funcIndex = func.Index; if (!func.V.TtIsFunction()) { // not a function // retry with `function' tag method func = tryFuncTM(func); // now it must be a function return(D_PreCall(func, nResults)); } if (func.V.ClIsLuaClosure()) { var cl = func.V.ClLValue(); Utl.Assert(cl != null); var p = cl.Proto; D_CheckStack(p.MaxStackSize + p.NumParams); func = Stack[funcIndex]; // 补全参数 int n = (Top.Index - func.Index) - 1; for ( ; n < p.NumParams; ++n) { StkId.inc(ref Top).V.SetNilValue(); } int stackBase = (!p.IsVarArg) ? (func.Index + 1) : AdjustVarargs(p, n); CI = ExtendCI(); CI.NumResults = nResults; CI.FuncIndex = func.Index; CI.BaseIndex = stackBase; CI.TopIndex = stackBase + p.MaxStackSize; Utl.Assert(CI.TopIndex <= StackLast); CI.SavedPc = new InstructionPtr(p.Code, 0); CI.CallStatus = CallStatus.CIST_LUA; Top = Stack[CI.TopIndex]; return(false); } if (func.V.ClIsCsClosure()) { var cscl = func.V.ClCsValue(); Utl.Assert(cscl != null); D_CheckStack(LuaDef.LUA_MINSTACK); func = Stack[funcIndex]; CI = ExtendCI(); CI.NumResults = nResults; CI.FuncIndex = func.Index; CI.TopIndex = Top.Index + LuaDef.LUA_MINSTACK; CI.CallStatus = CallStatus.CIST_NONE; // do the actual call int n = cscl.F(this); // poscall D_PosCall(Top.Index - n); return(true); } throw new System.NotImplementedException(); }
private void V_FinishOp() { int ciIndex = CI.Index; int stackBase = CI.BaseIndex; Instruction i = (CI.SavedPc - 1).Value; // interrupted instruction OpCode op = i.GET_OPCODE(); switch (op) { case OpCode.OP_ADD: case OpCode.OP_SUB: case OpCode.OP_MUL: case OpCode.OP_DIV: case OpCode.OP_MOD: case OpCode.OP_POW: case OpCode.OP_UNM: case OpCode.OP_LEN: case OpCode.OP_GETTABUP: case OpCode.OP_GETTABLE: case OpCode.OP_SELF: { var tmp = Stack[stackBase + i.GETARG_A()]; Top = Stack[Top.Index - 1]; tmp.V.SetObj(ref Stack[Top.Index].V); break; } case OpCode.OP_LE: case OpCode.OP_LT: case OpCode.OP_EQ: { bool res = !IsFalse(ref Stack[Top.Index - 1].V); Top = Stack[Top.Index - 1]; // metamethod should not be called when operand is K Utl.Assert(!Instruction.ISK(i.GETARG_B())); if (op == OpCode.OP_LE && // `<=' using `<' instead? T_GetTMByObj(ref Stack[stackBase + i.GETARG_B()].V, TMS.TM_LE).V.TtIsNil()) { res = !res; // invert result } var ci = BaseCI[ciIndex]; Utl.Assert(ci.SavedPc.Value.GET_OPCODE() == OpCode.OP_JMP); if ((res ? 1 : 0) != i.GETARG_A()) { if ((i.GETARG_A() == 0) == res) // condition failed? { ci.SavedPc.Index++; // skip jump instruction } } break; } case OpCode.OP_CONCAT: { StkId top = Stack[Top.Index - 1]; // top when `CallBinTM' was called int b = i.GETARG_B(); // first element to concatenate int total = top.Index - 1 - (stackBase + b); // yet to concatenate var tmp = Stack[top.Index - 2]; tmp.V.SetObj(ref top.V); // put TM result in proper position if (total > 1) // are there elements to concat? { Top = Stack[Top.Index - 1]; V_Concat(total); } // move final result to final position var ci = BaseCI[ciIndex]; var tmp2 = Stack[ci.BaseIndex + i.GETARG_A()]; tmp2.V.SetObj(ref Stack[Top.Index - 1].V); Top = Stack[ci.TopIndex]; break; } case OpCode.OP_TFORCALL: { var ci = BaseCI[ciIndex]; Utl.Assert(ci.SavedPc.Value.GET_OPCODE() == OpCode.OP_TFORLOOP); Top = Stack[ci.TopIndex]; // restore top break; } case OpCode.OP_CALL: { if (i.GETARG_C() - 1 >= 0) // numResults >= 0? { var ci = BaseCI[ciIndex]; Top = Stack[ci.TopIndex]; // restore top } break; } case OpCode.OP_TAILCALL: case OpCode.OP_SETTABUP: case OpCode.OP_SETTABLE: break; default: Utl.Assert(false); break; } }
private bool V_EqualObject(ref TValue t1, ref TValue t2, bool rawEq) { Utl.Assert(t1.Tt == t2.Tt); StkId tm = null; switch (t1.Tt) { case (int)LuaType.LUA_TNIL: return(true); case (int)LuaType.LUA_TNUMBER: return(t1.NValue == t2.NValue); case (int)LuaType.LUA_TUINT64: return(t1.UInt64Value == t2.UInt64Value); case (int)LuaType.LUA_TBOOLEAN: return(t1.BValue() == t2.BValue()); case (int)LuaType.LUA_TSTRING: return(t1.SValue() == t2.SValue()); case (int)LuaType.LUA_TUSERDATA: { var ud1 = t1.RawUValue(); var ud2 = t2.RawUValue(); if (ud1.Value == ud2.Value) { return(true); } if (rawEq) { return(false); } tm = GetEqualTM(ud1.MetaTable, ud2.MetaTable, TMS.TM_EQ); break; } case (int)LuaType.LUA_TTABLE: { var tbl1 = t1.HValue(); var tbl2 = t2.HValue(); if (System.Object.ReferenceEquals(tbl1, tbl2)) { return(true); } if (rawEq) { return(false); } tm = GetEqualTM(tbl1.MetaTable, tbl2.MetaTable, TMS.TM_EQ); break; } default: return(t1.OValue == t2.OValue); } if (tm == null) // no TM? { return(false); } CallTM(ref tm.V, ref t1, ref t2, Top, true); // call TM return(!IsFalse(ref Top.V)); }
private void V_Execute() { ExecuteEnvironment env; CallInfo ci = CI; newframe: Utl.Assert(ci == CI); var cl = Stack[ci.FuncIndex].V.ClLValue(); env.Stack = Stack; env.K = cl.Proto.K; env.Base = ci.BaseIndex; #if DEBUG_NEW_FRAME ULDebug.Log("#### NEW FRAME #########################################################################"); ULDebug.Log("## cl:" + cl); ULDebug.Log("## Base:" + env.Base); ULDebug.Log("########################################################################################"); #endif while (true) { Instruction i = ci.SavedPc.ValueInc; env.I = i; #if DEBUG_SRC_INFO int line = 0; string src = ""; if (ci.IsLua) { line = GetCurrentLine(ci); src = GetCurrentLuaFunc(ci).Proto.Source; } #endif StkId ra = env.RA; #if DEBUG_DUMP_INS_STACK #if DEBUG_DUMP_INS_STACK_EX DumpStack(env.Base, i.ToString()); #else DumpStack(env.Base); #endif #endif #if DEBUG_INSTRUCTION ULDebug.Log(System.DateTime.Now + " [VM] ======================================================================== Instruction: " + i #if DEBUG_INSTRUCTION_WITH_STACK + "\n" + DumpStackToString(env.Base.Index) #endif ); #endif #if DEBUG_RECORD_INS InstructionHistory.Enqueue(i); if (InstructionHistory.Count > 100) { InstructionHistory.Dequeue(); } #endif switch (i.GET_OPCODE()) { case OpCode.OP_MOVE: { var rb = env.RB; #if DEBUG_OP_MOVE ULDebug.Log("[VM] ==== OP_MOVE rb:" + rb); ULDebug.Log("[VM] ==== OP_MOVE ra:" + ra); #endif ra.V.SetObj(ref rb.V); break; } case OpCode.OP_LOADK: { var rb = env.K[i.GETARG_Bx()]; ra.V.SetObj(ref rb.V); break; } case OpCode.OP_LOADKX: { Utl.Assert(ci.SavedPc.Value.GET_OPCODE() == OpCode.OP_EXTRAARG); var rb = env.K[ci.SavedPc.ValueInc.GETARG_Ax()]; ra.V.SetObj(ref rb.V); break; } case OpCode.OP_LOADBOOL: { ra.V.SetBValue(i.GETARG_B() != 0); if (i.GETARG_C() != 0) { ci.SavedPc.Index += 1; // skip next instruction (if C) } break; } case OpCode.OP_LOADNIL: { int b = i.GETARG_B(); int index = ra.Index; do { Stack[index++].V.SetNilValue(); } while (b-- > 0); break; } case OpCode.OP_GETUPVAL: { int b = i.GETARG_B(); ra.V.SetObj(ref cl.Upvals[b].V.V); #if DEBUG_OP_GETUPVAL // for( var j=0; j<cl.Upvals.Length; ++j) // { // ULDebug.Log("[VM] ==== GETUPVAL upval:" + cl.Upvals[j] ); // } ULDebug.Log("[VM] ==== GETUPVAL b:" + b); ULDebug.Log("[VM] ==== GETUPVAL ra:" + ra); #endif break; } case OpCode.OP_GETTABUP: { int b = i.GETARG_B(); var key = env.RKC; V_GetTable(cl.Upvals[b].V, key, ra); #if DEBUG_OP_GETTABUP ULDebug.Log("[VM] ==== OP_GETTABUP key:" + key); ULDebug.Log("[VM] ==== OP_GETTABUP val:" + ra); #endif env.Base = ci.BaseIndex; break; } case OpCode.OP_GETTABLE: { var tbl = env.RB; var key = env.RKC; var val = ra; V_GetTable(tbl, key, val); #if DEBUG_OP_GETTABLE ULDebug.Log("[VM] ==== OP_GETTABLE key:" + key.ToString()); ULDebug.Log("[VM] ==== OP_GETTABLE val:" + val.ToString()); #endif break; } case OpCode.OP_SETTABUP: { int a = i.GETARG_A(); var key = env.RKB; var val = env.RKC; V_SetTable(cl.Upvals[a].V, key, val); #if DEBUG_OP_SETTABUP ULDebug.Log("[VM] ==== OP_SETTABUP key:" + key.Value); ULDebug.Log("[VM] ==== OP_SETTABUP val:" + val.Value); #endif env.Base = ci.BaseIndex; break; } case OpCode.OP_SETUPVAL: { int b = i.GETARG_B(); var uv = cl.Upvals[b]; uv.V.V.SetObj(ref ra.V); #if DEBUG_OP_SETUPVAL ULDebug.Log("[VM] ==== SETUPVAL b:" + b); ULDebug.Log("[VM] ==== SETUPVAL ra:" + ra); #endif break; } case OpCode.OP_SETTABLE: { var key = env.RKB; var val = env.RKC; #if DEBUG_OP_SETTABLE ULDebug.Log("[VM] ==== OP_SETTABLE key:" + key.ToString()); ULDebug.Log("[VM] ==== OP_SETTABLE val:" + val.ToString()); #endif V_SetTable(ra, key, val); break; } case OpCode.OP_NEWTABLE: { int b = i.GETARG_B(); int c = i.GETARG_C(); var tbl = new LuaTable(this); ra.V.SetHValue(tbl); if (b > 0 || c > 0) { tbl.Resize(b, c); } break; } case OpCode.OP_SELF: { // OP_SELF put function referenced by a table on ra // and the table on ra+1 // // RB: table // RKC: key var ra1 = Stack[ra.Index + 1]; var rb = env.RB; ra1.V.SetObj(ref rb.V); V_GetTable(rb, env.RKC, ra); env.Base = ci.BaseIndex; break; } case OpCode.OP_ADD: { var rkb = env.RKB; var rkc = env.RKC; if (rkb.V.TtIsNumber() && rkc.V.TtIsNumber()) { ra.V.SetNValue(rkb.V.NValue + rkc.V.NValue); } else { V_Arith(ra, rkb, rkc, TMS.TM_ADD); } env.Base = ci.BaseIndex; break; } case OpCode.OP_SUB: { var rkb = env.RKB; var rkc = env.RKC; if (rkb.V.TtIsNumber() && rkc.V.TtIsNumber()) { ra.V.SetNValue(rkb.V.NValue - rkc.V.NValue); } else { V_Arith(ra, rkb, rkc, TMS.TM_SUB); } env.Base = ci.BaseIndex; break; } case OpCode.OP_MUL: { var rkb = env.RKB; var rkc = env.RKC; if (rkb.V.TtIsNumber() && rkc.V.TtIsNumber()) { ra.V.SetNValue(rkb.V.NValue * rkc.V.NValue); } else { V_Arith(ra, rkb, rkc, TMS.TM_MUL); } env.Base = ci.BaseIndex; break; } case OpCode.OP_DIV: { var rkb = env.RKB; var rkc = env.RKC; if (rkb.V.TtIsNumber() && rkc.V.TtIsNumber()) { ra.V.SetNValue(rkb.V.NValue / rkc.V.NValue); } else { V_Arith(ra, rkb, rkc, TMS.TM_DIV); } env.Base = ci.BaseIndex; break; } case OpCode.OP_MOD: { var rkb = env.RKB; var rkc = env.RKC; if (rkb.V.TtIsNumber() && rkc.V.TtIsNumber()) { ra.V.SetNValue(rkb.V.NValue % rkc.V.NValue); } else { V_Arith(ra, rkb, rkc, TMS.TM_MOD); } env.Base = ci.BaseIndex; break; } case OpCode.OP_POW: { var rkb = env.RKB; var rkc = env.RKC; if (rkb.V.TtIsNumber() && rkc.V.TtIsNumber()) { ra.V.SetNValue(Math.Pow(rkb.V.NValue, rkc.V.NValue)); } else { V_Arith(ra, rkb, rkc, TMS.TM_POW); } env.Base = ci.BaseIndex; break; } case OpCode.OP_UNM: { var rb = env.RB; if (rb.V.TtIsNumber()) { ra.V.SetNValue(-rb.V.NValue); } else { V_Arith(ra, rb, rb, TMS.TM_UNM); env.Base = ci.BaseIndex; } break; } case OpCode.OP_NOT: { var rb = env.RB; ra.V.SetBValue(IsFalse(ref rb.V)); break; } case OpCode.OP_LEN: { V_ObjLen(ra, env.RB); env.Base = ci.BaseIndex; break; } case OpCode.OP_CONCAT: { int b = i.GETARG_B(); int c = i.GETARG_C(); Top = Stack[env.Base + c + 1]; V_Concat(c - b + 1); env.Base = ci.BaseIndex; ra = env.RA; // 'V_Concat' may invoke TMs and move the stack StkId rb = env.RB; ra.V.SetObj(ref rb.V); Top = Stack[ci.TopIndex]; // restore top break; } case OpCode.OP_JMP: { V_DoJump(ci, i, 0); break; } case OpCode.OP_EQ: { var lhs = env.RKB; var rhs = env.RKC; var expectEq = i.GETARG_A() != 0; #if DEBUG_OP_EQ ULDebug.Log("[VM] ==== OP_EQ lhs:" + lhs); ULDebug.Log("[VM] ==== OP_EQ rhs:" + rhs); ULDebug.Log("[VM] ==== OP_EQ expectEq:" + expectEq); ULDebug.Log("[VM] ==== OP_EQ (lhs.V == rhs.V):" + (lhs.V == rhs.V)); #endif if ((lhs.V == rhs.V) != expectEq) { ci.SavedPc.Index += 1; // skip next jump instruction } else { V_DoNextJump(ci); } env.Base = ci.BaseIndex; break; } case OpCode.OP_LT: { var expectCmpResult = i.GETARG_A() != 0; if (V_LessThan(env.RKB, env.RKC) != expectCmpResult) { ci.SavedPc.Index += 1; } else { V_DoNextJump(ci); } env.Base = ci.BaseIndex; break; } case OpCode.OP_LE: { var expectCmpResult = i.GETARG_A() != 0; if (V_LessEqual(env.RKB, env.RKC) != expectCmpResult) { ci.SavedPc.Index += 1; } else { V_DoNextJump(ci); } env.Base = ci.BaseIndex; break; } case OpCode.OP_TEST: { if ((i.GETARG_C() != 0) ? IsFalse(ref ra.V) : !IsFalse(ref ra.V)) { ci.SavedPc.Index += 1; } else { V_DoNextJump(ci); } env.Base = ci.BaseIndex; break; } case OpCode.OP_TESTSET: { var rb = env.RB; if ((i.GETARG_C() != 0) ? IsFalse(ref rb.V) : !IsFalse(ref rb.V)) { ci.SavedPc.Index += 1; } else { ra.V.SetObj(ref rb.V); V_DoNextJump(ci); } env.Base = ci.BaseIndex; break; } case OpCode.OP_CALL: { int b = i.GETARG_B(); int nresults = i.GETARG_C() - 1; if (b != 0) { Top = Stack[ra.Index + b]; } // else previous instruction set top if (D_PreCall(ra, nresults)) // C# function? { if (nresults >= 0) { Top = Stack[ci.TopIndex]; } env.Base = ci.BaseIndex; } else // Lua function { ci = CI; ci.CallStatus |= CallStatus.CIST_REENTRY; goto newframe; } break; } case OpCode.OP_TAILCALL: { int b = i.GETARG_B(); if (b != 0) { Top = Stack[ra.Index + b]; } // else previous instruction set top Utl.Assert(i.GETARG_C() - 1 == LuaDef.LUA_MULTRET); var called = D_PreCall(ra, LuaDef.LUA_MULTRET); // C# function ? if (called) { env.Base = ci.BaseIndex; } // LuaFunciton else { var nci = CI; // called frame var oci = BaseCI[CI.Index - 1]; // caller frame StkId nfunc = Stack[nci.FuncIndex]; // called function StkId ofunc = Stack[oci.FuncIndex]; // caller function var ncl = nfunc.V.ClLValue(); var ocl = ofunc.V.ClLValue(); // last stack slot filled by 'precall' int lim = nci.BaseIndex + ncl.Proto.NumParams; if (cl.Proto.P.Count > 0) { F_Close(Stack[env.Base]); } // move new frame into old one var nindex = nfunc.Index; var oindex = ofunc.Index; while (nindex < lim) { Stack[oindex++].V.SetObj(ref Stack[nindex++].V); } oci.BaseIndex = ofunc.Index + (nci.BaseIndex - nfunc.Index); oci.TopIndex = ofunc.Index + (Top.Index - nfunc.Index); Top = Stack[oci.TopIndex]; oci.SavedPc = nci.SavedPc; oci.CallStatus |= CallStatus.CIST_TAIL; ci = CI = oci; ocl = ofunc.V.ClLValue(); Utl.Assert(Top.Index == oci.BaseIndex + ocl.Proto.MaxStackSize); goto newframe; } break; } case OpCode.OP_RETURN: { int b = i.GETARG_B(); if (b != 0) { Top = Stack[ra.Index + b - 1]; } if (cl.Proto.P.Count > 0) { F_Close(Stack[env.Base]); } b = D_PosCall(ra.Index); if ((ci.CallStatus & CallStatus.CIST_REENTRY) == 0) { return; } else { ci = CI; if (b != 0) { Top = Stack[ci.TopIndex]; } goto newframe; } } case OpCode.OP_FORLOOP: { var ra1 = Stack[ra.Index + 1]; var ra2 = Stack[ra.Index + 2]; var ra3 = Stack[ra.Index + 3]; var step = ra2.V.NValue; var idx = ra.V.NValue + step; // increment index var limit = ra1.V.NValue; if ((0 < step) ? idx <= limit : limit <= idx) { ci.SavedPc.Index += i.GETARG_sBx(); // jump back ra.V.SetNValue(idx); // updateinternal index... ra3.V.SetNValue(idx); // ... and external index } break; } case OpCode.OP_FORPREP: { var init = new TValue(); var limit = new TValue(); var step = new TValue(); var ra1 = Stack[ra.Index + 1]; var ra2 = Stack[ra.Index + 2]; // WHY: why limit is not used ? if (!V_ToNumber(ra, ref init)) { G_RunError("'for' initial value must be a number"); } if (!V_ToNumber(ra1, ref limit)) { G_RunError("'for' limit must be a number"); } if (!V_ToNumber(ra2, ref step)) { G_RunError("'for' step must be a number"); } ra.V.SetNValue(init.NValue - step.NValue); ci.SavedPc.Index += i.GETARG_sBx(); break; } case OpCode.OP_TFORCALL: { int rai = ra.Index; int cbi = ra.Index + 3; Stack[cbi + 2].V.SetObj(ref Stack[rai + 2].V); Stack[cbi + 1].V.SetObj(ref Stack[rai + 1].V); Stack[cbi].V.SetObj(ref Stack[rai].V); StkId callBase = Stack[cbi]; Top = Stack[cbi + 3]; // func. +2 args (state and index) D_Call(callBase, i.GETARG_C(), true); env.Base = ci.BaseIndex; Top = Stack[ci.TopIndex]; i = ci.SavedPc.ValueInc; // go to next instruction env.I = i; ra = env.RA; DumpStack(env.Base); #if DEBUG_INSTRUCTION ULDebug.Log("[VM] ============================================================ OP_TFORCALL Instruction: " + i); #endif Utl.Assert(i.GET_OPCODE() == OpCode.OP_TFORLOOP); goto l_tforloop; } case OpCode.OP_TFORLOOP: l_tforloop: { StkId ra1 = Stack[ra.Index + 1]; if (!ra1.V.TtIsNil()) // continue loop? { ra.V.SetObj(ref ra1.V); ci.SavedPc += i.GETARG_sBx(); } break; } // sets the values for a range of array elements in a table(RA) // RA -> table // RB -> number of elements to set // C -> encodes the block number of the table to be initialized // the values used to initialize the table are located in // R(A+1), R(A+2) ... case OpCode.OP_SETLIST: { int n = i.GETARG_B(); int c = i.GETARG_C(); if (n == 0) { n = (Top.Index - ra.Index) - 1; } if (c == 0) { Utl.Assert(ci.SavedPc.Value.GET_OPCODE() == OpCode.OP_EXTRAARG); c = ci.SavedPc.ValueInc.GETARG_Ax(); } var tbl = ra.V.HValue(); Utl.Assert(tbl != null); int last = ((c - 1) * LuaDef.LFIELDS_PER_FLUSH) + n; int rai = ra.Index; for (; n > 0; --n) { tbl.SetInt(last--, ref Stack[rai + n].V); } #if DEBUG_OP_SETLIST ULDebug.Log("[VM] ==== OP_SETLIST ci.Top:" + ci.Top.Index); ULDebug.Log("[VM] ==== OP_SETLIST Top:" + Top.Index); #endif Top = Stack[ci.TopIndex]; // correct top (in case of previous open call) break; } case OpCode.OP_CLOSURE: { LuaProto p = cl.Proto.P[i.GETARG_Bx()]; V_PushClosure(p, cl.Upvals, env.Base, ra); #if DEBUG_OP_CLOSURE ULDebug.Log("OP_CLOSURE:" + ra.Value); var racl = ra.Value as LuaLClosure; if (racl != null) { for (int ii = 0; ii < racl.Upvals.Count; ++ii) { ULDebug.Log(ii + " ) " + racl.Upvals[ii]); } } #endif break; } /// <summary> /// VARARG implements the vararg operator `...' in expressions. /// VARARG copies B-1 parameters into a number of registers /// starting from R(A), padding with nils if there aren't enough values. /// If B is 0, VARARG copies as many values as it can based on /// the number of parameters passed. /// If a fixed number of values is required, B is a value greater than 1. /// If any number of values is required, B is 0. /// </summary> case OpCode.OP_VARARG: { int b = i.GETARG_B() - 1; int n = (env.Base - ci.FuncIndex) - cl.Proto.NumParams - 1; if (b < 0) // B == 0? { b = n; D_CheckStack(n); ra = env.RA; // previous call may change the stack Top = Stack[ra.Index + n]; } var p = ra.Index; var q = env.Base - n; for (int j = 0; j < b; ++j) { if (j < n) { Stack[p++].V.SetObj(ref Stack[q++].V); } else { Stack[p++].V.SetNilValue(); } } break; } case OpCode.OP_EXTRAARG: { Utl.Assert(false); V_NotImplemented(i); break; } default: V_NotImplemented(i); break; } } }
public static void Posfix(FuncState fs, BinOpr op, ExpDesc e1, ExpDesc e2, int line) { switch (op) { case BinOpr.AND: { Utl.Assert(e1.ExitTrue == NO_JUMP); DischargeVars(fs, e2); e2.ExitFalse = Concat(fs, e2.ExitFalse, e1.ExitFalse); e1.CopyFrom(e2); break; } case BinOpr.OR: { Utl.Assert(e1.ExitFalse == NO_JUMP); DischargeVars(fs, e2); e2.ExitTrue = Concat(fs, e2.ExitTrue, e1.ExitTrue); e1.CopyFrom(e2); break; } case BinOpr.CONCAT: { Exp2Val(fs, e2); var pe2 = fs.GetCode(e2); if (e2.Kind == ExpKind.VRELOCABLE && pe2.Value.GET_OPCODE() == OpCode.OP_CONCAT) { Utl.Assert(e1.Info == pe2.Value.GETARG_B() - 1); FreeExp(fs, e1); pe2.Value = pe2.Value.SETARG_B(e1.Info); e1.Kind = ExpKind.VRELOCABLE; e1.Info = e2.Info; } else { // operand must be on the `stack' Exp2NextReg(fs, e2); CodeArith(fs, OpCode.OP_CONCAT, e1, e2, line); } break; } case BinOpr.ADD: { CodeArith(fs, OpCode.OP_ADD, e1, e2, line); break; } case BinOpr.SUB: { CodeArith(fs, OpCode.OP_SUB, e1, e2, line); break; } case BinOpr.MUL: { CodeArith(fs, OpCode.OP_MUL, e1, e2, line); break; } case BinOpr.DIV: { CodeArith(fs, OpCode.OP_DIV, e1, e2, line); break; } case BinOpr.MOD: { CodeArith(fs, OpCode.OP_MOD, e1, e2, line); break; } case BinOpr.POW: { CodeArith(fs, OpCode.OP_POW, e1, e2, line); break; } case BinOpr.EQ: { CodeComp(fs, OpCode.OP_EQ, 1, e1, e2); break; } case BinOpr.LT: { CodeComp(fs, OpCode.OP_LT, 1, e1, e2); break; } case BinOpr.LE: { CodeComp(fs, OpCode.OP_LE, 1, e1, e2); break; } case BinOpr.NE: { CodeComp(fs, OpCode.OP_EQ, 0, e1, e2); break; } case BinOpr.GT: { CodeComp(fs, OpCode.OP_LT, 0, e1, e2); break; } case BinOpr.GE: { CodeComp(fs, OpCode.OP_LE, 0, e1, e2); break; } default: Utl.Assert(false); break; } }
public Token GetLookAhead() { Utl.Assert(LookAhead == null); LookAhead = _Lex(); return(LookAhead); }