| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185 |
- using System.Runtime.CompilerServices;
- namespace Lua.Runtime;
- public static partial class LuaVirtualMachine
- {
- [MethodImpl(MethodImplOptions.NoInlining)]
- static bool ExecutePerInstructionHook(VirtualMachineExecutionContext context)
- {
- var r = Impl(context);
- if (r.IsCompleted)
- {
- if (r.Result == 0)
- {
- context.Thread.PopCallStackFrameWithStackPop();
- }
- return false;
- }
- context.Task = r;
- context.Pc--;
- return true;
- static async ValueTask<int> Impl(VirtualMachineExecutionContext context)
- {
- bool countHookIsDone = false;
- var pc = context.Pc;
- var prototype = context.Prototype;
- if (context.Thread.IsCountHookEnabled && --context.Thread.HookCount == 0)
- {
- context.Thread.HookCount = context.Thread.BaseHookCount;
- var hook = context.Thread.Hook!;
- var stack = context.Thread.Stack;
- stack.Push("count");
- stack.Push(LuaValue.Nil);
- var funcContext = new LuaFunctionExecutionContext { Thread = context.Thread, ArgumentCount = 2, ReturnFrameBase = context.Thread.Stack.Count - 2, };
- var frame = new CallStackFrame
- {
- Base = funcContext.FrameBase,
- ReturnBase = funcContext.ReturnFrameBase,
- VariableArgumentCount = hook.GetVariableArgumentCount(funcContext.ArgumentCount),
- Function = hook,
- CallerInstructionIndex = context.Pc,
- };
- frame.Flags |= CallStackFrameFlags.InHook;
- context.Thread.IsInHook = true;
- context.Thread.PushCallStackFrame(frame);
- await hook.Func(funcContext, context.CancellationToken);
- context.Thread.IsInHook = false;
- countHookIsDone = true;
- }
- if (context.Thread.IsLineHookEnabled)
- {
- var sourcePositions = prototype.LineInfo;
- var line = sourcePositions[pc];
- if (countHookIsDone || pc == 0 || context.Thread.LastPc < 0 || pc <= context.Thread.LastPc || sourcePositions[context.Thread.LastPc] != line)
- {
- if (countHookIsDone)
- {
- context.Thread.PopCallStackFrameWithStackPop();
- }
- var hook = context.Thread.Hook!;
- var stack = context.Thread.Stack;
- stack.Push("line");
- stack.Push(line);
- var funcContext = new LuaFunctionExecutionContext { Thread = context.Thread, ArgumentCount = 2, ReturnFrameBase = context.Thread.Stack.Count - 2, };
- var frame = new CallStackFrame
- {
- Base = funcContext.FrameBase,
- ReturnBase = funcContext.ReturnFrameBase,
- VariableArgumentCount = hook.GetVariableArgumentCount(funcContext.ArgumentCount),
- Function = hook,
- CallerInstructionIndex = pc,
- };
- frame.Flags |= CallStackFrameFlags.InHook;
- context.Thread.IsInHook = true;
- context.Thread.PushCallStackFrame(frame);
- await hook.Func(funcContext, context.CancellationToken);
- context.Thread.IsInHook = false;
- context.Thread.LastPc = pc;
- return 0;
- }
- context.Thread.LastPc = pc;
- }
- if (countHookIsDone)
- {
- return 0;
- }
- return -1;
- }
- }
- [MethodImpl(MethodImplOptions.NoInlining)]
- static ValueTask<int> ExecuteCallHook(VirtualMachineExecutionContext context, in CallStackFrame frame, int arguments, bool isTailCall = false)
- {
- return ExecuteCallHook(new()
- {
- Thread = context.Thread, ArgumentCount = arguments, ReturnFrameBase = frame.ReturnBase, CallerInstructionIndex = frame.CallerInstructionIndex,
- }, context.CancellationToken, isTailCall);
- }
- internal static async ValueTask<int> ExecuteCallHook(LuaFunctionExecutionContext context, CancellationToken cancellationToken, bool isTailCall = false)
- {
- var argCount = context.ArgumentCount;
- var hook = context.Thread.Hook!;
- var stack = context.Thread.Stack;
- if (context.Thread.IsCallHookEnabled)
- {
- stack.Push((isTailCall ? "tail call" : "call"));
- stack.Push(LuaValue.Nil);
- var funcContext = new LuaFunctionExecutionContext { Thread = context.Thread, ArgumentCount = 2, ReturnFrameBase = context.Thread.Stack.Count - 2, };
- CallStackFrame frame = new()
- {
- Base = funcContext.FrameBase,
- ReturnBase = funcContext.ReturnFrameBase,
- VariableArgumentCount = hook.GetVariableArgumentCount(2),
- Function = hook,
- CallerInstructionIndex = 0,
- Flags = CallStackFrameFlags.InHook
- };
- context.Thread.PushCallStackFrame(frame);
- try
- {
- context.Thread.IsInHook = true;
- await hook.Func(funcContext, cancellationToken);
- }
- finally
- {
- context.Thread.IsInHook = false;
- context.Thread.PopCallStackFrameWithStackPop();
- }
- }
- {
- ref readonly var frame = ref context.Thread.GetCurrentFrame();
- var task = frame.Function.Func(new() { Thread = context.Thread, ArgumentCount = argCount, ReturnFrameBase = frame.ReturnBase, }, cancellationToken);
- var r = await task;
- if (isTailCall || !context.Thread.IsReturnHookEnabled)
- {
- return r;
- }
- stack.Push("return");
- stack.Push(LuaValue.Nil);
- var funcContext = new LuaFunctionExecutionContext { Thread = context.Thread, ArgumentCount = 2, ReturnFrameBase = context.Thread.Stack.Count - 2, };
- context.Thread.PushCallStackFrame(new()
- {
- Base = funcContext.FrameBase,
- ReturnBase = funcContext.ReturnFrameBase,
- VariableArgumentCount = hook.GetVariableArgumentCount(2),
- Function = hook,
- CallerInstructionIndex = 0,
- Flags = CallStackFrameFlags.InHook
- });
- try
- {
- context.Thread.IsInHook = true;
- await hook.Func(funcContext, cancellationToken);
- }
- finally
- {
- context.Thread.IsInHook = false;
- }
- context.Thread.PopCallStackFrameWithStackPop();
- return r;
- }
- }
- }
|