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 F_Load(ref LoadParameter param) { var L = param.L; LuaProto proto; var c = param.LoadInfo.PeekByte(); if (c == LuaConf.LUA_SIGNATURE[0]) { L.CheckMode(param.Mode, "binary"); proto = Undump.LoadBinary(L, param.LoadInfo, param.Name); } else { L.CheckMode(param.Mode, "text"); proto = Parser.Parse(L, param.LoadInfo, param.Name); } var cl = new LuaLClosureValue(proto); Utl.Assert(cl.Upvals.Length == cl.Proto.Upvalues.Count); L.Top.V.SetClLValue(cl); L.IncrTop(); }
string ILuaAPI.ToString(int index) { StkId addr; if (!Index2Addr(index, out addr)) { return(null); } if (addr.V.TtIsString()) { return(addr.V.OValue as string); } if (!V_ToString(ref addr.V)) { return(null); } if (!Index2Addr(index, out addr)) { return(null); } Utl.Assert(addr.V.TtIsString()); return(addr.V.OValue as string); }
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); }
internal int GetCurrentLine(CallInfo ci) { Utl.Assert(ci.IsLua); LuaLClosureValue cl = Stack[ci.FuncIndex].V.ClLValue(); return(cl.Proto.GetFuncLine(ci.CurrentPc)); }
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 void FuncInfo(LuaDebug ar, StkId func) { Utl.Assert(func.V.TtIsFunction()); if (func.V.ClIsLuaClosure()) { var lcl = func.V.ClLValue(); var 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()) { var lcl = func.V.ClLValue(); var p = lcl.Proto; var lineinfo = p.LineInfo; var t = new LuaTable(this); Top.V.SetHValue(t); IncrTop(); var 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 static void FreeReg(FuncState fs, int reg) { if (!Instruction.ISK(reg) && reg >= fs.NumActVar) { fs.FreeReg--; Utl.Assert(reg == fs.FreeReg); } }
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); }
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 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; }
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 bool Index2Addr(int index, out StkId addr) { CallInfo ci = CI; if (index > 0) { var addrIndex = ci.FuncIndex + index; Utl.ApiCheck(index <= ci.TopIndex - (ci.FuncIndex + 1), "unacceptable index"); if (addrIndex >= Top.Index) { addr = default(StkId); return(false); } addr = Stack[addrIndex]; return(true); } else if (index > LuaDef.LUA_REGISTRYINDEX) { Utl.ApiCheck(index != 0 && -index <= Top.Index - (ci.FuncIndex + 1), "invalid index"); addr = Stack[Top.Index + index]; return(true); } else if (index == LuaDef.LUA_REGISTRYINDEX) { addr = G.Registry; return(true); } // upvalues else { index = LuaDef.LUA_REGISTRYINDEX - index; Utl.ApiCheck(index <= LuaLimits.MAXUPVAL + 1, "upvalue index too large"); var func = Stack[ci.FuncIndex]; Utl.Assert(func.V.TtIsFunction()); if (func.V.ClIsLcsClosure()) { addr = default(StkId); return(false); } Utl.Assert(func.V.ClIsCsClosure()); var clcs = func.V.ClCsValue(); if (index > clcs.Upvals.Length) { addr = default(StkId); return(false); } addr = clcs.Upvals[index - 1]; return(true); } }
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 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); } }
// do the work for `lua_resume' in protected mode private void Resume(int firstArg) { int numCSharpCalls = NumCSharpCalls; CallInfo ci = CI; if (numCSharpCalls >= LuaLimits.LUAI_MAXCCALLS) { ResumeError("C stack overflow", firstArg); } if (Status == ThreadStatus.LUA_OK) // may be starting a coroutine { if (ci.Index > 0) // not in base level { ResumeError("cannot resume non-suspended coroutine", firstArg); } if (!D_PreCall(Stack[firstArg - 1], LuaDef.LUA_MULTRET)) // Lua function? { V_Execute(); // call it } } else if (Status != ThreadStatus.LUA_YIELD) { ResumeError("cannot resume dead coroutine", firstArg); } else // resume from previous yield { Status = ThreadStatus.LUA_OK; ci.FuncIndex = ci.ExtraIndex; if (ci.IsLua) // yielded inside a hook? { V_Execute(); // just continue running Lua code } else // `common' yield { if (ci.ContinueFunc != null) { ci.Status = ThreadStatus.LUA_YIELD; // `default' status ci.CallStatus |= CallStatus.CIST_YIELDED; int n = ci.ContinueFunc(this); // call continuation Utl.ApiCheckNumElems(this, n); firstArg = Top.Index - n; // yield results come from continuation } D_PosCall(firstArg); } Unroll(); } Utl.Assert(numCSharpCalls == NumCSharpCalls); }
ThreadStatus ILuaAPI.Resume(ILuaState from, int numArgs) { LuaState fromState = from as LuaState; NumCSharpCalls = (fromState != null) ? fromState.NumCSharpCalls + 1 : 1; NumNonYieldable = 0; // allow yields Utl.ApiCheckNumElems(this, (Status == ThreadStatus.LUA_OK) ? numArgs + 1 : numArgs); var resumeParam = new ResumeParam(); resumeParam.L = this; resumeParam.firstArg = Top.Index - numArgs; ThreadStatus status = D_RawRunProtected(DG_Resume, ref resumeParam); if (status == ThreadStatus.LUA_RESUME_ERROR) // error calling `lua_resume'? { status = ThreadStatus.LUA_ERRRUN; } else // yield or regular error { while (status != ThreadStatus.LUA_OK && status != ThreadStatus.LUA_YIELD) // error? { if (Recover(status)) // recover point? { var unrollParam = new UnrollParam(); unrollParam.L = this; status = D_RawRunProtected(DG_Unroll, ref unrollParam); } else // unrecoverable error { Status = status; // mark thread as `dead' SetErrorObj(status, Top); CI.TopIndex = Top.Index; break; } } Utl.Assert(status == Status); } NumNonYieldable = 1; // do not allow yields NumCSharpCalls--; Utl.Assert(NumCSharpCalls == ((fromState != null) ? fromState.NumCSharpCalls : 0)); return(status); }
private string GetUpvalueName(CallInfo ci, StkId o, out string name) { var func = Stack[ci.FuncIndex]; Utl.Assert(func.V.TtIsFunction() && func.V.ClIsLuaClosure()); var lcl = func.V.ClLValue(); for (int i = 0; i < lcl.Upvals.Length; ++i) { if (lcl.Upvals[i].V == o) { name = UpvalName(lcl.Proto, i); return("upvalue"); } } name = default(string); return(null); }
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; }
ThreadStatus ILuaAPI.Load(ILoadInfo loadinfo, string name, string mode) { var param = new LoadParameter(this, loadinfo, name, mode); var status = D_PCall(DG_F_Load, ref param, Top.Index, ErrFunc); if (status == ThreadStatus.LUA_OK) { var below = Stack[Top.Index - 1]; Utl.Assert(below.V.TtIsFunction() && below.V.ClIsLuaClosure()); var cl = below.V.ClLValue(); if (cl.Upvals.Length == 1) { var gt = G.Registry.V.HValue().GetInt(LuaDef.LUA_RIDX_GLOBALS); cl.Upvals[0].V.V.SetObj(ref gt.V); } } return(status); }
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; }
public int GetInfo(string what, LuaDebug ar) { CallInfo ci; StkId func; int pos = 0; if (what[pos] == '>') { ci = null; func = Stack[Top.Index - 1]; Utl.ApiCheck(func.V.TtIsFunction(), "function expected"); pos++; Top = Stack[Top.Index - 1]; } else { ci = BaseCI[ar.ActiveCIIndex]; func = Stack[ci.FuncIndex]; Utl.Assert(Stack[ci.FuncIndex].V.TtIsFunction()); } // var IsClosure( func.Value ) ? func.Value int status = AuxGetInfo(what, ar, func, ci); if (what.Contains("f")) { Top.V.SetObj(ref func.V); IncrTop(); } if (what.Contains("L")) { CollectValidLines(func); } return(status); }
int ILuaAPI.YieldK(int numResults, int context, CSharpFunctionDelegate continueFunc) { CallInfo ci = CI; Utl.ApiCheckNumElems(this, numResults); if (NumNonYieldable > 0) { if (this != G.MainThread) { G_RunError("attempt to yield across metamethod/C-call boundary"); } else { G_RunError("attempt to yield from outside a coroutine"); } } Status = ThreadStatus.LUA_YIELD; ci.ExtraIndex = ci.FuncIndex; // save current `func' if (ci.IsLua) // inside a hook { Utl.ApiCheck(continueFunc == null, "hooks cannot continue after yielding"); } else { ci.ContinueFunc = continueFunc; if (ci.ContinueFunc != null) // is there a continuation { ci.Context = context; } ci.FuncIndex = Top.Index - (numResults + 1); D_Throw(ThreadStatus.LUA_YIELD); } Utl.Assert((ci.CallStatus & CallStatus.CIST_HOOKED) != 0); // must be inside a hook return(0); }
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 void FinishCSharpCall() { CallInfo ci = CI; Utl.Assert(ci.ContinueFunc != null); // must have a continuation Utl.Assert(NumNonYieldable == 0); // finish `CallK' AdjustResults(ci.NumResults); // call continuation function if ((ci.CallStatus & CallStatus.CIST_STAT) == 0) // no call status? { ci.Status = ThreadStatus.LUA_YIELD; // `default' status } Utl.Assert(ci.Status != ThreadStatus.LUA_OK); ci.CallStatus = (ci.CallStatus & ~(CallStatus.CIST_YPCALL | CallStatus.CIST_STAT)) | CallStatus.CIST_YIELDED; int n = ci.ContinueFunc(this); // call Utl.ApiCheckNumElems(this, n); // finish `D_PreCall' D_PosCall(Top.Index - n); }