Browse Source

Optimize: optimize and fix stacktrace

Akeit0 1 year ago
parent
commit
271cf48e28

+ 7 - 0
src/Lua/CodeAnalysis/Compilation/FunctionCompilationContext.cs

@@ -64,6 +64,11 @@ public class FunctionCompilationContext : IDisposable
     // loop
     // loop
     FastListCore<BreakDescription> breakQueue;
     FastListCore<BreakDescription> breakQueue;
     FastListCore<GotoDescription> gotoQueue;
     FastListCore<GotoDescription> gotoQueue;
+    
+    /// <summary>
+    /// Maximum local stack size
+    /// </summary>
+    public byte MaxStackPosition { get; set; }
 
 
     /// <summary>
     /// <summary>
     /// Chunk name (for debug)
     /// Chunk name (for debug)
@@ -271,6 +276,7 @@ public class FunctionCompilationContext : IDisposable
             UpValues = upvalues.AsSpan().ToArray(),
             UpValues = upvalues.AsSpan().ToArray(),
             Functions = functions.AsSpan().ToArray(),
             Functions = functions.AsSpan().ToArray(),
             ParameterCount = ParameterCount,
             ParameterCount = ParameterCount,
+            MaxStackPosition = MaxStackPosition,
         };
         };
 
 
         foreach (var function in functions.AsSpan())
         foreach (var function in functions.AsSpan())
@@ -300,6 +306,7 @@ public class FunctionCompilationContext : IDisposable
         LoopLevel = 0;
         LoopLevel = 0;
         ParameterCount = 0;
         ParameterCount = 0;
         HasVariableArguments = false;
         HasVariableArguments = false;
+        MaxStackPosition = 0;
     }
     }
 
 
     /// <summary>
     /// <summary>

+ 1 - 0
src/Lua/CodeAnalysis/Compilation/ScopeCompilationContext.cs

@@ -74,6 +74,7 @@ public class ScopeCompilationContext : IDisposable
     {
     {
         Function.PushInstruction(instruction, position);
         Function.PushInstruction(instruction, position);
         if (incrementStackPosition) StackPosition++;
         if (incrementStackPosition) StackPosition++;
+        Function.MaxStackPosition = Math.Max(Function.MaxStackPosition, StackPosition);
     }
     }
 
 
     [MethodImpl(MethodImplOptions.AggressiveInlining)]
     [MethodImpl(MethodImplOptions.AggressiveInlining)]

+ 33 - 1
src/Lua/Internal/PooledList.cs

@@ -36,6 +36,32 @@ internal ref struct PooledList<T>
         tail++;
         tail++;
     }
     }
 
 
+    public void AddRange(scoped ReadOnlySpan<T> items)
+    {
+        ThrowIfDisposed();
+
+        if (buffer == null)
+        {
+            buffer = ArrayPool<T>.Shared.Rent(items.Length);
+        }
+        else if (buffer.Length < tail + items.Length)
+        {
+            var newSize = buffer.Length * 2;
+            while (newSize < tail + items.Length)
+            {
+                newSize *= 2;
+            }
+            
+            var newArray = ArrayPool<T>.Shared.Rent(newSize);
+            buffer.AsSpan().CopyTo(newArray);
+            ArrayPool<T>.Shared.Return(buffer);
+            buffer = newArray;
+        }
+
+        items.CopyTo(buffer.AsSpan()[tail..]);
+        tail += items.Length;
+    }
+    
     public void Clear()
     public void Clear()
     {
     {
         ThrowIfDisposed();
         ThrowIfDisposed();
@@ -78,6 +104,12 @@ internal ref struct PooledList<T>
 
 
     void ThrowIfDisposed()
     void ThrowIfDisposed()
     {
     {
-        if (tail == -1) throw new ObjectDisposedException(nameof(PooledList<T>));
+        if (tail == -1) ThrowDisposedException();
+    }
+    
+    void ThrowDisposedException()
+    {
+        throw new ObjectDisposedException(nameof(PooledList<T>));
     }
     }
+    
 }
 }

+ 0 - 5
src/Lua/LuaCoroutine.cs

@@ -63,11 +63,6 @@ public sealed class LuaCoroutine : LuaThread, IValueTaskSource<LuaCoroutine.Yiel
                         Stack.EnsureCapacity(baseThread.Stack.Count);
                         Stack.EnsureCapacity(baseThread.Stack.Count);
                         baseThread.Stack.AsSpan().CopyTo(Stack.GetBuffer());
                         baseThread.Stack.AsSpan().CopyTo(Stack.GetBuffer());
                         Stack.NotifyTop(baseThread.Stack.Count);
                         Stack.NotifyTop(baseThread.Stack.Count);
