Browse Source

change: remove LuaThreadAccess and Rename LuaThread to LuaState LuaState to LuaGlobalState

Akeit0 4 months ago
parent
commit
ceec70223c
54 changed files with 1728 additions and 1657 deletions
  1. 4 4
      sandbox/Benchmark/AddBenchmark.cs
  2. 3 3
      sandbox/Benchmark/BenchmarkCore.cs
  3. 4 4
      sandbox/Benchmark/CoroutineBenchmark.cs
  4. 2 2
      sandbox/Benchmark/HookedBenchmark.cs
  5. 9 9
      sandbox/Benchmark/InterpreterSteps.cs
  6. 2 2
      sandbox/Benchmark/NBodyBenchmark.cs
  7. 5 4
      sandbox/ConsoleApp1/Program.cs
  8. 3 5
      sandbox/ConsoleApp2/Program.cs
  9. 3 3
      sandbox/JitTest/Program.cs
  10. 3 3
      src/Lua.SourceGenerator/LuaObjectGenerator.Emit.cs
  11. 1 1
      src/Lua/CodeAnalysis/Compilation/Parser.cs
  12. 1 1
      src/Lua/CodeAnalysis/Compilation/Scanner.cs
  13. 2 2
      src/Lua/CodeAnalysis/Compilation/TempBlock.cs
  14. 67 67
      src/Lua/Exceptions.cs
  15. 255 0
      src/Lua/Internal/CoroutineCore.cs
  16. 323 323
      src/Lua/LuaCoroutine.cs
  17. 2 4
      src/Lua/LuaFunctionExecutionContext.cs
  18. 0 43
      src/Lua/LuaFunctionExtensions.cs
  19. 5 87
      src/Lua/LuaGlobalState.cs
  20. 268 32
      src/Lua/LuaState.cs
  21. 271 18
      src/Lua/LuaStateExtensions.cs
  22. 4 13
      src/Lua/LuaThreadExtensions.cs
  23. 0 36
      src/Lua/LuaUserThread.cs
  24. 0 21
      src/Lua/Runtime/Lease.cs
  25. 8 8
      src/Lua/Runtime/LuaClosure.cs
  26. 0 148
      src/Lua/Runtime/LuaThreadAccess.cs
  27. 0 320
      src/Lua/Runtime/LuaThreadAccessExtensions.cs
  28. 14 14
      src/Lua/Runtime/LuaVirtualMachine.Debug.cs
  29. 160 161
      src/Lua/Runtime/LuaVirtualMachine.cs
  30. 14 15
      src/Lua/Standard/BasicLibrary.cs
  31. 12 12
      src/Lua/Standard/CoroutineLibrary.cs
  32. 36 39
      src/Lua/Standard/DebugLibrary.cs
  33. 4 4
      src/Lua/Standard/Internal/Bit32Helper.cs
  34. 12 12
      src/Lua/Standard/Internal/DateTimeHelper.cs
  35. 10 10
      src/Lua/Standard/Internal/IOHelper.cs
  36. 2 2
      src/Lua/Standard/Internal/MatchState.cs
  37. 24 26
      src/Lua/Standard/ModuleLibrary.cs
  38. 59 0
      src/Lua/Standard/OpenLibsExtensions.cs
  39. 4 4
      src/Lua/Standard/StringLibrary.cs
  40. 5 5
      src/Lua/Standard/TableLibrary.cs
  41. 2 2
      tests/Lua.Tests/AbstractFileTests.cs
  42. 6 6
      tests/Lua.Tests/AsyncTests.cs
  43. 12 12
      tests/Lua.Tests/CancellationTest.cs
  44. 1 1
      tests/Lua.Tests/ConditionalsTests.cs
  45. 5 5
      tests/Lua.Tests/LocalTests.cs
  46. 3 3
      tests/Lua.Tests/LoopTests.cs
  47. 28 36
      tests/Lua.Tests/LuaApiTests.cs
  48. 8 8
      tests/Lua.Tests/LuaObjectTests.cs
  49. 1 1
      tests/Lua.Tests/LuaTests.cs
  50. 11 11
      tests/Lua.Tests/MetatableTests.cs
  51. 12 12
      tests/Lua.Tests/OperatorTests.cs
  52. 36 36
      tests/Lua.Tests/PatternMatchingTests.cs
  53. 2 2
      tests/Lua.Tests/StringTests.cs
  54. 0 55
      tests/Lua.Tests/ValidationTests.cs

+ 4 - 4
sandbox/Benchmark/AddBenchmark.cs

