Browse Source

Change: Return values on LuaStack

Akeit0 7 months ago
parent
commit
5210c37ad1
41 changed files with 1055 additions and 1476 deletions
  1. 4 3
      sandbox/Benchmark/AddBenchmark.cs
  2. 3 1
      sandbox/Benchmark/InterpreterSteps.cs
  3. 3 4
      sandbox/ConsoleApp1/Program.cs
  4. 16 14
      src/Lua.SourceGenerator/LuaObjectGenerator.Emit.cs
  5. 16 79
      src/Lua/CodeAnalysis/Compilation/LuaCompiler.cs
  6. 1 1
      src/Lua/CodeAnalysis/Syntax/Nodes/BooleanLiteralNode.cs
  7. 1 1
      src/Lua/Internal/BitFlags.cs
  8. 2 1
      src/Lua/Internal/BitFlags256.cs
  9. 26 0
      src/Lua/Internal/LuaResult.cs
  10. 17 45
      src/Lua/LuaCoroutine.cs
  11. 7 16
      src/Lua/LuaFunction.cs
  12. 62 0
      src/Lua/LuaFunctionExecutionContext.cs
  13. 6 6
      src/Lua/LuaFunctionExtensions.cs
  14. 4 6
      src/Lua/LuaMainThread.cs
  15. 18 33
      src/Lua/LuaState.cs
  16. 18 25
      src/Lua/LuaStateExtensions.cs
  17. 5 5
      src/Lua/LuaThread.cs
  18. 14 12
      src/Lua/LuaThreadExtensions.cs
  19. 6 9
      src/Lua/LuaValue.cs
  20. 2 2
      src/Lua/Runtime/CSharpClosure.cs
  21. 3 2
      src/Lua/Runtime/CallStackFrame.cs
  22. 1 1
      src/Lua/Runtime/LuaClosure.cs
  23. 12 0
      src/Lua/Runtime/LuaStack.cs
  24. 30 19
      src/Lua/Runtime/LuaVirtualMachine.Debug.cs
  25. 161 391
      src/Lua/Runtime/LuaVirtualMachine.cs
  26. 41 0
      src/Lua/Runtime/Metamethods.cs
  27. 42 41
      src/Lua/Runtime/OpCode.cs
  28. 89 153
      src/Lua/Standard/BasicLibrary.cs
  29. 35 47
      src/Lua/Standard/BitwiseLibrary.cs
  30. 39 52
      src/Lua/Standard/CoroutineLibrary.cs
  31. 61 103
      src/Lua/Standard/DebugLibrary.cs
  32. 26 40
      src/Lua/Standard/FileHandle.cs
  33. 48 56
      src/Lua/Standard/IOLibrary.cs
  34. 25 19
      src/Lua/Standard/Internal/IOHelper.cs
  35. 70 106
      src/Lua/Standard/MathematicsLibrary.cs
  36. 4 7
      src/Lua/Standard/ModuleLibrary.cs
  37. 5 7
      src/Lua/Standard/OpenLibsExtensions.cs
  38. 28 45
      src/Lua/Standard/OperatingSystemLibrary.cs
  39. 64 80
      src/Lua/Standard/StringLibrary.cs
  40. 36 42
      src/Lua/Standard/TableLibrary.cs
  41. 4 2
      tests/Lua.Tests/MetatableTests.cs

+ 4 - 3
sandbox/Benchmark/AddBenchmark.cs

@@ -22,10 +22,11 @@ public class AddBenchmark
         core.Setup("add.lua");
         core.Setup("add.lua");
         core.LuaCSharpState.OpenStandardLibraries();
         core.LuaCSharpState.OpenStandardLibraries();
 
 
-        core.LuaCSharpState.Environment["add"] = new LuaFunction("add", (context, buffer, ct) =>
+        core.LuaCSharpState.Environment["add"] = new LuaFunction("add", (context, ct) =>
         {
         {
-            buffer.Span[0] = context.GetArgument<double>(0) + context.GetArgument<double>(1);
-            return new(1);
+            var a = context.GetArgument<double>(0);
+            var b = context.GetArgument<double>(1);
+            return new(context.Return(a + b));
         });
         });
         core.MoonSharpState.Globals["add"] = (Func<double, double, double>)Add;
         core.MoonSharpState.Globals["add"] = (Func<double, double, double>)Add;
         core.NLuaState.RegisterFunction("add", typeof(AddBenchmark).GetMethod(nameof(Add), BindingFlags.Static | BindingFlags.Public));
         core.NLuaState.RegisterFunction("add", typeof(AddBenchmark).GetMethod(nameof(Add), BindingFlags.Static | BindingFlags.Public));

+ 3 - 1
sandbox/Benchmark/InterpreterSteps.cs

@@ -92,6 +92,8 @@ public class InterpreterSteps
     [Benchmark]
     [Benchmark]
     public async ValueTask RunAsync()
     public async ValueTask RunAsync()
     {
     {
-        await state.RunAsync(chunk, results);
+        using (await state.RunAsync(chunk))
+        {
+        }
     }
     }
 }
 }

+ 3 - 4
sandbox/ConsoleApp1/Program.cs

@@ -27,12 +27,11 @@ try
 
 
     Console.WriteLine("Output " + new string('-', 50));
     Console.WriteLine("Output " + new string('-', 50));
 
 
-    var results = new LuaValue[64];
-    var resultCount = await state.RunAsync(chunk, results);
+    using var results = await state.RunAsync(chunk);
 
 
     Console.WriteLine("Result " + new string('-', 50));
     Console.WriteLine("Result " + new string('-', 50));
 
 
-    for (int i = 0; i < resultCount; i++)
+    for (int i = 0; i < results.Count; i++)
     {
     {
         Console.WriteLine(results[i]);
         Console.WriteLine(results[i]);
     }
     }
@@ -42,7 +41,7 @@ try
 catch (Exception ex)
 catch (Exception ex)
 {
 {
     Console.WriteLine(ex);
     Console.WriteLine(ex);
-    if(ex is LuaRuntimeException { InnerException: not null } luaEx)
+    if (ex is LuaRuntimeException { InnerException: not null } luaEx)
     {
     {
         Console.WriteLine(luaEx.InnerException);
         Console.WriteLine(luaEx.InnerException);
     }
     }

+ 16 - 14
src/Lua.SourceGenerator/LuaObjectGenerator.Emit.cs

@@ -178,7 +178,7 @@ partial class LuaObjectGenerator
 
 
         PARAMETERS:
         PARAMETERS:
             foreach (var typeSymbol in method.Symbol.Parameters
             foreach (var typeSymbol in method.Symbol.Parameters
-                .Select(x => x.Type))
+                         .Select(x => x.Type))
             {
             {
                 if (SymbolEqualityComparer.Default.Equals(typeSymbol, references.LuaValue)) continue;
                 if (SymbolEqualityComparer.Default.Equals(typeSymbol, references.LuaValue)) continue;
                 if (SymbolEqualityComparer.Default.Equals(typeSymbol, typeMetadata.Symbol)) continue;
                 if (SymbolEqualityComparer.Default.Equals(typeSymbol, typeMetadata.Symbol)) continue;
@@ -201,7 +201,7 @@ partial class LuaObjectGenerator
 
 
     static bool TryEmitIndexMetamethod(TypeMetadata typeMetadata, CodeBuilder builder, in SourceProductionContext context)
     static bool TryEmitIndexMetamethod(TypeMetadata typeMetadata, CodeBuilder builder, in SourceProductionContext context)
     {
     {
-        builder.AppendLine(@"static readonly global::Lua.LuaFunction __metamethod_index = new global::Lua.LuaFunction(""index"", (context, buffer, ct) =>");
+        builder.AppendLine(@"static readonly global::Lua.LuaFunction __metamethod_index = new global::Lua.LuaFunction(""index"", (context, ct) =>");
 
 
         using (builder.BeginBlockScope())
         using (builder.BeginBlockScope())
         {
         {
@@ -224,17 +224,17 @@ partial class LuaObjectGenerator
                 }
                 }
 
 
                 foreach (var methodMetadata in typeMetadata.Methods
                 foreach (var methodMetadata in typeMetadata.Methods
-                    .Where(x => x.HasMemberAttribute))
+                             .Where(x => x.HasMemberAttribute))
                 {
                 {
                     builder.AppendLine(@$"""{methodMetadata.LuaMemberName}"" => new global::Lua.LuaValue(__function_{methodMetadata.LuaMemberName}),");
                     builder.AppendLine(@$"""{methodMetadata.LuaMemberName}"" => new global::Lua.LuaValue(__function_{methodMetadata.LuaMemberName}),");
                 }
                 }
 
 
                 builder.AppendLine(@$"_ => global::Lua.LuaValue.Nil,");
                 builder.AppendLine(@$"_ => global::Lua.LuaValue.Nil,");
             }
             }
+
             builder.AppendLine(";");
             builder.AppendLine(";");
 
 
-            builder.AppendLine("buffer.Span[0] = result;");
-            builder.AppendLine("return new(1);");
+            builder.AppendLine("return new global::System.Threading.Tasks.ValueTask<int>(context.Return(result));");
         }
         }
 
 
         builder.AppendLine(");");
         builder.AppendLine(");");
@@ -244,7 +244,7 @@ partial class LuaObjectGenerator
 
 
     static bool TryEmitNewIndexMetamethod(TypeMetadata typeMetadata, CodeBuilder builder, in SourceProductionContext context)
     static bool TryEmitNewIndexMetamethod(TypeMetadata typeMetadata, CodeBuilder builder, in SourceProductionContext context)
     {
     {
-        builder.AppendLine(@"static readonly global::Lua.LuaFunction __metamethod_newindex = new global::Lua.LuaFunction(""newindex"", (context, buffer, ct) =>");
+        builder.AppendLine(@"static readonly global::Lua.LuaFunction __metamethod_newindex = new global::Lua.LuaFunction(""newindex"", (context, ct) =>");
 
 
         using (builder.BeginBlockScope())
         using (builder.BeginBlockScope())
         {
         {
@@ -278,7 +278,7 @@ partial class LuaObjectGenerator
                 }
                 }
 
 
                 foreach (var methodMetadata in typeMetadata.Methods
                 foreach (var methodMetadata in typeMetadata.Methods
-                    .Where(x => x.HasMemberAttribute))
+                             .Where(x => x.HasMemberAttribute))
                 {
                 {
                     builder.AppendLine(@$"case ""{methodMetadata.LuaMemberName}"":");
                     builder.AppendLine(@$"case ""{methodMetadata.LuaMemberName}"":");
 
 
@@ -296,7 +296,7 @@ partial class LuaObjectGenerator
                 }
                 }
             }
             }
 
 
-            builder.AppendLine("return new(0);");
+            builder.AppendLine("return new global::System.Threading.Tasks.ValueTask<int>(context.Return());");
         }
         }
 
 
         builder.AppendLine(");");
         builder.AppendLine(");");
@@ -348,7 +348,7 @@ partial class LuaObjectGenerator
 
 
     static void EmitMethodFunction(string functionName, string chunkName, TypeMetadata typeMetadata, MethodMetadata methodMetadata, CodeBuilder builder, SymbolReferences references)
     static void EmitMethodFunction(string functionName, string chunkName, TypeMetadata typeMetadata, MethodMetadata methodMetadata, CodeBuilder builder, SymbolReferences references)
     {
     {
-        builder.AppendLine($@"static readonly global::Lua.LuaFunction {functionName} = new global::Lua.LuaFunction(""{chunkName}"", {(methodMetadata.IsAsync ? "async" : "")} (context, buffer, ct) =>");
+        builder.AppendLine($@"static readonly global::Lua.LuaFunction {functionName} = new global::Lua.LuaFunction(""{chunkName}"", {(methodMetadata.IsAsync ? "async" : "")} (context, ct) =>");
 
 
         using (builder.BeginBlockScope())
         using (builder.BeginBlockScope())
         {
         {
@@ -388,6 +388,7 @@ partial class LuaObjectGenerator
                         builder.AppendLine($"var arg{index} = context.GetArgument<{parameter.Type.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat)}>({index});");
                         builder.AppendLine($"var arg{index} = context.GetArgument<{parameter.Type.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat)}>({index});");
                     }
                     }
                 }
                 }
+
                 index++;
                 index++;
             }
             }
 
 
@@ -414,24 +415,24 @@ partial class LuaObjectGenerator
                 builder.AppendLine(");", false);
                 builder.AppendLine(");", false);
             }
             }
 
 
+            builder.Append("return ");
             if (methodMetadata.HasReturnValue)
             if (methodMetadata.HasReturnValue)
             {
             {
                 if (SymbolEqualityComparer.Default.Equals(methodMetadata.Symbol.ReturnType, references.LuaValue))
                 if (SymbolEqualityComparer.Default.Equals(methodMetadata.Symbol.ReturnType, references.LuaValue))
                 {
                 {
-                    builder.AppendLine("buffer.Span[0] = result;");
+                    builder.AppendLine(methodMetadata.IsAsync ? "context.Return(result));" : "new global::System.Threading.Tasks.ValueTask<int>(context.Return(result));");
                 }
                 }
                 else
                 else
                 {
                 {
-                    builder.AppendLine("buffer.Span[0] = new global::Lua.LuaValue(result);");
+                    builder.AppendLine(methodMetadata.IsAsync ? "context.Return(new global::Lua.LuaValue(result))));" : "new global::System.Threading.Tasks.ValueTask<int>(context.Return(new global::Lua.LuaValue(result)));");
                 }
                 }
-
-                builder.AppendLine($"return {(methodMetadata.IsAsync ? "1" : "new(1)")};");
             }
             }
             else
             else
             {
             {
-                builder.AppendLine($"return {(methodMetadata.IsAsync ? "0" : "new(0)")};");
+                builder.AppendLine(methodMetadata.IsAsync ? "context.Return();" : "new global::System.Threading.Tasks.ValueTask<int>(context.Return());");
             }
             }
         }
         }
+
         builder.AppendLine(");");
         builder.AppendLine(");");
         builder.AppendLine();
         builder.AppendLine();
     }
     }
@@ -453,6 +454,7 @@ partial class LuaObjectGenerator
                 {
                 {
                     builder.AppendLine($"__metatable[global::Lua.Runtime.Metamethods.{metamethod}] = __metamethod_{metamethod};");
                     builder.AppendLine($"__metatable[global::Lua.Runtime.Metamethods.{metamethod}] = __metamethod_{metamethod};");
                 }
                 }
+
                 builder.AppendLine("return __metatable;");
                 builder.AppendLine("return __metatable;");
             }
             }
 
 

+ 16 - 79
src/Lua/CodeAnalysis/Compilation/LuaCompiler.cs

@@ -26,10 +26,7 @@ public sealed class LuaCompiler : ISyntaxNodeVisitor<ScopeCompilationContext, bo
         // set global enviroment upvalue
         // set global enviroment upvalue
         context.AddUpValue(new()
         context.AddUpValue(new()
         {
         {
-            Name = "_ENV".AsMemory(),
-            Id = 0,
-            Index = -1,
-            IsInRegister = false,
+            Name = "_ENV".AsMemory(), Id = 0, Index = -1, IsInRegister = false,
         });
         });
 
 
         context.ChunkName = chunkName;
         context.ChunkName = chunkName;
@@ -471,11 +468,7 @@ public sealed class LuaCompiler : ISyntaxNodeVisitor<ScopeCompilationContext, bo
             else
             else
             {
             {
                 // register local variable
                 // register local variable
-                context.AddLocalVariable(identifier.Name, new()
-                {
-                    RegisterIndex = (byte)(context.StackPosition - 1),
-                    StartPc = context.Function.Instructions.Length,
-                });
+                context.AddLocalVariable(identifier.Name, new() { RegisterIndex = (byte)(context.StackPosition - 1), StartPc = context.Function.Instructions.Length, });
             }
             }
         }
         }
 
 