-
-                        // copy callstack value
-                        CallStack.EnsureCapacity(baseThread.CallStack.Count);
-                        baseThread.CallStack.AsSpan().CopyTo(CallStack.GetBuffer());
-                        CallStack.NotifyTop(baseThread.CallStack.Count);
                     }
                     }
                     else
                     else
                     {
                     {

+ 0 - 3
src/Lua/LuaFunction.cs

@@ -23,9 +23,6 @@ public class LuaFunction(string name, Func<LuaFunctionExecutionContext, Memory<L
         var frame = new CallStackFrame
         var frame = new CallStackFrame
         {
         {
             Base = context.FrameBase,
             Base = context.FrameBase,
-            CallPosition = context.SourcePosition,
-            ChunkName = context.ChunkName ?? LuaState.DefaultChunkName,
-            RootChunkName = context.RootChunkName ?? LuaState.DefaultChunkName,
             VariableArgumentCount = this is Closure closure ? Math.Max(context.ArgumentCount - closure.Proto.ParameterCount, 0) : 0,
             VariableArgumentCount = this is Closure closure ? Math.Max(context.ArgumentCount - closure.Proto.ParameterCount, 0) : 0,
             Function = this,
             Function = this,
         };
         };

+ 25 - 5
src/Lua/LuaState.cs

@@ -88,13 +88,33 @@ public sealed class LuaState
 
 
     public Traceback GetTraceback()
     public Traceback GetTraceback()
     {
     {
-        // TODO: optimize
+        if(threadStack.Count==0)
+        {
+            return new()
+            {
+                RootFunc = (Closure)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()
         return new()
         {
         {
-            StackFrames = threadStack.AsSpan().ToArray()
-                .Append(MainThread)
-                .SelectMany(x => x.GetCallStackFrames()[1..].ToArray())
-                .ToArray()
+            RootFunc = (Closure)MainThread.GetCallStackFrames()[0].Function,
+            StackFrames = list.AsSpan().ToArray()
         };
         };
     }
     }
 
 

+ 8 - 4
src/Lua/Runtime/CallStackFrame.cs

@@ -7,10 +7,14 @@ namespace Lua.Runtime;
 public record struct CallStackFrame
 public record struct CallStackFrame
 {
 {
     public required int Base;
     public required int Base;
-    public required string ChunkName;
-    public required string RootChunkName;
     public required LuaFunction Function;
     public required LuaFunction Function;
-    public required SourcePosition? CallPosition;
     public required int VariableArgumentCount;
     public required int VariableArgumentCount;
-    public  int? CallerInstructionIndex;
+    public int CallerInstructionIndex;
+    internal CallStackFrameFlags Flags;
+}
+
+[Flags]
+public enum CallStackFrameFlags
+{
+    ReversedLe = 1,
 }
 }

+ 2 - 0
src/Lua/Runtime/Chunk.cs

@@ -13,6 +13,8 @@ public sealed class Chunk
     public required UpValueInfo[] UpValues { get; init; }
     public required UpValueInfo[] UpValues { get; init; }
     public required Chunk[] Functions { get; init; }
     public required Chunk[] Functions { get; init; }
     public required int ParameterCount { get; init; }
     public required int ParameterCount { get; init; }
+    
+    public required byte MaxStackPosition { get; init; }
 
 
     Chunk? rootCache;
     Chunk? rootCache;
 
 

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

@@ -108,6 +108,13 @@ public sealed class LuaStack(int initialSize = 256)
     {
     {
         return ref array[index];
         return ref array[index];
     }
     }
+    
+    [MethodImpl(MethodImplOptions.AggressiveInlining)]
+    internal ref LuaValue GetWithNotifyTop(int index)
+    {
+        if (this.top <= index) this.top = index + 1;
+        return ref array[index];
+    }
 
 
     static void ThrowEmptyStack()
     static void ThrowEmptyStack()
     {
     {

+ 204 - 164
src/Lua/Runtime/LuaVirtualMachine.cs

@@ -58,7 +58,7 @@ public static partial class LuaVirtualMachine
             var frames = callStack.AsSpan();
             var frames = callStack.AsSpan();
             if (frames.Length == BaseCallStackCount) return false;
             if (frames.Length == BaseCallStackCount) return false;
             ref readonly var frame = ref frames[^1];
             ref readonly var frame = ref frames[^1];
-            Pc = frame.CallerInstructionIndex!.Value;
+            Pc = frame.CallerInstructionIndex;
             ref readonly var lastFrame = ref frames[^2];
             ref readonly var lastFrame = ref frames[^2];
             Closure = Unsafe.As<Closure>(lastFrame.Function);
             Closure = Unsafe.As<Closure>(lastFrame.Function);
             var callInstruction = Chunk.Instructions[Pc];
             var callInstruction = Chunk.Instructions[Pc];
@@ -74,6 +74,11 @@ public static partial class LuaVirtualMachine
             if (opCode is OpCode.Eq or OpCode.Lt or OpCode.Le)
             if (opCode is OpCode.Eq or OpCode.Lt or OpCode.Le)
             {
             {
                 var compareResult = result.Length > 0 && result[0].ToBoolean();
                 var compareResult = result.Length > 0 && result[0].ToBoolean();
+                if ((frame.Flags & CallStackFrameFlags.ReversedLe) != 0)
+                {
+                    compareResult = !compareResult;
+                }
+
                 if (compareResult != (callInstruction.A == 1))
                 if (compareResult != (callInstruction.A == 1))
                 {
                 {
                     Pc++;
                     Pc++;
@@ -85,32 +90,34 @@ public static partial class LuaVirtualMachine
 
 
             var target = callInstruction.A + FrameBase;
             var target = callInstruction.A + FrameBase;
             var targetCount = result.Length;
             var targetCount = result.Length;
-            if (opCode == OpCode.TForCall)
-            {
-                target += 3;
-                targetCount = callInstruction.C;
-            }
-            else if (opCode == OpCode.Call)
+            switch (opCode)
             {
             {
-                var c = callInstruction.C;
-                if (c != 0)
+                case OpCode.Call:
                 {
                 {
-                    targetCount = c - 1;
+                    var c = callInstruction.C;
+                    if (c != 0)
+                    {
+                        targetCount = c - 1;
+                    }
+
+                    break;
                 }
                 }
-            }
-            else if (opCode == OpCode.Self)
-            {
-                Stack.Get(target) = result.Length == 0 ? LuaValue.Nil : result[0];
-                Thread.PopCallStackFrameUnsafe(target + 2);
-                return true;
-            }
-            else if (opCode is OpCode.SetTable or OpCode.SetTabUp)
-            {
-                targetCount = 0;
-            }
-            else // Other opcodes has one result
-            {
-                targetCount = 1;
+                case OpCode.TForCall:
+                    target += 3;
+                    targetCount = callInstruction.C;
+                    break;
+
+                case OpCode.Self:
+                    Stack.Get(target) = result.Length == 0 ? LuaValue.Nil : result[0];
+                    Thread.PopCallStackFrameUnsafe(target + 2);
+                    return true;
+                case OpCode.SetTable or OpCode.SetTabUp:
+                    targetCount = 0;
+                    break;
+                // Other opcodes has one result
+                default:
+                    targetCount = 1;
+                    break;
             }
             }
 
 
             var count = Math.Min(result.Length, targetCount);
             var count = Math.Min(result.Length, targetCount);
@@ -301,57 +308,54 @@ public static partial class LuaVirtualMachine
                 //This is a label to restart the execution when new function is called or restarted
                 //This is a label to restart the execution when new function is called or restarted
                 Restart:
                 Restart:
 
 
-                var instructions = context.Chunk.Instructions;
+                ref var instructionsHead = ref context.Chunk.Instructions[0];
                 var frameBase = context.FrameBase;
                 var frameBase = context.FrameBase;
                 var stack = context.Stack;
                 var stack = context.Stack;
+                stack.EnsureCapacity(frameBase + context.Chunk.MaxStackPosition);
                 ref var constHead = ref MemoryMarshalEx.UnsafeElementAt(context.Chunk.Constants, 0);
                 ref var constHead = ref MemoryMarshalEx.UnsafeElementAt(context.Chunk.Constants, 0);
 
 
-                do
+                while (true)
                 {
                 {
-                    var instruction = instructions[++context.Pc];
-                    context.Instruction = instruction;
-                    var iA = (int)instruction.A;
-                    var ra1 = iA + frameBase + 1;
-                    switch (instruction.OpCode)
+                    var instructionRef = Unsafe.Add(ref instructionsHead, ++context.Pc);
+                    context.Instruction = instructionRef;
+                    switch (instructionRef.OpCode)
                     {
                     {
                         case OpCode.Move:
                         case OpCode.Move:
-                            stack.EnsureCapacity(ra1);
+                            var instruction = instructionRef;
                             ref var stackHead = ref stack.Get(frameBase);
                             ref var stackHead = ref stack.Get(frameBase);
+                            var iA = instruction.A;
                             Unsafe.Add(ref stackHead, iA) = Unsafe.Add(ref stackHead, instruction.UIntB);
                             Unsafe.Add(ref stackHead, iA) = Unsafe.Add(ref stackHead, instruction.UIntB);
-                            stack.NotifyTop(ra1);
+                            stack.NotifyTop(iA + frameBase + 1);
                             continue;
                             continue;
                         case OpCode.LoadK:
                         case OpCode.LoadK:
-                            stack.EnsureCapacity(ra1);
-                            stack.Get(ra1 - 1) = Unsafe.Add(ref constHead, instruction.Bx);
-                            stack.NotifyTop(ra1);
+                            instruction = instructionRef;
+                            stack.GetWithNotifyTop(instruction.A + frameBase) = Unsafe.Add(ref constHead, instruction.Bx);
                             continue;
                             continue;
                         case OpCode.LoadBool:
                         case OpCode.LoadBool:
-                            stack.EnsureCapacity(ra1);
-                            stack.Get(ra1 - 1) = instruction.B != 0;
-                            stack.NotifyTop(ra1);
+                            instruction = instructionRef;
+                            stack.GetWithNotifyTop(instruction.A + frameBase) = instruction.B != 0;
                             if (instruction.C != 0) context.Pc++;
                             if (instruction.C != 0) context.Pc++;
                             continue;
                             continue;
                         case OpCode.LoadNil:
                         case OpCode.LoadNil:
+                            instruction = instructionRef;
+                            var ra1 = instruction.A + frameBase + 1;
                             var iB = instruction.B;
                             var iB = instruction.B;
-                            stack.EnsureCapacity(ra1 + iB);
                             stack.GetBuffer().Slice(ra1 - 1, iB + 1).Clear();
                             stack.GetBuffer().Slice(ra1 - 1, iB + 1).Clear();
                             stack.NotifyTop(ra1 + iB);
                             stack.NotifyTop(ra1 + iB);
                             continue;
                             continue;
                         case OpCode.GetUpVal:
                         case OpCode.GetUpVal:
-                            stack.EnsureCapacity(ra1);
-                            stack.Get(ra1 - 1) = context.Closure.GetUpValue(instruction.B);
-                            stack.NotifyTop(ra1);
+                            instruction = instructionRef;
+                            stack.GetWithNotifyTop(instruction.A + frameBase) = context.Closure.GetUpValue(instruction.B);
                             continue;
                             continue;
                         case OpCode.GetTabUp:
                         case OpCode.GetTabUp:
-                            stack.EnsureCapacity(ra1);
+                            instruction = instructionRef;
                             stackHead = ref stack.Get(frameBase);
                             stackHead = ref stack.Get(frameBase);
                             ref readonly var vc = ref RKC(ref stackHead, ref constHead, instruction);
                             ref readonly var vc = ref RKC(ref stackHead, ref constHead, instruction);
                             var table = context.Closure.GetUpValue(instruction.B);
                             var table = context.Closure.GetUpValue(instruction.B);
 
 
                             if (table.TryReadTable(out var luaTable) && luaTable.TryGetValue(vc, out var resultValue))
                             if (table.TryReadTable(out var luaTable) && luaTable.TryGetValue(vc, out var resultValue))
                             {
                             {
-                                Unsafe.Add(ref stackHead, iA) = resultValue;
-                                stack.NotifyTop(ra1);
+                                stack.GetWithNotifyTop(instruction.A + frameBase) = resultValue;
                                 continue;
                                 continue;
                             }
                             }
 
 
@@ -362,20 +366,16 @@ public static partial class LuaVirtualMachine
                             }
                             }
 
 
                             postOperation = PostOperationType.SetResult;
                             postOperation = PostOperationType.SetResult;
-                            break;
+                            goto Await;
                         case OpCode.GetTable:
                         case OpCode.GetTable:
-                            stack.EnsureCapacity(ra1);
+                            instruction = instructionRef;
                             stackHead = ref stack.Get(frameBase);
                             stackHead = ref stack.Get(frameBase);
                             ref readonly var vb = ref Unsafe.Add(ref stackHead, instruction.UIntB);
                             ref readonly var vb = ref Unsafe.Add(ref stackHead, instruction.UIntB);
                             vc = ref RKC(ref stackHead, ref constHead, instruction);
                             vc = ref RKC(ref stackHead, ref constHead, instruction);
-                            if (vb.TryReadTable(out luaTable))
+                            if (vb.TryReadTable(out luaTable) && luaTable.TryGetValue(vc, out resultValue))
                             {
                             {
-                                if (luaTable.TryGetValue(vc, out resultValue))
-                                {
-                                    Unsafe.Add(ref stackHead, iA) = resultValue;
-                                    stack.NotifyTop(ra1);
-                                    continue;
-                                }
+                                stack.GetWithNotifyTop(instruction.A + frameBase) = resultValue;
+                                continue;
                             }
                             }
 
 
                             if (TryGetMetaTableValue(vb, vc, ref context, out doRestart))
                             if (TryGetMetaTableValue(vb, vc, ref context, out doRestart))
@@ -385,9 +385,9 @@ public static partial class LuaVirtualMachine
                             }
                             }
 
 
                             postOperation = PostOperationType.SetResult;
                             postOperation = PostOperationType.SetResult;
-                            break;
-
+                            goto Await;
                         case OpCode.SetTabUp:
                         case OpCode.SetTabUp:
+                            instruction = instructionRef;
                             stackHead = ref stack.Get(frameBase);
                             stackHead = ref stack.Get(frameBase);
                             vb = ref RKB(ref stackHead, ref constHead, instruction);
                             vb = ref RKB(ref stackHead, ref constHead, instruction);
                             if (vb.TryReadNumber(out var numB))
                             if (vb.TryReadNumber(out var numB))
@@ -415,12 +415,14 @@ public static partial class LuaVirtualMachine
                             }
                             }
 
 
                             postOperation = PostOperationType.Nop;
                             postOperation = PostOperationType.Nop;
-                            break;
+                            goto Await;
 
 
                         case OpCode.SetUpVal:
                         case OpCode.SetUpVal:
-                            context.Closure.SetUpValue(instruction.B, stack.Get(ra1 - 1));
+                            instruction = instructionRef;
+                            context.Closure.SetUpValue(instruction.B, stack.Get(instruction.A + frameBase));
                             continue;
                             continue;
                         case OpCode.SetTable:
                         case OpCode.SetTable:
+                            instruction = instructionRef;
                             stackHead = ref stack.Get(frameBase);
                             stackHead = ref stack.Get(frameBase);
                             vb = ref RKB(ref stackHead, ref constHead, instruction);
                             vb = ref RKB(ref stackHead, ref constHead, instruction);
                             if (vb.TryReadNumber(out numB))
                             if (vb.TryReadNumber(out numB))
@@ -432,17 +434,11 @@ public static partial class LuaVirtualMachine
                                 }
                                 }
                             }
                             }
 
 
-                            table = Unsafe.Add(ref stackHead, iA);
+                            table = Unsafe.Add(ref stackHead, instruction.A);
 
 
                             if (table.TryReadTable(out luaTable))
                             if (table.TryReadTable(out luaTable))
                             {
                             {
-                                if (luaTable.Metatable == null || !luaTable.Metatable!.ContainsKey(Metamethods.NewIndex))
-                                {
-                                    luaTable[vb] = RKC(ref stackHead, ref constHead, instruction);
-                                    continue;
-                                }
-
-                                if (luaTable.ContainsKey(vb))
+                                if (luaTable.Metatable == null || !luaTable.Metatable.ContainsKey(Metamethods.NewIndex) || luaTable.ContainsKey(vb))
                                 {
                                 {
                                     luaTable[vb] = RKC(ref stackHead, ref constHead, instruction);
                                     luaTable[vb] = RKC(ref stackHead, ref constHead, instruction);
                                     continue;
                                     continue;
@@ -457,28 +453,26 @@ public static partial class LuaVirtualMachine
                             }
                             }
 
 
                             postOperation = PostOperationType.Nop;
                             postOperation = PostOperationType.Nop;
-                            break;
-
-
+                            goto Await;
                         case OpCode.NewTable:
                         case OpCode.NewTable:
-                            stack.EnsureCapacity(ra1);
-                            stack.Get(ra1 - 1) = new LuaTable(instruction.B, instruction.C);
-                            stack.NotifyTop(ra1);
+                            instruction = instructionRef;
+                            stack.GetWithNotifyTop(instruction.A + frameBase) = new LuaTable(instruction.B, instruction.C);
                             continue;
                             continue;
                         case OpCode.Self:
                         case OpCode.Self:
-                            stack.EnsureCapacity(ra1 + 1);
+                            instruction = instructionRef;
+                            iA = instruction.A;
                             stackHead = ref stack.Get(frameBase);
                             stackHead = ref stack.Get(frameBase);
                             vc = ref RKC(ref stackHead, ref constHead, instruction);
                             vc = ref RKC(ref stackHead, ref constHead, instruction);
                             table = Unsafe.Add(ref stackHead, instruction.UIntB);
                             table = Unsafe.Add(ref stackHead, instruction.UIntB);
-
                             if (table.TryReadTable(out luaTable) && luaTable.TryGetValue(vc, out resultValue))
                             if (table.TryReadTable(out luaTable) && luaTable.TryGetValue(vc, out resultValue))
                             {
                             {
                                 Unsafe.Add(ref stackHead, iA) = resultValue;
                                 Unsafe.Add(ref stackHead, iA) = resultValue;
                                 Unsafe.Add(ref stackHead, iA + 1) = table;
                                 Unsafe.Add(ref stackHead, iA + 1) = table;
-                                stack.NotifyTop(ra1 + 2);
+                                stack.NotifyTop(iA + frameBase + 2);
                                 continue;
                                 continue;
                             }
                             }
 
 
+
                             if (TryGetMetaTableValue(table, vc, ref context, out doRestart))
                             if (TryGetMetaTableValue(table, vc, ref context, out doRestart))
                             {
                             {
                                 if (doRestart) goto Restart;
                                 if (doRestart) goto Restart;
@@ -486,27 +480,27 @@ public static partial class LuaVirtualMachine
                             }
                             }
 
 
                             postOperation = PostOperationType.Self;
                             postOperation = PostOperationType.Self;
-                            break;
+                            goto Await;
                         case OpCode.Add:
                         case OpCode.Add:
-                            stack.EnsureCapacity(ra1);
+                            instruction = instructionRef;
+                            iA = instruction.A;
                             stackHead = ref stack.Get(frameBase);
                             stackHead = ref stack.Get(frameBase);
                             vb = ref RKB(ref stackHead, ref constHead, instruction);
                             vb = ref RKB(ref stackHead, ref constHead, instruction);
                             vc = ref RKC(ref stackHead, ref constHead, instruction);
                             vc = ref RKC(ref stackHead, ref constHead, instruction);
-
-                            if(vb.Type  == LuaValueType.Number && vc.Type== LuaValueType.Number)
+                            if (vb.Type == LuaValueType.Number && vc.Type == LuaValueType.Number)
                             {
                             {
-                                Unsafe.Add(ref stackHead, iA) = vb.UnsafeReadDouble() + vc.UnsafeReadDouble() ;
-                                stack.NotifyTop(ra1);
+                                Unsafe.Add(ref stackHead, iA) = vb.UnsafeReadDouble() + vc.UnsafeReadDouble();
+                                stack.NotifyTop(iA + frameBase + 1);
                                 continue;
                                 continue;
                             }
                             }
-                            
+
                             if (vb.TryReadDouble(out numB) && vc.TryReadDouble(out var numC))
                             if (vb.TryReadDouble(out numB) && vc.TryReadDouble(out var numC))
                             {
                             {
                                 Unsafe.Add(ref stackHead, iA) = numB + numC;
                                 Unsafe.Add(ref stackHead, iA) = numB + numC;
-                                stack.NotifyTop(ra1);
+                                stack.NotifyTop(iA + frameBase + 1);
                                 continue;
                                 continue;
                             }
                             }
-                            
+
                             if (ExecuteBinaryOperationMetaMethod(vb, vc, ref context, Metamethods.Add, "add", out doRestart))
                             if (ExecuteBinaryOperationMetaMethod(vb, vc, ref context, Metamethods.Add, "add", out doRestart))
                             {
                             {
                                 if (doRestart) goto Restart;
                                 if (doRestart) goto Restart;
@@ -514,22 +508,25 @@ public static partial class LuaVirtualMachine
                             }
                             }
 
 
                             postOperation = PostOperationType.SetResult;
                             postOperation = PostOperationType.SetResult;
-                            break;
+                            goto Await;
                         case OpCode.Sub:
                         case OpCode.Sub:
-                            stack.EnsureCapacity(ra1);
+                            instruction = instructionRef;
+                            iA = instruction.A;
                             stackHead = ref stack.Get(frameBase);
                             stackHead = ref stack.Get(frameBase);
                             vb = ref RKB(ref stackHead, ref constHead, instruction);
                             vb = ref RKB(ref stackHead, ref constHead, instruction);
                             vc = ref RKC(ref stackHead, ref constHead, instruction);
                             vc = ref RKC(ref stackHead, ref constHead, instruction);
-                            
-                            if(vb.Type  == LuaValueType.Number && vc.Type== LuaValueType.Number)
+
+                            if (vb.Type == LuaValueType.Number && vc.Type == LuaValueType.Number)
                             {
                             {
-                                Unsafe.Add(ref stackHead, iA) = vb.UnsafeReadDouble() - vc.UnsafeReadDouble() ;
+                                ra1 = iA + frameBase + 1;
+                                Unsafe.Add(ref stackHead, iA) = vb.UnsafeReadDouble() - vc.UnsafeReadDouble();
                                 stack.NotifyTop(ra1);
                                 stack.NotifyTop(ra1);
                                 continue;
                                 continue;
                             }
                             }
 
 
                             if (vb.TryReadDouble(out numB) && vc.TryReadDouble(out numC))
                             if (vb.TryReadDouble(out numB) && vc.TryReadDouble(out numC))
                             {
                             {
+                                ra1 = iA + frameBase + 1;
                                 Unsafe.Add(ref stackHead, iA) = numB - numC;
                                 Unsafe.Add(ref stackHead, iA) = numB - numC;
                                 stack.NotifyTop(ra1);
                                 stack.NotifyTop(ra1);
                                 continue;
                                 continue;
@@ -542,23 +539,26 @@ public static partial class LuaVirtualMachine
                             }
                             }
 
 
                             postOperation = PostOperationType.SetResult;
                             postOperation = PostOperationType.SetResult;
-                            break;
+                            goto Await;
 
 
                         case OpCode.Mul:
                         case OpCode.Mul:
-                            stack.EnsureCapacity(ra1);
+                            instruction = instructionRef;
+                            iA = instruction.A;
                             stackHead = ref stack.Get(frameBase);
                             stackHead = ref stack.Get(frameBase);
                             vb = ref RKB(ref stackHead, ref constHead, instruction);
                             vb = ref RKB(ref stackHead, ref constHead, instruction);
                             vc = ref RKC(ref stackHead, ref constHead, instruction);
                             vc = ref RKC(ref stackHead, ref constHead, instruction);
-                            
-                            if(vb.Type  == LuaValueType.Number && vc.Type== LuaValueType.Number)
+
+                            if (vb.Type == LuaValueType.Number && vc.Type == LuaValueType.Number)
                             {
                             {
-                                Unsafe.Add(ref stackHead, iA) = vb.UnsafeReadDouble() * vc.UnsafeReadDouble() ;
+                                ra1 = iA + frameBase + 1;
+                                Unsafe.Add(ref stackHead, iA) = vb.UnsafeReadDouble() * vc.UnsafeReadDouble();
                                 stack.NotifyTop(ra1);
                                 stack.NotifyTop(ra1);
                                 continue;
                                 continue;
                             }
                             }
 
 
                             if (vb.TryReadDouble(out numB) && vc.TryReadDouble(out numC))
                             if (vb.TryReadDouble(out numB) && vc.TryReadDouble(out numC))
                             {
                             {
+                                ra1 = iA + frameBase + 1;
                                 Unsafe.Add(ref stackHead, iA) = numB * numC;
                                 Unsafe.Add(ref stackHead, iA) = numB * numC;
                                 stack.NotifyTop(ra1);
                                 stack.NotifyTop(ra1);
                                 continue;
                                 continue;
@@ -571,23 +571,26 @@ public static partial class LuaVirtualMachine
                             }
                             }
 
 
                             postOperation = PostOperationType.SetResult;
                             postOperation = PostOperationType.SetResult;
-                            break;
+                            goto Await;
 
 
                         case OpCode.Div:
                         case OpCode.Div:
-                            stack.EnsureCapacity(ra1);
+                            instruction = instructionRef;
+                            iA = instruction.A;
                             stackHead = ref stack.Get(frameBase);
                             stackHead = ref stack.Get(frameBase);
                             vb = ref RKB(ref stackHead, ref constHead, instruction);
                             vb = ref RKB(ref stackHead, ref constHead, instruction);
                             vc = ref RKC(ref stackHead, ref constHead, instruction);
                             vc = ref RKC(ref stackHead, ref constHead, instruction);
-                            
-                            if(vb.Type  == LuaValueType.Number && vc.Type== LuaValueType.Number)
+
+                            if (vb.Type == LuaValueType.Number && vc.Type == LuaValueType.Number)
                             {
                             {
-                                Unsafe.Add(ref stackHead, iA) = vb.UnsafeReadDouble() / vc.UnsafeReadDouble() ;
+                                ra1 = iA + frameBase + 1;
+                                Unsafe.Add(ref stackHead, iA) = vb.UnsafeReadDouble() / vc.UnsafeReadDouble();
                                 stack.NotifyTop(ra1);
                                 stack.NotifyTop(ra1);
                                 continue;
                                 continue;
                             }
                             }
 
 
                             if (vb.TryReadDouble(out numB) && vc.TryReadDouble(out numC))
                             if (vb.TryReadDouble(out numB) && vc.TryReadDouble(out numC))
                             {
                             {
+                                ra1 = iA + frameBase + 1;
                                 Unsafe.Add(ref stackHead, iA) = numB / numC;
                                 Unsafe.Add(ref stackHead, iA) = numB / numC;
                                 stack.NotifyTop(ra1);
                                 stack.NotifyTop(ra1);
                                 continue;
                                 continue;
@@ -600,9 +603,10 @@ public static partial class LuaVirtualMachine
                             }
                             }
 
 
                             postOperation = PostOperationType.SetResult;
                             postOperation = PostOperationType.SetResult;
-                            break;
+                            goto Await;
                         case OpCode.Mod:
                         case OpCode.Mod:
-                            stack.EnsureCapacity(ra1);
+                            instruction = instructionRef;
+                            iA = instruction.A;
                             stackHead = ref stack.Get(frameBase);
                             stackHead = ref stack.Get(frameBase);
                             vb = ref RKB(ref stackHead, ref constHead, instruction);
                             vb = ref RKB(ref stackHead, ref constHead, instruction);
                             vc = ref RKC(ref stackHead, ref constHead, instruction);
                             vc = ref RKC(ref stackHead, ref constHead, instruction);
@@ -615,7 +619,6 @@ public static partial class LuaVirtualMachine
                                 }
                                 }
 
 
                                 Unsafe.Add(ref stackHead, iA) = mod;
                                 Unsafe.Add(ref stackHead, iA) = mod;
-                                stack.NotifyTop(ra1);
                                 continue;
                                 continue;
                             }
                             }
 
 
@@ -626,14 +629,16 @@ public static partial class LuaVirtualMachine
                             }
                             }
 
 
                             postOperation = PostOperationType.SetResult;
                             postOperation = PostOperationType.SetResult;
-                            break;
+                            goto Await;
                         case OpCode.Pow:
                         case OpCode.Pow:
-                            stack.EnsureCapacity(ra1);
+                            instruction = instructionRef;
+                            iA = instruction.A;
                             stackHead = ref stack.Get(frameBase);
                             stackHead = ref stack.Get(frameBase);
                             vb = ref RKB(ref stackHead, ref constHead, instruction);
                             vb = ref RKB(ref stackHead, ref constHead, instruction);
                             vc = ref RKC(ref stackHead, ref constHead, instruction);
                             vc = ref RKC(ref stackHead, ref constHead, instruction);
                             if (vb.TryReadDouble(out numB) && vc.TryReadDouble(out numC))
                             if (vb.TryReadDouble(out numB) && vc.TryReadDouble(out numC))
                             {
                             {
+                                ra1 = iA + frameBase + 1;
                                 Unsafe.Add(ref stackHead, iA) = Math.Pow(numB, numC);
                                 Unsafe.Add(ref stackHead, iA) = Math.Pow(numB, numC);
                                 stack.NotifyTop(ra1);
                                 stack.NotifyTop(ra1);
                                 continue;
                                 continue;
@@ -646,17 +651,18 @@ public static partial class LuaVirtualMachine
                             }
                             }
 
 
                             postOperation = PostOperationType.SetResult;
                             postOperation = PostOperationType.SetResult;
-                            break;
-
+                            goto Await;
                         case OpCode.Unm:
                         case OpCode.Unm:
-                            stack.EnsureCapacity(ra1);
+                            instruction = instructionRef;
+                            iA = instruction.A;
                             stackHead = ref stack.Get(frameBase);
                             stackHead = ref stack.Get(frameBase);
                             vb = ref Unsafe.Add(ref stackHead, instruction.UIntB);
                             vb = ref Unsafe.Add(ref stackHead, instruction.UIntB);
 
 
                             if (vb.TryReadDouble(out numB))
                             if (vb.TryReadDouble(out numB))
                             {
                             {
+                                //ra1 = iA + frameBase + 1;
                                 Unsafe.Add(ref stackHead, iA) = -numB;
                                 Unsafe.Add(ref stackHead, iA) = -numB;
-                                stack.NotifyTop(ra1);
+                                //stack.NotifyTop(ra1);
                                 continue;
                                 continue;
                             }
                             }
 
 
@@ -667,25 +673,29 @@ public static partial class LuaVirtualMachine
                             }
                             }
 
 
                             postOperation = PostOperationType.SetResult;
                             postOperation = PostOperationType.SetResult;
