Allow reflection for NativeInterface + statically reference GetFunctionAddress so it gets compiled

This commit is contained in:
Evan Husted 2025-03-01 19:56:00 -06:00
parent ccfcdd4219
commit c3083076ee
9 changed files with 89 additions and 70 deletions

View File

@ -7,15 +7,17 @@ namespace ARMeilleure.Instructions
{
static partial class InstEmit
{
private const string SupervisorCallName = nameof(NativeInterface.SupervisorCall);
private const string BreakName = nameof(NativeInterface.Break);
private const string UndefinedName = nameof(NativeInterface.Undefined);
public static void Brk(ArmEmitterContext context)
{
OpCodeException op = (OpCodeException)context.CurrOp;
string name = nameof(NativeInterface.Break);
context.StoreToContext();
context.Call(typeof(NativeInterface).GetMethod(name), Const(op.Address), Const(op.Id));
context.Call(NativeInterface.Type.GetMethod(BreakName), Const(op.Address), Const(op.Id));
context.LoadFromContext();
@ -25,12 +27,10 @@ namespace ARMeilleure.Instructions
public static void Svc(ArmEmitterContext context)
{
OpCodeException op = (OpCodeException)context.CurrOp;
string name = nameof(NativeInterface.SupervisorCall);
context.StoreToContext();
context.Call(typeof(NativeInterface).GetMethod(name), Const(op.Address), Const(op.Id));
context.Call(NativeInterface.Type.GetMethod(SupervisorCallName), Const(op.Address), Const(op.Id));
context.LoadFromContext();
@ -41,11 +41,9 @@ namespace ARMeilleure.Instructions
{
OpCode op = context.CurrOp;
string name = nameof(NativeInterface.Undefined);
context.StoreToContext();
context.Call(typeof(NativeInterface).GetMethod(name), Const(op.Address), Const(op.RawOpCode));
context.Call(NativeInterface.Type.GetMethod(UndefinedName), Const(op.Address), Const(op.RawOpCode));
context.LoadFromContext();

View File

@ -14,7 +14,7 @@ namespace ARMeilleure.Instructions
context.StoreToContext();
context.Call(typeof(NativeInterface).GetMethod(name), Const(((IOpCode)op).Address), Const(op.Id));
context.Call(NativeInterface.Type.GetMethod(name), Const(((IOpCode)op).Address), Const(op.Id));
context.LoadFromContext();
@ -29,7 +29,7 @@ namespace ARMeilleure.Instructions
context.StoreToContext();
context.Call(typeof(NativeInterface).GetMethod(name), Const(((IOpCode)op).Address), Const(op.Id));
context.Call(NativeInterface.Type.GetMethod(name), Const(((IOpCode)op).Address), Const(op.Id));
context.LoadFromContext();

View File

@ -478,7 +478,7 @@ namespace ARMeilleure.Instructions
context.BranchIf(lblNotWatched, pte, Const(0L), Comparison.GreaterOrEqual, BasicBlockFrequency.Cold);
// Signal memory tracking. Size here doesn't matter as address is assumed to be size aligned here.
context.Call(typeof(NativeInterface).GetMethod(nameof(NativeInterface.SignalMemoryTracking)), address, Const(1UL), Const(write ? 1 : 0));
context.Call(NativeInterface.Type.GetMethod(nameof(NativeInterface.SignalMemoryTracking)), address, Const(1UL), Const(write ? 1 : 0));
context.MarkLabel(lblNotWatched);
pte = context.BitwiseAnd(pte, Const(0xffffffffffffUL)); // Ignore any software protection bits. (they are still used by C# memory access)
@ -489,7 +489,7 @@ namespace ARMeilleure.Instructions
context.BranchIfTrue(lblNonNull, pte, BasicBlockFrequency.Cold);
// The call is not expected to return (it should throw).
context.Call(typeof(NativeInterface).GetMethod(nameof(NativeInterface.ThrowInvalidMemoryAccess)), address);
context.Call(NativeInterface.Type.GetMethod(nameof(NativeInterface.ThrowInvalidMemoryAccess)), address);
context.MarkLabel(lblNonNull);
}
@ -535,16 +535,16 @@ namespace ARMeilleure.Instructions
switch (size)
{
case 0:
info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.ReadByte));
info = NativeInterface.Type.GetMethod(nameof(NativeInterface.ReadByte));
break;
case 1:
info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.ReadUInt16));
info = NativeInterface.Type.GetMethod(nameof(NativeInterface.ReadUInt16));
break;
case 2:
info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.ReadUInt32));
info = NativeInterface.Type.GetMethod(nameof(NativeInterface.ReadUInt32));
break;
case 3:
info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.ReadUInt64));
info = NativeInterface.Type.GetMethod(nameof(NativeInterface.ReadUInt64));
break;
}
@ -564,19 +564,19 @@ namespace ARMeilleure.Instructions
switch (size)
{
case 0:
info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.ReadByte));
info = NativeInterface.Type.GetMethod(nameof(NativeInterface.ReadByte));
break;
case 1:
info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.ReadUInt16));
info = NativeInterface.Type.GetMethod(nameof(NativeInterface.ReadUInt16));
break;
case 2:
info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.ReadUInt32));
info = NativeInterface.Type.GetMethod(nameof(NativeInterface.ReadUInt32));
break;
case 3:
info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.ReadUInt64));
info = NativeInterface.Type.GetMethod(nameof(NativeInterface.ReadUInt64));
break;
case 4:
info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.ReadVector128));
info = NativeInterface.Type.GetMethod(nameof(NativeInterface.ReadVector128));
break;
}
@ -608,16 +608,16 @@ namespace ARMeilleure.Instructions
switch (size)
{
case 0:
info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.WriteByte));
info = NativeInterface.Type.GetMethod(nameof(NativeInterface.WriteByte));
break;
case 1:
info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.WriteUInt16));
info = NativeInterface.Type.GetMethod(nameof(NativeInterface.WriteUInt16));
break;
case 2:
info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.WriteUInt32));
info = NativeInterface.Type.GetMethod(nameof(NativeInterface.WriteUInt32));
break;
case 3:
info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.WriteUInt64));
info = NativeInterface.Type.GetMethod(nameof(NativeInterface.WriteUInt64));
break;
}
@ -643,19 +643,19 @@ namespace ARMeilleure.Instructions
switch (size)
{
case 0:
info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.WriteByte));
info = NativeInterface.Type.GetMethod(nameof(NativeInterface.WriteByte));
break;
case 1:
info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.WriteUInt16));
info = NativeInterface.Type.GetMethod(nameof(NativeInterface.WriteUInt16));
break;
case 2:
info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.WriteUInt32));
info = NativeInterface.Type.GetMethod(nameof(NativeInterface.WriteUInt32));
break;
case 3:
info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.WriteUInt64));
info = NativeInterface.Type.GetMethod(nameof(NativeInterface.WriteUInt64));
break;
case 4:
info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.WriteVector128));
info = NativeInterface.Type.GetMethod(nameof(NativeInterface.WriteVector128));
break;
}