@@ -605,11 +598,7 @@ public sealed class LuaCompiler : ISyntaxNodeVisitor<ScopeCompilationContext, bo
     public bool VisitLocalFunctionDeclarationStatementNode(LocalFunctionDeclarationStatementNode node, ScopeCompilationContext context)
     public bool VisitLocalFunctionDeclarationStatementNode(LocalFunctionDeclarationStatementNode node, ScopeCompilationContext context)
     {
     {
         // assign local variable
         // assign local variable
-        context.AddLocalVariable(node.Name, new()
-        {
-            RegisterIndex = context.StackPosition,
-            StartPc = context.Function.Instructions.Length,
-        });
+        context.AddLocalVariable(node.Name, new() { RegisterIndex = context.StackPosition, StartPc = context.Function.Instructions.Length, });
 
 
         // compile function
         // compile function
         var funcIndex = CompileFunctionProto(node.Name, context, node.ParameterNodes, node.Nodes, node.ParameterNodes.Length, node.HasVariableArguments, false, node.LineDefined, node.EndPosition.Line);
         var funcIndex = CompileFunctionProto(node.Name, context, node.ParameterNodes, node.Nodes, node.ParameterNodes.Length, node.HasVariableArguments, false, node.LineDefined, node.EndPosition.Line);
@@ -688,11 +677,7 @@ public sealed class LuaCompiler : ISyntaxNodeVisitor<ScopeCompilationContext, bo
 
 
         if (hasSelfParameter)
         if (hasSelfParameter)
         {
         {
-            funcContext.Scope.AddLocalVariable("self".AsMemory(), new()
-            {
-                RegisterIndex = 0,
-                StartPc = 0,
-            });
+            funcContext.Scope.AddLocalVariable("self".AsMemory(), new() { RegisterIndex = 0, StartPc = 0, });
 
 
             funcContext.Scope.StackPosition++;
             funcContext.Scope.StackPosition++;
         }
         }
@@ -701,11 +686,7 @@ public sealed class LuaCompiler : ISyntaxNodeVisitor<ScopeCompilationContext, bo
         for (int i = 0; i < parameters.Length; i++)
         for (int i = 0; i < parameters.Length; i++)
         {
         {
             var parameter = parameters[i];
             var parameter = parameters[i];
-            funcContext.Scope.AddLocalVariable(parameter.Name, new()
-            {
-                RegisterIndex = (byte)(i + (hasSelfParameter ? 1 : 0)),
-                StartPc = 0,
-            });
+            funcContext.Scope.AddLocalVariable(parameter.Name, new() { RegisterIndex = (byte)(i + (hasSelfParameter ? 1 : 0)), StartPc = 0, });
 
 
             funcContext.Scope.StackPosition++;
             funcContext.Scope.StackPosition++;
         }
         }
@@ -749,10 +730,7 @@ public sealed class LuaCompiler : ISyntaxNodeVisitor<ScopeCompilationContext, bo
 
 
     public bool VisitBreakStatementNode(BreakStatementNode node, ScopeCompilationContext context)
     public bool VisitBreakStatementNode(BreakStatementNode node, ScopeCompilationContext context)
     {
     {
-        context.Function.AddUnresolvedBreak(new()
-        {
-            Index = context.Function.Instructions.Length
-        }, node.Position);
+        context.Function.AddUnresolvedBreak(new() { Index = context.Function.Instructions.Length }, node.Position);
         context.PushInstruction(Instruction.Jmp(0, 0), node.Position);
         context.PushInstruction(Instruction.Jmp(0, 0), node.Position);
 
 
         return true;
         return true;
@@ -921,30 +899,14 @@ public sealed class LuaCompiler : ISyntaxNodeVisitor<ScopeCompilationContext, bo
         context.Function.LoopLevel++;
         context.Function.LoopLevel++;
         using var scopeContext = context.CreateChildScope();
         using var scopeContext = context.CreateChildScope();
         {
         {
-            scopeContext.AddLocalVariable("(for index)".AsMemory(), new()
-            {
-                RegisterIndex = startPosition,
-                StartPc = context.Function.Instructions.Length,
-            });
+            scopeContext.AddLocalVariable("(for index)".AsMemory(), new() { RegisterIndex = startPosition, StartPc = context.Function.Instructions.Length, });
 
 
-            scopeContext.AddLocalVariable("(for limit)".AsMemory(), new()
-            {
-                RegisterIndex = (byte)(startPosition + 1),
-                StartPc = context.Function.Instructions.Length,
-            });
+            scopeContext.AddLocalVariable("(for limit)".AsMemory(), new() { RegisterIndex = (byte)(startPosition + 1), StartPc = context.Function.Instructions.Length, });
 
 
-            scopeContext.AddLocalVariable("(for step)".AsMemory(), new()
-            {
-                RegisterIndex = (byte)(startPosition + 2),
-                StartPc = context.Function.Instructions.Length,
-            });
+            scopeContext.AddLocalVariable("(for step)".AsMemory(), new() { RegisterIndex = (byte)(startPosition + 2), StartPc = context.Function.Instructions.Length, });
 
 
             // add local variable
             // add local variable
-            scopeContext.AddLocalVariable(node.VariableName, new()
-            {
-                RegisterIndex = (byte)(startPosition + 3),
-                StartPc = context.Function.Instructions.Length,
-            });
+            scopeContext.AddLocalVariable(node.VariableName, new() { RegisterIndex = (byte)(startPosition + 3), StartPc = context.Function.Instructions.Length, });
 
 
             foreach (var childNode in node.StatementNodes)
             foreach (var childNode in node.StatementNodes)
             {
             {
@@ -984,33 +946,17 @@ public sealed class LuaCompiler : ISyntaxNodeVisitor<ScopeCompilationContext, bo
         {
         {
             scopeContext.StackPosition = (byte)(startPosition + 3 + node.Names.Length);
             scopeContext.StackPosition = (byte)(startPosition + 3 + node.Names.Length);
 
 
-            scopeContext.AddLocalVariable("(for generator)".AsMemory(), new()
-            {
-                RegisterIndex = (byte)(startPosition),
-                StartPc = context.Function.Instructions.Length,
-            });
+            scopeContext.AddLocalVariable("(for generator)".AsMemory(), new() { RegisterIndex = (byte)(startPosition), StartPc = context.Function.Instructions.Length, });
 
 
-            scopeContext.AddLocalVariable("(for state)".AsMemory(), new()
-            {
-                RegisterIndex = (byte)(startPosition + 1),
-                StartPc = context.Function.Instructions.Length,
-            });
+            scopeContext.AddLocalVariable("(for state)".AsMemory(), new() { RegisterIndex = (byte)(startPosition + 1), StartPc = context.Function.Instructions.Length, });
 
 
-            scopeContext.AddLocalVariable("(for control)".AsMemory(), new()
-            {
-                RegisterIndex = (byte)(startPosition + 2),
-                StartPc = context.Function.Instructions.Length,
-            });
+            scopeContext.AddLocalVariable("(for control)".AsMemory(), new() { RegisterIndex = (byte)(startPosition + 2), StartPc = context.Function.Instructions.Length, });
 
 
             // add local variables
             // add local variables
             for (int i = 0; i < node.Names.Length; i++)
             for (int i = 0; i < node.Names.Length; i++)
             {
             {
                 var name = node.Names[i];
                 var name = node.Names[i];
-                scopeContext.AddLocalVariable(name.Name, new()
-                {
-                    RegisterIndex = (byte)(startPosition + 3 + i),
-                    StartPc = context.Function.Instructions.Length,
-                });
+                scopeContext.AddLocalVariable(name.Name, new() { RegisterIndex = (byte)(startPosition + 3 + i), StartPc = context.Function.Instructions.Length, });
             }
             }
 
 
             foreach (var childNode in node.StatementNodes)
             foreach (var childNode in node.StatementNodes)
@@ -1037,12 +983,7 @@ public sealed class LuaCompiler : ISyntaxNodeVisitor<ScopeCompilationContext, bo
 
 
     public bool VisitLabelStatementNode(LabelStatementNode node, ScopeCompilationContext context)
     public bool VisitLabelStatementNode(LabelStatementNode node, ScopeCompilationContext context)
     {
     {
-        var desc = new LabelDescription()
-        {
-            Name = node.Name,
-            Index = context.Function.Instructions.Length,
-            RegisterIndex = context.StackPosition
-        };
+        var desc = new LabelDescription() { Name = node.Name, Index = context.Function.Instructions.Length, RegisterIndex = context.StackPosition };
 
 
         context.AddLabel(desc);
         context.AddLabel(desc);
         context.Function.ResolveGoto(desc);
         context.Function.ResolveGoto(desc);
@@ -1058,11 +999,7 @@ public sealed class LuaCompiler : ISyntaxNodeVisitor<ScopeCompilationContext, bo
         }
         }
         else
         else
         {
         {
-            context.Function.AddUnresolvedGoto(new()
-            {
-                Name = node.Name,
-                JumpInstructionIndex = context.Function.Instructions.Length
-            });
+            context.Function.AddUnresolvedGoto(new() { Name = node.Name, JumpInstructionIndex = context.Function.Instructions.Length });
 
 
             // add uninitialized jmp instruction
             // add uninitialized jmp instruction
             context.PushInstruction(Instruction.Jmp(0, 0), node.Position);
             context.PushInstruction(Instruction.Jmp(0, 0), node.Position);

+ 1 - 1
src/Lua/CodeAnalysis/Syntax/Nodes/BooleanLiteralNode.cs

@@ -6,4 +6,4 @@ public record BooleanLiteralNode(bool Value, SourcePosition Position) : Expressi
     {
     {
         return visitor.VisitBooleanLiteralNode(this, context);
         return visitor.VisitBooleanLiteralNode(this, context);
     }
     }
-}
+}

+ 1 - 1
src/Lua/Internal/BitFlags.cs

@@ -19,7 +19,7 @@ internal struct BitFlags2
             }
             }
         }
         }
     }
     }
-    
+
     public bool Flag1
     public bool Flag1
     {
     {
         get => (Value & 2) == 2;
         get => (Value & 2) == 2;

+ 2 - 1
src/Lua/Internal/BitFlags256.cs

@@ -3,7 +3,7 @@ namespace Lua.Internal;
 internal unsafe struct BitFlags256
 internal unsafe struct BitFlags256
 {
 {
     internal fixed long Data[4];
     internal fixed long Data[4];
-    
+
     public bool this[int index]
     public bool this[int index]
     {
     {
         get => (Data[index >> 6] & (1L << (index & 63))) != 0;
         get => (Data[index >> 6] & (1L << (index & 63))) != 0;
@@ -19,5 +19,6 @@ internal unsafe struct BitFlags256
             }
             }
         }
         }
     }
     }
+
     public void Set(int index) => Data[index >> 6] |= 1L << (index & 63);
     public void Set(int index) => Data[index >> 6] |= 1L << (index & 63);
 }
 }

+ 26 - 0
src/Lua/Internal/LuaResult.cs

@@ -0,0 +1,26 @@
+using Lua.Runtime;
+
+namespace Lua.Internal;
+
+public readonly struct LuaResult : IDisposable
+{
+    readonly LuaStack stack;
+    readonly int returnBase;
+
+    internal LuaResult(LuaStack stack, int returnBase)
+    {
+        this.stack = stack;
+        this.returnBase = returnBase;
+    }
+
+    public int Count => stack.Count - returnBase;
+    public int Length => stack.Count - returnBase;
+    public ReadOnlySpan<LuaValue> AsSpan() => stack.AsSpan()[returnBase..];
+
+    public LuaValue this[int index] => AsSpan()[index];
+
+    public void Dispose()
+    {
+        stack.PopUntil(returnBase);
+    }
+}

+ 17 - 45
src/Lua/LuaCoroutine.cs

@@ -20,19 +20,17 @@ public sealed class LuaCoroutine : LuaThread, IValueTaskSource<LuaCoroutine.Yiel
     byte status;
     byte status;
     bool isFirstCall = true;
     bool isFirstCall = true;
     ValueTask<int> functionTask;
     ValueTask<int> functionTask;
-    LuaValue[] buffer;
+    int returnFrameBase;
 
 
     ManualResetValueTaskSourceCore<ResumeContext> resume;
     ManualResetValueTaskSourceCore<ResumeContext> resume;
     ManualResetValueTaskSourceCore<YieldContext> yield;
     ManualResetValueTaskSourceCore<YieldContext> yield;
     Traceback? traceback;
     Traceback? traceback;
+    internal int ReturnFrameBase => returnFrameBase;
 
 
     public LuaCoroutine(LuaFunction function, bool isProtectedMode)
     public LuaCoroutine(LuaFunction function, bool isProtectedMode)
     {
     {
         IsProtectedMode = isProtectedMode;
         IsProtectedMode = isProtectedMode;
         Function = function;
         Function = function;
-
-        buffer = ArrayPool<LuaValue>.Shared.Rent(1024);
-        buffer.AsSpan().Clear();
     }
     }
 
 
     public override LuaThreadStatus GetStatus() => (LuaThreadStatus)status;
     public override LuaThreadStatus GetStatus() => (LuaThreadStatus)status;
@@ -44,11 +42,9 @@ public sealed class LuaCoroutine : LuaThread, IValueTaskSource<LuaCoroutine.Yiel
 
 
     public bool IsProtectedMode { get; }
     public bool IsProtectedMode { get; }
     public LuaFunction Function { get; }
     public LuaFunction Function { get; }
-    
-    
     internal Traceback? LuaTraceback => traceback;
     internal Traceback? LuaTraceback => traceback;
 
 
-    public override async ValueTask<int> ResumeAsync(LuaFunctionExecutionContext context, Memory<LuaValue> buffer, CancellationToken cancellationToken = default)
+    public override async ValueTask<int> ResumeAsync(LuaFunctionExecutionContext context, CancellationToken cancellationToken = default)
     {
     {
         var baseThread = context.Thread;
         var baseThread = context.Thread;
         baseThread.UnsafeSetStatus(LuaThreadStatus.Normal);
         baseThread.UnsafeSetStatus(LuaThreadStatus.Normal);
@@ -84,9 +80,7 @@ public sealed class LuaCoroutine : LuaThread, IValueTaskSource<LuaCoroutine.Yiel
                 case LuaThreadStatus.Running:
                 case LuaThreadStatus.Running:
                     if (IsProtectedMode)
                     if (IsProtectedMode)
                     {
                     {
-                        buffer.Span[0] = false;
-                        buffer.Span[1] = "cannot resume non-suspended coroutine";
-                        return 2;
+                        return context.Return(false, "cannot resume non-suspended coroutine");
                     }
                     }
                     else
                     else
                     {
                     {
@@ -95,9 +89,7 @@ public sealed class LuaCoroutine : LuaThread, IValueTaskSource<LuaCoroutine.Yiel
                 case LuaThreadStatus.Dead:
                 case LuaThreadStatus.Dead:
                     if (IsProtectedMode)
                     if (IsProtectedMode)
                     {
                     {
-                        buffer.Span[0] = false;
-                        buffer.Span[1] = "cannot resume dead coroutine";
-                        return 2;
+                        return context.Return(false, "cannot resume dead coroutine");
                     }
                     }
                     else
                     else
                     {
                     {
@@ -121,6 +113,7 @@ public sealed class LuaCoroutine : LuaThread, IValueTaskSource<LuaCoroutine.Yiel
             {
             {
                 if (isFirstCall)
                 if (isFirstCall)
                 {
                 {
+                    returnFrameBase = Stack.Count;
                     int frameBase;
                     int frameBase;
                     var variableArgumentCount = Function.GetVariableArgumentCount(context.ArgumentCount - 1);
                     var variableArgumentCount = Function.GetVariableArgumentCount(context.ArgumentCount - 1);
 
 
@@ -128,7 +121,6 @@ public sealed class LuaCoroutine : LuaThread, IValueTaskSource<LuaCoroutine.Yiel
                     {
                     {
                         var fixedArgumentCount = context.ArgumentCount - 1 - variableArgumentCount;
                         var fixedArgumentCount = context.ArgumentCount - 1 - variableArgumentCount;
                         var args = context.Arguments;
                         var args = context.Arguments;
-
                         Stack.PushRange(args.Slice(1 + fixedArgumentCount, variableArgumentCount));
                         Stack.PushRange(args.Slice(1 + fixedArgumentCount, variableArgumentCount));
 
 
                         frameBase = Stack.Count;
                         frameBase = Stack.Count;
@@ -147,47 +139,35 @@ public sealed class LuaCoroutine : LuaThread, IValueTaskSource<LuaCoroutine.Yiel
                         State = context.State,
                         State = context.State,
                         Thread = this,
                         Thread = this,
                         ArgumentCount = context.ArgumentCount - 1,
                         ArgumentCount = context.ArgumentCount - 1,
-                        FrameBase = frameBase
-                    }, this.buffer, cancellationToken).Preserve();
+                        FrameBase = frameBase,
+                        ReturnFrameBase = returnFrameBase
+                    }, cancellationToken).Preserve();
 
 
                     Volatile.Write(ref isFirstCall, false);
                     Volatile.Write(ref isFirstCall, false);
                 }
                 }
 
 
                 var (index, result0, result1) = await ValueTaskEx.WhenAny(resumeTask, functionTask!);
                 var (index, result0, result1) = await ValueTaskEx.WhenAny(resumeTask, functionTask!);
 
 
-                var bufferSpan = buffer.Span;
                 if (index == 0)
                 if (index == 0)
                 {
                 {
                     var results = result0.Results;
                     var results = result0.Results;
-
-                    bufferSpan[0] = true;
-                    results.CopyTo(bufferSpan[1..]);
-
-                    return results.Length + 1;
+                    return context.Return(true, results.AsSpan());
                 }
                 }
                 else
                 else
                 {
                 {
-                    var resultCount = functionTask!.Result;
-
                     Volatile.Write(ref status, (byte)LuaThreadStatus.Dead);
                     Volatile.Write(ref status, (byte)LuaThreadStatus.Dead);
-                    bufferSpan[0] = true;
-                    this.buffer.AsSpan()[..resultCount].CopyTo(bufferSpan[1..]);
-
-                    ArrayPool<LuaValue>.Shared.Return(this.buffer);
-
-                    return 1 + resultCount;
+                    var count = context.Return(true, Stack.AsSpan()[returnFrameBase..]);
+                    Stack.PopUntil(returnFrameBase);
+                    return count;
                 }
                 }
             }
             }
             catch (Exception ex) when (ex is not OperationCanceledException)
             catch (Exception ex) when (ex is not OperationCanceledException)
             {
             {
                 if (IsProtectedMode)
                 if (IsProtectedMode)
                 {
                 {
-                    ArrayPool<LuaValue>.Shared.Return(this.buffer);
                     traceback = (ex as LuaRuntimeException)?.LuaTraceback;
                     traceback = (ex as LuaRuntimeException)?.LuaTraceback;
                     Volatile.Write(ref status, (byte)LuaThreadStatus.Dead);
                     Volatile.Write(ref status, (byte)LuaThreadStatus.Dead);
-                    buffer.Span[0] = false;
-                    buffer.Span[1] = ex is LuaRuntimeException { ErrorObject: not null } luaEx ? luaEx.ErrorObject.Value : ex.Message;
-                    return 2;
+                    return context.Return(false, ex is LuaRuntimeException { ErrorObject: not null } luaEx ? luaEx.ErrorObject.Value : ex.Message);
                 }
                 }
                 else
                 else
                 {
                 {
@@ -207,7 +187,7 @@ public sealed class LuaCoroutine : LuaThread, IValueTaskSource<LuaCoroutine.Yiel
         }
         }
     }
     }
 
 
-    public override async ValueTask<int> YieldAsync(LuaFunctionExecutionContext context, Memory<LuaValue> buffer, CancellationToken cancellationToken = default)
+    public override async ValueTask<int> YieldAsync(LuaFunctionExecutionContext context, CancellationToken cancellationToken = default)
     {
     {
         if (Volatile.Read(ref status) != (byte)LuaThreadStatus.Running)
         if (Volatile.Read(ref status) != (byte)LuaThreadStatus.Running)
         {
         {
@@ -219,10 +199,7 @@ public sealed class LuaCoroutine : LuaThread, IValueTaskSource<LuaCoroutine.Yiel
             throw new LuaRuntimeException(context.State.GetTraceback(), "attempt to yield across a C#-call boundary");
             throw new LuaRuntimeException(context.State.GetTraceback(), "attempt to yield across a C#-call boundary");
         }
         }
 
 
-        resume.SetResult(new()
-        {
-            Results = context.Arguments.ToArray(),
-        });
+        resume.SetResult(new() { Results = context.Arguments.ToArray(), });
 
 
         Volatile.Write(ref status, (byte)LuaThreadStatus.Suspended);
         Volatile.Write(ref status, (byte)LuaThreadStatus.Suspended);
 
 
@@ -240,12 +217,7 @@ public sealed class LuaCoroutine : LuaThread, IValueTaskSource<LuaCoroutine.Yiel
         try
         try
         {
         {
             var result = await new ValueTask<YieldContext>(this, yield.Version);
             var result = await new ValueTask<YieldContext>(this, yield.Version);
-            for (int i = 0; i < result.Results.Length; i++)
-            {
-                buffer.Span[i] = result.Results[i];
-            }
-
-            return result.Results.Length;
+            return (context.Return(result.Results));
         }
         }
         catch (Exception ex) when (ex is not OperationCanceledException)
         catch (Exception ex) when (ex is not OperationCanceledException)
         {
         {

+ 7 - 16
src/Lua/LuaFunction.cs

@@ -1,37 +1,28 @@
-using System.Runtime.CompilerServices;
 using Lua.Runtime;
 using Lua.Runtime;
 
 
 namespace Lua;
 namespace Lua;
 
 
-public class LuaFunction(string name, Func<LuaFunctionExecutionContext, Memory<LuaValue>, CancellationToken, ValueTask<int>> func)
+public class LuaFunction(string name, Func<LuaFunctionExecutionContext, CancellationToken, ValueTask<int>> func)
 {
 {
     public string Name { get; } = name;
     public string Name { get; } = name;
-    internal Func<LuaFunctionExecutionContext, Memory<LuaValue>, CancellationToken, ValueTask<int>> Func { get; } = func;
+    internal Func<LuaFunctionExecutionContext, CancellationToken, ValueTask<int>> Func { get; } = func;
 
 
-    public LuaFunction(Func<LuaFunctionExecutionContext, Memory<LuaValue>, CancellationToken, ValueTask<int>> func) : this("anonymous", func)
+    public LuaFunction(Func<LuaFunctionExecutionContext, CancellationToken, ValueTask<int>> func) : this("anonymous", func)
     {
     {
     }
     }
 
 
-    public async ValueTask<int> InvokeAsync(LuaFunctionExecutionContext context, Memory<LuaValue> buffer, CancellationToken cancellationToken)
+    public async ValueTask<int> InvokeAsync(LuaFunctionExecutionContext context, CancellationToken cancellationToken)
     {
     {
-        var frame = new CallStackFrame
-        {
-            Base = context.FrameBase,
-            VariableArgumentCount = this is LuaClosure closure ? Math.Max(context.ArgumentCount - closure.Proto.ParameterCount, 0) : 0,
-            Function = this,
-        };
-
+        var frame = new CallStackFrame { Base = context.FrameBase, VariableArgumentCount = this.GetVariableArgumentCount(context.ArgumentCount), Function = this, ReturnBase = context.ReturnFrameBase };
         context.Thread.PushCallStackFrame(frame);
         context.Thread.PushCallStackFrame(frame);
-
-
         try
         try
         {
         {
             if (context.Thread.CallOrReturnHookMask.Value != 0 && !context.Thread.IsInHook)
             if (context.Thread.CallOrReturnHookMask.Value != 0 && !context.Thread.IsInHook)
             {
             {
-                return await LuaVirtualMachine.ExecuteCallHook(context, buffer, cancellationToken);
+                return await LuaVirtualMachine.ExecuteCallHook(context, cancellationToken);
             }
             }
 
 
-            return await Func(context, buffer, cancellationToken);
+            return await Func(context, cancellationToken);
         }
         }
         finally
         finally
         {
         {

+ 62 - 0
src/Lua/LuaFunctionExecutionContext.cs

@@ -12,6 +12,7 @@ public readonly record struct LuaFunctionExecutionContext
     public required LuaThread Thread { get; init; }
     public required LuaThread Thread { get; init; }
     public required int ArgumentCount { get; init; }
     public required int ArgumentCount { get; init; }
     public required int FrameBase { get; init; }
     public required int FrameBase { get; init; }
+    public required int ReturnFrameBase { get; init; }
     public SourcePosition? SourcePosition { get; init; }
     public SourcePosition? SourcePosition { get; init; }
     public string? RootChunkName { get; init; }
     public string? RootChunkName { get; init; }
     public string? ChunkName { get; init; }
     public string? ChunkName { get; init; }
@@ -116,6 +117,67 @@ public readonly record struct LuaFunctionExecutionContext
         return argValue;
         return argValue;
     }
     }
 
 
+    public int Return()
+    {
+        Thread.Stack.PopUntil(ReturnFrameBase);
+        return 0;
+    }
+
+    public int Return(LuaValue result)
+    {
+        var stack = Thread.Stack;
+        stack.SetTop(ReturnFrameBase + 1);
+        stack.FastGet(ReturnFrameBase) = result;
+        return 1;
+    }
+
+    public int Return(LuaValue result0, LuaValue result1)
+    {
+        var stack = Thread.Stack;
+        stack.SetTop(ReturnFrameBase + 2);
+        stack.FastGet(ReturnFrameBase) = result0;
+        stack.FastGet(ReturnFrameBase + 1) = result1;
+        return 2;
+    }
+
+    public int Return(LuaValue result0, LuaValue result1, LuaValue result2)
+    {
+        var stack = Thread.Stack;
+        stack.SetTop(ReturnFrameBase + 3);
+        stack.FastGet(ReturnFrameBase) = result0;
+        stack.FastGet(ReturnFrameBase + 1) = result1;
+        stack.FastGet(ReturnFrameBase + 2) = result2;
+        return 3;
+    }
+
+    public int Return(ReadOnlySpan<LuaValue> results)
+    {
+        var stack = Thread.Stack;
+        stack.EnsureCapacity(ReturnFrameBase + results.Length);
+        results.CopyTo(stack.GetBuffer()[ReturnFrameBase..(ReturnFrameBase + results.Length)]);
+        stack.SetTop(ReturnFrameBase + results.Length);
+        return results.Length;
+    }
+
+    internal int Return(LuaValue result0, ReadOnlySpan<LuaValue> results)
+    {
+        var stack = Thread.Stack;
+        stack.EnsureCapacity(ReturnFrameBase + results.Length);
+        stack.SetTop(ReturnFrameBase + results.Length + 1);
+        var buffer = stack.GetBuffer();
+        buffer[ReturnFrameBase] = result0;
+        results.CopyTo(buffer[(ReturnFrameBase + 1)..(ReturnFrameBase + results.Length + 1)]);
+        return results.Length + 1;
+    }
+
+    public Span<LuaValue> GetReturnBuffer(int count)
+    {
+        var stack = Thread.Stack;
+        stack.SetTop(ReturnFrameBase + count);
+        var buffer = stack.GetBuffer()[ReturnFrameBase..(ReturnFrameBase + count)];
+        return buffer;
+    }
+
     public CSharpClosure? GetCsClosure()
     public CSharpClosure? GetCsClosure()
     {
     {
         return Thread.GetCurrentFrame().Function as CSharpClosure;
         return Thread.GetCurrentFrame().Function as CSharpClosure;

+ 6 - 6
src/Lua/LuaFunctionExtensions.cs

@@ -6,11 +6,9 @@ public static class LuaFunctionExtensions
 {
 {
     public static async ValueTask<LuaValue[]> InvokeAsync(this LuaFunction function, LuaState state, LuaValue[] arguments, CancellationToken cancellationToken = default)
     public static async ValueTask<LuaValue[]> InvokeAsync(this LuaFunction function, LuaState state, LuaValue[] arguments, CancellationToken cancellationToken = default)
     {
     {
-        using var buffer = new PooledArray<LuaValue>(1024);
-
         var thread = state.CurrentThread;
         var thread = state.CurrentThread;
         var frameBase = thread.Stack.Count;
         var frameBase = thread.Stack.Count;
-        
+
         for (int i = 0; i < arguments.Length; i++)
         for (int i = 0; i < arguments.Length; i++)
         {
         {
             thread.Stack.Push(arguments[i]);
             thread.Stack.Push(arguments[i]);
@@ -22,8 +20,10 @@ public static class LuaFunctionExtensions
             Thread = thread,
             Thread = thread,
             ArgumentCount = arguments.Length,
             ArgumentCount = arguments.Length,
             FrameBase = frameBase,
             FrameBase = frameBase,
-        }, buffer.AsMemory(), cancellationToken);
-
-        return buffer.AsSpan()[0..resultCount].ToArray();
+            ReturnFrameBase = frameBase,
+        }, cancellationToken);
+        var r = thread.Stack.GetBuffer()[frameBase..(frameBase + resultCount)].ToArray();
+        thread.Stack.PopUntil(frameBase);
+        return r;
     }
     }
 }
 }

+ 4 - 6
src/Lua/LuaMainThread.cs

@@ -12,15 +12,13 @@ public sealed class LuaMainThread : LuaThread
         // Do nothing
         // Do nothing
     }
     }
 
 
-    public override ValueTask<int> ResumeAsync(LuaFunctionExecutionContext context, Memory<LuaValue> buffer, CancellationToken cancellationToken = default)
+    public override ValueTask<int> ResumeAsync(LuaFunctionExecutionContext context, CancellationToken cancellationToken = default)
     {
     {
-        buffer.Span[0] = false;
-        buffer.Span[1] = "cannot resume non-suspended coroutine";
-        return new(2);
+        return new(context.Return(false, "cannot resume non-suspended coroutine"));
     }
     }
 
 
-    public override ValueTask<int> YieldAsync(LuaFunctionExecutionContext context, Memory<LuaValue> buffer, CancellationToken cancellationToken = default)
+    public override ValueTask<int> YieldAsync(LuaFunctionExecutionContext context, CancellationToken cancellationToken = default)
     {
     {
         throw new LuaRuntimeException(context.State.GetTraceback(), "attempt to yield from outside a coroutine");
         throw new LuaRuntimeException(context.State.GetTraceback(), "attempt to yield from outside a coroutine");
     }
     }
-}
+}

+ 18 - 33
src/Lua/LuaState.cs

@@ -31,6 +31,7 @@ public sealed class LuaState
     public LuaTable Registry => registry;
     public LuaTable Registry => registry;
     public LuaTable LoadedModules => packages;
     public LuaTable LoadedModules => packages;
     public LuaMainThread MainThread => mainThread;
     public LuaMainThread MainThread => mainThread;
+
     public LuaThread CurrentThread
     public LuaThread CurrentThread
     {
     {
         get
         get
@@ -61,24 +62,28 @@ public sealed class LuaState
         envUpValue = UpValue.Closed(environment);
         envUpValue = UpValue.Closed(environment);
     }
     }
 
 
-    public async ValueTask<int> RunAsync(Chunk chunk, Memory<LuaValue> buffer, CancellationToken cancellationToken = default)
+    public async ValueTask<LuaResult> RunAsync(Chunk chunk, CancellationToken cancellationToken = default)
     {
     {
+        ThrowIfResultNotDisposed();
         ThrowIfRunning();
         ThrowIfRunning();
 
 
         Volatile.Write(ref isRunning, true);
         Volatile.Write(ref isRunning, true);
         try
         try
         {
         {
             var closure = new LuaClosure(this, chunk);
             var closure = new LuaClosure(this, chunk);
-            return await closure.InvokeAsync(new()
+            await closure.InvokeAsync(new()
             {
             {
                 State = this,
                 State = this,
                 Thread = CurrentThread,
                 Thread = CurrentThread,
                 ArgumentCount = 0,
                 ArgumentCount = 0,
                 FrameBase = 0,
                 FrameBase = 0,
+                ReturnFrameBase = 0,
                 SourcePosition = null,
                 SourcePosition = null,
                 RootChunkName = chunk.Name,
                 RootChunkName = chunk.Name,
                 ChunkName = chunk.Name,
                 ChunkName = chunk.Name,
-            }, buffer, cancellationToken);
+            }, cancellationToken);
+
+            return new LuaResult(CurrentThread.Stack, 0);
         }
         }
         finally
         finally
         {
         {
@@ -93,36 +98,7 @@ public sealed class LuaState
 
 
     public Traceback GetTraceback()
     public Traceback GetTraceback()
     {
     {
-        if (threadStack.Count == 0)
-        {
-            return new(this)
-            {
-                RootFunc = (LuaClosure)MainThread.GetCallStackFrames()[0].Function,
-                StackFrames = MainThread.GetCallStackFrames()[1..]
-                    .ToArray()
-            };
-        }
-
-        using var list = new PooledList<CallStackFrame>(8);
-        foreach (var frame in MainThread.GetCallStackFrames()[1..])
-        {
-            list.Add(frame);
-        }
-
-        foreach (var thread in threadStack.AsSpan())
-        {
-            if (thread.CallStack.Count == 0) continue;
-            foreach (var frame in thread.GetCallStackFrames()[1..])
-            {
-                list.Add(frame);
-            }
-        }
-
-        return new(this)
-        {
-            RootFunc = (LuaClosure)MainThread.GetCallStackFrames()[0].Function,
-            StackFrames = list.AsSpan().ToArray()
-        };
+        return GetTraceback(CurrentThread);
     }
     }
 
 
     internal Traceback GetTraceback(LuaThread thread)
     internal Traceback GetTraceback(LuaThread thread)
@@ -132,6 +108,7 @@ public sealed class LuaState
         {
         {
             list.Add(frame);
             list.Add(frame);
         }
         }
+
         LuaClosure rootFunc;
         LuaClosure rootFunc;
         if (thread.GetCallStackFrames()[0].Function is LuaClosure closure)
         if (thread.GetCallStackFrames()[0].Function is LuaClosure closure)
         {
         {
@@ -231,6 +208,14 @@ public sealed class LuaState
         }
         }
     }
     }
 
 
+    void ThrowIfResultNotDisposed()
+    {
+        if (MainThread.Stack.Count != 0)
+        {
+            throw new InvalidOperationException("LuaResult is not disposed");
+        }
+    }
+
     void ThrowIfRunning()
     void ThrowIfRunning()
     {
     {
         if (Volatile.Read(ref isRunning))
         if (Volatile.Read(ref isRunning))

+ 18 - 25
src/Lua/LuaStateExtensions.cs

@@ -1,4 +1,3 @@
-using System.Buffers;
 using Lua.CodeAnalysis.Compilation;
 using Lua.CodeAnalysis.Compilation;
 using Lua.CodeAnalysis.Syntax;
 using Lua.CodeAnalysis.Syntax;
 
 
@@ -6,47 +5,41 @@ namespace Lua;
 
 
 public static class LuaStateExtensions
 public static class LuaStateExtensions
 {
 {
-    public static ValueTask<int> DoStringAsync(this LuaState state, string source, Memory<LuaValue> buffer, string? chunkName = null, CancellationToken cancellationToken = default)
+    public static async ValueTask<int> DoStringAsync(this LuaState state, string source, Memory<LuaValue> buffer, string? chunkName = null, CancellationToken cancellationToken = default)
     {
     {
         var syntaxTree = LuaSyntaxTree.Parse(source, chunkName);
         var syntaxTree = LuaSyntaxTree.Parse(source, chunkName);
         var chunk = LuaCompiler.Default.Compile(syntaxTree, chunkName);
         var chunk = LuaCompiler.Default.Compile(syntaxTree, chunkName);
-        return state.RunAsync(chunk, buffer, cancellationToken);
+        using var result = await state.RunAsync(chunk, cancellationToken);
+        result.AsSpan().CopyTo(buffer.Span);
+        return result.Count;
     }
     }
 
 
     public static async ValueTask<LuaValue[]> DoStringAsync(this LuaState state, string source, string? chunkName = null, CancellationToken cancellationToken = default)
     public static async ValueTask<LuaValue[]> DoStringAsync(this LuaState state, string source, string? chunkName = null, CancellationToken cancellationToken = default)
     {
     {
-        var buffer = ArrayPool<LuaValue>.Shared.Rent(1024);
-        try
-        {
-            var resultCount = await DoStringAsync(state, source, buffer, chunkName, cancellationToken);
-            return buffer.AsSpan(0, resultCount).ToArray();
-        }
-        finally
-        {
-            ArrayPool<LuaValue>.Shared.Return(buffer);
-        }
+        var syntaxTree = LuaSyntaxTree.Parse(source, chunkName);
+        var chunk = LuaCompiler.Default.Compile(syntaxTree, chunkName);
+        using var result = await state.RunAsync(chunk, cancellationToken);
+        return result.AsSpan().ToArray();
     }
     }
 
 
     public static async ValueTask<int> DoFileAsync(this LuaState state, string path, Memory<LuaValue> buffer, CancellationToken cancellationToken = default)
     public static async ValueTask<int> DoFileAsync(this LuaState state, string path, Memory<LuaValue> buffer, CancellationToken cancellationToken = default)
     {
     {
         var text = await File.ReadAllTextAsync(path, cancellationToken);
         var text = await File.ReadAllTextAsync(path, cancellationToken);
-        var fileName = "@"+Path.GetFileName(path);
+        var fileName = "@" + Path.GetFileName(path);
         var syntaxTree = LuaSyntaxTree.Parse(text, fileName);
         var syntaxTree = LuaSyntaxTree.Parse(text, fileName);
         var chunk = LuaCompiler.Default.Compile(syntaxTree, fileName);
         var chunk = LuaCompiler.Default.Compile(syntaxTree, fileName);
-        return await state.RunAsync(chunk, buffer, cancellationToken);
+        using var result = await state.RunAsync(chunk, cancellationToken);
+        result.AsSpan().CopyTo(buffer.Span);
+        return result.Count;
     }
     }
 
 
     public static async ValueTask<LuaValue[]> DoFileAsync(this LuaState state, string path, CancellationToken cancellationToken = default)
     public static async ValueTask<LuaValue[]> DoFileAsync(this LuaState state, string path, CancellationToken cancellationToken = default)
     {
     {
-        var buffer = ArrayPool<LuaValue>.Shared.Rent(1024);
-        try
-        {
-            var resultCount = await DoFileAsync(state, path, buffer, cancellationToken);
-            return buffer.AsSpan(0, resultCount).ToArray();
-        }
-        finally
-        {
-            ArrayPool<LuaValue>.Shared.Return(buffer);
-        }
+        var text = await File.ReadAllTextAsync(path, cancellationToken);
+        var fileName = "@" + Path.GetFileName(path);
+        var syntaxTree = LuaSyntaxTree.Parse(text, fileName);
+        var chunk = LuaCompiler.Default.Compile(syntaxTree, fileName);
+        using var result = await state.RunAsync(chunk, cancellationToken);
+        return result.AsSpan().ToArray();
     }
     }
 }
 }

+ 5 - 5
src/Lua/LuaThread.cs

@@ -8,8 +8,8 @@ public abstract class LuaThread
 {
 {
     public abstract LuaThreadStatus GetStatus();
     public abstract LuaThreadStatus GetStatus();
     public abstract void UnsafeSetStatus(LuaThreadStatus status);
     public abstract void UnsafeSetStatus(LuaThreadStatus status);
-    public abstract ValueTask<int> ResumeAsync(LuaFunctionExecutionContext context, Memory<LuaValue> buffer, CancellationToken cancellationToken = default);
-    public abstract ValueTask<int> YieldAsync(LuaFunctionExecutionContext context, Memory<LuaValue> buffer, CancellationToken cancellationToken = default);
+    public abstract ValueTask<int> ResumeAsync(LuaFunctionExecutionContext context, CancellationToken cancellationToken = default);
+    public abstract ValueTask<int> YieldAsync(LuaFunctionExecutionContext context, CancellationToken cancellationToken = default);
 
 
     LuaStack stack = new();
     LuaStack stack = new();
     FastStackCore<CallStackFrame> callStack;
     FastStackCore<CallStackFrame> callStack;
@@ -72,7 +72,7 @@ public abstract class LuaThread
     }
     }
 
 
     [MethodImpl(MethodImplOptions.AggressiveInlining)]
     [MethodImpl(MethodImplOptions.AggressiveInlining)]
-    internal void PopCallStackFrame()
+    internal void PopCallStackFrameWithStackPop()
     {
     {
         if (callStack.TryPop(out var frame))
         if (callStack.TryPop(out var frame))
         {
         {
@@ -85,7 +85,7 @@ public abstract class LuaThread
     }
     }
 
 
     [MethodImpl(MethodImplOptions.AggressiveInlining)]
     [MethodImpl(MethodImplOptions.AggressiveInlining)]
-    internal void PopCallStackFrameUnsafe(int frameBase)
+    internal void PopCallStackFrameWithStackPop(int frameBase)
     {
     {
         if (callStack.TryPop())
         if (callStack.TryPop())
         {
         {
@@ -98,7 +98,7 @@ public abstract class LuaThread
     }
     }
 
 
     [MethodImpl(MethodImplOptions.AggressiveInlining)]
     [MethodImpl(MethodImplOptions.AggressiveInlining)]
-    internal void PopCallStackFrameUnsafe()
+    internal void PopCallStackFrame()
     {
     {
         if (!callStack.TryPop())
         if (!callStack.TryPop())
         {
         {

+ 14 - 12
src/Lua/LuaThreadExtensions.cs

@@ -6,26 +6,25 @@ public static class LuaThreadExtensions
 {
 {
     public static async ValueTask<LuaValue[]> ResumeAsync(this LuaThread thread, LuaState state, CancellationToken cancellationToken = default)
     public static async ValueTask<LuaValue[]> ResumeAsync(this LuaThread thread, LuaState state, CancellationToken cancellationToken = default)
     {
     {
-        using var buffer = new PooledArray<LuaValue>(1024);
-
         var frameBase = thread.Stack.Count;
         var frameBase = thread.Stack.Count;
         thread.Stack.Push(thread);
         thread.Stack.Push(thread);
 
 
-        var resultCount = await thread.ResumeAsync(new()
+        await thread.ResumeAsync(new()
         {
         {
             State = state,
             State = state,
             Thread = state.CurrentThread,
             Thread = state.CurrentThread,
             ArgumentCount = 1,
             ArgumentCount = 1,
             FrameBase = frameBase,
             FrameBase = frameBase,
-        }, buffer.AsMemory(), cancellationToken);
-
-        return buffer.AsSpan()[0..resultCount].ToArray();
+            ReturnFrameBase = frameBase,
+        }, cancellationToken);
+        var returnBase = ((LuaCoroutine)thread).ReturnFrameBase;
+        var results = thread.Stack.AsSpan()[returnBase..].ToArray();
+        thread.Stack.PopUntil(returnBase);
+        return results;
     }
     }
 
 
     public static async ValueTask<LuaValue[]> ResumeAsync(this LuaThread thread, LuaState state, LuaValue[] arguments, CancellationToken cancellationToken = default)
     public static async ValueTask<LuaValue[]> ResumeAsync(this LuaThread thread, LuaState state, LuaValue[] arguments, CancellationToken cancellationToken = default)
     {
     {
-        using var buffer = new PooledArray<LuaValue>(1024);
-
         var frameBase = thread.Stack.Count;
         var frameBase = thread.Stack.Count;
         thread.Stack.Push(thread);
         thread.Stack.Push(thread);
         for (int i = 0; i < arguments.Length; i++)
         for (int i = 0; i < arguments.Length; i++)
@@ -33,14 +32,17 @@ public static class LuaThreadExtensions
             thread.Stack.Push(arguments[i]);
             thread.Stack.Push(arguments[i]);
         }
         }
 
 
-        var resultCount = await thread.ResumeAsync(new()
+        await thread.ResumeAsync(new()
         {
         {
             State = state,
             State = state,
             Thread = state.CurrentThread,
             Thread = state.CurrentThread,
             ArgumentCount = 1 + arguments.Length,
             ArgumentCount = 1 + arguments.Length,
             FrameBase = frameBase,
             FrameBase = frameBase,
-        }, buffer.AsMemory(), cancellationToken);
-
-        return buffer.AsSpan()[0..resultCount].ToArray();
+            ReturnFrameBase = frameBase,
+        }, cancellationToken);
+        var returnBase = ((LuaCoroutine)thread).ReturnFrameBase;
+        var results = thread.Stack.AsSpan()[returnBase..].ToArray();
+        thread.Stack.PopUntil(returnBase);
+        return results;
     }
     }
 }
 }

+ 6 - 9
src/Lua/LuaValue.cs

@@ -584,7 +584,7 @@ public readonly struct LuaValue : IEquatable<LuaValue>
         return false;
         return false;
     }
     }
 
 
-    internal ValueTask<int> CallToStringAsync(LuaFunctionExecutionContext context, Memory<LuaValue> buffer, CancellationToken cancellationToken)
+    internal ValueTask<int> CallToStringAsync(LuaFunctionExecutionContext context, CancellationToken cancellationToken)
     {
     {
         if (this.TryGetMetamethod(context.State, Metamethods.ToString, out var metamethod))
         if (this.TryGetMetamethod(context.State, Metamethods.ToString, out var metamethod))
         {
         {
@@ -593,18 +593,15 @@ public readonly struct LuaValue : IEquatable<LuaValue>
                 LuaRuntimeException.AttemptInvalidOperation(context.State.GetTraceback(), "call", metamethod);
                 LuaRuntimeException.AttemptInvalidOperation(context.State.GetTraceback(), "call", metamethod);
             }
             }
 
 
-            context.State.Push(this);
+            var stack = context.Thread.Stack;
+            stack.Push(this);
 
 
-            return func.InvokeAsync(context with
-            {
-                ArgumentCount = 1,
-                FrameBase = context.Thread.Stack.Count - 1,
-            }, buffer, cancellationToken);
+            return func.InvokeAsync(context with { ArgumentCount = 1, FrameBase = stack.Count - 1, ReturnFrameBase = stack.Count - 1, }, cancellationToken);
         }
         }
         else
         else
         {
         {
-            buffer.Span[0] = ToString();
-            return new(1);
+            context.Thread.Stack.Push(ToString());
+            return default;
         }
         }
     }
     }
 }
 }

+ 2 - 2
src/Lua/Runtime/CSharpClosure.cs

@@ -1,6 +1,6 @@
 namespace Lua.Runtime;
 namespace Lua.Runtime;
 
 
-public sealed class CSharpClosure(string name,LuaValue[] upValues,Func<LuaFunctionExecutionContext, Memory<LuaValue>, CancellationToken, ValueTask<int>> func) : LuaFunction(name, func)
+public sealed class CSharpClosure(string name, LuaValue[] upValues, Func<LuaFunctionExecutionContext, CancellationToken, ValueTask<int>> func) : LuaFunction(name, func)
 {
 {
-   public readonly LuaValue[] UpValues = upValues;
+    public readonly LuaValue[] UpValues = upValues;
 }
 }

+ 3 - 2
src/Lua/Runtime/CallStackFrame.cs

@@ -6,18 +6,19 @@ namespace Lua.Runtime;
 public record struct CallStackFrame
 public record struct CallStackFrame
 {
 {
     public required int Base;
     public required int Base;
+    public required int ReturnBase;
     public required LuaFunction Function;
     public required LuaFunction Function;
     public required int VariableArgumentCount;
     public required int VariableArgumentCount;
     public int CallerInstructionIndex;
     public int CallerInstructionIndex;
     internal CallStackFrameFlags Flags;
     internal CallStackFrameFlags Flags;
-    internal bool IsTailCall => (Flags & CallStackFrameFlags.TailCall) ==CallStackFrameFlags.TailCall;
+    internal bool IsTailCall => (Flags & CallStackFrameFlags.TailCall) == CallStackFrameFlags.TailCall;
 }
 }
 
 
 [Flags]
 [Flags]
 public enum CallStackFrameFlags
 public enum CallStackFrameFlags
 {
 {
     //None = 0,
     //None = 0,
-    ReversedLe  = 1,
+    ReversedLe = 1,
     TailCall = 2,
     TailCall = 2,
     InHook = 4,
     InHook = 4,
 }
 }

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

@@ -9,7 +9,7 @@ public sealed class LuaClosure : LuaFunction
     FastListCore<UpValue> upValues;
     FastListCore<UpValue> upValues;
 
 
     public LuaClosure(LuaState state, Chunk proto, LuaTable? environment = null)
     public LuaClosure(LuaState state, Chunk proto, LuaTable? environment = null)
-        : base(proto.Name, (context, buffer, ct) => LuaVirtualMachine.ExecuteClosureAsync(context.State, buffer, ct))
+        : base(proto.Name, (context, ct) => LuaVirtualMachine.ExecuteClosureAsync(context.State, ct))
     {
     {
         this.proto = proto;
         this.proto = proto;
 
 

+ 12 - 0
src/Lua/Runtime/LuaStack.cs

@@ -27,6 +27,11 @@ public sealed class LuaStack(int initialSize = 256)
                 size *= 2;
                 size *= 2;
             }
             }
 
 
+            if (1000000 < size)
+            {
+                throw new LuaException("Lua Stack overflow");
+            }
+
             Array.Resize(ref array, size);
             Array.Resize(ref array, size);
         }
         }
     }
     }
@@ -134,4 +139,11 @@ public sealed class LuaStack(int initialSize = 256)
     {
     {
         throw new InvalidOperationException("Empty stack");
         throw new InvalidOperationException("Empty stack");
     }
     }
+
+    internal void SetTop(int top)
+    {
+        EnsureCapacity(top);
+        NotifyTop(top);
+        PopUntil(top);
+    }
 }
 }

+ 30 - 19
src/Lua/Runtime/LuaVirtualMachine.Debug.cs

@@ -12,7 +12,7 @@ public static partial class LuaVirtualMachine
         {
         {
             if (r.Result == 0)
             if (r.Result == 0)
             {
             {
-                context.Thread.PopCallStackFrame();
+                context.Thread.PopCallStackFrameWithStackPop();
             }
             }
 
 
             return false;
             return false;
@@ -39,18 +39,20 @@ public static partial class LuaVirtualMachine
                     Thread = context.Thread,
                     Thread = context.Thread,
                     ArgumentCount = 2,
                     ArgumentCount = 2,
                     FrameBase = context.Thread.Stack.Count - 2,
                     FrameBase = context.Thread.Stack.Count - 2,
+                    ReturnFrameBase = context.Thread.Stack.Count - 2,
                 };
                 };
                 var frame = new CallStackFrame
                 var frame = new CallStackFrame
                 {
                 {
                     Base = funcContext.FrameBase,
                     Base = funcContext.FrameBase,
-                    VariableArgumentCount = hook is LuaClosure closure ? Math.Max(funcContext.ArgumentCount - closure.Proto.ParameterCount, 0) : 0,
+                    ReturnBase = funcContext.ReturnFrameBase,
+                    VariableArgumentCount = hook.GetVariableArgumentCount(funcContext.ArgumentCount),
                     Function = hook,
                     Function = hook,
                     CallerInstructionIndex = context.Pc,
                     CallerInstructionIndex = context.Pc,
                 };
                 };
                 frame.Flags |= CallStackFrameFlags.InHook;
                 frame.Flags |= CallStackFrameFlags.InHook;
                 context.Thread.IsInHook = true;
                 context.Thread.IsInHook = true;
                 context.Thread.PushCallStackFrame(frame);
                 context.Thread.PushCallStackFrame(frame);
-                await hook.Func(funcContext, Memory<LuaValue>.Empty, context.CancellationToken);
+                await hook.Func(funcContext, context.CancellationToken);
                 context.Thread.IsInHook = false;
                 context.Thread.IsInHook = false;
 
 
 
 
@@ -68,7 +70,7 @@ public static partial class LuaVirtualMachine
                 {
                 {
                     if (countHookIsDone)
                     if (countHookIsDone)
                     {
                     {
-                        context.Thread.PopCallStackFrame();
+                        context.Thread.PopCallStackFrameWithStackPop();
                     }
                     }
 
 
 
 
@@ -82,18 +84,20 @@ public static partial class LuaVirtualMachine
                         Thread = context.Thread,
                         Thread = context.Thread,
                         ArgumentCount = 2,
                         ArgumentCount = 2,
                         FrameBase = context.Thread.Stack.Count - 2,
                         FrameBase = context.Thread.Stack.Count - 2,
+                        ReturnFrameBase = context.Thread.Stack.Count - 2,
                     };
                     };
                     var frame = new CallStackFrame
                     var frame = new CallStackFrame
                     {
                     {
                         Base = funcContext.FrameBase,
                         Base = funcContext.FrameBase,
-                        VariableArgumentCount = hook is LuaClosure closure ? Math.Max(funcContext.ArgumentCount - closure.Proto.ParameterCount, 0) : 0,
+                        ReturnBase = funcContext.ReturnFrameBase,
+                        VariableArgumentCount = hook.GetVariableArgumentCount(funcContext.ArgumentCount),
                         Function = hook,
                         Function = hook,
                         CallerInstructionIndex = pc,
                         CallerInstructionIndex = pc,
                     };
                     };
                     frame.Flags |= CallStackFrameFlags.InHook;
                     frame.Flags |= CallStackFrameFlags.InHook;
                     context.Thread.IsInHook = true;
                     context.Thread.IsInHook = true;
                     context.Thread.PushCallStackFrame(frame);
                     context.Thread.PushCallStackFrame(frame);
-                    await hook.Func(funcContext, Memory<LuaValue>.Empty, context.CancellationToken);
+                    await hook.Func(funcContext, context.CancellationToken);
                     context.Thread.IsInHook = false;
                     context.Thread.IsInHook = false;
                     context.Pc--;
                     context.Pc--;
                     context.Thread.LastPc = pc;
                     context.Thread.LastPc = pc;
@@ -122,11 +126,12 @@ public static partial class LuaVirtualMachine
             Thread = context.Thread,
             Thread = context.Thread,
             ArgumentCount = arguments,
             ArgumentCount = arguments,
             FrameBase = frame.Base,
             FrameBase = frame.Base,
+            ReturnFrameBase = frame.ReturnBase,
             CallerInstructionIndex = frame.CallerInstructionIndex,
             CallerInstructionIndex = frame.CallerInstructionIndex,
-        }, context.ResultsBuffer, context.CancellationToken, isTailCall);
+        }, context.CancellationToken, isTailCall);
     }
     }
 
 
-    internal static async ValueTask<int> ExecuteCallHook(LuaFunctionExecutionContext context, Memory<LuaValue> buffer, CancellationToken cancellationToken, bool isTailCall = false)
+    internal static async ValueTask<int> ExecuteCallHook(LuaFunctionExecutionContext context, CancellationToken cancellationToken, bool isTailCall = false)
     {
     {
         var argCount = context.ArgumentCount;
         var argCount = context.ArgumentCount;
         var hook = context.Thread.Hook!;
         var hook = context.Thread.Hook!;
@@ -142,10 +147,12 @@ public static partial class LuaVirtualMachine
                 Thread = context.Thread,
                 Thread = context.Thread,
                 ArgumentCount = 2,
                 ArgumentCount = 2,
                 FrameBase = context.Thread.Stack.Count - 2,
                 FrameBase = context.Thread.Stack.Count - 2,
+                ReturnFrameBase = context.Thread.Stack.Count - 2,
             };
             };
             CallStackFrame frame = new()
             CallStackFrame frame = new()
             {
             {
                 Base = funcContext.FrameBase,
                 Base = funcContext.FrameBase,
+                ReturnBase = funcContext.ReturnFrameBase,
                 VariableArgumentCount = hook.GetVariableArgumentCount(2),
                 VariableArgumentCount = hook.GetVariableArgumentCount(2),
                 Function = hook,
                 Function = hook,
                 CallerInstructionIndex = 0,
                 CallerInstructionIndex = 0,
@@ -156,29 +163,31 @@ public static partial class LuaVirtualMachine
             try
             try
             {
             {
                 context.Thread.IsInHook = true;
                 context.Thread.IsInHook = true;
-                await hook.Func(funcContext, Memory<LuaValue>.Empty, cancellationToken);
+                await hook.Func(funcContext, cancellationToken);
             }
             }
             finally
             finally
             {
             {
                 context.Thread.IsInHook = false;
                 context.Thread.IsInHook = false;
-                context.Thread.PopCallStackFrame();
+                context.Thread.PopCallStackFrameWithStackPop();
             }
             }
         }
         }
 
 
         {
         {
-            var frame = context.Thread.GetCurrentFrame();
+            ref readonly var frame = ref context.Thread.GetCurrentFrame();
             var task = frame.Function.Func(new()
             var task = frame.Function.Func(new()
             {
             {
                 State = context.State,
                 State = context.State,
                 Thread = context.Thread,
                 Thread = context.Thread,
                 ArgumentCount = argCount,
                 ArgumentCount = argCount,
                 FrameBase = frame.Base,
                 FrameBase = frame.Base,
-            }, buffer, cancellationToken);
+                ReturnFrameBase = frame.ReturnBase,
+            }, cancellationToken);
+            var r = await task;
             if (isTailCall || !context.Thread.IsReturnHookEnabled)
             if (isTailCall || !context.Thread.IsReturnHookEnabled)
             {
             {
-                return await task;
+                return r;
             }
             }
-            var result = await task;
+
             stack.Push("return");
             stack.Push("return");
             stack.Push(LuaValue.Nil);
             stack.Push(LuaValue.Nil);
             var funcContext = new LuaFunctionExecutionContext
             var funcContext = new LuaFunctionExecutionContext
@@ -187,12 +196,14 @@ public static partial class LuaVirtualMachine
                 Thread = context.Thread,
                 Thread = context.Thread,
                 ArgumentCount = 2,
                 ArgumentCount = 2,
                 FrameBase = context.Thread.Stack.Count - 2,
                 FrameBase = context.Thread.Stack.Count - 2,
+                ReturnFrameBase = context.Thread.Stack.Count - 2,
             };
             };
-           
 
 
-            context.Thread.PushCallStackFrame( new()
+
+            context.Thread.PushCallStackFrame(new()
             {
             {
                 Base = funcContext.FrameBase,
                 Base = funcContext.FrameBase,
+                ReturnBase = funcContext.ReturnFrameBase,
                 VariableArgumentCount = hook.GetVariableArgumentCount(2),
                 VariableArgumentCount = hook.GetVariableArgumentCount(2),
                 Function = hook,
                 Function = hook,
                 CallerInstructionIndex = 0,
                 CallerInstructionIndex = 0,
@@ -201,15 +212,15 @@ public static partial class LuaVirtualMachine
             try
             try
             {
             {
                 context.Thread.IsInHook = true;
                 context.Thread.IsInHook = true;
-                await hook.Func(funcContext, Memory<LuaValue>.Empty, cancellationToken);
+                await hook.Func(funcContext, cancellationToken);
             }
             }
             finally
             finally
             {
             {
                 context.Thread.IsInHook = false;
                 context.Thread.IsInHook = false;
             }
             }
 
 
-            context.Thread.PopCallStackFrame();
-            return result;
+            context.Thread.PopCallStackFrameWithStackPop();
+            return r;
         }
         }
     }
     }
 }
 }

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