-                            break;
-
+                            goto Await;
                         case OpCode.Not:
                         case OpCode.Not:
+                            instruction = instructionRef;
+                            iA = instruction.A;
+                            ra1 = iA + frameBase + 1;
                             stack.EnsureCapacity(ra1);
                             stack.EnsureCapacity(ra1);
                             stackHead = ref stack.Get(frameBase);
                             stackHead = ref stack.Get(frameBase);
                             Unsafe.Add(ref stackHead, iA) = !Unsafe.Add(ref stackHead, instruction.UIntB).ToBoolean();
                             Unsafe.Add(ref stackHead, iA) = !Unsafe.Add(ref stackHead, instruction.UIntB).ToBoolean();
-                            stack.NotifyTop(ra1);
+                            //stack.NotifyTop(ra1);
                             continue;
                             continue;
 
 
                         case OpCode.Len:
                         case OpCode.Len:
-                            stack.EnsureCapacity(ra1);
+                            instruction = instructionRef;
                             stackHead = ref stack.Get(frameBase);
                             stackHead = ref stack.Get(frameBase);
 
 
                             vb = ref Unsafe.Add(ref stackHead, instruction.UIntB);
                             vb = ref Unsafe.Add(ref stackHead, instruction.UIntB);
 
 
                             if (vb.TryReadString(out var str))
                             if (vb.TryReadString(out var str))
                             {
                             {
+                                iA = instruction.A;
+                                // ra1 = iA + frameBase + 1;
                                 Unsafe.Add(ref stackHead, iA) = str.Length;
                                 Unsafe.Add(ref stackHead, iA) = str.Length;
-                                stack.NotifyTop(ra1);
+                                //stack.NotifyTop(ra1);
                                 continue;
                                 continue;
                             }
                             }
 
 
