| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248 |
- using ARMeilleure.Instructions;
- using ARMeilleure.IntermediateRepresentation;
- using ARMeilleure.State;
- using ARMeilleure.Translation.Cache;
- using System;
- using System.Reflection;
- using System.Runtime.InteropServices;
- using static ARMeilleure.IntermediateRepresentation.Operand.Factory;
- namespace ARMeilleure.Translation
- {
- /// <summary>
- /// Represents a stub manager.
- /// </summary>
- class TranslatorStubs : IDisposable
- {
- private static readonly Lazy<IntPtr> _slowDispatchStub = new(GenerateSlowDispatchStub, isThreadSafe: true);
- private bool _disposed;
- private readonly Translator _translator;
- private readonly Lazy<IntPtr> _dispatchStub;
- private readonly Lazy<DispatcherFunction> _dispatchLoop;
- /// <summary>
- /// Gets the dispatch stub.
- /// </summary>
- /// <exception cref="ObjectDisposedException"><see cref="TranslatorStubs"/> instance was disposed</exception>
- public IntPtr DispatchStub
- {
- get
- {
- if (_disposed)
- {
- throw new ObjectDisposedException(null);
- }
- return _dispatchStub.Value;
- }
- }
- /// <summary>
- /// Gets the slow dispatch stub.
- /// </summary>
- /// <exception cref="ObjectDisposedException"><see cref="TranslatorStubs"/> instance was disposed</exception>
- public IntPtr SlowDispatchStub
- {
- get
- {
- if (_disposed)
- {
- throw new ObjectDisposedException(null);
- }
- return _slowDispatchStub.Value;
- }
- }
- /// <summary>
- /// Gets the dispatch loop function.
- /// </summary>
- /// <exception cref="ObjectDisposedException"><see cref="TranslatorStubs"/> instance was disposed</exception>
- public DispatcherFunction DispatchLoop
- {
- get
- {
- if (_disposed)
- {
- throw new ObjectDisposedException(null);
- }
- return _dispatchLoop.Value;
- }
- }
- /// <summary>
- /// Initializes a new instance of the <see cref="TranslatorStubs"/> class with the specified
- /// <see cref="Translator"/> instance.
- /// </summary>
- /// <param name="translator"><see cref="Translator"/> instance to use</param>
- /// <exception cref="ArgumentNullException"><paramref name="translator"/> is null</exception>
- public TranslatorStubs(Translator translator)
- {
- _translator = translator ?? throw new ArgumentNullException(nameof(translator));
- _dispatchStub = new(GenerateDispatchStub, isThreadSafe: true);
- _dispatchLoop = new(GenerateDispatchLoop, isThreadSafe: true);
- }
- /// <summary>
- /// Releases all resources used by the <see cref="TranslatorStubs"/> instance.
- /// </summary>
- public void Dispose()
- {
- Dispose(true);
- GC.SuppressFinalize(this);
- }
- /// <summary>
- /// Releases all unmanaged and optionally managed resources used by the <see cref="TranslatorStubs"/> instance.
- /// </summary>
- /// <param name="disposing"><see langword="true"/> to dispose managed resources also; otherwise just unmanaged resouces</param>
- protected virtual void Dispose(bool disposing)
- {
- if (!_disposed)
- {
- if (_dispatchStub.IsValueCreated)
- {
- JitCache.Unmap(_dispatchStub.Value);
- }
- if (_dispatchLoop.IsValueCreated)
- {
- JitCache.Unmap(Marshal.GetFunctionPointerForDelegate(_dispatchLoop.Value));
- }
- _disposed = true;
- }
- }
- /// <summary>
- /// Frees resources used by the <see cref="TranslatorStubs"/> instance.
- /// </summary>
- ~TranslatorStubs()
- {
- Dispose(false);
- }
- /// <summary>
- /// Generates a <see cref="DispatchStub"/>.
- /// </summary>
- /// <returns>Generated <see cref="DispatchStub"/></returns>
- private IntPtr GenerateDispatchStub()
- {
- var context = new EmitterContext();
- Operand lblFallback = Label();
- Operand lblEnd = Label();
- // Load the target guest address from the native context.
- Operand nativeContext = context.LoadArgument(OperandType.I64, 0);
- Operand guestAddress = context.Load(OperandType.I64,
- context.Add(nativeContext, Const((ulong)NativeContext.GetDispatchAddressOffset())));
- // Check if guest address is within range of the AddressTable.
- Operand masked = context.BitwiseAnd(guestAddress, Const(~_translator.FunctionTable.Mask));
- context.BranchIfTrue(lblFallback, masked);
- Operand index = default;
- Operand page = Const((long)_translator.FunctionTable.Base);
- for (int i = 0; i < _translator.FunctionTable.Levels.Length; i++)
- {
- ref var level = ref _translator.FunctionTable.Levels[i];
- // level.Mask is not used directly because it is more often bigger than 32-bits, so it will not
- // be encoded as an immediate on x86's bitwise and operation.
- Operand mask = Const(level.Mask >> level.Index);
- index = context.BitwiseAnd(context.ShiftRightUI(guestAddress, Const(level.Index)), mask);
- if (i < _translator.FunctionTable.Levels.Length - 1)
- {
- page = context.Load(OperandType.I64, context.Add(page, context.ShiftLeft(index, Const(3))));
- context.BranchIfFalse(lblFallback, page);
- }
- }
- Operand hostAddress;
- Operand hostAddressAddr = context.Add(page, context.ShiftLeft(index, Const(3)));
- hostAddress = context.Load(OperandType.I64, hostAddressAddr);
- context.Tailcall(hostAddress, nativeContext);
- context.MarkLabel(lblFallback);
- hostAddress = context.Call(typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetFunctionAddress)), guestAddress);
- context.Tailcall(hostAddress, nativeContext);
- var cfg = context.GetControlFlowGraph();
- var retType = OperandType.I64;
- var argTypes = new[] { OperandType.I64 };
- var func = Compiler.Compile(cfg, argTypes, retType, CompilerOptions.HighCq).Map<GuestFunction>();
- return Marshal.GetFunctionPointerForDelegate(func);
- }
- /// <summary>
- /// Generates a <see cref="SlowDispatchStub"/>.
- /// </summary>
- /// <returns>Generated <see cref="SlowDispatchStub"/></returns>
- private static IntPtr GenerateSlowDispatchStub()
- {
- var context = new EmitterContext();
- // Load the target guest address from the native context.
- Operand nativeContext = context.LoadArgument(OperandType.I64, 0);
- Operand guestAddress = context.Load(OperandType.I64,
- context.Add(nativeContext, Const((ulong)NativeContext.GetDispatchAddressOffset())));
- MethodInfo getFuncAddress = typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetFunctionAddress));
- Operand hostAddress = context.Call(getFuncAddress, guestAddress);
- context.Tailcall(hostAddress, nativeContext);
- var cfg = context.GetControlFlowGraph();
- var retType = OperandType.I64;
- var argTypes = new[] { OperandType.I64 };
- var func = Compiler.Compile(cfg, argTypes, retType, CompilerOptions.HighCq).Map<GuestFunction>();
- return Marshal.GetFunctionPointerForDelegate(func);
- }
- /// <summary>
- /// Generates a <see cref="DispatchLoop"/> function.
- /// </summary>
- /// <returns><see cref="DispatchLoop"/> function</returns>
- private DispatcherFunction GenerateDispatchLoop()
- {
- var context = new EmitterContext();
- Operand beginLbl = Label();
- Operand endLbl = Label();
- Operand nativeContext = context.LoadArgument(OperandType.I64, 0);
- Operand guestAddress = context.Copy(
- context.AllocateLocal(OperandType.I64),
- context.LoadArgument(OperandType.I64, 1));
- Operand runningAddress = context.Add(nativeContext, Const((ulong)NativeContext.GetRunningOffset()));
- Operand dispatchAddress = context.Add(nativeContext, Const((ulong)NativeContext.GetDispatchAddressOffset()));
- context.MarkLabel(beginLbl);
- context.Store(dispatchAddress, guestAddress);
- context.Copy(guestAddress, context.Call(Const((ulong)DispatchStub), OperandType.I64, nativeContext));
- context.BranchIfFalse(endLbl, guestAddress);
- context.BranchIfFalse(endLbl, context.Load(OperandType.I32, runningAddress));
- context.Branch(beginLbl);
- context.MarkLabel(endLbl);
- context.Return();
- var cfg = context.GetControlFlowGraph();
- var retType = OperandType.None;
- var argTypes = new[] { OperandType.I64, OperandType.I64 };
- return Compiler.Compile(cfg, argTypes, retType, CompilerOptions.HighCq).Map<DispatcherFunction>();
- }
- }
- }
|