// #define ENABLE_DUMP_STACK // #define DEBUG_RECORD_INS using System.Collections.Generic; namespace UniLua { using InstructionPtr = Pointer; using ULDebug = UniLua.Tools.ULDebug; public struct Pointer { private List List; public int Index { get; set; } public T Value { get { return List[Index]; } set { List[Index] = value; } } public T ValueInc { get { return List[Index++]; } set { List[Index++] = value; } } public Pointer( List list, int index ) : this() { List = list; Index = index; } public Pointer( Pointer other ) : this() { List = other.List; Index = other.Index; } public static Pointer operator +( Pointer lhs, int rhs ) { return new Pointer( lhs.List, lhs.Index + rhs ); } public static Pointer operator -( Pointer lhs, int rhs ) { return new Pointer( lhs.List, lhs.Index - rhs ); } } public enum CallStatus { CIST_NONE = 0, CIST_LUA = (1<<0), /* call is running a Lua function */ CIST_HOOKED = (1<<1), /* call is running a debug hook */ CIST_REENTRY = (1<<2), /* call is running on same invocation of luaV_execute of previous call */ CIST_YIELDED = (1<<3), /* call reentered after suspension */ CIST_YPCALL = (1<<4), /* call is a yieldable protected call */ CIST_STAT = (1<<5), /* call has an error status (pcall) */ CIST_TAIL = (1<<6), /* call was tail called */ } public class CallInfo { public CallInfo[] List; public int Index; public int FuncIndex; public int TopIndex; public int NumResults; public CallStatus CallStatus; public CSharpFunctionDelegate ContinueFunc; public int Context; public int ExtraIndex; public bool OldAllowHook; public int OldErrFunc; public ThreadStatus Status; // for Lua functions public int BaseIndex; public InstructionPtr SavedPc; public bool IsLua { get { return (CallStatus & CallStatus.CIST_LUA) != 0; } } public int CurrentPc { get { Utl.Assert( IsLua ); return SavedPc.Index - 1; } } } public class GlobalState { public StkId Registry; public LuaUpvalue UpvalHead; public LuaTable[] MetaTables; public LuaState MainThread; public GlobalState( LuaState state ) { MainThread = state; Registry = new StkId(); UpvalHead = new LuaUpvalue(); MetaTables = new LuaTable[(int)LuaType.LUA_NUMTAGS]; } } public delegate void LuaHookDelegate(ILuaState lua, LuaDebug ar); public partial class LuaState { public StkId[] Stack; public StkId Top; public int StackSize; public int StackLast; public CallInfo CI; public CallInfo[] BaseCI; public GlobalState G; public int NumNonYieldable; public int NumCSharpCalls; public int ErrFunc; public ThreadStatus Status { get; set; } public bool AllowHook; public byte HookMask; public int BaseHookCount; public int HookCount; public LuaHookDelegate Hook; public LinkedList OpenUpval; #if DEBUG_RECORD_INS private Queue InstructionHistory; #endif private ILuaAPI API; static LuaState() { TheNilValue = new StkId(); TheNilValue.V.SetNilValue(); } public LuaState( GlobalState g=null ) { API = (ILuaAPI)this; NumNonYieldable = 1; NumCSharpCalls = 0; Hook = null; HookMask = 0; BaseHookCount = 0; AllowHook = true; ResetHookCount(); Status = ThreadStatus.LUA_OK; if( g == null ) { G = new GlobalState(this); InitRegistry(); } else { G = g; } OpenUpval = new LinkedList(); ErrFunc = 0; #if DEBUG_RECORD_INS InstructionHistory = new Queue(); #endif InitStack(); } private void IncrTop() { StkId.inc(ref Top); D_CheckStack(0); } private StkId RestoreStack( int index ) { return Stack[index]; } private void ApiIncrTop() { StkId.inc(ref Top); // Console.WriteLine( "[ApiIncrTop] ==== Top.Index:" + Top.Index ); // Console.WriteLine( "[ApiIncrTop] ==== CI.Top.Index:" + CI.Top.Index ); Utl.ApiCheck( Top.Index <= CI.TopIndex, "stack overflow" ); } private void InitStack() { Stack = new StkId[LuaDef.BASIC_STACK_SIZE]; StackSize = LuaDef.BASIC_STACK_SIZE; StackLast = LuaDef.BASIC_STACK_SIZE - LuaDef.EXTRA_STACK; for(int i=0; i {2} {3}" , i-baseIndex , i , inStack ? Stack[i].ToString() : "" , postfix ); sb.Append( body ).Append("\n"); } return sb.ToString(); } public void DumpStack( int baseIndex, string tag="" ) { #if ENABLE_DUMP_STACK Console.WriteLine(DumpStackToString(baseIndex, tag)); #endif } private void ResetHookCount() { HookCount = BaseHookCount; } } }