@@ -696,7 +706,7 @@ public static partial class LuaVirtualMachine
                             }
                             }
 
 
                             postOperation = PostOperationType.SetResult;
                             postOperation = PostOperationType.SetResult;
-                            break;
+                            goto Await;
                         case OpCode.Concat:
                         case OpCode.Concat:
                             if (Concat(ref context, out doRestart))
                             if (Concat(ref context, out doRestart))
                             {
                             {
@@ -705,9 +715,11 @@ public static partial class LuaVirtualMachine
                             }
                             }
 
 
                             postOperation = PostOperationType.SetResult;
                             postOperation = PostOperationType.SetResult;
-                            break;
+                            goto Await;
                         case OpCode.Jmp:
                         case OpCode.Jmp:
+                            instruction = instructionRef;
                             context.Pc += instruction.SBx;
                             context.Pc += instruction.SBx;
+                            iA = instruction.A;
                             if (iA != 0)
                             if (iA != 0)
                             {
                             {
                                 context.State.CloseUpValues(context.Thread, frameBase + iA - 1);
                                 context.State.CloseUpValues(context.Thread, frameBase + iA - 1);
@@ -715,7 +727,8 @@ public static partial class LuaVirtualMachine
 
 
                             continue;
                             continue;
                         case OpCode.Eq:
                         case OpCode.Eq:
-                            stack.EnsureCapacity(ra1);
+                            instruction = instructionRef;
+                            iA = instruction.A;
                             stackHead = ref stack.Get(frameBase);
                             stackHead = ref stack.Get(frameBase);
                             vb = ref RKB(ref stackHead, ref constHead, instruction);
                             vb = ref RKB(ref stackHead, ref constHead, instruction);
                             vc = ref RKC(ref stackHead, ref constHead, instruction);
                             vc = ref RKC(ref stackHead, ref constHead, instruction);
@@ -736,9 +749,10 @@ public static partial class LuaVirtualMachine
                             }
                             }
 
 
                             postOperation = PostOperationType.Compare;
                             postOperation = PostOperationType.Compare;
