|
|
@@ -1,175 +1,433 @@
|
|
|
using Lua.CodeAnalysis.Compilation;
|
|
|
-using System.Diagnostics.CodeAnalysis;
|
|
|
using System.Runtime.CompilerServices;
|
|
|
using Lua.Internal;
|
|
|
-using Lua.IO;
|
|
|
-using Lua.Loaders;
|
|
|
using Lua.Platforms;
|
|
|
using Lua.Runtime;
|
|
|
-using Lua.Standard;
|
|
|
using System.Buffers;
|
|
|
-using System.Text;
|
|
|
|
|
|
namespace Lua;
|
|
|
|
|
|
-public sealed class LuaState
|
|
|
+public class LuaState : IDisposable
|
|
|
{
|
|
|
- // states
|
|
|
- readonly LuaMainThread mainThread;
|
|
|
- FastListCore<UpValue> openUpValues;
|
|
|
- FastStackCore<LuaThread> threadStack;
|
|
|
- readonly LuaTable environment;
|
|
|
- readonly LuaTable registry = new();
|
|
|
- readonly UpValue envUpValue;
|
|
|
+ internal LuaState(LuaGlobalState globalState)
|
|
|
+ {
|
|
|
+ GlobalState = globalState;
|
|
|
+ CoreData = ThreadCoreData.Create();
|
|
|
+ }
|
|
|
+
|
|
|
+ internal LuaState(LuaGlobalState globalState, LuaFunction function, bool isProtectedMode)
|
|
|
+ {
|
|
|
+ GlobalState = globalState;
|
|
|
+ CoreData = ThreadCoreData.Create();
|
|
|
+ coroutine = new(this, function, isProtectedMode);
|
|
|
+ }
|
|
|
+
|
|
|
+ public static LuaState Create()
|
|
|
+ {
|
|
|
+ var globalState = LuaGlobalState.Create();
|
|
|
+ return globalState.MainThread;
|
|
|
+ }
|
|
|
|
|
|
+ public static LuaState Create(LuaPlatform platform)
|
|
|
+ {
|
|
|
+ return LuaGlobalState.Create(platform).MainThread;
|
|
|
+ }
|
|
|
|
|
|
- FastStackCore<LuaDebug.LuaDebugBuffer> debugBufferPool;
|
|
|
+ internal static LuaState CreateCoroutine(LuaGlobalState globalState, LuaFunction function, bool isProtectedMode = false)
|
|
|
+ {
|
|
|
+ return new(globalState, function, isProtectedMode);
|
|
|
+ }
|
|
|
|
|
|
- internal int CallCount;
|
|
|
+ public LuaState CreateThread()
|
|
|
+ {
|
|
|
+ return new(GlobalState);
|
|
|
+ }
|
|
|
+
|
|
|
+ public LuaState CreateCoroutine(LuaFunction function, bool isProtectedMode = false)
|
|
|
+ {
|
|
|
+ return new(GlobalState, function, isProtectedMode);
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ public LuaThreadStatus GetStatus()
|
|
|
+ {
|
|
|
+ if (coroutine is not null)
|
|
|
+ {
|
|
|
+ return (LuaThreadStatus)coroutine.status;
|
|
|
+ }
|
|
|
+
|
|
|
+ return LuaThreadStatus.Running;
|
|
|
+ }
|
|
|
+
|
|
|
+ public void UnsafeSetStatus(LuaThreadStatus status)
|
|
|
+ {
|
|
|
+ if (coroutine is null)
|
|
|
+ {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ coroutine.status = (byte)status;
|
|
|
+ }
|
|
|
+
|
|
|
+ public ValueTask<int> ResumeAsync(LuaFunctionExecutionContext context, CancellationToken cancellationToken = default)
|
|
|
+ {
|
|
|
+ if (coroutine is not null)
|
|
|
+ {
|
|
|
+ return coroutine.ResumeAsyncCore(context.State.Stack, context.ArgumentCount, context.ReturnFrameBase, context.State, cancellationToken);
|
|
|
+ }
|
|
|
+
|
|
|
+ return new(context.Return(false, "cannot resume non-suspended coroutine"));
|
|
|
+ }
|
|
|
+
|
|
|
+ public ValueTask<int> ResumeAsync(LuaStack stack, CancellationToken cancellationToken = default)
|
|
|
+ {
|
|
|
+ if (coroutine is not null)
|
|
|
+ {
|
|
|
+ return coroutine.ResumeAsyncCore(stack, stack.Count, 0, null, cancellationToken);
|
|
|
+ }
|
|
|
+
|
|
|
+ stack.Push(false);
|
|
|
+ stack.Push("cannot resume non-suspended coroutine");
|
|
|
+ return new(2);
|
|
|
+ }
|
|
|
+
|
|
|
+ public ValueTask<int> YieldAsync(LuaFunctionExecutionContext context, CancellationToken cancellationToken = default)
|
|
|
+ {
|
|
|
+ if (coroutine is not null)
|
|
|
+ {
|
|
|
+ return coroutine.YieldAsyncCore(context.State.Stack, context.ArgumentCount, context.ReturnFrameBase, context.State, cancellationToken);
|
|
|
+ }
|
|
|
+
|
|
|
+ throw new LuaRuntimeException(context.State, "cannot yield from a non-running coroutine");
|
|
|
+ }
|
|
|
+
|
|
|
+ public ValueTask<int> YieldAsync(LuaStack stack, CancellationToken cancellationToken = default)
|
|
|
+ {
|
|
|
+ if (coroutine is not null)
|
|
|
+ {
|
|
|
+ return coroutine.YieldAsyncCore(stack, stack.Count, 0, null, cancellationToken);
|
|
|
+ }
|
|
|
+
|
|
|
+ throw new LuaRuntimeException(null, "cannot yield from a non-running coroutine");
|
|
|
+ }
|
|
|
+
|
|
|
+ class ThreadCoreData : IPoolNode<ThreadCoreData>
|
|
|
+ {
|
|
|
+ //internal LuaCoroutineData? coroutineData;
|
|
|
+ internal readonly LuaStack Stack = new();
|
|
|
+ internal FastStackCore<CallStackFrame> CallStack;
|
|
|
+
|
|
|
+ void Clear()
|
|
|
+ {
|
|
|
+ Stack.Clear();
|
|
|
+ CallStack.Clear();
|
|
|
+ }
|
|
|
+
|
|
|
+ static LinkedPool<ThreadCoreData> pool;
|
|
|
+ ThreadCoreData? nextNode;
|
|
|
|
|
|
- internal UpValue EnvUpValue => envUpValue;
|
|
|
+ public ref ThreadCoreData? NextNode => ref nextNode;
|
|
|
|
|
|
- internal ref FastStackCore<LuaThread> ThreadStack => ref threadStack;
|
|
|
+ public static ThreadCoreData Create()
|
|
|
+ {
|
|
|
+ if (!pool.TryPop(out var result))
|
|
|
+ {
|
|
|
+ result = new();
|
|
|
+ }
|
|
|
+
|
|
|
+ return result;
|
|
|
+ }
|
|
|
+
|
|
|
+ public void Release()
|
|
|
+ {
|
|
|
+ Clear();
|
|
|
+ pool.TryPush(this);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ FastListCore<UpValue> openUpValues;
|
|
|
+ internal int CallCount;
|
|
|
+ internal LuaGlobalState GlobalState { get; }
|
|
|
+ ThreadCoreData? CoreData;
|
|
|
+ CoroutineCore? coroutine;
|
|
|
+ internal bool IsLineHookEnabled;
|
|
|
+ internal BitFlags2 CallOrReturnHookMask;
|
|
|
+ internal bool IsInHook;
|
|
|
+ internal long HookCount;
|
|
|
+ internal int BaseHookCount;
|
|
|
+ internal int LastPc;
|
|
|
+
|
|
|
+ internal ILuaTracebackBuildable? CurrentException;
|
|
|
+ internal readonly ReversedStack<CallStackFrame> ExceptionTrace = new();
|
|
|
+ internal LuaFunction? LastCallerFunction;
|
|
|
|
|
|
internal ref FastListCore<UpValue> OpenUpValues => ref openUpValues;
|
|
|
+ public bool IsRunning => CallStackFrameCount != 0;
|
|
|
+ public bool IsCoroutine => coroutine != null;
|
|
|
+ internal LuaFunction? Hook { get; set; }
|
|
|
|
|
|
- internal ref FastStackCore<LuaDebug.LuaDebugBuffer> DebugBufferPool => ref debugBufferPool;
|
|
|
+ public LuaFunction? CoroutineFunction => coroutine?.Function;
|
|
|
|
|
|
- public LuaTable Environment => environment;
|
|
|
+ public bool CanResume => GetStatus() == LuaThreadStatus.Suspended;
|
|
|
|
|
|
- public LuaTable Registry => registry;
|
|
|
+ public LuaStack Stack => CoreData!.Stack;
|
|
|
|
|
|
- public LuaTable LoadedModules => registry[ModuleLibrary.LoadedKeyForRegistry].Read<LuaTable>();
|
|
|
+ internal Traceback? LuaTraceback => coroutine?.Traceback;
|
|
|
|
|
|
- public LuaTable PreloadModules => registry[ModuleLibrary.PreloadKeyForRegistry].Read<LuaTable>();
|
|
|
+ public LuaTable Environment => GlobalState.Environment;
|
|
|
|
|
|
- public LuaMainThread MainThread => mainThread;
|
|
|
+ public LuaTable Registry => GlobalState.Registry;
|
|
|
|
|
|
- public LuaThreadAccess RootAccess => new(mainThread, 0);
|
|
|
+ public LuaTable LoadedModules => GlobalState.LoadedModules;
|
|
|
|
|
|
- public LuaPlatform Platform { get; }
|
|
|
+ public LuaTable PreloadModules => GlobalState.PreloadModules;
|
|
|
|
|
|
- public ILuaModuleLoader? ModuleLoader { get; set; }
|
|
|
+ public LuaState MainThread => GlobalState.MainThread;
|
|
|
|
|
|
- public ILuaFileSystem FileSystem => Platform.FileSystem ?? throw new InvalidOperationException("FileSystem is not set. Please set it before access.");
|
|
|
+ public ILuaModuleLoader? ModuleLoader
|
|
|
+ {
|
|
|
+ get => GlobalState.ModuleLoader;
|
|
|
+ set => GlobalState.ModuleLoader = value;
|
|
|
+ }
|
|
|
|
|
|
- public ILuaOsEnvironment OsEnvironment => Platform.OsEnvironment ?? throw new InvalidOperationException("OperatingSystem is not set. Please set it before access.");
|
|
|
+ public LuaPlatform Platform
|
|
|
+ {
|
|
|
+ get => GlobalState.Platform;
|
|
|
+ set => GlobalState.Platform = value;
|
|
|
+ }
|
|
|
|
|
|
+ internal bool IsCallHookEnabled
|
|
|
+ {
|
|
|
+ get => CallOrReturnHookMask.Flag0;
|
|
|
+ set => CallOrReturnHookMask.Flag0 = value;
|
|
|
+ }
|
|
|
|
|
|
- public TimeProvider TimeProvider => Platform.TimeProvider ?? throw new InvalidOperationException("TimeProvider is not set. Please set it before access.");
|
|
|
+ internal bool IsReturnHookEnabled
|
|
|
+ {
|
|
|
+ get => CallOrReturnHookMask.Flag1;
|
|
|
+ set => CallOrReturnHookMask.Flag1 = value;
|
|
|
+ }
|
|
|
|
|
|
- public ILuaStandardIO StandardIO => Platform.StandardIO;
|
|
|
+ public int CallStackFrameCount => CoreData == null ? 0 : CoreData!.CallStack.Count;
|
|
|
|
|
|
- // metatables
|
|
|
- LuaTable? nilMetatable;
|
|
|
- LuaTable? numberMetatable;
|
|
|
- LuaTable? stringMetatable;
|
|
|
- LuaTable? booleanMetatable;
|
|
|
- LuaTable? functionMetatable;
|
|
|
- LuaTable? threadMetatable;
|
|
|
+ public ref readonly CallStackFrame GetCurrentFrame()
|
|
|
+ {
|
|
|
+ return ref CoreData!.CallStack.PeekRef();
|
|
|
+ }
|
|
|
|
|
|
- public static LuaState Create(LuaPlatform? platform = null)
|
|
|
+ public ReadOnlySpan<LuaValue> GetStackValues()
|
|
|
{
|
|
|
- LuaState state = new(platform ?? LuaPlatform.Default);
|
|
|
- return state;
|
|
|
+ return CoreData == null ? default : CoreData!.Stack.AsSpan();
|
|
|
}
|
|
|
|
|
|
- LuaState(LuaPlatform platform)
|
|
|
+ public ReadOnlySpan<CallStackFrame> GetCallStackFrames()
|
|
|
{
|
|
|
- mainThread = new(this);
|
|
|
- environment = new();
|
|
|
- envUpValue = UpValue.Closed(environment);
|
|
|
- registry[ModuleLibrary.LoadedKeyForRegistry] = new LuaTable(0, 8);
|
|
|
- registry[ModuleLibrary.PreloadKeyForRegistry] = new LuaTable(0, 8);
|
|
|
- Platform = platform;
|
|
|
+ return CoreData == null ? default : CoreData!.CallStack.AsSpan();
|
|
|
}
|
|
|
|
|
|
|
|
|
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
|
- internal bool TryGetMetatable(LuaValue value, [NotNullWhen(true)] out LuaTable? result)
|
|
|
- {
|
|
|
- result = value.Type switch
|
|
|
- {
|
|
|
- LuaValueType.Nil => nilMetatable,
|
|
|
- LuaValueType.Boolean => booleanMetatable,
|
|
|
- LuaValueType.String => stringMetatable,
|
|
|
- LuaValueType.Number => numberMetatable,
|
|
|
- LuaValueType.Function => functionMetatable,
|
|
|
- LuaValueType.Thread => threadMetatable,
|
|
|
- LuaValueType.UserData => value.UnsafeRead<ILuaUserData>().Metatable,
|
|
|
- LuaValueType.Table => value.UnsafeRead<LuaTable>().Metatable,
|
|
|
- _ => null
|
|
|
+ internal CallStackFrame CreateCallStackFrame(LuaFunction function, int argumentCount, int returnBase, int callerInstructionIndex)
|
|
|
+ {
|
|
|
+ var state = this;
|
|
|
+ var varArgumentCount = function.GetVariableArgumentCount(argumentCount);
|
|
|
+ if (varArgumentCount != 0)
|
|
|
+ {
|
|
|
+ if (varArgumentCount < 0)
|
|
|
+ {
|
|
|
+ state.Stack.SetTop(state.Stack.Count - varArgumentCount);
|
|
|
+ argumentCount -= varArgumentCount;
|
|
|
+ varArgumentCount = 0;
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ LuaVirtualMachine.PrepareVariableArgument(state.Stack, argumentCount, varArgumentCount);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ CallStackFrame frame = new()
|
|
|
+ {
|
|
|
+ Base = state.Stack.Count - argumentCount,
|
|
|
+ VariableArgumentCount = varArgumentCount,
|
|
|
+ Function = function,
|
|
|
+ ReturnBase = returnBase,
|
|
|
+ CallerInstructionIndex = callerInstructionIndex
|
|
|
};
|
|
|
|
|
|
- return result != null;
|
|
|
+ if (state.IsInHook)
|
|
|
+ {
|
|
|
+ frame.Flags |= CallStackFrameFlags.InHook;
|
|
|
+ }
|
|
|
+
|
|
|
+ return frame;
|
|
|
}
|
|
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
|
- internal void SetMetatable(LuaValue value, LuaTable metatable)
|
|
|
- {
|
|
|
- switch (value.Type)
|
|
|
- {
|
|
|
- case LuaValueType.Nil:
|
|
|
- nilMetatable = metatable;
|
|
|
- break;
|
|
|
- case LuaValueType.Boolean:
|
|
|
- booleanMetatable = metatable;
|
|
|
- break;
|
|
|
- case LuaValueType.String:
|
|
|
- stringMetatable = metatable;
|
|
|
- break;
|
|
|
- case LuaValueType.Number:
|
|
|
- numberMetatable = metatable;
|
|
|
- break;
|
|
|
- case LuaValueType.Function:
|
|
|
- functionMetatable = metatable;
|
|
|
- break;
|
|
|
- case LuaValueType.Thread:
|
|
|
- threadMetatable = metatable;
|
|
|
- break;
|
|
|
- case LuaValueType.UserData:
|
|
|
- value.UnsafeRead<ILuaUserData>().Metatable = metatable;
|
|
|
- break;
|
|
|
- case LuaValueType.Table:
|
|
|
- value.UnsafeRead<LuaTable>().Metatable = metatable;
|
|
|
- break;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- internal UpValue GetOrAddUpValue(LuaThread thread, int registerIndex)
|
|
|
+ internal void PushCallStackFrame(in CallStackFrame frame)
|
|
|
{
|
|
|
- foreach (var upValue in openUpValues.AsSpan())
|
|
|
+ CurrentException?.BuildOrGet();
|
|
|
+ CurrentException = null;
|
|
|
+ ref var callStack = ref CoreData!.CallStack;
|
|
|
+ callStack.Push(frame);
|
|
|
+ }
|
|
|
+
|
|
|
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
|
+ internal void PopCallStackFrameWithStackPop()
|
|
|
+ {
|
|
|
+ var coreData = CoreData!;
|
|
|
+ ref var callStack = ref coreData.CallStack;
|
|
|
+ var popFrame = callStack.Pop();
|
|
|
+ if (CurrentException != null)
|
|
|
{
|
|
|
- if (upValue.RegisterIndex == registerIndex && upValue.Thread == thread)
|
|
|
- {
|
|
|
- return upValue;
|
|
|
- }
|
|
|
+ ExceptionTrace.Push(popFrame);
|
|
|
}
|
|
|
|
|
|
- var newUpValue = UpValue.Open(thread, registerIndex);
|
|
|
- openUpValues.Add(newUpValue);
|
|
|
- return newUpValue;
|
|
|
+ coreData.Stack.PopUntil(popFrame.ReturnBase);
|
|
|
}
|
|
|
|
|
|
- internal void CloseUpValues(LuaThread thread, int frameBase)
|
|
|
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
|
+ internal void PopCallStackFrameWithStackPop(int frameBase)
|
|
|
{
|
|
|
- for (var i = 0; i < openUpValues.Length; i++)
|
|
|
+ var coreData = CoreData!;
|
|
|
+ ref var callStack = ref coreData.CallStack;
|
|
|
+ var popFrame = callStack.Pop();
|
|
|
+ if (CurrentException != null)
|
|
|
{
|
|
|
- var upValue = openUpValues[i];
|
|
|
- if (upValue.Thread != thread)
|
|
|
+ ExceptionTrace.Push(popFrame);
|
|
|
+ }
|
|
|
+
|
|
|
+ {
|
|
|
+ coreData.Stack.PopUntil(frameBase);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
|
+ internal void PopCallStackFrame()
|
|
|
+ {
|
|
|
+ var coreData = CoreData!;
|
|
|
+ ref var callStack = ref coreData.CallStack;
|
|
|
+ var popFrame = callStack.Pop();
|
|
|
+ if (CurrentException != null)
|
|
|
+ {
|
|
|
+ ExceptionTrace.Push(popFrame);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
|
+ internal void PopCallStackFrameUntil(int top)
|
|
|
+ {
|
|
|
+ var coreData = CoreData!;
|
|
|
+ ref var callStack = ref coreData.CallStack;
|
|
|
+ if (CurrentException != null)
|
|
|
+ {
|
|
|
+ ExceptionTrace.Push(callStack.AsSpan()[top..]);
|
|
|
+ }
|
|
|
+
|
|
|
+ callStack.PopUntil(top);
|
|
|
+ }
|
|
|
+
|
|
|
+ public void SetHook(LuaFunction? hook, string mask, int count = 0)
|
|
|
+ {
|
|
|
+ if (hook is null)
|
|
|
+ {
|
|
|
+ HookCount = 0;
|
|
|
+ BaseHookCount = 0;
|
|
|
+ Hook = null;
|
|
|
+ IsLineHookEnabled = false;
|
|
|
+ IsCallHookEnabled = false;
|
|
|
+ IsReturnHookEnabled = false;
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ HookCount = count > 0 ? count + 1 : 0;
|
|
|
+ BaseHookCount = count;
|
|
|
+
|
|
|
+ IsLineHookEnabled = mask.Contains('l');
|
|
|
+ IsCallHookEnabled = mask.Contains('c');
|
|
|
+ IsReturnHookEnabled = mask.Contains('r');
|
|
|
+
|
|
|
+ if (IsLineHookEnabled)
|
|
|
+ {
|
|
|
+ LastPc = CallStackFrameCount > 0 ? GetCurrentFrame().CallerInstructionIndex : -1;
|
|
|
+ }
|
|
|
+
|
|
|
+ Hook = hook;
|
|
|
+ }
|
|
|
+
|
|
|
+ internal void DumpStackValues()
|
|
|
+ {
|
|
|
+ var span = GetStackValues();
|
|
|
+ for (var i = 0; i < span.Length; i++)
|
|
|
+ {
|
|
|
+ Console.WriteLine($"LuaStack [{i}]\t{span[i]}");
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ public Traceback GetTraceback()
|
|
|
+ {
|
|
|
+ return new(this, GetCallStackFrames());
|
|
|
+ }
|
|
|
+
|
|
|
+ public ValueTask<int> RunAsync(LuaFunction function, CancellationToken cancellationToken = default)
|
|
|
+ {
|
|
|
+ return RunAsync(function, 0, Stack.Count, cancellationToken);
|
|
|
+ }
|
|
|
+
|
|
|
+ public ValueTask<int> RunAsync(LuaFunction function, int argumentCount, CancellationToken cancellationToken = default)
|
|
|
+ {
|
|
|
+ return RunAsync(function, argumentCount, Stack.Count - argumentCount, cancellationToken);
|
|
|
+ }
|
|
|
+
|
|
|
+ public async ValueTask<int> RunAsync(LuaFunction function, int argumentCount, int returnBase, CancellationToken cancellationToken = default)
|
|
|
+ {
|
|
|
+ if (function == null)
|
|
|
+ {
|
|
|
+ throw new ArgumentNullException(nameof(function));
|
|
|
+ }
|
|
|
+
|
|
|
+ this.ThrowIfCancellationRequested(cancellationToken);
|
|
|
+ var state = this;
|
|
|
+ var varArgumentCount = function.GetVariableArgumentCount(argumentCount);
|
|
|
+ if (varArgumentCount != 0)
|
|
|
+ {
|
|
|
+ if (varArgumentCount < 0)
|
|
|
+ {
|
|
|
+ state.Stack.SetTop(state.Stack.Count - varArgumentCount);
|
|
|
+ varArgumentCount = 0;
|
|
|
+ }
|
|
|
+ else
|
|
|
{
|
|
|
- continue;
|
|
|
+ LuaVirtualMachine.PrepareVariableArgument(state.Stack, argumentCount, varArgumentCount);
|
|
|
}
|
|
|
|
|
|
- if (upValue.RegisterIndex >= frameBase)
|
|
|
+ argumentCount -= varArgumentCount;
|
|
|
+ }
|
|
|
+
|
|
|
+ CallStackFrame frame = new() { Base = state.Stack.Count - argumentCount, VariableArgumentCount = varArgumentCount, Function = function, ReturnBase = returnBase };
|
|
|
+ if (state.IsInHook)
|
|
|
+ {
|
|
|
+ frame.Flags |= CallStackFrameFlags.InHook;
|
|
|
+ }
|
|
|
+
|
|
|
+ state.PushCallStackFrame(frame);
|
|
|
+ LuaFunctionExecutionContext context = new() { State = state, ArgumentCount = argumentCount, ReturnFrameBase = returnBase };
|
|
|
+ var callStackTop = state.CallStackFrameCount;
|
|
|
+ try
|
|
|
+ {
|
|
|
+ if (CallOrReturnHookMask.Value != 0 && !IsInHook)
|
|
|
{
|
|
|
- upValue.Close();
|
|
|
- openUpValues.RemoveAtSwapBack(i);
|
|
|
- i--;
|
|
|
+ return await LuaVirtualMachine.ExecuteCallHook(context, cancellationToken);
|
|
|
}
|
|
|
+
|
|
|
+ return await function.Func(context, cancellationToken);
|
|
|
+ }
|
|
|
+ finally
|
|
|
+ {
|
|
|
+ PopCallStackFrameUntil(callStackTop - 1);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+
|
|
|
public unsafe LuaClosure Load(ReadOnlySpan<char> chunk, string chunkName, LuaTable? environment = null)
|
|
|
{
|
|
|
Prototype prototype;
|
|
|
@@ -178,7 +436,7 @@ public sealed class LuaState
|
|
|
prototype = Parser.Parse(this, new(ptr, chunk.Length), chunkName);
|
|
|
}
|
|
|
|
|
|
- return new(MainThread, prototype, environment);
|
|
|
+ return new(this, prototype, environment);
|
|
|
}
|
|
|
|
|
|
public LuaClosure Load(ReadOnlySpan<byte> chunk, string? chunkName = null, string mode = "bt", LuaTable? environment = null)
|
|
|
@@ -187,7 +445,7 @@ public sealed class LuaState
|
|
|
{
|
|
|
if (chunk[0] == '\e')
|
|
|
{
|
|
|
- return new(MainThread, Parser.UnDump(chunk, chunkName), environment);
|
|
|
+ return new(this, Parser.UnDump(chunk, chunkName), environment);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
@@ -208,4 +466,46 @@ public sealed class LuaState
|
|
|
ArrayPool<char>.Shared.Return(pooled);
|
|
|
}
|
|
|
}
|
|
|
+
|
|
|
+
|
|
|
+ internal UpValue GetOrAddUpValue(int registerIndex)
|
|
|
+ {
|
|
|
+ foreach (var upValue in openUpValues.AsSpan())
|
|
|
+ {
|
|
|
+ if (upValue.RegisterIndex == registerIndex)
|
|
|
+ {
|
|
|
+ return upValue;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ var newUpValue = UpValue.Open(this, registerIndex);
|
|
|
+ openUpValues.Add(newUpValue);
|
|
|
+ return newUpValue;
|
|
|
+ }
|
|
|
+
|
|
|
+ internal void CloseUpValues(int frameBase)
|
|
|
+ {
|
|
|
+ for (var i = 0; i < openUpValues.Length; i++)
|
|
|
+ {
|
|
|
+ var upValue = openUpValues[i];
|
|
|
+
|
|
|
+ if (upValue.RegisterIndex >= frameBase)
|
|
|
+ {
|
|
|
+ upValue.Close();
|
|
|
+ openUpValues.RemoveAtSwapBack(i);
|
|
|
+ i--;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ public void Dispose()
|
|
|
+ {
|
|
|
+ if (CoreData!.CallStack.Count != 0)
|
|
|
+ {
|
|
|
+ throw new InvalidOperationException("This state is running! Call stack is not empty!!");
|
|
|
+ }
|
|
|
+
|
|
|
+ CoreData.Release();
|
|
|
+ CoreData = null!;
|
|
|
+ }
|
|
|
}
|