Browse Source

Optimize: VM skip stack bounds check

Akeit0 1 year ago
parent
commit
59e165c8c2
2 changed files with 57 additions and 47 deletions
  1. 10 0
      src/Lua/Runtime/LuaStack.cs
  2. 47 47
      src/Lua/Runtime/LuaVirtualMachine.cs

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

@@ -1,4 +1,5 @@
 using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
 using Lua.Internal;
 
 namespace Lua.Runtime;
@@ -109,6 +110,15 @@ public sealed class LuaStack(int initialSize = 256)
         return ref array[index];
     }
     
+    [MethodImpl(MethodImplOptions.AggressiveInlining)]
+    internal ref LuaValue FastGet(int index)
+    {
+#if NET6_0_OR_GREATER
+        return ref Unsafe.Add(ref MemoryMarshal.GetArrayDataReference(array), index);
+#endif
+        return ref array[index];
+    }
+    
     [MethodImpl(MethodImplOptions.AggressiveInlining)]
     internal ref LuaValue GetWithNotifyTop(int index)
     {

+ 47 - 47
src/Lua/Runtime/LuaVirtualMachine.cs

@@ -108,7 +108,7 @@ public static partial class LuaVirtualMachine
                     break;
 
                 case OpCode.Self:
-                    Stack.Get(target) = result.Length == 0 ? LuaValue.Nil : result[0];
+                    Stack.FastGet(target) = result.Length == 0 ? LuaValue.Nil : result[0];
                     Thread.PopCallStackFrameUnsafe(target + 2);
                     return true;
                 case OpCode.SetTable or OpCode.SetTabUp:
@@ -268,7 +268,7 @@ public static partial class LuaVirtualMachine
                         case PostOperationType.Nop: break;
                         case PostOperationType.SetResult:
                             var RA = context.Instruction.A + context.FrameBase;
-                            context.Stack.Get(RA) = context.TaskResult == 0 ? LuaValue.Nil : context.ResultsBuffer[0];
+                            context.Stack.FastGet(RA) = context.TaskResult == 0 ? LuaValue.Nil : context.ResultsBuffer[0];
                             context.Stack.NotifyTop(RA + 1);
                             context.ClearResultsBuffer();
                             break;
@@ -322,7 +322,7 @@ public static partial class LuaVirtualMachine
                     {
                         case OpCode.Move:
                             var instruction = instructionRef;
-                            ref var stackHead = ref stack.Get(frameBase);
+                            ref var stackHead = ref stack.FastGet(frameBase);
                             var iA = instruction.A;
                             Unsafe.Add(ref stackHead, iA) = Unsafe.Add(ref stackHead, instruction.UIntB);
                             stack.NotifyTop(iA + frameBase + 1);
@@ -349,7 +349,7 @@ public static partial class LuaVirtualMachine
                             continue;
                         case OpCode.GetTabUp:
                             instruction = instructionRef;
-                            stackHead = ref stack.Get(frameBase);
+                            stackHead = ref stack.FastGet(frameBase);
                             ref readonly var vc = ref RKC(ref stackHead, ref constHead, instruction);
                             var table = context.Closure.GetUpValue(instruction.B);
 
@@ -369,7 +369,7 @@ public static partial class LuaVirtualMachine
                             goto Await;
                         case OpCode.GetTable:
                             instruction = instructionRef;
-                            stackHead = ref stack.Get(frameBase);
+                            stackHead = ref stack.FastGet(frameBase);
                             ref readonly var vb = ref Unsafe.Add(ref stackHead, instruction.UIntB);
                             vc = ref RKC(ref stackHead, ref constHead, instruction);
                             if (vb.TryReadTable(out luaTable) && luaTable.TryGetValue(vc, out resultValue))
@@ -388,7 +388,7 @@ public static partial class LuaVirtualMachine
                             goto Await;
                         case OpCode.SetTabUp:
                             instruction = instructionRef;
-                            stackHead = ref stack.Get(frameBase);
+                            stackHead = ref stack.FastGet(frameBase);
                             vb = ref RKB(ref stackHead, ref constHead, instruction);
                             if (vb.TryReadNumber(out var numB))
                             {
@@ -419,11 +419,11 @@ public static partial class LuaVirtualMachine
 
                         case OpCode.SetUpVal:
                             instruction = instructionRef;
-                            context.Closure.SetUpValue(instruction.B, stack.Get(instruction.A + frameBase));
+                            context.Closure.SetUpValue(instruction.B, stack.FastGet(instruction.A + frameBase));
                             continue;
                         case OpCode.SetTable:
                             instruction = instructionRef;
-                            stackHead = ref stack.Get(frameBase);
+                            stackHead = ref stack.FastGet(frameBase);
                             vb = ref RKB(ref stackHead, ref constHead, instruction);
                             if (vb.TryReadNumber(out numB))
                             {
@@ -461,7 +461,7 @@ public static partial class LuaVirtualMachine
                         case OpCode.Self:
                             instruction = instructionRef;
                             iA = instruction.A;
-                            stackHead = ref stack.Get(frameBase);
+                            stackHead = ref stack.FastGet(frameBase);
                             vc = ref RKC(ref stackHead, ref constHead, instruction);
                             table = Unsafe.Add(ref stackHead, instruction.UIntB);
                             if (table.TryReadTable(out luaTable) && luaTable.TryGetValue(vc, out resultValue))
@@ -484,7 +484,7 @@ public static partial class LuaVirtualMachine
                         case OpCode.Add:
                             instruction = instructionRef;
                             iA = instruction.A;
-                            stackHead = ref stack.Get(frameBase);
+                            stackHead = ref stack.FastGet(frameBase);
                             vb = ref RKB(ref stackHead, ref constHead, instruction);
                             vc = ref RKC(ref stackHead, ref constHead, instruction);
                             if (vb.Type == LuaValueType.Number && vc.Type == LuaValueType.Number)
@@ -512,7 +512,7 @@ public static partial class LuaVirtualMachine
                         case OpCode.Sub:
                             instruction = instructionRef;
                             iA = instruction.A;
-                            stackHead = ref stack.Get(frameBase);
+                            stackHead = ref stack.FastGet(frameBase);
                             vb = ref RKB(ref stackHead, ref constHead, instruction);
                             vc = ref RKC(ref stackHead, ref constHead, instruction);
 
@@ -544,7 +544,7 @@ public static partial class LuaVirtualMachine
                         case OpCode.Mul:
                             instruction = instructionRef;
                             iA = instruction.A;
-                            stackHead = ref stack.Get(frameBase);
+                            stackHead = ref stack.FastGet(frameBase);
                             vb = ref RKB(ref stackHead, ref constHead, instruction);
                             vc = ref RKC(ref stackHead, ref constHead, instruction);
 
@@ -576,7 +576,7 @@ public static partial class LuaVirtualMachine
                         case OpCode.Div:
                             instruction = instructionRef;
                             iA = instruction.A;
-                            stackHead = ref stack.Get(frameBase);
+                            stackHead = ref stack.FastGet(frameBase);
                             vb = ref RKB(ref stackHead, ref constHead, instruction);
                             vc = ref RKC(ref stackHead, ref constHead, instruction);
 
@@ -607,7 +607,7 @@ public static partial class LuaVirtualMachine
                         case OpCode.Mod:
                             instruction = instructionRef;
                             iA = instruction.A;
-                            stackHead = ref stack.Get(frameBase);
+                            stackHead = ref stack.FastGet(frameBase);
                             vb = ref RKB(ref stackHead, ref constHead, instruction);
                             vc = ref RKC(ref stackHead, ref constHead, instruction);
                             if (vb.TryReadDouble(out numB) && vc.TryReadDouble(out numC))
@@ -633,7 +633,7 @@ public static partial class LuaVirtualMachine
                         case OpCode.Pow:
                             instruction = instructionRef;
                             iA = instruction.A;
-                            stackHead = ref stack.Get(frameBase);
+                            stackHead = ref stack.FastGet(frameBase);
                             vb = ref RKB(ref stackHead, ref constHead, instruction);
                             vc = ref RKC(ref stackHead, ref constHead, instruction);
                             if (vb.TryReadDouble(out numB) && vc.TryReadDouble(out numC))
@@ -655,7 +655,7 @@ public static partial class LuaVirtualMachine
                         case OpCode.Unm:
                             instruction = instructionRef;
                             iA = instruction.A;
-                            stackHead = ref stack.Get(frameBase);
+                            stackHead = ref stack.FastGet(frameBase);
                             vb = ref Unsafe.Add(ref stackHead, instruction.UIntB);
 
                             if (vb.TryReadDouble(out numB))
@@ -679,14 +679,14 @@ public static partial class LuaVirtualMachine
                             iA = instruction.A;
                             ra1 = iA + frameBase + 1;
                             stack.EnsureCapacity(ra1);
-                            stackHead = ref stack.Get(frameBase);
+                            stackHead = ref stack.FastGet(frameBase);
                             Unsafe.Add(ref stackHead, iA) = !Unsafe.Add(ref stackHead, instruction.UIntB).ToBoolean();
                             //stack.NotifyTop(ra1);
                             continue;
 
                         case OpCode.Len:
                             instruction = instructionRef;
-                            stackHead = ref stack.Get(frameBase);
+                            stackHead = ref stack.FastGet(frameBase);
 
                             vb = ref Unsafe.Add(ref stackHead, instruction.UIntB);
 
@@ -729,7 +729,7 @@ public static partial class LuaVirtualMachine
                         case OpCode.Eq:
                             instruction = instructionRef;
                             iA = instruction.A;
-                            stackHead = ref stack.Get(frameBase);
+                            stackHead = ref stack.FastGet(frameBase);
                             vb = ref RKB(ref stackHead, ref constHead, instruction);
                             vc = ref RKC(ref stackHead, ref constHead, instruction);
                             if (vb == vc)
@@ -753,7 +753,7 @@ public static partial class LuaVirtualMachine
                         case OpCode.Lt:
                             instruction = instructionRef;
                             iA = instruction.A;
-                            stackHead = ref stack.Get(frameBase);
+                            stackHead = ref stack.FastGet(frameBase);
                             vb = ref RKB(ref stackHead, ref constHead, instruction);
                             vc = ref RKC(ref stackHead, ref constHead, instruction);
 
@@ -792,7 +792,7 @@ public static partial class LuaVirtualMachine
                         case OpCode.Le:
                             instruction = instructionRef;
                             iA = instruction.A;
-                            stackHead = ref stack.Get(frameBase);
+                            stackHead = ref stack.FastGet(frameBase);
                             vb = ref RKB(ref stackHead, ref constHead, instruction);
                             vc = ref RKC(ref stackHead, ref constHead, instruction);
 
@@ -829,7 +829,7 @@ public static partial class LuaVirtualMachine
 
                         case OpCode.Test:
                             instruction = instructionRef;
-                            if (stack.Get(instruction.A + frameBase).ToBoolean() != (instruction.C == 1))
+                            if (stack.FastGet(instruction.A + frameBase).ToBoolean() != (instruction.C == 1))
                             {
                                 context.Pc++;
                             }
@@ -837,7 +837,7 @@ public static partial class LuaVirtualMachine
                             continue;
                         case OpCode.TestSet:
                             instruction = instructionRef;
-                            vb = ref stack.Get(instruction.B + frameBase);
+                            vb = ref stack.FastGet(instruction.B + frameBase);
                             if (vb.ToBoolean() != (instruction.C == 1))
                             {
                                 context.Pc++;
@@ -889,7 +889,7 @@ public static partial class LuaVirtualMachine
                             context.ResultCount = retCount;
                             goto End;
                         case OpCode.ForLoop:
-                            ref var indexRef = ref stack.Get(instructionRef.A + frameBase);
+                            ref var indexRef = ref stack.FastGet(instructionRef.A + frameBase);
                             var limit = Unsafe.Add(ref indexRef, 1).UnsafeReadDouble();
                             var step = Unsafe.Add(ref indexRef, 2).UnsafeReadDouble();
                             var index = indexRef.UnsafeReadDouble() + step;
@@ -906,7 +906,7 @@ public static partial class LuaVirtualMachine
                             stack.NotifyTop(instructionRef.A + frameBase + 1);
                             continue;
                         case OpCode.ForPrep:
-                            indexRef = ref stack.Get(instructionRef.A + frameBase);
+                            indexRef = ref stack.FastGet(instructionRef.A + frameBase);
 
                             if (!indexRef.TryReadDouble(out var init))
                             {
@@ -943,7 +943,7 @@ public static partial class LuaVirtualMachine
                             instruction = instructionRef;
                             iA = instruction.A;
                             ra1 = iA + frameBase + 1;
-                            ref var forState = ref stack.Get(ra1);
+                            ref var forState = ref stack.FastGet(ra1);
 
                             if (forState.Type is not LuaValueType.Nil)
                             {
@@ -960,7 +960,7 @@ public static partial class LuaVirtualMachine
                             iA = instruction.A;
                             ra1 = iA + frameBase + 1;
                             stack.EnsureCapacity(ra1);
-                            stack.Get(ra1 - 1) = new Closure(context.State, context.Chunk.Functions[instruction.SBx]);
+                            stack.FastGet(ra1 - 1) = new Closure(context.State, context.Chunk.Functions[instruction.SBx]);
                             stack.NotifyTop(ra1);
                             continue;
                         case OpCode.VarArg:
@@ -973,7 +973,7 @@ public static partial class LuaVirtualMachine
                                 : instruction.B - 1;
                             var ra = ra1 - 1;
                             stack.EnsureCapacity(ra + count);
-                            stackHead = ref stack.Get(0);
+                            stackHead = ref stack.FastGet(0);
                             for (int i = 0; i < count; i++)
                             {
                                 Unsafe.Add(ref stackHead, ra + i) = frameVariableArgumentCount > i
@@ -1042,7 +1042,7 @@ public static partial class LuaVirtualMachine
         var instruction = context.Instruction;
         var RA = instruction.A + context.FrameBase;
         var RB = instruction.B + context.FrameBase;
-        ref var stackHead = ref stack.Get(0);
+        ref var stackHead = ref stack.FastGet(0);
         var table = Unsafe.Add(ref stackHead, RB);
         Unsafe.Add(ref stackHead, RA + 1) = table;
         Unsafe.Add(ref stackHead, RA) = context.TaskResult == 0 ? LuaValue.Nil : context.ResultsBuffer[0];
@@ -1056,7 +1056,7 @@ public static partial class LuaVirtualMachine
         var stack = context.Stack;
         var RA = instruction.A + context.FrameBase;
         stack.EnsureCapacity(RA + 1);
-        ref var stackHead = ref stack.Get(context.FrameBase);
+        ref var stackHead = ref stack.FastGet(context.FrameBase);
         ref var constHead = ref MemoryMarshalEx.UnsafeElementAt(context.Chunk.Constants, 0);
         var vb = RKB(ref stackHead, ref constHead, instruction);
         var vc = RKC(ref stackHead, ref constHead, instruction);
@@ -1078,7 +1078,7 @@ public static partial class LuaVirtualMachine
 
         if (bIsValid && cIsValid)
         {
-            stack.Get(RA) = strB + strC;
+            stack.FastGet(RA) = strB + strC;
             stack.NotifyTop(RA + 1);
             doRestart = false;
             return true;
@@ -1091,7 +1091,7 @@ public static partial class LuaVirtualMachine
     {
         var instruction = context.Instruction;
         var RA = instruction.A + context.FrameBase;
-        var va = context.Stack.Get(RA);
+        var va = context.Stack.FastGet(RA);
         if (!va.TryReadFunction(out var func))
         {
             if (va.TryGetMetamethod(context.State, Metamethods.Call, out var metamethod) &&
@@ -1154,7 +1154,7 @@ public static partial class LuaVirtualMachine
                     var stack = context.Stack;
                     var RA = instruction.A + context.FrameBase;
                     stack.EnsureCapacity(RA + resultCount);
-                    ref var stackHead = ref stack.Get(RA);
+                    ref var stackHead = ref stack.FastGet(RA);
                     var results = context.ResultsBuffer.AsSpan(0, rawResultCount);
                     for (int i = 0; i < resultCount; i++)
                     {
@@ -1193,7 +1193,7 @@ public static partial class LuaVirtualMachine
             var stack = context.Stack;
             var RA = instruction.A + context.FrameBase;
             stack.EnsureCapacity(RA + resultCount);
-            ref var stackHead = ref stack.Get(RA);
+            ref var stackHead = ref stack.FastGet(RA);
             var results = context.ResultsBuffer.AsSpan(0, rawResultCount);
             for (int i = 0; i < resultCount; i++)
             {
@@ -1217,7 +1217,7 @@ public static partial class LuaVirtualMachine
 
         state.CloseUpValues(thread, context.FrameBase);
 
-        var va = stack.Get(RA);
+        var va = stack.FastGet(RA);
         if (!va.TryReadFunction(out var func))
         {
             if (!va.TryGetMetamethod(state, Metamethods.Call, out var metamethod) &&
@@ -1273,15 +1273,15 @@ public static partial class LuaVirtualMachine
         var stack = context.Stack;
         var RA = instruction.A + context.FrameBase;
 
-        var iteratorRaw = stack.Get(RA);
+        var iteratorRaw = stack.FastGet(RA);
         if (!iteratorRaw.TryReadFunction(out var iterator))
         {
             LuaRuntimeException.AttemptInvalidOperation(GetTracebacks(ref context), "call", iteratorRaw);
         }
 
         var newBase = RA + 3 + instruction.C;
-        stack.Get(newBase) = stack.Get(RA + 1);
-        stack.Get(newBase + 1) = stack.Get(RA + 2);
+        stack.FastGet(newBase) = stack.FastGet(RA + 1);
+        stack.FastGet(newBase + 1) = stack.FastGet(RA + 2);
         stack.NotifyTop(newBase + 2);
         var newFrame = iterator.CreateNewFrame(ref context, newBase);
         context.Thread.PushCallStackFrame(newFrame);
@@ -1319,7 +1319,7 @@ public static partial class LuaVirtualMachine
         for (int i = 1; i <= instruction.C; i++)
         {
             var index = i - 1;
-            stack.Get(RA + 2 + i) = index >= resultCount
+            stack.FastGet(RA + 2 + i) = index >= resultCount
                 ? LuaValue.Nil
                 : resultBuffer[i - 1];
         }
@@ -1334,7 +1334,7 @@ public static partial class LuaVirtualMachine
         var stack = context.Stack;
         var RA = instruction.A + context.FrameBase;
 
-        if (!stack.Get(RA).TryReadTable(out var table))
+        if (!stack.FastGet(RA).TryReadTable(out var table))
         {
             throw new LuaException("internal error");
         }
@@ -1409,10 +1409,10 @@ public static partial class LuaVirtualMachine
                 context.Thread.PopCallStackFrame();
                 var ra = context.Instruction.A + context.FrameBase;
                 var resultCount = awaiter.GetResult();
-                context.Stack.Get(ra) = resultCount == 0 ? default : context.ResultsBuffer[0];
+                context.Stack.FastGet(ra) = resultCount == 0 ? default : context.ResultsBuffer[0];
                 if (isSelf)
                 {
-                    context.Stack.Get(ra + 1) = table;
+                    context.Stack.FastGet(ra + 1) = table;
                     context.Stack.NotifyTop(ra + 2);
                 }
                 else
@@ -1431,10 +1431,10 @@ public static partial class LuaVirtualMachine
         if (table.Type == LuaValueType.Table)
         {
             var ra = context.Instruction.A + context.FrameBase;
-            context.Stack.Get(ra) = default;
+            context.Stack.FastGet(ra) = default;
             if (isSelf)
             {
-                context.Stack.Get(ra + 1) = table;
+                context.Stack.FastGet(ra + 1) = table;
                 context.Stack.NotifyTop(ra + 2);
             }
             else
@@ -1531,7 +1531,7 @@ public static partial class LuaVirtualMachine
                 var resultCount = context.Awaiter.GetResult();
                 context.Thread.PopCallStackFrame();
                 var RA = context.Instruction.A + context.FrameBase;
-                stack.Get(RA) = resultCount == 0 ? LuaValue.Nil : context.ResultsBuffer[0];
+                stack.FastGet(RA) = resultCount == 0 ? LuaValue.Nil : context.ResultsBuffer[0];
                 context.ClearResultsBuffer(resultCount);
                 return true;
             }
@@ -1577,7 +1577,7 @@ public static partial class LuaVirtualMachine
                 context.Thread.PopCallStackFrame();
                 var RA = context.Instruction.A + context.FrameBase;
                 var resultCount = context.Awaiter.GetResult();
-                stack.Get(RA) = resultCount == 0 ? LuaValue.Nil : context.ResultsBuffer[0];
+                stack.FastGet(RA) = resultCount == 0 ? LuaValue.Nil : context.ResultsBuffer[0];
                 context.ClearResultsBuffer(resultCount);
                 return true;
             }
@@ -1588,7 +1588,7 @@ public static partial class LuaVirtualMachine
         if (isLen && vb.TryReadTable(out var table))
         {
             var RA = context.Instruction.A + context.FrameBase;
-            stack.Get(RA) = table.ArrayLength;
+            stack.FastGet(RA) = table.ArrayLength;
             return true;
         }