-                            break;
+                            goto Await;
                         case OpCode.Lt:
                         case OpCode.Lt:
-                            stack.EnsureCapacity(ra1);
+                            instruction = instructionRef;
+                            iA = instruction.A;
                             stackHead = ref stack.Get(frameBase);
                             stackHead = ref stack.Get(frameBase);
                             vb = ref RKB(ref stackHead, ref constHead, instruction);
                             vb = ref RKB(ref stackHead, ref constHead, instruction);
                             vc = ref RKC(ref stackHead, ref constHead, instruction);
                             vc = ref RKC(ref stackHead, ref constHead, instruction);
@@ -773,10 +787,11 @@ public static partial class LuaVirtualMachine
                             }
                             }
 
 
                             postOperation = PostOperationType.Compare;
                             postOperation = PostOperationType.Compare;
-                            break;
+                            goto Await;
 
 
                         case OpCode.Le:
                         case OpCode.Le:
-                            stack.EnsureCapacity(ra1);
+                            instruction = instructionRef;
+                            iA = instruction.A;
                             stackHead = ref stack.Get(frameBase);
                             stackHead = ref stack.Get(frameBase);
                             vb = ref RKB(ref stackHead, ref constHead, instruction);
                             vb = ref RKB(ref stackHead, ref constHead, instruction);
                             vc = ref RKC(ref stackHead, ref constHead, instruction);
                             vc = ref RKC(ref stackHead, ref constHead, instruction);
@@ -810,17 +825,18 @@ public static partial class LuaVirtualMachine
                             }
                             }
 
 
                             postOperation = PostOperationType.Compare;
                             postOperation = PostOperationType.Compare;
-                            break;
+                            goto Await;
 
 
                         case OpCode.Test:
                         case OpCode.Test:
-                            if (stack.Get(ra1 - 1).ToBoolean() != (instruction.C == 1))
+                            instruction = instructionRef;
+                            if (stack.Get(instruction.A + frameBase).ToBoolean() != (instruction.C == 1))
                             {
                             {
                                 context.Pc++;
                                 context.Pc++;
                             }
                             }
 
 
                             continue;
                             continue;
