LuaThread.cs 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217
  1. using System.Runtime.CompilerServices;
  2. using Lua.Internal;
  3. using Lua.Runtime;
  4. namespace Lua;
  5. public abstract class LuaThread
  6. {
  7. protected LuaThread() { }
  8. public virtual LuaThreadStatus GetStatus()
  9. {
  10. return LuaThreadStatus.Running;
  11. }
  12. public virtual void UnsafeSetStatus(LuaThreadStatus status) { }
  13. public virtual ValueTask<int> ResumeAsync(LuaFunctionExecutionContext context, CancellationToken cancellationToken = default)
  14. {
  15. return new(context.Return(false, "cannot resume non-suspended coroutine"));
  16. }
  17. public virtual ValueTask<int> YieldAsync(LuaFunctionExecutionContext context, CancellationToken cancellationToken = default)
  18. {
  19. throw new LuaRuntimeException(context.Thread, "attempt to yield from outside a coroutine");
  20. }
  21. protected class ThreadCoreData : IPoolNode<ThreadCoreData>
  22. {
  23. //internal LuaCoroutineData? coroutineData;
  24. internal readonly LuaStack Stack = new();
  25. internal FastStackCore<CallStackFrame> CallStack;
  26. public void Clear()
  27. {
  28. Stack.Clear();
  29. CallStack.Clear();
  30. }
  31. static LinkedPool<ThreadCoreData> pool;
  32. ThreadCoreData? nextNode;
  33. public ref ThreadCoreData? NextNode => ref nextNode;
  34. public static ThreadCoreData Create()
  35. {
  36. if (!pool.TryPop(out ThreadCoreData result))
  37. {
  38. result = new ThreadCoreData();
  39. }
  40. return result;
  41. }
  42. public void Release()
  43. {
  44. Clear();
  45. pool.TryPush(this);
  46. }
  47. }
  48. public LuaState State { get; protected set; } = null!;
  49. protected ThreadCoreData? CoreData = new();
  50. internal BitFlags2 LineAndCountHookMask;
  51. internal BitFlags2 CallOrReturnHookMask;
  52. internal bool IsInHook;
  53. internal int HookCount;
  54. internal int BaseHookCount;
  55. internal int LastPc;
  56. internal int LastVersion;
  57. internal int CurrentVersion;
  58. internal ILuaTracebackBuildable? CurrentException;
  59. internal readonly ReversedStack<CallStackFrame> ExceptionTrace = new();
  60. // internal bool CancelRequested;
  61. // internal CancellationToken CancellationToken;
  62. public bool IsRunning => CallStackFrameCount != 0;
  63. internal LuaFunction? Hook { get; set; }
  64. public LuaStack Stack => CoreData!.Stack;
  65. internal bool IsLineHookEnabled
  66. {
  67. get => LineAndCountHookMask.Flag0;
  68. set => LineAndCountHookMask.Flag0 = value;
  69. }
  70. internal bool IsCountHookEnabled
  71. {
  72. get => LineAndCountHookMask.Flag1;
  73. set => LineAndCountHookMask.Flag1 = value;
  74. }
  75. internal bool IsCallHookEnabled
  76. {
  77. get => CallOrReturnHookMask.Flag0;
  78. set => CallOrReturnHookMask.Flag0 = value;
  79. }
  80. internal bool IsReturnHookEnabled
  81. {
  82. get => CallOrReturnHookMask.Flag1;
  83. set => CallOrReturnHookMask.Flag1 = value;
  84. }
  85. public int CallStackFrameCount => CoreData == null ? 0 : CoreData!.CallStack.Count;
  86. internal LuaThreadAccess CurrentAccess => new(this, CurrentVersion);
  87. public LuaThreadAccess TopLevelAccess => new(this, 0);
  88. public ref readonly CallStackFrame GetCurrentFrame()
  89. {
  90. return ref CoreData!.CallStack.PeekRef();
  91. }
  92. public ReadOnlySpan<LuaValue> GetStackValues()
  93. {
  94. return CoreData == null ? default : CoreData!.Stack.AsSpan();
  95. }
  96. public ReadOnlySpan<CallStackFrame> GetCallStackFrames()
  97. {
  98. return CoreData == null ? default : CoreData!.CallStack.AsSpan();
  99. }
  100. void UpdateCurrentVersion(ref FastStackCore<CallStackFrame> callStack)
  101. {
  102. CurrentVersion = callStack.Count == 0 ? 0 : callStack.PeekRef().Version;
  103. }
  104. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  105. internal LuaThreadAccess PushCallStackFrame(in CallStackFrame frame)
  106. {
  107. CurrentException?.BuildOrGet();
  108. CurrentException = null;
  109. ref var callStack = ref CoreData!.CallStack;
  110. callStack.Push(frame);
  111. callStack.PeekRef().Version = CurrentVersion = ++LastVersion;
  112. return new LuaThreadAccess(this, CurrentVersion);
  113. }
  114. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  115. internal void PopCallStackFrameWithStackPop()
  116. {
  117. var coreData = CoreData!;
  118. ref var callStack = ref coreData.CallStack;
  119. var popFrame = callStack.Pop();
  120. UpdateCurrentVersion(ref callStack);
  121. if (CurrentException != null)
  122. {
  123. ExceptionTrace.Push(popFrame);
  124. }
  125. coreData.Stack.PopUntil(popFrame.ReturnBase);
  126. }
  127. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  128. internal void PopCallStackFrameWithStackPop(int frameBase)
  129. {
  130. var coreData = CoreData!;
  131. ref var callStack = ref coreData.CallStack;
  132. var popFrame = callStack.Pop();
  133. UpdateCurrentVersion(ref callStack);
  134. if (CurrentException != null)
  135. {
  136. ExceptionTrace.Push(popFrame);
  137. }
  138. {
  139. coreData.Stack.PopUntil(frameBase);
  140. }
  141. }
  142. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  143. internal void PopCallStackFrame()
  144. {
  145. var coreData = CoreData!;
  146. ref var callStack = ref coreData.CallStack;
  147. var popFrame = callStack.Pop();
  148. UpdateCurrentVersion(ref callStack);
  149. if (CurrentException != null)
  150. {
  151. ExceptionTrace.Push(popFrame);
  152. }
  153. }
  154. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  155. internal void PopCallStackFrameUntil(int top)
  156. {
  157. var coreData = CoreData!;
  158. ref var callStack = ref coreData.CallStack;
  159. if (CurrentException != null)
  160. {
  161. ExceptionTrace.Push(callStack.AsSpan()[top..]);
  162. }
  163. callStack.PopUntil(top);
  164. UpdateCurrentVersion(ref callStack);
  165. }
  166. internal void DumpStackValues()
  167. {
  168. var span = GetStackValues();
  169. for (int i = 0; i < span.Length; i++)
  170. {
  171. Console.WriteLine($"LuaStack [{i}]\t{span[i]}");
  172. }
  173. }
  174. public Traceback GetTraceback()
  175. {
  176. return new(State, GetCallStackFrames());
  177. }
  178. }