@@ -20,9 +20,9 @@ public class AddBenchmark
     {
         core = new();
         core.Setup("add.lua");
-        core.LuaGlobalCSharpState.OpenStandardLibraries();
+        core.LuaCSharpState.OpenStandardLibraries();
 
-        core.LuaGlobalCSharpState.Environment["add"] = new LuaFunction("add", (context, ct) =>
+        core.LuaCSharpState.Environment["add"] = new LuaFunction("add", (context, ct) =>
         {
             var a = context.GetArgument<double>(0);
             var b = context.GetArgument<double>(1);
@@ -67,14 +67,14 @@ public class AddBenchmark
     [Benchmark(Description = "Lua-CSharp (DoString)")]
     public async Task<LuaValue> Benchmark_LuaCSharp_String()
     {
-        await core.LuaGlobalCSharpState.DoStringAsync(core.SourceText, buffer);
+        await core.LuaCSharpState.DoStringAsync(core.SourceText, buffer);
         return buffer[0];
     }
 
     [Benchmark(Description = "Lua-CSharp (DoFileAsync)")]
     public async Task<LuaValue> Benchmark_LuaCSharp_File()
     {
-        await core.LuaGlobalCSharpState.DoFileAsync(core.FilePath, buffer);
+        await core.LuaCSharpState.DoFileAsync(core.FilePath, buffer);
         return buffer[0];
     }
 }

+ 3 - 3
sandbox/Benchmark/BenchmarkCore.cs

@@ -5,13 +5,13 @@ public class BenchmarkCore : IDisposable
 {
     public NLua.Lua NLuaState => nLuaState;
     public Script MoonSharpState => moonSharpState;
-    public LuaGlobalState LuaGlobalCSharpState => luaGlobalCSharpState;
+    public LuaState LuaCSharpState => luaCSharpState;
     public string FilePath => filePath;
     public string SourceText => sourceText;
 
     NLua.Lua nLuaState = default!;
     Script moonSharpState = default!;
-    LuaGlobalState luaGlobalCSharpState = default!;
+    LuaState luaCSharpState = default!;
     string filePath = default!;
     string sourceText = default!;
 
@@ -25,7 +25,7 @@ public class BenchmarkCore : IDisposable
         nLuaState = new();
 
         // Lua-CSharp
-        luaGlobalCSharpState = LuaGlobalState.Create();
+        luaCSharpState = LuaState.Create();
 
         filePath = FileHelper.GetAbsolutePath(fileName);
         sourceText = File.ReadAllText(filePath);

+ 4 - 4
sandbox/Benchmark/CoroutineBenchmark.cs

@@ -13,8 +13,8 @@ public class CoroutineBenchmark
     public void GlobalSetup()
     {
         core.Setup("coroutine.lua");
-        core.LuaGlobalCSharpState.OpenBasicLibrary();
-        core.LuaGlobalCSharpState.OpenCoroutineLibrary();
+        core.LuaCSharpState.OpenBasicLibrary();
+        core.LuaCSharpState.OpenCoroutineLibrary();
     }
 
     [Benchmark(Description = "MoonSharp (RunString)")]
@@ -44,14 +44,14 @@ public class CoroutineBenchmark
     [Benchmark(Description = "Lua-CSharp (DoString)")]
     public async Task<LuaValue> Benchmark_LuaCSharp_String()
     {
-        await core.LuaGlobalCSharpState.DoStringAsync(core.SourceText, buffer);
+        await core.LuaCSharpState.DoStringAsync(core.SourceText, buffer);
         return buffer[0];
     }
 
     [Benchmark(Description = "Lua-CSharp (DoFileAsync)")]
     public async Task<LuaValue> Benchmark_LuaCSharp_File()
     {
-        await core.LuaGlobalCSharpState.DoFileAsync(core.FilePath, buffer);
+        await core.LuaCSharpState.DoFileAsync(core.FilePath, buffer);
         return buffer[0];
     }
 }

+ 2 - 2
sandbox/Benchmark/HookedBenchmark.cs

@@ -13,7 +13,7 @@ public class HookedBenchmark
     {
         core = new();
         core.Setup("hooked.lua");
-        core.LuaGlobalCSharpState.OpenStandardLibraries();
+        core.LuaCSharpState.OpenStandardLibraries();
     }
 
     [IterationCleanup]
@@ -34,7 +34,7 @@ public class HookedBenchmark
     [Benchmark(Description = "Lua-CSharp (DoString)")]
     public async Task<LuaValue> Benchmark_LuaCSharp_String()
     {
-        await core.LuaGlobalCSharpState.DoStringAsync(core.SourceText, buffer);
+        await core.LuaCSharpState.DoStringAsync(core.SourceText, buffer);
         return buffer[0];
     }
 }

+ 9 - 9
sandbox/Benchmark/InterpreterSteps.cs

@@ -7,7 +7,7 @@ using Lua.Standard;
 public class InterpreterSteps
 {
     string sourceText = default!;
-    LuaGlobalState globalState = default!;
+    LuaState state = default!;
     LuaClosure closure = default!;
 
     [GlobalSetup]
@@ -15,19 +15,19 @@ public class InterpreterSteps
     {
         var filePath = FileHelper.GetAbsolutePath("n-body.lua");
         sourceText = File.ReadAllText(filePath);
-        globalState = LuaGlobalState.Create();
-        globalState.OpenStandardLibraries();
-        closure = globalState.Load(sourceText, sourceText);
+        state = LuaState.Create();
+        state.OpenStandardLibraries();
+        closure = state.Load(sourceText, sourceText);
     }
 
     [IterationSetup]
     public void Setup()
     {
-        globalState = default!;
+        state = default!;
         GC.Collect();
 
-        globalState = LuaGlobalState.Create();
-        globalState.OpenStandardLibraries();
+        state = LuaState.Create();
+        state.OpenStandardLibraries();
     }
 
     [Benchmark]
@@ -40,12 +40,12 @@ public class InterpreterSteps
     [Benchmark]
     public LuaClosure Compile()
     {
-        return globalState.Load(sourceText, sourceText);
+        return state.Load(sourceText, sourceText);
     }
 
     [Benchmark]
     public async ValueTask RunAsync()
     {
-        await globalState.RootAccess.Call(closure, []);
+        await state.Call(closure, []);
     }
 }

+ 2 - 2
sandbox/Benchmark/NBodyBenchmark.cs

@@ -14,7 +14,7 @@ public class NBodyBenchmark
     {
         core = new();
         core.Setup("n-body.lua");
-        core.LuaGlobalCSharpState.OpenStandardLibraries();
+        core.LuaCSharpState.OpenStandardLibraries();
     }
 
     [IterationCleanup]
@@ -52,7 +52,7 @@ public class NBodyBenchmark
     [Benchmark(Description = "Lua-CSharp (DoString)")]
     public async Task<LuaValue> Benchmark_LuaCSharp_String()
     {
-        await core.LuaGlobalCSharpState.DoStringAsync(core.SourceText, buffer);
+        await core.LuaCSharpState.DoStringAsync(core.SourceText, buffer);
         return buffer[0];
     }
 

+ 5 - 4
sandbox/ConsoleApp1/Program.cs

@@ -7,9 +7,10 @@ using System;
 using System.IO;
 using System.Text;
 
-var state = LuaGlobalState.Create();
+var state = LuaState.Create();
+var globalState = state.GlobalState;
 state.OpenStandardLibraries();
-state.Environment["escape"] = new LuaFunction("escape",
+globalState.Environment["escape"] = new LuaFunction("escape",
     (c, _) =>
     {
         var arg = c.HasArgument(0) ? c.GetArgument<string>(0) : "";
@@ -36,8 +37,8 @@ try
     timer.Start();
     for (var i = 0; i < 1000; i++)
     {
-        var count = await state.RootAccess.RunAsync(closure);
-        state.RootAccess.Pop(count);
+        var count = await state.RunAsync(closure);
+        state.Pop(count);
         if (i % 100 == 0)
         {
             Console.WriteLine($"Iteration {i} completed. Time elapsed: {timer.ElapsedMilliseconds} ms");

+ 3 - 5
sandbox/ConsoleApp2/Program.cs

@@ -3,12 +3,11 @@ using Lua;
 using Lua.Standard;
 using System;
 
-var state = LuaGlobalState.Create();
+var state = LuaState.Create();
 state.OpenStandardLibraries();
 {
     var closure = state.Load("return function (a,b,...)  print('a : '..a..' b :'..'args : ',...) end", "@simple");
-    using var threadLease = state.MainThread.RentUserThread();
-    var access = threadLease.State.RootAccess;
+    using var access = LuaState.Create(state.GlobalState);
     {
         var count = await access.RunAsync(closure, 0);
         var results = access.ReadTopValues(count);
@@ -43,8 +42,7 @@ state.OpenStandardLibraries();
         end
         """, "coroutine");
     var f = results[0].Read<LuaClosure>();
-    using var coroutineLease = state.MainThread.RentCoroutine(f);
-    var coroutine = coroutineLease.Thread;
+    using var coroutine = LuaState.CreateCoroutine(state.GlobalState,(f));
     {
         var stack = new LuaStack();
         stack.PushRange("a", "b", "c", "d", "e");

+ 3 - 3
sandbox/JitTest/Program.cs

@@ -11,14 +11,14 @@ using Lua.Standard;
 // dotnet run --configuration Release /p:DefineConstants="CASE_MARKER"
 // to activate the CASE_MARKER
 // JitInspect can be run in Windows and Linux (MacOS is not supported yet)
-var luaState = LuaGlobalState.Create();
+var luaState = LuaState.Create();
 luaState.OpenStandardLibraries();
 var closure = luaState.Load(File.ReadAllBytes(GetAbsolutePath("test.lua")), "test.lua");
 
 for (var i = 0; i < 1000; i++)
 {
-    await luaState.RootAccess.RunAsync(closure);
-    luaState.MainThread.Stack.Clear();
+    await luaState.RunAsync(closure);
+    luaState.Stack.Clear();
 }
 
 var savePath = GetAbsolutePath("history");

+ 3 - 3
src/Lua.SourceGenerator/LuaObjectGenerator.Emit.cs

@@ -333,7 +333,7 @@ partial class LuaObjectGenerator
                     {
                         if (propertyMetadata.IsReadOnly)
                         {
-                            builder.AppendLine($@"throw new global::Lua.LuaRuntimeException(context.Thread, $""'{{key}}' cannot overwrite."");");
+                            builder.AppendLine($@"throw new global::Lua.LuaRuntimeException(context.State, $""'{{key}}' cannot overwrite."");");
                         }
                         else if (propertyMetadata.IsStatic)
                         {
@@ -371,7 +371,7 @@ partial class LuaObjectGenerator
 
                     using (builder.BeginIndentScope())
                     {
-                        builder.AppendLine($@"throw new global::Lua.LuaRuntimeException(context.Thread, $""'{{key}}' cannot overwrite."");");
+                        builder.AppendLine($@"throw new global::Lua.LuaRuntimeException(context.State, $""'{{key}}' cannot overwrite."");");
                     }
                 }
 
@@ -379,7 +379,7 @@ partial class LuaObjectGenerator
 
                 using (builder.BeginIndentScope())
                 {
-                    builder.AppendLine(@$"throw new global::Lua.LuaRuntimeException(context.Thread, $""'{{key}}' not found."");");
+                    builder.AppendLine(@$"throw new global::Lua.LuaRuntimeException(context.State, $""'{{key}}' not found."");");
                 }
             }
 

+ 1 - 1
src/Lua/CodeAnalysis/Compilation/Parser.cs

@@ -935,7 +935,7 @@ class Parser : IPoolNode<Parser>, IDisposable
         Function = Function.CloseMainFunction();
     }
 
-    public static Prototype Parse(LuaGlobalState l, TextReader r, string name)
+    public static Prototype Parse(LuaState l, TextReader r, string name)
     {
         using var p = Get(new()
         {

+ 1 - 1
src/Lua/CodeAnalysis/Compilation/Scanner.cs

@@ -9,7 +9,7 @@ using static Constants;
 
 struct Scanner
 {
-    public LuaGlobalState L;
+    public LuaState L;
     public PooledList<char> Buffer;
     public TextReader R;
     public int Current;

+ 2 - 2
src/Lua/CodeAnalysis/Compilation/TempBlock.cs

@@ -1,9 +1,9 @@
 namespace Lua.CodeAnalysis.Compilation;
 
-readonly ref struct TempBlock(LuaGlobalState globalState)
+readonly ref struct TempBlock(LuaState state)
 {
     public void Dispose()
     {
-        globalState.CallCount--;
+        state.CallCount--;
     }
 }

+ 67 - 67
src/Lua/Exceptions.cs

@@ -88,28 +88,28 @@ interface ILuaTracebackBuildable
 
 public class LuaRuntimeException : Exception, ILuaTracebackBuildable
 {
-    public LuaRuntimeException(LuaState? thread, Exception innerException) : base(innerException.Message, innerException)
+    public LuaRuntimeException(LuaState? state, Exception innerException) : base(innerException.Message, innerException)
     {
-        if (thread != null)
+        if (state != null)
         {
-            thread.CurrentException?.BuildOrGet();
-            thread.ExceptionTrace.Clear();
-            thread.CurrentException = this;
+            state.CurrentException?.BuildOrGet();
+            state.ExceptionTrace.Clear();
+            state.CurrentException = this;
         }
 
-        Thread = thread;
+        State = state;
     }
 
-    public LuaRuntimeException(LuaState? thread, LuaValue errorObject, int level = 1)
+    public LuaRuntimeException(LuaState? state, LuaValue errorObject, int level = 1)
     {
-        if (thread != null)
+        if (state != null)
         {
-            thread.CurrentException?.BuildOrGet();
-            thread.ExceptionTrace.Clear();
-            thread.CurrentException = this;
+            state.CurrentException?.BuildOrGet();
+            state.ExceptionTrace.Clear();
+            state.CurrentException = this;
         }
 
-        Thread = thread;
+        State = state;
 
         ErrorObject = errorObject;
         this.level = level;
@@ -132,31 +132,31 @@ public class LuaRuntimeException : Exception, ILuaTracebackBuildable
         }
     }
 
-    internal LuaState? Thread { get; private set; } = default!;
+    internal LuaState? State { get; private set; } = default!;
     public LuaValue ErrorObject { get; }
 
-    public static void AttemptInvalidOperation(LuaState? thread, string op, LuaValue a, LuaValue b)
+    public static void AttemptInvalidOperation(LuaState? state, string op, LuaValue a, LuaValue b)
     {
         var typeA = a.TypeToString();
         var typeB = b.TypeToString();
         if (typeA == typeB)
         {
-            throw new LuaRuntimeException(thread, $"attempt to {op} two {typeA} values");
+            throw new LuaRuntimeException(state, $"attempt to {op} two {typeA} values");
         }
 
-        throw new LuaRuntimeException(thread, $"attempt to {op} a {typeA} value with a {typeB} value");
+        throw new LuaRuntimeException(state, $"attempt to {op} a {typeA} value with a {typeB} value");
     }
 
-    public static void AttemptInvalidOperation(LuaState? thread, string op, LuaValue a)
+    public static void AttemptInvalidOperation(LuaState? state, string op, LuaValue a)
     {
-        throw new LuaRuntimeException(thread, $"attempt to {op} a {a.TypeToString()} value");
+        throw new LuaRuntimeException(state, $"attempt to {op} a {a.TypeToString()} value");
     }
 
-    internal static void AttemptInvalidOperationOnLuaStack(LuaState thread, string op, int lastPc, int regA, int regB)
+    internal static void AttemptInvalidOperationOnLuaStack(LuaState state, string op, int lastPc, int regA, int regB)
     {
-        var caller = thread.GetCurrentFrame();
-        var luaValueA = regA < 255 ? thread.Stack[caller.Base + regA] : ((LuaClosure)caller.Function).Proto.Constants[regA - 256];
-        var luaValueB = regB < 255 ? thread.Stack[caller.Base + regB] : ((LuaClosure)caller.Function).Proto.Constants[regB - 256];
+        var caller = state.GetCurrentFrame();
+        var luaValueA = regA < 255 ? state.Stack[caller.Base + regA] : ((LuaClosure)caller.Function).Proto.Constants[regA - 256];
+        var luaValueB = regB < 255 ? state.Stack[caller.Base + regB] : ((LuaClosure)caller.Function).Proto.Constants[regB - 256];
         var function = caller.Function;
         var tA = LuaDebug.GetName(((LuaClosure)function).Proto, lastPc, regA, out var nameA);
         var tB = LuaDebug.GetName(((LuaClosure)function).Proto, lastPc, regB, out var nameB);
@@ -181,13 +181,13 @@ public class LuaRuntimeException : Exception, ILuaTracebackBuildable
             builder.AddRange($" ({tB} '{nameB}')");
         }
 
-        throw new LuaRuntimeException(thread, builder.AsSpan().ToString());
+        throw new LuaRuntimeException(state, builder.AsSpan().ToString());
     }
 
-    internal static void AttemptInvalidOperationOnLuaStack(LuaState thread, string op, int lastPc, int reg)
+    internal static void AttemptInvalidOperationOnLuaStack(LuaState state, string op, int lastPc, int reg)
     {
-        var caller = thread.GetCurrentFrame();
-        var luaValue = reg < 255 ? thread.Stack[caller.Base + reg] : ((LuaClosure)caller.Function).Proto.Constants[reg - 256];
+        var caller = state.GetCurrentFrame();
+        var luaValue = reg < 255 ? state.Stack[caller.Base + reg] : ((LuaClosure)caller.Function).Proto.Constants[reg - 256];
         var function = caller.Function;
         var t = LuaDebug.GetName(((LuaClosure)function).Proto, lastPc, reg, out var name);
 
@@ -203,12 +203,12 @@ public class LuaRuntimeException : Exception, ILuaTracebackBuildable
             builder.AddRange($" ({t} '{name}')");
         }
 
-        throw new LuaRuntimeException(thread, builder.AsSpan().ToString());
+        throw new LuaRuntimeException(state, builder.AsSpan().ToString());
     }
 
-    internal static void AttemptInvalidOperationOnUpValues(LuaState thread, string op, int reg)
+    internal static void AttemptInvalidOperationOnUpValues(LuaState state, string op, int reg)
     {
-        var caller = thread.GetCurrentFrame();
+        var caller = state.GetCurrentFrame();
         var closure = (LuaClosure)caller.Function;
         var proto = closure.Proto;
 
@@ -216,22 +216,22 @@ public class LuaRuntimeException : Exception, ILuaTracebackBuildable
         var luaValue = closure.UpValues[upValue.Index].GetValue();
         var name = upValue.Name;
 
-        throw new LuaRuntimeException(thread, $"attempt to {op} a {luaValue.TypeToString()} value (upvalue '{name}')");
+        throw new LuaRuntimeException(state, $"attempt to {op} a {luaValue.TypeToString()} value (upvalue '{name}')");
     }
 
-    internal static (string NameWhat, string Name) GetCurrentFunctionName(LuaState thread)
+    internal static (string NameWhat, string Name) GetCurrentFunctionName(LuaState state)
     {
-        var current = thread.GetCurrentFrame();
+        var current = state.GetCurrentFrame();
         var pc = current.CallerInstructionIndex;
         LuaFunction callerFunction;
         if (current.IsTailCall)
         {
-            pc = thread.LastPc;
-            callerFunction = thread.LastCallerFunction!;
+            pc = state.LastPc;
+            callerFunction = state.LastCallerFunction!;
         }
         else
         {
-            var caller = thread.GetCallStackFrames()[^2];
+            var caller = state.GetCallStackFrames()[^2];
             callerFunction = caller.Function;
         }
 
@@ -243,64 +243,64 @@ public class LuaRuntimeException : Exception, ILuaTracebackBuildable
         return (LuaDebug.GetFuncName(callerClosure.Proto, pc, out var name) ?? "", name ?? current.Function.Name);
     }
 
-    public static void BadArgument(LuaState thread, int argumentId)
+    public static void BadArgument(LuaState state, int argumentId)
     {
-        BadArgument(thread, argumentId, "value expected");
+        BadArgument(state, argumentId, "value expected");
     }
 
 
-    public static void BadArgument(LuaState thread, int argumentId, LuaValueType expected, LuaValueType actual)
+    public static void BadArgument(LuaState state, int argumentId, LuaValueType expected, LuaValueType actual)
     {
-        BadArgument(thread, argumentId, $"{LuaValue.ToString(expected)} expected, got {LuaValue.ToString(actual)})");
+        BadArgument(state, argumentId, $"{LuaValue.ToString(expected)} expected, got {LuaValue.ToString(actual)})");
     }
 
-    public static void BadArgument(LuaState thread, int argumentId, LuaValueType[] expected, LuaValueType actual)
+    public static void BadArgument(LuaState state, int argumentId, LuaValueType[] expected, LuaValueType actual)
     {
-        BadArgument(thread, argumentId, $"({string.Join(" or ", expected.Select(LuaValue.ToString))} expected, got {LuaValue.ToString(actual)})");
+        BadArgument(state, argumentId, $"({string.Join(" or ", expected.Select(LuaValue.ToString))} expected, got {LuaValue.ToString(actual)})");
     }
 
 
-    public static void BadArgument(LuaState thread, int argumentId, string expected, string actual)
+    public static void BadArgument(LuaState state, int argumentId, string expected, string actual)
     {
-        BadArgument(thread, argumentId, $"({expected} expected, got {actual})");
+        BadArgument(state, argumentId, $"({expected} expected, got {actual})");
     }
 
-    public static void BadArgument(LuaState thread, int argumentId, string[] expected, string actual)
+    public static void BadArgument(LuaState state, int argumentId, string[] expected, string actual)
     {
         if (expected.Length == 0)
         {
             throw new ArgumentException("Expected array must not be empty", nameof(expected));
         }
 
-        BadArgument(thread, argumentId, $"({string.Join(" or ", expected)} expected, got {actual})");
+        BadArgument(state, argumentId, $"({string.Join(" or ", expected)} expected, got {actual})");
     }
 
 
-    public static void BadArgument(LuaState thread, int argumentId, string message)
+    public static void BadArgument(LuaState state, int argumentId, string message)
     {
-        var (nameWhat, name) = GetCurrentFunctionName(thread);
+        var (nameWhat, name) = GetCurrentFunctionName(state);
         if (nameWhat == "method")
         {
             argumentId--;
             if (argumentId == 0)
             {
-                throw new LuaRuntimeException(thread, $"calling '{name}' on bad self ({message})");
+                throw new LuaRuntimeException(state, $"calling '{name}' on bad self ({message})");
             }
         }
 
-        throw new LuaRuntimeException(thread, $"bad argument #{argumentId} to '{name}' ({message})");
+        throw new LuaRuntimeException(state, $"bad argument #{argumentId} to '{name}' ({message})");
     }
 
-    public static void BadArgumentNumberIsNotInteger(LuaState thread, int argumentId)
+    public static void BadArgumentNumberIsNotInteger(LuaState state, int argumentId)
     {
-        BadArgument(thread, argumentId, "number has no integer representation");
+        BadArgument(state, argumentId, "number has no integer representation");
     }
 
-    public static void ThrowBadArgumentIfNumberIsNotInteger(LuaState thread, int argumentId, double value)
+    public static void ThrowBadArgumentIfNumberIsNotInteger(LuaState state, int argumentId, double value)
     {
         if (!MathEx.IsInteger(value))
         {
-            BadArgumentNumberIsNotInteger(thread, argumentId);
+            BadArgumentNumberIsNotInteger(state, argumentId);
         }
     }
 
@@ -330,17 +330,17 @@ public class LuaRuntimeException : Exception, ILuaTracebackBuildable
             return luaTraceback;
         }
 
-        if (Thread != null)
+        if (State != null)
         {
-            var callStack = Thread.ExceptionTrace.AsSpan();
+            var callStack = State.ExceptionTrace.AsSpan();
             if (callStack.IsEmpty)
             {
                 return null;
             }
 
-            luaTraceback = new(Thread.GlobalState, callStack);
-            Thread.ExceptionTrace.Clear();
-            Thread = null;
+            luaTraceback = new(State.GlobalState, callStack);
+            State.ExceptionTrace.Clear();
+            State = null;
         }
 
         return luaTraceback;
@@ -348,8 +348,8 @@ public class LuaRuntimeException : Exception, ILuaTracebackBuildable
 
     internal void Forget()
     {
-        Thread?.ExceptionTrace.Clear();
-        Thread = null;
+        State?.ExceptionTrace.Clear();
+        State = null;
     }
 
     internal string MinimalMessage()
@@ -362,9 +362,9 @@ public class LuaRuntimeException : Exception, ILuaTracebackBuildable
 
         if (luaTraceback == null)
         {
-            if (Thread != null)
+            if (State != null)
             {
-                var callStack = Thread.ExceptionTrace.AsSpan();
+                var callStack = State.ExceptionTrace.AsSpan();
                 level = Math.Min(level, callStack.Length + 1);
                 callStack = callStack[..^(level - 1)];
                 if (callStack.IsEmpty)
@@ -473,12 +473,12 @@ public sealed class LuaCanceledException : OperationCanceledException, ILuaTrace
 
     internal LuaState? State { get; private set; }
 
-    internal LuaCanceledException(LuaState thread, CancellationToken cancellationToken, Exception? innerException = null) : base("The operation was cancelled during execution on Lua.", innerException, cancellationToken)
+    internal LuaCanceledException(LuaState state, CancellationToken cancellationToken, Exception? innerException = null) : base("The operation was cancelled during execution on Lua.", innerException, cancellationToken)
     {
-        thread.CurrentException?.BuildOrGet();
-        thread.ExceptionTrace.Clear();
-        thread.CurrentException = this;
-        State = thread;
+        state.CurrentException?.BuildOrGet();
+        state.ExceptionTrace.Clear();
+        state.CurrentException = this;
+        State = state;
     }
 
 

+ 255 - 0
src/Lua/Internal/CoroutineCore.cs

@@ -0,0 +1,255 @@
+using Lua.Internal.CompilerServices;
+using Lua.Runtime;
+using System.Runtime.CompilerServices;
+using System.Threading.Tasks.Sources;
+
+namespace Lua.Internal;
+
+class CoroutineCore:IValueTaskSource<CoroutineCore.YieldContext>, IValueTaskSource<CoroutineCore.ResumeContext>
+{
+    
+    public CoroutineCore(LuaState state, LuaFunction function, bool isProtectedMode)
+    {
+        Thread = state;
+        Function = function;
+        IsProtectedMode = isProtectedMode;
+        status = (byte)LuaThreadStatus.Suspended;
+    }
+    readonly struct YieldContext(LuaStack stack, int argCount)
+    {
+        public ReadOnlySpan<LuaValue> Results => stack.AsSpan()[^argCount..];
+    }
+
+    readonly struct ResumeContext(LuaStack? stack, int argCount)
+    {
+        public ReadOnlySpan<LuaValue> Results => stack!.AsSpan()[^argCount..];
+
+        public bool IsDead => stack == null;
+    }
+    internal byte status ;
+    bool isFirstCall = true;
+    ValueTask<int> functionTask;
+
+    ManualResetValueTaskSourceCore<ResumeContext> resume;
+    ManualResetValueTaskSourceCore<YieldContext> yield;
+    Traceback? traceback;
+    
+    public bool IsProtectedMode { get; private set; }
+    public LuaFunction Function { get; private set; } = null!;
+    
+    public LuaState Thread { get; private set; } = null!;
+    
+    public Traceback? Traceback => traceback;
+    
+    YieldContext IValueTaskSource<YieldContext>.GetResult(short token)
+    {
+        return yield.GetResult(token);
+    }
+
+    ValueTaskSourceStatus IValueTaskSource<YieldContext>.GetStatus(short token)
+    {
+        return yield.GetStatus(token);
+    }
+
+    void IValueTaskSource<YieldContext>.OnCompleted(Action<object?> continuation, object? state, short token, ValueTaskSourceOnCompletedFlags flags)
+    {
+        yield.OnCompleted(continuation, state, token, flags);
+    }
+
+    ResumeContext IValueTaskSource<ResumeContext>.GetResult(short token)
+    {
+        return resume.GetResult(token);
+    }
+
+    ValueTaskSourceStatus IValueTaskSource<ResumeContext>.GetStatus(short token)
+    {
+        return resume.GetStatus(token);
+    }
+
+    void IValueTaskSource<ResumeContext>.OnCompleted(Action<object?> continuation, object? state, short token, ValueTaskSourceOnCompletedFlags flags)
+    {
+        resume.OnCompleted(continuation, state, token, flags);
+    }
+    
+     [AsyncMethodBuilder(typeof(LightAsyncValueTaskMethodBuilder<>))]
+    internal async ValueTask<int> ResumeAsyncCore(LuaStack stack, int argCount, int returnBase, LuaState? baseThread, CancellationToken cancellationToken = default)
+    {
+        if (baseThread != null)
+        {
+            baseThread.UnsafeSetStatus(LuaThreadStatus.Normal);
+
+            baseThread.GlobalState.ThreadStack.Push(Thread);
+        }
+
+        try
+        {
+            switch ((LuaThreadStatus)Volatile.Read(ref status))
+            {
+                case LuaThreadStatus.Suspended:
+                    Volatile.Write(ref status, (byte)LuaThreadStatus.Running);
+
+                    if (!isFirstCall)
+                    {
+                        yield.SetResult(new(stack, argCount));
+                    }
+
+                    break;
+                case LuaThreadStatus.Normal:
+                case LuaThreadStatus.Running:
+                    if (IsProtectedMode)
+                    {
+                        stack.PopUntil(returnBase);
+                        stack.Push(false);
+                        stack.Push("cannot resume non-suspended coroutine");
+                        return 2;
+                    }
+                    else
+                    {
+                        throw new LuaRuntimeException(baseThread, "cannot resume non-suspended coroutine");
+                    }
+                case LuaThreadStatus.Dead:
+                    if (IsProtectedMode)
+                    {
+                        stack.PopUntil(returnBase);
+                        stack.Push(false);
+                        stack.Push("cannot resume dead coroutine");
+                        return 2;
+                    }
+                    else
+                    {
+                        throw new LuaRuntimeException(baseThread, "cannot resume dead coroutine");
+                    }
+            }
+
+            ValueTask<ResumeContext> resumeTask = new(this, resume.Version);
+
+            CancellationTokenRegistration registration = default;
+            if (cancellationToken.CanBeCanceled)
+            {
+                registration = cancellationToken.UnsafeRegister(static x =>
+                {
+                    var coroutine = (CoroutineCore)x!;
+                    coroutine.yield.SetException(new OperationCanceledException());
+                }, this);
+            }
+
+            try
+            {
+                if (isFirstCall)
+                {
+                    Thread.Stack.PushRange(stack.AsSpan()[^argCount..]);
+                    //functionTask = Function.InvokeAsync(new() { Access = this.CurrentAccess, ArgumentCount = Stack.Count, ReturnFrameBase = 0 }, cancellationToken);
+                    functionTask = Thread.RunAsync(Function, Thread.Stack.Count, cancellationToken);
+                    Volatile.Write(ref isFirstCall, false);
+                    if (!functionTask.IsCompleted)
+                    {
+                        functionTask.GetAwaiter().OnCompleted(() => resume.SetResult(default));
+                    }
+                }
+
+                ResumeContext result0;
+                if (functionTask.IsCompleted || (result0 = await resumeTask).IsDead)
+                {
+                    _ = functionTask.Result;
+                    Volatile.Write(ref status, (byte)LuaThreadStatus.Dead);
+                    stack.PopUntil(returnBase);
+                    stack.Push(true);
+                    stack.PushRange(Thread.Stack.AsSpan());
+                    Thread.Dispose();
+                    return stack.Count - returnBase;
+                }
+                else
+                {
+                    Volatile.Write(ref status, (byte)LuaThreadStatus.Suspended);
+                    var results = result0.Results;
+                    stack.PopUntil(returnBase);
+                    stack.Push(true);
+                    stack.PushRange(results);
+                    return results.Length + 1;
+                }
+            }
+            catch (Exception ex) when (ex is not OperationCanceledException)
+            {
+                if (IsProtectedMode)
+                {
+                    if (ex is ILuaTracebackBuildable tracebackBuildable)
+                    {
+                        traceback = tracebackBuildable.BuildOrGet();
+                    }
+
+                    Volatile.Write(ref status, (byte)LuaThreadStatus.Dead);
+                    Thread.Dispose();
+                    stack.PopUntil(returnBase);
+                    stack.Push(false);
+                    stack.Push(ex is LuaRuntimeException luaEx ? luaEx.ErrorObject : ex.Message);
+                    return 2;
+                }
+                else
+                {
+                    throw;
+                }
+            }
+            finally
+            {
+                registration.Dispose();
+                resume.Reset();
+            }
+        }
+        finally
+        {
+            if (baseThread != null)
+            {
+                baseThread.GlobalState.ThreadStack.Pop();
+                baseThread.UnsafeSetStatus(LuaThreadStatus.Running);
+            }
+        }
+    }
+    [AsyncMethodBuilder(typeof(LightAsyncValueTaskMethodBuilder<>))]
+    internal async ValueTask<int> YieldAsyncCore(LuaStack stack, int argCount, int returnBase, LuaState? baseThread, CancellationToken cancellationToken = default)
+    {
+        if (Volatile.Read(ref status) != (byte)LuaThreadStatus.Running)
+        {
+            throw new LuaRuntimeException(baseThread, "cannot yield from a non-running coroutine");
+        }
+
+        if (baseThread != null)
+        {
+            if (baseThread.GetCallStackFrames()[^2].Function is not LuaClosure)
+            {
+                throw new LuaRuntimeException(baseThread, "attempt to yield across a C#-call boundary");
+            }
+        }
+
+        resume.SetResult(new(stack, argCount));
+
+
+        CancellationTokenRegistration registration = default;
+        if (cancellationToken.CanBeCanceled)
+        {
+            registration = cancellationToken.UnsafeRegister(static x =>
+            {
+                var coroutine = (CoroutineCore)x!;
+                coroutine.yield.SetException(new OperationCanceledException());
+            }, this);
+        }
+
+    RETRY:
+        try
+        {
+            var result = await new ValueTask<YieldContext>(this, yield.Version);
+            stack.PopUntil(returnBase);
+            stack.PushRange(result.Results);
+            return result.Results.Length;
+        }
+        catch (Exception ex) when (ex is not OperationCanceledException)
+        {
+            yield.Reset();
+            goto RETRY;
+        }
+        finally
+        {
+            registration.Dispose();
+            yield.Reset();
+        }
+    }
+}

+ 323 - 323
src/Lua/LuaCoroutine.cs

@@ -1,323 +1,323 @@
-using System.Threading.Tasks.Sources;
-using Lua.Internal;
-using Lua.Internal.CompilerServices;
-using Lua.Runtime;
-using System.Runtime.CompilerServices;
-
-namespace Lua;
-
-public sealed class LuaCoroutine : LuaState, IValueTaskSource<LuaCoroutine.YieldContext>, IValueTaskSource<LuaCoroutine.ResumeContext>, IPoolNode<LuaCoroutine>
-{
-    static LinkedPool<LuaCoroutine> pool;
-    LuaCoroutine? nextNode;
-
-    ref LuaCoroutine? IPoolNode<LuaCoroutine>.NextNode => ref nextNode;
-
-    public static LuaCoroutine Create(LuaState parent, LuaFunction function, bool isProtectedMode)
-    {
-        if (!pool.TryPop(out var result))
-        {
-            result = new();
-        }
-
-        result.Init(parent, function, isProtectedMode);
-        return result;
-    }
-
-    public void Release()
-    {
-        if (CoreData != null && CoreData.CallStack.Count != 0)
-        {
-            throw new InvalidOperationException("This thread is running! Call stack is not empty!!");
-        }
-
-        ReleaseCore();
-        pool.TryPush(this);
-    }
-
-    readonly struct YieldContext(LuaStack stack, int argCount)
-    {
-        public ReadOnlySpan<LuaValue> Results => stack.AsSpan()[^argCount..];
-    }
-
-    readonly struct ResumeContext(LuaStack? stack, int argCount)
-    {
-        public ReadOnlySpan<LuaValue> Results => stack!.AsSpan()[^argCount..];
-
-        public bool IsDead => stack == null;
-    }
-
-    byte status;
-    bool isFirstCall = true;
-    ValueTask<int> functionTask;
-
-    ManualResetValueTaskSourceCore<ResumeContext> resume;
-    ManualResetValueTaskSourceCore<YieldContext> yield;
-    Traceback? traceback;
-
-    internal void Init(LuaState parent, LuaFunction function, bool isProtectedMode)
-    {
-        CoreData = ThreadCoreData.Create();
-        GlobalState = parent.GlobalState;
-        IsProtectedMode = isProtectedMode;
-        Function = function;
-    }
-
-    public override LuaThreadStatus GetStatus()
-    {
-        return (LuaThreadStatus)status;
-    }
-
-    public override void UnsafeSetStatus(LuaThreadStatus status)
-    {
-        this.status = (byte)status;
-    }
-
-    public bool IsProtectedMode { get; private set; }
-    public LuaFunction Function { get; private set; } = null!;
-
-    internal Traceback? LuaTraceback => traceback;
-
-    public bool CanResume => status == (byte)LuaThreadStatus.Suspended;
-
-    public ValueTask<int> ResumeAsync(LuaStack stack, CancellationToken cancellationToken = default)
-    {
-        return ResumeAsyncCore(stack, stack.Count, 0, null, cancellationToken);
-    }
-
-    public override ValueTask<int> ResumeAsync(LuaFunctionExecutionContext context, CancellationToken cancellationToken = default)
-    {
-        return ResumeAsyncCore(context.State.Stack, context.ArgumentCount, context.ReturnFrameBase, context.State, cancellationToken);
-    }
-
-
-    [AsyncMethodBuilder(typeof(LightAsyncValueTaskMethodBuilder<>))]
-    async ValueTask<int> ResumeAsyncCore(LuaStack stack, int argCount, int returnBase, LuaState? baseThread, CancellationToken cancellationToken = default)
-    {
-        if (baseThread != null)
-        {
-            baseThread.UnsafeSetStatus(LuaThreadStatus.Normal);
-
-            baseThread.GlobalState.ThreadStack.Push(this);
-        }
-
-        try
-        {
-            switch ((LuaThreadStatus)Volatile.Read(ref status))
-            {
-                case LuaThreadStatus.Suspended:
-                    Volatile.Write(ref status, (byte)LuaThreadStatus.Running);
-
-                    if (!isFirstCall)
-                    {
-                        yield.SetResult(new(stack, argCount));
-                    }
-
-                    break;
-                case LuaThreadStatus.Normal:
-                case LuaThreadStatus.Running:
-                    if (IsProtectedMode)
-                    {
-                        stack.PopUntil(returnBase);
-                        stack.Push(false);
-                        stack.Push("cannot resume non-suspended coroutine");
-                        return 2;
-                    }
-                    else
-                    {
-                        throw new LuaRuntimeException(baseThread, "cannot resume non-suspended coroutine");
-                    }
-                case LuaThreadStatus.Dead:
-                    if (IsProtectedMode)
-                    {
-                        stack.PopUntil(returnBase);
-                        stack.Push(false);
-                        stack.Push("cannot resume dead coroutine");
-                        return 2;
-                    }
-                    else
-                    {
-                        throw new LuaRuntimeException(baseThread, "cannot resume dead coroutine");
-                    }
-            }
-
-            ValueTask<ResumeContext> resumeTask = new(this, resume.Version);
-
-            CancellationTokenRegistration registration = default;
-            if (cancellationToken.CanBeCanceled)
-            {
-                registration = cancellationToken.UnsafeRegister(static x =>
-                {
-                    var coroutine = (LuaCoroutine)x!;
-                    coroutine.yield.SetException(new OperationCanceledException());
-                }, this);
-            }
-
-            try
-            {
-                if (isFirstCall)
-                {
-                    Stack.PushRange(stack.AsSpan()[^argCount..]);
-                    //functionTask = Function.InvokeAsync(new() { Access = this.CurrentAccess, ArgumentCount = Stack.Count, ReturnFrameBase = 0 }, cancellationToken);
-                    functionTask = CurrentAccess.RunAsync(Function, Stack.Count, cancellationToken);
-                    Volatile.Write(ref isFirstCall, false);
-                    if (!functionTask.IsCompleted)
-                    {
-                        functionTask.GetAwaiter().OnCompleted(() => resume.SetResult(default));
-                    }
-                }
-
-                ResumeContext result0;
-                if (functionTask.IsCompleted || (result0 = await resumeTask).IsDead)
-                {
-                    _ = functionTask.Result;
-                    Volatile.Write(ref status, (byte)LuaThreadStatus.Dead);
-                    stack.PopUntil(returnBase);
-                    stack.Push(true);
-                    stack.PushRange(Stack.AsSpan());
-                    ReleaseCore();
-                    return stack.Count - returnBase;
-                }
-                else
-                {
-                    Volatile.Write(ref status, (byte)LuaThreadStatus.Suspended);
-                    var results = result0.Results;
-                    stack.PopUntil(returnBase);
-                    stack.Push(true);
-                    stack.PushRange(results);
-                    return results.Length + 1;
-                }
-            }
-            catch (Exception ex) when (ex is not OperationCanceledException)
-            {
-                if (IsProtectedMode)
-                {
-                    if (ex is ILuaTracebackBuildable tracebackBuildable)
-                    {
-                        traceback = tracebackBuildable.BuildOrGet();
-                    }
-
-                    Volatile.Write(ref status, (byte)LuaThreadStatus.Dead);
-                    ReleaseCore();
-                    stack.PopUntil(returnBase);
-                    stack.Push(false);
-                    stack.Push(ex is LuaRuntimeException luaEx ? luaEx.ErrorObject : ex.Message);
-                    return 2;
-                }
-                else
-                {
-                    throw;
-                }
-            }
-            finally
-            {
-                registration.Dispose();
-                resume.Reset();
-            }
-        }
-        finally
-        {
-            if (baseThread != null)
-            {
-                baseThread.GlobalState.ThreadStack.Pop();
-                baseThread.UnsafeSetStatus(LuaThreadStatus.Running);
-            }
-        }
-    }
-
-    public ValueTask<int> YieldAsync(LuaStack stack, CancellationToken cancellationToken = default)
-    {
-        return YieldAsyncCore(stack, stack.Count, 0, null, cancellationToken);
-    }
-
-    public override ValueTask<int> YieldAsync(LuaFunctionExecutionContext context, CancellationToken cancellationToken = default)
-    {
-        return YieldAsyncCore(context.State.Stack, context.ArgumentCount, context.ReturnFrameBase, context.State, cancellationToken);
-    }
-
-    [AsyncMethodBuilder(typeof(LightAsyncValueTaskMethodBuilder<>))]
-    async ValueTask<int> YieldAsyncCore(LuaStack stack, int argCount, int returnBase, LuaState? baseThread, CancellationToken cancellationToken = default)
-    {
-        if (Volatile.Read(ref status) != (byte)LuaThreadStatus.Running)
-        {
-            throw new LuaRuntimeException(baseThread, "cannot yield from a non-running coroutine");
-        }
-
-        if (baseThread != null)
-        {
-            if (baseThread.GetCallStackFrames()[^2].Function is not LuaClosure)
-            {
-                throw new LuaRuntimeException(baseThread, "attempt to yield across a C#-call boundary");
-            }
-        }
-
-        resume.SetResult(new(stack, argCount));
-
-
-        CancellationTokenRegistration registration = default;
-        if (cancellationToken.CanBeCanceled)
-        {
-            registration = cancellationToken.UnsafeRegister(static x =>
-            {
-                var coroutine = (LuaCoroutine)x!;
-                coroutine.yield.SetException(new OperationCanceledException());
-            }, this);
-        }
-
-    RETRY:
-        try
-        {
-            var result = await new ValueTask<YieldContext>(this, yield.Version);
-            stack.PopUntil(returnBase);
-            stack.PushRange(result.Results);
-            return result.Results.Length;
-        }
-        catch (Exception ex) when (ex is not OperationCanceledException)
-        {
-            yield.Reset();
-            goto RETRY;
-        }
-        finally
-        {
-            registration.Dispose();
-            yield.Reset();
-        }
-    }
-
-    YieldContext IValueTaskSource<YieldContext>.GetResult(short token)
-    {
-        return yield.GetResult(token);
-    }
-
-    ValueTaskSourceStatus IValueTaskSource<YieldContext>.GetStatus(short token)
-    {
-        return yield.GetStatus(token);
-    }
-
-    void IValueTaskSource<YieldContext>.OnCompleted(Action<object?> continuation, object? state, short token, ValueTaskSourceOnCompletedFlags flags)
-    {
-        yield.OnCompleted(continuation, state, token, flags);
-    }
-
-    ResumeContext IValueTaskSource<ResumeContext>.GetResult(short token)
-    {
-        return resume.GetResult(token);
-    }
-
-    ValueTaskSourceStatus IValueTaskSource<ResumeContext>.GetStatus(short token)
-    {
-        return resume.GetStatus(token);
-    }
-
-    void IValueTaskSource<ResumeContext>.OnCompleted(Action<object?> continuation, object? state, short token, ValueTaskSourceOnCompletedFlags flags)
-    {
-        resume.OnCompleted(continuation, state, token, flags);
-    }
-
-    void ReleaseCore()
-    {
-        // ReSharper disable once ConditionIsAlwaysTrueOrFalseAccordingToNullableAPIContract
-        CoreData?.Release();
-        CoreData = null!;
-    }
-}
+// using System.Threading.Tasks.Sources;
+// using Lua.Internal;
+// using Lua.Internal.CompilerServices;
+// using Lua.Runtime;
+// using System.Runtime.CompilerServices;
+//
+// namespace Lua;
+//
+// public sealed class LuaCoroutine : LuaState, IValueTaskSource<LuaCoroutine.YieldContext>, IValueTaskSource<LuaCoroutine.ResumeContext>, IPoolNode<LuaCoroutine>
+// {
+//     static LinkedPool<LuaCoroutine> pool;
+//     LuaCoroutine? nextNode;
+//
+//     ref LuaCoroutine? IPoolNode<LuaCoroutine>.NextNode => ref nextNode;
+//
+//     public static LuaCoroutine Create(LuaState parent, LuaFunction function, bool isProtectedMode)
+//     {
+//         if (!pool.TryPop(out var result))
+//         {
+//             result = new();
+//         }
+//
+//         result.Init(parent, function, isProtectedMode);
+//         return result;
+//     }
+//
+//     public void Release()
+//     {
+//         if (CoreData != null && CoreData.CallStack.Count != 0)
+//         {
+//             throw new InvalidOperationException("This state is running! Call stack is not empty!!");
+//         }
+//
+//         ReleaseCore();
+//         pool.TryPush(this);
+//     }
+//
+//     readonly struct YieldContext(LuaStack stack, int argCount)
+//     {
+//         public ReadOnlySpan<LuaValue> Results => stack.AsSpan()[^argCount..];
+//     }
+//
+//     readonly struct ResumeContext(LuaStack? stack, int argCount)
+//     {
+//         public ReadOnlySpan<LuaValue> Results => stack!.AsSpan()[^argCount..];
+//
+//         public bool IsDead => stack == null;
+//     }
+//
+//     byte status;
+//     bool isFirstCall = true;
+//     ValueTask<int> functionTask;
+//
+//     ManualResetValueTaskSourceCore<ResumeContext> resume;
+//     ManualResetValueTaskSourceCore<YieldContext> yield;
+//     Traceback? traceback;
+//
+//     internal void Init(LuaState parent, LuaFunction function, bool isProtectedMode)
+//     {
+//         CoreData = ThreadCoreData.Create();
+//         GlobalState = parent.GlobalState;
+//         IsProtectedMode = isProtectedMode;
+//         Function = function;
+//     }
+//
+//     public override LuaThreadStatus GetStatus()
+//     {
+//         return (LuaThreadStatus)status;
+//     }
+//
+//     public override void UnsafeSetStatus(LuaThreadStatus status)
+//     {
+//         this.status = (byte)status;
+//     }
+//
+//     public bool IsProtectedMode { get; private set; }
+//     public LuaFunction Function { get; private set; } = null!;
+//
+//     internal Traceback? LuaTraceback => traceback;
+//
+//     public bool CanResume => status == (byte)LuaThreadStatus.Suspended;
+//
+//     public ValueTask<int> ResumeAsync(LuaStack stack, CancellationToken cancellationToken = default)
+//     {
+//         return ResumeAsyncCore(stack, stack.Count, 0, null, cancellationToken);
+//     }
+//
+//     public override ValueTask<int> ResumeAsync(LuaFunctionExecutionContext context, CancellationToken cancellationToken = default)
+//     {
+//         return ResumeAsyncCore(context.State.Stack, context.ArgumentCount, context.ReturnFrameBase, context.State, cancellationToken);
+//     }
+//
+//
+//     [AsyncMethodBuilder(typeof(LightAsyncValueTaskMethodBuilder<>))]
+//     async ValueTask<int> ResumeAsyncCore(LuaStack stack, int argCount, int returnBase, LuaState? baseThread, CancellationToken cancellationToken = default)
+//     {
+//         if (baseThread != null)
+//         {
+//             baseThread.UnsafeSetStatus(LuaThreadStatus.Normal);
+//
+//             baseThread.GlobalState.ThreadStack.Push(this);
+//         }
+//
+//         try
+//         {
+//             switch ((LuaThreadStatus)Volatile.Read(ref status))
+//             {
+//                 case LuaThreadStatus.Suspended:
+//                     Volatile.Write(ref status, (byte)LuaThreadStatus.Running);
+//
+//                     if (!isFirstCall)
+//                     {
+//                         yield.SetResult(new(stack, argCount));
+//                     }
+//
+//                     break;
+//                 case LuaThreadStatus.Normal:
+//                 case LuaThreadStatus.Running:
+//                     if (IsProtectedMode)
+//                     {
+//                         stack.PopUntil(returnBase);
+//                         stack.Push(false);
+//                         stack.Push("cannot resume non-suspended coroutine");
+//                         return 2;
+//                     }
+//                     else
+//                     {
+//                         throw new LuaRuntimeException(baseThread, "cannot resume non-suspended coroutine");
+//                     }
+//                 case LuaThreadStatus.Dead:
+//                     if (IsProtectedMode)
+//                     {
+//                         stack.PopUntil(returnBase);
+//                         stack.Push(false);
+//                         stack.Push("cannot resume dead coroutine");
+//                         return 2;
+//                     }
+//                     else
+//                     {
+//                         throw new LuaRuntimeException(baseThread, "cannot resume dead coroutine");
+//                     }
+//             }
+//
+//             ValueTask<ResumeContext> resumeTask = new(this, resume.Version);
+//
+//             CancellationTokenRegistration registration = default;
+//             if (cancellationToken.CanBeCanceled)
+//             {
+//                 registration = cancellationToken.UnsafeRegister(static x =>
+//                 {
+//                     var coroutine = (LuaCoroutine)x!;
+//                     coroutine.yield.SetException(new OperationCanceledException());
+//                 }, this);
+//             }
+//
+//             try
+//             {
+//                 if (isFirstCall)
+//                 {
+//                     Stack.PushRange(stack.AsSpan()[^argCount..]);
+//                     //functionTask = Function.InvokeAsync(new() { Access = this.CurrentAccess, ArgumentCount = Stack.Count, ReturnFrameBase = 0 }, cancellationToken);
+//                     functionTask = CurrentAccess.RunAsync(Function, Stack.Count, cancellationToken);
+//                     Volatile.Write(ref isFirstCall, false);
+//                     if (!functionTask.IsCompleted)
+//                     {
+//                         functionTask.GetAwaiter().OnCompleted(() => resume.SetResult(default));
+//                     }
+//                 }
+//
+//                 ResumeContext result0;
+//                 if (functionTask.IsCompleted || (result0 = await resumeTask).IsDead)
+//                 {
+//                     _ = functionTask.Result;
+//                     Volatile.Write(ref status, (byte)LuaThreadStatus.Dead);
+//                     stack.PopUntil(returnBase);
+//                     stack.Push(true);
+//                     stack.PushRange(Stack.AsSpan());
+//                     ReleaseCore();
+//                     return stack.Count - returnBase;
+//                 }
+//                 else
+//                 {
+//                     Volatile.Write(ref status, (byte)LuaThreadStatus.Suspended);
+//                     var results = result0.Results;
+//                     stack.PopUntil(returnBase);
+//                     stack.Push(true);
+//                     stack.PushRange(results);
+//                     return results.Length + 1;
+//                 }
+//             }
+//             catch (Exception ex) when (ex is not OperationCanceledException)
+//             {
+//                 if (IsProtectedMode)
+//                 {
+//                     if (ex is ILuaTracebackBuildable tracebackBuildable)
+//                     {
+//                         traceback = tracebackBuildable.BuildOrGet();
+//                     }
+//
+//                     Volatile.Write(ref status, (byte)LuaThreadStatus.Dead);
+//                     ReleaseCore();
+//                     stack.PopUntil(returnBase);
+//                     stack.Push(false);
+//                     stack.Push(ex is LuaRuntimeException luaEx ? luaEx.ErrorObject : ex.Message);
+//                     return 2;
+//                 }
+//                 else
+//                 {
+//                     throw;
+//                 }
+//             }
+//             finally
+//             {
+//                 registration.Dispose();
+//                 resume.Reset();
+//             }
+//         }
+//         finally
+//         {
+//             if (baseThread != null)
+//             {
+//                 baseThread.GlobalState.ThreadStack.Pop();
+//                 baseThread.UnsafeSetStatus(LuaThreadStatus.Running);
+//             }
+//         }
+//     }
+//
+//     public ValueTask<int> YieldAsync(LuaStack stack, CancellationToken cancellationToken = default)
+//     {
+//         return YieldAsyncCore(stack, stack.Count, 0, null, cancellationToken);
+//     }
+//
+//     public override ValueTask<int> YieldAsync(LuaFunctionExecutionContext context, CancellationToken cancellationToken = default)
+//     {
+//         return YieldAsyncCore(context.State.Stack, context.ArgumentCount, context.ReturnFrameBase, context.State, cancellationToken);
+//     }
+//
+//     [AsyncMethodBuilder(typeof(LightAsyncValueTaskMethodBuilder<>))]
+//     async ValueTask<int> YieldAsyncCore(LuaStack stack, int argCount, int returnBase, LuaState? baseThread, CancellationToken cancellationToken = default)
+//     {
+//         if (Volatile.Read(ref status) != (byte)LuaThreadStatus.Running)
+//         {
+//             throw new LuaRuntimeException(baseThread, "cannot yield from a non-running coroutine");
+//         }
+//
+//         if (baseThread != null)
+//         {
+//             if (baseThread.GetCallStackFrames()[^2].Function is not LuaClosure)
+//             {
+//                 throw new LuaRuntimeException(baseThread, "attempt to yield across a C#-call boundary");
+//             }
+//         }
+//
+//         resume.SetResult(new(stack, argCount));
+//
+//
+//         CancellationTokenRegistration registration = default;
+//         if (cancellationToken.CanBeCanceled)
+//         {
+//             registration = cancellationToken.UnsafeRegister(static x =>
+//             {
+//                 var coroutine = (LuaCoroutine)x!;
+//                 coroutine.yield.SetException(new OperationCanceledException());
+//             }, this);
+//         }
+//
+//     RETRY:
+//         try
+//         {
+//             var result = await new ValueTask<YieldContext>(this, yield.Version);
+//             stack.PopUntil(returnBase);
+//             stack.PushRange(result.Results);
+//             return result.Results.Length;
+//         }
+//         catch (Exception ex) when (ex is not OperationCanceledException)
+//         {
+//             yield.Reset();
+//             goto RETRY;
+//         }
+//         finally
+//         {
+//             registration.Dispose();
+//             yield.Reset();
+//         }
+//     }
+//
+//     YieldContext IValueTaskSource<YieldContext>.GetResult(short token)
+//     {
+//         return yield.GetResult(token);
+//     }
+//
+//     ValueTaskSourceStatus IValueTaskSource<YieldContext>.GetStatus(short token)
+//     {
+//         return yield.GetStatus(token);
+//     }
+//
+//     void IValueTaskSource<YieldContext>.OnCompleted(Action<object?> continuation, object? state, short token, ValueTaskSourceOnCompletedFlags flags)
+//     {
+//         yield.OnCompleted(continuation, state, token, flags);
+//     }
+//
+//     ResumeContext IValueTaskSource<ResumeContext>.GetResult(short token)
+//     {
+//         return resume.GetResult(token);
+//     }
+//
+//     ValueTaskSourceStatus IValueTaskSource<ResumeContext>.GetStatus(short token)
+//     {
+//         return resume.GetStatus(token);
+//     }
+//
+//     void IValueTaskSource<ResumeContext>.OnCompleted(Action<object?> continuation, object? state, short token, ValueTaskSourceOnCompletedFlags flags)
+//     {
+//         resume.OnCompleted(continuation, state, token, flags);
+//     }
+//
+//     void ReleaseCore()
+//     {
+//         // ReSharper disable once ConditionIsAlwaysTrueOrFalseAccordingToNullableAPIContract
+//         CoreData?.Release();
+//         CoreData = null!;
+//     }
+// }

+ 2 - 4
src/Lua/LuaFunctionExecutionContext.cs

@@ -8,10 +8,8 @@ namespace Lua;
 public readonly record struct LuaFunctionExecutionContext
 {
     public LuaGlobalState GlobalState => State.GlobalState;
-
-    public required LuaThreadAccess Access { get; init; }
-
-    public LuaState State => Access.State;
+    
+    public LuaState State { get; init; }
 
     public required int ArgumentCount { get; init; }
 

+ 0 - 43
src/Lua/LuaFunctionExtensions.cs

@@ -1,43 +0,0 @@
-// using Lua.Runtime;
-//
-// namespace Lua;
-//
-// public static class LuaFunctionExtensions
-// {
-//     
-//     public static async ValueTask<int> InvokeAsync(this LuaFunction function, LuaThread thread, int argumentCount, CancellationToken cancellationToken = default)
-//     {
-//         var returnFrameBase = thread.Stack.Count-argumentCount;
-//         var varArgumentCount = function.GetVariableArgumentCount(argumentCount);
-//         if (varArgumentCount != 0)
-//         {
-//             if (varArgumentCount < 0)
-//             {
-//                 thread.Stack.SetTop(thread.Stack.Count - varArgumentCount);
-//                 argumentCount -= varArgumentCount;
-//                 varArgumentCount = 0;
-//             }
-//             else
-//             {
-//                 LuaVirtualMachine.PrepareVariableArgument(thread.Stack, argumentCount, varArgumentCount);
-//             }
-//         }
-//
-//         LuaFunctionExecutionContext context = new() { Thread = thread, ArgumentCount = argumentCount , ReturnFrameBase = returnFrameBase, };
-//         var frame = new CallStackFrame { Base = context.FrameBase, VariableArgumentCount = varArgumentCount, Function = function, ReturnBase = context.ReturnFrameBase };
-//         context.Thread.PushCallStackFrame(frame);
-//         try
-//         {
-//             if (context.Thread.CallOrReturnHookMask.Value != 0 && !context.Thread.IsInHook)
-//             {
-//                 return await LuaVirtualMachine.ExecuteCallHook(context, cancellationToken);
-//             }
-//
-//             return await function.Func(context, cancellationToken);
-//         }
-//         finally
-//         {
-//             context.Thread.PopCallStackFrame();
-//         }
-//     }
-// }

+ 5 - 87
src/Lua/LuaGlobalState.cs

@@ -16,22 +16,16 @@ public sealed class LuaGlobalState
 {
     // states
     readonly LuaState mainState;
-    FastListCore<UpValue> openUpValues;
-    FastStackCore<LuaState> threadStack;
+    FastStackCore<LuaState> stateStack;
     readonly LuaTable environment;
     readonly LuaTable registry = new();
     readonly UpValue envUpValue;
 
-
     FastStackCore<LuaDebug.LuaDebugBuffer> debugBufferPool;
 
-    internal int CallCount;
-
     internal UpValue EnvUpValue => envUpValue;
 
-    internal ref FastStackCore<LuaState> ThreadStack => ref threadStack;
-
-    internal ref FastListCore<UpValue> OpenUpValues => ref openUpValues;
+    internal ref FastStackCore<LuaState> ThreadStack => ref stateStack;
 
     internal ref FastStackCore<LuaDebug.LuaDebugBuffer> DebugBufferPool => ref debugBufferPool;
 
@@ -45,8 +39,6 @@ public sealed class LuaGlobalState
 
     public LuaState MainThread => mainState;
 
-    public LuaThreadAccess RootAccess => new(mainState, 0);
-
     public LuaPlatform Platform { get; }
 
     public ILuaModuleLoader? ModuleLoader { get; set; }
@@ -55,7 +47,6 @@ public sealed class LuaGlobalState
 
     public ILuaOsEnvironment OsEnvironment => Platform.OsEnvironment ?? throw new InvalidOperationException("OperatingSystem is not set. Please set it before access.");
 
-
     public TimeProvider TimeProvider => Platform.TimeProvider ?? throw new InvalidOperationException("TimeProvider is not set. Please set it before access.");
 
     public ILuaStandardIO StandardIO => Platform.StandardIO;
@@ -66,7 +57,7 @@ public sealed class LuaGlobalState
     LuaTable? stringMetatable;
     LuaTable? booleanMetatable;
     LuaTable? functionMetatable;
-    LuaTable? threadMetatable;
+    LuaTable? stateMetatable;
 
     public static LuaGlobalState Create(LuaPlatform? platform = null)
     {
@@ -95,7 +86,7 @@ public sealed class LuaGlobalState
             LuaValueType.String => stringMetatable,
             LuaValueType.Number => numberMetatable,
             LuaValueType.Function => functionMetatable,
-            LuaValueType.Thread => threadMetatable,
+            LuaValueType.Thread => stateMetatable,
             LuaValueType.UserData => value.UnsafeRead<ILuaUserData>().Metatable,
             LuaValueType.Table => value.UnsafeRead<LuaTable>().Metatable,
             _ => null
@@ -125,7 +116,7 @@ public sealed class LuaGlobalState
                 functionMetatable = metatable;
                 break;
             case LuaValueType.Thread:
-                threadMetatable = metatable;
+                stateMetatable = metatable;
                 break;
             case LuaValueType.UserData:
                 value.UnsafeRead<ILuaUserData>().Metatable = metatable;
@@ -135,77 +126,4 @@ public sealed class LuaGlobalState
                 break;
         }
     }
-
-    internal UpValue GetOrAddUpValue(LuaState thread, int registerIndex)
-    {
-        foreach (var upValue in openUpValues.AsSpan())
-        {
-            if (upValue.RegisterIndex == registerIndex && upValue.Thread == thread)
-            {
-                return upValue;
-            }
-        }
-
-        var newUpValue = UpValue.Open(thread, registerIndex);
-        openUpValues.Add(newUpValue);
-        return newUpValue;
-    }
-
-    internal void CloseUpValues(LuaState thread, int frameBase)
-    {
-        for (var i = 0; i < openUpValues.Length; i++)
-        {
-            var upValue = openUpValues[i];
-            if (upValue.Thread != thread)
-            {
-                continue;
-            }
-
-            if (upValue.RegisterIndex >= frameBase)
-            {
-                upValue.Close();
-                openUpValues.RemoveAtSwapBack(i);
-                i--;
-            }
-        }
-    }
-
-    public unsafe LuaClosure Load(ReadOnlySpan<char> chunk, string chunkName, LuaTable? environment = null)
-    {
-        Prototype prototype;
-        fixed (char* ptr = chunk)
-        {
-            prototype = Parser.Parse(this, new(ptr, chunk.Length), chunkName);
-        }
-
-        return new(MainThread, prototype, environment);
-    }
-
-    public LuaClosure Load(ReadOnlySpan<byte> chunk, string? chunkName = null, string mode = "bt", LuaTable? environment = null)
-    {
-        if (chunk.Length > 4)
-        {
-            if (chunk[0] == '\e')
-            {
-                return new(MainThread, Parser.UnDump(chunk, chunkName), environment);
-            }
-        }
-
-        chunk = BomUtility.GetEncodingFromBytes(chunk, out var encoding);
-
-        var charCount = encoding.GetCharCount(chunk);
-        var pooled = ArrayPool<char>.Shared.Rent(charCount);
-        try
-        {
-            var chars = pooled.AsSpan(0, charCount);
-            encoding.GetChars(chunk, chars);
-            chunkName ??= chars.ToString();
-
-            return Load(chars, chunkName, environment);
-        }
-        finally
-        {
-            ArrayPool<char>.Shared.Return(pooled);
-        }
-    }
 }

+ 268 - 32
src/Lua/LuaState.cs

@@ -1,43 +1,117 @@
+using Lua.CodeAnalysis.Compilation;
 using System.Runtime.CompilerServices;
 using Lua.Internal;
+using Lua.Platforms;
 using Lua.Runtime;
+using System.Buffers;
 
 namespace Lua;
 
-public class LuaState:IDisposable
+public class LuaState : IDisposable
 {
-    protected LuaState() { }
-
     internal LuaState(LuaGlobalState globalState)
     {
         GlobalState = globalState;
         CoreData = ThreadCoreData.Create();
     }
 
-    public virtual LuaThreadStatus GetStatus()
+    internal LuaState(LuaGlobalState globalState, LuaFunction function, bool isProtectedMode)
+    {
+        GlobalState = globalState;
+        CoreData = ThreadCoreData.Create();
+        coroutine = new(this, function, isProtectedMode);
+    }
+
+    public static LuaState Create(LuaGlobalState? globalState = null)
+    {
+        if (globalState is not null)
+        {
+            return new(globalState);
+        }
+
+        globalState = LuaGlobalState.Create();
+        return globalState.MainThread;
+    }
+    
+    public static LuaState Create(LuaPlatform platform)
+    {
+        return LuaGlobalState.Create(platform).MainThread;
+    }
+
+    public static LuaState CreateCoroutine(LuaGlobalState globalState, 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 virtual void UnsafeSetStatus(LuaThreadStatus status) { }
+    public void UnsafeSetStatus(LuaThreadStatus status)
+    {
+        if (coroutine is null)
+        {
+            return;
+        }
+
+        coroutine.status = (byte)status;
+    }
 
-    public virtual ValueTask<int> ResumeAsync(LuaFunctionExecutionContext context, CancellationToken cancellationToken = default)
+    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 virtual ValueTask<int> YieldAsync(LuaFunctionExecutionContext context, CancellationToken cancellationToken = default)
+    public ValueTask<int> ResumeAsync(LuaStack stack, CancellationToken cancellationToken = default)
     {
-        throw new LuaRuntimeException(context.State, "attempt to yield from outside a coroutine");
+        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);
     }
 
-    protected class ThreadCoreData : IPoolNode<ThreadCoreData>
+    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;
 
-        public void Clear()
+        void Clear()
         {
             Stack.Clear();
             CallStack.Clear();
@@ -65,8 +139,12 @@ public class LuaState:IDisposable
         }
     }
 
-    public LuaGlobalState GlobalState { get; protected set; } = null!;
-    protected ThreadCoreData? CoreData = new();
+
+    FastListCore<UpValue> openUpValues;
+    internal int CallCount;
+    public LuaGlobalState GlobalState { get; }
+    ThreadCoreData? CoreData;
+    CoroutineCore? coroutine;
     internal bool IsLineHookEnabled;
     internal BitFlags2 CallOrReturnHookMask;
     internal bool IsInHook;
@@ -74,19 +152,27 @@ public class LuaState:IDisposable
     internal int BaseHookCount;
     internal int LastPc;
 
-    internal int LastVersion;
-    internal int CurrentVersion;
-
     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; }
 
+    public LuaFunction? CoroutineFunction => coroutine?.Function;
+
+    public bool CanResume => GetStatus() == LuaThreadStatus.Suspended;
+
     public LuaStack Stack => CoreData!.Stack;
 
+    internal Traceback? LuaTraceback => coroutine?.Traceback;
+
+    public LuaTable Environment => GlobalState.Environment;
+
+    public LuaPlatform Platform => GlobalState.Platform;
+
     internal bool IsCallHookEnabled
     {
         get => CallOrReturnHookMask.Flag0;
@@ -101,10 +187,6 @@ public class LuaState:IDisposable
 
     public int CallStackFrameCount => CoreData == null ? 0 : CoreData!.CallStack.Count;
 
-    internal LuaThreadAccess CurrentAccess => new(this, CurrentVersion);
-
-    public LuaThreadAccess RootAccess => new(this, 0);
-
     public ref readonly CallStackFrame GetCurrentFrame()
     {
         return ref CoreData!.CallStack.PeekRef();
@@ -120,21 +202,49 @@ public class LuaState:IDisposable
         return CoreData == null ? default : CoreData!.CallStack.AsSpan();
     }
 
-    void UpdateCurrentVersion(ref FastStackCore<CallStackFrame> callStack)
+
+    internal CallStackFrame CreateCallStackFrame(LuaFunction function, int argumentCount, int returnBase, int callerInstructionIndex)
     {
-        CurrentVersion = callStack.Count == 0 ? 0 : callStack.PeekRef().Version;
-    }
+        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
+        };
+
+        if (state.IsInHook)
+        {
+            frame.Flags |= CallStackFrameFlags.InHook;
+        }
 
+        return frame;
+    }
 
     [MethodImpl(MethodImplOptions.AggressiveInlining)]
-    internal LuaThreadAccess PushCallStackFrame(in CallStackFrame frame)
+    internal void PushCallStackFrame(in CallStackFrame frame)
     {
         CurrentException?.BuildOrGet();
         CurrentException = null;
         ref var callStack = ref CoreData!.CallStack;
         callStack.Push(frame);
-        callStack.PeekRef().Version = CurrentVersion = ++LastVersion;
-        return new(this, CurrentVersion);
     }
 
     [MethodImpl(MethodImplOptions.AggressiveInlining)]
@@ -143,7 +253,6 @@ public class LuaState:IDisposable
         var coreData = CoreData!;
         ref var callStack = ref coreData.CallStack;
         var popFrame = callStack.Pop();
-        UpdateCurrentVersion(ref callStack);
         if (CurrentException != null)
         {
             ExceptionTrace.Push(popFrame);
@@ -158,7 +267,6 @@ public class LuaState:IDisposable
         var coreData = CoreData!;
         ref var callStack = ref coreData.CallStack;
         var popFrame = callStack.Pop();
-        UpdateCurrentVersion(ref callStack);
         if (CurrentException != null)
         {
             ExceptionTrace.Push(popFrame);
@@ -175,7 +283,6 @@ public class LuaState:IDisposable
         var coreData = CoreData!;
         ref var callStack = ref coreData.CallStack;
         var popFrame = callStack.Pop();
-        UpdateCurrentVersion(ref callStack);
         if (CurrentException != null)
         {
             ExceptionTrace.Push(popFrame);
@@ -193,7 +300,6 @@ public class LuaState:IDisposable
         }
 
         callStack.PopUntil(top);
-        UpdateCurrentVersion(ref callStack);
     }
 
     public void SetHook(LuaFunction? hook, string mask, int count = 0)
@@ -237,12 +343,142 @@ public class LuaState:IDisposable
     {
         return new(GlobalState, 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
+            {
+                LuaVirtualMachine.PrepareVariableArgument(state.Stack, argumentCount, varArgumentCount);
+            }
+
+            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)
+            {
+                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;
+        fixed (char* ptr = chunk)
+        {
+            prototype = Parser.Parse(this, new(ptr, chunk.Length), chunkName);
+        }
+
+        return new(this, prototype, environment);
+    }
+
+    public LuaClosure Load(ReadOnlySpan<byte> chunk, string? chunkName = null, string mode = "bt", LuaTable? environment = null)
+    {
+        if (chunk.Length > 4)
+        {
+            if (chunk[0] == '\e')
+            {
+                return new(this, Parser.UnDump(chunk, chunkName), environment);
+            }
+        }
+
+        chunk = BomUtility.GetEncodingFromBytes(chunk, out var encoding);
+
+        var charCount = encoding.GetCharCount(chunk);
+        var pooled = ArrayPool<char>.Shared.Rent(charCount);
+        try
+        {
+            var chars = pooled.AsSpan(0, charCount);
+            encoding.GetChars(chunk, chars);
+            chunkName ??= chars.ToString();
+
+            return Load(chars, chunkName, environment);
+        }
+        finally
+        {
+            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 thread is running! Call stack is not empty!!");
+            throw new InvalidOperationException("This state is running! Call stack is not empty!!");
         }
 
         CoreData.Release();

+ 271 - 18
src/Lua/LuaStateExtensions.cs

@@ -1,47 +1,300 @@
 using Lua.IO;
 using Lua.Runtime;
+using System.Runtime.CompilerServices;
+
+// ReSharper disable MethodHasAsyncOverloadWithCancellation
 
 namespace Lua;
 
 public static class LuaStateExtensions
 {
-    public static ValueTask<int> DoStringAsync(this LuaGlobalState globalState, string source, Memory<LuaValue> buffer, string? chunkName = null, CancellationToken cancellationToken = default)
+    public static async ValueTask<LuaClosure> LoadFileAsync(this LuaState state, string fileName, string mode, LuaTable? environment, CancellationToken cancellationToken)
     {
-        return globalState.RootAccess.DoStringAsync(source, buffer, chunkName, cancellationToken);
+        var name = "@" + fileName;
+        using var stream = await state.GlobalState.FileSystem.Open(fileName, LuaFileOpenMode.Read, cancellationToken);
+        var source = await stream.ReadAllAsync(cancellationToken);
+        var closure = state.Load(source, name, environment);
+
+        return closure;
     }
 
-    public static ValueTask<LuaValue[]> DoStringAsync(this LuaGlobalState globalState, string source, string? chunkName = null, CancellationToken cancellationToken = default)
+    public static ValueTask<int> DoStringAsync(this LuaState state, string source, Memory<LuaValue> results, string? chunkName = null, CancellationToken cancellationToken = default)
     {
-        return globalState.RootAccess.DoStringAsync(source, chunkName, cancellationToken);
+        var closure = state.Load(source, chunkName ?? source);
+        return ExecuteAsync(state, closure, results, cancellationToken);
     }
 
-    public static ValueTask<int> ExecuteAsync(this LuaGlobalState globalState, ReadOnlySpan<byte> source, Memory<LuaValue> buffer, string chunkName, CancellationToken cancellationToken = default)
+    public static ValueTask<LuaValue[]> DoStringAsync(this LuaState state, string source, string? chunkName = null, CancellationToken cancellationToken = default)
     {
-        return globalState.RootAccess.ExecuteAsync(source, buffer, chunkName, cancellationToken);
+        var closure = state.Load(source, chunkName ?? source);
+        return ExecuteAsync(state, closure, cancellationToken);
     }
 
-    public static ValueTask<LuaValue[]> ExecuteAsync(this LuaGlobalState globalState, ReadOnlySpan<byte> source, string chunkName, CancellationToken cancellationToken = default)
+    public static ValueTask<int> ExecuteAsync(this LuaState state, ReadOnlySpan<byte> source, Memory<LuaValue> results, string chunkName, CancellationToken cancellationToken = default)
     {
-        return globalState.RootAccess.ExecuteAsync(source, chunkName, cancellationToken);
+        var closure = state.Load(source, chunkName);
+        return ExecuteAsync(state, closure, results, cancellationToken);
     }
 
-    public static ValueTask<int> DoFileAsync(this LuaGlobalState globalState, string path, Memory<LuaValue> buffer, CancellationToken cancellationToken = default)
+    public static ValueTask<LuaValue[]> ExecuteAsync(this LuaState state, ReadOnlySpan<byte> source, string chunkName, CancellationToken cancellationToken = default)
     {
-        return globalState.RootAccess.DoFileAsync(path, buffer, cancellationToken);
+        var closure = state.Load(source, chunkName);
+        return ExecuteAsync(state, closure, cancellationToken);
     }
 
-    public static ValueTask<LuaValue[]> DoFileAsync(this LuaGlobalState globalState, string path, CancellationToken cancellationToken = default)
+    public static async ValueTask<int> DoFileAsync(this LuaState state, string path, Memory<LuaValue> buffer, CancellationToken cancellationToken = default)
     {
-        return globalState.RootAccess.DoFileAsync(path, cancellationToken);
+        var closure = await state.LoadFileAsync(path, "bt", null, cancellationToken);
+        var count = await state.RunAsync(closure, 0, cancellationToken);
+        using var results = state.ReadTopValues(count);
+        results.AsSpan()[..Math.Min(buffer.Length, results.Length)].CopyTo(buffer.Span);
+        return results.Count;
     }
 
-    public static async ValueTask<LuaClosure> LoadFileAsync(this LuaGlobalState globalState, string fileName, string mode, LuaTable? environment, CancellationToken cancellationToken)
+    public static async ValueTask<LuaValue[]> DoFileAsync(this LuaState state, string path, CancellationToken cancellationToken = default)
     {
-        var name = "@" + fileName;
-        using var stream = await globalState.FileSystem.Open(fileName, LuaFileOpenMode.Read, cancellationToken);
-        var source = await stream.ReadAllAsync(cancellationToken);
-        var closure = globalState.Load(source, name, environment);
+        var closure = await state.LoadFileAsync(path, "bt", null, cancellationToken);
+        var count = await state.RunAsync(closure, 0, cancellationToken);
+        using var results = state.ReadTopValues(count);
+        return results.AsSpan().ToArray();
+    }
 
-        return closure;
+    public static async ValueTask<int> ExecuteAsync(this LuaState state, LuaClosure closure, Memory<LuaValue> buffer, CancellationToken cancellationToken = default)
+    {
+        var count = await state.RunAsync(closure, 0, cancellationToken);
+        using var results = state.ReadTopValues(count);
+        results.AsSpan()[..Math.Min(buffer.Length, results.Length)].CopyTo(buffer.Span);
+        return results.Count;
+    }
+
+    public static async ValueTask<LuaValue[]> ExecuteAsync(this LuaState state, LuaClosure closure, CancellationToken cancellationToken = default)
+    {
+        var count = await state.RunAsync(closure, 0, cancellationToken);
+        using var results = state.ReadTopValues(count);
+        return results.AsSpan().ToArray();
+    }
+
+    public static void Push(this LuaState state, LuaValue value)
+    {
+        state.Stack.Push(value);
+    }
+
+    public static void Push(this LuaState state, params ReadOnlySpan<LuaValue> span)
+    {
+        state.Stack.PushRange(span);
+    }
+
+    public static void Pop(this LuaState state, int count)
+    {
+        state.Stack.Pop(count);
+    }
+
+    public static LuaValue Pop(this LuaState state)
+    {
+        return state.Stack.Pop();
+    }
+
+    public static LuaTopValuesReader ReadTopValues(this LuaState state, int argumentCount)
+    {
+        var stack = state.Stack;
+        return new(stack, stack.Count - argumentCount);
+    }
+
+    public static ValueTask<LuaValue> Add(this LuaState state, LuaValue x, LuaValue y, CancellationToken cancellationToken = default)
+    {
+        if (x.TryReadDouble(out var numX) && y.TryReadDouble(out var numY))
+        {
+            return new(numX + numY);
+        }
+
+        return LuaVirtualMachine.ExecuteBinaryOperationMetaMethod(state, x, y, OpCode.Add, cancellationToken);
+    }
+
+    public static ValueTask<LuaValue> Sub(this LuaState state, LuaValue x, LuaValue y, CancellationToken cancellationToken = default)
+    {
+        if (x.TryReadDouble(out var numX) && y.TryReadDouble(out var numY))
+        {
+            return new(numX - numY);
+        }
+
+        return LuaVirtualMachine.ExecuteBinaryOperationMetaMethod(state, x, y, OpCode.Sub, cancellationToken);
+    }
+
+    public static ValueTask<LuaValue> Mul(this LuaState state, LuaValue x, LuaValue y, CancellationToken cancellationToken = default)
+    {
+        if (x.TryReadDouble(out var numX) && y.TryReadDouble(out var numY))
+        {
+            return new(numX * numY);
+        }
+
+        return LuaVirtualMachine.ExecuteBinaryOperationMetaMethod(state, x, y, OpCode.Mul, cancellationToken);
+    }
+
+    public static ValueTask<LuaValue> Div(this LuaState state, LuaValue x, LuaValue y, CancellationToken cancellationToken = default)
+    {
+        if (x.TryReadDouble(out var numX) && y.TryReadDouble(out var numY))
+        {
+            return new(numX / numY);
+        }
+
+        return LuaVirtualMachine.ExecuteBinaryOperationMetaMethod(state, x, y, OpCode.Div, cancellationToken);
+    }
+
+    public static ValueTask<LuaValue> Mod(this LuaState state, LuaValue x, LuaValue y, CancellationToken cancellationToken = default)
+    {
+        if (x.TryReadDouble(out var numX) && y.TryReadDouble(out var numY))
+        {
+            return new(LuaVirtualMachine.Mod(numX, numY));
+        }
+
+        return LuaVirtualMachine.ExecuteBinaryOperationMetaMethod(state, x, y, OpCode.Mod, cancellationToken);
+    }
+
+    public static ValueTask<LuaValue> Pow(this LuaState state, LuaValue x, LuaValue y, CancellationToken cancellationToken = default)
+    {
+        if (x.TryReadDouble(out var numX) && y.TryReadDouble(out var numY))
+        {
+            return new(Math.Pow(numX, numY));
+        }
+
+        return LuaVirtualMachine.ExecuteBinaryOperationMetaMethod(state, x, y, OpCode.Pow, cancellationToken);
+    }
+
+
+    public static ValueTask<LuaValue> Unm(this LuaState state, LuaValue value, CancellationToken cancellationToken = default)
+    {
+        if (value.TryReadDouble(out var numB))
+        {
+            return new(-numB);
+        }
+
+        return LuaVirtualMachine.ExecuteUnaryOperationMetaMethod(state, value, OpCode.Unm, cancellationToken);
+    }
+
+    public static ValueTask<LuaValue> Len(this LuaState state, LuaValue value, CancellationToken cancellationToken = default)
+    {
+        if (value.TryReadString(out var str))
+        {
+            return new(str.Length);
+        }
+
+        if (value.TryReadTable(out var table))
+        {
+            return new(table.ArrayLength);
+        }
+
+        return LuaVirtualMachine.ExecuteUnaryOperationMetaMethod(state, value, OpCode.Len, cancellationToken);
+    }
+
+
+    public static ValueTask<bool> LessThan(this LuaState state, LuaValue x, LuaValue y, CancellationToken cancellationToken = default)
+    {
+        if (x.TryReadNumber(out var numX) && y.TryReadNumber(out var numY))
+        {
+            return new(numX < numY);
+        }
+
+        if (x.TryReadString(out var strX) && y.TryReadString(out var strY))
+        {
+            var c = StringComparer.Ordinal.Compare(strX, strY);
+            return new(c < 0);
+        }
+
+        return LuaVirtualMachine.ExecuteCompareOperationMetaMethod(state, x, y, OpCode.Lt, cancellationToken);
+    }
+
+    public static ValueTask<bool> LessThanOrEquals(this LuaState state, LuaValue x, LuaValue y, CancellationToken cancellationToken = default)
+    {
+        if (x.TryReadNumber(out var numX) && y.TryReadNumber(out var numY))
+        {
+            return new(numX <= numY);
+        }
+
+        if (x.TryReadString(out var strX) && y.TryReadString(out var strY))
+        {
+            var c = StringComparer.Ordinal.Compare(strX, strY);
+            return new(c <= 0);
+        }
+
+        return LuaVirtualMachine.ExecuteCompareOperationMetaMethod(state, x, y, OpCode.Le, cancellationToken);
+    }
+
+    public static ValueTask<bool> Equals(this LuaState state, LuaValue x, LuaValue y, CancellationToken cancellationToken = default)
+    {
+        if (x == y)
+        {
+            return new(true);
+        }
+
+        return LuaVirtualMachine.ExecuteCompareOperationMetaMethod(state, x, y, OpCode.Eq, cancellationToken);
+    }
+
+    public static async ValueTask<LuaValue> GetTable(this LuaState state, LuaValue table, LuaValue key, CancellationToken cancellationToken = default)
+    {
+        if (table.TryReadTable(out var luaTable))
+        {
+            if (luaTable.TryGetValue(key, out var value))
+            {
+                return value;
+            }
+        }
+
+        return await LuaVirtualMachine.ExecuteGetTableSlowPath(state, table, key, cancellationToken);
+    }
+
+    public static ValueTask SetTable(this LuaState state, LuaValue table, LuaValue key, LuaValue value, CancellationToken cancellationToken = default)
+    {
+        if (key.TryReadNumber(out var numB))
+        {
+            if (double.IsNaN(numB))
+            {
+                throw new LuaRuntimeException(state, "table index is NaN");
+            }
+        }
+
+
+        if (table.TryReadTable(out var luaTable))
+        {
+            ref var valueRef = ref luaTable.FindValue(key);
+            if (!Unsafe.IsNullRef(ref valueRef) && valueRef.Type != LuaValueType.Nil)
+            {
+                valueRef = value;
+                return default;
+            }
+        }
+
+        return LuaVirtualMachine.ExecuteSetTableSlowPath(state, table, key, value, cancellationToken);
+    }
+
+    public static ValueTask<LuaValue> Concat(this LuaState state, ReadOnlySpan<LuaValue> values, CancellationToken cancellationToken = default)
+    {
+        state.Stack.PushRange(values);
+        return Concat(state, values.Length, cancellationToken);
+    }
+
+    public static ValueTask<LuaValue> Concat(this LuaState state, int concatCount, CancellationToken cancellationToken = default)
+    {
+        return LuaVirtualMachine.Concat(state, concatCount, cancellationToken);
+    }
+
+    public static ValueTask<int> Call(this LuaState state, int funcIndex, int returnBase, CancellationToken cancellationToken = default)
+    {
+        return LuaVirtualMachine.Call(state, funcIndex, returnBase, cancellationToken);
+    }
+
+    public static ValueTask<LuaValue[]> Call(this LuaState state, LuaValue function, ReadOnlySpan<LuaValue> arguments, CancellationToken cancellationToken = default)
+    {
+        var funcIndex = state.Stack.Count;
+        state.Stack.Push(function);
+        state.Stack.PushRange(arguments);
+        return Impl(state, funcIndex, cancellationToken);
+
+        static async ValueTask<LuaValue[]> Impl(LuaState state, int funcIndex, CancellationToken cancellationToken)
+        {
+            await LuaVirtualMachine.Call(state, funcIndex, funcIndex, cancellationToken);
+            var count = state.Stack.Count - funcIndex;
+            using var results = state.ReadTopValues(count);
+            return results.AsSpan().ToArray();
+        }
     }
 }

+ 4 - 13
src/Lua/LuaThreadExtensions.cs

@@ -4,28 +4,19 @@ namespace Lua;
 
 public static class LuaThreadExtensions
 {
-    public static UserThreadLease RentUserThread(this LuaState thread)
-    {
-        return new(LuaUserThread.Create(thread));
-    }
-
-    public static CoroutineLease RentCoroutine(this LuaState thread, LuaFunction function, bool isProtectedMode = false)
-    {
-        return new(LuaCoroutine.Create(thread, function, isProtectedMode));
-    }
 
-    internal static void ThrowIfCancellationRequested(this LuaState thread, CancellationToken cancellationToken)
+    internal static void ThrowIfCancellationRequested(this LuaState state, CancellationToken cancellationToken)
     {
         if (cancellationToken.IsCancellationRequested)
         {
-            Throw(thread, cancellationToken);
+            Throw(state, cancellationToken);
         }
 
         return;
 
-        static void Throw(LuaState thread, CancellationToken cancellationToken)
+        static void Throw(LuaState state, CancellationToken cancellationToken)
         {
-            throw new LuaCanceledException(thread, cancellationToken);
+            throw new LuaCanceledException(state, cancellationToken);
         }
     }
 }

+ 0 - 36
src/Lua/LuaUserThread.cs

@@ -1,36 +0,0 @@
-using Lua.Internal;
-
-namespace Lua;
-
-public sealed class LuaUserThread : LuaState, IPoolNode<LuaUserThread>
-{
-    static LinkedPool<LuaUserThread> pool;
-    LuaUserThread? nextNode;
-
-    ref LuaUserThread? IPoolNode<LuaUserThread>.NextNode => ref nextNode;
-
-    public static LuaUserThread Create(LuaState parent)
-    {
-        if (!pool.TryPop(out var result))
-        {
-            result = new();
-        }
-
-        result.GlobalState = parent.GlobalState;
-        result.CoreData = ThreadCoreData.Create();
-
-        return result;
-    }
-
-    public void Release()
-    {
-        if (CoreData!.CallStack.Count != 0)
-        {
-            throw new InvalidOperationException("This thread is running! Call stack is not empty!!");
-        }
-
-        CoreData.Release();
-        CoreData = null!;
-        pool.TryPush(this);
-    }
-}

+ 0 - 21
src/Lua/Runtime/Lease.cs

@@ -1,21 +0,0 @@
-namespace Lua.Runtime;
-
-public readonly struct UserThreadLease(LuaUserThread thread) : IDisposable
-{
-    public LuaUserThread State { get; } = thread;
-
-    public void Dispose()
-    {
-        State.Release();
-    }
-}
-
-public readonly struct CoroutineLease(LuaCoroutine thread) : IDisposable
-{
-    public LuaCoroutine Thread { get; } = thread;
-
-    public void Dispose()
-    {
-        Thread.Release();
-    }
-}

+ 8 - 8
src/Lua/Runtime/LuaClosure.cs

@@ -8,7 +8,7 @@ public sealed class LuaClosure : LuaFunction
 {
     FastListCore<UpValue> upValues;
 
-    public LuaClosure(LuaState thread, Prototype proto, LuaTable? environment = null)
+    public LuaClosure(LuaState state, Prototype proto, LuaTable? environment = null)
         : base(proto.ChunkName, static (context, ct) => LuaVirtualMachine.ExecuteClosureAsync(context.State, ct))
     {
         Proto = proto;
@@ -18,19 +18,19 @@ public sealed class LuaClosure : LuaFunction
             return;
         }
 
-        if (thread.CallStackFrameCount == 0)
+        if (state.CallStackFrameCount == 0)
         {
-            upValues.Add(thread.GlobalState.EnvUpValue);
+            upValues.Add(state.GlobalState.EnvUpValue);
             return;
         }
 
-        var baseIndex = thread.GetCallStackFrames()[^1].Base;
+        var baseIndex = state.GetCallStackFrames()[^1].Base;
 
         // add upvalues
         for (var i = 0; i < proto.UpValues.Length; i++)
         {
             var description = proto.UpValues[i];
-            var upValue = GetUpValueFromDescription(thread.GlobalState, thread, description, baseIndex);
+            var upValue = GetUpValueFromDescription(state.GlobalState, state, description, baseIndex);
             upValues.Add(upValue);
         }
     }
@@ -62,7 +62,7 @@ public sealed class LuaClosure : LuaFunction
         upValues[index].SetValue(value);
     }
 
-    static UpValue GetUpValueFromDescription(LuaGlobalState globalState, LuaState thread, UpValueDesc description, int baseIndex = 0)
+    static UpValue GetUpValueFromDescription(LuaGlobalState globalState, LuaState state, UpValueDesc description, int baseIndex = 0)
     {
         if (description.IsLocal)
         {
@@ -71,11 +71,11 @@ public sealed class LuaClosure : LuaFunction
                 return globalState.EnvUpValue;
             }
 
-            return globalState.GetOrAddUpValue(thread, baseIndex + description.Index);
+            return state.GetOrAddUpValue(baseIndex + description.Index);
         }
 
 
-        if (thread.GetCurrentFrame().Function is LuaClosure parentClosure)
+        if (state.GetCurrentFrame().Function is LuaClosure parentClosure)
         {
             return parentClosure.UpValues[description.Index];
         }

+ 0 - 148
src/Lua/Runtime/LuaThreadAccess.cs

@@ -1,148 +0,0 @@
-using System.Runtime.CompilerServices;
-
-namespace Lua.Runtime;
-
-public readonly struct LuaThreadAccess
-{
-    internal LuaThreadAccess(LuaState thread, int version)
-    {
-        State = thread;
-        Version = version;
-    }
-
-    public readonly LuaState State;
-    public readonly int Version;
-
-    public bool IsValid => Version == State.CurrentVersion;
-
-    public LuaGlobalState GlobalState
-    {
-        [MethodImpl(MethodImplOptions.AggressiveInlining)]
-        get
-        {
-            ThrowIfInvalid();
-            return State.GlobalState;
-        }
-    }
-
-    public LuaStack Stack
-    {
-        [MethodImpl(MethodImplOptions.AggressiveInlining)]
-        get
-        {
-            ThrowIfInvalid();
-            return State.Stack;
-        }
-    }
-
-    public ValueTask<int> RunAsync(LuaFunction function, CancellationToken cancellationToken = default)
-    {
-        return RunAsync(function, 0, State.Stack.Count, cancellationToken);
-    }
-
-    public ValueTask<int> RunAsync(LuaFunction function, int argumentCount, CancellationToken cancellationToken = default)
-    {
-        return RunAsync(function, argumentCount, State.Stack.Count - argumentCount, cancellationToken);
-    }
-
-    public async ValueTask<int> RunAsync(LuaFunction function, int argumentCount, int returnBase, CancellationToken cancellationToken = default)
-    {
-        ThrowIfInvalid();
-        if (function == null)
-        {
-            throw new ArgumentNullException(nameof(function));
-        }
-
-        State.ThrowIfCancellationRequested(cancellationToken);
-        var thread = State;
-        var varArgumentCount = function.GetVariableArgumentCount(argumentCount);
-        if (varArgumentCount != 0)
-        {
-            if (varArgumentCount < 0)
-            {
-                thread.Stack.SetTop(thread.Stack.Count - varArgumentCount);
-                varArgumentCount = 0;
-            }
-            else
-            {
-                LuaVirtualMachine.PrepareVariableArgument(thread.Stack, argumentCount, varArgumentCount);
-            }
-
-            argumentCount -= varArgumentCount;
-        }
-
-        CallStackFrame frame = new() { Base = thread.Stack.Count - argumentCount, VariableArgumentCount = varArgumentCount, Function = function, ReturnBase = returnBase };
-        if (thread.IsInHook)
-        {
-            frame.Flags |= CallStackFrameFlags.InHook;
-        }
-
-        var access = thread.PushCallStackFrame(frame);
-        LuaFunctionExecutionContext context = new() { Access = access, ArgumentCount = argumentCount, ReturnFrameBase = returnBase };
-        var callStackTop = thread.CallStackFrameCount;
-        try
-        {
-            if (State.CallOrReturnHookMask.Value != 0 && !State.IsInHook)
-            {
-                return await LuaVirtualMachine.ExecuteCallHook(context, cancellationToken);
-            }
-
-            return await function.Func(context, cancellationToken);
-        }
-        finally
-        {
-            State.PopCallStackFrameUntil(callStackTop - 1);
-        }
-    }
-
-
-    internal CallStackFrame CreateCallStackFrame(LuaFunction function, int argumentCount, int returnBase, int callerInstructionIndex)
-    {
-        var thread = State;
-        var varArgumentCount = function.GetVariableArgumentCount(argumentCount);
-        if (varArgumentCount != 0)
-        {
-            if (varArgumentCount < 0)
-            {
-                thread.Stack.SetTop(thread.Stack.Count - varArgumentCount);
-                argumentCount -= varArgumentCount;
-                varArgumentCount = 0;
-            }
-            else
-            {
-                LuaVirtualMachine.PrepareVariableArgument(thread.Stack, argumentCount, varArgumentCount);
-            }
-        }
-
-        CallStackFrame frame = new()
-        {
-            Base = thread.Stack.Count - argumentCount,
-            VariableArgumentCount = varArgumentCount,
-            Function = function,
-            ReturnBase = returnBase,
-            CallerInstructionIndex = callerInstructionIndex
-        };
-
-        if (thread.IsInHook)
-        {
-            frame.Flags |= CallStackFrameFlags.InHook;
-        }
-
-        return frame;
-    }
-
-
-    [MethodImpl(MethodImplOptions.AggressiveInlining)]
-    public void ThrowIfInvalid()
-    {
-        if (Version != State.CurrentVersion)
-        {
-            ThrowInvalid();
-        }
-    }
-
-    void ThrowInvalid()
-    {
-        throw new InvalidOperationException("Thread access is invalid.");
-    }
-}

+ 0 - 320
src/Lua/Runtime/LuaThreadAccessExtensions.cs

@@ -1,320 +0,0 @@
-using System.Runtime.CompilerServices;
-
-// ReSharper disable MethodHasAsyncOverloadWithCancellation
-
-namespace Lua.Runtime;
-
-public static class LuaThreadAccessAccessExtensions
-{
-    public static ValueTask<int> DoStringAsync(this LuaThreadAccess access, string source, Memory<LuaValue> results, string? chunkName = null, CancellationToken cancellationToken = default)
-    {
-        access.ThrowIfInvalid();
-        var closure = access.GlobalState.Load(source, chunkName ?? source);
-        return ExecuteAsync(access, closure, results, cancellationToken);
-    }
-
-    public static ValueTask<LuaValue[]> DoStringAsync(this LuaThreadAccess access, string source, string? chunkName = null, CancellationToken cancellationToken = default)
-    {
-        access.ThrowIfInvalid();
-        var closure = access.GlobalState.Load(source, chunkName ?? source);
-        return ExecuteAsync(access, closure, cancellationToken);
-    }
-
-    public static ValueTask<int> ExecuteAsync(this LuaThreadAccess access, ReadOnlySpan<byte> source, Memory<LuaValue> results, string chunkName, CancellationToken cancellationToken = default)
-    {
-        access.ThrowIfInvalid();
-        var closure = access.GlobalState.Load(source, chunkName);
-        return ExecuteAsync(access, closure, results, cancellationToken);
-    }
-
-    public static ValueTask<LuaValue[]> ExecuteAsync(this LuaThreadAccess access, ReadOnlySpan<byte> source, string chunkName, CancellationToken cancellationToken = default)
-    {
-        access.ThrowIfInvalid();
-        var closure = access.GlobalState.Load(source, chunkName);
-        return ExecuteAsync(access, closure, cancellationToken);
-    }
-
-    public static async ValueTask<int> DoFileAsync(this LuaThreadAccess access, string path, Memory<LuaValue> buffer, CancellationToken cancellationToken = default)
-    {
-        access.ThrowIfInvalid();
-        var closure = await access.GlobalState.LoadFileAsync(path, "bt", null, cancellationToken);
-        var count = await access.RunAsync(closure, 0, cancellationToken);
-        using var results = access.ReadTopValues(count);
-        results.AsSpan()[..Math.Min(buffer.Length, results.Length)].CopyTo(buffer.Span);
-        return results.Count;
-    }
-
-    public static async ValueTask<LuaValue[]> DoFileAsync(this LuaThreadAccess access, string path, CancellationToken cancellationToken = default)
-    {
-        var closure = await access.GlobalState.LoadFileAsync(path, "bt", null, cancellationToken);
-        var count = await access.RunAsync(closure, 0, cancellationToken);
-        using var results = access.ReadTopValues(count);
-        return results.AsSpan().ToArray();
-    }
-
-    public static async ValueTask<int> ExecuteAsync(this LuaThreadAccess access, LuaClosure closure, Memory<LuaValue> buffer, CancellationToken cancellationToken = default)
-    {
-        access.ThrowIfInvalid();
-        var count = await access.RunAsync(closure, 0, cancellationToken);
-        using var results = access.ReadTopValues(count);
-        results.AsSpan()[..Math.Min(buffer.Length, results.Length)].CopyTo(buffer.Span);
-        return results.Count;
-    }
-
-    public static async ValueTask<LuaValue[]> ExecuteAsync(this LuaThreadAccess access, LuaClosure closure, CancellationToken cancellationToken = default)
-    {
-        access.ThrowIfInvalid();
-        var count = await access.RunAsync(closure, 0, cancellationToken);
-        using var results = access.ReadTopValues(count);
-        return results.AsSpan().ToArray();
-    }
-
-    public static void Push(this LuaThreadAccess access, LuaValue value)
-    {
-        access.ThrowIfInvalid();
-        access.Stack.Push(value);
-    }
-
-    public static void Push(this LuaThreadAccess access, params ReadOnlySpan<LuaValue> span)
-    {
-        access.ThrowIfInvalid();
-        access.Stack.PushRange(span);
-    }
-
-    public static void Pop(this LuaThreadAccess access, int count)
-    {
-        access.ThrowIfInvalid();
-        access.Stack.Pop(count);
-    }
-
-    public static LuaValue Pop(this LuaThreadAccess access)
-    {
-        access.ThrowIfInvalid();
-        return access.Stack.Pop();
-    }
-
-    public static LuaTopValuesReader ReadTopValues(this LuaThreadAccess access, int argumentCount)
-    {
-        access.ThrowIfInvalid();
-        var stack = access.Stack;
-        return new(stack, stack.Count - argumentCount);
-    }
-
-    public static ValueTask<LuaValue> Add(this LuaThreadAccess access, LuaValue x, LuaValue y, CancellationToken cancellationToken = default)
-    {
-        if (x.TryReadDouble(out var numX) && y.TryReadDouble(out var numY))
-        {
-            return new(numX + numY);
-        }
-
-        access.ThrowIfInvalid();
-        return LuaVirtualMachine.ExecuteBinaryOperationMetaMethod(access.State, x, y, OpCode.Add, cancellationToken);
-    }
-
-    public static ValueTask<LuaValue> Sub(this LuaThreadAccess access, LuaValue x, LuaValue y, CancellationToken cancellationToken = default)
-    {
-        if (x.TryReadDouble(out var numX) && y.TryReadDouble(out var numY))
-        {
-            return new(numX - numY);
-        }
-
-        access.ThrowIfInvalid();
-        return LuaVirtualMachine.ExecuteBinaryOperationMetaMethod(access.State, x, y, OpCode.Sub, cancellationToken);
-    }
-
-    public static ValueTask<LuaValue> Mul(this LuaThreadAccess access, LuaValue x, LuaValue y, CancellationToken cancellationToken = default)
-    {
-        if (x.TryReadDouble(out var numX) && y.TryReadDouble(out var numY))
-        {
-            return new(numX * numY);
-        }
-
-        access.ThrowIfInvalid();
-        return LuaVirtualMachine.ExecuteBinaryOperationMetaMethod(access.State, x, y, OpCode.Mul, cancellationToken);
-    }
-
-    public static ValueTask<LuaValue> Div(this LuaThreadAccess access, LuaValue x, LuaValue y, CancellationToken cancellationToken = default)
-    {
-        if (x.TryReadDouble(out var numX) && y.TryReadDouble(out var numY))
-        {
-            return new(numX / numY);
-        }
-
-        access.ThrowIfInvalid();
-        return LuaVirtualMachine.ExecuteBinaryOperationMetaMethod(access.State, x, y, OpCode.Div, cancellationToken);
-    }
-
-    public static ValueTask<LuaValue> Mod(this LuaThreadAccess access, LuaValue x, LuaValue y, CancellationToken cancellationToken = default)
-    {
-        if (x.TryReadDouble(out var numX) && y.TryReadDouble(out var numY))
-        {
-            return new(LuaVirtualMachine.Mod(numX, numY));
-        }
-
-        access.ThrowIfInvalid();
-        return LuaVirtualMachine.ExecuteBinaryOperationMetaMethod(access.State, x, y, OpCode.Mod, cancellationToken);
-    }
-
-    public static ValueTask<LuaValue> Pow(this LuaThreadAccess access, LuaValue x, LuaValue y, CancellationToken cancellationToken = default)
-    {
-        if (x.TryReadDouble(out var numX) && y.TryReadDouble(out var numY))
-        {
-            return new(Math.Pow(numX, numY));
-        }
-
-        access.ThrowIfInvalid();
-        return LuaVirtualMachine.ExecuteBinaryOperationMetaMethod(access.State, x, y, OpCode.Pow, cancellationToken);
-    }
-
-
-    public static ValueTask<LuaValue> Unm(this LuaThreadAccess access, LuaValue value, CancellationToken cancellationToken = default)
-    {
-        if (value.TryReadDouble(out var numB))
-        {
-            return new(-numB);
-        }
-
-        access.ThrowIfInvalid();
-        return LuaVirtualMachine.ExecuteUnaryOperationMetaMethod(access.State, value, OpCode.Unm, cancellationToken);
-    }
-
-    public static ValueTask<LuaValue> Len(this LuaThreadAccess access, LuaValue value, CancellationToken cancellationToken = default)
-    {
-        if (value.TryReadString(out var str))
-        {
-            return new(str.Length);
-        }
-
-        if (value.TryReadTable(out var table))
-        {
-            return new(table.ArrayLength);
-        }
-
-        access.ThrowIfInvalid();
-        return LuaVirtualMachine.ExecuteUnaryOperationMetaMethod(access.State, value, OpCode.Len, cancellationToken);
-    }
-
-
-    public static ValueTask<bool> LessThan(this LuaThreadAccess access, LuaValue x, LuaValue y, CancellationToken cancellationToken = default)
-    {
-        if (x.TryReadNumber(out var numX) && y.TryReadNumber(out var numY))
-        {
-            return new(numX < numY);
-        }
-
-        if (x.TryReadString(out var strX) && y.TryReadString(out var strY))
-        {
-            var c = StringComparer.Ordinal.Compare(strX, strY);
-            return new(c < 0);
-        }
-
-        access.ThrowIfInvalid();
-        return LuaVirtualMachine.ExecuteCompareOperationMetaMethod(access.State, x, y, OpCode.Lt, cancellationToken);
-    }
-
-    public static ValueTask<bool> LessThanOrEquals(this LuaThreadAccess access, LuaValue x, LuaValue y, CancellationToken cancellationToken = default)
-    {
-        if (x.TryReadNumber(out var numX) && y.TryReadNumber(out var numY))
-        {
-            return new(numX <= numY);
-        }
-
-        if (x.TryReadString(out var strX) && y.TryReadString(out var strY))
-        {
-            var c = StringComparer.Ordinal.Compare(strX, strY);
-            return new(c <= 0);
-        }
-
-        access.ThrowIfInvalid();
-        return LuaVirtualMachine.ExecuteCompareOperationMetaMethod(access.State, x, y, OpCode.Le, cancellationToken);
-    }
-
-    public static ValueTask<bool> Equals(this LuaThreadAccess access, LuaValue x, LuaValue y, CancellationToken cancellationToken = default)
-    {
-        if (x == y)
-        {
-            return new(true);
-        }
-
-        access.ThrowIfInvalid();
-        return LuaVirtualMachine.ExecuteCompareOperationMetaMethod(access.State, x, y, OpCode.Eq, cancellationToken);
-    }
-
-
-    public static async ValueTask<LuaValue> GetTable(this LuaThreadAccess access, LuaValue table, LuaValue key, CancellationToken cancellationToken = default)
-    {
-        if (table.TryReadTable(out var luaTable))
-        {
-            if (luaTable.TryGetValue(key, out var value))
-            {
-                return value;
-            }
-        }
-
-        access.ThrowIfInvalid();
-        return await LuaVirtualMachine.ExecuteGetTableSlowPath(access.State, table, key, cancellationToken);
-    }
-
-    public static ValueTask SetTable(this LuaThreadAccess access, LuaValue table, LuaValue key, LuaValue value, CancellationToken cancellationToken = default)
-    {
-        access.ThrowIfInvalid();
-
-        if (key.TryReadNumber(out var numB))
-        {
-            if (double.IsNaN(numB))
-            {
-                throw new LuaRuntimeException(access.State, "table index is NaN");
-            }
-        }
-
-
-        if (table.TryReadTable(out var luaTable))
-        {
-            ref var valueRef = ref luaTable.FindValue(key);
-            if (!Unsafe.IsNullRef(ref valueRef) && valueRef.Type != LuaValueType.Nil)
-            {
-                valueRef = value;
-                return default;
-            }
-        }
-
-        return LuaVirtualMachine.ExecuteSetTableSlowPath(access.State, table, key, value, cancellationToken);
-    }
-
-    public static ValueTask<LuaValue> Concat(this LuaThreadAccess access, ReadOnlySpan<LuaValue> values, CancellationToken cancellationToken = default)
-    {
-        access.ThrowIfInvalid();
-        access.Stack.PushRange(values);
-        return Concat(access, values.Length, cancellationToken);
-    }
-
-    public static ValueTask<LuaValue> Concat(this LuaThreadAccess access, int concatCount, CancellationToken cancellationToken = default)
-    {
-        access.ThrowIfInvalid();
-        return LuaVirtualMachine.Concat(access.State, concatCount, cancellationToken);
-    }
-
-    public static ValueTask<int> Call(this LuaThreadAccess access, int funcIndex, int returnBase, CancellationToken cancellationToken = default)
-    {
-        access.ThrowIfInvalid();
-        return LuaVirtualMachine.Call(access.State, funcIndex, returnBase, cancellationToken);
-    }
-
-    public static ValueTask<LuaValue[]> Call(this LuaThreadAccess access, LuaValue function, ReadOnlySpan<LuaValue> arguments, CancellationToken cancellationToken = default)
-    {
-        access.ThrowIfInvalid();
-        var thread = access.State;
-        var funcIndex = thread.Stack.Count;
-        thread.Stack.Push(function);
-        thread.Stack.PushRange(arguments);
-        return Impl(access, funcIndex, cancellationToken);
-
-        static async ValueTask<LuaValue[]> Impl(LuaThreadAccess access, int funcIndex, CancellationToken cancellationToken)
-        {
-            await LuaVirtualMachine.Call(access.State, funcIndex, funcIndex, cancellationToken);
-            var count = access.Stack.Count - funcIndex;
-            using var results = access.ReadTopValues(count);
-            return results.AsSpan().ToArray();
-        }
-    }
-}

+ 14 - 14
src/Lua/Runtime/LuaVirtualMachine.Debug.cs

@@ -38,9 +38,9 @@ public static partial class LuaVirtualMachine
                 stack.Push("count");
                 stack.Push(LuaValue.Nil);
                 context.State.IsInHook = true;
-                var frame = context.State.CurrentAccess.CreateCallStackFrame(hook, 2, top, pc);
-                var access = context.State.PushCallStackFrame(frame);
-                LuaFunctionExecutionContext funcContext = new() { Access = access, ArgumentCount = stack.Count - frame.Base, ReturnFrameBase = frame.ReturnBase };
+                var frame = context.State.CreateCallStackFrame(hook, 2, top, pc);
+                context.State.PushCallStackFrame(frame);
+                LuaFunctionExecutionContext funcContext = new() { State = context.State, ArgumentCount = stack.Count - frame.Base, ReturnFrameBase = frame.ReturnBase };
                 await hook.Func(funcContext, context.CancellationToken);
                 context.State.IsInHook = false;
 
@@ -67,9 +67,9 @@ public static partial class LuaVirtualMachine
                     stack.Push("line");
                     stack.Push(line);
                     context.State.IsInHook = true;
-                    var frame = context.State.CurrentAccess.CreateCallStackFrame(hook, 2, top, pc);
-                    var access = context.State.PushCallStackFrame(frame);
-                    LuaFunctionExecutionContext funcContext = new() { Access = access, ArgumentCount = stack.Count - frame.Base, ReturnFrameBase = frame.ReturnBase };
+                    var frame = context.State.CreateCallStackFrame(hook, 2, top, pc);
+                    context.State.PushCallStackFrame(frame);
+                    LuaFunctionExecutionContext funcContext = new() { State = context.State, ArgumentCount = stack.Count - frame.Base, ReturnFrameBase = frame.ReturnBase };
                     try
                     {
                         await hook.Func(funcContext, context.CancellationToken);
@@ -98,7 +98,7 @@ public static partial class LuaVirtualMachine
     [MethodImpl(MethodImplOptions.NoInlining)]
     static ValueTask<int> ExecuteCallHook(VirtualMachineExecutionContext context, in CallStackFrame frame, int arguments, bool isTailCall = false)
     {
-        return ExecuteCallHook(new() { Access = context.State.CurrentAccess, ArgumentCount = arguments, ReturnFrameBase = frame.ReturnBase }, context.CancellationToken, isTailCall);
+        return ExecuteCallHook(new() { State = context.State, ArgumentCount = arguments, ReturnFrameBase = frame.ReturnBase }, context.CancellationToken, isTailCall);
     }
 
     internal static async ValueTask<int> ExecuteCallHook(LuaFunctionExecutionContext context, CancellationToken cancellationToken, bool isTailCall = false)
@@ -113,9 +113,9 @@ public static partial class LuaVirtualMachine
 
             stack.Push(LuaValue.Nil);
             context.State.IsInHook = true;
-            var frame = context.State.CurrentAccess.CreateCallStackFrame(hook, 2, top, 0);
-            var access = context.State.PushCallStackFrame(frame);
-            LuaFunctionExecutionContext funcContext = new() { Access = access, ArgumentCount = stack.Count - frame.Base, ReturnFrameBase = frame.ReturnBase };
+            var frame = context.State.CreateCallStackFrame(hook, 2, top, 0);
+            context.State.PushCallStackFrame(frame);
+            LuaFunctionExecutionContext funcContext = new() { State = context.State, ArgumentCount = stack.Count - frame.Base, ReturnFrameBase = frame.ReturnBase };
             try
             {
                 await hook.Func(funcContext, cancellationToken);
@@ -131,7 +131,7 @@ public static partial class LuaVirtualMachine
 
         {
             var frame = context.State.GetCurrentFrame();
-            var task = frame.Function.Func(new() { Access = context.State.CurrentAccess, ArgumentCount = argCount, ReturnFrameBase = frame.ReturnBase }, cancellationToken);
+            var task = frame.Function.Func(new() { State = context.State, ArgumentCount = argCount, ReturnFrameBase = frame.ReturnBase }, cancellationToken);
             var r = await task;
             if (isTailCall || !context.State.IsReturnHookEnabled)
             {
@@ -143,9 +143,9 @@ public static partial class LuaVirtualMachine
             stack.Push("return");
             stack.Push(LuaValue.Nil);
             context.State.IsInHook = true;
-            frame = context.State.CurrentAccess.CreateCallStackFrame(hook, 2, top, 0);
-            var access = context.State.PushCallStackFrame(frame);
-            LuaFunctionExecutionContext funcContext = new() { Access = access, ArgumentCount = stack.Count - frame.Base, ReturnFrameBase = frame.ReturnBase };
+            frame = context.State.CreateCallStackFrame(hook, 2, top, 0);
+            context.State.PushCallStackFrame(frame);
+            LuaFunctionExecutionContext funcContext = new() { State = context.State, ArgumentCount = stack.Count - frame.Base, ReturnFrameBase = frame.ReturnBase };
             try
             {
                 context.State.IsInHook = true;

File diff suppressed because it is too large
+ 160 - 161
src/Lua/Runtime/LuaVirtualMachine.cs


+ 14 - 15
src/Lua/Standard/BasicLibrary.cs

@@ -95,8 +95,8 @@ public sealed class BasicLibrary
     {
         var arg0 = context.GetArgument<string>(0);
         context.State.Stack.PopUntil(context.ReturnFrameBase);
-        var closure = await context.GlobalState.LoadFileAsync(arg0, "bt", null, cancellationToken);
-        return await context.Access.RunAsync(closure, cancellationToken);
+        var closure = await context.State.LoadFileAsync(arg0, "bt", null, cancellationToken);
+        return await context.State.RunAsync(closure, cancellationToken);
     }
 
     public ValueTask<int> Error(LuaFunctionExecutionContext context, CancellationToken cancellationToken)
@@ -146,7 +146,7 @@ public sealed class BasicLibrary
             stack.Push(metamethod);
             stack.Push(arg0);
 
-            await LuaVirtualMachine.Call(context.Access.State, top, context.ReturnFrameBase, cancellationToken);
+            await LuaVirtualMachine.Call(context.State, top, context.ReturnFrameBase, cancellationToken);
             stack.SetTop(context.ReturnFrameBase + 3);
             return 3;
         }
@@ -167,7 +167,7 @@ public sealed class BasicLibrary
         // do not use LuaState.DoFileAsync as it uses the newExecutionContext
         try
         {
-            return context.Return(await context.GlobalState.LoadFileAsync(arg0, mode, arg2, cancellationToken));
+            return context.Return(await context.State.LoadFileAsync(arg0, mode, arg2, cancellationToken));
         }
         catch (Exception ex)
         {
@@ -197,7 +197,7 @@ public sealed class BasicLibrary
         {
             if (arg0.TryRead<string>(out var str))
             {
-                return new(context.Return(context.GlobalState.Load(str, name ?? str, arg3)));
+                return new(context.Return(context.State.Load(str, name ?? str, arg3)));
             }
             else if (arg0.TryRead<LuaFunction>(out var function))
             {
@@ -243,7 +243,7 @@ public sealed class BasicLibrary
             stack.Push(metamethod);
             stack.Push(arg0);
 
-            await LuaVirtualMachine.Call(context.Access.State, top, context.ReturnFrameBase, cancellationToken);
+            await LuaVirtualMachine.Call(context.State, top, context.ReturnFrameBase, cancellationToken);
             stack.SetTop(context.ReturnFrameBase + 3);
             return 3;
         }
@@ -256,7 +256,7 @@ public sealed class BasicLibrary
         var frameCount = context.State.CallStackFrameCount;
         try
         {
-            var count = await LuaVirtualMachine.Call(context.Access.State, context.FrameBase, context.ReturnFrameBase + 1, cancellationToken);
+            var count = await LuaVirtualMachine.Call(context.State, context.FrameBase, context.ReturnFrameBase + 1, cancellationToken);
 
             context.State.Stack.Get(context.ReturnFrameBase) = true;
             return count + 1;
@@ -567,7 +567,7 @@ public sealed class BasicLibrary
             LuaValueType.String => "string",
             LuaValueType.Number => "number",
             LuaValueType.Function => "function",
-            LuaValueType.Thread => "thread",
+            LuaValueType.Thread => "state",
             LuaValueType.LightUserData => "userdata",
             LuaValueType.UserData => "userdata",
             LuaValueType.Table => "table",
@@ -585,31 +585,30 @@ public sealed class BasicLibrary
         {
             var stack = context.State.Stack;
             stack.Get(context.FrameBase + 1) = arg0;
-            var count = await LuaVirtualMachine.Call(context.Access.State, context.FrameBase + 1, context.ReturnFrameBase + 1, cancellationToken);
+            var count = await LuaVirtualMachine.Call(context.State, context.FrameBase + 1, context.ReturnFrameBase + 1, cancellationToken);
 
             context.State.Stack.Get(context.ReturnFrameBase) = true;
             return count + 1;
         }
         catch (Exception ex)
         {
-            var thread = context.State;
-            thread.PopCallStackFrameUntil(frameCount);
+            var state = context.State;
+            state.PopCallStackFrameUntil(frameCount);
             cancellationToken.ThrowIfCancellationRequested();
 
-            var access = thread.CurrentAccess;
             if (ex is LuaRuntimeException luaEx)
             {
                 luaEx.Forget();
-                access.Push(luaEx.ErrorObject);
+                state.Push(luaEx.ErrorObject);
             }
             else
             {
-                access.Push(ex.Message);
+                state.Push(ex.Message);
             }
 
 
             // invoke error handler
-            var count = await access.RunAsync(arg1, 1, context.ReturnFrameBase + 1, cancellationToken);
+            var count = await state.RunAsync(arg1, 1, context.ReturnFrameBase + 1, cancellationToken);
             context.State.Stack.Get(context.ReturnFrameBase) = false;
             return count + 1;
         }

+ 12 - 12
src/Lua/Standard/CoroutineLibrary.cs

@@ -25,13 +25,13 @@ public sealed class CoroutineLibrary
     public ValueTask<int> Create(LuaFunctionExecutionContext context, CancellationToken cancellationToken)
     {
         var arg0 = context.GetArgument<LuaFunction>(0);
-        return new(context.Return(LuaCoroutine.Create(context.State, arg0, true)));
+        return new(context.Return(LuaState.CreateCoroutine(context.State.GlobalState, arg0, true)));
     }
 
     public ValueTask<int> Resume(LuaFunctionExecutionContext context, CancellationToken cancellationToken)
     {
-        var thread = context.GetArgument<LuaState>(0);
-        return thread.ResumeAsync(context with { ArgumentCount = context.ArgumentCount - 1 }, cancellationToken);
+        var state = context.GetArgument<LuaState>(0);
+        return state.ResumeAsync(context with { ArgumentCount = context.ArgumentCount - 1 }, cancellationToken);
     }
 
     public ValueTask<int> Running(LuaFunctionExecutionContext context, CancellationToken cancellationToken)
@@ -41,8 +41,8 @@ public sealed class CoroutineLibrary
 
     public ValueTask<int> Status(LuaFunctionExecutionContext context, CancellationToken cancellationToken)
     {
-        var thread = context.GetArgument<LuaState>(0);
-        return new(context.Return(thread.GetStatus() switch
+        var state = context.GetArgument<LuaState>(0);
+        return new(context.Return(state.GetStatus() switch
         {
             LuaThreadStatus.Normal => "normal",
             LuaThreadStatus.Suspended => "suspended",
@@ -55,22 +55,22 @@ public sealed class CoroutineLibrary
     public ValueTask<int> Wrap(LuaFunctionExecutionContext context, CancellationToken cancellationToken)
     {
         var arg0 = context.GetArgument<LuaFunction>(0);
-        var thread = LuaCoroutine.Create(context.State, arg0, false);
-        return new(context.Return(new CSharpClosure("wrap", [thread],
+        var state = LuaState.CreateCoroutine(context.State.GlobalState, arg0, false);
+        return new(context.Return(new CSharpClosure("wrap", [state],
             static async (context, cancellationToken) =>
             {
-                var thread = context.GetCsClosure()!.UpValues[0].Read<LuaState>();
-                if (thread is not LuaCoroutine coroutine)
+                var state = context.GetCsClosure()!.UpValues[0].Read<LuaState>();
+                if (!state.IsCoroutine)
                 {
-                    return await thread.ResumeAsync(context, cancellationToken);
+                    return await state.ResumeAsync(context, cancellationToken);
                 }
 
                 var stack = context.State.Stack;
                 var frameBase = stack.Count;
-                context.State.PushCallStackFrame(new() { Base = frameBase, ReturnBase = context.ReturnFrameBase, VariableArgumentCount = 0, Function = coroutine.Function });
+                context.State.PushCallStackFrame(new() { Base = frameBase, ReturnBase = context.ReturnFrameBase, VariableArgumentCount = 0, Function = state.CoroutineFunction! });
                 try
                 {
-                    await thread.ResumeAsync(context, cancellationToken);
+                    await state.ResumeAsync(context, cancellationToken);
                     var result = context.GetReturnBuffer(context.State.Stack.Count - context.ReturnFrameBase);
                     result[1..].CopyTo(result);
                     context.State.Stack.Pop();

+ 36 - 39
src/Lua/Standard/DebugLibrary.cs

@@ -43,10 +43,10 @@ public class DebugLibrary
             return context.State;
         }
 
-        if (context.GetArgument(0).TryRead<LuaState>(out var thread))
+        if (context.GetArgument(0).TryRead<LuaState>(out var state))
         {
             argOffset = 1;
-            return thread;
+            return state;
         }
 
         argOffset = 0;
@@ -54,7 +54,7 @@ public class DebugLibrary
     }
 
 
-    static ref LuaValue FindLocal(LuaState thread, int level, int index, out string? name)
+    static ref LuaValue FindLocal(LuaState state, int level, int index, out string? name)
     {
         if (index == 0)
         {
@@ -62,7 +62,7 @@ public class DebugLibrary
             return ref Unsafe.NullRef<LuaValue>();
         }
 
-        var callStack = thread.GetCallStackFrames();
+        var callStack = state.GetCallStackFrames();
         var frame = callStack[^(level + 1)];
         if (index < 0)
         {
@@ -71,7 +71,7 @@ public class DebugLibrary
             if (frameVariableArgumentCount > 0 && index < frameVariableArgumentCount)
             {
                 name = "(*vararg)";
-                return ref thread.Stack.Get(frame.Base - frameVariableArgumentCount + index);
+                return ref state.Stack.Get(frame.Base - frameVariableArgumentCount + index);
             }
 
             name = null;
@@ -115,13 +115,13 @@ public class DebugLibrary
                 if (localId == 0)
                 {
                     name = l.Name;
-                    return ref thread.Stack.Get(frameBase + index);
+                    return ref state.Stack.Get(frameBase + index);
                 }
             }
         }
         else
         {
-            var nextFrameBase = level != 0 ? callStack[^level].Base : thread.Stack.Count;
+            var nextFrameBase = level != 0 ? callStack[^level].Base : state.Stack.Count;
 
             if (nextFrameBase - 1 < frameBase + index)
             {
@@ -131,7 +131,7 @@ public class DebugLibrary
         }
 
         name = "(*temporary)";
-        return ref thread.Stack.Get(frameBase + index);
+        return ref state.Stack.Get(frameBase + index);
     }
 
     public ValueTask<int> GetLocal(LuaFunctionExecutionContext context, CancellationToken cancellationToken)
@@ -150,7 +150,7 @@ public class DebugLibrary
             return LuaValue.Nil;
         }
 
-        var thread = GetLuaThread(context, out var argOffset);
+        var state = GetLuaThread(context, out var argOffset);
 
         var index = context.GetArgument<int>(argOffset + 1);
         if (context.GetArgument(argOffset).TryReadFunction(out var f))
@@ -161,12 +161,12 @@ public class DebugLibrary
         var level = context.GetArgument<int>(argOffset);
 
 
-        if (level < 0 || level >= thread.GetCallStackFrames().Length)
+        if (level < 0 || level >= state.GetCallStackFrames().Length)
         {
             context.ThrowBadArgument(1, "level out of range");
         }
 
-        ref var local = ref FindLocal(thread, level, index, out var name);
+        ref var local = ref FindLocal(state, level, index, out var name);
         if (name is null)
         {
             return new(context.Return(LuaValue.Nil));
@@ -177,19 +177,19 @@ public class DebugLibrary
 
     public ValueTask<int> SetLocal(LuaFunctionExecutionContext context, CancellationToken cancellationToken)
     {
-        var thread = GetLuaThread(context, out var argOffset);
+        var state = GetLuaThread(context, out var argOffset);
 
         var value = context.GetArgument(argOffset + 2);
         var index = context.GetArgument<int>(argOffset + 1);
         var level = context.GetArgument<int>(argOffset);
 
 
-        if (level < 0 || level >= thread.GetCallStackFrames().Length)
+        if (level < 0 || level >= state.GetCallStackFrames().Length)
         {
             context.ThrowBadArgument(1, "level out of range");
         }
 
-        ref var local = ref FindLocal(thread, level, index, out var name);
+        ref var local = ref FindLocal(state, level, index, out var name);
         if (name is null)
         {
             return new(context.Return(LuaValue.Nil));
@@ -333,7 +333,7 @@ public class DebugLibrary
 
     public ValueTask<int> Traceback(LuaFunctionExecutionContext context, CancellationToken cancellationToken)
     {
-        var thread = GetLuaThread(context, out var argOffset);
+        var state = GetLuaThread(context, out var argOffset);
 
         var message = context.GetArgumentOrDefault(argOffset);
         var level = context.GetArgumentOrDefault<int>(argOffset + 1, argOffset == 0 ? 1 : 0);
@@ -348,15 +348,12 @@ public class DebugLibrary
             return new(context.Return(LuaValue.Nil));
         }
 
-        if (thread is LuaCoroutine coroutine)
+        if (state is { IsCoroutine: true, LuaTraceback: {} traceback })
         {
-            if (coroutine.LuaTraceback is not null)
-            {
-                return new(context.Return(coroutine.LuaTraceback.ToString(level)));
-            }
+            return new(context.Return(traceback.ToString(level)));
         }
 
-        var callStack = thread.GetCallStackFrames();
+        var callStack = state.GetCallStackFrames();
         if (callStack.Length == 0)
         {
             return new(context.Return("stack traceback:"));
@@ -421,26 +418,26 @@ public class DebugLibrary
 
     public async ValueTask<int> SetHook(LuaFunctionExecutionContext context, CancellationToken cancellationToken)
     {
-        var thread = GetLuaThread(context, out var argOffset);
+        var state = GetLuaThread(context, out var argOffset);
         var hook = context.GetArgumentOrDefault<LuaFunction?>(argOffset);
         var mask = context.GetArgumentOrDefault<string?>(argOffset + 1) ?? "";
         var count = context.GetArgumentOrDefault<int>(argOffset + 2);
-        thread.SetHook(hook, mask, count);
+        state.SetHook(hook, mask, count);
         if (hook is null)
         {
             return 0;
         }
 
-        if (thread.IsReturnHookEnabled && context.State == thread)
+        if (state.IsReturnHookEnabled && context.State == state)
         {
-            var stack = thread.Stack;
+            var stack = state.Stack;
             var top = stack.Count;
             stack.Push("return");
             stack.Push(LuaValue.Nil);
             context.State.IsInHook = true;
-            var frame = context.State.CurrentAccess.CreateCallStackFrame(hook, 2, top, 0);
-            var access = context.State.PushCallStackFrame(frame);
-            LuaFunctionExecutionContext funcContext = new() { Access = access, ArgumentCount = stack.Count - frame.Base, ReturnFrameBase = frame.ReturnBase };
+            var frame = context.State.CreateCallStackFrame(hook, 2, top, 0);
+            context.State.PushCallStackFrame(frame);
+            LuaFunctionExecutionContext funcContext = new() { State = context.State, ArgumentCount = stack.Count - frame.Base, ReturnFrameBase = frame.ReturnBase };
             try
             {
                 await hook.Func(funcContext, cancellationToken);
@@ -457,23 +454,23 @@ public class DebugLibrary
 
     public ValueTask<int> GetHook(LuaFunctionExecutionContext context, CancellationToken cancellationToken)
     {
-        var thread = GetLuaThread(context, out var argOffset);
-        if (thread.Hook is null)
+        var state = GetLuaThread(context, out var argOffset);
+        if (state.Hook is null)
         {
             return new(context.Return(LuaValue.Nil, LuaValue.Nil, LuaValue.Nil));
         }
 
-        return new(context.Return(thread.Hook,
-            (thread.IsCallHookEnabled ? "c" : "") +
-            (thread.IsReturnHookEnabled ? "r" : "") +
-            (thread.IsLineHookEnabled ? "l" : "")
-            , thread.BaseHookCount));
+        return new(context.Return(state.Hook,
+            (state.IsCallHookEnabled ? "c" : "") +
+            (state.IsReturnHookEnabled ? "r" : "") +
+            (state.IsLineHookEnabled ? "l" : "")
+            , state.BaseHookCount));
     }
 
     public ValueTask<int> GetInfo(LuaFunctionExecutionContext context, CancellationToken cancellationToken)
     {
         //return new(0);
-        var thread = GetLuaThread(context, out var argOffset);
+        var state = GetLuaThread(context, out var argOffset);
         var what = context.GetArgumentOrDefault<string>(argOffset + 1, "flnStu");
         CallStackFrame? previousFrame = null;
         CallStackFrame? currentFrame = null;
@@ -488,7 +485,7 @@ public class DebugLibrary
         {
             var level = context.GetArgument<int>(argOffset) + 1;
 
-            var callStack = thread.GetCallStackFrames();
+            var callStack = state.GetCallStackFrames();
 
             if (level <= 0 || level > callStack.Length)
             {
@@ -496,11 +493,11 @@ public class DebugLibrary
             }
 
 
-            currentFrame = thread.GetCallStackFrames()[^level];
+            currentFrame = state.GetCallStackFrames()[^level];
             previousFrame = level + 1 <= callStack.Length ? callStack[^(level + 1)] : null;
             if (level != 1)
             {
-                pc = thread.GetCallStackFrames()[^(level - 1)].CallerInstructionIndex;
+                pc = state.GetCallStackFrames()[^(level - 1)].CallerInstructionIndex;
             }
 
             functionToInspect = currentFrame.Value.Function;

+ 4 - 4
src/Lua/Standard/Internal/Bit32Helper.cs

@@ -18,14 +18,14 @@ static class Bit32Helper
         return (int)(long)Math.IEEERemainder(d, Bit32);
     }
 
-    public static void ValidateFieldAndWidth(LuaState thread, string functionName, int argumentId, int field, int width)
+    public static void ValidateFieldAndWidth(LuaState state, string functionName, int argumentId, int field, int width)
     {
         if (field > 31 || field + width > 32)
-            throw new LuaRuntimeException(thread, "trying to access non-existent bits");
+            throw new LuaRuntimeException(state, "trying to access non-existent bits");
         if (field < 0)
-            throw new LuaRuntimeException(thread, $"bad argument #{argumentId} to '{functionName}' (field cannot be negative)");
+            throw new LuaRuntimeException(state, $"bad argument #{argumentId} to '{functionName}' (field cannot be negative)");
 
         if (width <= 0)
-            throw new LuaRuntimeException(thread, $"bad argument #{argumentId} to '{functionName}' (width must be positive)");
+            throw new LuaRuntimeException(state, $"bad argument #{argumentId} to '{functionName}' (width must be positive)");
     }
 }

+ 12 - 12
src/Lua/Standard/Internal/DateTimeHelper.cs

@@ -30,15 +30,15 @@ static class DateTimeHelper
         return DateTime.UnixEpoch + ts;
     }
 
-    public static DateTime ParseTimeTable(LuaState thread, LuaTable table)
+    public static DateTime ParseTimeTable(LuaState state, LuaTable table)
     {
-        static int GetTimeField(LuaState thread, LuaTable table, string key, bool required = true, int defaultValue = 0)
+        static int GetTimeField(LuaState state, LuaTable table, string key, bool required = true, int defaultValue = 0)
         {
             if (!table.TryGetValue(key, out var value))
             {
                 if (required)
                 {
-                    throw new LuaRuntimeException(thread, $"field '{key}' missing in date table");
+                    throw new LuaRuntimeException(state, $"field '{key}' missing in date table");
                 }
                 else
                 {
@@ -51,20 +51,20 @@ static class DateTimeHelper
                 return (int)d;
             }
 
-            throw new LuaRuntimeException(thread, $"field '{key}' is not an integer");
+            throw new LuaRuntimeException(state, $"field '{key}' is not an integer");
         }
 
-        var day = GetTimeField(thread, table, "day");
-        var month = GetTimeField(thread, table, "month");
-        var year = GetTimeField(thread, table, "year");
-        var sec = GetTimeField(thread, table, "sec", false, 0);
-        var min = GetTimeField(thread, table, "min", false, 0);
-        var hour = GetTimeField(thread, table, "hour", false, 12);
+        var day = GetTimeField(state, table, "day");
+        var month = GetTimeField(state, table, "month");
+        var year = GetTimeField(state, table, "year");
+        var sec = GetTimeField(state, table, "sec", false, 0);
+        var min = GetTimeField(state, table, "min", false, 0);
+        var hour = GetTimeField(state, table, "hour", false, 12);
 
         return new(year, month, day, hour, min, sec);
     }
 
-    public static string StrFTime(LuaState thread, ReadOnlySpan<char> format, DateTime d)
+    public static string StrFTime(LuaState state, ReadOnlySpan<char> format, DateTime d)
     {
         // reference: http://www.cplusplus.com/reference/ctime/strftime/
 
@@ -194,7 +194,7 @@ static class DateTimeHelper
             }
             else
             {
-                throw new LuaRuntimeException(thread, $"bad argument #1 to 'date' (invalid conversion specifier '{format.ToString()}')");
+                throw new LuaRuntimeException(state, $"bad argument #1 to 'date' (invalid conversion specifier '{format.ToString()}')");
             }
         }
 

+ 10 - 10
src/Lua/Standard/Internal/IOHelper.cs

@@ -7,19 +7,19 @@ namespace Lua.Standard.Internal;
 
 static class IOHelper
 {
-    public static async ValueTask<int> Open(LuaState thread, string fileName, string mode, bool throwError, CancellationToken cancellationToken)
+    public static async ValueTask<int> Open(LuaState state, string fileName, string mode, bool throwError, CancellationToken cancellationToken)
     {
         var fileMode = LuaFileOpenModeExtensions.ParseModeFromString(mode);
         if (!fileMode.IsValid())
         {
-            throw new LuaRuntimeException(thread, "bad argument #2 to 'open' (invalid mode)");
+            throw new LuaRuntimeException(state, "bad argument #2 to 'open' (invalid mode)");
         }
 
         try
         {
-            var stream = await thread.GlobalState.FileSystem.Open(fileName, fileMode, cancellationToken);
+            var stream = await state.GlobalState.FileSystem.Open(fileName, fileMode, cancellationToken);
 
-            thread.Stack.Push(new(new FileHandle(stream)));
+            state.Stack.Push(new(new FileHandle(stream)));
             return 1;
         }
         catch (IOException ex)
@@ -29,9 +29,9 @@ static class IOHelper
                 throw;
             }
 
-            thread.Stack.Push(LuaValue.Nil);
-            thread.Stack.Push(ex.Message);
-            thread.Stack.Push(ex.HResult);
+            state.Stack.Push(LuaValue.Nil);
+            state.Stack.Push(ex.Message);
+            state.Stack.Push(ex.HResult);
             return 3;
         }
     }
@@ -79,14 +79,14 @@ static class IOHelper
 
     static readonly LuaValue[] defaultReadFormat = ["*l"];
 
-    public static async ValueTask<int> ReadAsync(LuaState thread, FileHandle file, string name, int startArgumentIndex, ReadOnlyMemory<LuaValue> formats, bool throwError, CancellationToken cancellationToken)
+    public static async ValueTask<int> ReadAsync(LuaState state, FileHandle file, string name, int startArgumentIndex, ReadOnlyMemory<LuaValue> formats, bool throwError, CancellationToken cancellationToken)
     {
         if (formats.Length == 0)
         {
             formats = defaultReadFormat;
         }
 
-        var stack = thread.Stack;
+        var stack = state.Stack;
         var top = stack.Count;
 
         try
@@ -133,7 +133,7 @@ static class IOHelper
                 }
                 else
                 {
-                    LuaRuntimeException.BadArgument(thread, i + 1, ["string", "integer"], format.TypeToString());
+                    LuaRuntimeException.BadArgument(state, i + 1, ["string", "integer"], format.TypeToString());
                 }
             }
 

+ 2 - 2
src/Lua/Standard/Internal/MatchState.cs

@@ -2,7 +2,7 @@ using System.Buffers;
 
 namespace Lua.Standard.Internal;
 
-class MatchState(LuaState thread, string source, string pattern)
+class MatchState(LuaState state, string source, string pattern)
 {
     internal const int LuaMaxCaptures = 32;
     const int CapUnfinished = -1;
@@ -19,7 +19,7 @@ class MatchState(LuaState thread, string source, string pattern)
         public bool IsPosition => Len == CapPosition;
     }
 
-    public readonly LuaState State = thread;
+    public readonly LuaState State = state;
     public readonly string Source = source;
     public readonly string Pattern = pattern;
     public int Level = 0;

+ 24 - 26
src/Lua/Standard/ModuleLibrary.cs

@@ -30,15 +30,15 @@ public sealed class ModuleLibrary
             {
                 var module = await moduleLoader.LoadAsync(arg0, cancellationToken);
                 loader = module.Type == LuaModuleType.Bytes
-                    ? context.GlobalState.Load(module.ReadBytes(), module.Name)
-                    : context.GlobalState.Load(module.ReadText(), module.Name);
+                    ? context.State.Load(module.ReadBytes(), module.Name)
+                    : context.State.Load(module.ReadText(), module.Name);
             }
             else
             {
-                loader = await FindLoader(context.Access, arg0, cancellationToken);
+                loader = await FindLoader(context.State, arg0, cancellationToken);
             }
 
-            await context.Access.RunAsync(loader, 0, context.ReturnFrameBase, cancellationToken);
+            await context.State.RunAsync(loader, 0, context.ReturnFrameBase, cancellationToken);
             loadedTable = context.State.Stack.Get(context.ReturnFrameBase);
             loaded[arg0] = loadedTable;
         }
@@ -46,15 +46,14 @@ public sealed class ModuleLibrary
         return context.Return(loadedTable);
     }
 
-    internal static async ValueTask<string?> FindFile(LuaThreadAccess access, string name, string pName, string dirSeparator)
+    internal static async ValueTask<string?> FindFile(LuaState state, string name, string pName, string dirSeparator)
     {
-        var thread = access.State;
-        var state = thread.GlobalState;
-        var package = state.Environment["package"];
-        var p = await access.GetTable(package, pName);
+        var globalState = state.GlobalState;
+        var package = globalState.Environment["package"];
+        var p = await state.GetTable(package, pName);
         if (!p.TryReadString(out var path))
         {
-            throw new LuaRuntimeException(thread, $"package.{pName} must be a string");
+            throw new LuaRuntimeException(state, $"package.{pName} must be a string");
         }
 
         return SearchPath(state, name, path, ".", dirSeparator);
@@ -66,11 +65,11 @@ public sealed class ModuleLibrary
         var path = context.GetArgument<string>(1);
         var separator = context.GetArgument<string>(2);
         var dirSeparator = context.GetArgument<string>(3);
-        var fileName = SearchPath(context.GlobalState, name, path, separator, dirSeparator);
+        var fileName = SearchPath(context.State, name, path, separator, dirSeparator);
         return new(context.Return(fileName ?? LuaValue.Nil));
     }
 
-    internal static string? SearchPath(LuaGlobalState globalState, string name, string path, string separator, string dirSeparator)
+    internal static string? SearchPath(LuaState state, string name, string path, string separator, string dirSeparator)
     {
         if (separator != "")
         {
@@ -88,7 +87,7 @@ public sealed class ModuleLibrary
         {
             path = pathSpan[..nextIndex].ToString();
             var fileName = path.Replace("?", name);
-            if (globalState.FileSystem.IsReadable(fileName))
+            if (state.GlobalState.FileSystem.IsReadable(fileName))
             {
                 return fileName;
             }
@@ -109,10 +108,9 @@ public sealed class ModuleLibrary
         return null;
     }
 
-    internal static async ValueTask<LuaFunction> FindLoader(LuaThreadAccess access, string name, CancellationToken cancellationToken)
+    internal static async ValueTask<LuaFunction> FindLoader(LuaState state, string name, CancellationToken cancellationToken)
     {
-        var state = access.GlobalState;
-        var package = state.Environment["package"].Read<LuaTable>();
+        var package = state.GlobalState.Environment["package"].Read<LuaTable>();
         var searchers = package["searchers"].Read<LuaTable>();
         for (var i = 0; i < searchers.GetArraySpan().Length; i++)
         {
@@ -123,24 +121,24 @@ public sealed class ModuleLibrary
             }
 
             var loader = searcher;
-            var top = access.Stack.Count;
-            access.Stack.Push(loader);
-            access.Stack.Push(name);
-            var resultCount = await access.Call(top, top, cancellationToken);
+            var top = state.Stack.Count;
+            state.Stack.Push(loader);
+            state.Stack.Push(name);
+            var resultCount = await state.Call(top, top, cancellationToken);
             if (0 < resultCount)
             {
-                var result = access.Stack.Get(top);
+                var result = state.Stack.Get(top);
                 if (result.Type == LuaValueType.Function)
                 {
-                    access.Stack.SetTop(top);
+                    state.Stack.SetTop(top);
                     return result.Read<LuaFunction>();
                 }
             }
 
-            access.Stack.SetTop(top);
+            state.Stack.SetTop(top);
         }
 
-        throw new LuaRuntimeException(access.State, $"Module '{name}' not found");
+        throw new LuaRuntimeException(state, $"Module '{name}' not found");
     }
 
     public ValueTask<int> SearcherPreload(LuaFunctionExecutionContext context, CancellationToken cancellationToken)
@@ -158,12 +156,12 @@ public sealed class ModuleLibrary
     public async ValueTask<int> SearcherLua(LuaFunctionExecutionContext context, CancellationToken cancellationToken)
     {
         var name = context.GetArgument<string>(0);
-        var fileName = await FindFile(context.Access, name, "path", context.GlobalState.FileSystem.DirectorySeparator);
+        var fileName = await FindFile(context.State, name, "path", context.GlobalState.FileSystem.DirectorySeparator);
         if (fileName == null)
         {
             return context.Return(LuaValue.Nil);
         }
 
-        return context.Return(await context.GlobalState.LoadFileAsync(fileName, "bt", null, cancellationToken));
+        return context.Return(await context.State.LoadFileAsync(fileName, "bt", null, cancellationToken));
     }
 }

+ 59 - 0
src/Lua/Standard/OpenLibsExtensions.cs

@@ -145,6 +145,9 @@ public static class OpenLibsExtensions
         globalState.Environment["table"] = table;
         globalState.LoadedModules["table"] = table;
     }
+    
+    
+
 
     public static void OpenDebugLibrary(this LuaGlobalState globalState)
     {
@@ -158,6 +161,12 @@ public static class OpenLibsExtensions
         globalState.LoadedModules["debug"] = debug;
     }
 
+    public static void OpenDebugLibrary(this LuaState state)
+    {
+        state.GlobalState.OpenDebugLibrary();
+    }
+
+
     public static void OpenStandardLibraries(this LuaGlobalState globalState)
     {
         globalState.OpenBasicLibrary();
@@ -171,4 +180,54 @@ public static class OpenLibsExtensions
         globalState.OpenTableLibrary();
         globalState.OpenDebugLibrary();
     }
+
+    public static void OpenStandardLibraries(this LuaState state)
+    {
+        state.GlobalState.OpenStandardLibraries();
+    }
+
+    public static void OpenBasicLibrary(this LuaState state)
+    {
+        state.GlobalState.OpenBasicLibrary();
+    }
+
+    public static void OpenBitwiseLibrary(this LuaState state)
+    {
+        state.GlobalState.OpenBitwiseLibrary();
+    }
+
+    public static void OpenCoroutineLibrary(this LuaState state)
+    {
+        state.GlobalState.OpenCoroutineLibrary();
+    }
+
+    public static void OpenIOLibrary(this LuaState state)
+    {
+        state.GlobalState.OpenIOLibrary();
+    }
+
+    public static void OpenMathLibrary(this LuaState state)
+    {
+        state.GlobalState.OpenMathLibrary();
+    }
+
+    public static void OpenModuleLibrary(this LuaState state)
+    {
+        state.GlobalState.OpenModuleLibrary();
+    }
+
+    public static void OpenOperatingSystemLibrary(this LuaState state)
+    {
+        state.GlobalState.OpenOperatingSystemLibrary();
+    }
+
+    public static void OpenStringLibrary(this LuaState state)
+    {
+        state.GlobalState.OpenStringLibrary();
+    }
+
+    public static void OpenTableLibrary(this LuaState state)
+    {
+        state.GlobalState.OpenTableLibrary();
+    }
 }

+ 4 - 4
src/Lua/Standard/StringLibrary.cs

@@ -616,8 +616,8 @@ public sealed class StringLibrary
                     {
                         // No captures, pass whole match
                         stack.Push(s.AsSpan(sIdx, res - sIdx).ToString());
-                        var retCount = await context.Access.RunAsync(func, 1, cancellationToken);
-                        using var results = context.Access.ReadTopValues(retCount);
+                        var retCount = await context.State.RunAsync(func, 1, cancellationToken);
+                        using var results = context.State.ReadTopValues(retCount);
                         result = results.Count > 0 ? results[0] : LuaValue.Nil;
                     }
                     else
@@ -636,8 +636,8 @@ public sealed class StringLibrary
                             }
                         }
 
-                        var retCount = await context.Access.RunAsync(func, matchState.Level, cancellationToken);
-                        using var results = context.Access.ReadTopValues(retCount);
+                        var retCount = await context.State.RunAsync(func, matchState.Level, cancellationToken);
+                        using var results = context.State.ReadTopValues(retCount);
                         result = results.Count > 0 ? results[0] : LuaValue.Nil;
                     }
                 }

+ 5 - 5
src/Lua/Standard/TableLibrary.cs

@@ -183,23 +183,23 @@ public sealed class TableLibrary
     {
         var pivot = memory.Span[high];
         var i = low - 1;
-        var access = context.State.CurrentAccess;
+        var state = context.State;
 
         for (var j = low; j < high; j++)
         {
-            var stack = context.State.Stack;
+            var stack = state.Stack;
             var top = stack.Count;
             stack.Push(memory.Span[j]);
             stack.Push(pivot);
-            await access.RunAsync(comparer, 2, cancellationToken);
+            await state.RunAsync(comparer, 2, cancellationToken);
 
-            if (context.State.Stack.Get(top).ToBoolean())
+            if (state.Stack.Get(top).ToBoolean())
             {
                 i++;
                 Swap(memory.Span, i, j);
             }
 
-            context.State.Stack.PopUntil(top);
+            state.Stack.PopUntil(top);
         }
 
         Swap(memory.Span, i + 1, high);

+ 2 - 2
tests/Lua.Tests/AbstractFileTests.cs

@@ -30,7 +30,7 @@ public class AbstractFileTests
     {
         var fileContent = "line1\nline2\r\nline3";
         var fileSystem = new ReadOnlyFileSystem(new() { { "test.txt", fileContent } });
-        var state = LuaGlobalState.Create(new(
+        var state = LuaState.Create(new LuaPlatform(
             fileSystem: fileSystem,
             osEnvironment: null!,
             standardIO: new ConsoleStandardIO(),
@@ -64,7 +64,7 @@ public class AbstractFileTests
     {
         var fileContent = "Hello, World!";
         var fileSystem = new ReadOnlyFileSystem(new() { { "test.txt", fileContent } });
-        var state = LuaGlobalState.Create(new(
+        var state = LuaState.Create(new LuaPlatform(
             fileSystem: fileSystem,
             osEnvironment: null!,
             standardIO: new ConsoleStandardIO(),

+ 6 - 6
tests/Lua.Tests/AsyncTests.cs

@@ -4,15 +4,15 @@ namespace Lua.Tests;
 
 public class AsyncTests
 {
-    LuaGlobalState globalState = default!;
+    LuaState state = default!;
 
     [SetUp]
     public void SetUp()
     {
-        globalState = LuaGlobalState.Create();
-        globalState.OpenStandardLibraries();
-        var assert = globalState.Environment["assert"].Read<LuaFunction>();
-        globalState.Environment["assert"] = new LuaFunction("assert_with_wait",
+        state = LuaState.Create();
+        state.OpenStandardLibraries();
+        var assert = state.Environment["assert"].Read<LuaFunction>();
+        state.Environment["assert"] = new LuaFunction("assert_with_wait",
             async (context, ct) =>
             {
                 await Task.Delay(1, ct);
@@ -42,7 +42,7 @@ public class AsyncTests
         var path = FileHelper.GetAbsolutePath(file);
         try
         {
-            await globalState.DoFileAsync(path);
+            await state.DoFileAsync(path);
         }
         catch (LuaRuntimeException e)
         {

+ 12 - 12
tests/Lua.Tests/CancellationTest.cs

@@ -5,15 +5,15 @@ namespace Lua.Tests;
 
 public class CancellationTest
 {
-    LuaGlobalState globalState = default!;
+    LuaState state = default!;
 
     [SetUp]
     public void SetUp()
     {
-        globalState = LuaGlobalState.Create();
-        globalState.OpenStandardLibraries();
+        state = LuaState.Create();
+        state.OpenStandardLibraries();
 
-        globalState.Environment["assert"] = new LuaFunction("assert_with_wait",
+        state.Environment["assert"] = new LuaFunction("assert_with_wait",
             async (context, ct) =>
             {
                 await Task.Delay(1, ct);
@@ -32,14 +32,14 @@ public class CancellationTest
 
                 return context.Return(context.Arguments);
             });
-        globalState.Environment["sleep"] = new LuaFunction("sleep",
+        state.Environment["sleep"] = new LuaFunction("sleep",
             (context, _) =>
             {
                 Thread.Sleep(context.GetArgument<int>(0));
 
                 return new(context.Return());
             });
-        globalState.Environment["wait"] = new LuaFunction("wait",
+        state.Environment["wait"] = new LuaFunction("wait",
             async (context, ct) =>
             {
                 await Task.Delay(context.GetArgument<int>(0), ct);
@@ -61,7 +61,7 @@ public class CancellationTest
 
         try
         {
-            await globalState.DoStringAsync(source, "@test.lua", cancellationTokenSource.Token);
+            await state.DoStringAsync(source, "@test.lua", cancellationTokenSource.Token);
             Assert.Fail("Expected TaskCanceledException was not thrown.");
         }
         catch (Exception e)
@@ -90,7 +90,7 @@ public class CancellationTest
 
         try
         {
-            await globalState.DoStringAsync(source, "@test.lua", cancellationTokenSource.Token);
+            await state.DoStringAsync(source, "@test.lua", cancellationTokenSource.Token);
             Assert.Fail("Expected TaskCanceledException was not thrown.");
         }
         catch (Exception e)
@@ -123,7 +123,7 @@ public class CancellationTest
         });
         try
         {
-            var r = await globalState.DoStringAsync(source, "@test.lua", cancellationTokenSource.Token);
+            var r = await state.DoStringAsync(source, "@test.lua", cancellationTokenSource.Token);
             Console.WriteLine(r[0]);
             Assert.Fail("Expected TaskCanceledException was not thrown.");
         }
@@ -160,7 +160,7 @@ public class CancellationTest
         });
         try
         {
-            var r = await globalState.DoStringAsync(source, "@test.lua", cancellationTokenSource.Token);
+            var r = await state.DoStringAsync(source, "@test.lua", cancellationTokenSource.Token);
             Console.WriteLine(r[0]);
             Assert.Fail("Expected TaskCanceledException was not thrown.");
         }
@@ -191,7 +191,7 @@ public class CancellationTest
                      """;
         var cancellationTokenSource = new CancellationTokenSource();
         var sw = Stopwatch.StartNew();
-        globalState.MainThread.SetHook(new("timeout", async (context, cancellationToken) =>
+        state.SetHook(new("timeout", async (context, cancellationToken) =>
         {
             if (sw.ElapsedMilliseconds > 100)
             {
@@ -208,7 +208,7 @@ public class CancellationTest
         });
         try
         {
-            var r = await globalState.DoStringAsync(source, "@test.lua", cancellationTokenSource.Token);
+            var r = await state.DoStringAsync(source, "@test.lua", cancellationTokenSource.Token);
             Console.WriteLine(r[0]);
             Assert.Fail("Expected TaskCanceledException was not thrown.");
         }

+ 1 - 1
tests/Lua.Tests/ConditionalsTests.cs

@@ -12,7 +12,7 @@ end
 
 return clamp(0, 1, 25), clamp(10, 1, 25), clamp(30, 1, 25)
 ";
-        var result = await LuaGlobalState.Create().DoStringAsync(source);
+        var result = await LuaState.Create().DoStringAsync(source);
 
         Assert.That(result, Has.Length.EqualTo(3));
         Assert.That(result[0], Is.EqualTo(new LuaValue(1)));

+ 5 - 5
tests/Lua.Tests/LocalTests.cs

@@ -8,7 +8,7 @@ public class LocalTests
         var source = @"
 local function f(x) x = nil; return x end
 return f(10)";
-        var result = await LuaGlobalState.Create().DoStringAsync(source);
+        var result = await LuaState.Create().DoStringAsync(source);
 
         Assert.That(result, Has.Length.EqualTo(1));
         Assert.That(result[0], Is.EqualTo(LuaValue.Nil));
@@ -20,7 +20,7 @@ return f(10)";
         var source = @"
 local function f() local x; return x end
 return f(10)";
-        var result = await LuaGlobalState.Create().DoStringAsync(source);
+        var result = await LuaState.Create().DoStringAsync(source);
 
         Assert.That(result, Has.Length.EqualTo(1));
         Assert.That(result[0], Is.EqualTo(LuaValue.Nil));
@@ -32,7 +32,7 @@ return f(10)";
         var source = @"
 local function f(x) x = nil; local y; return x, y end
 return f(10)";
-        var result = await LuaGlobalState.Create().DoStringAsync(source);
+        var result = await LuaState.Create().DoStringAsync(source);
 
         Assert.That(result, Has.Length.EqualTo(2));
         Assert.Multiple(() =>
@@ -46,7 +46,7 @@ return f(10)";
     public async Task Test_LocalVariable_1()
     {
         var source = "local i = 10; do local i = 100; return i end";
-        var result = await LuaGlobalState.Create().DoStringAsync(source);
+        var result = await LuaState.Create().DoStringAsync(source);
 
         Assert.That(result, Has.Length.EqualTo(1));
         Assert.That(result[0], Is.EqualTo(new LuaValue(100)));
@@ -59,7 +59,7 @@ return f(10)";
 local i = 10
 do local i = 100 end
 return i";
-        var result = await LuaGlobalState.Create().DoStringAsync(source);
+        var result = await LuaState.Create().DoStringAsync(source);
 
         Assert.That(result, Has.Length.EqualTo(1));
         Assert.That(result[0], Is.EqualTo(new LuaValue(10)));

+ 3 - 3
tests/Lua.Tests/LoopTests.cs

@@ -11,7 +11,7 @@ for i = 1, 10 do
     n = n + i
 end
 return n";
-        var result = await LuaGlobalState.Create().DoStringAsync(source);
+        var result = await LuaState.Create().DoStringAsync(source);
 
         Assert.That(result, Has.Length.EqualTo(1));
         Assert.That(result[0], Is.EqualTo(new LuaValue(55)));
@@ -26,7 +26,7 @@ for i = 0, 10, 2 do
     n = n + i
 end
 return n";
-        var result = await LuaGlobalState.Create().DoStringAsync(source);
+        var result = await LuaState.Create().DoStringAsync(source);
 
         Assert.That(result, Has.Length.EqualTo(1));
         Assert.That(result[0], Is.EqualTo(new LuaValue(30)));
@@ -41,7 +41,7 @@ while n < 100 do
     n = n + 1
 end
 return n";
-        var result = await LuaGlobalState.Create().DoStringAsync(source);
+        var result = await LuaState.Create().DoStringAsync(source);
 
         Assert.That(result, Has.Length.EqualTo(1));
         Assert.That(result[0], Is.EqualTo(new LuaValue(100)));

+ 28 - 36
tests/Lua.Tests/LuaApiTests.cs

@@ -5,13 +5,13 @@ namespace Lua.Tests;
 
 public class LuaApiTests
 {
-    LuaGlobalState globalState = default!;
+    LuaState state = default!;
 
     [OneTimeSetUp]
     public void SetUp()
     {
-        globalState = LuaGlobalState.Create();
-        globalState.OpenStandardLibraries();
+        state = LuaState.Create();
+        state.OpenStandardLibraries();
     }
 
     [Test]
@@ -34,12 +34,11 @@ public class LuaApiTests
                      setmetatable(a, metatable)
                      return a, b
                      """;
-        var access = globalState.RootAccess;
-        var result = await access.DoStringAsync(source);
+        var result = await state.DoStringAsync(source);
         var a = result[0].Read<LuaTable>();
         var b = result[1].Read<LuaTable>();
 
-        var c = await access.Add(a, b);
+        var c = await state.Add(a, b);
         var table = c.Read<LuaTable>();
         Assert.Multiple(() =>
         {
@@ -68,11 +67,10 @@ public class LuaApiTests
                      setmetatable(a, metatable)
                      return a
                      """;
-        var access = globalState.RootAccess;
 
-        var result = await access.DoStringAsync(source);
+        var result = await state.DoStringAsync(source);
         var a = result[0].Read<LuaTable>();
-        var c = await access.Unm(a);
+        var c = await state.Unm(a);
         var table = c.Read<LuaTable>();
         Assert.Multiple(() =>
         {
@@ -106,14 +104,13 @@ public class LuaApiTests
                      setmetatable(a, metatable)
                      return a, b, c
                      """;
-        var access = globalState.RootAccess;
-        var result = await access.DoStringAsync(source);
+        var result = await state.DoStringAsync(source);
         var a = result[0].Read<LuaTable>();
         var b = result[1].Read<LuaTable>();
         var c = result[2].Read<LuaTable>();
-        var ab = await access.Equals(a, b);
+        var ab = await state.Equals(a, b);
         Assert.False(ab);
-        var ac = await access.Equals(a, c);
+        var ac = await state.Equals(a, c);
         Assert.True(ac);
     }
 
@@ -129,12 +126,11 @@ public class LuaApiTests
                      setmetatable(a, metatable)
                      return a
                      """;
-        var access = globalState.RootAccess;
-        var result = await access.DoStringAsync(source);
+        var result = await state.DoStringAsync(source);
         var a = result[0].Read<LuaTable>();
-        Assert.That(await access.GetTable(a, "x"), Is.EqualTo(new LuaValue(1)));
-        a.Metatable!["__index"] = globalState.DoStringAsync("return function(a,b) return b end").Result[0];
-        Assert.That(await access.GetTable(a, "x"), Is.EqualTo(new LuaValue("x")));
+        Assert.That(await state.GetTable(a, "x"), Is.EqualTo(new LuaValue(1)));
+        a.Metatable!["__index"] = state.DoStringAsync("return function(a,b) return b end").Result[0];
+        Assert.That(await state.GetTable(a, "x"), Is.EqualTo(new LuaValue("x")));
     }
 
     [Test]
@@ -150,10 +146,9 @@ public class LuaApiTests
                      setmetatable(a, metatable)
                      return a
                      """;
-        var access = globalState.RootAccess;
-        var result = await access.DoStringAsync(source);
+        var result = await state.DoStringAsync(source);
         var a = result[0].Read<LuaTable>();
-        await access.SetTable(a, "a", "b");
+        await state.SetTable(a, "a", "b");
         var b = a.Metatable!["__newindex"].Read<LuaTable>()["a"];
         Assert.True(b.Read<string>() == "b");
     }
@@ -183,14 +178,13 @@ setmetatable(c, metatable)
 
 return a,b,c
 ";
-        var access = globalState.RootAccess;
-        var result = await access.DoStringAsync(source);
+        var result = await state.DoStringAsync(source);
         Assert.That(result, Has.Length.EqualTo(3));
 
         var a = result[0];
         var b = result[1];
         var c = result[2];
-        var d = await access.Concat([a, b, c]);
+        var d = await state.Concat([a, b, c]);
 
         var table = d.Read<LuaTable>();
         Assert.That(table.ArrayLength, Is.EqualTo(9));
@@ -229,22 +223,21 @@ return a,b,c
                      local c ={name ="c"}
                      return a,b,c
                      """;
-        var access = globalState.RootAccess;
-        var result = await access.DoStringAsync(source);
+        var result = await state.DoStringAsync(source);
         var a = result[0];
         var b = result[1];
         var c = result[2];
-        var d = await access.Add(b, c);
+        var d = await state.Add(b, c);
         Assert.True(d.TryRead(out string s));
         Assert.That(s, Is.EqualTo("abc"));
-        d = await access.Unm(b);
+        d = await state.Unm(b);
         Assert.True(d.TryRead(out s));
         Assert.That(s, Is.EqualTo("abb"));
-        d = await access.Concat([c, b]);
+        d = await state.Concat([c, b]);
         Assert.True(d.TryRead(out s));
         Assert.That(s, Is.EqualTo("acb"));
 
-        var aResult = await access.Call(a, [b, c]);
+        var aResult = await state.Call(a, [b, c]);
         Assert.That(aResult, Has.Length.EqualTo(1));
         Assert.That(aResult[0].Read<string>(), Is.EqualTo("abc"));
     }
@@ -272,22 +265,21 @@ return a,b,c
                      local c ={name ="c"}
                      return a,b,c
                      """;
-        var access = globalState.RootAccess;
-        var result = await access.DoStringAsync(source);
+        var result = await state.DoStringAsync(source);
         var a = result[0];
         var b = result[1];
         var c = result[2];
-        var d = await access.Add(b, c);
+        var d = await state.Add(b, c);
         Assert.True(d.TryRead(out string s));
         Assert.That(s, Is.EqualTo("abc"));
-        d = await access.Unm(b);
+        d = await state.Unm(b);
         Assert.True(d.TryRead(out s));
         Assert.That(s, Is.EqualTo("abb"));
-        d = await access.Concat([c, b]);
+        d = await state.Concat([c, b]);
         Assert.True(d.TryRead(out s));
         Assert.That(s, Is.EqualTo("acb"));
 
-        var aResult = await access.Call(a, [b, c]);
+        var aResult = await state.Call(a, [b, c]);
         Assert.That(aResult, Has.Length.EqualTo(1));
         Assert.That(aResult[0].Read<string>(), Is.EqualTo("abc"));
     }

+ 8 - 8
tests/Lua.Tests/LuaObjectTests.cs

@@ -60,7 +60,7 @@ public class LuaObjectTests
     {
         var userData = new TestUserData { Property = 1 };
 
-        var state = LuaGlobalState.Create();
+        var state = LuaState.Create();
         state.Environment["test"] = userData;
         var results = await state.DoStringAsync("return test.Property");
 
@@ -73,7 +73,7 @@ public class LuaObjectTests
     {
         var userData = new TestUserData { PropertyWithName = "foo" };
 
-        var state = LuaGlobalState.Create();
+        var state = LuaState.Create();
         state.Environment["test"] = userData;
         var results = await state.DoStringAsync("return test.p2");
 
@@ -86,7 +86,7 @@ public class LuaObjectTests
     {
         var userData = new TestUserData();
 
-        var state = LuaGlobalState.Create();
+        var state = LuaState.Create();
         state.Environment["test"] = userData;
         var results = await state.DoStringAsync("return test.MethodVoid()");
 
@@ -98,7 +98,7 @@ public class LuaObjectTests
     {
         var userData = new TestUserData();
 
-        var state = LuaGlobalState.Create();
+        var state = LuaState.Create();
         state.Environment["test"] = userData;
         var results = await state.DoStringAsync("return test.MethodAsync()");
 
@@ -110,7 +110,7 @@ public class LuaObjectTests
     {
         var userData = new TestUserData();
 
-        var state = LuaGlobalState.Create();
+        var state = LuaState.Create();
         state.Environment["test"] = userData;
         var results = await state.DoStringAsync("return test.StaticMethodWithReturnValue(1, 2)");
 
@@ -123,7 +123,7 @@ public class LuaObjectTests
     {
         var userData = new TestUserData { Property = 1 };
 
-        var state = LuaGlobalState.Create();
+        var state = LuaState.Create();
         state.Environment["test"] = userData;
         var results = await state.DoStringAsync("return test:InstanceMethodWithReturnValue()");
 
@@ -136,7 +136,7 @@ public class LuaObjectTests
     {
         var userData = new TestUserData { Property = 1 };
 
-        var state = LuaGlobalState.Create();
+        var state = LuaState.Create();
         state.Environment["test"] = userData;
         var results = await state.DoStringAsync("return test:InstanceMethodWithReturnValueAsync(2)");
 
@@ -149,7 +149,7 @@ public class LuaObjectTests
     {
         var userData = new TestUserData();
 
-        var state = LuaGlobalState.Create();
+        var state = LuaState.Create();
         state.OpenBasicLibrary();
         state.Environment["test"] = userData;
         var results = await state.DoStringAsync("""

+ 1 - 1
tests/Lua.Tests/LuaTests.cs

@@ -29,7 +29,7 @@ public class LuaTests
     [TestCase("tests-lua/verybig.lua")]
     public async Task Test_Lua(string file)
     {
-        var state = LuaGlobalState.Create();
+        var state = LuaState.Create();
         state.Platform.StandardIO = new TestStandardIO();
         state.OpenStandardLibraries();
         var path = FileHelper.GetAbsolutePath(file);

+ 11 - 11
tests/Lua.Tests/MetatableTests.cs

@@ -4,13 +4,13 @@ namespace Lua.Tests;
 
 public class MetatableTests
 {
-    LuaGlobalState globalState = default!;
+    LuaState state = default!;
 
     [OneTimeSetUp]
     public void SetUp()
     {
-        globalState = LuaGlobalState.Create();
-        globalState.OpenStandardLibraries();
+        state = LuaState.Create();
+        state.OpenStandardLibraries();
     }
 
     [Test]
@@ -35,7 +35,7 @@ setmetatable(a, metatable)
 return a + b
 ";
 
-        var result = await globalState.DoStringAsync(source);
+        var result = await state.DoStringAsync(source);
         Assert.That(result, Has.Length.EqualTo(1));
 
         var table = result[0].Read<LuaTable>();
@@ -69,7 +69,7 @@ setmetatable(a, metatable)
 return a .. b
 ";
 
-        var result = await globalState.DoStringAsync(source);
+        var result = await state.DoStringAsync(source);
         Assert.That(result, Has.Length.EqualTo(1));
 
         var table = result[0].Read<LuaTable>();
@@ -97,7 +97,7 @@ assert(a.x == nil)
 metatable.__index= function(a,b) return b end
 assert(a.x == 'x')
 ";
-        await globalState.DoStringAsync(source);
+        await state.DoStringAsync(source);
     }
 
     [Test]
@@ -118,7 +118,7 @@ a.x = 2
 assert(a.x == nil)
 assert(metatable.__newindex.x == 2)
 ";
-        await globalState.DoStringAsync(source);
+        await state.DoStringAsync(source);
     }
 
     [Test]
@@ -141,7 +141,7 @@ end
 tail(a, 3)
 assert(tail(a, 3) == 4)
 ";
-        await globalState.DoStringAsync(source);
+        await state.DoStringAsync(source);
     }
 
     [Test]
@@ -169,7 +169,7 @@ t =setmetatable({},{__call = a})
 for i in t do 
 end
 ";
-        await globalState.DoStringAsync(source);
+        await state.DoStringAsync(source);
     }
 
     [Test]
@@ -184,7 +184,7 @@ end
                      debug.sethook()
                      return t
                      """;
-        var r = await globalState.DoStringAsync(source);
+        var r = await state.DoStringAsync(source);
         Assert.That(r, Has.Length.EqualTo(1));
         Assert.That(r[0].Read<LuaTable>()[1].Read<string>(), Does.Contain("stack traceback:"));
     }
@@ -211,6 +211,6 @@ end
                      assert((b + c)== "abc")
                      assert((b .. c)== "abc")
                      """;
-        await globalState.DoStringAsync(source);
+        await state.DoStringAsync(source);
     }
 }

+ 12 - 12
tests/Lua.Tests/OperatorTests.cs

@@ -9,7 +9,7 @@ public class OperatorTests
     [TestCase(5, 10)]
     public async Task Test_Add(double a, double b)
     {
-        var result = await LuaGlobalState.Create().DoStringAsync($"return {a} + {b}");
+        var result = await LuaState.Create().DoStringAsync($"return {a} + {b}");
         Assert.That(result, Has.Length.EqualTo(1));
         Assert.That(result[0], Is.EqualTo(new LuaValue(a + b)));
     }
@@ -21,7 +21,7 @@ public class OperatorTests
     [TestCase(5, 10)]
     public async Task Test_Sub(double a, double b)
     {
-        var result = await LuaGlobalState.Create().DoStringAsync($"return {a} - {b}");
+        var result = await LuaState.Create().DoStringAsync($"return {a} - {b}");
         Assert.That(result, Has.Length.EqualTo(1));
         Assert.That(result[0], Is.EqualTo(new LuaValue(a - b)));
     }
@@ -33,7 +33,7 @@ public class OperatorTests
     [TestCase(5, 10)]
     public async Task Test_Mul(double a, double b)
     {
-        var result = await LuaGlobalState.Create().DoStringAsync($"return {a} * {b}");
+        var result = await LuaState.Create().DoStringAsync($"return {a} * {b}");
         Assert.That(result, Has.Length.EqualTo(1));
         Assert.That(result[0], Is.EqualTo(new LuaValue(a * b)));
     }
@@ -45,7 +45,7 @@ public class OperatorTests
     [TestCase(5, 10)]
     public async Task Test_Div(double a, double b)
     {
-        var result = await LuaGlobalState.Create().DoStringAsync($"return {a} / {b}");
+        var result = await LuaState.Create().DoStringAsync($"return {a} / {b}");
         Assert.That(result, Has.Length.EqualTo(1));
         Assert.That(result[0], Is.EqualTo(new LuaValue(a / b)));
     }
@@ -57,7 +57,7 @@ public class OperatorTests
     [TestCase(5, 10)]
     public async Task Test_Mod(double a, double b)
     {
-        var result = await LuaGlobalState.Create().DoStringAsync($"return {a} % {b}");
+        var result = await LuaState.Create().DoStringAsync($"return {a} % {b}");
         Assert.That(result, Has.Length.EqualTo(1));
         Assert.That(result[0], Is.EqualTo(new LuaValue(a % b)));
     }
@@ -69,7 +69,7 @@ public class OperatorTests
     [TestCase(5, 10)]
     public async Task Test_Pow(double a, double b)
     {
-        var result = await LuaGlobalState.Create().DoStringAsync($"return {a} ^ {b}");
+        var result = await LuaState.Create().DoStringAsync($"return {a} ^ {b}");
         Assert.That(result, Has.Length.EqualTo(1));
         Assert.That(result[0], Is.EqualTo(new LuaValue(Math.Pow(a, b))));
     }
@@ -81,7 +81,7 @@ public class OperatorTests
     public async Task Test_Or(bool a, bool b)
     {
         string strA = a.ToString().ToLower(), strB = b.ToString().ToLower();
-        var result = await LuaGlobalState.Create().DoStringAsync($"return {strA} or {strB}");
+        var result = await LuaState.Create().DoStringAsync($"return {strA} or {strB}");
         Assert.That(result, Has.Length.EqualTo(1));
         Assert.That(result[0], Is.EqualTo(new LuaValue(a || b)));
     }
@@ -93,7 +93,7 @@ public class OperatorTests
     public async Task Test_And(bool a, bool b)
     {
         string strA = a.ToString().ToLower(), strB = b.ToString().ToLower();
-        var result = await LuaGlobalState.Create().DoStringAsync($"return {strA} and {strB}");
+        var result = await LuaState.Create().DoStringAsync($"return {strA} and {strB}");
         Assert.That(result, Has.Length.EqualTo(1));
         Assert.That(result[0], Is.EqualTo(new LuaValue(a && b)));
     }
@@ -103,7 +103,7 @@ public class OperatorTests
     [TestCase(5, 5)]
     public async Task Test_LessThan(double a, double b)
     {
-        var result = await LuaGlobalState.Create().DoStringAsync($"return {a} < {b}");
+        var result = await LuaState.Create().DoStringAsync($"return {a} < {b}");
         Assert.That(result, Has.Length.EqualTo(1));
         Assert.That(result[0], Is.EqualTo(new LuaValue(a < b)));
     }
@@ -113,7 +113,7 @@ public class OperatorTests
     [TestCase(5, 5)]
     public async Task Test_LessThanOrEquals(double a, double b)
     {
-        var result = await LuaGlobalState.Create().DoStringAsync($"return {a} <= {b}");
+        var result = await LuaState.Create().DoStringAsync($"return {a} <= {b}");
         Assert.That(result, Has.Length.EqualTo(1));
         Assert.That(result[0], Is.EqualTo(new LuaValue(a <= b)));
     }
@@ -123,7 +123,7 @@ public class OperatorTests
     [TestCase(5, 5)]
     public async Task Test_GreaterThan(double a, double b)
     {
-        var result = await LuaGlobalState.Create().DoStringAsync($"return {a} > {b}");
+        var result = await LuaState.Create().DoStringAsync($"return {a} > {b}");
         Assert.That(result, Has.Length.EqualTo(1));
         Assert.That(result[0], Is.EqualTo(new LuaValue(a > b)));
     }
@@ -133,7 +133,7 @@ public class OperatorTests
     [TestCase(5, 5)]
     public async Task Test_GreaterThanOrEquals(double a, double b)
     {
-        var result = await LuaGlobalState.Create().DoStringAsync($"return {a} >= {b}");
+        var result = await LuaState.Create().DoStringAsync($"return {a} >= {b}");
         Assert.That(result, Has.Length.EqualTo(1));
         Assert.That(result[0], Is.EqualTo(new LuaValue(a >= b)));
     }

+ 36 - 36
tests/Lua.Tests/PatternMatchingTests.cs

@@ -7,7 +7,7 @@ public class PatternMatchingTests
     [Test]
     public async Task Test_StringMatch_BasicPatterns()
     {
-        var state = LuaGlobalState.Create();
+        var state = LuaState.Create();
         state.OpenStringLibrary();
 
         // Literal match
@@ -25,7 +25,7 @@ public class PatternMatchingTests
     [Test]
     public async Task Test_StringMatch_CharacterClasses()
     {
-        var state = LuaGlobalState.Create();
+        var state = LuaState.Create();
         state.OpenStringLibrary();
 
         // %d - digits
@@ -51,7 +51,7 @@ public class PatternMatchingTests
     [Test]
     public async Task Test_StringMatch_Quantifiers()
     {
-        var state = LuaGlobalState.Create();
+        var state = LuaState.Create();
         state.OpenStringLibrary();
 
         // + (one or more)
@@ -80,7 +80,7 @@ public class PatternMatchingTests
     [Test]
     public async Task Test_StringMatch_Captures()
     {
-        var state = LuaGlobalState.Create();
+        var state = LuaState.Create();
         state.OpenStringLibrary();
 
         // Single capture
@@ -108,7 +108,7 @@ public class PatternMatchingTests
     [Test]
     public async Task Test_StringMatch_Anchors()
     {
-        var state = LuaGlobalState.Create();
+        var state = LuaState.Create();
         state.OpenStringLibrary();
 
         // ^ (start anchor)
@@ -129,7 +129,7 @@ public class PatternMatchingTests
     [Test]
     public async Task Test_StringMatch_WithInitPosition()
     {
-        var state = LuaGlobalState.Create();
+        var state = LuaState.Create();
         state.OpenStringLibrary();
 
         // Start from specific position
@@ -147,7 +147,7 @@ public class PatternMatchingTests
     [Test]
     public async Task Test_StringMatch_SpecialPatterns()
     {
-        var state = LuaGlobalState.Create();
+        var state = LuaState.Create();
         state.OpenStringLibrary();
 
         // Dot (any character)
@@ -169,7 +169,7 @@ public class PatternMatchingTests
     [Test]
     public async Task Test_StringFind_BasicUsage()
     {
-        var state = LuaGlobalState.Create();
+        var state = LuaState.Create();
         state.OpenStringLibrary();
 
         // Basic literal search
@@ -193,7 +193,7 @@ public class PatternMatchingTests
     [Test]
     public async Task Test_StringFind_WithPatterns()
     {
-        var state = LuaGlobalState.Create();
+        var state = LuaState.Create();
         state.OpenStringLibrary();
 
         // Pattern with captures
@@ -224,7 +224,7 @@ public class PatternMatchingTests
     [Test]
     public async Task Test_StringFind_PlainSearch()
     {
-        var state = LuaGlobalState.Create();
+        var state = LuaState.Create();
         state.OpenStringLibrary();
 
         // Plain search (4th parameter = true)
@@ -243,7 +243,7 @@ public class PatternMatchingTests
     [Test]
     public async Task Test_StringFind_EdgeCases()
     {
-        var state = LuaGlobalState.Create();
+        var state = LuaState.Create();
         state.OpenStringLibrary();
 
         // Empty pattern
@@ -287,7 +287,7 @@ public class PatternMatchingTests
     [Test]
     public async Task Test_StringGMatch_BasicUsage()
     {
-        var state = LuaGlobalState.Create();
+        var state = LuaState.Create();
         state.OpenStringLibrary();
         state.OpenTableLibrary();
         // Test basic gmatch iteration
@@ -307,7 +307,7 @@ public class PatternMatchingTests
     [Test]
     public async Task Test_StringGMatch_WithCaptures()
     {
-        var state = LuaGlobalState.Create();
+        var state = LuaState.Create();
         state.OpenStringLibrary();
         state.OpenTableLibrary();
 
@@ -328,7 +328,7 @@ public class PatternMatchingTests
     [Test]
     public async Task Test_StringGMatch_Numbers()
     {
-        var state = LuaGlobalState.Create();
+        var state = LuaState.Create();
         state.OpenStringLibrary();
         state.OpenTableLibrary();
 
@@ -349,7 +349,7 @@ public class PatternMatchingTests
     [Test]
     public async Task Test_StringGMatch_EmptyMatches()
     {
-        var state = LuaGlobalState.Create();
+        var state = LuaState.Create();
         state.OpenStringLibrary();
         state.OpenTableLibrary();
 
@@ -368,7 +368,7 @@ public class PatternMatchingTests
     [Test]
     public async Task Test_StringGMatch_ComplexPatterns()
     {
-        var state = LuaGlobalState.Create();
+        var state = LuaState.Create();
         state.OpenStringLibrary();
         state.OpenTableLibrary();
 
@@ -389,7 +389,7 @@ public class PatternMatchingTests
     [Test]
     public async Task Test_StringGMatch_PositionCaptures()
     {
-        var state = LuaGlobalState.Create();
+        var state = LuaState.Create();
         state.OpenStringLibrary();
         state.OpenTableLibrary();
 
@@ -412,7 +412,7 @@ public class PatternMatchingTests
     [Test]
     public async Task Test_StringGMatch_NoMatches()
     {
-        var state = LuaGlobalState.Create();
+        var state = LuaState.Create();
         state.OpenStringLibrary();
         state.OpenTableLibrary();
 
@@ -430,7 +430,7 @@ public class PatternMatchingTests
     [Test]
     public async Task Test_StringGMatch_SingleCharacter()
     {
-        var state = LuaGlobalState.Create();
+        var state = LuaState.Create();
         state.OpenStringLibrary();
         state.OpenTableLibrary();
 
@@ -451,7 +451,7 @@ public class PatternMatchingTests
     [Test]
     public async Task Test_StringFind_And_GMatch_Consistency()
     {
-        var state = LuaGlobalState.Create();
+        var state = LuaState.Create();
         state.OpenStringLibrary();
 
         // Test that find and gmatch work consistently with the same pattern
@@ -476,7 +476,7 @@ public class PatternMatchingTests
     [Test]
     public async Task Test_Pattern_NegatedCharacterClassWithCapture()
     {
-        var state = LuaGlobalState.Create();
+        var state = LuaState.Create();
         state.OpenStringLibrary();
 
         // Test the problematic pattern ^([^:]*):
@@ -514,7 +514,7 @@ public class PatternMatchingTests
     [Test]
     public async Task Test_StringGSub_BasicReplacements()
     {
-        var state = LuaGlobalState.Create();
+        var state = LuaState.Create();
         state.OpenStringLibrary();
 
         // Simple string replacement
@@ -539,7 +539,7 @@ public class PatternMatchingTests
     [Test]
     public async Task Test_StringGSub_PatternReplacements()
     {
-        var state = LuaGlobalState.Create();
+        var state = LuaState.Create();
         state.OpenStringLibrary();
 
         // Character class patterns
@@ -564,7 +564,7 @@ public class PatternMatchingTests
     [Test]
     public async Task Test_StringGSub_FunctionReplacements()
     {
-        var state = LuaGlobalState.Create();
+        var state = LuaState.Create();
         state.OpenStringLibrary();
 
         // Function replacement
@@ -602,7 +602,7 @@ public class PatternMatchingTests
     [Test]
     public async Task Test_StringGSub_TableReplacements()
     {
-        var state = LuaGlobalState.Create();
+        var state = LuaState.Create();
         state.OpenStringLibrary();
 
         // Table replacement
@@ -627,7 +627,7 @@ public class PatternMatchingTests
     [Test]
     public async Task Test_StringGSub_EmptyPattern()
     {
-        var state = LuaGlobalState.Create();
+        var state = LuaState.Create();
         state.OpenStringLibrary();
 
         // Empty pattern should match at every position
@@ -640,7 +640,7 @@ public class PatternMatchingTests
     [Test]
     public async Task Test_StringGSub_BalancedPatterns()
     {
-        var state = LuaGlobalState.Create();
+        var state = LuaState.Create();
         state.OpenStringLibrary();
 
         // Balanced parentheses pattern
@@ -663,7 +663,7 @@ public class PatternMatchingTests
     [Test]
     public async Task Test_StringGSub_EscapeSequences()
     {
-        var state = LuaGlobalState.Create();
+        var state = LuaState.Create();
         state.OpenStringLibrary();
 
         // Test %% escape (literal %)
@@ -676,7 +676,7 @@ public class PatternMatchingTests
     [Test]
     public async Task Test_StringGSub_EdgeCases()
     {
-        var state = LuaGlobalState.Create();
+        var state = LuaState.Create();
         state.OpenStringLibrary();
 
         // Empty string
@@ -701,7 +701,7 @@ public class PatternMatchingTests
     [Test]
     public async Task Test_StringGSub_ComplexPatterns()
     {
-        var state = LuaGlobalState.Create();
+        var state = LuaState.Create();
         state.OpenStringLibrary();
 
         // Email replacement
@@ -728,7 +728,7 @@ public class PatternMatchingTests
     [Test]
     public async Task Test_PatternMatching_Consistency()
     {
-        var state = LuaGlobalState.Create();
+        var state = LuaState.Create();
         state.OpenStringLibrary();
 
         // Test that all string functions work consistently with same patterns
@@ -766,7 +766,7 @@ public class PatternMatchingTests
     [Test]
     public async Task Test_PatternMatching_SpecialPatterns()
     {
-        var state = LuaGlobalState.Create();
+        var state = LuaState.Create();
         state.OpenStringLibrary();
 
         // Frontier pattern %f
@@ -791,7 +791,7 @@ public class PatternMatchingTests
     [Test]
     public void Test_PatternMatching_ErrorCases()
     {
-        var state = LuaGlobalState.Create();
+        var state = LuaState.Create();
         state.OpenStringLibrary();
 
         // Invalid pattern - missing closing bracket
@@ -813,7 +813,7 @@ public class PatternMatchingTests
     [Test]
     public async Task Test_DollarSignPattern_EscapingIssue()
     {
-        var state = LuaGlobalState.Create();
+        var state = LuaState.Create();
         state.OpenStringLibrary();
         state.OpenTableLibrary();
 
@@ -855,7 +855,7 @@ public class PatternMatchingTests
     [Test]
     public async Task Test_DollarSignPattern_CompleteExample()
     {
-        var state = LuaGlobalState.Create();
+        var state = LuaState.Create();
         state.OpenStringLibrary();
         state.OpenTableLibrary();
         state.OpenBasicLibrary();
@@ -902,7 +902,7 @@ public class PatternMatchingTests
     [Test]
     public async Task Test_DollarSignPattern_EdgeCases()
     {
-        var state = LuaGlobalState.Create();
+        var state = LuaState.Create();
         state.OpenStringLibrary();
         state.OpenTableLibrary();
 

+ 2 - 2
tests/Lua.Tests/StringTests.cs

@@ -10,7 +10,7 @@ public class StringTests
     [TestCase("\r\n")]
     public async Task Test_ShortString_RealNewLine(string newLine)
     {
-        var result = await LuaGlobalState.Create().DoStringAsync($"return \"\\{newLine}\"");
+        var result = await LuaState.Create().DoStringAsync($"return \"\\{newLine}\"");
         Assert.That(result, Has.Length.EqualTo(1));
         Assert.That(result[0], Is.EqualTo(new LuaValue("\n")));
     }
@@ -18,7 +18,7 @@ public class StringTests
     [TestCase("fr-FR")]
     public async Task Test_StringFormat_Culture(string newLine)
     {
-        var state = LuaGlobalState.Create();
+        var state = LuaState.Create();
         state.OpenBasicLibrary();
         state.OpenStringLibrary();
         var culture = CultureInfo.CurrentCulture;

+ 0 - 55
tests/Lua.Tests/ValidationTests.cs

@@ -1,55 +0,0 @@
-using Lua.Runtime;
-using Lua.Standard;
-
-namespace Lua.Tests;
-
-public class ValidationTests
-{
-    [Test]
-    public async Task Test_Simple()
-    {
-        var state = LuaGlobalState.Create();
-        state.OpenStandardLibraries();
-        LuaThreadAccess innerAccess = default!;
-        state.Environment["wait"] = new LuaFunction("wait",
-            async (context, ct) =>
-            {
-                innerAccess = context.Access;
-                await Task.Delay((int)(context.GetArgument<double>(0) * 1000), ct);
-                return context.Return(context.Arguments);
-            });
-
-        var task = state.DoStringAsync("wait(0.5)");
-
-        await Task.Delay(100);
-        Assert.That(task.IsCompleted, Is.False);
-        Assert.ThrowsAsync<InvalidOperationException>(async () =>
-        {
-            await state.DoStringAsync("print('hello')");
-        });
-        await task;
-
-        Assert.ThrowsAsync<InvalidOperationException>(async () =>
-        {
-            await innerAccess.DoStringAsync("print('hello')");
-        });
-        Assert.DoesNotThrowAsync(async () =>
-        {
-            await state.DoStringAsync("wait(0.5)");
-        });
-    }
-
-    [Test]
-    public async Task Test_Recursive()
-    {
-        var state = LuaGlobalState.Create();
-        state.OpenStandardLibraries();
-        state.Environment["dostring"] = new LuaFunction("dostring",
-            async (context, ct) => context.Return(await context.Access.DoStringAsync(context.GetArgument<string>(0), null, ct)));
-
-        var result = await state.DoStringAsync("""return dostring("return 1")""");
-
-        Assert.That(result.Length, Is.EqualTo(1));
-        Assert.That(result[0].Read<double>(), Is.EqualTo(1));
-    }
-}

Some files were not shown because too many files changed in this diff