-
                         case OpCode.TestSet:
                         case OpCode.TestSet:
+                            instruction = instructionRef;
                             vb = ref stack.Get(instruction.B + frameBase);
                             vb = ref stack.Get(instruction.B + frameBase);
                             if (vb.ToBoolean() != (instruction.C == 1))
                             if (vb.ToBoolean() != (instruction.C == 1))
                             {
                             {
@@ -828,8 +844,7 @@ public static partial class LuaVirtualMachine
                             }
                             }
                             else
                             else
                             {
                             {
-                                stack.Get(ra1 - 1) = vb;
-                                stack.NotifyTop(ra1);
+                                stack.GetWithNotifyTop(instruction.A + frameBase) = vb;
                             }
                             }
 
 
                             continue;
                             continue;
@@ -842,7 +857,7 @@ public static partial class LuaVirtualMachine
                             }
                             }
 
 
                             postOperation = PostOperationType.Call;
                             postOperation = PostOperationType.Call;
-                            break;
+                            goto Await;
                         case OpCode.TailCall:
                         case OpCode.TailCall:
                             if (TailCall(ref context, out doRestart))
                             if (TailCall(ref context, out doRestart))
                             {
                             {
@@ -852,8 +867,11 @@ public static partial class LuaVirtualMachine
                             }
                             }
 
 
                             postOperation = PostOperationType.TailCall;
                             postOperation = PostOperationType.TailCall;
-                            break;
+                            goto Await;
                         case OpCode.Return:
                         case OpCode.Return:
+                            instruction = instructionRef;
+                            iA = instruction.A;
+                            ra1 = iA + frameBase + 1;
                             context.State.CloseUpValues(context.Thread, frameBase);
                             context.State.CloseUpValues(context.Thread, frameBase);
                             if (context.Pop(instruction, frameBase)) goto Restart;
                             if (context.Pop(instruction, frameBase)) goto Restart;
                             var retCount = instruction.B - 1;
                             var retCount = instruction.B - 1;
@@ -871,26 +889,24 @@ public static partial class LuaVirtualMachine
                             context.ResultCount = retCount;
                             context.ResultCount = retCount;
                             goto End;
                             goto End;
                         case OpCode.ForLoop:
                         case OpCode.ForLoop:
-                            stack.EnsureCapacity(ra1 + 3);
-                            ref var indexRef = ref stack.Get(ra1 - 1);
-
-                            var lastIndex = indexRef.UnsafeReadDouble();
-                            var step = Unsafe.Add(ref indexRef, 2).UnsafeReadDouble();
-                            var index = lastIndex + step;
+                            ref var indexRef = ref stack.Get(instructionRef.A + frameBase);
                             var limit = Unsafe.Add(ref indexRef, 1).UnsafeReadDouble();
                             var limit = Unsafe.Add(ref indexRef, 1).UnsafeReadDouble();
+                            var step = Unsafe.Add(ref indexRef, 2).UnsafeReadDouble();
+                            var index = indexRef.UnsafeReadDouble() + step;
+
                             if (step >= 0 ? index <= limit : limit <= index)
                             if (step >= 0 ? index <= limit : limit <= index)
                             {
                             {
-                                context.Pc += instruction.SBx;
+                                context.Pc += instructionRef.SBx;
                                 indexRef = index;
                                 indexRef = index;
                                 Unsafe.Add(ref indexRef, 3) = index;
                                 Unsafe.Add(ref indexRef, 3) = index;
-                                stack.NotifyTop(ra1 + 3);
+                                stack.NotifyTop(instructionRef.A + frameBase + 4);
                                 continue;
                                 continue;
                             }
                             }
 
 
-                            stack.NotifyTop(ra1);
+                            stack.NotifyTop(instructionRef.A + frameBase + 1);
                             continue;
                             continue;
                         case OpCode.ForPrep:
                         case OpCode.ForPrep:
-                            indexRef = ref stack.Get(ra1 - 1);
+                            indexRef = ref stack.Get(instructionRef.A + frameBase);
 
 
                             if (!indexRef.TryReadDouble(out var init))
                             if (!indexRef.TryReadDouble(out var init))
                             {
                             {
@@ -911,8 +927,8 @@ public static partial class LuaVirtualMachine
                             }
                             }
 
 
                             indexRef = init - step;
                             indexRef = init - step;
-                            stack.NotifyTop(ra1);
-                            context.Pc += instruction.SBx;
+                            //stack.NotifyTop(instructionRef.A + frameBase + 1);
+                            context.Pc += instructionRef.SBx;
                             continue;
                             continue;
                         case OpCode.TForCall:
                         case OpCode.TForCall:
                             if (TForCall(ref context, out doRestart))
                             if (TForCall(ref context, out doRestart))
@@ -922,9 +938,13 @@ public static partial class LuaVirtualMachine
                             }
                             }
 
 
                             postOperation = PostOperationType.TForCall;
                             postOperation = PostOperationType.TForCall;
-                            break;
+                            goto Await;
                         case OpCode.TForLoop:
                         case OpCode.TForLoop:
+                            instruction = instructionRef;
+                            iA = instruction.A;
+                            ra1 = iA + frameBase + 1;
                             ref var forState = ref stack.Get(ra1);
                             ref var forState = ref stack.Get(ra1);
+
                             if (forState.Type is not LuaValueType.Nil)
                             if (forState.Type is not LuaValueType.Nil)
                             {
                             {
                                 Unsafe.Add(ref forState, -1) = forState;
                                 Unsafe.Add(ref forState, -1) = forState;
@@ -936,11 +956,17 @@ public static partial class LuaVirtualMachine
                             SetList(ref context);
                             SetList(ref context);
                             continue;
                             continue;
                         case OpCode.Closure:
                         case OpCode.Closure:
+                            instruction = instructionRef;
+                            iA = instruction.A;
+                            ra1 = iA + frameBase + 1;
                             stack.EnsureCapacity(ra1);
                             stack.EnsureCapacity(ra1);
                             stack.Get(ra1 - 1) = new Closure(context.State, context.Chunk.Functions[instruction.SBx]);
                             stack.Get(ra1 - 1) = new Closure(context.State, context.Chunk.Functions[instruction.SBx]);
                             stack.NotifyTop(ra1);
                             stack.NotifyTop(ra1);
                             continue;
                             continue;
                         case OpCode.VarArg:
                         case OpCode.VarArg:
+                            instruction = instructionRef;
+                            iA = instruction.A;
+                            ra1 = iA + frameBase + 1;
                             var frameVariableArgumentCount = context.VariableArgumentCount;
                             var frameVariableArgumentCount = context.VariableArgumentCount;
                             var count = instruction.B == 0
                             var count = instruction.B == 0
                                 ? frameVariableArgumentCount
                                 ? frameVariableArgumentCount
@@ -950,8 +976,8 @@ public static partial class LuaVirtualMachine
                             stackHead = ref stack.Get(0);
                             stackHead = ref stack.Get(0);
                             for (int i = 0; i < count; i++)
                             for (int i = 0; i < count; i++)
                             {
                             {
-                                Unsafe.Add(ref stackHead,ra + i) = frameVariableArgumentCount > i
-                                    ? Unsafe.Add(ref stackHead,frameBase - (frameVariableArgumentCount - i))
+                                Unsafe.Add(ref stackHead, ra + i) = frameVariableArgumentCount > i
+                                    ? Unsafe.Add(ref stackHead, frameBase - (frameVariableArgumentCount - i))
                                     : default;
                                     : default;
                             }
                             }
 
 
@@ -959,12 +985,12 @@ public static partial class LuaVirtualMachine
                             continue;
                             continue;
                         case OpCode.ExtraArg:
                         case OpCode.ExtraArg:
                         default:
                         default:
-                            ThrowLuaNotImplementedException(ref context, instruction.OpCode);
+                            ThrowLuaNotImplementedException(ref context, context.Instruction.OpCode);
                             return;
                             return;
                     }
                     }
-                } while (postOperation == PostOperationType.None);
-
+                }
 
 
+                Await:
                 //Set the state to await and return with setting this method as the task's continuation
                 //Set the state to await and return with setting this method as the task's continuation
                 state = State.Await;
                 state = State.Await;
                 Builder.AwaitOnCompleted(ref context.Awaiter, ref this);
                 Builder.AwaitOnCompleted(ref context.Awaiter, ref this);