View File

@ -29,10 +29,10 @@ namespace ARMeilleure.Instructions
switch (GetPackedId(op))
{
case 0b11_011_0000_0000_001:
info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetCtrEl0));
info = NativeInterface.Type.GetMethod(nameof(NativeInterface.GetCtrEl0));
break;
case 0b11_011_0000_0000_111:
info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetDczidEl0));
info = NativeInterface.Type.GetMethod(nameof(NativeInterface.GetDczidEl0));
break;
case 0b11_011_0100_0010_000:
EmitGetNzcv(context);
@ -53,13 +53,13 @@ namespace ARMeilleure.Instructions
EmitGetTpidr2El0(context);
return;
case 0b11_011_1110_0000_000:
info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetCntfrqEl0));
info = NativeInterface.Type.GetMethod(nameof(NativeInterface.GetCntfrqEl0));
break;
case 0b11_011_1110_0000_001:
info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetCntpctEl0));
info = NativeInterface.Type.GetMethod(nameof(NativeInterface.GetCntpctEl0));
break;
case 0b11_011_1110_0000_010:
info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetCntvctEl0));
info = NativeInterface.Type.GetMethod(nameof(NativeInterface.GetCntvctEl0));
break;
default:
@ -131,7 +131,7 @@ namespace ARMeilleure.Instructions
case 0b11_011_0111_0101_001: // IC IVAU
Operand target = Register(op.Rt, RegisterType.Integer, OperandType.I64);
context.Call(typeof(NativeInterface).GetMethod(nameof(NativeInterface.InvalidateCacheLine)), target);
context.Call(NativeInterface.Type.GetMethod(nameof(NativeInterface.InvalidateCacheLine)), target);
break;
}
}