+ 41 - 0
src/Lua/Runtime/Metamethods.cs

@@ -21,4 +21,45 @@ public static class Metamethods
     public const string Pairs = "__pairs";
     public const string Pairs = "__pairs";
     public const string IPairs = "__ipairs";
     public const string IPairs = "__ipairs";
     public new const string ToString = "__tostring";
     public new const string ToString = "__tostring";
+
+    internal static (string Name, string Description) GetNameAndDescription(this OpCode opCode)
+    {
+        switch (opCode)
+        {
+            case OpCode.GetTabUp:
+            case OpCode.GetTable:
+            case OpCode.Self:
+                return (Index, "index");
+            case OpCode.SetTabUp:
+            case OpCode.SetTable:
+                return (NewIndex, "new index");
+            case OpCode.Add:
+                return (Add, "add");
+            case OpCode.Sub:
+                return (Sub, "sub");
+            case OpCode.Mul:
+                return (Mul, "mul");
+            case OpCode.Div:
+                return (Div, "div");
+            case OpCode.Mod:
+                return (Mod, "mod");
+            case OpCode.Pow:
+                return (Pow, "pow");
+            case OpCode.Unm:
+                return (Unm, "unm");
+            case OpCode.Len:
+                return (Len, "get length of");
+            case OpCode.Eq:
+                return (Eq, "eq");
+            case OpCode.Lt:
+                return (Lt, "lt");
+            case OpCode.Le:
+                return (Le, "le");
+            case OpCode.Call:
+                return (Call, "call");
+            case OpCode.Concat:
+                return (Concat, "concat");
+            default: return (opCode.ToString(), opCode.ToString());
+        }
+    }
 }
 }

+ 42 - 41
src/Lua/Runtime/OpCode.cs

@@ -2,60 +2,61 @@ namespace Lua.Runtime;
 
 
 public enum OpCode : byte
 public enum OpCode : byte
 {
 {
-    Move,       // A B     R(A) := R(B)
-    LoadK,      // A Bx    R(A) := Kst(Bx)
-    LoadKX,     // A       R(A) := Kst(extra arg)
-    LoadBool,   // A B C   R(A) := (Bool)B; if (C) pc++
-    LoadNil,    // A B     R(A), R(A+1), ..., R(A+B) := nil
+    Move, // A B     R(A) := R(B)
+    LoadK, // A Bx    R(A) := Kst(Bx)
+    LoadKX, // A       R(A) := Kst(extra arg)
+    LoadBool, // A B C   R(A) := (Bool)B; if (C) pc++
+    LoadNil, // A B     R(A), R(A+1), ..., R(A+B) := nil
 
 
-    GetUpVal,   // A B     R(A) := UpValue[B]
-    GetTabUp,   // A B C   R(A) := UpValue[B][RK(C)]
-    GetTable,   // A B C   R(A) := R(B)[RK(C)]
+    GetUpVal, // A B     R(A) := UpValue[B]
+    GetTabUp, // A B C   R(A) := UpValue[B][RK(C)]
+    GetTable, // A B C   R(A) := R(B)[RK(C)]
 
 
-    SetTabUp,   // A B C   UpValue[A][RK(B)] := RK(C)
-    SetUpVal,   // A B     UpValue[B] := R(A)
-    SetTable,   // A B C   R(A)[RK(B)] := RK(C)
+    SetTabUp, // A B C   UpValue[A][RK(B)] := RK(C)
+    SetUpVal, // A B     UpValue[B] := R(A)
+    SetTable, // A B C   R(A)[RK(B)] := RK(C)
 
 
-    NewTable,   // A B C   R(A) := {} (size = B,C)
+    NewTable, // A B C   R(A) := {} (size = B,C)
 
 
-    Self,       // A B C   R(A+1) := R(B); R(A) := R(B)[RK(C)]
+    Self, // A B C   R(A+1) := R(B); R(A) := R(B)[RK(C)]
 
 
-    Add,        // A B C   R(A) := RK(B) + RK(C)
-    Sub,        // A B C   R(A) := RK(B) - RK(C)
-    Mul,        // A B C   R(A) := RK(B) * RK(C)
-    Div,        // A B C   R(A) := RK(B) / RK(C)
-    Mod,        // A B C   R(A) := RK(B) % RK(C)
-    Pow,        // A B C   R(A) := RK(B) ^ RK(C)
-    Unm,        // A B     R(A) := -R(B)
-    Not,        // A B     R(A) := not R(B)
-    Len,        // A B     R(A) := length of R(B)
+    Add, // A B C   R(A) := RK(B) + RK(C)
+    Sub, // A B C   R(A) := RK(B) - RK(C)
+    Mul, // A B C   R(A) := RK(B) * RK(C)
+    Div, // A B C   R(A) := RK(B) / RK(C)
+    Mod, // A B C   R(A) := RK(B) % RK(C)
+    Pow, // A B C   R(A) := RK(B) ^ RK(C)
+    Unm, // A B     R(A) := -R(B)
+    Not, // A B     R(A) := not R(B)
+    Len, // A B     R(A) := length of R(B)
 
 
-    Concat,     // A B C   R(A) := R(B).. ... ..R(C)
+    Concat, // A B C   R(A) := R(B).. ... ..R(C)
 
 
-    Jmp,        // A sBx   pc+=sBx; if (A) close all upvalues >= R(A - 1)
-    Eq,         // A B C   if ((RK(B) == RK(C)) ~= A) then pc++
-    Lt,         // A B C   if ((RK(B) <  RK(C)) ~= A) then pc++
-    Le,         // A B C   if ((RK(B) <= RK(C)) ~= A) then pc++
+    Jmp, // A sBx   pc+=sBx; if (A) close all upvalues >= R(A - 1)
+    Eq, // A B C   if ((RK(B) == RK(C)) ~= A) then pc++
+    Lt, // A B C   if ((RK(B) <  RK(C)) ~= A) then pc++
+    Le, // A B C   if ((RK(B) <= RK(C)) ~= A) then pc++
 
 
-    Test,       // A C     if not (R(A) <=> C) then pc++
-    TestSet,    // A B C   if (R(B) <=> C) then R(A) := R(B) else pc++
+    Test, // A C     if not (R(A) <=> C) then pc++
+    TestSet, // A B C   if (R(B) <=> C) then R(A) := R(B) else pc++
 
 
-    Call,       // A B C   R(A), ... ,R(A+C-2) := R(A)(R(A+1), ... ,R(A+B-1))
-    TailCall,   // A B C   return R(A)(R(A+1), ... ,R(A+B-1))
-    Return,     // A B     return R(A), ... ,R(A+B-2)      (see note)
+    Call, // A B C   R(A), ... ,R(A+C-2) := R(A)(R(A+1), ... ,R(A+B-1))
+    TailCall, // A B C   return R(A)(R(A+1), ... ,R(A+B-1))
+    Return, // A B     return R(A), ... ,R(A+B-2)      (see note)
 
 
-    ForLoop,    // A sBx   R(A)+=R(A+2);
-                //         if R(A) <?= R(A+1) then { pc+=sBx; R(A+3)=R(A) }
-    ForPrep,    // A sBx   R(A)-=R(A+2); pc+=sBx
+    ForLoop, // A sBx   R(A)+=R(A+2);
 
 
-    TForCall,   // A C     R(A+3), ... ,R(A+2+C) := R(A)(R(A+1), R(A+2));
-    TForLoop,   // A sBx   if R(A+1) ~= nil then { R(A)=R(A+1); pc += sBx }
+    //         if R(A) <?= R(A+1) then { pc+=sBx; R(A+3)=R(A) }
+    ForPrep, // A sBx   R(A)-=R(A+2); pc+=sBx
 
 
-    SetList,    // A B C   R(A)[(C-1)*FPF+i] := R(A+i), 1 <= i <= B
+    TForCall, // A C     R(A+3), ... ,R(A+2+C) := R(A)(R(A+1), R(A+2));
+    TForLoop, // A sBx   if R(A+1) ~= nil then { R(A)=R(A+1); pc += sBx }
 
 
-    Closure,    // A Bx    R(A) := closure(KPROTO[Bx])
+    SetList, // A B C   R(A)[(C-1)*FPF+i] := R(A+i), 1 <= i <= B
 
 
-    VarArg,     // A B     R(A), R(A+1), ..., R(A+B-2) = vararg
+    Closure, // A Bx    R(A) := closure(KPROTO[Bx])
 
 
-    ExtraArg    // Ax      extra (larger) argument for previous opcode
+    VarArg, // A B     R(A), R(A+1), ..., R(A+B-2) = vararg
+
+    ExtraArg // Ax      extra (larger) argument for previous opcode
 }
 }

+ 89 - 153
src/Lua/Standard/BasicLibrary.cs

@@ -11,7 +11,8 @@ public sealed class BasicLibrary
 
 
     public BasicLibrary()
     public BasicLibrary()
     {
     {
-        Functions = [
+        Functions =
+        [
             new("assert", Assert),
             new("assert", Assert),
             new("collectgarbage", CollectGarbage),
             new("collectgarbage", CollectGarbage),
             new("dofile", DoFile),
             new("dofile", DoFile),
@@ -36,7 +37,7 @@ public sealed class BasicLibrary
             new("xpcall", XPCall),
             new("xpcall", XPCall),
         ];
         ];
 
 
-        IPairsIterator = new("iterator", (context, buffer, cancellationToken) =>
+        IPairsIterator = new("iterator", (context, cancellationToken) =>
         {
         {
             var table = context.GetArgument<LuaTable>(0);
             var table = context.GetArgument<LuaTable>(0);
             var i = context.GetArgument<double>(1);
             var i = context.GetArgument<double>(1);
@@ -44,16 +45,12 @@ public sealed class BasicLibrary
             i++;
             i++;
             if (table.TryGetValue(i, out var value))
             if (table.TryGetValue(i, out var value))
             {
             {
-                buffer.Span[0] = i;
-                buffer.Span[1] = value;
+                return new(context.Return(i, value));
             }
             }
             else
             else
             {
             {
-                buffer.Span[0] = LuaValue.Nil;
-                buffer.Span[1] = LuaValue.Nil;
+                return new(context.Return(LuaValue.Nil, LuaValue.Nil));
             }
             }
-
-            return new(2);
         });
         });
 
 
         PairsIterator = new("iterator", Next);
         PairsIterator = new("iterator", Next);
@@ -63,7 +60,7 @@ public sealed class BasicLibrary
     readonly LuaFunction IPairsIterator;
     readonly LuaFunction IPairsIterator;
     readonly LuaFunction PairsIterator;
     readonly LuaFunction PairsIterator;
 
 
-    public ValueTask<int> Assert(LuaFunctionExecutionContext context, Memory<LuaValue> buffer, CancellationToken cancellationToken)
+    public ValueTask<int> Assert(LuaFunctionExecutionContext context, CancellationToken cancellationToken)
     {
     {
         var arg0 = context.GetArgument(0);
         var arg0 = context.GetArgument(0);
 
 
@@ -78,49 +75,43 @@ public sealed class BasicLibrary
             throw new LuaAssertionException(context.State.GetTraceback(), message);
             throw new LuaAssertionException(context.State.GetTraceback(), message);
         }
         }
 
 
-        context.Arguments.CopyTo(buffer.Span);
-        return new(context.ArgumentCount);
+        return new(context.Return(context.Arguments));
     }
     }
 
 
-    public ValueTask<int> CollectGarbage(LuaFunctionExecutionContext context, Memory<LuaValue> buffer, CancellationToken cancellationToken)
+    public ValueTask<int> CollectGarbage(LuaFunctionExecutionContext context, CancellationToken cancellationToken)
     {
     {
         GC.Collect();
         GC.Collect();
-        return new(0);
+        return new(context.Return());
     }
     }
 
 
-    public async ValueTask<int> DoFile(LuaFunctionExecutionContext context, Memory<LuaValue> buffer, CancellationToken cancellationToken)
+    public async ValueTask<int> DoFile(LuaFunctionExecutionContext context, CancellationToken cancellationToken)
     {
     {
         var arg0 = context.GetArgument<string>(0);
         var arg0 = context.GetArgument<string>(0);
 
 
         // do not use LuaState.DoFileAsync as it uses the newExecutionContext
         // do not use LuaState.DoFileAsync as it uses the newExecutionContext
         var text = await File.ReadAllTextAsync(arg0, cancellationToken);
         var text = await File.ReadAllTextAsync(arg0, cancellationToken);
-        var fileName = Path.GetFileName(arg0);
-        var chunk = LuaCompiler.Default.Compile(text, "@"+fileName);
+        var fileName = "@" + Path.GetFileName(arg0);
+        var chunk = LuaCompiler.Default.Compile(text, fileName);
 
 
-        return await new LuaClosure(context.State, chunk).InvokeAsync(context, buffer, cancellationToken);
+        return await new LuaClosure(context.State, chunk).InvokeAsync(context, cancellationToken);
     }
     }
 
 
-    public ValueTask<int> Error(LuaFunctionExecutionContext context, Memory<LuaValue> buffer, CancellationToken cancellationToken)
+    public ValueTask<int> Error(LuaFunctionExecutionContext context, CancellationToken cancellationToken)
     {
     {
-        var value = context.ArgumentCount == 0 || context.Arguments[0].Type is LuaValueType.Nil
-            ? "(error object is a nil value)"
+        var value = context.ArgumentCount == 0
+            ? LuaValue.Nil
             : context.Arguments[0];
             : context.Arguments[0];
 
 
-        Traceback t;
-        try
-        {
-           t = context.State.GetTraceback(context.Thread);
-            
-        }
-        catch (Exception e)
+        var traceback = context.State.GetTraceback();
+        if (value.TryReadString(out var str))
         {
         {
-            Console.WriteLine(e);
-            throw;
+            value = $"{traceback.RootChunkName}:{traceback.LastPosition.Line}: {str}";
         }
         }
-        throw new LuaRuntimeException(t, value);
+
+        throw new LuaRuntimeException(traceback, value);
     }
     }
 
 