@@ -980,7 +1006,7 @@ public static partial class LuaVirtualMachine
             {
             {
                 if (e is not LuaRuntimeException)
                 if (e is not LuaRuntimeException)
                 {
                 {
-                    e = new LuaRuntimeCSharpException(context.State.GetTraceback(), e);
+                    e = new LuaRuntimeCSharpException(GetTracebacks(ref context), e);
                 }
                 }
 
 
                 context.PopOnTopCallStackFrames();
                 context.PopOnTopCallStackFrames();
@@ -1074,7 +1100,7 @@ public static partial class LuaVirtualMachine
             }
             }
             else
             else
             {
             {
-                LuaRuntimeException.AttemptInvalidOperation(GetTracebacks(ref context), "call", metamethod);
+                LuaRuntimeException.AttemptInvalidOperation(GetTracebacks(ref context), "call", va);
             }
             }
         }
         }
 
 
@@ -1318,7 +1344,7 @@ public static partial class LuaVirtualMachine
             : instruction.B;
             : instruction.B;
 
 
         table.EnsureArrayCapacity((instruction.C - 1) * 50 + count);
         table.EnsureArrayCapacity((instruction.C - 1) * 50 + count);
-        stack.AsSpan().Slice(RA + 1, count)
+        stack.GetBuffer().Slice(RA + 1, count)
             .CopyTo(table.GetArraySpan()[((instruction.C - 1) * 50)..]);
             .CopyTo(table.GetArraySpan()[((instruction.C - 1) * 50)..]);
     }
     }
 
 
@@ -1506,7 +1532,6 @@ public static partial class LuaVirtualMachine
                 context.Thread.PopCallStackFrame();
                 context.Thread.PopCallStackFrame();
                 var RA = context.Instruction.A + context.FrameBase;
                 var RA = context.Instruction.A + context.FrameBase;
                 stack.Get(RA) = resultCount == 0 ? LuaValue.Nil : context.ResultsBuffer[0];
                 stack.Get(RA) = resultCount == 0 ? LuaValue.Nil : context.ResultsBuffer[0];
-                stack.NotifyTop(RA + 1);
                 context.ClearResultsBuffer(resultCount);
                 context.ClearResultsBuffer(resultCount);
                 return true;
                 return true;
             }
             }
@@ -1553,7 +1578,6 @@ public static partial class LuaVirtualMachine
                 var RA = context.Instruction.A + context.FrameBase;
                 var RA = context.Instruction.A + context.FrameBase;
                 var resultCount = context.Awaiter.GetResult();
                 var resultCount = context.Awaiter.GetResult();
                 stack.Get(RA) = resultCount == 0 ? LuaValue.Nil : context.ResultsBuffer[0];
                 stack.Get(RA) = resultCount == 0 ? LuaValue.Nil : context.ResultsBuffer[0];
-                stack.NotifyTop(RA + 1);
                 context.ClearResultsBuffer(resultCount);
                 context.ClearResultsBuffer(resultCount);
                 return true;
                 return true;
             }
             }
@@ -1565,7 +1589,6 @@ public static partial class LuaVirtualMachine
         {
         {
             var RA = context.Instruction.A + context.FrameBase;
             var RA = context.Instruction.A + context.FrameBase;
             stack.Get(RA) = table.ArrayLength;
             stack.Get(RA) = table.ArrayLength;
-            stack.NotifyTop(RA + 1);
             return true;
             return true;
         }
         }
 
 
@@ -1573,11 +1596,14 @@ public static partial class LuaVirtualMachine
         return true;
         return true;
     }
     }
 
 
