public FuncState() { Proto = new LuaProto(); H = new Dictionary<TValue, int>(); NumActVar = 0; FreeReg = 0; }
private void DumpUpvalues(LuaProto proto) { DumpVector(proto.Upvalues, (upval) => { DumpByte(upval.InStack ? (byte)1 : (byte)0); DumpByte((byte)upval.Index); }); }
public FuncState() { Proto = new LuaProto(); H = new Dictionary <TValue, int>(); NumActVar = 0; FreeReg = 0; }
private void FuncInfo(LuaDebug ar, StkId func) { Utl.Assert(func.V.TtIsFunction()); if (func.V.ClIsLuaClosure()) { LuaLClosureValue lcl = func.V.ClLValue(); LuaProto p = lcl.Proto; ar.Source = string.IsNullOrEmpty(p.Source) ? "=?" : p.Source; ar.LineDefined = p.LineDefined; ar.LastLineDefined = p.LastLineDefined; ar.What = (ar.LineDefined == 0) ? "main" : "Lua"; } else if (func.V.ClIsCsClosure()) { ar.Source = "=[C#]"; ar.LineDefined = -1; ar.LastLineDefined = -1; ar.What = "C#"; } else { throw new System.NotImplementedException(); } if (ar.Source.Length > LuaDef.LUA_IDSIZE) { ar.ShortSrc = ar.Source.Substring(0, LuaDef.LUA_IDSIZE); } else { ar.ShortSrc = ar.Source; } }
private void CollectValidLines(StkId func) { Utl.Assert(func.V.TtIsFunction()); if (func.V.ClIsLuaClosure()) { LuaLClosureValue lcl = func.V.ClLValue(); LuaProto p = lcl.Proto; List <int> lineinfo = p.LineInfo; LuaTable t = new LuaTable(this); Top.V.SetHValue(t); IncrTop(); TValue v = new TValue(); v.SetBValue(true); for (int i = 0; i < lineinfo.Count; ++i) { t.SetInt(lineinfo[i], ref v); } } else if (func.V.ClIsCsClosure()) { Top.V.SetNilValue(); IncrTop(); } else { throw new System.NotImplementedException(); } }
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); }); }
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); }
private string GetFuncName(CallInfo ci, out string name) { LuaProto proto = GetCurrentLuaFunc(ci).Proto; // calling function int pc = ci.CurrentPc; // calling instruction index Instruction ins = proto.Code[pc]; // calling instruction TMS tm; switch (ins.GET_OPCODE()) { case OpCode.OP_CALL: case OpCode.OP_TAILCALL: /* get function name */ return(GetObjName(proto, pc, ins.GETARG_A(), out name)); case OpCode.OP_TFORCALL: { /* for iterator */ name = "for iterator"; return("for iterator"); } /* all other instructions can call only through metamethods */ case OpCode.OP_SELF: case OpCode.OP_GETTABUP: case OpCode.OP_GETTABLE: tm = TMS.TM_INDEX; break; case OpCode.OP_SETTABUP: case OpCode.OP_SETTABLE: tm = TMS.TM_NEWINDEX; break; case OpCode.OP_EQ: tm = TMS.TM_EQ; break; case OpCode.OP_ADD: tm = TMS.TM_ADD; break; case OpCode.OP_SUB: tm = TMS.TM_SUB; break; case OpCode.OP_MUL: tm = TMS.TM_MUL; break; case OpCode.OP_DIV: tm = TMS.TM_DIV; break; case OpCode.OP_MOD: tm = TMS.TM_MOD; break; case OpCode.OP_POW: tm = TMS.TM_POW; break; case OpCode.OP_UNM: tm = TMS.TM_UNM; break; case OpCode.OP_LEN: tm = TMS.TM_LEN; break; case OpCode.OP_LT: tm = TMS.TM_LT; break; case OpCode.OP_LE: tm = TMS.TM_LE; break; case OpCode.OP_CONCAT: tm = TMS.TM_CONCAT; break; default: name = null; return(null); /* else no useful name can be found */ } name = GetTagMethodName(tm); return("metamethod"); }
private void LoadConstants(LuaProto proto) { var n = LoadInt(); #if DEBUG_UNDUMP ClientLog.Instance.Log("Load Constants:" + n); #endif proto.K.Clear(); for (int i = 0; i < n; ++i) { int t = (int)LoadByte(); #if DEBUG_UNDUMP ClientLog.Instance.Log("Constant Type:" + t); #endif var v = new StkId(); switch (t) { case (int)LuaType.LUA_TNIL: v.V.SetNilValue(); proto.K.Add(v); break; case (int)LuaType.LUA_TBOOLEAN: v.V.SetBValue(LoadBoolean()); proto.K.Add(v); break; case (int)LuaType.LUA_TNUMBER: v.V.SetNValue(LoadNumber()); proto.K.Add(v); break; case (int)LuaType.LUA_TSTRING: #if DEBUG_UNDUMP ClientLog.Instance.Log("LuaType.LUA_TSTRING"); #endif v.V.SetSValue(LoadString()); proto.K.Add(v); break; default: throw new UndumpException( "LoadConstants unknown type: " + t); } } n = LoadInt(); #if DEBUG_UNDUMP ClientLog.Instance.Log("Load Functions:" + n); #endif proto.P.Clear(); for (int i = 0; i < n; ++i) { proto.P.Add(LoadFunction()); } }
public LuaLClosureValue(LuaProto p) { Proto = p; Upvals = new LuaUpvalue[p.Upvalues.Count]; for (int i = 0; i < p.Upvalues.Count; ++i) { Upvals[i] = new LuaUpvalue(); } }
private void DumpFunction(LuaProto proto) { DumpInt(proto.LineDefined); DumpInt(proto.LastLineDefined); DumpByte((byte)proto.NumParams); DumpByte(proto.IsVarArg ? (byte)1 : (byte)0); DumpByte((byte)proto.MaxStackSize); DumpCode(proto); DumpConstants(proto); DumpUpvalues(proto); DumpDebug(proto); }
private string F_GetLocalName( LuaProto proto, int localNumber, int pc ) { for( int i=0; i<proto.LocVars.Count && proto.LocVars[i].StartPc <= pc; ++i ) { if( pc < proto.LocVars[i].EndPc ) { // is variable active? --localNumber; if( localNumber == 0 ) return proto.LocVars[i].VarName; } } return null; }
public static DumpStatus Dump( LuaProto proto, LuaWriter writer, bool strip) { var d = new DumpState(); d.Writer = writer; d.Strip = strip; d.Status = DumpStatus.OK; d.DumpHeader(); d.DumpFunction(proto); return(d.Status); }
private void LoadCode(LuaProto proto) { var n = LoadInt(); #if DEBUG_UNDUMP ClientLog.Instance.Log("LoadCode n:" + n); #endif proto.Code.Clear(); for (int i = 0; i < n; ++i) { proto.Code.Add(LoadInstruction()); #if DEBUG_UNDUMP ClientLog.Instance.Log("Count:" + proto.Code.Count); ClientLog.Instance.Log("LoadInstruction:" + proto.Code[proto.Code.Count - 1]); #endif } }
private void LoadUpvalues(LuaProto proto) { int n = LoadInt(); #if DEBUG_UNDUMP ULDebug.Log("Load Upvalues:" + n); #endif proto.Upvalues.Clear(); for (int i = 0; i < n; ++i) { UpvalDesc upvalDesc = new UpvalDesc(); upvalDesc.Name = null; upvalDesc.InStack = LoadBoolean(); upvalDesc.Index = (int)LoadByte(); proto.Upvalues.Add(upvalDesc); } }
private void LoadCode(LuaProto proto) { int n = LoadInt(); #if DEBUG_UNDUMP ULDebug.Log("LoadCode n:" + n); #endif proto.Code.Clear(); for (int i = 0; i < n; ++i) { proto.Code.Add(LoadInstruction()); #if DEBUG_UNDUMP ULDebug.Log("Count:" + proto.Code.Count); ULDebug.Log("LoadInstruction:" + proto.Code[proto.Code.Count - 1]); #endif } }
private string F_GetLocalName(LuaProto proto, int localNumber, int pc) { for (int i = 0; i < proto.LocVars.Count && proto.LocVars[i].StartPc <= pc; ++i) { if (pc < proto.LocVars[i].EndPc) // is variable active? { --localNumber; if (localNumber == 0) { return(proto.LocVars[i].VarName); } } } return(null); }
private void DumpDebug(LuaProto proto) { DumpString(Strip ? null : proto.Source); DumpVector((Strip ? null : proto.LineInfo), delegate(int line) { DumpInt(line); }); DumpVector((Strip ? null : proto.LocVars), delegate(LocVar locvar) { DumpString(locvar.VarName); DumpInt(locvar.StartPc); DumpInt(locvar.EndPc); }); DumpVector((Strip ? null : proto.Upvalues), delegate(UpvalDesc upval) { DumpString(upval.Name); }); }
private void DumpDebug(LuaProto proto) { DumpString(Strip ? null : proto.Source); DumpVector((Strip ? null : proto.LineInfo), (line) => { DumpInt(line); }); DumpVector((Strip ? null : proto.LocVars), (locvar) => { DumpString(locvar.VarName); DumpInt(locvar.StartPc); DumpInt(locvar.EndPc); }); DumpVector((Strip ? null : proto.Upvalues), (upval) => { DumpString(upval.Name); }); }
private LuaProto LoadFunction() { #if DEBUG_UNDUMP ClientLog.Instance.Log("LoadFunction enter"); #endif LuaProto proto = new LuaProto(); proto.LineDefined = LoadInt(); proto.LastLineDefined = LoadInt(); proto.NumParams = LoadByte(); proto.IsVarArg = LoadBoolean(); proto.MaxStackSize = LoadByte(); LoadCode(proto); LoadConstants(proto); LoadUpvalues(proto); LoadDebug(proto); return(proto); }
private void LoadUpvalues(LuaProto proto) { var n = LoadInt(); #if DEBUG_UNDUMP ClientLog.Instance.Log("Load Upvalues:" + n); #endif proto.Upvalues.Clear(); for (int i = 0; i < n; ++i) { proto.Upvalues.Add( new UpvalDesc() { Name = null, InStack = LoadBoolean(), Index = (int)LoadByte() }); } }
private void LoadDebug(LuaProto proto) { int n; proto.Source = LoadString(); // LineInfo n = LoadInt(); #if DEBUG_UNDUMP ClientLog.Instance.Log("Load LineInfo:" + n); #endif proto.LineInfo.Clear(); for (int i = 0; i < n; ++i) { proto.LineInfo.Add(LoadInt()); } // LocalVar n = LoadInt(); #if DEBUG_UNDUMP ClientLog.Instance.Log("Load LocalVar:" + n); #endif proto.LocVars.Clear(); for (int i = 0; i < n; ++i) { proto.LocVars.Add( new LocVar() { VarName = LoadString(), StartPc = LoadInt(), EndPc = LoadInt(), }); } // Upvalues' name n = LoadInt(); for (int i = 0; i < n; ++i) { proto.Upvalues[i].Name = LoadString(); } }
private StkId 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" ); StkId fixedArg = Top - actual; // first fixed argument StkId stackBase = Top; // final position of first argument for( int i=0; i<NumFixArgs; ++i ) { Top.ValueInc = fixedArg.Value; fixedArg.ValueInc = new LuaNil(); } return stackBase; }
private void LoadDebug(LuaProto proto) { int n; proto.Source = LoadString(); // LineInfo n = LoadInt(); #if DEBUG_UNDUMP ULDebug.Log("Load LineInfo:" + n); #endif proto.LineInfo.Clear(); for (int i = 0; i < n; ++i) { proto.LineInfo.Add(LoadInt()); } // LocalVar n = LoadInt(); #if DEBUG_UNDUMP ULDebug.Log("Load LocalVar:" + n); #endif proto.LocVars.Clear(); for (int i = 0; i < n; ++i) { LocVar locVar = new LocVar(); locVar.VarName = LoadString(); locVar.StartPc = LoadInt(); locVar.EndPc = LoadInt(); proto.LocVars.Add(locVar); } // Upvalues' name n = LoadInt(); for (int i = 0; i < n; ++i) { proto.Upvalues[i].Name = LoadString(); } }
private void V_PushClosure(LuaProto p, LuaUpvalue[] encup, int stackBase, StkId ra) { var ncl = new LuaLClosureValue(p); ra.V.SetClLValue(ncl); for (int i = 0; i < p.Upvalues.Count; ++i) { // ULDebug.Log( "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ V_PushClosure i:" + i ); // ULDebug.Log( "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ V_PushClosure InStack:" + p.Upvalues[i].InStack ); // ULDebug.Log( "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ V_PushClosure Index:" + p.Upvalues[i].Index ); if (p.Upvalues[i].InStack) // upvalue refers to local variable { ncl.Upvals[i] = F_FindUpval( Stack[stackBase + p.Upvalues[i].Index]); } else // get upvalue from enclosing function { ncl.Upvals[i] = encup[p.Upvalues[i].Index]; } } }
private void KName(LuaProto proto, int pc, int c, out string name) { if (Instruction.ISK(c)) // is `c' a constant { var val = proto.K[Instruction.INDEXK(c)]; if (val.V.TtIsString()) // literal constant? { name = val.V.SValue(); return; } // else no reasonable name found } else // `c' is a register { string what = GetObjName(proto, pc, c, out name); if (what == "constant") // found a constant name { return; // `name' already filled } // else no reasonable name found } name = "?"; // no reasonable name found }
private void LoadCode( LuaProto proto ) { var n = LoadInt(); #if DEBUG_UNDUMP ULDebug.Log( "LoadCode n:" + n ); #endif proto.Code.Clear(); for( int i=0; i<n; ++i ) { proto.Code.Add( LoadInstruction() ); #if DEBUG_UNDUMP ULDebug.Log( "Count:" + proto.Code.Count ); ULDebug.Log( "LoadInstruction:" + proto.Code[proto.Code.Count-1] ); #endif } }
private string UpvalName(LuaProto p, int uv) { // TODO return("(UpvalName:NotImplemented)"); }
private int FindSetReg(LuaProto proto, int lastpc, int reg) { var setreg = -1; // keep last instruction that changed `reg' for (int pc = 0; pc < lastpc; ++pc) { var ins = proto.Code[pc]; var op = ins.GET_OPCODE(); var a = ins.GETARG_A(); switch (op) { case OpCode.OP_LOADNIL: { var b = ins.GETARG_B(); // set registers from `a' to `a+b' if (a <= reg && reg <= a + b) { setreg = pc; } break; } case OpCode.OP_TFORCALL: { // effect all regs above its base if (reg >= a + 2) { setreg = pc; } break; } case OpCode.OP_CALL: case OpCode.OP_TAILCALL: { // effect all registers above base if (reg >= a) { setreg = pc; } break; } case OpCode.OP_JMP: { var b = ins.GETARG_sBx(); var dest = pc + 1 + b; // jump is forward and do not skip `lastpc' if (pc < dest && dest <= lastpc) { pc += b; // do the jump } break; } case OpCode.OP_TEST: { // jumped code can change `a' if (reg == a) { setreg = pc; } break; } default: { // any instruction that set A if (Coder.TestAMode(op) && reg == a) { setreg = pc; } break; } } } return(setreg); }
public LuaLClosure( LuaProto proto ) { Proto = proto; Upvals = new List<LuaUpvalue>(); for( int i=0; i<proto.Upvalues.Count; ++i ) { Upvals.Add( null ); } }
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(Utl.LuaMod(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; } } }
private LuaProto LoadFunction() { #if DEBUG_UNDUMP ULDebug.Log( "LoadFunction enter" ); #endif LuaProto proto = new LuaProto(); proto.LineDefined = LoadInt(); proto.LastLineDefined = LoadInt(); proto.NumParams = LoadByte(); proto.IsVarArg = LoadBoolean(); proto.MaxStackSize = LoadByte(); LoadCode(proto); LoadConstants(proto); LoadUpvalues(proto); LoadDebug(proto); return proto; }
public LuaLClosureValue(LuaProto p) { Proto = p; Upvals = new LuaUpvalue[p.Upvalues.Count]; for(int i=0; i<p.Upvalues.Count; ++i) { Upvals[i] = new LuaUpvalue(); } }
private void V_PushClosure( LuaProto p, List<LuaUpvalue> encup, StkId stackBase, StkId ra ) { LuaLClosure ncl = new LuaLClosure( p ); ra.Value = ncl; for( int i=0; i<p.Upvalues.Count; ++i ) { // Debug.Log( "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ V_PushClosure i:" + i ); // Debug.Log( "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ V_PushClosure InStack:" + p.Upvalues[i].InStack ); // Debug.Log( "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ V_PushClosure Index:" + p.Upvalues[i].Index ); if( p.Upvalues[i].InStack ) // upvalue refers to local variable ncl.Upvals[i] = F_FindUpval( stackBase + p.Upvalues[i].Index ); else // get upvalue from enclosing function ncl.Upvals[i] = encup[ p.Upvalues[i].Index ]; } }
/// <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()) { LuaLClosureValue cl = func.V.ClLValue(); Utl.Assert(cl != null); LuaProto 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()) { LuaCsClosureValue 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 DumpCode(LuaProto proto) { DumpVector(proto.Code, delegate(Instruction ins) { DumpBlock(BitConverter.GetBytes((uint)ins)); }); }
private void V_PushClosure( LuaProto p, LuaUpvalue[] encup, int stackBase, StkId ra ) { var ncl = new LuaLClosureValue( p ); ra.V.SetClLValue(ncl); for( int i=0; i<p.Upvalues.Count; ++i ) { // ULDebug.Log( "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ V_PushClosure i:" + i ); // ULDebug.Log( "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ V_PushClosure InStack:" + p.Upvalues[i].InStack ); // ULDebug.Log( "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ V_PushClosure Index:" + p.Upvalues[i].Index ); if( p.Upvalues[i].InStack ) // upvalue refers to local variable ncl.Upvals[i] = F_FindUpval( Stack[stackBase + p.Upvalues[i].Index] ); else // get upvalue from enclosing function ncl.Upvals[i] = encup[ p.Upvalues[i].Index ]; } }
private void LoadConstants( LuaProto proto ) { var n = LoadInt(); #if DEBUG_UNDUMP ULDebug.Log( "Load Constants:" + n ); #endif proto.K.Clear(); for( int i=0; i<n; ++i ) { int t = (int)LoadByte(); #if DEBUG_UNDUMP ULDebug.Log( "Constant Type:" + t ); #endif var v = new StkId(); switch( t ) { case (int)LuaType.LUA_TNIL: v.V.SetNilValue(); proto.K.Add( v ); break; case (int)LuaType.LUA_TBOOLEAN: v.V.SetBValue(LoadBoolean()); proto.K.Add( v ); break; case (int)LuaType.LUA_TNUMBER: v.V.SetNValue(LoadNumber()); proto.K.Add( v ); break; case (int)LuaType.LUA_TSTRING: #if DEBUG_UNDUMP ULDebug.Log( "LuaType.LUA_TSTRING" ); #endif v.V.SetSValue(LoadString()); proto.K.Add( v ); break; default: throw new UndumpException( "LoadConstants unknown type: " + t ); } } n = LoadInt(); #if DEBUG_UNDUMP ULDebug.Log( "Load Functions:" + n ); #endif proto.P.Clear(); for( int i=0; i<n; ++i ) { proto.P.Add( LoadFunction() ); } }
private void LoadDebug( LuaProto proto ) { int n; proto.Source = LoadString(); // LineInfo n = LoadInt(); #if DEBUG_UNDUMP ULDebug.Log( "Load LineInfo:" + n ); #endif proto.LineInfo.Clear(); for( int i=0; i<n; ++i ) { proto.LineInfo.Add( LoadInt() ); } // LocalVar n = LoadInt(); #if DEBUG_UNDUMP ULDebug.Log( "Load LocalVar:" + n ); #endif proto.LocVars.Clear(); for( int i=0; i<n; ++i ) { proto.LocVars.Add( new LocVar() { VarName = LoadString(), StartPc = LoadInt(), EndPc = LoadInt(), } ); } // Upvalues' name n = LoadInt(); for( int i=0; i<n; ++i ) { proto.Upvalues[i].Name = LoadString(); } }
private void DumpCode(LuaProto proto) { DumpVector(proto.Code, (ins) => { DumpBlock(BitConverter.GetBytes((uint)ins)); }); }
private void LoadUpvalues( LuaProto proto ) { var n = LoadInt(); #if DEBUG_UNDUMP ULDebug.Log( "Load Upvalues:" + n ); #endif proto.Upvalues.Clear(); for( int i=0; i<n; ++i ) { proto.Upvalues.Add( new UpvalDesc() { Name = null, InStack = LoadBoolean(), Index = (int)LoadByte() } ); } }
private void LoadConstants( LuaProto proto ) { var n = LoadInt(); #if DEBUG_UNDUMP Debug.Log( "Load Constants:" + n ); #endif proto.K.Clear(); for( int i=0; i<n; ++i ) { int t = (int)LoadByte(); #if DEBUG_UNDUMP Debug.Log( "Constant Type:" + t ); #endif switch( t ) { case (int)LuaType.LUA_TNIL: proto.K.Add( new LuaNil() ); break; case (int)LuaType.LUA_TBOOLEAN: proto.K.Add( new LuaBoolean( LoadBoolean() ) ); break; case (int)LuaType.LUA_TNUMBER: proto.K.Add( new LuaNumber( LoadNumber() ) ); break; case (int)LuaType.LUA_TSTRING: #if DEBUG_UNDUMP Debug.Log( "LuaType.LUA_TSTRING" ); #endif proto.K.Add( new LuaString( LoadString() ) ); break; default: throw new UndumpException( "LoadConstants unknown type: " + t ); } } n = LoadInt(); #if DEBUG_UNDUMP Debug.Log( "Load Functions:" + n ); #endif proto.P.Clear(); for( int i=0; i<n; ++i ) { proto.P.Add( LoadFunction() ); } }
private string GetObjName(LuaProto proto, int lastpc, int reg, out string name) { name = F_GetLocalName(proto, reg + 1, lastpc); if (name != null) // is a local? { return("local"); } // else try symbolic execution var pc = FindSetReg(proto, lastpc, reg); if (pc != -1) { var ins = proto.Code[pc]; var op = ins.GET_OPCODE(); switch (op) { case OpCode.OP_MOVE: { var b = ins.GETARG_B(); // move from `b' to `a' if (b < ins.GETARG_A()) { return(GetObjName(proto, pc, b, out name)); } break; } case OpCode.OP_GETTABUP: case OpCode.OP_GETTABLE: { var k = ins.GETARG_C(); var t = ins.GETARG_B(); var vn = (op == OpCode.OP_GETTABLE) ? F_GetLocalName(proto, t + 1, pc) : UpvalName(proto, t); KName(proto, pc, k, out name); return((vn == LuaDef.LUA_ENV) ? "global" : "field"); } case OpCode.OP_GETUPVAL: { name = UpvalName(proto, ins.GETARG_B()); return("upvalue"); } case OpCode.OP_LOADK: case OpCode.OP_LOADKX: { var b = (op == OpCode.OP_LOADK) ? ins.GETARG_Bx() : proto.Code[pc + 1].GETARG_Ax(); var val = proto.K[b]; if (val.V.TtIsString()) { name = val.V.SValue(); return("constant"); } break; } case OpCode.OP_SELF: { var k = ins.GETARG_C(); // key index KName(proto, pc, k, out name); return("method"); } default: break; // go through to return null } } return(null); // could not find reasonable name }
private LuaProto AddPrototype() { var p = new LuaProto(); CurFunc.Proto.P.Add( p ); return p; }