-    public ValueTask<int> GetMetatable(LuaFunctionExecutionContext context, Memory<LuaValue> buffer, CancellationToken cancellationToken)
+    public ValueTask<int> GetMetatable(LuaFunctionExecutionContext context, CancellationToken cancellationToken)
     {
     {
         var arg0 = context.GetArgument(0);
         var arg0 = context.GetArgument(0);
 
 
@@ -128,26 +119,26 @@ public sealed class BasicLibrary
         {
         {
             if (table.Metatable == null)
             if (table.Metatable == null)
             {
             {
-                buffer.Span[0] = LuaValue.Nil;
+                context.Return(LuaValue.Nil);
             }
             }
             else if (table.Metatable.TryGetValue(Metamethods.Metatable, out var metatable))
             else if (table.Metatable.TryGetValue(Metamethods.Metatable, out var metatable))
             {
             {
-                buffer.Span[0] = metatable;
+                context.Return(metatable);
             }
             }
             else
             else
             {
             {
-                buffer.Span[0] = table.Metatable;
+                context.Return(table.Metatable);
             }
             }
         }
         }
         else
         else
         {
         {
-            buffer.Span[0] = LuaValue.Nil;
+            context.Return(LuaValue.Nil);
         }
         }
 
 
-        return new(1);
+        return default;
     }
     }
 
 
-    public ValueTask<int> IPairs(LuaFunctionExecutionContext context, Memory<LuaValue> buffer, CancellationToken cancellationToken)
+    public ValueTask<int> IPairs(LuaFunctionExecutionContext context, CancellationToken cancellationToken)
     {
     {
         var arg0 = context.GetArgument<LuaTable>(0);
         var arg0 = context.GetArgument<LuaTable>(0);
 
 
@@ -159,16 +150,13 @@ public sealed class BasicLibrary
                 LuaRuntimeException.AttemptInvalidOperation(context.State.GetTraceback(), "call", metamethod);
                 LuaRuntimeException.AttemptInvalidOperation(context.State.GetTraceback(), "call", metamethod);
             }
             }
 
 
-            return function.InvokeAsync(context, buffer, cancellationToken);
+            return function.InvokeAsync(context, cancellationToken);
         }
         }
 
 
-        buffer.Span[0] = IPairsIterator;
-        buffer.Span[1] = arg0;
-        buffer.Span[2] = 0;
-        return new(3);
+        return new(context.Return(IPairsIterator, arg0, 0));
     }
     }
 
 
-    public async ValueTask<int> LoadFile(LuaFunctionExecutionContext context, Memory<LuaValue> buffer, CancellationToken cancellationToken)
+    public async ValueTask<int> LoadFile(LuaFunctionExecutionContext context, CancellationToken cancellationToken)
     {
     {
         // Lua-CSharp does not support binary chunks, the mode argument is ignored.
         // Lua-CSharp does not support binary chunks, the mode argument is ignored.
         var arg0 = context.GetArgument<string>(0);
         var arg0 = context.GetArgument<string>(0);
@@ -180,20 +168,17 @@ public sealed class BasicLibrary
         try
         try
         {
         {
             var text = await File.ReadAllTextAsync(arg0, cancellationToken);
             var text = await File.ReadAllTextAsync(arg0, cancellationToken);
-            var fileName = Path.GetFileName(arg0);
+            var fileName = "@" + Path.GetFileName(arg0);
             var chunk = LuaCompiler.Default.Compile(text, fileName);
             var chunk = LuaCompiler.Default.Compile(text, fileName);
-            buffer.Span[0] = new LuaClosure(context.State, chunk, arg2);
-            return 1;
+            return context.Return(new LuaClosure(context.State, chunk, arg2));
         }
         }
         catch (Exception ex)
         catch (Exception ex)
         {
         {
-            buffer.Span[0] = LuaValue.Nil;
-            buffer.Span[1] = ex.Message;
-            return 2;
+            return context.Return(LuaValue.Nil, ex.Message);
         }
         }
     }
     }
 
 
-    public ValueTask<int> Load(LuaFunctionExecutionContext context, Memory<LuaValue> buffer, CancellationToken cancellationToken)
+    public ValueTask<int> Load(LuaFunctionExecutionContext context, CancellationToken cancellationToken)
     {
     {
         // Lua-CSharp does not support binary chunks, the mode argument is ignored.
         // Lua-CSharp does not support binary chunks, the mode argument is ignored.
         var arg0 = context.GetArgument(0);
         var arg0 = context.GetArgument(0);
@@ -212,8 +197,7 @@ public sealed class BasicLibrary
             if (arg0.TryRead<string>(out var str))
             if (arg0.TryRead<string>(out var str))
             {
             {
                 var chunk = LuaCompiler.Default.Compile(str, arg1 ?? str);
                 var chunk = LuaCompiler.Default.Compile(str, arg1 ?? str);
-                buffer.Span[0] = new LuaClosure(context.State, chunk, arg3);
-                return new(1);
+                return new(context.Return(new LuaClosure(context.State, chunk, arg3)));
             }
             }
             else if (arg0.TryRead<LuaFunction>(out var function))
             else if (arg0.TryRead<LuaFunction>(out var function))
             {
             {
@@ -228,31 +212,26 @@ public sealed class BasicLibrary
         }
         }
         catch (Exception ex)
         catch (Exception ex)
         {
         {
-            buffer.Span[0] = LuaValue.Nil;
-            buffer.Span[1] = ex.Message;
-            return new(2);
+            return new(context.Return(LuaValue.Nil, ex.Message));
         }
         }
     }
     }
 
 
-    public ValueTask<int> Next(LuaFunctionExecutionContext context, Memory<LuaValue> buffer, CancellationToken cancellationToken)
+    public ValueTask<int> Next(LuaFunctionExecutionContext context, CancellationToken cancellationToken)
     {
     {
         var arg0 = context.GetArgument<LuaTable>(0);
         var arg0 = context.GetArgument<LuaTable>(0);
         var arg1 = context.HasArgument(1) ? context.Arguments[1] : LuaValue.Nil;
         var arg1 = context.HasArgument(1) ? context.Arguments[1] : LuaValue.Nil;
 
 
         if (arg0.TryGetNext(arg1, out var kv))
         if (arg0.TryGetNext(arg1, out var kv))
         {
         {
-            buffer.Span[0] = kv.Key;
-            buffer.Span[1] = kv.Value;
-            return new(2);
+            return new(context.Return(kv.Key, kv.Value));
         }
         }
         else
         else
         {
         {
-            buffer.Span[0] = LuaValue.Nil;
-            return new(1);
+            return new(context.Return(LuaValue.Nil));
         }
         }
     }
     }
 
 
-    public ValueTask<int> Pairs(LuaFunctionExecutionContext context, Memory<LuaValue> buffer, CancellationToken cancellationToken)
+    public ValueTask<int> Pairs(LuaFunctionExecutionContext context, CancellationToken cancellationToken)
     {
     {
         var arg0 = context.GetArgument<LuaTable>(0);
         var arg0 = context.GetArgument<LuaTable>(0);
 
 
@@ -264,115 +243,94 @@ public sealed class BasicLibrary
                 LuaRuntimeException.AttemptInvalidOperation(context.State.GetTraceback(), "call", metamethod);
                 LuaRuntimeException.AttemptInvalidOperation(context.State.GetTraceback(), "call", metamethod);
             }
             }
 
 
-            return function.InvokeAsync(context, buffer, cancellationToken);
+            return function.InvokeAsync(context, cancellationToken);
         }
         }
 
 
-        buffer.Span[0] = PairsIterator;
-        buffer.Span[1] = arg0;
-        buffer.Span[2] = LuaValue.Nil;
-        return new(3);
+        return new(context.Return(PairsIterator, arg0, LuaValue.Nil));
     }
     }
 
 
-    public async ValueTask<int> PCall(LuaFunctionExecutionContext context, Memory<LuaValue> buffer, CancellationToken cancellationToken)
+    public async ValueTask<int> PCall(LuaFunctionExecutionContext context, CancellationToken cancellationToken)
     {
     {
         var arg0 = context.GetArgument<LuaFunction>(0);
         var arg0 = context.GetArgument<LuaFunction>(0);
-
         try
         try
         {
         {
-            using var methodBuffer = new PooledArray<LuaValue>(1024);
+            var count = await arg0.InvokeAsync(context with { State = context.State, ArgumentCount = context.ArgumentCount - 1, FrameBase = context.FrameBase + 1, ReturnFrameBase = context.ReturnFrameBase + 1 }, cancellationToken);
 
 
-            var resultCount = await arg0.InvokeAsync(context with
-            {
-                State = context.State,
-                ArgumentCount = context.ArgumentCount - 1,
-                FrameBase = context.FrameBase + 1,
-            }, methodBuffer.AsMemory(), cancellationToken);
-
-            buffer.Span[0] = true;
-            methodBuffer.AsSpan()[..resultCount].CopyTo(buffer.Span[1..]);
-
-            return resultCount + 1;
+            context.Thread.Stack.Get(context.ReturnFrameBase) = true;
+            return count + 1;
         }
         }
         catch (Exception ex)
         catch (Exception ex)
         {
         {
-            buffer.Span[0] = false;
             if (ex is LuaRuntimeException { ErrorObject: not null } luaEx)
             if (ex is LuaRuntimeException { ErrorObject: not null } luaEx)
             {
             {
-                buffer.Span[1] = luaEx.ErrorObject.Value;
+                return context.Return(false, luaEx.ErrorObject.Value);
             }
             }
             else
             else
             {
             {
-                buffer.Span[1] = ex.Message;
+                return context.Return(false, ex.Message);
             }
             }
-
-            return 2;
         }
         }
     }
     }
 
 
-    public async ValueTask<int> Print(LuaFunctionExecutionContext context, Memory<LuaValue> buffer, CancellationToken cancellationToken)
+    public async ValueTask<int> Print(LuaFunctionExecutionContext context, CancellationToken cancellationToken)
     {
     {
-        using var methodBuffer = new PooledArray<LuaValue>(1);
-
         for (int i = 0; i < context.ArgumentCount; i++)
         for (int i = 0; i < context.ArgumentCount; i++)
         {
         {
-            await context.Arguments[i].CallToStringAsync(context, methodBuffer.AsMemory(), cancellationToken);
-            Console.Write(methodBuffer[0]);
+            var top = context.Thread.Stack.Count;
+            await context.Arguments[i].CallToStringAsync(context, cancellationToken);
+            Console.Write(context.Thread.Stack.Get(top).ToString());
             Console.Write('\t');
             Console.Write('\t');
         }
         }
 
 
         Console.WriteLine();
         Console.WriteLine();
-        return 0;
+        return context.Return();
     }
     }
 
 
-    public ValueTask<int> RawEqual(LuaFunctionExecutionContext context, Memory<LuaValue> buffer, CancellationToken cancellationToken)
+    public ValueTask<int> RawEqual(LuaFunctionExecutionContext context, CancellationToken cancellationToken)
     {
     {
         var arg0 = context.GetArgument(0);
         var arg0 = context.GetArgument(0);
         var arg1 = context.GetArgument(1);
         var arg1 = context.GetArgument(1);
 
 
-        buffer.Span[0] = arg0 == arg1;
-        return new(1);
+        return new(context.Return(arg0 == arg1));
     }
     }
 
 
-    public ValueTask<int> RawGet(LuaFunctionExecutionContext context, Memory<LuaValue> buffer, CancellationToken cancellationToken)
+    public ValueTask<int> RawGet(LuaFunctionExecutionContext context, CancellationToken cancellationToken)
     {
     {
         var arg0 = context.GetArgument<LuaTable>(0);
         var arg0 = context.GetArgument<LuaTable>(0);
         var arg1 = context.GetArgument(1);
         var arg1 = context.GetArgument(1);
-
-        buffer.Span[0] = arg0[arg1];
-        return new(1);
+        return new(context.Return(arg0[arg1]));
     }
     }
 
 
-    public ValueTask<int> RawLen(LuaFunctionExecutionContext context, Memory<LuaValue> buffer, CancellationToken cancellationToken)
+    public ValueTask<int> RawLen(LuaFunctionExecutionContext context, CancellationToken cancellationToken)
     {
     {
         var arg0 = context.GetArgument(0);
         var arg0 = context.GetArgument(0);
 
 
         if (arg0.TryRead<LuaTable>(out var table))
         if (arg0.TryRead<LuaTable>(out var table))
         {
         {
-            buffer.Span[0] = table.ArrayLength;
+            return new(context.Return(table.ArrayLength));
         }
         }
         else if (arg0.TryRead<string>(out var str))
         else if (arg0.TryRead<string>(out var str))
         {
         {
-            buffer.Span[0] = str.Length;
+            return new(context.Return(str.Length));
         }
         }
         else
         else
         {
         {
             LuaRuntimeException.BadArgument(context.State.GetTraceback(), 2, "rawlen", [LuaValueType.String, LuaValueType.Table]);
             LuaRuntimeException.BadArgument(context.State.GetTraceback(), 2, "rawlen", [LuaValueType.String, LuaValueType.Table]);
+            return default;
         }
         }
-
-        return new(1);
     }
     }
 
 
-    public ValueTask<int> RawSet(LuaFunctionExecutionContext context, Memory<LuaValue> buffer, CancellationToken cancellationToken)
+    public ValueTask<int> RawSet(LuaFunctionExecutionContext context, CancellationToken cancellationToken)
     {
     {
         var arg0 = context.GetArgument<LuaTable>(0);
         var arg0 = context.GetArgument<LuaTable>(0);
         var arg1 = context.GetArgument(1);
         var arg1 = context.GetArgument(1);
         var arg2 = context.GetArgument(2);
         var arg2 = context.GetArgument(2);
 
 
         arg0[arg1] = arg2;
         arg0[arg1] = arg2;
-        return new(0);
+        return new(context.Return());
     }
     }
 
 
-    public ValueTask<int> Select(LuaFunctionExecutionContext context, Memory<LuaValue> buffer, CancellationToken cancellationToken)
+    public ValueTask<int> Select(LuaFunctionExecutionContext context, CancellationToken cancellationToken)
     {
     {
         var arg0 = context.GetArgument(0);
         var arg0 = context.GetArgument(0);
 
 
@@ -387,14 +345,11 @@ public sealed class BasicLibrary
                 ? context.Arguments[index..]
                 ? context.Arguments[index..]
                 : context.Arguments[(context.ArgumentCount + index)..];
                 : context.Arguments[(context.ArgumentCount + index)..];
 
 
-            span.CopyTo(buffer.Span);
-
-            return new(span.Length);
+            return new(context.Return(span));
         }
         }
         else if (arg0.TryRead<string>(out var str) && str == "#")
         else if (arg0.TryRead<string>(out var str) && str == "#")
         {
         {
-            buffer.Span[0] = context.ArgumentCount - 1;
-            return new(1);
+            return new(context.Return(context.ArgumentCount - 1));
         }
         }
         else
         else
         {
         {
@@ -403,7 +358,7 @@ public sealed class BasicLibrary
         }
         }
     }
     }
 
 
-    public ValueTask<int> SetMetatable(LuaFunctionExecutionContext context, Memory<LuaValue> buffer, CancellationToken cancellationToken)
+    public ValueTask<int> SetMetatable(LuaFunctionExecutionContext context, CancellationToken cancellationToken)
     {
     {
         var arg0 = context.GetArgument<LuaTable>(0);
         var arg0 = context.GetArgument<LuaTable>(0);
         var arg1 = context.GetArgument(1);
         var arg1 = context.GetArgument(1);
@@ -426,11 +381,11 @@ public sealed class BasicLibrary
             arg0.Metatable = arg1.Read<LuaTable>();
             arg0.Metatable = arg1.Read<LuaTable>();
         }
         }
 
 
-        buffer.Span[0] = arg0;
-        return new(1);
+
+        return new(context.Return(arg0));
     }
     }
 
 
-    public ValueTask<int> ToNumber(LuaFunctionExecutionContext context, Memory<LuaValue> buffer, CancellationToken cancellationToken)
+    public ValueTask<int> ToNumber(LuaFunctionExecutionContext context, CancellationToken cancellationToken)
     {
     {
         var e = context.GetArgument(0);
         var e = context.GetArgument(0);
         int? toBase = context.HasArgument(1)
         int? toBase = context.HasArgument(1)
@@ -477,6 +432,7 @@ public sealed class BasicLibrary
                     {
                     {
                         span = span[1..];
                         span = span[1..];
                     }
                     }
+
                     if (span.Length == 0) goto END;
                     if (span.Length == 0) goto END;
 
 
                     if (toBase == 16 && span.Length > 2 && span[0] is '0' && span[1] is 'x' or 'X')
                     if (toBase == 16 && span.Length > 2 && span[0] is '0' && span[1] is 'x' or 'X')
@@ -500,13 +456,13 @@ public sealed class BasicLibrary
         }
         }
 
 
     END:
     END:
-        if (value != null && double.IsNaN(value.Value))
+        if (value is double.NaN)
         {
         {
             value = null;
             value = null;
         }
         }
 
 
-        buffer.Span[0] = value == null ? LuaValue.Nil : value.Value;
-        return new(1);
+
+        return new(context.Return(value ?? LuaValue.Nil));
     }
     }
 
 
     static double StringToDouble(ReadOnlySpan<char> text, int toBase)
     static double StringToDouble(ReadOnlySpan<char> text, int toBase)
@@ -566,17 +522,18 @@ public sealed class BasicLibrary
         return value;
         return value;
     }
     }
 
 
-    public ValueTask<int> ToString(LuaFunctionExecutionContext context, Memory<LuaValue> buffer, CancellationToken cancellationToken)
+    public ValueTask<int> ToString(LuaFunctionExecutionContext context, CancellationToken cancellationToken)
     {
     {
         var arg0 = context.GetArgument(0);
         var arg0 = context.GetArgument(0);
-        return arg0.CallToStringAsync(context, buffer, cancellationToken);
+        context.Return();
+        return arg0.CallToStringAsync(context, cancellationToken);
     }
     }
 
 
-    public ValueTask<int> Type(LuaFunctionExecutionContext context, Memory<LuaValue> buffer, CancellationToken cancellationToken)
+    public ValueTask<int> Type(LuaFunctionExecutionContext context, CancellationToken cancellationToken)
     {
     {
         var arg0 = context.GetArgument(0);
         var arg0 = context.GetArgument(0);
 
 
-        buffer.Span[0] = arg0.Type switch
+        return new(context.Return(arg0.Type switch
         {
         {
             LuaValueType.Nil => "nil",
             LuaValueType.Nil => "nil",
             LuaValueType.Boolean => "boolean",
             LuaValueType.Boolean => "boolean",
@@ -584,56 +541,35 @@ public sealed class BasicLibrary
             LuaValueType.Number => "number",
             LuaValueType.Number => "number",
             LuaValueType.Function => "function",
             LuaValueType.Function => "function",
             LuaValueType.Thread => "thread",
             LuaValueType.Thread => "thread",
+            LuaValueType.LightUserData => "userdata",
             LuaValueType.UserData => "userdata",
             LuaValueType.UserData => "userdata",
             LuaValueType.Table => "table",
             LuaValueType.Table => "table",
             _ => throw new NotImplementedException(),
             _ => throw new NotImplementedException(),
-        };
-
-        return new(1);
+        }));
     }
     }
 
 
-    public async ValueTask<int> XPCall(LuaFunctionExecutionContext context, Memory<LuaValue> buffer, CancellationToken cancellationToken)
+    public async ValueTask<int> XPCall(LuaFunctionExecutionContext context, CancellationToken cancellationToken)
     {
     {
         var arg0 = context.GetArgument<LuaFunction>(0);
         var arg0 = context.GetArgument<LuaFunction>(0);
         var arg1 = context.GetArgument<LuaFunction>(1);
         var arg1 = context.GetArgument<LuaFunction>(1);
 
 
-        using var methodBuffer = new PooledArray<LuaValue>(1024);
-        methodBuffer.AsSpan().Clear();
-
         try
         try
         {
         {
-            var resultCount = await arg0.InvokeAsync(context with
-            {
-                State = context.State,
-                ArgumentCount = context.ArgumentCount - 2,
-                FrameBase = context.FrameBase + 2,
-            }, methodBuffer.AsMemory(), cancellationToken);
-
-            buffer.Span[0] = true;
-            methodBuffer.AsSpan()[..resultCount].CopyTo(buffer.Span[1..]);
+            var count = await arg0.InvokeAsync(context with { State = context.State, ArgumentCount = context.ArgumentCount - 2, FrameBase = context.FrameBase + 2, ReturnFrameBase = context.ReturnFrameBase + 1 }, cancellationToken);
 
 
-            return resultCount + 1;
+            context.Thread.Stack.Get(context.ReturnFrameBase) = true;
+            return count + 1;
         }
         }
         catch (Exception ex)
         catch (Exception ex)
         {
         {
-            methodBuffer.AsSpan().Clear();
             var error = ex is LuaRuntimeException { ErrorObject: not null } luaEx ? luaEx.ErrorObject.Value : ex.Message;
             var error = ex is LuaRuntimeException { ErrorObject: not null } luaEx ? luaEx.ErrorObject.Value : ex.Message;
 
 
             context.State.Push(error);
             context.State.Push(error);
 
 
             // invoke error handler
             // invoke error handler
-            await arg1.InvokeAsync(context with
-            {
-                State = context.State,
-                ArgumentCount = 1,
-                FrameBase = context.Thread.Stack.Count - 1,
-            }, methodBuffer.AsMemory(), cancellationToken);
-
-            buffer.Span[0] = false;
-            buffer.Span[1] = methodBuffer[0];
-
-
-            return 2;
+            var count = await arg1.InvokeAsync(context with { State = context.State, ArgumentCount = 1, FrameBase = context.Thread.Stack.Count - 1, ReturnFrameBase = context.ReturnFrameBase + 1 }, cancellationToken);
+            context.Thread.Stack.Get(context.ReturnFrameBase) = false;
+            return count + 1;
         }
         }
     }
     }
 }
 }

+ 35 - 47
src/Lua/Standard/BitwiseLibrary.cs

@@ -8,7 +8,8 @@ public sealed class BitwiseLibrary
 
 
     public BitwiseLibrary()
     public BitwiseLibrary()
     {
     {
-        Functions = [
+        Functions =
+        [
             new("arshift", ArShift),
             new("arshift", ArShift),
             new("band", BAnd),
             new("band", BAnd),
             new("bnot", BNot),
             new("bnot", BNot),
@@ -26,7 +27,7 @@ public sealed class BitwiseLibrary
 
 
     public readonly LuaFunction[] Functions;
     public readonly LuaFunction[] Functions;
 
 
-    public ValueTask<int> ArShift(LuaFunctionExecutionContext context, Memory<LuaValue> buffer, CancellationToken cancellationToken)
+    public ValueTask<int> ArShift(LuaFunctionExecutionContext context, CancellationToken cancellationToken)
     {
     {
         var x = context.GetArgument<double>(0);
         var x = context.GetArgument<double>(0);
         var disp = context.GetArgument<double>(1);
         var disp = context.GetArgument<double>(1);
@@ -46,16 +47,15 @@ public sealed class BitwiseLibrary
             v >>= a;
             v >>= a;
         }
         }
 
 
-        buffer.Span[0] = (uint)v;
-        return new(1);
+        return new(context.Return((uint)v));
     }
     }
 
 
-    public ValueTask<int> BAnd(LuaFunctionExecutionContext context, Memory<LuaValue> buffer, CancellationToken cancellationToken)
+    public ValueTask<int> BAnd(LuaFunctionExecutionContext context, CancellationToken cancellationToken)
     {
     {
         if (context.ArgumentCount == 0)
         if (context.ArgumentCount == 0)
         {
         {
-            buffer.Span[0] = uint.MaxValue;
-            return new(1);
+            context.Return(uint.MaxValue);
+            return default;
         }
         }
 
 
         var arg0 = context.GetArgument<double>(0);
         var arg0 = context.GetArgument<double>(0);
@@ -72,26 +72,24 @@ public sealed class BitwiseLibrary
             value &= v;
             value &= v;
         }
         }
 
 
-        buffer.Span[0] = value;
-        return new(1);
+
+        return new(context.Return(value));
     }
     }
 
 
-    public ValueTask<int> BNot(LuaFunctionExecutionContext context, Memory<LuaValue> buffer, CancellationToken cancellationToken)
+    public ValueTask<int> BNot(LuaFunctionExecutionContext context, CancellationToken cancellationToken)
     {
     {
         var arg0 = context.GetArgument<double>(0);
         var arg0 = context.GetArgument<double>(0);
         LuaRuntimeException.ThrowBadArgumentIfNumberIsNotInteger(context.State, "bnot", 1, arg0);
         LuaRuntimeException.ThrowBadArgumentIfNumberIsNotInteger(context.State, "bnot", 1, arg0);
 
 
         var value = Bit32Helper.ToUInt32(arg0);
         var value = Bit32Helper.ToUInt32(arg0);
-        buffer.Span[0] = ~value;
-        return new(1);
+        return new(context.Return(~value));
     }
     }
 
 
-    public ValueTask<int> BOr(LuaFunctionExecutionContext context, Memory<LuaValue> buffer, CancellationToken cancellationToken)
+    public ValueTask<int> BOr(LuaFunctionExecutionContext context, CancellationToken cancellationToken)
     {
     {
         if (context.ArgumentCount == 0)
         if (context.ArgumentCount == 0)
         {
         {
-            buffer.Span[0] = 0;
-            return new(1);
+            return new(context.Return(0));
         }
         }
 
 
         var arg0 = context.GetArgument<double>(0);
         var arg0 = context.GetArgument<double>(0);
@@ -108,16 +106,15 @@ public sealed class BitwiseLibrary
             value |= v;
             value |= v;
         }
         }
 
 
-        buffer.Span[0] = value;
-        return new(1);
+        return new(context.Return(value));
     }
     }
 
 
-    public ValueTask<int> BTest(LuaFunctionExecutionContext context, Memory<LuaValue> buffer, CancellationToken cancellationToken)
+    public ValueTask<int> BTest(LuaFunctionExecutionContext context, CancellationToken cancellationToken)
     {
     {
         if (context.ArgumentCount == 0)
         if (context.ArgumentCount == 0)
         {
         {
-            buffer.Span[0] = true;
-            return new(1);
+            ;
+            return new(context.Return(true));
         }
         }
 
 
         var arg0 = context.GetArgument<double>(0);
         var arg0 = context.GetArgument<double>(0);
@@ -134,16 +131,14 @@ public sealed class BitwiseLibrary
             value &= v;
             value &= v;
         }
         }
 
 
-        buffer.Span[0] = value != 0;
-        return new(1);
+        return new(context.Return(value != 0));
     }
     }
 
 
-    public ValueTask<int> BXor(LuaFunctionExecutionContext context, Memory<LuaValue> buffer, CancellationToken cancellationToken)
+    public ValueTask<int> BXor(LuaFunctionExecutionContext context, CancellationToken cancellationToken)
     {
     {
         if (context.ArgumentCount == 0)
         if (context.ArgumentCount == 0)
         {
         {
-            buffer.Span[0] = 0;
-            return new(1);
+            return new(context.Return(0));
         }
         }
 
 
         var arg0 = context.GetArgument<double>(0);
         var arg0 = context.GetArgument<double>(0);
@@ -160,11 +155,10 @@ public sealed class BitwiseLibrary
             value ^= v;
             value ^= v;
         }
         }
 
 
-        buffer.Span[0] = value;
-        return new(1);
+        return new(context.Return(value));
     }
     }
 
 
-    public ValueTask<int> Extract(LuaFunctionExecutionContext context, Memory<LuaValue> buffer, CancellationToken cancellationToken)
+    public ValueTask<int> Extract(LuaFunctionExecutionContext context, CancellationToken cancellationToken)
     {
     {
         var arg0 = context.GetArgument<double>(0);
         var arg0 = context.GetArgument<double>(0);
         var arg1 = context.GetArgument<double>(1);
         var arg1 = context.GetArgument<double>(1);
@@ -184,18 +178,16 @@ public sealed class BitwiseLibrary
 
 
         if (field == 0 && width == 32)
         if (field == 0 && width == 32)
         {
         {
-            buffer.Span[0] = n;
+            return new(context.Return(n));
         }
         }
         else
         else
         {
         {
             var mask = (uint)((1 << width) - 1);
             var mask = (uint)((1 << width) - 1);
-            buffer.Span[0] = (n >> field) & mask;
+            return new(context.Return((n >> field) & mask));
         }
         }
-
-        return new(1);
     }
     }
 
 
-    public ValueTask<int> LRotate(LuaFunctionExecutionContext context, Memory<LuaValue> buffer, CancellationToken cancellationToken)
+    public ValueTask<int> LRotate(LuaFunctionExecutionContext context, CancellationToken cancellationToken)
     {
     {
         var x = context.GetArgument<double>(0);
         var x = context.GetArgument<double>(0);
         var disp = context.GetArgument<double>(1);
         var disp = context.GetArgument<double>(1);
@@ -215,11 +207,11 @@ public sealed class BitwiseLibrary
             v = (v << a) | (v >> (32 - a));
             v = (v << a) | (v >> (32 - a));
         }
         }
 
 
-        buffer.Span[0] = v;
-        return new(1);
+        ;
+        return new(context.Return(v));
     }
     }
 
 
-    public ValueTask<int> LShift(LuaFunctionExecutionContext context, Memory<LuaValue> buffer, CancellationToken cancellationToken)
+    public ValueTask<int> LShift(LuaFunctionExecutionContext context, CancellationToken cancellationToken)
     {
     {
         var x = context.GetArgument<double>(0);
         var x = context.GetArgument<double>(0);
         var disp = context.GetArgument<double>(1);
         var disp = context.GetArgument<double>(1);
@@ -243,11 +235,10 @@ public sealed class BitwiseLibrary
             v <<= a;
             v <<= a;
         }
         }
 
 
-        buffer.Span[0] = v;
-        return new(1);
+        return new(context.Return(v));
     }
     }
 
 