View File

@ -127,7 +127,7 @@ namespace ARMeilleure.Instructions
// Timer.
14 => opc switch
{
0 => typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetCntpctEl0)),
0 => NativeInterface.Type.GetMethod(nameof(NativeInterface.GetCntpctEl0)),
_ => throw new NotImplementedException($"Unknown MRRC Opc1 0x{opc:X} at 0x{op.Address:X} (0x{op.RawOpCode:X})."),
},
_ => throw new NotImplementedException($"Unknown MRRC 0x{op.RawOpCode:X} at 0x{op.Address:X}."),

View File

@ -2,12 +2,32 @@ using ARMeilleure.Memory;
using ARMeilleure.State;
using ARMeilleure.Translation;
using System;
using System.Diagnostics.CodeAnalysis;
using System.Runtime.InteropServices;
namespace ARMeilleure.Instructions
{
static class NativeInterface
{
[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)]
public static readonly Type Type = typeof(NativeInterface);
static NativeInterface()
{
try
{
//TODO:
// dude. this is so bad. figure out AOT's bs.
// this needs to be compiled into the AOT build but it doesn't get compiled
// under any circumstances unless directly referenced like below, not dynamically which is how it's always used.
_ = GetFunctionAddress(0);
}
catch
{
}
}
private class ThreadContext
{
public ExecutionContext Context { get; }
@ -178,8 +198,7 @@ namespace ARMeilleure.Instructions
{
throw new InvalidAccessException(address);
}
[UnmanagedCallersOnly]
public static ulong GetFunctionAddress(ulong address)
{
TranslatedFunction function = Context.Translator.GetOrTranslate(address, GetContext().ExecutionMode);

View File

@ -1,6 +1,7 @@
using ARMeilleure.Instructions;
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Reflection;
namespace ARMeilleure.Translation
@ -62,7 +63,7 @@ namespace ARMeilleure.Translation
}
private static readonly SortedList<string, DelegateInfo> _delegates;
static Delegates()
{
_delegates = new SortedList<string, DelegateInfo>();
@ -79,30 +80,30 @@ namespace ARMeilleure.Translation
SetDelegateInfo(typeof(MathHelperF).GetMethod(nameof(MathHelperF.Round)));
SetDelegateInfo(typeof(MathHelperF).GetMethod(nameof(MathHelperF.Truncate)));
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.Break)));
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.CheckSynchronization)));
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.EnqueueForRejit)));
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetCntfrqEl0)));
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetCntpctEl0)));
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetCntvctEl0)));
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetCtrEl0)));
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetDczidEl0)));
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetFunctionAddress)));
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.InvalidateCacheLine)));
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.ReadByte)));
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.ReadUInt16)));
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.ReadUInt32)));
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.ReadUInt64)));
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.ReadVector128)));
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.SignalMemoryTracking)));
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.SupervisorCall)));
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.ThrowInvalidMemoryAccess)));
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.Undefined)));
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.WriteByte)));
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.WriteUInt16)));
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.WriteUInt32)));
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.WriteUInt64)));
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.WriteVector128)));
SetDelegateInfo(NativeInterface.Type.GetMethod(nameof(NativeInterface.Break)));
SetDelegateInfo(NativeInterface.Type.GetMethod(nameof(NativeInterface.CheckSynchronization)));
SetDelegateInfo(NativeInterface.Type.GetMethod(nameof(NativeInterface.EnqueueForRejit)));
SetDelegateInfo(NativeInterface.Type.GetMethod(nameof(NativeInterface.GetCntfrqEl0)));
SetDelegateInfo(NativeInterface.Type.GetMethod(nameof(NativeInterface.GetCntpctEl0)));
SetDelegateInfo(NativeInterface.Type.GetMethod(nameof(NativeInterface.GetCntvctEl0)));
SetDelegateInfo(NativeInterface.Type.GetMethod(nameof(NativeInterface.GetCtrEl0)));
SetDelegateInfo(NativeInterface.Type.GetMethod(nameof(NativeInterface.GetDczidEl0)));
SetDelegateInfo(NativeInterface.Type.GetMethod(nameof(NativeInterface.GetFunctionAddress)));
SetDelegateInfo(NativeInterface.Type.GetMethod(nameof(NativeInterface.InvalidateCacheLine)));
SetDelegateInfo(NativeInterface.Type.GetMethod(nameof(NativeInterface.ReadByte)));
SetDelegateInfo(NativeInterface.Type.GetMethod(nameof(NativeInterface.ReadUInt16)));
SetDelegateInfo(NativeInterface.Type.GetMethod(nameof(NativeInterface.ReadUInt32)));
SetDelegateInfo(NativeInterface.Type.GetMethod(nameof(NativeInterface.ReadUInt64)));
SetDelegateInfo(NativeInterface.Type.GetMethod(nameof(NativeInterface.ReadVector128)));
SetDelegateInfo(NativeInterface.Type.GetMethod(nameof(NativeInterface.SignalMemoryTracking)));
SetDelegateInfo(NativeInterface.Type.GetMethod(nameof(NativeInterface.SupervisorCall)));
SetDelegateInfo(NativeInterface.Type.GetMethod(nameof(NativeInterface.ThrowInvalidMemoryAccess)));
SetDelegateInfo(NativeInterface.Type.GetMethod(nameof(NativeInterface.Undefined)));
SetDelegateInfo(NativeInterface.Type.GetMethod(nameof(NativeInterface.WriteByte)));
SetDelegateInfo(NativeInterface.Type.GetMethod(nameof(NativeInterface.WriteUInt16)));
SetDelegateInfo(NativeInterface.Type.GetMethod(nameof(NativeInterface.WriteUInt32)));
SetDelegateInfo(NativeInterface.Type.GetMethod(nameof(NativeInterface.WriteUInt64)));
SetDelegateInfo(NativeInterface.Type.GetMethod(nameof(NativeInterface.WriteVector128)));
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.CountLeadingSigns)));
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.CountLeadingZeros)));

