|
|
@@ -22,11 +22,11 @@ public static partial class LuaVirtualMachine
|
|
|
{
|
|
|
public readonly LuaState State = state;
|
|
|
public readonly LuaStack Stack = stack;
|
|
|
- public Closure Closure = (Closure)frame.Function;
|
|
|
+ public LuaClosure LuaClosure = (LuaClosure)frame.Function;
|
|
|
public readonly LuaValue[] ResultsBuffer = resultsBuffer;
|
|
|
public readonly Memory<LuaValue> Buffer = buffer;
|
|
|
public readonly LuaThread Thread = thread;
|
|
|
- public Chunk Chunk => Closure.Proto;
|
|
|
+ public Chunk Chunk => LuaClosure.Proto;
|
|
|
public int FrameBase = frame.Base;
|
|
|
public int VariableArgumentCount = frame.VariableArgumentCount;
|
|
|
public readonly CancellationToken CancellationToken = cancellationToken;
|
|
|
@@ -35,10 +35,13 @@ public static partial class LuaVirtualMachine
|
|
|
public int ResultCount;
|
|
|
public int TaskResult;
|
|
|
public ValueTask<int> Task;
|
|
|
+ public int LastHookPc = -1;
|
|
|
public bool IsTopLevel => BaseCallStackCount == Thread.CallStack.Count;
|
|
|
|
|
|
readonly int BaseCallStackCount = thread.CallStack.Count;
|
|
|
|
|
|
+ public PostOperationType PostOperation;
|
|
|
+
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
|
public bool Pop(Instruction instruction, int frameBase)
|
|
|
{
|
|
|
@@ -58,8 +61,9 @@ public static partial class LuaVirtualMachine
|
|
|
if (frames.Length == BaseCallStackCount) return false;
|
|
|
ref readonly var frame = ref frames[^1];
|
|
|
Pc = frame.CallerInstructionIndex;
|
|
|
+ Thread.LastPc = Pc;
|
|
|
ref readonly var lastFrame = ref frames[^2];
|
|
|
- Closure = Unsafe.As<Closure>(lastFrame.Function);
|
|
|
+ LuaClosure = Unsafe.As<LuaClosure>(lastFrame.Function);
|
|
|
var callInstruction = Chunk.Instructions[Pc];
|
|
|
FrameBase = lastFrame.Base;
|
|
|
VariableArgumentCount = lastFrame.VariableArgumentCount;
|
|
|
@@ -92,15 +96,15 @@ public static partial class LuaVirtualMachine
|
|
|
switch (opCode)
|
|
|
{
|
|
|
case OpCode.Call:
|
|
|
+ {
|
|
|
+ var c = callInstruction.C;
|
|
|
+ if (c != 0)
|
|
|
{
|
|
|
- var c = callInstruction.C;
|
|
|
- if (c != 0)
|
|
|
- {
|
|
|
- targetCount = c - 1;
|
|
|
- }
|
|
|
-
|
|
|
- break;
|
|
|
+ targetCount = c - 1;
|
|
|
}
|
|
|
+
|
|
|
+ break;
|
|
|
+ }
|
|
|
case OpCode.TForCall:
|
|
|
target += 3;
|
|
|
targetCount = callInstruction.C;
|
|
|
@@ -142,7 +146,7 @@ public static partial class LuaVirtualMachine
|
|
|
public void Push(in CallStackFrame frame)
|
|
|
{
|
|
|
Pc = -1;
|
|
|
- Closure = (frame.Function as Closure)!;
|
|
|
+ LuaClosure = (frame.Function as LuaClosure)!;
|
|
|
FrameBase = frame.Base;
|
|
|
VariableArgumentCount = frame.VariableArgumentCount;
|
|
|
}
|
|
|
@@ -186,49 +190,60 @@ public static partial class LuaVirtualMachine
|
|
|
ResultsBuffer.AsSpan(0, count).Clear();
|
|
|
}
|
|
|
|
|
|
+ public int? ExecutePostOperation(PostOperationType postOperation)
|
|
|
+ {
|
|
|
+ switch (postOperation)
|
|
|
+ {
|
|
|
+ case PostOperationType.Nop: break;
|
|
|
+ case PostOperationType.SetResult:
|
|
|
+ var RA = Instruction.A + FrameBase;
|
|
|
+ Stack.Get(RA) = TaskResult == 0 ? LuaValue.Nil : ResultsBuffer[0];
|
|
|
+ Stack.NotifyTop(RA + 1);
|
|
|
+ ClearResultsBuffer();
|
|
|
+ break;
|
|
|
+ case PostOperationType.TForCall:
|
|
|
+ TForCallPostOperation(ref this);
|
|
|
+ break;
|
|
|
+ case PostOperationType.Call:
|
|
|
+ CallPostOperation(ref this);
|
|
|
+ break;
|
|
|
+ case PostOperationType.TailCall:
|
|
|
+ var resultsSpan = ResultsBuffer.AsSpan(0, TaskResult);
|
|
|
+ if (!PopFromBuffer(resultsSpan))
|
|
|
+ {
|
|
|
+ ResultCount = TaskResult;
|
|
|
+ resultsSpan.CopyTo(Buffer.Span);
|
|
|
+ resultsSpan.Clear();
|
|
|
+ LuaValueArrayPool.Return1024(ResultsBuffer);
|
|
|
+ return TaskResult;
|
|
|
+ }
|
|
|
+
|
|
|
+ resultsSpan.Clear();
|
|
|
+ break;
|
|
|
+ case PostOperationType.Self:
|
|
|
+ SelfPostOperation(ref this);
|
|
|
+ break;
|
|
|
+ case PostOperationType.Compare:
|
|
|
+ ComparePostOperation(ref this);
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
public async ValueTask<int> ExecuteClosureAsyncImpl()
|
|
|
{
|
|
|
- while (MoveNext(ref this, out var postOperation))
|
|
|
+ while (MoveNext(ref this))
|
|
|
{
|
|
|
TaskResult = await Task;
|
|
|
Task = default;
|
|
|
-
|
|
|
- Thread.PopCallStackFrame();
|
|
|
- switch (postOperation)
|
|
|
+ if (PostOperation != PostOperationType.TailCall)
|
|
|
{
|
|
|
- case PostOperationType.Nop: break;
|
|
|
- case PostOperationType.SetResult:
|
|
|
- var RA = Instruction.A + FrameBase;
|
|
|
- Stack.Get(RA) = TaskResult == 0 ? LuaValue.Nil : ResultsBuffer[0];
|
|
|
- Stack.NotifyTop(RA + 1);
|
|
|
- ClearResultsBuffer();
|
|
|
- break;
|
|
|
- case PostOperationType.TForCall:
|
|
|
- TForCallPostOperation(ref this);
|
|
|
- break;
|
|
|
- case PostOperationType.Call:
|
|
|
- CallPostOperation(ref this);
|
|
|
- break;
|
|
|
- case PostOperationType.TailCall:
|
|
|
- var resultsSpan = ResultsBuffer.AsSpan(0, TaskResult);
|
|
|
- if (!PopFromBuffer(resultsSpan))
|
|
|
- {
|
|
|
- ResultCount = TaskResult;
|
|
|
- resultsSpan.CopyTo(Buffer.Span);
|
|
|
- resultsSpan.Clear();
|
|
|
- LuaValueArrayPool.Return1024(ResultsBuffer);
|
|
|
- return TaskResult;
|
|
|
- }
|
|
|
-
|
|
|
- resultsSpan.Clear();
|
|
|
- break;
|
|
|
- case PostOperationType.Self:
|
|
|
- SelfPostOperation(ref this);
|
|
|
- break;
|
|
|
- case PostOperationType.Compare:
|
|
|
- ComparePostOperation(ref this);
|
|
|
- break;
|
|
|
+ Thread.PopCallStackFrame();
|
|
|
}
|
|
|
+
|
|
|
+ var r = ExecutePostOperation(PostOperation);
|
|
|
+ if (r.HasValue) return r.Value;
|
|
|
}
|
|
|
|
|
|
return ResultCount;
|
|
|
@@ -250,7 +265,7 @@ public static partial class LuaVirtualMachine
|
|
|
internal static ValueTask<int> ExecuteClosureAsync(LuaState luaState, Memory<LuaValue> buffer, CancellationToken cancellationToken)
|
|
|
{
|
|
|
var thread = luaState.CurrentThread;
|
|
|
- ref readonly var frame = ref thread.GetCallStackFrames()[^1];
|
|
|
+ ref readonly var frame = ref thread.GetCurrentFrame();
|
|
|
var resultBuffer = LuaValueArrayPool.Rent1024();
|
|
|
|
|
|
var context = new VirtualMachineExecutionContext(luaState, thread.Stack, resultBuffer, buffer, thread, in frame,
|
|
|
@@ -259,24 +274,46 @@ public static partial class LuaVirtualMachine
|
|
|
return context.ExecuteClosureAsyncImpl();
|
|
|
}
|
|
|
|
|
|
- static bool MoveNext(ref VirtualMachineExecutionContext context, out PostOperationType postOperation)
|
|
|
+ static bool MoveNext(ref VirtualMachineExecutionContext context)
|
|
|
{
|
|
|
- postOperation = PostOperationType.None;
|
|
|
-
|
|
|
try
|
|
|
{
|
|
|
- // 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:
|
|
|
ref var instructionsHead = ref context.Chunk.Instructions[0];
|
|
|
var frameBase = context.FrameBase;
|
|
|
var stack = context.Stack;
|
|
|
stack.EnsureCapacity(frameBase + context.Chunk.MaxStackPosition);
|
|
|
ref var constHead = ref MemoryMarshalEx.UnsafeElementAt(context.Chunk.Constants, 0);
|
|
|
+ ref var lineAndCountHookMask = ref context.Thread.LineAndCountHookMask;
|
|
|
+ goto Loop;
|
|
|
+ LineHook:
|
|
|
+
|
|
|
+ {
|
|
|
+ context.LastHookPc = context.Pc;
|
|
|
+ if (!context.Thread.IsInHook && ExecutePerInstructionHook(ref context))
|
|
|
+ {
|
|
|
+ {
|
|
|
+ context.PostOperation = PostOperationType.Nop;
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ }
|
|
|
|
|
|
+ --context.Pc;
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ Loop:
|
|
|
while (true)
|
|
|
{
|
|
|
var instructionRef = Unsafe.Add(ref instructionsHead, ++context.Pc);
|
|
|
context.Instruction = instructionRef;
|
|
|
+ if (lineAndCountHookMask.Value != 0 && (context.Pc != context.LastHookPc))
|
|
|
+ {
|
|
|
+ goto LineHook;
|
|
|
+ }
|
|
|
+
|
|
|
+ context.LastHookPc = -1;
|
|
|
switch (instructionRef.OpCode)
|
|
|
{
|
|
|
case OpCode.Move:
|
|
|
@@ -304,14 +341,14 @@ public static partial class LuaVirtualMachine
|
|
|
continue;
|
|
|
case OpCode.GetUpVal:
|
|
|
instruction = instructionRef;
|
|
|
- stack.GetWithNotifyTop(instruction.A + frameBase) = context.Closure.GetUpValue(instruction.B);
|
|
|
+ stack.GetWithNotifyTop(instruction.A + frameBase) = context.LuaClosure.GetUpValue(instruction.B);
|
|
|
continue;
|
|
|
case OpCode.GetTabUp:
|
|
|
case OpCode.GetTable:
|
|
|
instruction = instructionRef;
|
|
|
stackHead = ref stack.FastGet(frameBase);
|
|
|
ref readonly var vc = ref RKC(ref stackHead, ref constHead, instruction);
|
|
|
- ref readonly var vb = ref (instruction.OpCode == OpCode.GetTable ? ref Unsafe.Add(ref stackHead, instruction.UIntB) : ref context.Closure.GetUpValueRef(instruction.B));
|
|
|
+ ref readonly var vb = ref (instruction.OpCode == OpCode.GetTable ? ref Unsafe.Add(ref stackHead, instruction.UIntB) : ref context.LuaClosure.GetUpValueRef(instruction.B));
|
|
|
var doRestart = false;
|
|
|
if (vb.TryReadTable(out var luaTable) && luaTable.TryGetValue(vc, out var resultValue) || GetTableValueSlowPath(vb, vc, ref context, out resultValue, out doRestart))
|
|
|
{
|
|
|
@@ -320,7 +357,6 @@ public static partial class LuaVirtualMachine
|
|
|
continue;
|
|
|
}
|
|
|
|
|
|
- postOperation = PostOperationType.SetResult;
|
|
|
return true;
|
|
|
case OpCode.SetTabUp:
|
|
|
instruction = instructionRef;
|
|
|
@@ -335,7 +371,7 @@ public static partial class LuaVirtualMachine
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- var table = context.Closure.GetUpValue(instruction.A);
|
|
|
+ var table = context.LuaClosure.GetUpValue(instruction.A);
|
|
|
|
|
|
if (table.TryReadTable(out luaTable))
|
|
|
{
|
|
|
@@ -354,12 +390,11 @@ public static partial class LuaVirtualMachine
|
|
|
continue;
|
|
|
}
|
|
|
|
|
|
- postOperation = PostOperationType.Nop;
|
|
|
return true;
|
|
|
|
|
|
case OpCode.SetUpVal:
|
|
|
instruction = instructionRef;
|
|
|
- context.Closure.SetUpValue(instruction.B, stack.FastGet(instruction.A + frameBase));
|
|
|
+ context.LuaClosure.SetUpValue(instruction.B, stack.FastGet(instruction.A + frameBase));
|
|
|
continue;
|
|
|
case OpCode.SetTable:
|
|
|
instruction = instructionRef;
|
|
|
@@ -394,7 +429,6 @@ public static partial class LuaVirtualMachine
|
|
|
continue;
|
|
|
}
|
|
|
|
|
|
- postOperation = PostOperationType.Nop;
|
|
|
return true;
|
|
|
case OpCode.NewTable:
|
|
|
instruction = instructionRef;
|
|
|
@@ -417,7 +451,6 @@ public static partial class LuaVirtualMachine
|
|
|
continue;
|
|
|
}
|
|
|
|
|
|
- postOperation = PostOperationType.Self;
|
|
|
return true;
|
|
|
case OpCode.Add:
|
|
|
instruction = instructionRef;
|
|
|
@@ -445,7 +478,6 @@ public static partial class LuaVirtualMachine
|
|
|
continue;
|
|
|
}
|
|
|
|
|
|
- postOperation = PostOperationType.SetResult;
|
|
|
return true;
|
|
|
case OpCode.Sub:
|
|
|
instruction = instructionRef;
|
|
|
@@ -476,7 +508,6 @@ public static partial class LuaVirtualMachine
|
|
|
continue;
|
|
|
}
|
|
|
|
|
|
- postOperation = PostOperationType.SetResult;
|
|
|
return true;
|
|
|
|
|
|
case OpCode.Mul:
|
|
|
@@ -508,7 +539,6 @@ public static partial class LuaVirtualMachine
|
|
|
continue;
|
|
|
}
|
|
|
|
|
|
- postOperation = PostOperationType.SetResult;
|
|
|
return true;
|
|
|
|
|
|
case OpCode.Div:
|
|
|
@@ -540,7 +570,6 @@ public static partial class LuaVirtualMachine
|
|
|
continue;
|
|
|
}
|
|
|
|
|
|
- postOperation = PostOperationType.SetResult;
|
|
|
return true;
|
|
|
case OpCode.Mod:
|
|
|
instruction = instructionRef;
|
|
|
@@ -566,7 +595,6 @@ public static partial class LuaVirtualMachine
|
|
|
continue;
|
|
|
}
|
|
|
|
|
|
- postOperation = PostOperationType.SetResult;
|
|
|
return true;
|
|
|
case OpCode.Pow:
|
|
|
instruction = instructionRef;
|
|
|
@@ -588,7 +616,6 @@ public static partial class LuaVirtualMachine
|
|
|
continue;
|
|
|
}
|
|
|
|
|
|
- postOperation = PostOperationType.SetResult;
|
|
|
return true;
|
|
|
case OpCode.Unm:
|
|
|
instruction = instructionRef;
|
|
|
@@ -610,7 +637,6 @@ public static partial class LuaVirtualMachine
|
|
|
continue;
|
|
|
}
|
|
|
|
|
|
- postOperation = PostOperationType.SetResult;
|
|
|
return true;
|
|
|
case OpCode.Not:
|
|
|
instruction = instructionRef;
|
|
|
@@ -642,7 +668,6 @@ public static partial class LuaVirtualMachine
|
|
|
continue;
|
|
|
}
|
|
|
|
|
|
- postOperation = PostOperationType.SetResult;
|
|
|
return true;
|
|
|
case OpCode.Concat:
|
|
|
if (Concat(ref context, out doRestart))
|
|
|
@@ -651,7 +676,6 @@ public static partial class LuaVirtualMachine
|
|
|
continue;
|
|
|
}
|
|
|
|
|
|
- postOperation = PostOperationType.SetResult;
|
|
|
return true;
|
|
|
case OpCode.Jmp:
|
|
|
instruction = instructionRef;
|
|
|
@@ -685,7 +709,6 @@ public static partial class LuaVirtualMachine
|
|
|
continue;
|
|
|
}
|
|
|
|
|
|
- postOperation = PostOperationType.Compare;
|
|
|
return true;
|
|
|
case OpCode.Lt:
|
|
|
instruction = instructionRef;
|
|
|
@@ -723,7 +746,6 @@ public static partial class LuaVirtualMachine
|
|
|
continue;
|
|
|
}
|
|
|
|
|
|
- postOperation = PostOperationType.Compare;
|
|
|
return true;
|
|
|
case OpCode.Le:
|
|
|
instruction = instructionRef;
|
|
|
@@ -760,7 +782,6 @@ public static partial class LuaVirtualMachine
|
|
|
continue;
|
|
|
}
|
|
|
|
|
|
- postOperation = PostOperationType.Compare;
|
|
|
return true;
|
|
|
case OpCode.Test:
|
|
|
instruction = instructionRef;
|
|
|
@@ -791,7 +812,6 @@ public static partial class LuaVirtualMachine
|
|
|
continue;
|
|
|
}
|
|
|
|
|
|
- postOperation = PostOperationType.Call;
|
|
|
return true;
|
|
|
case OpCode.TailCall:
|
|
|
if (TailCall(ref context, out doRestart))
|
|
|
@@ -801,7 +821,6 @@ public static partial class LuaVirtualMachine
|
|
|
continue;
|
|
|
}
|
|
|
|
|
|
- postOperation = PostOperationType.TailCall;
|
|
|
return true;
|
|
|
case OpCode.Return:
|
|
|
instruction = instructionRef;
|
|
|
@@ -872,7 +891,7 @@ public static partial class LuaVirtualMachine
|
|
|
continue;
|
|
|
}
|
|
|
|
|
|
- postOperation = PostOperationType.TForCall;
|
|
|
+
|
|
|
return true;
|
|
|
case OpCode.TForLoop:
|
|
|
instruction = instructionRef;
|
|
|
@@ -895,7 +914,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.Get(ra1 - 1) = new LuaClosure(context.State, context.Chunk.Functions[instruction.SBx]);
|
|
|
stack.NotifyTop(ra1);
|
|
|
continue;
|
|
|
case OpCode.VarArg:
|
|
|
@@ -926,22 +945,23 @@ public static partial class LuaVirtualMachine
|
|
|
}
|
|
|
|
|
|
End:
|
|
|
- postOperation = PostOperationType.None;
|
|
|
+ context.PostOperation = PostOperationType.None;
|
|
|
LuaValueArrayPool.Return1024(context.ResultsBuffer);
|
|
|
return false;
|
|
|
}
|
|
|
catch (Exception e)
|
|
|
{
|
|
|
- context.PopOnTopCallStackFrames();
|
|
|
context.State.CloseUpValues(context.Thread, context.FrameBase);
|
|
|
LuaValueArrayPool.Return1024(context.ResultsBuffer, true);
|
|
|
if (e is not LuaRuntimeException)
|
|
|
{
|
|
|
- var newException = new LuaRuntimeException(GetTracebacks(ref context), e);
|
|
|
+ var newException = new LuaRuntimeException(context.State.GetTraceback(), e);
|
|
|
+ context.PopOnTopCallStackFrames();
|
|
|
context = default;
|
|
|
throw newException;
|
|
|
}
|
|
|
|
|
|
+ context.PopOnTopCallStackFrames();
|
|
|
throw;
|
|
|
}
|
|
|
}
|
|
|
@@ -1014,11 +1034,15 @@ public static partial class LuaVirtualMachine
|
|
|
var instruction = context.Instruction;
|
|
|
var RA = instruction.A + context.FrameBase;
|
|
|
var va = context.Stack.Get(RA);
|
|
|
+ var newBase = RA + 1;
|
|
|
+ bool isMetamethod = false;
|
|
|
if (!va.TryReadFunction(out var func))
|
|
|
{
|
|
|
if (va.TryGetMetamethod(context.State, Metamethods.Call, out var metamethod) &&
|
|
|
metamethod.TryReadFunction(out func))
|
|
|
{
|
|
|
+ newBase -= 1;
|
|
|
+ isMetamethod = true;
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
@@ -1027,12 +1051,20 @@ public static partial class LuaVirtualMachine
|
|
|
}
|
|
|
|
|
|
var thread = context.Thread;
|
|
|
- var (newBase, argumentCount, variableArgumentCount) = PrepareForFunctionCall(thread, func, instruction, RA);
|
|
|
-
|
|
|
+ var (argumentCount, variableArgumentCount) = PrepareForFunctionCall(thread, func, instruction, newBase, isMetamethod);
|
|
|
+ newBase += variableArgumentCount;
|
|
|
var newFrame = func.CreateNewFrame(ref context, newBase, variableArgumentCount);
|
|
|
|
|
|
thread.PushCallStackFrame(newFrame);
|
|
|
- if (func is Closure)
|
|
|
+ if (thread.CallOrReturnHookMask.Value != 0 && !context.Thread.IsInHook)
|
|
|
+ {
|
|
|
+ context.PostOperation = PostOperationType.Call;
|
|
|
+ context.Task=ExecuteCallHook(ref context, newFrame,argumentCount);
|
|
|
+ doRestart = false;
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (func is LuaClosure)
|
|
|
{
|
|
|
context.Push(newFrame);
|
|
|
doRestart = true;
|
|
|
@@ -1048,6 +1080,7 @@ public static partial class LuaVirtualMachine
|
|
|
|
|
|
if (!task.IsCompleted)
|
|
|
{
|
|
|
+ context.PostOperation = PostOperationType.Call;
|
|
|
context.Task = task;
|
|
|
return false;
|
|
|
}
|
|
|
@@ -1131,6 +1164,8 @@ public static partial class LuaVirtualMachine
|
|
|
var instruction = context.Instruction;
|
|
|
var stack = context.Stack;
|
|
|
var RA = instruction.A + context.FrameBase;
|
|
|
+ var newBase = RA + 1;
|
|
|
+ bool isMetamethod = false;
|
|
|
var state = context.State;
|
|
|
var thread = context.Thread;
|
|
|
|
|
|
@@ -1139,20 +1174,39 @@ public static partial class LuaVirtualMachine
|
|
|
var va = stack.Get(RA);
|
|
|
if (!va.TryReadFunction(out var func))
|
|
|
{
|
|
|
- if (!va.TryGetMetamethod(state, Metamethods.Call, out var metamethod) &&
|
|
|
- !metamethod.TryReadFunction(out func))
|
|
|
+ if (va.TryGetMetamethod(state, Metamethods.Call, out var metamethod) &&
|
|
|
+ metamethod.TryReadFunction(out func))
|
|
|
+ {
|
|
|
+ isMetamethod = true;
|
|
|
+ newBase -= 1;
|
|
|
+ }
|
|
|
+ else
|
|
|
{
|
|
|
LuaRuntimeException.AttemptInvalidOperation(GetTracebacks(ref context), "call", metamethod);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- var (newBase, argumentCount, variableArgumentCount) = PrepareForFunctionTailCall(thread, func, instruction, RA);
|
|
|
+ var (argumentCount, variableArgumentCount) = PrepareForFunctionTailCall(thread, func, instruction, newBase, isMetamethod);
|
|
|
+ newBase = context.FrameBase + variableArgumentCount;
|
|
|
|
|
|
+ var lastPc = thread.CallStack.AsSpan()[^1].CallerInstructionIndex;
|
|
|
+ context.Thread.PopCallStackFrameUnsafe();
|
|
|
var newFrame = func.CreateNewFrame(ref context, newBase, variableArgumentCount);
|
|
|
+
|
|
|
+ newFrame.Flags |= CallStackFrameFlags.TailCall;
|
|
|
+ newFrame.CallerInstructionIndex = lastPc;
|
|
|
thread.PushCallStackFrame(newFrame);
|
|
|
|
|
|
+ if (thread.CallOrReturnHookMask.Value != 0 && !context.Thread.IsInHook)
|
|
|
+ {
|
|
|
+ context.PostOperation = PostOperationType.TailCall;
|
|
|
+ context.Task=ExecuteCallHook(ref context, newFrame,argumentCount,true);
|
|
|
+ doRestart = false;
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
context.Push(newFrame);
|
|
|
- if (func is Closure)
|
|
|
+ if (func is LuaClosure)
|
|
|
{
|
|
|
doRestart = true;
|
|
|
return true;
|
|
|
@@ -1163,12 +1217,11 @@ public static partial class LuaVirtualMachine
|
|
|
|
|
|
if (!task.IsCompleted)
|
|
|
{
|
|
|
+ context.PostOperation = PostOperationType.TailCall;
|
|
|
context.Task = task;
|
|
|
return false;
|
|
|
}
|
|
|
|
|
|
- context.Thread.PopCallStackFrame();
|
|
|
-
|
|
|
doRestart = true;
|
|
|
var awaiter = task.GetAwaiter();
|
|
|
var resultCount = awaiter.GetResult();
|
|
|
@@ -1190,20 +1243,48 @@ public static partial class LuaVirtualMachine
|
|
|
var instruction = context.Instruction;
|
|
|
var stack = context.Stack;
|
|
|
var RA = instruction.A + context.FrameBase;
|
|
|
-
|
|
|
+ bool isMetamethod = false;
|
|
|
var iteratorRaw = stack.Get(RA);
|
|
|
if (!iteratorRaw.TryReadFunction(out var iterator))
|
|
|
{
|
|
|
- LuaRuntimeException.AttemptInvalidOperation(GetTracebacks(ref context), "call", iteratorRaw);
|
|
|
+ if (iteratorRaw.TryGetMetamethod(context.State, Metamethods.Call, out var metamethod) &&
|
|
|
+ metamethod.TryReadFunction(out iterator))
|
|
|
+ {
|
|
|
+ isMetamethod = true;
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ LuaRuntimeException.AttemptInvalidOperation(GetTracebacks(ref context), "call", metamethod);
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
var newBase = RA + 3 + instruction.C;
|
|
|
- stack.Get(newBase) = stack.Get(RA + 1);
|
|
|
- stack.Get(newBase + 1) = stack.Get(RA + 2);
|
|
|
- stack.NotifyTop(newBase + 2);
|
|
|
- var newFrame = iterator.CreateNewFrame(ref context, newBase);
|
|
|
+
|
|
|
+ if (isMetamethod)
|
|
|
+ {
|
|
|
+ stack.Get(newBase) = iteratorRaw;
|
|
|
+ stack.Get(newBase + 1) = stack.Get(RA + 1);
|
|
|
+ stack.Get(newBase + 2) = stack.Get(RA + 2);
|
|
|
+ stack.NotifyTop(newBase + 3);
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ stack.Get(newBase) = stack.Get(RA + 1);
|
|
|
+ stack.Get(newBase + 1) = stack.Get(RA + 2);
|
|
|
+ stack.NotifyTop(newBase + 2);
|
|
|
+ }
|
|
|
+
|
|
|
+ var argumentCount = isMetamethod ? 3 : 2;
|
|
|
+ var variableArgumentCount = iterator.GetVariableArgumentCount(argumentCount);
|
|
|
+ if (variableArgumentCount != 0)
|
|
|
+ {
|
|
|
+ PrepareVariableArgument(stack, newBase, argumentCount, variableArgumentCount);
|
|
|
+ newBase += variableArgumentCount;
|
|
|
+ }
|
|
|
+
|
|
|
+ var newFrame = iterator.CreateNewFrame(ref context, newBase, variableArgumentCount);
|
|
|
context.Thread.PushCallStackFrame(newFrame);
|
|
|
- if (iterator is Closure)
|
|
|
+ if (iterator is LuaClosure)
|
|
|
{
|
|
|
context.Push(newFrame);
|
|
|
doRestart = true;
|
|
|
@@ -1214,6 +1295,7 @@ public static partial class LuaVirtualMachine
|
|
|
|
|
|
if (!task.IsCompleted)
|
|
|
{
|
|
|
+ context.PostOperation = PostOperationType.TForCall;
|
|
|
context.Task = task;
|
|
|
|
|
|
return false;
|
|
|
@@ -1264,6 +1346,7 @@ public static partial class LuaVirtualMachine
|
|
|
table.EnsureArrayCapacity((instruction.C - 1) * 50 + count);
|
|
|
stack.GetBuffer().Slice(RA + 1, count)
|
|
|
.CopyTo(table.GetArraySpan()[((instruction.C - 1) * 50)..]);
|
|
|
+ stack.PopUntil(RA + 1);
|
|
|
}
|
|
|
|
|
|
static void ComparePostOperation(ref VirtualMachineExecutionContext context)
|
|
|
@@ -1325,7 +1408,7 @@ public static partial class LuaVirtualMachine
|
|
|
}
|
|
|
|
|
|
table = metatableValue;
|
|
|
- Function:
|
|
|
+ Function:
|
|
|
if (table.TryReadFunction(out var function))
|
|
|
{
|
|
|
return CallGetTableFunc(targetTable, function, key, ref context, out value, out doRestart);
|
|
|
@@ -1345,8 +1428,16 @@ public static partial class LuaVirtualMachine
|
|
|
var newFrame = indexTable.CreateNewFrame(ref context, stack.Count - 2);
|
|
|
|
|
|
context.Thread.PushCallStackFrame(newFrame);
|
|
|
+ if (context.Thread.CallOrReturnHookMask.Value != 0 && !context.Thread.IsInHook)
|
|
|
+ {
|
|
|
+ context.PostOperation = context.Instruction.OpCode == OpCode.GetTable ? PostOperationType.SetResult : PostOperationType.Self;
|
|
|
+ context.Task=ExecuteCallHook(ref context, newFrame,2);
|
|
|
+ doRestart = false;
|
|
|
+ result = default;
|
|
|
+ return false;
|
|
|
+ }
|
|
|
|
|
|
- if (indexTable is Closure)
|
|
|
+ if (indexTable is LuaClosure)
|
|
|
{
|
|
|
context.Push(newFrame);
|
|
|
doRestart = true;
|
|
|
@@ -1358,6 +1449,7 @@ public static partial class LuaVirtualMachine
|
|
|
|
|
|
if (!task.IsCompleted)
|
|
|
{
|
|
|
+ context.PostOperation = context.Instruction.OpCode == OpCode.GetTable ? PostOperationType.SetResult : PostOperationType.Self;
|
|
|
context.Task = task;
|
|
|
result = default;
|
|
|
return false;
|
|
|
@@ -1414,9 +1506,10 @@ public static partial class LuaVirtualMachine
|
|
|
|
|
|
table = metatableValue;
|
|
|
|
|
|
- Function:
|
|
|
+ Function:
|
|
|
if (table.TryReadFunction(out var function))
|
|
|
{
|
|
|
+ context.PostOperation = PostOperationType.Nop;
|
|
|
return CallSetTableFunc(targetTable, function, key, value, ref context, out doRestart);
|
|
|
}
|
|
|
}
|
|
|
@@ -1436,8 +1529,15 @@ public static partial class LuaVirtualMachine
|
|
|
var newFrame = newIndexFunction.CreateNewFrame(ref context, stack.Count - 3);
|
|
|
|
|
|
context.Thread.PushCallStackFrame(newFrame);
|
|
|
+ if (context.Thread.CallOrReturnHookMask.Value != 0 && !context.Thread.IsInHook)
|
|
|
+ {
|
|
|
+ context.PostOperation = PostOperationType.Nop;
|
|
|
+ context.Task=ExecuteCallHook(ref context, newFrame,3);
|
|
|
+ doRestart = false;
|
|
|
+ return false;
|
|
|
+ }
|
|
|
|
|
|
- if (newIndexFunction is Closure)
|
|
|
+ if (newIndexFunction is LuaClosure)
|
|
|
{
|
|
|
context.Push(newFrame);
|
|
|
doRestart = true;
|
|
|
@@ -1447,6 +1547,7 @@ public static partial class LuaVirtualMachine
|
|
|
var task = newIndexFunction.Invoke(ref context, newFrame, 3);
|
|
|
if (!task.IsCompleted)
|
|
|
{
|
|
|
+ context.PostOperation = PostOperationType.Nop;
|
|
|
context.Task = task;
|
|
|
return false;
|
|
|
}
|
|
|
@@ -1482,8 +1583,15 @@ public static partial class LuaVirtualMachine
|
|
|
var newFrame = func.CreateNewFrame(ref context, stack.Count - 2);
|
|
|
|
|
|
context.Thread.PushCallStackFrame(newFrame);
|
|
|
+ if (context.Thread.CallOrReturnHookMask.Value != 0 && !context.Thread.IsInHook)
|
|
|
+ {
|
|
|
+ context.PostOperation = PostOperationType.SetResult;
|
|
|
+ context.Task=ExecuteCallHook(ref context, newFrame,2);
|
|
|
+ doRestart = false;
|
|
|
+ return false;
|
|
|
+ }
|
|
|
|
|
|
- if (func is Closure)
|
|
|
+ if (func is LuaClosure)
|
|
|
{
|
|
|
context.Push(newFrame);
|
|
|
doRestart = true;
|
|
|
@@ -1495,6 +1603,7 @@ public static partial class LuaVirtualMachine
|
|
|
|
|
|
if (!task.IsCompleted)
|
|
|
{
|
|
|
+ context.PostOperation = PostOperationType.SetResult;
|
|
|
context.Task = task;
|
|
|
return false;
|
|
|
}
|
|
|
@@ -1528,8 +1637,15 @@ public static partial class LuaVirtualMachine
|
|
|
var newFrame = func.CreateNewFrame(ref context, stack.Count - 1);
|
|
|
|
|
|
context.Thread.PushCallStackFrame(newFrame);
|
|
|
+ if (context.Thread.CallOrReturnHookMask.Value != 0 && !context.Thread.IsInHook)
|
|
|
+ {
|
|
|
+ context.PostOperation = PostOperationType.SetResult;
|
|
|
+ context.Task=ExecuteCallHook(ref context, newFrame,1);
|
|
|
+ doRestart = false;
|
|
|
+ return false;
|
|
|
+ }
|
|
|
|
|
|
- if (func is Closure)
|
|
|
+ if (func is LuaClosure)
|
|
|
{
|
|
|
context.Push(newFrame);
|
|
|
doRestart = true;
|
|
|
@@ -1541,6 +1657,7 @@ public static partial class LuaVirtualMachine
|
|
|
|
|
|
if (!task.IsCompleted)
|
|
|
{
|
|
|
+ context.PostOperation = PostOperationType.SetResult;
|
|
|
context.Task = task;
|
|
|
return false;
|
|
|
}
|
|
|
@@ -1585,8 +1702,14 @@ public static partial class LuaVirtualMachine
|
|
|
var newFrame = func.CreateNewFrame(ref context, stack.Count - 2);
|
|
|
if (reverseLe) newFrame.Flags |= CallStackFrameFlags.ReversedLe;
|
|
|
context.Thread.PushCallStackFrame(newFrame);
|
|
|
-
|
|
|
- if (func is Closure)
|
|
|
+ if (context.Thread.CallOrReturnHookMask.Value != 0 && !context.Thread.IsInHook)
|
|
|
+ {
|
|
|
+ context.PostOperation = PostOperationType.Compare;
|
|
|
+ context.Task=ExecuteCallHook(ref context, newFrame,2);
|
|
|
+ doRestart = false;
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ if (func is LuaClosure)
|
|
|
{
|
|
|
context.Push(newFrame);
|
|
|
doRestart = true;
|
|
|
@@ -1597,6 +1720,7 @@ public static partial class LuaVirtualMachine
|
|
|
|
|
|
if (!task.IsCompleted)
|
|
|
{
|
|
|
+ context.PostOperation = PostOperationType.Compare;
|
|
|
context.Task = task;
|
|
|
return false;
|
|
|
}
|
|
|
@@ -1646,7 +1770,7 @@ public static partial class LuaVirtualMachine
|
|
|
// If there are variable arguments, the base of the stack is moved by that number and the values of the variable arguments are placed in front of it.
|
|
|
// see: https://wubingzheng.github.io/build-lua-in-rust/en/ch08-02.arguments.html
|
|
|
[MethodImpl(MethodImplOptions.NoInlining)]
|
|
|
- static (int FrameBase, int ArgumentCount, int VariableArgumentCount) PrepareVariableArgument(LuaStack stack, int newBase, int argumentCount,
|
|
|
+ static ( int ArgumentCount, int VariableArgumentCount) PrepareVariableArgument(LuaStack stack, int newBase, int argumentCount,
|
|
|
int variableArgumentCount)
|
|
|
{
|
|
|
var temp = newBase;
|
|
|
@@ -1658,51 +1782,59 @@ public static partial class LuaVirtualMachine
|
|
|
var stackBuffer = stack.GetBuffer()[temp..];
|
|
|
stackBuffer[..argumentCount].CopyTo(stackBuffer[variableArgumentCount..]);
|
|
|
stackBuffer.Slice(argumentCount, variableArgumentCount).CopyTo(stackBuffer);
|
|
|
- return (newBase, argumentCount, variableArgumentCount);
|
|
|
+ return (argumentCount, variableArgumentCount);
|
|
|
}
|
|
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
|
- static (int FrameBase, int ArgumentCount, int VariableArgumentCount) PrepareForFunctionCall(LuaThread thread, LuaFunction function,
|
|
|
- Instruction instruction, int RA)
|
|
|
+ static (int ArgumentCount, int VariableArgumentCount) PrepareForFunctionCall(LuaThread thread, LuaFunction function,
|
|
|
+ Instruction instruction, int newBase, bool isMetaMethod)
|
|
|
{
|
|
|
var argumentCount = instruction.B - 1;
|
|
|
if (argumentCount == -1)
|
|
|
{
|
|
|
- argumentCount = (ushort)(thread.Stack.Count - (RA + 1));
|
|
|
+ argumentCount = (ushort)(thread.Stack.Count - newBase);
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
- thread.Stack.NotifyTop(RA + 1 + argumentCount);
|
|
|
+ if (isMetaMethod)
|
|
|
+ {
|
|
|
+ argumentCount += 1;
|
|
|
+ }
|
|
|
+
|
|
|
+ thread.Stack.NotifyTop(newBase + argumentCount);
|
|
|
}
|
|
|
|
|
|
- var newBase = RA + 1;
|
|
|
var variableArgumentCount = function.GetVariableArgumentCount(argumentCount);
|
|
|
|
|
|
if (variableArgumentCount <= 0)
|
|
|
{
|
|
|
- return (newBase, argumentCount, 0);
|
|
|
+ return (argumentCount, 0);
|
|
|
}
|
|
|
|
|
|
return PrepareVariableArgument(thread.Stack, newBase, argumentCount, variableArgumentCount);
|
|
|
}
|
|
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
|
- static (int FrameBase, int ArgumentCount, int VariableArgumentCount) PrepareForFunctionTailCall(LuaThread thread, LuaFunction function,
|
|
|
- Instruction instruction, int RA)
|
|
|
+ static (int ArgumentCount, int VariableArgumentCount) PrepareForFunctionTailCall(LuaThread thread, LuaFunction function,
|
|
|
+ Instruction instruction, int newBase, bool isMetaMethod)
|
|
|
{
|
|
|
var stack = thread.Stack;
|
|
|
|
|
|
var argumentCount = instruction.B - 1;
|
|
|
if (instruction.B == 0)
|
|
|
{
|
|
|
- argumentCount = (ushort)(stack.Count - (RA + 1));
|
|
|
+ argumentCount = (ushort)(stack.Count - newBase);
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
- thread.Stack.NotifyTop(RA + 1 + argumentCount);
|
|
|
+ if (isMetaMethod)
|
|
|
+ {
|
|
|
+ argumentCount += 1;
|
|
|
+ }
|
|
|
+
|
|
|
+ thread.Stack.NotifyTop(newBase + argumentCount);
|
|
|
}
|
|
|
|
|
|
- var newBase = RA + 1;
|
|
|
|
|
|
// In the case of tailcall, the local variables of the caller are immediately discarded, so there is no need to retain them.
|
|
|
// Therefore, a call can be made without allocating new registers.
|
|
|
@@ -1718,7 +1850,7 @@ public static partial class LuaVirtualMachine
|
|
|
|
|
|
if (variableArgumentCount <= 0)
|
|
|
{
|
|
|
- return (newBase, argumentCount, 0);
|
|
|
+ return (argumentCount, 0);
|
|
|
}
|
|
|
|
|
|
return PrepareVariableArgument(thread.Stack, newBase, argumentCount, variableArgumentCount);
|