-    public ValueTask<int> Replace(LuaFunctionExecutionContext context, Memory<LuaValue> buffer, CancellationToken cancellationToken)
+    public ValueTask<int> Replace(LuaFunctionExecutionContext context, CancellationToken cancellationToken)
     {
     {
         var arg0 = context.GetArgument<double>(0);
         var arg0 = context.GetArgument<double>(0);
         var arg1 = context.GetArgument<double>(1);
         var arg1 = context.GetArgument<double>(1);
@@ -279,11 +270,10 @@ public sealed class BitwiseLibrary
 
 
         v = v & mask;
         v = v & mask;
         n = (n & ~(mask << field)) | (v << field);
         n = (n & ~(mask << field)) | (v << field);
-        buffer.Span[0] = n;
-        return new(1);
+        return new(context.Return(n));
     }
     }
 
 
-    public ValueTask<int> RRotate(LuaFunctionExecutionContext context, Memory<LuaValue> buffer, CancellationToken cancellationToken)
+    public ValueTask<int> RRotate(LuaFunctionExecutionContext context, CancellationToken cancellationToken)
     {
     {
         var x = context.GetArgument<double>(0);
         var x = context.GetArgument<double>(0);
         var disp = context.GetArgument<double>(1);
         var disp = context.GetArgument<double>(1);
@@ -303,11 +293,10 @@ public sealed class BitwiseLibrary
             v = (v >> a) | (v << (32 - a));
             v = (v >> a) | (v << (32 - a));
         }
         }
 
 
-        buffer.Span[0] = v;
-        return new(1);
+        return new(context.Return(v));
     }
     }
 
 
-    public ValueTask<int> RShift(LuaFunctionExecutionContext context, Memory<LuaValue> buffer, CancellationToken cancellationToken)
+    public ValueTask<int> RShift(LuaFunctionExecutionContext context, CancellationToken cancellationToken)
     {
     {
         var x = context.GetArgument<double>(0);
         var x = context.GetArgument<double>(0);
         var disp = context.GetArgument<double>(1);
         var disp = context.GetArgument<double>(1);
@@ -331,7 +320,6 @@ public sealed class BitwiseLibrary
             v >>= a;
             v >>= a;
         }
         }
 
 
-        buffer.Span[0] = v;
-        return new(1);
+        return new(context.Return(v));
     }
     }
 }
 }

+ 39 - 52
src/Lua/Standard/CoroutineLibrary.cs

@@ -8,7 +8,8 @@ public sealed class CoroutineLibrary
 
 
     public CoroutineLibrary()
     public CoroutineLibrary()
     {
     {
-        Functions = [
+        Functions =
+        [
             new("create", Create),
             new("create", Create),
             new("resume", Resume),
             new("resume", Resume),
             new("running", Running),
             new("running", Running),
@@ -20,87 +21,73 @@ public sealed class CoroutineLibrary
 
 
     public readonly LuaFunction[] Functions;
     public readonly LuaFunction[] Functions;
 
 
-    public ValueTask<int> Create(LuaFunctionExecutionContext context, Memory<LuaValue> buffer, CancellationToken cancellationToken)
+    public ValueTask<int> Create(LuaFunctionExecutionContext context, CancellationToken cancellationToken)
     {
     {
         var arg0 = context.GetArgument<LuaFunction>(0);
         var arg0 = context.GetArgument<LuaFunction>(0);
-        buffer.Span[0] = new LuaCoroutine(arg0, true);
-        return new(1);
+        return new(context.Return(new LuaCoroutine(arg0, true)));
     }
     }
 
 
-    public ValueTask<int> Resume(LuaFunctionExecutionContext context, Memory<LuaValue> buffer, CancellationToken cancellationToken)
+    public ValueTask<int> Resume(LuaFunctionExecutionContext context, CancellationToken cancellationToken)
     {
     {
         var thread = context.GetArgument<LuaThread>(0);
         var thread = context.GetArgument<LuaThread>(0);
-        return thread.ResumeAsync(context, buffer, cancellationToken);
+        return thread.ResumeAsync(context, cancellationToken);
     }
     }
 
 
-    public ValueTask<int> Running(LuaFunctionExecutionContext context, Memory<LuaValue> buffer, CancellationToken cancellationToken)
+    public ValueTask<int> Running(LuaFunctionExecutionContext context, CancellationToken cancellationToken)
     {
     {
-        buffer.Span[0] = context.Thread;
-        buffer.Span[1] = context.Thread == context.State.MainThread;
-        return new(2);
+        return new(context.Return(context.Thread, context.Thread == context.State.MainThread));
     }
     }
 
 
-    public ValueTask<int> Status(LuaFunctionExecutionContext context, Memory<LuaValue> buffer, CancellationToken cancellationToken)
+    public ValueTask<int> Status(LuaFunctionExecutionContext context, CancellationToken cancellationToken)
     {
     {
         var thread = context.GetArgument<LuaThread>(0);
         var thread = context.GetArgument<LuaThread>(0);
-        buffer.Span[0] = thread.GetStatus() switch
+        return new(context.Return(thread.GetStatus() switch
         {
         {
             LuaThreadStatus.Normal => "normal",
             LuaThreadStatus.Normal => "normal",
             LuaThreadStatus.Suspended => "suspended",
             LuaThreadStatus.Suspended => "suspended",
             LuaThreadStatus.Running => "running",
             LuaThreadStatus.Running => "running",
             LuaThreadStatus.Dead => "dead",
             LuaThreadStatus.Dead => "dead",
             _ => "",
             _ => "",
-        };
-        return new(1);
+        }));
     }
     }
 
 
-    public ValueTask<int> Wrap(LuaFunctionExecutionContext context, Memory<LuaValue> buffer, CancellationToken cancellationToken)
+
+    public ValueTask<int> Wrap(LuaFunctionExecutionContext context, CancellationToken cancellationToken)
     {
     {
         var arg0 = context.GetArgument<LuaFunction>(0);
         var arg0 = context.GetArgument<LuaFunction>(0);
         var thread = new LuaCoroutine(arg0, false);
         var thread = new LuaCoroutine(arg0, false);
-
-        buffer.Span[0] = new CSharpClosure("wrap", [thread],static async (context, buffer, cancellationToken) =>
-        {
-            var thread = context.GetCsClosure()!.UpValues[0].Read<LuaThread>();
-            if (thread is not LuaCoroutine coroutine)
-            {
-                return await thread.ResumeAsync(context, buffer, cancellationToken);
-            }
-            var stack = context.Thread.Stack;
-            var frameBase = stack.Count;
-
-            stack.Push(thread);
-            stack.PushRange(context.Arguments);
-            context.Thread.PushCallStackFrame(new()
+        return new(context.Return(new CSharpClosure("wrap", [thread],
+            static async (context, cancellationToken) =>
             {
             {
-                Base = frameBase,
-                VariableArgumentCount = 0,
-                Function = coroutine.Function,
-            });
-            try
-            {
-                var resultCount = await thread.ResumeAsync(context with
+                var thread = context.GetCsClosure()!.UpValues[0].Read<LuaThread>();
+                if (thread is not LuaCoroutine coroutine)
                 {
                 {
-                    ArgumentCount = context.ArgumentCount + 1,
-                    FrameBase = frameBase,
-                }, buffer, cancellationToken);
-
-                buffer.Span[1..].CopyTo(buffer.Span[0..]);
-                return resultCount - 1;
-            }
-            finally
-            {
-                context.Thread.PopCallStackFrame();
-            }
+                    return await thread.ResumeAsync(context, cancellationToken);
+                }
 
 
-           
-        });
+                var stack = context.Thread.Stack;
+                var frameBase = stack.Count;
 
 
-        return new(1);
+                stack.Push(thread);
+                stack.PushRange(context.Arguments);
+                context.Thread.PushCallStackFrame(new() { Base = frameBase, ReturnBase = context.ReturnFrameBase, VariableArgumentCount = 0, Function = coroutine.Function });
+                try
+                {
+                    await thread.ResumeAsync(context with { ArgumentCount = context.ArgumentCount + 1, FrameBase = frameBase, ReturnFrameBase = context.ReturnFrameBase, }, cancellationToken);
+                    var result = context.GetReturnBuffer(context.Thread.Stack.Count - context.ReturnFrameBase);
+                    result[1..].CopyTo(result);
+                    context.Thread.Stack.Pop();
+                    return result.Length - 1;
+                }
+                finally
+                {
+                    context.Thread.PopCallStackFrame();
+                }
+            })));
     }
     }
 
 
-    public ValueTask<int> Yield(LuaFunctionExecutionContext context, Memory<LuaValue> buffer, CancellationToken cancellationToken)
+    public ValueTask<int> Yield(LuaFunctionExecutionContext context, CancellationToken cancellationToken)
     {
     {
-        return context.Thread.YieldAsync(context, buffer, cancellationToken);
+        return context.Thread.YieldAsync(context, cancellationToken);
     }
     }
 }
 }

+ 61 - 103
src/Lua/Standard/DebugLibrary.cs

@@ -124,7 +124,7 @@ public class DebugLibrary
         return ref thread.Stack.Get(frameBase + index);
         return ref thread.Stack.Get(frameBase + index);
     }
     }
 
 
-    public ValueTask<int> GetLocal(LuaFunctionExecutionContext context, Memory<LuaValue> buffer, CancellationToken cancellationToken)
+    public ValueTask<int> GetLocal(LuaFunctionExecutionContext context, CancellationToken cancellationToken)
     {
     {
         static LuaValue GetParam(LuaFunction function, int index)
         static LuaValue GetParam(LuaFunction function, int index)
         {
         {
@@ -145,8 +145,7 @@ public class DebugLibrary
         var index = context.GetArgument<int>(argOffset + 1);
         var index = context.GetArgument<int>(argOffset + 1);
         if (context.GetArgument(argOffset).TryReadFunction(out var f))
         if (context.GetArgument(argOffset).TryReadFunction(out var f))
         {
         {
-            buffer.Span[0] = GetParam(f, index - 1);
-            return new(1);
+            return new(context.Return(GetParam(f, index - 1)));
         }
         }
 
 
         var level = context.GetArgument<int>(argOffset);
         var level = context.GetArgument<int>(argOffset);
@@ -160,16 +159,13 @@ public class DebugLibrary
         ref var local = ref FindLocal(thread, level, index, out var name);
         ref var local = ref FindLocal(thread, level, index, out var name);
         if (name is null)
         if (name is null)
         {
         {
-            buffer.Span[0] = LuaValue.Nil;
-            return new(1);
+            return new(context.Return(LuaValue.Nil));
         }
         }
 
 
-        buffer.Span[0] = name;
-        buffer.Span[1] = local;
-        return new(2);
+        return new(context.Return(name, local));
     }
     }
 
 
-    public ValueTask<int> SetLocal(LuaFunctionExecutionContext context, Memory<LuaValue> buffer, CancellationToken cancellationToken)
+    public ValueTask<int> SetLocal(LuaFunctionExecutionContext context, CancellationToken cancellationToken)
     {
     {
         var thread = GetLuaThread(context, out var argOffset);
         var thread = GetLuaThread(context, out var argOffset);
 
 
@@ -186,16 +182,14 @@ public class DebugLibrary
         ref var local = ref FindLocal(thread, level, index, out var name);
         ref var local = ref FindLocal(thread, level, index, out var name);
         if (name is null)
         if (name is null)
         {
         {
-            buffer.Span[0] = LuaValue.Nil;
-            return new(1);
+            return new(context.Return(LuaValue.Nil));
         }
         }
 
 
-        buffer.Span[0] = name;
         local = value;
         local = value;
-        return new(1);
+        return new(context.Return(name));
     }
     }
 
 
-    public ValueTask<int> GetUpValue(LuaFunctionExecutionContext context, Memory<LuaValue> buffer, CancellationToken cancellationToken)
+    public ValueTask<int> GetUpValue(LuaFunctionExecutionContext context, CancellationToken cancellationToken)
     {
     {
         var func = context.GetArgument<LuaFunction>(0);
         var func = context.GetArgument<LuaFunction>(0);
         var index = context.GetArgument<int>(1) - 1;
         var index = context.GetArgument<int>(1) - 1;
@@ -206,15 +200,13 @@ public class DebugLibrary
                 var upValues = csClosure.UpValues;
                 var upValues = csClosure.UpValues;
                 if (index < 0 || index >= upValues.Length)
                 if (index < 0 || index >= upValues.Length)
                 {
                 {
-                    return new(0);
+                    return new(context.Return());
                 }
                 }
 
 
-                buffer.Span[0] = "";
-                buffer.Span[1] = upValues[index];
-                return new(1);
+                return new(context.Return("", upValues[index]));
             }
             }
 
 
-            return new(0);
+            return new(context.Return());
         }
         }
 
 
         {
         {
@@ -222,17 +214,15 @@ public class DebugLibrary
             var descriptions = closure.Proto.UpValues;
             var descriptions = closure.Proto.UpValues;
             if (index < 0 || index >= descriptions.Length)
             if (index < 0 || index >= descriptions.Length)
             {
             {
-                return new(0);
+                return new(context.Return());
             }
             }
 
 
             var description = descriptions[index];
             var description = descriptions[index];
-            buffer.Span[0] = description.Name.ToString();
-            buffer.Span[1] = upValues[index].GetValue();
-            return new(2);
+            return new(context.Return(description.Name.ToString(), upValues[index].GetValue()));
         }
         }
     }
     }
 
 
-    public ValueTask<int> SetUpValue(LuaFunctionExecutionContext context, Memory<LuaValue> buffer, CancellationToken cancellationToken)
+    public ValueTask<int> SetUpValue(LuaFunctionExecutionContext context, CancellationToken cancellationToken)
     {
     {
         var func = context.GetArgument<LuaFunction>(0);
         var func = context.GetArgument<LuaFunction>(0);
         var index = context.GetArgument<int>(1) - 1;
         var index = context.GetArgument<int>(1) - 1;
@@ -244,15 +234,12 @@ public class DebugLibrary
                 var upValues = csClosure.UpValues;
                 var upValues = csClosure.UpValues;
                 if (index >= 0 && index < upValues.Length)
                 if (index >= 0 && index < upValues.Length)
                 {
                 {
-                    buffer.Span[0] = "";
                     upValues[index] = value;
                     upValues[index] = value;
-                    return new(0);
+                    return new(context.Return(""));
                 }
                 }
-
-                return new(0);
             }
             }
 
 
-            return new(0);
+            return new(context.Return());
         }
         }
 
 
         {
         {
@@ -260,33 +247,30 @@ public class DebugLibrary
             var descriptions = closure.Proto.UpValues;
             var descriptions = closure.Proto.UpValues;
             if (index < 0 || index >= descriptions.Length)
             if (index < 0 || index >= descriptions.Length)
             {
             {
-                return new(0);
+                return new(context.Return());
             }
             }
 
 
             var description = descriptions[index];
             var description = descriptions[index];
-            buffer.Span[0] = description.Name.ToString();
             upValues[index].SetValue(value);
             upValues[index].SetValue(value);
-            return new(1);
+            return new(context.Return(description.Name.ToString()));
         }
         }
     }
     }
 
 
-    public ValueTask<int> GetMetatable(LuaFunctionExecutionContext context, Memory<LuaValue> buffer, CancellationToken cancellationToken)
+    public ValueTask<int> GetMetatable(LuaFunctionExecutionContext context, CancellationToken cancellationToken)
     {
     {
         var arg0 = context.GetArgument(0);
         var arg0 = context.GetArgument(0);
 
 
         if (context.State.TryGetMetatable(arg0, out var table))
         if (context.State.TryGetMetatable(arg0, out var table))
         {
         {
-            buffer.Span[0] = table;
+            return new(context.Return(table));
         }
         }
         else
         else
         {
         {
-            buffer.Span[0] = LuaValue.Nil;
+            return new(context.Return(LuaValue.Nil));
         }
         }
-
-        return new(1);
     }
     }
 
 
-    public ValueTask<int> SetMetatable(LuaFunctionExecutionContext context, Memory<LuaValue> buffer, CancellationToken cancellationToken)
+    public ValueTask<int> SetMetatable(LuaFunctionExecutionContext context, CancellationToken cancellationToken)
     {
     {
         var arg0 = context.GetArgument(0);
         var arg0 = context.GetArgument(0);
         var arg1 = context.GetArgument(1);
         var arg1 = context.GetArgument(1);
@@ -298,16 +282,14 @@ public class DebugLibrary
 
 
         context.State.SetMetatable(arg0, arg1.UnsafeRead<LuaTable>());
         context.State.SetMetatable(arg0, arg1.UnsafeRead<LuaTable>());
 
 
-        buffer.Span[0] = arg0;
-        return new(1);
+        return new(context.Return(arg0));
     }
     }
 
 
-    public ValueTask<int> GetUserValue(LuaFunctionExecutionContext context, Memory<LuaValue> buffer, CancellationToken cancellationToken)
+    public ValueTask<int> GetUserValue(LuaFunctionExecutionContext context, CancellationToken cancellationToken)
     {
     {
         if (!context.GetArgumentOrDefault(0).TryRead<ILuaUserData>(out var iUserData))
         if (!context.GetArgumentOrDefault(0).TryRead<ILuaUserData>(out var iUserData))
         {
         {
-            buffer.Span[0] = LuaValue.Nil;
-            return new(1);
+            return new(context.Return(LuaValue.Nil));
         }
         }
 
 
         var index = 1; // context.GetArgument<int>(1); //for lua 5.4
         var index = 1; // context.GetArgument<int>(1); //for lua 5.4
@@ -316,15 +298,13 @@ public class DebugLibrary
             //index < 1 ||  // for lua 5.4
             //index < 1 ||  // for lua 5.4
            )
            )
         {
         {
-            buffer.Span[0] = LuaValue.Nil;
-            return new(1);
+            return new(context.Return(LuaValue.Nil));
         }
         }
 
 
-        buffer.Span[0] = userValues[index - 1];
-        return new(1);
+        return new(context.Return(userValues[index - 1]));
     }
     }
 
 
-    public ValueTask<int> SetUserValue(LuaFunctionExecutionContext context, Memory<LuaValue> buffer, CancellationToken cancellationToken)
+    public ValueTask<int> SetUserValue(LuaFunctionExecutionContext context, CancellationToken cancellationToken)
     {
     {
         var iUserData = context.GetArgument<ILuaUserData>(0);
         var iUserData = context.GetArgument<ILuaUserData>(0);
         var value = context.GetArgument(1);
         var value = context.GetArgument(1);
@@ -334,16 +314,14 @@ public class DebugLibrary
             //|| index < 1 // for lua 5.4
             //|| index < 1 // for lua 5.4
            )
            )
         {
         {
-            buffer.Span[0] = LuaValue.Nil;
-            return new(1);
+            return new(context.Return(LuaValue.Nil));
         }
         }
 
 
         userValues[index - 1] = value;
         userValues[index - 1] = value;
-        buffer.Span[0] = new LuaValue(iUserData);
-        return new(1);
+        return new(context.Return(new LuaValue(iUserData)));
     }
     }
 
 
-    public ValueTask<int> Traceback(LuaFunctionExecutionContext context, Memory<LuaValue> buffer, CancellationToken cancellationToken)
+    public ValueTask<int> Traceback(LuaFunctionExecutionContext context, CancellationToken cancellationToken)
     {
     {
         var thread = GetLuaThread(context, out var argOffset);
         var thread = GetLuaThread(context, out var argOffset);
 
 
@@ -352,67 +330,58 @@ public class DebugLibrary
 
 
         if (message.Type is not (LuaValueType.Nil or LuaValueType.String or LuaValueType.Number))
         if (message.Type is not (LuaValueType.Nil or LuaValueType.String or LuaValueType.Number))
         {
         {
-            buffer.Span[0] = message;
-            return new(1);
+            return new(context.Return(message));
         }
         }
 
 
         if (level < 0)
         if (level < 0)
         {
         {
-            buffer.Span[0] = LuaValue.Nil;
-            return new(1);
+            return new(context.Return(LuaValue.Nil));
         }
         }
 
 
         if (thread is LuaCoroutine coroutine)
         if (thread is LuaCoroutine coroutine)
         {
         {
             if (coroutine.LuaTraceback is not null)
             if (coroutine.LuaTraceback is not null)
             {
             {
-                buffer.Span[0] = coroutine.LuaTraceback.ToString(level);
-                return new(1);
+                return new(context.Return(coroutine.LuaTraceback.ToString(level)));
             }
             }
         }
         }
 
 
         var callStack = thread.GetCallStackFrames();
         var callStack = thread.GetCallStackFrames();
         if (callStack.Length == 0)
         if (callStack.Length == 0)
         {
         {
-            buffer.Span[0] = "stack traceback:";
-            return new(1);
+            return new(context.Return("stack traceback:"));
         }
         }
 
 
         var skipCount = Math.Min(Math.Max(level - 1, 0), callStack.Length - 1);
         var skipCount = Math.Min(Math.Max(level - 1, 0), callStack.Length - 1);
         var frames = callStack[1..^skipCount];
         var frames = callStack[1..^skipCount];
-        buffer.Span[0] = Runtime.Traceback.GetTracebackString(context.State, (LuaClosure)callStack[0].Function, frames, message, level == 1);
-        return new(1);
+        return new(context.Return(Runtime.Traceback.GetTracebackString(context.State, (LuaClosure)callStack[0].Function, frames, message, level == 1)));
     }
     }
 
 
-    public ValueTask<int> GetRegistry(LuaFunctionExecutionContext context, Memory<LuaValue> buffer, CancellationToken cancellationToken)
+    public ValueTask<int> GetRegistry(LuaFunctionExecutionContext context, CancellationToken cancellationToken)
     {
     {
-        buffer.Span[0] = context.State.Registry;
-        return new(1);
+        return new(context.Return(context.State.Registry));
     }
     }
 
 
-    public ValueTask<int> UpValueId(LuaFunctionExecutionContext context, Memory<LuaValue> buffer, CancellationToken cancellationToken)
+    public ValueTask<int> UpValueId(LuaFunctionExecutionContext context, CancellationToken cancellationToken)
     {
     {
         var n1 = context.GetArgument<int>(1);
         var n1 = context.GetArgument<int>(1);
         var f1 = context.GetArgument<LuaFunction>(0);
         var f1 = context.GetArgument<LuaFunction>(0);
 
 
         if (f1 is not LuaClosure closure)
         if (f1 is not LuaClosure closure)
         {
         {
-            buffer.Span[0] = LuaValue.Nil;
-            return new(1);
+            return new(context.Return(LuaValue.Nil));
         }
         }
 
 
         var upValues = closure.GetUpValuesSpan();
         var upValues = closure.GetUpValuesSpan();
         if (n1 <= 0 || n1 > upValues.Length)
         if (n1 <= 0 || n1 > upValues.Length)
         {
         {
-            buffer.Span[0] = LuaValue.Nil;
-            return new(1);
+            return new(context.Return(LuaValue.Nil));
         }
         }
 
 
-        buffer.Span[0] = new LuaValue(upValues[n1 - 1]);
-        return new(1);
+        return new(context.Return(new LuaValue(upValues[n1 - 1])));
     }
     }
 
 
-    public ValueTask<int> UpValueJoin(LuaFunctionExecutionContext context, Memory<LuaValue> buffer, CancellationToken cancellationToken)
+    public ValueTask<int> UpValueJoin(LuaFunctionExecutionContext context, CancellationToken cancellationToken)
     {
     {
         var n2 = context.GetArgument<int>(3);
         var n2 = context.GetArgument<int>(3);
         var f2 = context.GetArgument<LuaFunction>(2);
         var f2 = context.GetArgument<LuaFunction>(2);
@@ -421,8 +390,7 @@ public class DebugLibrary
 
 
         if (f1 is not LuaClosure closure1 || f2 is not LuaClosure closure2)
         if (f1 is not LuaClosure closure1 || f2 is not LuaClosure closure2)
         {
         {
-            buffer.Span[0] = LuaValue.Nil;
-            return new(1);
+            return new(context.Return(LuaValue.Nil));
         }
         }
 
 
         var upValues1 = closure1.GetUpValuesSpan();
         var upValues1 = closure1.GetUpValuesSpan();
@@ -441,7 +409,7 @@ public class DebugLibrary
         return new(0);
         return new(0);
     }
     }
 
 
-    public async ValueTask<int> SetHook(LuaFunctionExecutionContext context, Memory<LuaValue> buffer, CancellationToken cancellationToken)
+    public async ValueTask<int> SetHook(LuaFunctionExecutionContext context, CancellationToken cancellationToken)
     {
     {
         var thread = GetLuaThread(context, out var argOffset);
         var thread = GetLuaThread(context, out var argOffset);
         LuaFunction? hook = context.GetArgumentOrDefault<LuaFunction?>(argOffset);
         LuaFunction? hook = context.GetArgumentOrDefault<LuaFunction?>(argOffset);
@@ -496,54 +464,49 @@ public class DebugLibrary
                 Thread = context.Thread,
                 Thread = context.Thread,
                 ArgumentCount = 2,
                 ArgumentCount = 2,
                 FrameBase = stack.Count - 2,
                 FrameBase = stack.Count - 2,
+                ReturnFrameBase = stack.Count - 2,
             };
             };
             var frame = new CallStackFrame
             var frame = new CallStackFrame
             {
             {
-                Base = funcContext.FrameBase,
-                VariableArgumentCount = hook.GetVariableArgumentCount(2),
-                Function = hook,
+                Base = funcContext.FrameBase, ReturnBase = funcContext.ReturnFrameBase, VariableArgumentCount = hook.GetVariableArgumentCount(2), Function = hook,
             };
             };
             frame.Flags |= CallStackFrameFlags.InHook;
             frame.Flags |= CallStackFrameFlags.InHook;
             thread.PushCallStackFrame(frame);
             thread.PushCallStackFrame(frame);
             try
             try
             {
             {
                 thread.IsInHook = true;
                 thread.IsInHook = true;
-                await hook.Func(funcContext, Memory<LuaValue>.Empty, cancellationToken);
+                await hook.Func(funcContext, cancellationToken);
             }
             }
             finally
             finally
             {
             {
                 thread.IsInHook = false;
                 thread.IsInHook = false;
             }
             }
 
 
-            thread.PopCallStackFrame();
+            thread.PopCallStackFrameWithStackPop();
         }
         }
 
 
         return 0;
         return 0;
     }
     }
 
 
 
 
-    public ValueTask<int> GetHook(LuaFunctionExecutionContext context, Memory<LuaValue> buffer, CancellationToken cancellationToken)
+    public ValueTask<int> GetHook(LuaFunctionExecutionContext context, CancellationToken cancellationToken)
     {
     {
         var thread = GetLuaThread(context, out var argOffset);
         var thread = GetLuaThread(context, out var argOffset);
         if (thread.Hook is null)
         if (thread.Hook is null)
         {
         {
-            buffer.Span[0] = LuaValue.Nil;
-            buffer.Span[1] = LuaValue.Nil;
-            buffer.Span[2] = LuaValue.Nil;
-            return new(3);
+            return new(context.Return(LuaValue.Nil, LuaValue.Nil, LuaValue.Nil));
         }
         }
 
 
-        buffer.Span[0] = thread.Hook;
-        buffer.Span[1] = (
-            (thread.IsCallHookEnabled ? "c" : "") +
-            (thread.IsReturnHookEnabled ? "r" : "") +
-            (thread.IsLineHookEnabled ? "l" : "")
-        );
-        buffer.Span[2] = thread.BaseHookCount;
-        return new(3);
+        return new(context.Return(thread.Hook,
+            (
+                (thread.IsCallHookEnabled ? "c" : "") +
+                (thread.IsReturnHookEnabled ? "r" : "") +
+                (thread.IsLineHookEnabled ? "l" : "")
+            )
+            , thread.BaseHookCount));
     }
     }
 
 
-    public ValueTask<int> GetInfo(LuaFunctionExecutionContext context, Memory<LuaValue> buffer, CancellationToken cancellationToken)
+    public ValueTask<int> GetInfo(LuaFunctionExecutionContext context, CancellationToken cancellationToken)
     {
     {
         //return new(0);
         //return new(0);
         var thread = GetLuaThread(context, out var argOffset);
         var thread = GetLuaThread(context, out var argOffset);
@@ -565,8 +528,7 @@ public class DebugLibrary
 
 
             if (level <= 0 || level > callStack.Length)
             if (level <= 0 || level > callStack.Length)
             {
             {
-                buffer.Span[0] = LuaValue.Nil;
-                return new(1);
+                return new(context.Return(LuaValue.Nil));
             }
             }
 
 
 
 
@@ -616,9 +578,7 @@ public class DebugLibrary
         if (what.Contains('n'))
         if (what.Contains('n'))
         {
         {
             table["name"] = debug.Name ?? LuaValue.Nil;
             table["name"] = debug.Name ?? LuaValue.Nil;
-            ;
             table["namewhat"] = debug.NameWhat ?? LuaValue.Nil;
             table["namewhat"] = debug.NameWhat ?? LuaValue.Nil;
-            ;
         }
         }
 
 
         if (what.Contains('t'))
         if (what.Contains('t'))
@@ -645,8 +605,6 @@ public class DebugLibrary
             }
             }
         }
         }
 
 
-        buffer.Span[0] = table;
-
-        return new(1);
+        return new(context.Return(table));
     }
     }
 }
 }

+ 26 - 40
src/Lua/Standard/FileHandle.cs