View File

@ -457,7 +457,7 @@ namespace ARMeilleure.Translation
context.Store(address, count);
context.BranchIf(lblEnd, curCount, Const(MinsCallForRejit), Comparison.NotEqual, BasicBlockFrequency.Cold);
context.Call(typeof(NativeInterface).GetMethod(nameof(NativeInterface.EnqueueForRejit)), Const(context.EntryAddress));
context.Call(NativeInterface.Type.GetMethod(nameof(NativeInterface.EnqueueForRejit)), Const(context.EntryAddress));
context.MarkLabel(lblEnd);
}
@ -473,7 +473,7 @@ namespace ARMeilleure.Translation
Operand count = context.Load(OperandType.I32, countAddr);
context.BranchIfTrue(lblNonZero, count, BasicBlockFrequency.Cold);
Operand running = context.Call(typeof(NativeInterface).GetMethod(nameof(NativeInterface.CheckSynchronization)));
Operand running = context.Call(NativeInterface.Type.GetMethod(nameof(NativeInterface.CheckSynchronization)));
context.BranchIfTrue(lblExit, running, BasicBlockFrequency.Cold);
context.Return(Const(0L));

View File

@ -4,6 +4,7 @@ using ARMeilleure.IntermediateRepresentation;
using ARMeilleure.State;
using ARMeilleure.Translation.Cache;
using System;
using System.Diagnostics.CodeAnalysis;
using System.Runtime.InteropServices;
using static ARMeilleure.IntermediateRepresentation.Operand.Factory;
@ -181,7 +182,7 @@ namespace ARMeilleure.Translation
context.Tailcall(hostAddress, nativeContext);
context.MarkLabel(lblFallback);
hostAddress = context.Call(typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetFunctionAddress)), guestAddress);
hostAddress = context.Call(NativeInterface.Type.GetMethod(nameof(NativeInterface.GetFunctionAddress)), guestAddress);
context.Tailcall(hostAddress, nativeContext);
ControlFlowGraph cfg = context.GetControlFlowGraph();
@ -206,7 +207,7 @@ namespace ARMeilleure.Translation
Operand guestAddress = context.Load(OperandType.I64,
context.Add(nativeContext, Const((ulong)NativeContext.GetDispatchAddressOffset())));
Operand hostAddress = context.Call(typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetFunctionAddress)), guestAddress);
Operand hostAddress = context.Call(NativeInterface.Type.GetMethod(nameof(NativeInterface.GetFunctionAddress)), guestAddress);
context.Tailcall(hostAddress, nativeContext);
ControlFlowGraph cfg = context.GetControlFlowGraph();