// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
using System;
using Internal.ReadyToRunConstants;
using Internal.Text;
using Internal.TypeSystem;
namespace ILCompiler.DependencyAnalysis
{
/// <summary>
/// NativeAOT extern names and signatures of the <see cref="ReadyToRunHelper"/> helpers. The helpers are referenced by name
/// only, so there is no backing <see cref="MethodDesc"/> to source a signature from; the signature (needed to
/// import the helper on Wasm) is derived here from each helper's declaration.
/// </summary>
internal static class KnownExternFunctions
{
public static Utf8String GetName(ReadyToRunHelper function, TargetDetails target)
{
string name = function switch
{
ReadyToRunHelper.Throw => "RhpThrowEx",
ReadyToRunHelper.Rethrow => "RhpRethrow",
ReadyToRunHelper.ThrowExact => "RhpThrowExact",
ReadyToRunHelper.FailFast => "RhpFallbackFailFast",
ReadyToRunHelper.DebugBreak => "RhDebugBreak",
ReadyToRunHelper.WriteBarrier => target.Architecture switch
{
TargetArchitecture.ARM64 => "RhpAssignRefArm64",
TargetArchitecture.LoongArch64 => "RhpAssignRefLoongArch64",
TargetArchitecture.RiscV64 => "RhpAssignRefRiscV64",
_ => "RhpAssignRef"
},
ReadyToRunHelper.CheckedWriteBarrier =>
target.Architecture == TargetArchitecture.ARM64 ? "RhpCheckedAssignRefArm64" : "RhpCheckedAssignRef",
ReadyToRunHelper.WriteBarrier_EAX => "RhpAssignRefEAX",
ReadyToRunHelper.WriteBarrier_EBX => "RhpAssignRefEBX",
ReadyToRunHelper.WriteBarrier_ECX => "RhpAssignRefECX",
ReadyToRunHelper.WriteBarrier_EDI => "RhpAssignRefEDI",
ReadyToRunHelper.WriteBarrier_ESI => "RhpAssignRefESI",
ReadyToRunHelper.WriteBarrier_EBP => "RhpAssignRefEBP",
ReadyToRunHelper.CheckedWriteBarrier_EAX => "RhpCheckedAssignRefEAX",
ReadyToRunHelper.CheckedWriteBarrier_EBX => "RhpCheckedAssignRefEBX",
ReadyToRunHelper.CheckedWriteBarrier_ECX => "RhpCheckedAssignRefECX",
ReadyToRunHelper.CheckedWriteBarrier_EDI => "RhpCheckedAssignRefEDI",
ReadyToRunHelper.CheckedWriteBarrier_ESI => "RhpCheckedAssignRefESI",
ReadyToRunHelper.CheckedWriteBarrier_EBP => "RhpCheckedAssignRefEBP",
ReadyToRunHelper.BulkWriteBarrierSmall => "RhBulkMoveWithWriteBarrier",
ReadyToRunHelper.NewArray => "RhNewArray",
ReadyToRunHelper.NewObject => "RhNewObject",
ReadyToRunHelper.NewFast => "RhpNewFast",
ReadyToRunHelper.NewFinalizable => "RhpNewFinalizable",
ReadyToRunHelper.NewFastAlign8 => "RhpNewFastAlign8",
ReadyToRunHelper.NewFinalizableAlign8 => "RhpNewFinalizableAlign8",
ReadyToRunHelper.NewFastMisalign => "RhpNewFastMisalign",
ReadyToRunHelper.NewPtrArrayFast => "RhpNewPtrArrayFast",
ReadyToRunHelper.NewArrayFastAlign8 => "RhpNewArrayFastAlign8",
ReadyToRunHelper.NewArrayFast => "RhpNewArrayFast",
ReadyToRunHelper.NativeMemSet => "memset",
ReadyToRunHelper.DblRem => "fmod",
ReadyToRunHelper.FltRem => "fmodf",
ReadyToRunHelper.Lng2Dbl => "RhpLng2Dbl",
ReadyToRunHelper.ULng2Dbl => "RhpULng2Dbl",
ReadyToRunHelper.Lng2Flt => "RhpLng2Flt",
ReadyToRunHelper.ULng2Flt => "RhpULng2Flt",
ReadyToRunHelper.Dbl2Lng => "RhpDbl2Lng",
ReadyToRunHelper.Dbl2ULng => "RhpDbl2ULng",
ReadyToRunHelper.LMul => "RhpLMul",
ReadyToRunHelper.LRsz => "RhpLRsz",
ReadyToRunHelper.LRsh => "RhpLRsh",
ReadyToRunHelper.LLsh => "RhpLLsh",
ReadyToRunHelper.PInvokeBegin => "RhpPInvoke",
ReadyToRunHelper.PInvokeEnd => "RhpPInvokeReturn",
ReadyToRunHelper.ReversePInvokeEnter => "RhpReversePInvoke",
ReadyToRunHelper.ReversePInvokeExit => "RhpReversePInvokeReturn",
ReadyToRunHelper.GVMLookupForSlot => "RhpDispatchResolve",
ReadyToRunHelper.InterfaceDispatch => "RhpInterfaceDispatch",
ReadyToRunHelper.InterfaceDispatchGuarded => "RhpInterfaceDispatchGuarded",
ReadyToRunHelper.ResolveInterfaceMethodFast => "RhpResolveInterfaceMethodFast",
ReadyToRunHelper.ResolveInterfaceMethod => "RhpResolveInterfaceMethod",
ReadyToRunHelper.StackProbe => "RhpStackProbe",
ReadyToRunHelper.GCPoll => "RhpGcPoll",
ReadyToRunHelper.TlsGetAddr => "__tls_get_addr",
_ => throw new NotImplementedException(function.ToString())
};
return new Utf8String(name);
}
/// <summary>
/// Gets the signature of <paramref name="function"/>, or null if it has no standard-ABI signature.
/// </summary>
/// <remarks>
/// Extern function nodes are shared by name, so when a function is also reachable through a direct
/// P/Invoke (e.g. CoreLib's memset), its signature must exactly match that P/Invoke's signature.
/// </remarks>
public static MethodSignature GetSignature(ReadyToRunHelper function, TypeSystemContext context)
{
TypeDesc voidType = context.GetWellKnownType(WellKnownType.Void);
TypeDesc voidPointerType = voidType.MakePointerType();
TypeDesc objectType = context.GetWellKnownType(WellKnownType.Object);
TypeDesc nativeIntType = context.GetWellKnownType(WellKnownType.IntPtr);
TypeDesc nativeUIntType = context.GetWellKnownType(WellKnownType.UIntPtr);
TypeDesc int32Type = context.GetWellKnownType(WellKnownType.Int32);
TypeDesc int64Type = context.GetWellKnownType(WellKnownType.Int64);
TypeDesc uint64Type = context.GetWellKnownType(WellKnownType.UInt64);
TypeDesc singleType = context.GetWellKnownType(WellKnownType.Single);
TypeDesc doubleType = context.GetWellKnownType(WellKnownType.Double);
MethodSignature MakeSignature(TypeDesc returnType, params TypeDesc[] parameters) =>
new MethodSignature(MethodSignatureFlags.Static, 0, returnType, parameters);
MethodSignature MakeUnmanagedSignature(TypeDesc returnType, params TypeDesc[] parameters) =>
new MethodSignature(MethodSignatureFlags.Static | MethodSignatureFlags.UnmanagedCallingConvention, 0, returnType, parameters);
return function switch
{
ReadyToRunHelper.Throw => MakeSignature(voidType, objectType),
ReadyToRunHelper.ThrowExact => MakeSignature(voidType, objectType),
ReadyToRunHelper.Rethrow => MakeSignature(voidType),
ReadyToRunHelper.FailFast => MakeSignature(voidType),
ReadyToRunHelper.DebugBreak => MakeSignature(voidType),
ReadyToRunHelper.WriteBarrier => MakeUnmanagedSignature(voidType, nativeIntType, objectType),
ReadyToRunHelper.CheckedWriteBarrier => MakeUnmanagedSignature(voidType, nativeIntType, objectType),
ReadyToRunHelper.WriteBarrier_EAX or
ReadyToRunHelper.WriteBarrier_EBX or
ReadyToRunHelper.WriteBarrier_ECX or
ReadyToRunHelper.WriteBarrier_EDI or
ReadyToRunHelper.WriteBarrier_ESI or
ReadyToRunHelper.WriteBarrier_EBP or
ReadyToRunHelper.CheckedWriteBarrier_EAX or
ReadyToRunHelper.CheckedWriteBarrier_EBX or
ReadyToRunHelper.CheckedWriteBarrier_ECX or
ReadyToRunHelper.CheckedWriteBarrier_EDI or
ReadyToRunHelper.CheckedWriteBarrier_ESI or
ReadyToRunHelper.CheckedWriteBarrier_EBP => null,
ReadyToRunHelper.BulkWriteBarrierSmall => MakeSignature(voidType, nativeIntType, nativeIntType, nativeUIntType),
ReadyToRunHelper.NewArray => MakeSignature(objectType, nativeIntType, nativeIntType),
ReadyToRunHelper.NewObject => MakeSignature(objectType, nativeIntType),
ReadyToRunHelper.NewFast => MakeSignature(objectType, nativeIntType),
ReadyToRunHelper.NewFinalizable => MakeSignature(objectType, nativeIntType),
ReadyToRunHelper.NewFastAlign8 => MakeSignature(objectType, nativeIntType),
ReadyToRunHelper.NewFinalizableAlign8 => MakeSignature(objectType, nativeIntType),
ReadyToRunHelper.NewFastMisalign => MakeSignature(objectType, nativeIntType),
ReadyToRunHelper.NewPtrArrayFast => MakeSignature(objectType, nativeIntType, nativeIntType),
ReadyToRunHelper.NewArrayFastAlign8 => MakeSignature(objectType, nativeIntType, nativeIntType),
ReadyToRunHelper.NewArrayFast => MakeSignature(objectType, nativeIntType, nativeIntType),
ReadyToRunHelper.NativeMemSet => MakeUnmanagedSignature(voidPointerType, voidPointerType, int32Type, nativeUIntType),
ReadyToRunHelper.DblRem => MakeSignature(doubleType, doubleType, doubleType),
ReadyToRunHelper.FltRem => MakeSignature(singleType, singleType, singleType),
ReadyToRunHelper.Lng2Dbl => MakeSignature(doubleType, int64Type),
ReadyToRunHelper.ULng2Dbl => MakeSignature(doubleType, uint64Type),
ReadyToRunHelper.Lng2Flt => MakeSignature(singleType, int64Type),
ReadyToRunHelper.ULng2Flt => MakeSignature(singleType, uint64Type),
ReadyToRunHelper.Dbl2Lng => MakeSignature(int64Type, doubleType),
ReadyToRunHelper.Dbl2ULng => MakeSignature(uint64Type, doubleType),
ReadyToRunHelper.LMul => MakeSignature(int64Type, int64Type, int64Type),
ReadyToRunHelper.LRsz => MakeSignature(uint64Type, uint64Type, int32Type),
ReadyToRunHelper.LRsh => MakeSignature(int64Type, int64Type, int32Type),
ReadyToRunHelper.LLsh => MakeSignature(int64Type, int64Type, int32Type),
ReadyToRunHelper.PInvokeBegin => MakeSignature(voidType, nativeIntType),
ReadyToRunHelper.PInvokeEnd => MakeSignature(voidType, nativeIntType),
ReadyToRunHelper.ReversePInvokeEnter => MakeSignature(voidType, nativeIntType),
ReadyToRunHelper.ReversePInvokeExit => MakeSignature(voidType, nativeIntType),
ReadyToRunHelper.GCPoll => MakeSignature(voidType),
ReadyToRunHelper.GVMLookupForSlot => MakeSignature(nativeIntType, objectType, nativeIntType),
ReadyToRunHelper.ResolveInterfaceMethod => MakeSignature(nativeIntType, objectType, nativeIntType),
ReadyToRunHelper.ResolveInterfaceMethodFast => throw new NotImplementedException(
$"{nameof(ReadyToRunHelper.ResolveInterfaceMethodFast)} is not implemented by the runtime."),
ReadyToRunHelper.InterfaceDispatch or
ReadyToRunHelper.InterfaceDispatchGuarded => null,
ReadyToRunHelper.StackProbe => null,
ReadyToRunHelper.TlsGetAddr => null,
_ => throw new NotImplementedException(function.ToString())
};
}
}
}