@@ -7,14 +7,14 @@ namespace Lua.Standard;
 
 
 public class FileHandle : ILuaUserData
 public class FileHandle : ILuaUserData
 {
 {
-    public static readonly LuaFunction IndexMetamethod = new("index", (context, buffer, ct) =>
+    public static readonly LuaFunction IndexMetamethod = new("index", (context, ct) =>
     {
     {
         context.GetArgument<FileHandle>(0);
         context.GetArgument<FileHandle>(0);
         var key = context.GetArgument(1);
         var key = context.GetArgument(1);
 
 
         if (key.TryRead<string>(out var name))
         if (key.TryRead<string>(out var name))
         {
         {
-            buffer.Span[0] = name switch
+            return new(context.Return(name switch
             {
             {
                 "close" => CloseFunction!,
                 "close" => CloseFunction!,
                 "flush" => FlushFunction!,
                 "flush" => FlushFunction!,
@@ -24,14 +24,12 @@ public class FileHandle : ILuaUserData
                 "setvbuf" => SetVBufFunction!,
                 "setvbuf" => SetVBufFunction!,
                 "write" => WriteFunction!,
                 "write" => WriteFunction!,
                 _ => LuaValue.Nil,
                 _ => LuaValue.Nil,
-            };
+            }));
         }
         }
         else
         else
         {
         {
-            buffer.Span[0] = LuaValue.Nil;
+            return new(context.Return(LuaValue.Nil));
         }
         }
-
-        return new(1);
     });
     });
 
 
     Stream stream;
     Stream stream;
@@ -131,45 +129,37 @@ public class FileHandle : ILuaUserData
         }
         }
     }
     }
 
 
-    static readonly LuaFunction CloseFunction = new("close", (context, buffer, cancellationToken) =>
+    static readonly LuaFunction CloseFunction = new("close", (context, cancellationToken) =>
     {
     {
         var file = context.GetArgument<FileHandle>(0);
         var file = context.GetArgument<FileHandle>(0);
 
 
         try
         try
         {
         {
             file.Close();
             file.Close();
-            buffer.Span[0] = true;
-            return new(1);
+            return new(context.Return(true));
         }
         }
         catch (IOException ex)
         catch (IOException ex)
         {
         {
-            buffer.Span[0] = LuaValue.Nil;
-            buffer.Span[1] = ex.Message;
-            buffer.Span[2] = ex.HResult;
-            return new(3);
+            return new(context.Return(LuaValue.Nil, ex.Message, ex.HResult));
         }
         }
     });
     });
 
 
-    static readonly LuaFunction FlushFunction = new("flush", (context, buffer, cancellationToken) =>
+    static readonly LuaFunction FlushFunction = new("flush", (context, cancellationToken) =>
     {
     {
         var file = context.GetArgument<FileHandle>(0);
         var file = context.GetArgument<FileHandle>(0);
 
 
         try
         try
         {
         {
             file.Flush();
             file.Flush();
-            buffer.Span[0] = true;
-            return new(1);
+            return new(context.Return(true));
         }
         }
         catch (IOException ex)
         catch (IOException ex)
         {
         {
-            buffer.Span[0] = LuaValue.Nil;
-            buffer.Span[1] = ex.Message;
-            buffer.Span[2] = ex.HResult;
-            return new(3);
+            return new(context.Return(LuaValue.Nil, ex.Message, ex.HResult));
         }
         }
     });
     });
 
 
-    static readonly LuaFunction LinesFunction = new("lines", (context, buffer, cancellationToken) =>
+    static readonly LuaFunction LinesFunction = new("lines", (context, cancellationToken) =>
     {
     {
         var file = context.GetArgument<FileHandle>(0);
         var file = context.GetArgument<FileHandle>(0);
         var format = context.HasArgument(1)
         var format = context.HasArgument(1)
@@ -177,25 +167,25 @@ public class FileHandle : ILuaUserData
             : "*l";
             : "*l";
 
 
 
 
-        buffer.Span[0] = new CSharpClosure("iterator", [new (file),format],static (context, buffer, cancellationToken) =>
+        return new(context.Return(new CSharpClosure("iterator", [new(file), format], static (context, cancellationToken) =>
         {
         {
             var upValues = context.GetCsClosure()!.UpValues.AsSpan();
             var upValues = context.GetCsClosure()!.UpValues.AsSpan();
             var file = upValues[0].Read<FileHandle>();
             var file = upValues[0].Read<FileHandle>();
-            var resultCount = IOHelper.Read(context.State, file, "lines", 0, upValues[1..], buffer, true);
+            context.Return();
+            var resultCount = IOHelper.Read(context.State, file, "lines", 0, upValues[1..], context.Thread.Stack, true);
             return new(resultCount);
             return new(resultCount);
-        });
-
-        return new(1);
+        })));
     });
     });
 
 
-    static readonly LuaFunction ReadFunction = new("read", (context, buffer, cancellationToken) =>
+    static readonly LuaFunction ReadFunction = new("read", (context, cancellationToken) =>
     {
     {
         var file = context.GetArgument<FileHandle>(0);
         var file = context.GetArgument<FileHandle>(0);
-        var resultCount = IOHelper.Read(context.State, file, "read", 1, context.Arguments[1..], buffer, false);
+        context.Return();
+        var resultCount = IOHelper.Read(context.State, file, "read", 1, context.Arguments[1..], context.Thread.Stack, false);
         return new(resultCount);
         return new(resultCount);
     });
     });
 
 
-    static readonly LuaFunction SeekFunction = new("seek", (context, buffer, cancellationToken) =>
+    static readonly LuaFunction SeekFunction = new("seek", (context, cancellationToken) =>
     {
     {
         var file = context.GetArgument<FileHandle>(0);
         var file = context.GetArgument<FileHandle>(0);
         var whence = context.HasArgument(1)
         var whence = context.HasArgument(1)
@@ -212,19 +202,15 @@ public class FileHandle : ILuaUserData
 
 
         try
         try
         {
         {
-            buffer.Span[0] = file.Seek(whence, (long)offset);
-            return new(1);
+            return new(context.Return(file.Seek(whence, (long)offset)));
         }
         }
         catch (IOException ex)
         catch (IOException ex)
         {
         {
-            buffer.Span[0] = LuaValue.Nil;
-            buffer.Span[1] = ex.Message;
-            buffer.Span[2] = ex.HResult;
-            return new(3);
+            return new(context.Return(LuaValue.Nil, ex.Message, ex.HResult));
         }
         }
     });
     });
 
 
-    static readonly LuaFunction SetVBufFunction = new("setvbuf", (context, buffer, cancellationToken) =>
+    static readonly LuaFunction SetVBufFunction = new("setvbuf", (context, cancellationToken) =>
     {
     {
         var file = context.GetArgument<FileHandle>(0);
         var file = context.GetArgument<FileHandle>(0);
         var mode = context.GetArgument<string>(1);
         var mode = context.GetArgument<string>(1);
@@ -234,14 +220,14 @@ public class FileHandle : ILuaUserData
 
 
         file.SetVBuf(mode, size);
         file.SetVBuf(mode, size);
 
 
-        buffer.Span[0] = true;
-        return new(1);
+        return new(context.Return(true));
     });
     });
 
 
-    static readonly LuaFunction WriteFunction = new("write", (context, buffer, cancellationToken) =>
+    static readonly LuaFunction WriteFunction = new("write", (context, cancellationToken) =>
     {
     {
         var file = context.GetArgument<FileHandle>(0);
         var file = context.GetArgument<FileHandle>(0);
-        var resultCount = IOHelper.Write(file, "write", context, buffer);
+        context.Return();
+        var resultCount = IOHelper.Write(file, "write", context);
         return new(resultCount);
         return new(resultCount);
     });
     });
 }
 }

+ 48 - 56
src/Lua/Standard/IOLibrary.cs

@@ -10,7 +10,8 @@ public sealed class IOLibrary
 
 
     public IOLibrary()
     public IOLibrary()
     {
     {
-        Functions = [
+        Functions =
+        [
             new("close", Close),
             new("close", Close),
             new("flush", Flush),
             new("flush", Flush),
             new("input", Input),
             new("input", Input),
@@ -25,7 +26,7 @@ public sealed class IOLibrary
 
 
     public readonly LuaFunction[] Functions;
     public readonly LuaFunction[] Functions;
 
 
-    public ValueTask<int> Close(LuaFunctionExecutionContext context, Memory<LuaValue> buffer, CancellationToken cancellationToken)
+    public ValueTask<int> Close(LuaFunctionExecutionContext context, CancellationToken cancellationToken)
     {
     {
         var file = context.HasArgument(0)
         var file = context.HasArgument(0)
             ? context.GetArgument<FileHandle>(0)
             ? context.GetArgument<FileHandle>(0)
@@ -34,175 +35,166 @@ public sealed class IOLibrary
         try
         try
         {
         {
             file.Close();
             file.Close();
-            buffer.Span[0] = true;
-            return new(1);
+            return new(context.Return(true));
         }
         }
         catch (IOException ex)
         catch (IOException ex)
         {
         {
-            buffer.Span[0] = LuaValue.Nil;
-            buffer.Span[1] = ex.Message;
-            buffer.Span[2] = ex.HResult;
-            return new(3);
+            return new(context.Return(LuaValue.Nil, ex.Message, ex.HResult));
         }
         }
     }
     }
 
 
-    public ValueTask<int> Flush(LuaFunctionExecutionContext context, Memory<LuaValue> buffer, CancellationToken cancellationToken)
+    public ValueTask<int> Flush(LuaFunctionExecutionContext context, CancellationToken cancellationToken)
     {
     {
         var file = context.State.Environment["io"].Read<LuaTable>()["stdout"].Read<FileHandle>();
         var file = context.State.Environment["io"].Read<LuaTable>()["stdout"].Read<FileHandle>();
 
 
         try
         try
         {
         {
             file.Flush();
             file.Flush();
-            buffer.Span[0] = true;
-            return new(1);
+            return new(context.Return(true));
         }
         }
         catch (IOException ex)
         catch (IOException ex)
         {
         {
-            buffer.Span[0] = LuaValue.Nil;
-            buffer.Span[1] = ex.Message;
-            buffer.Span[2] = ex.HResult;
-            return new(3);
+            return new(context.Return(LuaValue.Nil, ex.Message, ex.HResult));
         }
         }
     }
     }
 
 
-    public ValueTask<int> Input(LuaFunctionExecutionContext context, Memory<LuaValue> buffer, CancellationToken cancellationToken)
+    public ValueTask<int> Input(LuaFunctionExecutionContext context, CancellationToken cancellationToken)
     {
     {
         var io = context.State.Environment["io"].Read<LuaTable>();
         var io = context.State.Environment["io"].Read<LuaTable>();
 
 
         if (context.ArgumentCount == 0 || context.Arguments[0].Type is LuaValueType.Nil)
         if (context.ArgumentCount == 0 || context.Arguments[0].Type is LuaValueType.Nil)
         {
         {
-            buffer.Span[0] = io["stdio"];
-            return new(1);
+            return new(context.Return(io["stdio"]));
         }
         }
 
 
         var arg = context.Arguments[0];
         var arg = context.Arguments[0];
         if (arg.TryRead<FileHandle>(out var file))
         if (arg.TryRead<FileHandle>(out var file))
         {
         {
             io["stdio"] = new(file);
             io["stdio"] = new(file);
-            buffer.Span[0] = new(file);
-            return new(1);
+            return new(context.Return(new LuaValue(file)));
         }
         }
         else
         else
         {
         {
             var stream = File.Open(arg.ToString()!, FileMode.Open, FileAccess.ReadWrite);
             var stream = File.Open(arg.ToString()!, FileMode.Open, FileAccess.ReadWrite);
             var handle = new FileHandle(stream);
             var handle = new FileHandle(stream);
             io["stdio"] = new(handle);
             io["stdio"] = new(handle);
-            buffer.Span[0] = new(handle);
-            return new(1);
+            return new(context.Return(new LuaValue(handle)));
         }
         }
     }
     }
 
 
-    public ValueTask<int> Lines(LuaFunctionExecutionContext context, Memory<LuaValue> buffer, CancellationToken cancellationToken)
+    public ValueTask<int> Lines(LuaFunctionExecutionContext context, CancellationToken cancellationToken)
     {
     {
         if (context.ArgumentCount == 0)
         if (context.ArgumentCount == 0)
         {
         {
             var file = context.State.Environment["io"].Read<LuaTable>()["stdio"].Read<FileHandle>();
             var file = context.State.Environment["io"].Read<LuaTable>()["stdio"].Read<FileHandle>();
-            buffer.Span[0] = new CSharpClosure("iterator",[new (file)] ,static (context, buffer, ct) =>
+            return new(context.Return(new CSharpClosure("iterator", [new(file)], static (context, ct) =>
             {
             {
                 var file = context.GetCsClosure()!.UpValues[0].Read<FileHandle>();
                 var file = context.GetCsClosure()!.UpValues[0].Read<FileHandle>();
-                var resultCount = IOHelper.Read(context.State, file, "lines", 0, [], buffer, true);
-                if (resultCount > 0 && buffer.Span[0].Type is LuaValueType.Nil)
+                context.Return();
+                var resultCount = IOHelper.Read(context.State, file, "lines", 0, [], context.Thread.Stack, true);
+                if (resultCount > 0 && context.Thread.Stack.Get(context.ReturnFrameBase).Type is LuaValueType.Nil)
                 {
                 {
                     file.Close();
                     file.Close();
                 }
                 }
+
                 return new(resultCount);
                 return new(resultCount);
-            });
-            return new(1);
+            })));
         }
         }
         else
         else
         {
         {
             var fileName = context.GetArgument<string>(0);
             var fileName = context.GetArgument<string>(0);
+            var stack = context.Thread.Stack;
+            context.Return();
 
 
-            using var methodBuffer = new PooledArray<LuaValue>(32);
-            IOHelper.Open(context.State, fileName, "r", methodBuffer.AsMemory(), true);
+            IOHelper.Open(context.State, fileName, "r", stack, true);
 
 
-            var file = methodBuffer[0].Read<FileHandle>();
+            var file = stack.Get(context.ReturnFrameBase).Read<FileHandle>();
             var upValues = new LuaValue[context.Arguments.Length];
             var upValues = new LuaValue[context.Arguments.Length];
             upValues[0] = new(file);
             upValues[0] = new(file);
             context.Arguments[1..].CopyTo(upValues[1..]);
             context.Arguments[1..].CopyTo(upValues[1..]);
 
 
-            buffer.Span[0] = new CSharpClosure("iterator", upValues, static (context, buffer, ct) =>
+            return new(context.Return(new CSharpClosure("iterator", upValues, static (context, ct) =>
             {
             {
                 var upValues = context.GetCsClosure()!.UpValues;
                 var upValues = context.GetCsClosure()!.UpValues;
                 var file = upValues[0].Read<FileHandle>();
                 var file = upValues[0].Read<FileHandle>();
                 var formats = upValues.AsSpan(1);
                 var formats = upValues.AsSpan(1);
-                var resultCount = IOHelper.Read(context.State, file, "lines", 0, formats, buffer, true);
-                if (resultCount > 0 && buffer.Span[0].Type is LuaValueType.Nil)
+                var stack = context.Thread.Stack;
+                context.Return();
+                var resultCount = IOHelper.Read(context.State, file, "lines", 0, formats, stack, true);
+                if (resultCount > 0 && stack.Get(context.ReturnFrameBase).Type is LuaValueType.Nil)
                 {
                 {
                     file.Close();
                     file.Close();
                 }
                 }
-                return new(resultCount);
-            });
 
 
-            return new(1);
+                return new(resultCount);
+            })));
         }
         }
     }
     }
 
 
-    public ValueTask<int> Open(LuaFunctionExecutionContext context, Memory<LuaValue> buffer, CancellationToken cancellationToken)
+    public ValueTask<int> Open(LuaFunctionExecutionContext context, CancellationToken cancellationToken)
     {
     {
         var fileName = context.GetArgument<string>(0);
         var fileName = context.GetArgument<string>(0);
         var mode = context.HasArgument(1)
         var mode = context.HasArgument(1)
             ? context.GetArgument<string>(1)
             ? context.GetArgument<string>(1)
             : "r";
             : "r";
-
-        var resultCount = IOHelper.Open(context.State, fileName, mode, buffer, false);
+        context.Return();
+        var resultCount = IOHelper.Open(context.State, fileName, mode, context.Thread.Stack, false);
         return new(resultCount);
         return new(resultCount);
     }
     }
 
 
-    public ValueTask<int> Output(LuaFunctionExecutionContext context, Memory<LuaValue> buffer, CancellationToken cancellationToken)
+    public ValueTask<int> Output(LuaFunctionExecutionContext context, CancellationToken cancellationToken)
     {
     {
         var io = context.State.Environment["io"].Read<LuaTable>();
         var io = context.State.Environment["io"].Read<LuaTable>();
 
 
         if (context.ArgumentCount == 0 || context.Arguments[0].Type is LuaValueType.Nil)
         if (context.ArgumentCount == 0 || context.Arguments[0].Type is LuaValueType.Nil)
         {
         {
-            buffer.Span[0] = io["stdout"];
-            return new(1);
+            return new(context.Return(io["stdout"]));
         }
         }
 
 
         var arg = context.Arguments[0];
         var arg = context.Arguments[0];
         if (arg.TryRead<FileHandle>(out var file))
         if (arg.TryRead<FileHandle>(out var file))
         {
         {
             io["stdout"] = new(file);
             io["stdout"] = new(file);
-            buffer.Span[0] = new(file);
-            return new(1);
+            return new(context.Return(new LuaValue(file)));
         }
         }
         else
         else
         {
         {
             var stream = File.Open(arg.ToString()!, FileMode.Open, FileAccess.ReadWrite);
             var stream = File.Open(arg.ToString()!, FileMode.Open, FileAccess.ReadWrite);
             var handle = new FileHandle(stream);
             var handle = new FileHandle(stream);
             io["stdout"] = new(handle);
             io["stdout"] = new(handle);
-            buffer.Span[0] = new(handle);
-            return new(1);
+            return new(context.Return(new LuaValue(handle)));
         }
         }
     }
     }
 
 
-    public ValueTask<int> Read(LuaFunctionExecutionContext context, Memory<LuaValue> buffer, CancellationToken cancellationToken)
+    public ValueTask<int> Read(LuaFunctionExecutionContext context, CancellationToken cancellationToken)
     {
     {
         var file = context.State.Environment["io"].Read<LuaTable>()["stdio"].Read<FileHandle>();
         var file = context.State.Environment["io"].Read<LuaTable>()["stdio"].Read<FileHandle>();
-        var resultCount = IOHelper.Read(context.State, file, "read", 0, context.Arguments, buffer, false);
+        context.Return();
+        var stack = context.Thread.Stack;
+
+        var resultCount = IOHelper.Read(context.State, file, "read", 0, context.Arguments, stack, false);
         return new(resultCount);
         return new(resultCount);
     }
     }
 
 
-    public ValueTask<int> Type(LuaFunctionExecutionContext context, Memory<LuaValue> buffer, CancellationToken cancellationToken)
+    public ValueTask<int> Type(LuaFunctionExecutionContext context, CancellationToken cancellationToken)
     {
     {
         var arg0 = context.GetArgument(0);
         var arg0 = context.GetArgument(0);
 
 
         if (arg0.TryRead<FileHandle>(out var file))
         if (arg0.TryRead<FileHandle>(out var file))
         {
         {
-            buffer.Span[0] = file.IsClosed ? "closed file" : "file";
+            return new(context.Return(file.IsClosed ? "closed file" : "file"));
         }
         }
         else
         else
         {
         {
-            buffer.Span[0] = LuaValue.Nil;
+            return new(context.Return(LuaValue.Nil));
         }
         }
-
-        return new(1);
     }
     }
 
 
-    public ValueTask<int> Write(LuaFunctionExecutionContext context, Memory<LuaValue> buffer, CancellationToken cancellationToken)
+    public ValueTask<int> Write(LuaFunctionExecutionContext context, CancellationToken cancellationToken)
     {
     {
         var file = context.State.Environment["io"].Read<LuaTable>()["stdout"].Read<FileHandle>();
         var file = context.State.Environment["io"].Read<LuaTable>()["stdout"].Read<FileHandle>();
-        var resultCount = IOHelper.Write(file, "write", context, buffer);
+        context.Return();
+        var resultCount = IOHelper.Write(file, "write", context);
         return new(resultCount);
         return new(resultCount);
     }
     }
 }
 }

+ 25 - 19
src/Lua/Standard/Internal/IOHelper.cs

@@ -1,11 +1,12 @@
 using System.Text;
 using System.Text;
 using Lua.Internal;
 using Lua.Internal;
+using Lua.Runtime;
 
 
 namespace Lua.Standard.Internal;
 namespace Lua.Standard.Internal;
 
 
 internal static class IOHelper
 internal static class IOHelper
 {
 {
-    public static int Open(LuaState state, string fileName, string mode, Memory<LuaValue> buffer, bool throwError)
+    public static int Open(LuaState state, string fileName, string mode, LuaStack stack, bool throwError)
     {
     {
         var fileMode = mode switch
         var fileMode = mode switch
         {
         {
@@ -25,7 +26,7 @@ internal static class IOHelper
         try
         try
         {
         {
             var stream = File.Open(fileName, fileMode, fileAccess);
             var stream = File.Open(fileName, fileMode, fileAccess);
-            buffer.Span[0] = new LuaValue(new FileHandle(stream));
+            stack.Push(new LuaValue(new FileHandle(stream)));
             return 1;
             return 1;
         }
         }
         catch (IOException ex)
         catch (IOException ex)
@@ -35,16 +36,16 @@ internal static class IOHelper
                 throw;
                 throw;
             }
             }
 
 
-            buffer.Span[0] = LuaValue.Nil;
-            buffer.Span[1] = ex.Message;
-            buffer.Span[2] = ex.HResult;
+            stack.Push(LuaValue.Nil);
+            stack.Push(ex.Message);
+            stack.Push(ex.HResult);
             return 3;
             return 3;
         }
         }
     }
     }
 
 
     // TODO: optimize (use IBuffertWrite<byte>, async)
     // TODO: optimize (use IBuffertWrite<byte>, async)
 
 
-    public static int Write(FileHandle file, string name, LuaFunctionExecutionContext context, Memory<LuaValue> buffer)
+    public static int Write(FileHandle file, string name, LuaFunctionExecutionContext context)
     {
     {
         try
         try
         {
         {
@@ -70,25 +71,28 @@ internal static class IOHelper
         }
         }
         catch (IOException ex)
         catch (IOException ex)
         {
         {
-            buffer.Span[0] = LuaValue.Nil;
-            buffer.Span[1] = ex.Message;
-            buffer.Span[2] = ex.HResult;
+            var stack = context.Thread.Stack;
+            stack.Push(LuaValue.Nil);
+            stack.Push(ex.Message);
+            stack.Push(ex.HResult);
             return 3;
             return 3;
         }
         }
 
 
-        buffer.Span[0] = new(file);
+        context.Thread.Stack.Push(new(file));
         return 1;
         return 1;
     }
     }
 
 
     static readonly LuaValue[] defaultReadFormat = ["*l"];
     static readonly LuaValue[] defaultReadFormat = ["*l"];
 
 
-    public static int Read(LuaState state, FileHandle file, string name, int startArgumentIndex, ReadOnlySpan<LuaValue> formats, Memory<LuaValue> buffer, bool throwError)
+    public static int Read(LuaState state, FileHandle file, string name, int startArgumentIndex, ReadOnlySpan<LuaValue> formats, LuaStack stack, bool throwError)
     {
     {
         if (formats.Length == 0)
         if (formats.Length == 0)
         {
         {
             formats = defaultReadFormat;
             formats = defaultReadFormat;
         }
         }
 
 
+        var top = stack.Count;
+
         try
         try
         {
         {
             for (int i = 0; i < formats.Length; i++)
             for (int i = 0; i < formats.Length; i++)
@@ -104,16 +108,16 @@ internal static class IOHelper
                             throw new NotImplementedException();
                             throw new NotImplementedException();
                         case "*a":
                         case "*a":
                         case "*all":
                         case "*all":
-                            buffer.Span[i] = file.ReadToEnd();
+                            stack.Push(file.ReadToEnd());
                             break;
                             break;
                         case "*l":
                         case "*l":
                         case "*line":
                         case "*line":
-                            buffer.Span[i] = file.ReadLine() ?? LuaValue.Nil;
+                            stack.Push(file.ReadLine() ?? LuaValue.Nil);
                             break;
                             break;
                         case "L":
                         case "L":
                         case "*L":
                         case "*L":
                             var text = file.ReadLine();
                             var text = file.ReadLine();
-                            buffer.Span[i] = text == null ? LuaValue.Nil : text + Environment.NewLine;
+                            stack.Push(text == null ? LuaValue.Nil : text + Environment.NewLine);
                             break;
                             break;
                     }
                     }
                 }
                 }
@@ -126,14 +130,15 @@ internal static class IOHelper
                         var b = file.ReadByte();
                         var b = file.ReadByte();
                         if (b == -1)
                         if (b == -1)
                         {
                         {
-                            buffer.Span[0] = LuaValue.Nil;
+                            stack.PopUntil(top);
+                            stack.Push(LuaValue.Nil);
                             return 1;
                             return 1;
                         }
                         }
 
 
                         byteBuffer[j] = (byte)b;
                         byteBuffer[j] = (byte)b;
                     }
                     }
 
 
-                    buffer.Span[i] = Encoding.UTF8.GetString(byteBuffer.AsSpan());
+                    stack.Push(Encoding.UTF8.GetString(byteBuffer.AsSpan()));
                 }
                 }
                 else
                 else
                 {
                 {
@@ -150,9 +155,10 @@ internal static class IOHelper
                 throw;
                 throw;
             }
             }
 
 
-            buffer.Span[0] = LuaValue.Nil;
-            buffer.Span[1] = ex.Message;
-            buffer.Span[2] = ex.HResult;
+            stack.PopUntil(top);
+            stack.Push(LuaValue.Nil);
+            stack.Push(ex.Message);
+            stack.Push(ex.HResult);
             return 3;
             return 3;
         }
         }
     }
     }

+ 70 - 106
src/Lua/Standard/MathematicsLibrary.cs

