LuaThread.cs 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214
  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 LuaRuntimeException? CurrentException;
  59. internal readonly ReversedStack<CallStackFrame> ExceptionTrace = new();
  60. public bool IsRunning => CallStackFrameCount != 0;
  61. internal LuaFunction? Hook { get; set; }
  62. public LuaStack Stack => CoreData!.Stack;
  63. internal bool IsLineHookEnabled
  64. {
  65. get => LineAndCountHookMask.Flag0;
  66. set => LineAndCountHookMask.Flag0 = value;
  67. }
  68. internal bool IsCountHookEnabled
  69. {
  70. get => LineAndCountHookMask.Flag1;
  71. set => LineAndCountHookMask.Flag1 = value;
  72. }
  73. internal bool IsCallHookEnabled
  74. {
  75. get => CallOrReturnHookMask.Flag0;
  76. set => CallOrReturnHookMask.Flag0 = value;
  77. }
  78. internal bool IsReturnHookEnabled
  79. {
  80. get => CallOrReturnHookMask.Flag1;
  81. set => CallOrReturnHookMask.Flag1 = value;
  82. }
  83. public int CallStackFrameCount => CoreData == null ? 0 : CoreData!.CallStack.Count;
  84. internal LuaThreadAccess CurrentAccess => new(this, CurrentVersion);
  85. public LuaThreadAccess TopLevelAccess => new(this, 0);
  86. public ref readonly CallStackFrame GetCurrentFrame()
  87. {
  88. return ref CoreData!.CallStack.PeekRef();
  89. }
  90. public ReadOnlySpan<LuaValue> GetStackValues()
  91. {
  92. return CoreData == null ? default : CoreData!.Stack.AsSpan();
  93. }
  94. public ReadOnlySpan<CallStackFrame> GetCallStackFrames()
  95. {
  96. return CoreData == null ? default : CoreData!.CallStack.AsSpan();
  97. }
  98. void UpdateCurrentVersion(ref FastStackCore<CallStackFrame> callStack)
  99. {
  100. CurrentVersion = callStack.Count == 0 ? 0 : callStack.PeekRef().Version;
  101. }
  102. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  103. internal LuaThreadAccess PushCallStackFrame(in CallStackFrame frame)
  104. {
  105. CurrentException?.Build();
  106. CurrentException = null;
  107. ref var callStack = ref CoreData!.CallStack;
  108. callStack.Push(frame);
  109. callStack.PeekRef().Version = CurrentVersion = ++LastVersion;
  110. return new LuaThreadAccess(this, CurrentVersion);
  111. }
  112. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  113. internal void PopCallStackFrameWithStackPop()
  114. {
  115. var coreData = CoreData!;
  116. ref var callStack = ref coreData.CallStack;
  117. var popFrame = callStack.Pop();
  118. UpdateCurrentVersion(ref callStack);
  119. if (CurrentException != null)
  120. {
  121. ExceptionTrace.Push(popFrame);
  122. }
  123. coreData.Stack.PopUntil(popFrame.ReturnBase);
  124. }
  125. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  126. internal void PopCallStackFrameWithStackPop(int frameBase)
  127. {
  128. var coreData = CoreData!;
  129. ref var callStack = ref coreData.CallStack;
  130. var popFrame = callStack.Pop();
  131. UpdateCurrentVersion(ref callStack);
  132. if (CurrentException != null)
  133. {
  134. ExceptionTrace.Push(popFrame);
  135. }
  136. {
  137. coreData.Stack.PopUntil(frameBase);
  138. }
  139. }
  140. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  141. internal void PopCallStackFrame()
  142. {
  143. var coreData = CoreData!;
  144. ref var callStack = ref coreData.CallStack;
  145. var popFrame = callStack.Pop();
  146. UpdateCurrentVersion(ref callStack);
  147. if (CurrentException != null)
  148. {
  149. ExceptionTrace.Push(popFrame);
  150. }
  151. }
  152. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  153. internal void PopCallStackFrameUntil(int top)
  154. {
  155. var coreData = CoreData!;
  156. ref var callStack = ref coreData.CallStack;
  157. if (CurrentException != null)
  158. {
  159. ExceptionTrace.Push(callStack.AsSpan()[top..]);
  160. }
  161. callStack.PopUntil(top);
  162. UpdateCurrentVersion(ref callStack);
  163. }
  164. internal void DumpStackValues()
  165. {
  166. var span = GetStackValues();
  167. for (int i = 0; i < span.Length; i++)
  168. {
  169. Console.WriteLine($"LuaStack [{i}]\t{span[i]}");
  170. }
  171. }
  172. public Traceback GetTraceback()
  173. {
  174. return new(State, GetCallStackFrames());
  175. }
  176. }