// #define DEBUG_D_PRE_CALL // #define DEBUG_D_POS_CALL namespace UniLua { using ULDebug = UniLua.Tools.ULDebug; using InstructionPtr = Pointer; using Exception = System.Exception; public class LuaRuntimeException : Exception { public ThreadStatus ErrCode { get; private set; } public LuaRuntimeException( ThreadStatus errCode ) { ErrCode = errCode; } } public partial class LuaState { internal void D_Throw( ThreadStatus errCode ) { throw new LuaRuntimeException( errCode ); } private ThreadStatus D_RawRunProtected( PFuncDelegate func, ref T ud ) { int oldNumCSharpCalls = NumCSharpCalls; ThreadStatus res = ThreadStatus.LUA_OK; try { func(ref ud); } catch( LuaRuntimeException e ) { NumCSharpCalls = oldNumCSharpCalls; res = e.ErrCode; } NumCSharpCalls = oldNumCSharpCalls; return res; } private void SetErrorObj( ThreadStatus errCode, StkId oldTop ) { switch( errCode ) { case ThreadStatus.LUA_ERRMEM: // memory error? oldTop.V.SetSValue("not enough memory"); break; case ThreadStatus.LUA_ERRERR: oldTop.V.SetSValue("error in error handling"); break; default: // error message on current top oldTop.V.SetObj(ref Stack[Top.Index-1].V); break; } Top = Stack[oldTop.Index+1]; } private ThreadStatus D_PCall( PFuncDelegate func, ref T ud, int oldTopIndex, int errFunc ) { int oldCIIndex = CI.Index; bool oldAllowHook = AllowHook; int oldNumNonYieldable = NumNonYieldable; int oldErrFunc = ErrFunc; ErrFunc = errFunc; ThreadStatus status = D_RawRunProtected( func, ref ud ); if( status != ThreadStatus.LUA_OK ) // an error occurred? { F_Close( Stack[oldTopIndex] ); SetErrorObj( status, Stack[oldTopIndex] ); CI = BaseCI[oldCIIndex]; AllowHook = oldAllowHook; NumNonYieldable = oldNumNonYieldable; } ErrFunc = oldErrFunc; return status; } private void D_Call( StkId func, int nResults, bool allowYield ) { if( ++NumCSharpCalls >= LuaLimits.LUAI_MAXCCALLS ) { if( NumCSharpCalls == LuaLimits.LUAI_MAXCCALLS ) G_RunError( "CSharp Stack Overflow" ); else if( NumCSharpCalls >= (LuaLimits.LUAI_MAXCCALLS + (LuaLimits.LUAI_MAXCCALLS>>3)) ) D_Throw( ThreadStatus.LUA_ERRERR ); } if( !allowYield ) NumNonYieldable++; if( !D_PreCall( func, nResults ) ) // is a Lua function ? V_Execute(); if( !allowYield ) NumNonYieldable--; NumCSharpCalls--; } /// /// return true if function has been executed /// private bool D_PreCall( StkId func, int nResults ) { // prepare for Lua call #if DEBUG_D_PRE_CALL Console.WriteLine( "============================ 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 0 ) { #if DEBUG_D_POS_CALL Console.WriteLine( "[D] ==== PosCall new LuaNil()" ); #endif Stack[resIndex++].V.SetNilValue(); } Top = Stack[resIndex]; #if DEBUG_D_POS_CALL Console.WriteLine( "[D] ==== PosCall return " + (wanted - LuaDef.LUA_MULTRET) ); #endif return (wanted - LuaDef.LUA_MULTRET); } private CallInfo ExtendCI() { int newIndex = CI.Index + 1; if(newIndex >= BaseCI.Length) { int newLength = BaseCI.Length*2; var newBaseCI = new CallInfo[newLength]; int i = 0; while(i < BaseCI.Length) { newBaseCI[i] = BaseCI[i]; newBaseCI[i].List = newBaseCI; ++i; } while(i < newLength) { var newCI = new CallInfo(); newBaseCI[i] = newCI; newCI.List = newBaseCI; newCI.Index = i; ++i; } BaseCI = newBaseCI; CI = newBaseCI[CI.Index]; return newBaseCI[newIndex]; } else { return BaseCI[newIndex]; } } 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; ifunc.Index; --i) { Stack[i].V.SetObj(ref Stack[i-1].V); } IncrTop(); func.V.SetObj(ref tmObj.V); return func; } private void D_CheckStack(int n) { if(StackLast - Top.Index <= n) D_GrowStack(n); // TODO: FOR DEBUGGING // else // CondMoveStack(); } // some space for error handling private const int ERRORSTACKSIZE = LuaConf.LUAI_MAXSTACK + 200; private void D_GrowStack(int n) { int size = Stack.Length; if(size > LuaConf.LUAI_MAXSTACK) D_Throw(ThreadStatus.LUA_ERRERR); int needed = Top.Index + n + LuaDef.EXTRA_STACK; int newsize = 2 * size; if(newsize > LuaConf.LUAI_MAXSTACK) { newsize = LuaConf.LUAI_MAXSTACK; } if(newsize < needed) { newsize = needed; } if(newsize > LuaConf.LUAI_MAXSTACK) { D_ReallocStack(ERRORSTACKSIZE); G_RunError("stack overflow"); } else { D_ReallocStack(newsize); } } private void D_ReallocStack(int size) { Utl.Assert(size <= LuaConf.LUAI_MAXSTACK || size == ERRORSTACKSIZE); var newStack = new StkId[size]; int i = 0; for( ; i