@@ -7,7 +7,8 @@ public sealed class MathematicsLibrary
 
 
     public MathematicsLibrary()
     public MathematicsLibrary()
     {
     {
-        Functions = [
+        Functions =
+        [
             new("abs", Abs),
             new("abs", Abs),
             new("acos", Acos),
             new("acos", Acos),
             new("asin", Asin),
             new("asin", Asin),
@@ -43,134 +44,123 @@ public sealed class MathematicsLibrary
     public sealed class RandomUserData(Random random) : ILuaUserData
     public sealed class RandomUserData(Random random) : ILuaUserData
     {
     {
         LuaTable? SharedMetatable;
         LuaTable? SharedMetatable;
-        public LuaTable? Metatable { get => SharedMetatable; set => SharedMetatable = value; }
+
+        public LuaTable? Metatable
+        {
+            get => SharedMetatable;
+            set => SharedMetatable = value;
+        }
+
         public Random Random { get; } = random;
         public Random Random { get; } = random;
     }
     }
 
 
-    public ValueTask<int> Abs(LuaFunctionExecutionContext context, Memory<LuaValue> buffer, CancellationToken cancellationToken)
+    public ValueTask<int> Abs(LuaFunctionExecutionContext context, CancellationToken cancellationToken)
     {
     {
         var arg0 = context.GetArgument<double>(0);
         var arg0 = context.GetArgument<double>(0);
-        buffer.Span[0] = Math.Abs(arg0);
-        return new(1);
+        return new(context.Return(Math.Abs(arg0)));
     }
     }
 
 
-    public ValueTask<int> Acos(LuaFunctionExecutionContext context, Memory<LuaValue> buffer, CancellationToken cancellationToken)
+    public ValueTask<int> Acos(LuaFunctionExecutionContext context, CancellationToken cancellationToken)
     {
     {
         var arg0 = context.GetArgument<double>(0);
         var arg0 = context.GetArgument<double>(0);
-        buffer.Span[0] = Math.Acos(arg0);
-        return new(1);
+        return new(context.Return(Math.Acos(arg0)));
     }
     }
 
 
-    public ValueTask<int> Asin(LuaFunctionExecutionContext context, Memory<LuaValue> buffer, CancellationToken cancellationToken)
+    public ValueTask<int> Asin(LuaFunctionExecutionContext context, CancellationToken cancellationToken)
     {
     {
         var arg0 = context.GetArgument<double>(0);
         var arg0 = context.GetArgument<double>(0);
-        buffer.Span[0] = Math.Asin(arg0);
-        return new(1);
+        return new(context.Return(Math.Asin(arg0)));
     }
     }
 
 
-    public ValueTask<int> Atan2(LuaFunctionExecutionContext context, Memory<LuaValue> buffer, CancellationToken cancellationToken)
+    public ValueTask<int> Atan2(LuaFunctionExecutionContext context, CancellationToken cancellationToken)
     {
     {
         var arg0 = context.GetArgument<double>(0);
         var arg0 = context.GetArgument<double>(0);
         var arg1 = context.GetArgument<double>(1);
         var arg1 = context.GetArgument<double>(1);
 
 
-        buffer.Span[0] = Math.Atan2(arg0, arg1);
-        return new(1);
+        return new(context.Return(Math.Atan2(arg0, arg1)));
     }
     }
 
 
-    public ValueTask<int> Atan(LuaFunctionExecutionContext context, Memory<LuaValue> buffer, CancellationToken cancellationToken)
+    public ValueTask<int> Atan(LuaFunctionExecutionContext context, CancellationToken cancellationToken)
     {
     {
         var arg0 = context.GetArgument<double>(0);
         var arg0 = context.GetArgument<double>(0);
-        buffer.Span[0] = Math.Atan(arg0);
-        return new(1);
+        return new(context.Return(Math.Atan(arg0)));
     }
     }
 
 
-    public ValueTask<int> Ceil(LuaFunctionExecutionContext context, Memory<LuaValue> buffer, CancellationToken cancellationToken)
+    public ValueTask<int> Ceil(LuaFunctionExecutionContext context, CancellationToken cancellationToken)
     {
     {
         var arg0 = context.GetArgument<double>(0);
         var arg0 = context.GetArgument<double>(0);
-        buffer.Span[0] = Math.Ceiling(arg0);
-        return new(1);
+        return new(context.Return(Math.Ceiling(arg0)));
     }
     }
 
 
-    public ValueTask<int> Cos(LuaFunctionExecutionContext context, Memory<LuaValue> buffer, CancellationToken cancellationToken)
+    public ValueTask<int> Cos(LuaFunctionExecutionContext context, CancellationToken cancellationToken)
     {
     {
         var arg0 = context.GetArgument<double>(0);
         var arg0 = context.GetArgument<double>(0);
-        buffer.Span[0] = Math.Cos(arg0);
-        return new(1);
+        return new(context.Return(Math.Cos(arg0)));
     }
     }
 
 
-    public ValueTask<int> Cosh(LuaFunctionExecutionContext context, Memory<LuaValue> buffer, CancellationToken cancellationToken)
+    public ValueTask<int> Cosh(LuaFunctionExecutionContext context, CancellationToken cancellationToken)
     {
     {
         var arg0 = context.GetArgument<double>(0);
         var arg0 = context.GetArgument<double>(0);
-        buffer.Span[0] = Math.Cosh(arg0);
-        return new(1);
+        return new(context.Return(Math.Cosh(arg0)));
     }
     }
 
 
-    public ValueTask<int> Deg(LuaFunctionExecutionContext context, Memory<LuaValue> buffer, CancellationToken cancellationToken)
+    public ValueTask<int> Deg(LuaFunctionExecutionContext context, CancellationToken cancellationToken)
     {
     {
         var arg0 = context.GetArgument<double>(0);
         var arg0 = context.GetArgument<double>(0);
-        buffer.Span[0] = arg0 * (180.0 / Math.PI);
-        return new(1);
+        return new(context.Return(arg0 * (180.0 / Math.PI)));
     }
     }
 
 
-    public ValueTask<int> Exp(LuaFunctionExecutionContext context, Memory<LuaValue> buffer, CancellationToken cancellationToken)
+    public ValueTask<int> Exp(LuaFunctionExecutionContext context, CancellationToken cancellationToken)
     {
     {
         var arg0 = context.GetArgument<double>(0);
         var arg0 = context.GetArgument<double>(0);
-        buffer.Span[0] = Math.Exp(arg0);
-        return new(1);
+        return new(context.Return(Math.Exp(arg0)));
     }
     }
 
 
-    public ValueTask<int> Floor(LuaFunctionExecutionContext context, Memory<LuaValue> buffer, CancellationToken cancellationToken)
+    public ValueTask<int> Floor(LuaFunctionExecutionContext context, CancellationToken cancellationToken)
     {
     {
         var arg0 = context.GetArgument<double>(0);
         var arg0 = context.GetArgument<double>(0);
-        buffer.Span[0] = Math.Floor(arg0);
-        return new(1);
+        return new(context.Return(Math.Floor(arg0)));
     }
     }
 
 
-    public ValueTask<int> Fmod(LuaFunctionExecutionContext context, Memory<LuaValue> buffer, CancellationToken cancellationToken)
+    public ValueTask<int> Fmod(LuaFunctionExecutionContext context, CancellationToken cancellationToken)
     {
     {
         var arg0 = context.GetArgument<double>(0);
         var arg0 = context.GetArgument<double>(0);
         var arg1 = context.GetArgument<double>(1);
         var arg1 = context.GetArgument<double>(1);
-        buffer.Span[0] = arg0 % arg1;
-        return new(1);
+        return new(context.Return(arg0 % arg1));
     }
     }
 
 
-    public ValueTask<int> Frexp(LuaFunctionExecutionContext context, Memory<LuaValue> buffer, CancellationToken cancellationToken)
+    public ValueTask<int> Frexp(LuaFunctionExecutionContext context, CancellationToken cancellationToken)
     {
     {
         var arg0 = context.GetArgument<double>(0);
         var arg0 = context.GetArgument<double>(0);
 
 
         var (m, e) = MathEx.Frexp(arg0);
         var (m, e) = MathEx.Frexp(arg0);
-        buffer.Span[0] = m;
-        buffer.Span[1] = e;
-        return new(2);
+        return new(context.Return(m, e));
     }
     }
 
 
-    public ValueTask<int> Ldexp(LuaFunctionExecutionContext context, Memory<LuaValue> buffer, CancellationToken cancellationToken)
+    public ValueTask<int> Ldexp(LuaFunctionExecutionContext context, CancellationToken cancellationToken)
     {
     {
         var arg0 = context.GetArgument<double>(0);
         var arg0 = context.GetArgument<double>(0);
         var arg1 = context.GetArgument<double>(1);
         var arg1 = context.GetArgument<double>(1);
 
 
-        buffer.Span[0] = arg0 * Math.Pow(2, arg1);
-        return new(1);
+        return new(context.Return(arg0 * Math.Pow(2, arg1)));
     }
     }
 
 
-    public ValueTask<int> Log(LuaFunctionExecutionContext context, Memory<LuaValue> buffer, CancellationToken cancellationToken)
+    public ValueTask<int> Log(LuaFunctionExecutionContext context, CancellationToken cancellationToken)
     {
     {
         var arg0 = context.GetArgument<double>(0);
         var arg0 = context.GetArgument<double>(0);
 
 
         if (context.ArgumentCount == 1)
         if (context.ArgumentCount == 1)
         {
         {
-            buffer.Span[0] = Math.Log(arg0);
+            return new(context.Return(Math.Log(arg0)));
         }
         }
         else
         else
         {
         {
             var arg1 = context.GetArgument<double>(1);
             var arg1 = context.GetArgument<double>(1);
-            buffer.Span[0] = Math.Log(arg0, arg1);
+            return new(context.Return(Math.Log(arg0, arg1)));
         }
         }
-
-        return new(1);
     }
     }
 
 
-    public ValueTask<int> Max(LuaFunctionExecutionContext context, Memory<LuaValue> buffer, CancellationToken cancellationToken)
+    public ValueTask<int> Max(LuaFunctionExecutionContext context, CancellationToken cancellationToken)
     {
     {
         var x = context.GetArgument<double>(0);
         var x = context.GetArgument<double>(0);
         for (int i = 1; i < context.ArgumentCount; i++)
         for (int i = 1; i < context.ArgumentCount; i++)
@@ -178,12 +168,10 @@ public sealed class MathematicsLibrary
             x = Math.Max(x, context.GetArgument<double>(i));
             x = Math.Max(x, context.GetArgument<double>(i));
         }
         }
 
 
-        buffer.Span[0] = x;
-
-        return new(1);
+        return new(context.Return(x));
     }
     }
 
 
-    public ValueTask<int> Min(LuaFunctionExecutionContext context, Memory<LuaValue> buffer, CancellationToken cancellationToken)
+    public ValueTask<int> Min(LuaFunctionExecutionContext context, CancellationToken cancellationToken)
     {
     {
         var x = context.GetArgument<double>(0);
         var x = context.GetArgument<double>(0);
         for (int i = 1; i < context.ArgumentCount; i++)
         for (int i = 1; i < context.ArgumentCount; i++)
@@ -191,109 +179,85 @@ public sealed class MathematicsLibrary
             x = Math.Min(x, context.GetArgument<double>(i));
             x = Math.Min(x, context.GetArgument<double>(i));
         }
         }
 
 
-        buffer.Span[0] = x;
-
-        return new(1);
+        return new(context.Return(x));
     }
     }
 
 
-    public ValueTask<int> Modf(LuaFunctionExecutionContext context, Memory<LuaValue> buffer, CancellationToken cancellationToken)
+    public ValueTask<int> Modf(LuaFunctionExecutionContext context, CancellationToken cancellationToken)
     {
     {
         var arg0 = context.GetArgument<double>(0);
         var arg0 = context.GetArgument<double>(0);
         var (i, f) = MathEx.Modf(arg0);
         var (i, f) = MathEx.Modf(arg0);
-        buffer.Span[0] = i;
-        buffer.Span[1] = f;
-        return new(2);
+        return new(context.Return(i, f));
     }
     }
 
 
-    public ValueTask<int> Pow(LuaFunctionExecutionContext context, Memory<LuaValue> buffer, CancellationToken cancellationToken)
+    public ValueTask<int> Pow(LuaFunctionExecutionContext context, CancellationToken cancellationToken)
     {
     {
         var arg0 = context.GetArgument<double>(0);
         var arg0 = context.GetArgument<double>(0);
         var arg1 = context.GetArgument<double>(1);
         var arg1 = context.GetArgument<double>(1);
 
 
-        buffer.Span[0] = Math.Pow(arg0, arg1);
-        return new(1);
+        return new(context.Return(Math.Pow(arg0, arg1)));
     }
     }
 
 
-    public ValueTask<int> Rad(LuaFunctionExecutionContext context, Memory<LuaValue> buffer, CancellationToken cancellationToken)
+    public ValueTask<int> Rad(LuaFunctionExecutionContext context, CancellationToken cancellationToken)
     {
     {
         var arg0 = context.GetArgument<double>(0);
         var arg0 = context.GetArgument<double>(0);
-        buffer.Span[0] = arg0 * (Math.PI / 180.0);
-        return new(1);
+        return new(context.Return(arg0 * (Math.PI / 180.0)));
     }
     }
 
 
-    public ValueTask<int> Random(LuaFunctionExecutionContext context, Memory<LuaValue> buffer, CancellationToken cancellationToken)
+    public ValueTask<int> Random(LuaFunctionExecutionContext context, CancellationToken cancellationToken)
     {
     {
         var rand = context.State.Environment[RandomInstanceKey].Read<RandomUserData>().Random;
         var rand = context.State.Environment[RandomInstanceKey].Read<RandomUserData>().Random;
-        // When we call it without arguments, it returns a pseudo-random real number with uniform distribution in the interval [0,1
+
         if (context.ArgumentCount == 0)
         if (context.ArgumentCount == 0)
         {
         {
-            buffer.Span[0] = rand.NextDouble();
+            return new(context.Return(rand.NextDouble()));
         }
         }
-        // When we call it with only one argument, an integer n, it returns an integer pseudo-random number such that 1 <= x <= n.
-        // This is different from the C# random functions.
-        // See: https://www.lua.org/pil/18.html
         else if (context.ArgumentCount == 1)
         else if (context.ArgumentCount == 1)
         {
         {
-            var arg0 = context.GetArgument<int>(0);
-            if (arg0 < 0)
-            {
-                LuaRuntimeException.BadArgument(context.State.GetTraceback(), 0, "random");
-            }
-            buffer.Span[0] = rand.Next(1, arg0 + 1);
+            var arg0 = context.GetArgument<double>(0);
+            return new(context.Return(rand.NextDouble() * (arg0 - 1) + 1));
         }
         }
-        // Finally, we can call random with two integer arguments, l and u, to get a pseudo-random integer x such that l <= x <= u.
         else
         else
         {
         {
-            var arg0 = context.GetArgument<int>(0);
-            var arg1 = context.GetArgument<int>(1);
-            if (arg0 < 1 || arg1 <= arg0)
-            {
-                LuaRuntimeException.BadArgument(context.State.GetTraceback(), 1, "random");
-            }
-            buffer.Span[0] = rand.Next(arg0, arg1 + 1);
+            var arg0 = context.GetArgument<double>(0);
+            var arg1 = context.GetArgument<double>(1);
+            return new(context.Return(rand.NextDouble() * (arg1 - arg0) + arg0));
         }
         }
-        return new(1);
     }
     }
 
 
-    public ValueTask<int> RandomSeed(LuaFunctionExecutionContext context, Memory<LuaValue> buffer, CancellationToken cancellationToken)
+    public ValueTask<int> RandomSeed(LuaFunctionExecutionContext context, CancellationToken cancellationToken)
     {
     {
         var arg0 = context.GetArgument<double>(0);
         var arg0 = context.GetArgument<double>(0);
         context.State.Environment[RandomInstanceKey] = new(new RandomUserData(new Random((int)BitConverter.DoubleToInt64Bits(arg0))));
         context.State.Environment[RandomInstanceKey] = new(new RandomUserData(new Random((int)BitConverter.DoubleToInt64Bits(arg0))));
-        return new(0);
+        return new(context.Return());
     }
     }
 
 
-    public ValueTask<int> Sin(LuaFunctionExecutionContext context, Memory<LuaValue> buffer, CancellationToken cancellationToken)
+    public ValueTask<int> Sin(LuaFunctionExecutionContext context, CancellationToken cancellationToken)
     {
     {
         var arg0 = context.GetArgument<double>(0);
         var arg0 = context.GetArgument<double>(0);
-        buffer.Span[0] = Math.Sin(arg0);
-        return new(1);
+        return new(context.Return(Math.Sin(arg0)));
     }
     }
 
 
-    public ValueTask<int> Sinh(LuaFunctionExecutionContext context, Memory<LuaValue> buffer, CancellationToken cancellationToken)
+    public ValueTask<int> Sinh(LuaFunctionExecutionContext context, CancellationToken cancellationToken)
     {
     {
         var arg0 = context.GetArgument<double>(0);
         var arg0 = context.GetArgument<double>(0);
-        buffer.Span[0] = Math.Sinh(arg0);
-        return new(1);
+        return new(context.Return(Math.Sinh(arg0)));
     }
     }
 
 
-    public ValueTask<int> Sqrt(LuaFunctionExecutionContext context, Memory<LuaValue> buffer, CancellationToken cancellationToken)
+    public ValueTask<int> Sqrt(LuaFunctionExecutionContext context, CancellationToken cancellationToken)
     {
     {
         var arg0 = context.GetArgument<double>(0);
         var arg0 = context.GetArgument<double>(0);
-        buffer.Span[0] = Math.Sqrt(arg0);
-        return new(1);
+        return new(context.Return(Math.Sqrt(arg0)));
     }
     }
 
 
-    public ValueTask<int> Tan(LuaFunctionExecutionContext context, Memory<LuaValue> buffer, CancellationToken cancellationToken)
+    public ValueTask<int> Tan(LuaFunctionExecutionContext context, CancellationToken cancellationToken)
     {
     {
         var arg0 = context.GetArgument<double>(0);
         var arg0 = context.GetArgument<double>(0);
-        buffer.Span[0] = Math.Tan(arg0);
-        return new(1);
+        return new(context.Return(Math.Tan(arg0)));
     }
     }
 
 
-    public ValueTask<int> Tanh(LuaFunctionExecutionContext context, Memory<LuaValue> buffer, CancellationToken cancellationToken)
+    public ValueTask<int> Tanh(LuaFunctionExecutionContext context, CancellationToken cancellationToken)
     {
     {
         var arg0 = context.GetArgument<double>(0);
         var arg0 = context.GetArgument<double>(0);
-        buffer.Span[0] = Math.Tanh(arg0);
-        return new(1);
+        return new(context.Return(Math.Tanh(arg0)));
     }
     }
 }
 }

+ 4 - 7
src/Lua/Standard/ModuleLibrary.cs

@@ -15,7 +15,7 @@ public sealed class ModuleLibrary
 
 
     public readonly LuaFunction RequireFunction;
     public readonly LuaFunction RequireFunction;
 
 
-    public async ValueTask<int> Require(LuaFunctionExecutionContext context, Memory<LuaValue> buffer, CancellationToken cancellationToken)
+    public async ValueTask<int> Require(LuaFunctionExecutionContext context, CancellationToken cancellationToken)
     {
     {
         var arg0 = context.GetArgument<string>(0);
         var arg0 = context.GetArgument<string>(0);
         var loaded = context.State.LoadedModules;
         var loaded = context.State.LoadedModules;
@@ -24,15 +24,12 @@ public sealed class ModuleLibrary
         {
         {
             var module = await context.State.ModuleLoader.LoadAsync(arg0, cancellationToken);
             var module = await context.State.ModuleLoader.LoadAsync(arg0, cancellationToken);
             var chunk = LuaCompiler.Default.Compile(module.ReadText(), module.Name);
             var chunk = LuaCompiler.Default.Compile(module.ReadText(), module.Name);
+            await new LuaClosure(context.State, chunk).InvokeAsync(context, cancellationToken);
 
 
-            using var methodBuffer = new PooledArray<LuaValue>(1);
-            await new LuaClosure(context.State, chunk).InvokeAsync(context, methodBuffer.AsMemory(), cancellationToken);
-
-            loadedTable = methodBuffer[0];
+            loadedTable = context.Thread.Stack.Get(context.ReturnFrameBase);
             loaded[arg0] = loadedTable;
             loaded[arg0] = loadedTable;
         }
         }
 
 
-        buffer.Span[0] = loadedTable;
-        return 1;
+        return context.Return(loadedTable);
     }
     }
 }
 }

+ 5 - 7
src/Lua/Standard/OpenLibsExtensions.cs

@@ -40,16 +40,16 @@ public static class OpenLibsExtensions
 
 
     public static void OpenIOLibrary(this LuaState state)
     public static void OpenIOLibrary(this LuaState state)
     {
     {
-        
         var io = new LuaTable(0, IOLibrary.Instance.Functions.Length);
         var io = new LuaTable(0, IOLibrary.Instance.Functions.Length);
         foreach (var func in IOLibrary.Instance.Functions)
         foreach (var func in IOLibrary.Instance.Functions)
         {
         {
             io[func.Name] = func;
             io[func.Name] = func;
         }
         }
+
         io["stdio"] = new LuaValue(new FileHandle(ConsoleHelper.OpenStandardInput()));
         io["stdio"] = new LuaValue(new FileHandle(ConsoleHelper.OpenStandardInput()));
         io["stdout"] = new LuaValue(new FileHandle(ConsoleHelper.OpenStandardOutput()));
         io["stdout"] = new LuaValue(new FileHandle(ConsoleHelper.OpenStandardOutput()));
         io["stderr"] = new LuaValue(new FileHandle(ConsoleHelper.OpenStandardError()));
         io["stderr"] = new LuaValue(new FileHandle(ConsoleHelper.OpenStandardError()));
-        
+
         state.Environment["io"] = io;
         state.Environment["io"] = io;
         state.LoadedModules["io"] = io;
         state.LoadedModules["io"] = io;
     }
     }
@@ -110,13 +110,11 @@ public static class OpenLibsExtensions
             state.SetMetatable(key, metatable);
             state.SetMetatable(key, metatable);
         }
         }
 
 
-        metatable[Metamethods.Index] = new LuaFunction("index", (context, buffer, cancellationToken) =>
+        metatable[Metamethods.Index] = new LuaFunction("index", (context, cancellationToken) =>
         {
         {
             context.GetArgument<string>(0);
             context.GetArgument<string>(0);
             var key = context.GetArgument(1);
             var key = context.GetArgument(1);
-
-            buffer.Span[0] = @string[key];
-            return new(1);
+            return new(context.Return(@string[key]));
         });
         });
     }
     }
 
 
@@ -131,7 +129,7 @@ public static class OpenLibsExtensions
         state.Environment["table"] = table;
         state.Environment["table"] = table;
         state.LoadedModules["table"] = table;
         state.LoadedModules["table"] = table;
     }
     }
-    
+
     public static void OpenDebugLibrary(this LuaState state)
     public static void OpenDebugLibrary(this LuaState state)
     {
     {
         var debug = new LuaTable(0, DebugLibrary.Instance.Functions.Length);
         var debug = new LuaTable(0, DebugLibrary.Instance.Functions.Length);

+ 28 - 45
src/Lua/Standard/OperatingSystemLibrary.cs

@@ -9,7 +9,8 @@ public sealed class OperatingSystemLibrary
 
 
     public OperatingSystemLibrary()
     public OperatingSystemLibrary()
     {
     {
-        Functions = [
+        Functions =
+        [
             new("clock", Clock),
             new("clock", Clock),
             new("date", Date),
             new("date", Date),
             new("difftime", DiffTime),
             new("difftime", DiffTime),
@@ -26,13 +27,12 @@ public sealed class OperatingSystemLibrary
 
 
     public readonly LuaFunction[] Functions;
     public readonly LuaFunction[] Functions;
 
 
-    public ValueTask<int> Clock(LuaFunctionExecutionContext context, Memory<LuaValue> buffer, CancellationToken cancellationToken)
+    public ValueTask<int> Clock(LuaFunctionExecutionContext context, CancellationToken cancellationToken)
     {
     {
-        buffer.Span[0] = DateTimeHelper.GetUnixTime(DateTime.UtcNow, Process.GetCurrentProcess().StartTime);
-        return new(1);
+        return new(context.Return(DateTimeHelper.GetUnixTime(DateTime.UtcNow, Process.GetCurrentProcess().StartTime)));
     }
     }
 
 
-    public ValueTask<int> Date(LuaFunctionExecutionContext context, Memory<LuaValue> buffer, CancellationToken cancellationToken)
+    public ValueTask<int> Date(LuaFunctionExecutionContext context, CancellationToken cancellationToken)
     {
     {
         var format = context.HasArgument(0)
         var format = context.HasArgument(0)
             ? context.GetArgument<string>(0).AsSpan()
             ? context.GetArgument<string>(0).AsSpan()
@@ -74,25 +74,22 @@ public sealed class OperatingSystemLibrary
             table["yday"] = now.DayOfYear;
             table["yday"] = now.DayOfYear;
             table["isdst"] = isDst;
             table["isdst"] = isDst;
 
 
-            buffer.Span[0] = table;
+            return new(context.Return(table));
         }
         }
         else
         else
         {
         {
-            buffer.Span[0] = DateTimeHelper.StrFTime(context.State, format, now);
+            return new(context.Return(DateTimeHelper.StrFTime(context.State, format, now)));
         }
         }
-
-        return new(1);
     }
     }
 
 
-    public ValueTask<int> DiffTime(LuaFunctionExecutionContext context, Memory<LuaValue> buffer, CancellationToken cancellationToken)
+    public ValueTask<int> DiffTime(LuaFunctionExecutionContext context, CancellationToken cancellationToken)
     {
     {
         var t2 = context.GetArgument<double>(0);
         var t2 = context.GetArgument<double>(0);
         var t1 = context.GetArgument<double>(1);
         var t1 = context.GetArgument<double>(1);
-        buffer.Span[0] = t2 - t1;
-        return new(1);
+        return new(context.Return(t2 - t1));
     }
     }
 
 
-    public ValueTask<int> Execute(LuaFunctionExecutionContext context, Memory<LuaValue> buffer, CancellationToken cancellationToken)
+    public ValueTask<int> Execute(LuaFunctionExecutionContext context, CancellationToken cancellationToken)
     {
     {
         // os.execute(command) is not supported
         // os.execute(command) is not supported
 
 
@@ -102,12 +99,11 @@ public sealed class OperatingSystemLibrary
         }
         }
         else
         else
         {
         {
-            buffer.Span[0] = false;
-            return new(1);
+            return new(context.Return(false));
         }
         }
     }
     }
 
 
-    public ValueTask<int> Exit(LuaFunctionExecutionContext context, Memory<LuaValue> buffer, CancellationToken cancellationToken)
+    public ValueTask<int> Exit(LuaFunctionExecutionContext context, CancellationToken cancellationToken)
     {
     {
         // Ignore 'close' parameter
         // Ignore 'close' parameter
 
 
@@ -133,80 +129,67 @@ public sealed class OperatingSystemLibrary
             Environment.Exit(0);
             Environment.Exit(0);
         }
         }
 
 
-        return new(0);
+        return new(context.Return());
     }
     }
 
 
-    public ValueTask<int> GetEnv(LuaFunctionExecutionContext context, Memory<LuaValue> buffer, CancellationToken cancellationToken)
+    public ValueTask<int> GetEnv(LuaFunctionExecutionContext context, CancellationToken cancellationToken)
     {
     {
         var variable = context.GetArgument<string>(0);
         var variable = context.GetArgument<string>(0);
-        buffer.Span[0] = Environment.GetEnvironmentVariable(variable) ?? LuaValue.Nil;
-        return new(1);
+        return new(context.Return(Environment.GetEnvironmentVariable(variable) ?? LuaValue.Nil));
     }
     }
 
 
-    public ValueTask<int> Remove(LuaFunctionExecutionContext context, Memory<LuaValue> buffer, CancellationToken cancellationToken)
+    public ValueTask<int> Remove(LuaFunctionExecutionContext context, CancellationToken cancellationToken)
     {
     {
         var fileName = context.GetArgument<string>(0);
         var fileName = context.GetArgument<string>(0);
         try
         try
         {
         {
             File.Delete(fileName);
             File.Delete(fileName);
-            buffer.Span[0] = true;
-            return new(1);
+            return new(context.Return(true));
         }
         }
         catch (IOException ex)
         catch (IOException ex)
         {
         {
-            buffer.Span[0] = LuaValue.Nil;
-            buffer.Span[1] = ex.Message;
-            buffer.Span[2] = ex.HResult;
-            return new(3);
+            return new(context.Return(LuaValue.Nil, ex.Message, ex.HResult));
         }
         }
     }
     }
 
 
-    public ValueTask<int> Rename(LuaFunctionExecutionContext context, Memory<LuaValue> buffer, CancellationToken cancellationToken)
+    public ValueTask<int> Rename(LuaFunctionExecutionContext context, CancellationToken cancellationToken)
     {
     {
         var oldName = context.GetArgument<string>(0);
         var oldName = context.GetArgument<string>(0);
         var newName = context.GetArgument<string>(1);
         var newName = context.GetArgument<string>(1);
         try
         try
         {
         {
             File.Move(oldName, newName);
             File.Move(oldName, newName);
-            buffer.Span[0] = true;
-            return new(1);
+            return new(context.Return(true));
         }
         }
         catch (IOException ex)
         catch (IOException ex)
         {
         {
-            buffer.Span[0] = LuaValue.Nil;
-            buffer.Span[1] = ex.Message;
-            buffer.Span[2] = ex.HResult;
-            return new(3);
+            return new(context.Return(LuaValue.Nil, ex.Message, ex.HResult));
         }
         }
     }
     }
 
 
-    public ValueTask<int> SetLocale(LuaFunctionExecutionContext context, Memory<LuaValue> buffer, CancellationToken cancellationToken)
+    public ValueTask<int> SetLocale(LuaFunctionExecutionContext context, CancellationToken cancellationToken)
     {
     {
         // os.setlocale is not supported (always return nil)
         // os.setlocale is not supported (always return nil)
 
 
-        buffer.Span[0] = LuaValue.Nil;
-        return new(1);
+        return new(context.Return(LuaValue.Nil));
     }
     }
 
 
-    public ValueTask<int> Time(LuaFunctionExecutionContext context, Memory<LuaValue> buffer, CancellationToken cancellationToken)
+    public ValueTask<int> Time(LuaFunctionExecutionContext context, CancellationToken cancellationToken)
     {
     {
         if (context.HasArgument(0))
         if (context.HasArgument(0))
         {
         {
             var table = context.GetArgument<LuaTable>(0);
             var table = context.GetArgument<LuaTable>(0);
             var date = DateTimeHelper.ParseTimeTable(context.State, table);
             var date = DateTimeHelper.ParseTimeTable(context.State, table);
-            buffer.Span[0] = DateTimeHelper.GetUnixTime(date);
-            return new(1);
+            return new(context.Return(DateTimeHelper.GetUnixTime(date)));
         }
         }
         else
         else
         {
         {
-            buffer.Span[0] = DateTimeHelper.GetUnixTime(DateTime.UtcNow);
-            return new(1);
+            return new(context.Return(DateTimeHelper.GetUnixTime(DateTime.UtcNow)));
         }
         }
     }
     }
 
 
-    public ValueTask<int> TmpName(LuaFunctionExecutionContext context, Memory<LuaValue> buffer, CancellationToken cancellationToken)
+    public ValueTask<int> TmpName(LuaFunctionExecutionContext context, CancellationToken cancellationToken)
     {
     {
-        buffer.Span[0] = Path.GetTempFileName();
-        return new(1);
+        return new(context.Return(Path.GetTempFileName()));
     }
     }
 }
 }

+ 64 - 80
src/Lua/Standard/StringLibrary.cs