+
     [MethodImpl(MethodImplOptions.NoInlining)]
     [MethodImpl(MethodImplOptions.NoInlining)]
     static bool ExecuteCompareOperationMetaMethod(LuaValue vb, LuaValue vc,
     static bool ExecuteCompareOperationMetaMethod(LuaValue vb, LuaValue vc,
         ref VirtualMachineExecutionContext context, string name, string? description, out bool doRestart)
         ref VirtualMachineExecutionContext context, string name, string? description, out bool doRestart)
     {
     {
         doRestart = false;
         doRestart = false;
+        bool reverseLe = false;
+        ReCheck:
         if (vb.TryGetMetamethod(context.State, name, out var metamethod) ||
         if (vb.TryGetMetamethod(context.State, name, out var metamethod) ||
             vc.TryGetMetamethod(context.State, name, out metamethod))
             vc.TryGetMetamethod(context.State, name, out metamethod))
         {
         {
@@ -1590,7 +1616,7 @@ public static partial class LuaVirtualMachine
             stack.Push(vb);
             stack.Push(vb);
             stack.Push(vc);
             stack.Push(vc);
             var newFrame = func.CreateNewFrame(ref context, stack.Count - 2);
             var newFrame = func.CreateNewFrame(ref context, stack.Count - 2);
-
+            if (reverseLe) newFrame.Flags |= CallStackFrameFlags.ReversedLe;
             context.Thread.PushCallStackFrame(newFrame);
             context.Thread.PushCallStackFrame(newFrame);
 
 
             if (func.IsClosure)
             if (func.IsClosure)
@@ -1608,6 +1634,7 @@ public static partial class LuaVirtualMachine
                 context.Thread.PopCallStackFrame();
                 context.Thread.PopCallStackFrame();
                 var resultCount = context.Awaiter.GetResult();
                 var resultCount = context.Awaiter.GetResult();
                 var compareResult = resultCount != 0 && context.ResultsBuffer[0].ToBoolean();
                 var compareResult = resultCount != 0 && context.ResultsBuffer[0].ToBoolean();
+                compareResult = reverseLe ? !compareResult : compareResult;
                 if (compareResult != (context.Instruction.A == 1))
                 if (compareResult != (context.Instruction.A == 1))
                 {
                 {
                     context.Pc++;
                     context.Pc++;
@@ -1621,8 +1648,21 @@ public static partial class LuaVirtualMachine
             return false;
             return false;
         }
         }
 
 
+        if (name == Metamethods.Le)
+        {
+            reverseLe = true;
+            name = Metamethods.Lt;
+            (vb, vc) = (vc, vb);
+            goto ReCheck;
+        }
+
         if (description != null)
         if (description != null)
         {
         {
+            if (reverseLe)
+            {
+                (vb, vc) = (vc, vb);
+            }
+
             LuaRuntimeException.AttemptInvalidOperation(GetTracebacks(ref context), description, vb, vc);
             LuaRuntimeException.AttemptInvalidOperation(GetTracebacks(ref context), description, vb, vc);
         }
         }
         else
         else
@@ -1663,6 +1703,10 @@ public static partial class LuaVirtualMachine
         {
         {
             argumentCount = (ushort)(thread.Stack.Count - (RA + 1));
             argumentCount = (ushort)(thread.Stack.Count - (RA + 1));
         }
         }
+        else
+        {
+            thread.Stack.NotifyTop(RA + 1 + argumentCount);
+        }
 
 
         var newBase = RA + 1;
         var newBase = RA + 1;
         var variableArgumentCount = function.GetVariableArgumentCount(argumentCount);
         var variableArgumentCount = function.GetVariableArgumentCount(argumentCount);
@@ -1686,6 +1730,10 @@ public static partial class LuaVirtualMachine
         {
         {
             argumentCount = (ushort)(stack.Count - (RA + 1));
             argumentCount = (ushort)(stack.Count - (RA + 1));
         }
         }
+        else
+        {
+            thread.Stack.NotifyTop(RA + 1 + argumentCount);
+        }
 
 
         var newBase = RA + 1;
         var newBase = RA + 1;
 
 
@@ -1711,17 +1759,15 @@ public static partial class LuaVirtualMachine
 
 
     static Traceback GetTracebacks(ref VirtualMachineExecutionContext context)
     static Traceback GetTracebacks(ref VirtualMachineExecutionContext context)
     {
     {
-        return GetTracebacks(context.State, context.Chunk, context.Pc);
+        return GetTracebacks(context.State, context.Pc);
     }
     }
 
 
-    static Traceback GetTracebacks(LuaState state, Chunk chunk, int pc)
+    static Traceback GetTracebacks(LuaState state, int pc)
     {
     {
         var frame = state.CurrentThread.GetCurrentFrame();
         var frame = state.CurrentThread.GetCurrentFrame();
         state.CurrentThread.PushCallStackFrame(frame with
         state.CurrentThread.PushCallStackFrame(frame with
         {
         {
-            CallPosition = chunk.SourcePositions[pc],
-            ChunkName = chunk.Name,
-            RootChunkName = chunk.GetRoot().Name,
+            CallerInstructionIndex = pc
         });
         });
         var tracebacks = state.GetTraceback();
         var tracebacks = state.GetTraceback();
         state.CurrentThread.PopCallStackFrame();
         state.CurrentThread.PopCallStackFrame();
@@ -1734,9 +1780,6 @@ public static partial class LuaVirtualMachine
         return new()
         return new()
         {
         {
             Base = newBase,
             Base = newBase,
-            CallPosition = context.Chunk.SourcePositions[context.Pc],
-            ChunkName = context.Chunk.Name,
-            RootChunkName = context.Chunk.GetRoot().Name,
             Function = function,
             Function = function,
             VariableArgumentCount = variableArgumentCount,
             VariableArgumentCount = variableArgumentCount,
             CallerInstructionIndex = context.Pc,
             CallerInstructionIndex = context.Pc,
@@ -1752,9 +1795,6 @@ public static partial class LuaVirtualMachine
             Thread = context.Thread,
             Thread = context.Thread,
             ArgumentCount = arguments,
             ArgumentCount = arguments,
             FrameBase = frame.Base,
             FrameBase = frame.Base,
-            SourcePosition = frame.CallPosition,
-            ChunkName = frame.ChunkName,
-            RootChunkName = frame.RootChunkName,
             CallerInstructionIndex = frame.CallerInstructionIndex,
             CallerInstructionIndex = frame.CallerInstructionIndex,
         }, context.ResultsBuffer, context.CancellationToken);
         }, context.ResultsBuffer, context.CancellationToken);
     }
     }

+ 54 - 9
src/Lua/Runtime/Tracebacks.cs

@@ -1,24 +1,69 @@
+using System.Globalization;
+using System.Runtime.CompilerServices;
 using Lua.CodeAnalysis;
 using Lua.CodeAnalysis;
+using Lua.Internal;
 
 
 namespace Lua.Runtime;
 namespace Lua.Runtime;
 
 
 public class Traceback
 public class Traceback
 {
 {
+    public required Closure RootFunc { get; init; }
     public required CallStackFrame[] StackFrames { get; init; }
     public required CallStackFrame[] StackFrames { get; init; }
 
 
-    internal string RootChunkName => StackFrames.Length == 0 ? "" : StackFrames[^1].RootChunkName;
-    internal SourcePosition LastPosition => StackFrames.Length == 0 ? default : StackFrames[^1].CallPosition!.Value;
+    internal string RootChunkName => RootFunc.Proto.Name; //StackFrames.Length == 0 ? "" : StackFrames[^1].Function is Closure closure ? closure.Proto.GetRoot().Name : StackFrames[^2].Function.Name;
+
+    internal SourcePosition LastPosition
+    {
+        get
+        {
+            var stackFrames = StackFrames.AsSpan();
+            for (var index = stackFrames.Length - 1; index >= 0; index--)
+            {
+                LuaFunction lastFunc = index > 0 ? stackFrames[index - 1].Function : RootFunc;
+                var frame = stackFrames[index];
+                if (lastFunc is Closure closure)
+                {
+                    var p = closure.Proto;
+                    return p.SourcePositions[frame.CallerInstructionIndex];
+                }
+            }
+
+            return default;
+        }
+    }
+
 
 
     public override string ToString()
     public override string ToString()
     {
     {
-        var str = string.Join("\n   ", StackFrames
-            .Where(x => x.CallPosition != null)
-            .Select(x =>
+        using var list = new PooledList<char>(64);
+        list.AddRange("stack traceback:\n");
+        var stackFrames = StackFrames.AsSpan();
+        var intFormatBuffer = (stackalloc char[15]);
+        for (var index = stackFrames.Length - 1; index >= 0; index--)
+        {
+            LuaFunction lastFunc = index > 0 ? stackFrames[index - 1].Function : RootFunc;
+            var frame = stackFrames[index];
+            if (lastFunc is not null and not Closure)
+            {
+                list.AddRange("\t[C#]: in function '");
+                list.AddRange(lastFunc.Name);
+                list.AddRange("'\n");
+            }
+            else if (lastFunc is Closure closure)
             {
             {
-                return $"{x.RootChunkName}:{x.CallPosition!.Value.Line}: {(string.IsNullOrEmpty(x.ChunkName) ? "" : $"in '{x.ChunkName}'")}";
-            })
-            .Reverse());
+                var p = closure.Proto;
+                var root = p.GetRoot();
+                list.AddRange("\t");
+                list.AddRange(root.Name);
+                list.AddRange(":");
+                p.SourcePositions[frame.CallerInstructionIndex].Line.TryFormat(intFormatBuffer, out var charsWritten,provider:CultureInfo.InvariantCulture);
+                list.AddRange(intFormatBuffer[..charsWritten]);
+                list.AddRange(root == p ? ": in '" : ": in function '");
+                list.AddRange(p.Name);
+                list.AddRange("'\n");
+            }
+        }
 
 
-        return $"stack traceback:\n   {str}";
+        return list.AsSpan().ToString();
     }
     }
 }
 }

+ 20 - 6
src/Lua/Standard/CoroutineLibrary.cs

@@ -64,15 +64,29 @@ public sealed class CoroutineLibrary
 
 
             stack.Push(thread);
             stack.Push(thread);
             stack.PushRange(context.Arguments);
             stack.PushRange(context.Arguments);
+            context.Thread.PushCallStackFrame(new()
+            {
+                Base = frameBase,
+                VariableArgumentCount = 0,
+                Function = arg0,
+            });
+            try
+            {
+                var resultCount = await thread.ResumeAsync(context with
+                {
+                    ArgumentCount = context.ArgumentCount + 1,
+                    FrameBase = frameBase,
+                }, buffer, cancellationToken);
 
 
-            var resultCount = await thread.ResumeAsync(context with
+                buffer.Span[1..].CopyTo(buffer.Span[0..]);
+                return resultCount - 1;
+            }
+            finally
             {
             {
-                ArgumentCount = context.ArgumentCount + 1,
-                FrameBase = frameBase,
-            }, buffer, cancellationToken);
+                context.Thread.PopCallStackFrame();
+            }
 
 
-            buffer.Span[1..].CopyTo(buffer.Span[0..]);
-            return resultCount - 1;
+           
         });
         });
 
 
         return new(1);
         return new(1);

+ 18 - 3
src/Lua/Standard/TableLibrary.cs

@@ -8,6 +8,7 @@ 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()
     {
     {
@@ -40,6 +41,7 @@ public sealed class TableLibrary
         ],
         ],
         ParameterCount = 2,
         ParameterCount = 2,
         UpValues = [],
         UpValues = [],
+        MaxStackPosition = 2,
     };
     };
 
 
     public ValueTask<int> Concat(LuaFunctionExecutionContext context, Memory<LuaValue> buffer, CancellationToken cancellationToken)
     public ValueTask<int> Concat(LuaFunctionExecutionContext context, Memory<LuaValue> buffer, CancellationToken cancellationToken)
@@ -158,9 +160,22 @@ public sealed class TableLibrary
         var arg1 = context.HasArgument(1)
         var arg1 = context.HasArgument(1)
             ? context.GetArgument<LuaFunction>(1)
             ? context.GetArgument<LuaFunction>(1)
             : new Closure(context.State, defaultComparer);
             : new Closure(context.State, defaultComparer);
-
-        await QuickSortAsync(context, arg0.GetArrayMemory(), 0, arg0.ArrayLength - 1, arg1, cancellationToken);
-        return 0;
+        
+        context.Thread.PushCallStackFrame(new ()
+        {
+            Base = context.FrameBase,
+            VariableArgumentCount = 0,
+            Function = arg1
+        });
+        try
+        {
+            await QuickSortAsync(context, arg0.GetArrayMemory(), 0, arg0.ArrayLength - 1, arg1, cancellationToken);
+            return 0;
+        }
+        finally
+        {
+            context.Thread.PopCallStackFrameUnsafe(context.FrameBase);
+        }
     }
     }
 
 
     async ValueTask QuickSortAsync(LuaFunctionExecutionContext context, Memory<LuaValue> memory, int low, int high, LuaFunction comparer, CancellationToken cancellationToken)
     async ValueTask QuickSortAsync(LuaFunctionExecutionContext context, Memory<LuaValue> memory, int low, int high, LuaFunction comparer, CancellationToken cancellationToken)