@@ -12,7 +12,8 @@ public sealed class StringLibrary
 
 
     public StringLibrary()
     public StringLibrary()
     {
     {
-        Functions = [
+        Functions =
+        [
             new("byte", Byte),
             new("byte", Byte),
             new("char", Char),
             new("char", Char),
             new("dump", Dump),
             new("dump", Dump),
@@ -31,7 +32,7 @@ public sealed class StringLibrary
 
 
     public readonly LuaFunction[] Functions;
     public readonly LuaFunction[] Functions;
 
 
-    public ValueTask<int> Byte(LuaFunctionExecutionContext context, Memory<LuaValue> buffer, CancellationToken cancellationToken)
+    public ValueTask<int> Byte(LuaFunctionExecutionContext context, CancellationToken cancellationToken)
     {
     {
         var s = context.GetArgument<string>(0);
         var s = context.GetArgument<string>(0);
         var i = context.HasArgument(1)
         var i = context.HasArgument(1)
@@ -45,20 +46,20 @@ public sealed class StringLibrary
         LuaRuntimeException.ThrowBadArgumentIfNumberIsNotInteger(context.State, "byte", 3, j);
         LuaRuntimeException.ThrowBadArgumentIfNumberIsNotInteger(context.State, "byte", 3, j);
 
 
         var span = StringHelper.Slice(s, (int)i, (int)j);
         var span = StringHelper.Slice(s, (int)i, (int)j);
+        var buffer = context.GetReturnBuffer(span.Length);
         for (int k = 0; k < span.Length; k++)
         for (int k = 0; k < span.Length; k++)
         {
         {
-            buffer.Span[k] = span[k];
+            buffer[k] = span[k];
         }
         }
 
 
         return new(span.Length);
         return new(span.Length);
     }
     }
 
 
-    public ValueTask<int> Char(LuaFunctionExecutionContext context, Memory<LuaValue> buffer, CancellationToken cancellationToken)
+    public ValueTask<int> Char(LuaFunctionExecutionContext context, CancellationToken cancellationToken)
     {
     {
         if (context.ArgumentCount == 0)
         if (context.ArgumentCount == 0)
         {
         {
-            buffer.Span[0] = "";
-            return new(1);
+            return new(context.Return(""));
         }
         }
 
 
         var builder = new ValueStringBuilder(context.ArgumentCount);
         var builder = new ValueStringBuilder(context.ArgumentCount);
@@ -69,17 +70,16 @@ public sealed class StringLibrary
             builder.Append((char)arg);
             builder.Append((char)arg);
         }
         }
 
 
-        buffer.Span[0] = builder.ToString();
-        return new(1);
+        return new(context.Return(builder.ToString()));
     }
     }
 
 
-    public ValueTask<int> Dump(LuaFunctionExecutionContext context, Memory<LuaValue> buffer, CancellationToken cancellationToken)
+    public ValueTask<int> Dump(LuaFunctionExecutionContext context, CancellationToken cancellationToken)
     {
     {
         // stirng.dump is not supported (throw exception)
         // stirng.dump is not supported (throw exception)
         throw new NotSupportedException("stirng.dump is not supported");
         throw new NotSupportedException("stirng.dump is not supported");
     }
     }
 
 
-    public ValueTask<int> Find(LuaFunctionExecutionContext context, Memory<LuaValue> buffer, CancellationToken cancellationToken)
+    public ValueTask<int> Find(LuaFunctionExecutionContext context, CancellationToken cancellationToken)
     {
     {
         var s = context.GetArgument<string>(0);
         var s = context.GetArgument<string>(0);
         var pattern = context.GetArgument<string>(1);
         var pattern = context.GetArgument<string>(1);
@@ -101,16 +101,13 @@ public sealed class StringLibrary
         // out of range
         // out of range
         if (init != 1 && (init < 1 || init > s.Length))
         if (init != 1 && (init < 1 || init > s.Length))
         {
         {
-            buffer.Span[0] = LuaValue.Nil;
-            return new(1);
+            return new(context.Return(LuaValue.Nil));
         }
         }
 
 
         // empty pattern
         // empty pattern
         if (pattern.Length == 0)
         if (pattern.Length == 0)
         {
         {
-            buffer.Span[0] = 1;
-            buffer.Span[1] = 1;
-            return new(2);
+            return new(context.Return(1, 1));
         }
         }
 
 
         var source = s.AsSpan()[(int)(init - 1)..];
         var source = s.AsSpan()[(int)(init - 1)..];
@@ -120,14 +117,11 @@ public sealed class StringLibrary
             var start = source.IndexOf(pattern);
             var start = source.IndexOf(pattern);
             if (start == -1)
             if (start == -1)
             {
             {
-                buffer.Span[0] = LuaValue.Nil;
-                return new(1);
+                return new(context.Return(LuaValue.Nil));
             }
             }
 
 
             // 1-based
             // 1-based
-            buffer.Span[0] = start + 1;
-            buffer.Span[1] = start + pattern.Length;
-            return new(2);
+            return new(context.Return(start + 1, start + pattern.Length));
         }
         }
         else
         else
         {
         {
@@ -137,22 +131,19 @@ public sealed class StringLibrary
             if (match.Success)
             if (match.Success)
             {
             {
                 // 1-based
                 // 1-based
-                buffer.Span[0] = init + match.Index;
-                buffer.Span[1] = init + match.Index + match.Length - 1;
-                return new(2);
+                return new(context.Return(init + match.Index, init + match.Index + match.Length - 1));
             }
             }
             else
             else
             {
             {
-                buffer.Span[0] = LuaValue.Nil;
-                return new(1);
+                return new(context.Return(LuaValue.Nil));
             }
             }
         }
         }
     }
     }
 
 
-    public async ValueTask<int> Format(LuaFunctionExecutionContext context, Memory<LuaValue> buffer, CancellationToken cancellationToken)
+    public async ValueTask<int> Format(LuaFunctionExecutionContext context, CancellationToken cancellationToken)
     {
     {
         var format = context.GetArgument<string>(0);
         var format = context.GetArgument<string>(0);
-
+        var stack = context.Thread.Stack;
         // TODO: pooling StringBuilder
         // TODO: pooling StringBuilder
         var builder = new StringBuilder(format.Length * 2);
         var builder = new StringBuilder(format.Length * 2);
         var parameterIndex = 1;
         var parameterIndex = 1;
@@ -241,6 +232,7 @@ public sealed class StringLibrary
                 {
                 {
                     throw new LuaRuntimeException(context.State.GetTraceback(), $"bad argument #{parameterIndex + 1} to 'format' (no value)");
                     throw new LuaRuntimeException(context.State.GetTraceback(), $"bad argument #{parameterIndex + 1} to 'format' (no value)");
                 }
                 }
+
                 var parameter = context.GetArgument(parameterIndex++);
                 var parameter = context.GetArgument(parameterIndex++);
 
 
                 // TODO: reduce allocation
                 // TODO: reduce allocation
@@ -261,22 +253,22 @@ public sealed class StringLibrary
                             case 'f':
                             case 'f':
                                 formattedValue = precision < 0
                                 formattedValue = precision < 0
                                     ? f.ToString(CultureInfo.InvariantCulture)
                                     ? f.ToString(CultureInfo.InvariantCulture)
-                                    : f.ToString($"F{precision}",CultureInfo.InvariantCulture);
+                                    : f.ToString($"F{precision}", CultureInfo.InvariantCulture);
                                 break;
                                 break;
                             case 'e':
                             case 'e':
                                 formattedValue = precision < 0
                                 formattedValue = precision < 0
                                     ? f.ToString(CultureInfo.InvariantCulture)
                                     ? f.ToString(CultureInfo.InvariantCulture)
-                                    : f.ToString($"E{precision}",CultureInfo.InvariantCulture);
+                                    : f.ToString($"E{precision}", CultureInfo.InvariantCulture);
                                 break;
                                 break;
                             case 'g':
                             case 'g':
                                 formattedValue = precision < 0
                                 formattedValue = precision < 0
                                     ? f.ToString(CultureInfo.InvariantCulture)
                                     ? f.ToString(CultureInfo.InvariantCulture)
-                                    : f.ToString($"G{precision}",CultureInfo.InvariantCulture);
+                                    : f.ToString($"G{precision}", CultureInfo.InvariantCulture);
                                 break;
                                 break;
                             case 'G':
                             case 'G':
                                 formattedValue = precision < 0
                                 formattedValue = precision < 0
                                     ? f.ToString(CultureInfo.InvariantCulture).ToUpper()
                                     ? f.ToString(CultureInfo.InvariantCulture).ToUpper()
-                                    : f.ToString($"G{precision}",CultureInfo.InvariantCulture).ToUpper();
+                                    : f.ToString($"G{precision}", CultureInfo.InvariantCulture).ToUpper();
                                 break;
                                 break;
                         }
                         }
 
 
@@ -284,18 +276,21 @@ public sealed class StringLibrary
                         {
                         {
                             formattedValue = $"+{formattedValue}";
                             formattedValue = $"+{formattedValue}";
                         }
                         }
+
                         break;
                         break;
                     case 's':
                     case 's':
-                        using (var strBuffer = new PooledArray<LuaValue>(1))
                         {
                         {
-                            await parameter.CallToStringAsync(context, strBuffer.AsMemory(), cancellationToken);
-                            formattedValue = strBuffer[0].Read<string>();
+                            var top = stack.Count;
+                            stack.Push(default);
+                            await parameter.CallToStringAsync(context with { ReturnFrameBase = top }, cancellationToken);
+                            formattedValue = stack.Pop().Read<string>();
                         }
                         }
 
 
                         if (specifier is 's' && precision > 0 && precision <= formattedValue.Length)
                         if (specifier is 's' && precision > 0 && precision <= formattedValue.Length)
                         {
                         {
                             formattedValue = formattedValue[..precision];
                             formattedValue = formattedValue[..precision];
                         }
                         }
+
                         break;
                         break;
                     case 'q':
                     case 'q':
                         switch (parameter.Type)
                         switch (parameter.Type)
@@ -314,13 +309,16 @@ public sealed class StringLibrary
                                 formattedValue = parameter.Read<double>().ToString(CultureInfo.InvariantCulture);
                                 formattedValue = parameter.Read<double>().ToString(CultureInfo.InvariantCulture);
                                 break;
                                 break;
                             default:
                             default:
-                                using (var strBuffer = new PooledArray<LuaValue>(1))
+
                                 {
                                 {
-                                    await parameter.CallToStringAsync(context, strBuffer.AsMemory(), cancellationToken);
-                                    formattedValue = strBuffer[0].Read<string>();
+                                    var top = stack.Count;
+                                    stack.Push(default);
+                                    await parameter.CallToStringAsync(context with { ReturnFrameBase = top }, cancellationToken);
+                                    formattedValue = stack.Pop().Read<string>();
                                 }
                                 }
                                 break;
                                 break;
                         }
                         }
+
                         break;
                         break;
                     case 'i':
                     case 'i':
                     case 'd':
                     case 'd':
@@ -385,6 +383,7 @@ public sealed class StringLibrary
                         {
                         {
                             formattedValue = $"+{formattedValue}";
                             formattedValue = $"+{formattedValue}";
                         }
                         }
+
                         break;
                         break;
                     default:
                     default:
                         throw new LuaRuntimeException(context.State.GetTraceback(), $"invalid option '%{specifier}' to 'format'");
                         throw new LuaRuntimeException(context.State.GetTraceback(), $"invalid option '%{specifier}' to 'format'");
@@ -420,12 +419,10 @@ public sealed class StringLibrary
             }
             }
         }
         }
 
 
-
-        buffer.Span[0] = builder.ToString();
-        return 1;
+        return context.Return(builder.ToString());
     }
     }
 
 
-    public ValueTask<int> GMatch(LuaFunctionExecutionContext context, Memory<LuaValue> buffer, CancellationToken cancellationToken)
+    public ValueTask<int> GMatch(LuaFunctionExecutionContext context, CancellationToken cancellationToken)
     {
     {
         var s = context.GetArgument<string>(0);
         var s = context.GetArgument<string>(0);
         var pattern = context.GetArgument<string>(1);
         var pattern = context.GetArgument<string>(1);
@@ -433,7 +430,7 @@ public sealed class StringLibrary
         var regex = StringHelper.ToRegex(pattern);
         var regex = StringHelper.ToRegex(pattern);
         var matches = regex.Matches(s);
         var matches = regex.Matches(s);
 
 
-        buffer.Span[0] = new CSharpClosure("iterator",[new LuaValue(matches),0],static (context, buffer, cancellationToken) =>
+        return new(context.Return(new CSharpClosure("iterator", [new LuaValue(matches), 0], static (context, cancellationToken) =>
         {
         {
             var upValues = context.GetCsClosure()!.UpValues;
             var upValues = context.GetCsClosure()!.UpValues;
             var matches = upValues[0].Read<MatchCollection>();
             var matches = upValues[0].Read<MatchCollection>();
@@ -444,32 +441,30 @@ public sealed class StringLibrary
                 var groups = match.Groups;
                 var groups = match.Groups;
 
 
                 i++;
                 i++;
-                 upValues[1] = i;
+                upValues[1] = i;
                 if (groups.Count == 1)
                 if (groups.Count == 1)
                 {
                 {
-                    buffer.Span[0] = match.Value;
+                    return new(context.Return(match.Value));
                 }
                 }
                 else
                 else
                 {
                 {
+                    var buffer = context.GetReturnBuffer(groups.Count);
                     for (int j = 0; j < groups.Count; j++)
                     for (int j = 0; j < groups.Count; j++)
                     {
                     {
-                        buffer.Span[j] = groups[j + 1].Value;
+                        buffer[j] = groups[j + 1].Value;
                     }
                     }
-                }
 
 
-                return new(groups.Count);
+                    return new(buffer.Length);
+                }
             }
             }
             else
             else
             {
             {
-                buffer.Span[0] = LuaValue.Nil;
-                return new(1);
+                return new(context.Return(LuaValue.Nil));
             }
             }
-        });
-
-        return new(1);
+        })));
     }
     }
 
 
-    public async ValueTask<int> GSub(LuaFunctionExecutionContext context, Memory<LuaValue> buffer, CancellationToken cancellationToken)
+    public async ValueTask<int> GSub(LuaFunctionExecutionContext context, CancellationToken cancellationToken)
     {
     {
         var s = context.GetArgument<string>(0);
         var s = context.GetArgument<string>(0);
         var pattern = context.GetArgument<string>(1);
         var pattern = context.GetArgument<string>(1);
@@ -521,14 +516,10 @@ public sealed class StringLibrary
                     context.State.Push(match.Groups[k].Value);
                     context.State.Push(match.Groups[k].Value);
                 }
                 }
 
 
-                using var methodBuffer = new PooledArray<LuaValue>(1024);
-                await func.InvokeAsync(context with
-                {
-                    ArgumentCount = match.Groups.Count,
-                    FrameBase = context.Thread.Stack.Count - context.ArgumentCount,
-                }, methodBuffer.AsMemory(), cancellationToken);
 
 
-                result = methodBuffer[0];
+                await func.InvokeAsync(context with { ArgumentCount = match.Groups.Count, FrameBase = context.Thread.Stack.Count - context.ArgumentCount, }, cancellationToken);
+
+                result = context.Thread.Stack.Get(context.ReturnFrameBase);
             }
             }
             else
             else
             {
             {
@@ -558,25 +549,22 @@ public sealed class StringLibrary
 
 
         builder.Append(s.AsSpan()[lastIndex..s.Length]);
         builder.Append(s.AsSpan()[lastIndex..s.Length]);
 
 
-        buffer.Span[0] = builder.ToString();
-        return 1;
+        return context.Return(builder.ToString());
     }
     }
 
 
-    public ValueTask<int> Len(LuaFunctionExecutionContext context, Memory<LuaValue> buffer, CancellationToken cancellationToken)
+    public ValueTask<int> Len(LuaFunctionExecutionContext context, CancellationToken cancellationToken)
     {
     {
         var s = context.GetArgument<string>(0);
         var s = context.GetArgument<string>(0);
-        buffer.Span[0] = s.Length;
-        return new(1);
+        return new(context.Return(s.Length));
     }
     }
 
 
-    public ValueTask<int> Lower(LuaFunctionExecutionContext context, Memory<LuaValue> buffer, CancellationToken cancellationToken)
+    public ValueTask<int> Lower(LuaFunctionExecutionContext context, CancellationToken cancellationToken)
     {
     {
         var s = context.GetArgument<string>(0);
         var s = context.GetArgument<string>(0);
-        buffer.Span[0] = s.ToLower();
-        return new(1);
+        return new(context.Return(s.ToLower()));
     }
     }
 
 
-    public ValueTask<int> Rep(LuaFunctionExecutionContext context, Memory<LuaValue> buffer, CancellationToken cancellationToken)
+    public ValueTask<int> Rep(LuaFunctionExecutionContext context, CancellationToken cancellationToken)
     {
     {
         var s = context.GetArgument<string>(0);
         var s = context.GetArgument<string>(0);
         var n_arg = context.GetArgument<double>(1);
         var n_arg = context.GetArgument<double>(1);
@@ -598,22 +586,20 @@ public sealed class StringLibrary
             }
             }
         }
         }
 
 
-        buffer.Span[0] = builder.ToString();
-        return new(1);
+        return new(context.Return(builder.ToString()));
     }
     }
 
 
-    public ValueTask<int> Reverse(LuaFunctionExecutionContext context, Memory<LuaValue> buffer, CancellationToken cancellationToken)
+    public ValueTask<int> Reverse(LuaFunctionExecutionContext context, CancellationToken cancellationToken)
     {
     {
         var s = context.GetArgument<string>(0);
         var s = context.GetArgument<string>(0);
         using var strBuffer = new PooledArray<char>(s.Length);
         using var strBuffer = new PooledArray<char>(s.Length);
         var span = strBuffer.AsSpan()[..s.Length];
         var span = strBuffer.AsSpan()[..s.Length];
         s.AsSpan().CopyTo(span);
         s.AsSpan().CopyTo(span);
         span.Reverse();
         span.Reverse();
-        buffer.Span[0] = span.ToString();
-        return new(1);
+        return new(context.Return(span.ToString()));
     }
     }
 
 
-    public ValueTask<int> Sub(LuaFunctionExecutionContext context, Memory<LuaValue> buffer, CancellationToken cancellationToken)
+    public ValueTask<int> Sub(LuaFunctionExecutionContext context, CancellationToken cancellationToken)
     {
     {
         var s = context.GetArgument<string>(0);
         var s = context.GetArgument<string>(0);
         var i = context.GetArgument<double>(1);
         var i = context.GetArgument<double>(1);
@@ -624,14 +610,12 @@ public sealed class StringLibrary
         LuaRuntimeException.ThrowBadArgumentIfNumberIsNotInteger(context.State, "sub", 2, i);
         LuaRuntimeException.ThrowBadArgumentIfNumberIsNotInteger(context.State, "sub", 2, i);
         LuaRuntimeException.ThrowBadArgumentIfNumberIsNotInteger(context.State, "sub", 3, j);
         LuaRuntimeException.ThrowBadArgumentIfNumberIsNotInteger(context.State, "sub", 3, j);
 
 
-        buffer.Span[0] = StringHelper.Slice(s, (int)i, (int)j).ToString();
-        return new(1);
+        return new(context.Return(StringHelper.Slice(s, (int)i, (int)j).ToString()));
     }
     }
 
 
-    public ValueTask<int> Upper(LuaFunctionExecutionContext context, Memory<LuaValue> buffer, CancellationToken cancellationToken)
+    public ValueTask<int> Upper(LuaFunctionExecutionContext context, CancellationToken cancellationToken)
     {
     {
         var s = context.GetArgument<string>(0);
         var s = context.GetArgument<string>(0);
-        buffer.Span[0] = s.ToUpper();
-        return new(1);
+        return new(context.Return(s.ToUpper()));
     }
     }
 }
 }

+ 36 - 42
src/Lua/Standard/TableLibrary.cs

@@ -8,11 +8,12 @@ namespace Lua.Standard;
 public sealed class TableLibrary
 public sealed class TableLibrary
 {
 {
     public static readonly TableLibrary Instance = new();
     public static readonly TableLibrary Instance = new();
-    
+
 
 
     public TableLibrary()
     public TableLibrary()
     {
     {
-        Functions = [
+        Functions =
+        [
             new("concat", Concat),
             new("concat", Concat),
             new("insert", Insert),
             new("insert", Insert),
             new("pack", Pack),
             new("pack", Pack),
@@ -30,25 +31,27 @@ public sealed class TableLibrary
         Name = "comp",
         Name = "comp",
         Functions = [],
         Functions = [],
         Constants = [],
         Constants = [],
-        Instructions = [
+        Instructions =
+        [
             Instruction.Le(1, 0, 1),
             Instruction.Le(1, 0, 1),
             Instruction.LoadBool(2, 1, 1),
             Instruction.LoadBool(2, 1, 1),
             Instruction.LoadBool(2, 0, 0),
             Instruction.LoadBool(2, 0, 0),
             Instruction.Return(2, 2),
             Instruction.Return(2, 2),
         ],
         ],
-        SourcePositions = [
+        SourcePositions =
+        [
             default, default, default, default,
             default, default, default, default,
         ],
         ],
         ParameterCount = 2,
         ParameterCount = 2,
         UpValues = [],
         UpValues = [],
-        Locals = [new LocalValueInfo(){Name = "a".AsMemory(),StartPc = 0,Index = 0,EndPc = 4}, new LocalValueInfo(){Name = "b".AsMemory(),StartPc = 0,Index = 1,EndPc = 4}],
+        Locals = [new LocalValueInfo() { Name = "a".AsMemory(), StartPc = 0, Index = 0, EndPc = 4 }, new LocalValueInfo() { Name = "b".AsMemory(), StartPc = 0, Index = 1, EndPc = 4 }],
         MaxStackPosition = 2,
         MaxStackPosition = 2,
         HasVariableArguments = false,
         HasVariableArguments = false,
         LineDefined = 0,
         LineDefined = 0,
         LastLineDefined = 0,
         LastLineDefined = 0,
     };
     };
 
 
-    public ValueTask<int> Concat(LuaFunctionExecutionContext context, Memory<LuaValue> buffer, CancellationToken cancellationToken)
+    public ValueTask<int> Concat(LuaFunctionExecutionContext context, CancellationToken cancellationToken)
     {
     {
         var arg0 = context.GetArgument<LuaTable>(0);
         var arg0 = context.GetArgument<LuaTable>(0);
         var arg1 = context.HasArgument(1)
         var arg1 = context.HasArgument(1)
@@ -83,11 +86,10 @@ public sealed class TableLibrary
             if (i != arg3) builder.Append(arg1);
             if (i != arg3) builder.Append(arg1);
         }
         }
 
 
-        buffer.Span[0] = builder.ToString();
-        return new(1);
+        return new(context.Return(builder.ToString()));
     }
     }
 
 
-    public ValueTask<int> Insert(LuaFunctionExecutionContext context, Memory<LuaValue> buffer, CancellationToken cancellationToken)
+    public ValueTask<int> Insert(LuaFunctionExecutionContext context, CancellationToken cancellationToken)
     {
     {
         var table = context.GetArgument<LuaTable>(0);
         var table = context.GetArgument<LuaTable>(0);
 
 
@@ -109,10 +111,10 @@ public sealed class TableLibrary
         }
         }
 
 
         table.Insert(pos, value);
         table.Insert(pos, value);
-        return new(0);
+        return new(context.Return());
     }
     }
 
 
-    public ValueTask<int> Pack(LuaFunctionExecutionContext context, Memory<LuaValue> buffer, CancellationToken cancellationToken)
+    public ValueTask<int> Pack(LuaFunctionExecutionContext context, CancellationToken cancellationToken)
     {
     {
         var table = new LuaTable(context.ArgumentCount, 1);
         var table = new LuaTable(context.ArgumentCount, 1);
 
 
@@ -121,13 +123,13 @@ public sealed class TableLibrary
         {
         {
             table[i + 1] = span[i];
             table[i + 1] = span[i];
         }
         }
+
         table["n"] = span.Length;
         table["n"] = span.Length;
 
 
-        buffer.Span[0] = table;
-        return new(1);
+        return new(context.Return(table));
     }
     }
 
 
-    public ValueTask<int> Remove(LuaFunctionExecutionContext context, Memory<LuaValue> buffer, CancellationToken cancellationToken)
+    public ValueTask<int> Remove(LuaFunctionExecutionContext context, CancellationToken cancellationToken)
     {
     {
         var table = context.GetArgument<LuaTable>(0);
         var table = context.GetArgument<LuaTable>(0);
         var n_arg = context.HasArgument(1)
         var n_arg = context.HasArgument(1)
@@ -142,43 +144,35 @@ public sealed class TableLibrary
         {
         {
             if (!context.HasArgument(1) && n == 0)
             if (!context.HasArgument(1) && n == 0)
             {
             {
-                buffer.Span[0] = LuaValue.Nil;
-                return new(1);
+                return new(context.Return(LuaValue.Nil));
             }
             }
 
 
             throw new LuaRuntimeException(context.State.GetTraceback(), "bad argument #2 to 'remove' (position out of bounds)");
             throw new LuaRuntimeException(context.State.GetTraceback(), "bad argument #2 to 'remove' (position out of bounds)");
         }
         }
         else if (n > table.ArrayLength)
         else if (n > table.ArrayLength)
         {
         {
-            buffer.Span[0] = LuaValue.Nil;
-            return new(1);
+            return new(context.Return(LuaValue.Nil));
         }
         }
 
 
-        buffer.Span[0] = table.RemoveAt(n);
-        return new(1);
+        return new(context.Return(table.RemoveAt(n)));
     }
     }
 
 
-    public async ValueTask<int> Sort(LuaFunctionExecutionContext context, Memory<LuaValue> buffer, CancellationToken cancellationToken)
+    public async ValueTask<int> Sort(LuaFunctionExecutionContext context, CancellationToken cancellationToken)
     {
     {
         var arg0 = context.GetArgument<LuaTable>(0);
         var arg0 = context.GetArgument<LuaTable>(0);
         var arg1 = context.HasArgument(1)
         var arg1 = context.HasArgument(1)
             ? context.GetArgument<LuaFunction>(1)
             ? context.GetArgument<LuaFunction>(1)
             : new LuaClosure(context.State, defaultComparer);
             : new LuaClosure(context.State, defaultComparer);
-        
-        context.Thread.PushCallStackFrame(new ()
-        {
-            Base = context.FrameBase,
-            VariableArgumentCount = 0,
-            Function = arg1
-        });
+
+        context.Thread.PushCallStackFrame(new() { Base = context.FrameBase, ReturnBase = context.ReturnFrameBase, VariableArgumentCount = 0, Function = arg1 });
         try
         try
         {
         {
             await QuickSortAsync(context, arg0.GetArrayMemory(), 0, arg0.ArrayLength - 1, arg1, cancellationToken);
             await QuickSortAsync(context, arg0.GetArrayMemory(), 0, arg0.ArrayLength - 1, arg1, cancellationToken);
-            return 0;
+            return context.Return();
         }
         }
         finally
         finally
         {
         {
-            context.Thread.PopCallStackFrameUnsafe(context.FrameBase);
+            context.Thread.PopCallStackFrameWithStackPop();
         }
         }
     }
     }
 
 
@@ -194,26 +188,24 @@ public sealed class TableLibrary
 
 
     async ValueTask<int> PartitionAsync(LuaFunctionExecutionContext context, Memory<LuaValue> memory, int low, int high, LuaFunction comparer, CancellationToken cancellationToken)
     async ValueTask<int> PartitionAsync(LuaFunctionExecutionContext context, Memory<LuaValue> memory, int low, int high, LuaFunction comparer, CancellationToken cancellationToken)
     {
     {
-        using var methodBuffer = new PooledArray<LuaValue>(1);
-
         var pivot = memory.Span[high];
         var pivot = memory.Span[high];
         int i = low - 1;
         int i = low - 1;
 
 
         for (int j = low; j < high; j++)
         for (int j = low; j < high; j++)
         {
         {
-            context.State.Push(memory.Span[j]);
-            context.State.Push(pivot);
-            await comparer.InvokeAsync(context with
-            {
-                ArgumentCount = 2,
-                FrameBase = context.Thread.Stack.Count - context.ArgumentCount,
-            }, methodBuffer.AsMemory(), cancellationToken);
+            var stack = context.Thread.Stack;
+            var top = stack.Count;
+            stack.Push(memory.Span[j]);
+            stack.Push(pivot);
+            await comparer.InvokeAsync(context with { ArgumentCount = 2, FrameBase = stack.Count - context.ArgumentCount, ReturnFrameBase = top }, cancellationToken);
 
 
-            if (methodBuffer[0].ToBoolean())
+            if (context.Thread.Stack.Get(top).ToBoolean())
             {
             {
                 i++;
                 i++;
                 Swap(memory.Span, i, j);
                 Swap(memory.Span, i, j);
             }
             }
+
+            context.Thread.Stack.PopUntil(top);
         }
         }
 
 
         Swap(memory.Span, i + 1, high);
         Swap(memory.Span, i + 1, high);
@@ -226,7 +218,7 @@ public sealed class TableLibrary
         (span[i], span[j]) = (span[j], span[i]);
         (span[i], span[j]) = (span[j], span[i]);
     }
     }
 
 
-    public ValueTask<int> Unpack(LuaFunctionExecutionContext context, Memory<LuaValue> buffer, CancellationToken cancellationToken)
+    public ValueTask<int> Unpack(LuaFunctionExecutionContext context, CancellationToken cancellationToken)
     {
     {
         var arg0 = context.GetArgument<LuaTable>(0);
         var arg0 = context.GetArgument<LuaTable>(0);
         var arg1 = context.HasArgument(1)
         var arg1 = context.HasArgument(1)
@@ -237,9 +229,11 @@ public sealed class TableLibrary
             : arg0.ArrayLength;
             : arg0.ArrayLength;
 
 
         var index = 0;
         var index = 0;
+        var count = arg2 - arg1 + 1;
+        var buffer = context.GetReturnBuffer(count);
         for (int i = arg1; i <= arg2; i++)
         for (int i = arg1; i <= arg2; i++)
         {
         {
-            buffer.Span[index] = arg0[i];
+            buffer[index] = arg0[i];
             index++;
             index++;
         }
         }
 
 

+ 4 - 2
tests/Lua.Tests/MetatableTests.cs

@@ -32,7 +32,7 @@ local b = { 4, 5, 6 }
 
 
 setmetatable(a, metatable)
 setmetatable(a, metatable)
 
 
-return a + b
+return a +b
 ";
 ";
 
 
         var result = await state.DoStringAsync(source);
         var result = await state.DoStringAsync(source);
@@ -109,7 +109,7 @@ assert(tail(a, 3) == 4)
 ";
 ";
         await state.DoStringAsync(source);
         await state.DoStringAsync(source);
     }
     }
-    
+
     [Test]
     [Test]
     public async Task Test_Metamethod_TForCall()
     public async Task Test_Metamethod_TForCall()
     {
     {
@@ -137,6 +137,7 @@ end
 ";
 ";
         await state.DoStringAsync(source);
         await state.DoStringAsync(source);
     }
     }
+
     [Test]
     [Test]
     public async Task Test_Hook_Metamethods()
     public async Task Test_Hook_Metamethods()
     {
     {
@@ -146,6 +147,7 @@ end
 
 
                      debug.sethook(function () table.insert(t,debug.traceback()) end,"c")
                      debug.sethook(function () table.insert(t,debug.traceback()) end,"c")
                      a =a+a
                      a =a+a
+                     debug.sethook()
                      return t
                      return t
                      """;
                      """;
         var r = await state.DoStringAsync(source);
         var r = await state.DoStringAsync(source);

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