Skip to content

Commit dc2b0f7

Browse files
AustinWisejkotas
andauthored
[NativeAOT] Objective-C: SetMessageSendPendingException and SetMessageSendCallback (#77956)
Co-authored-by: Jan Kotas <[email protected]>
1 parent 16b28c7 commit dc2b0f7

File tree

10 files changed

+160
-4
lines changed

10 files changed

+160
-4
lines changed

src/coreclr/nativeaot/Directory.Build.props

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,13 @@
5959
<FeatureComWrappers>false</FeatureComWrappers>
6060
<FeatureComWrappers Condition="'$(TargetsWindows)' == 'true'">true</FeatureComWrappers>
6161
</PropertyGroup>
62+
<PropertyGroup>
63+
<FeatureObjCMarshal>false</FeatureObjCMarshal>
64+
<FeatureObjCMarshal Condition="'$(TargetsOSX)' == 'true'">true</FeatureObjCMarshal>
65+
</PropertyGroup>
66+
<PropertyGroup>
67+
<DefineConstants Condition="'$(FeatureObjCMarshal)' == 'true'">FEATURE_OBJCMARSHAL;$(DefineConstants)</DefineConstants>
68+
</PropertyGroup>
6269

6370
<!-- Platform specific properties -->
6471
<PropertyGroup Condition="'$(Platform)' == 'x64'">

src/coreclr/nativeaot/System.Private.CoreLib/src/Internal/Runtime/CompilerHelpers/InteropHelpers.cs

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
using System.Runtime;
1010
using System.Runtime.CompilerServices;
1111
using System.Runtime.InteropServices;
12+
using System.Runtime.InteropServices.ObjectiveC;
1213
using System.Runtime.Loader;
1314
using System.Text;
1415
using System.Threading;
@@ -342,6 +343,17 @@ internal static unsafe void FixupMethodCell(IntPtr hModule, MethodFixupCell* pCe
342343
byte* methodName = (byte*)pCell->MethodName;
343344
IntPtr pTarget;
344345

346+
#if FEATURE_OBJCMARSHAL
347+
#pragma warning disable CA1416
348+
if (pCell->IsObjectiveCMessageSend && ObjectiveCMarshal.TryGetGlobalMessageSendCallback(pCell->ObjectiveCMessageSendFunction, out pTarget))
349+
{
350+
Debug.Assert(pTarget != IntPtr.Zero);
351+
pCell->Target = pTarget;
352+
return;
353+
}
354+
#pragma warning restore CA1416
355+
#endif
356+
345357
#if TARGET_WINDOWS
346358
CharSet charSetMangling = pCell->CharSetMangling;
347359
if (charSetMangling == 0)
@@ -613,7 +625,11 @@ internal unsafe struct MethodFixupCell
613625
public IntPtr Target;
614626
public IntPtr MethodName;
615627
public ModuleFixupCell* Module;
616-
public CharSet CharSetMangling;
628+
private int Flags;
629+
630+
public CharSet CharSetMangling => (CharSet)(Flags & MethodFixupCellFlagsConstants.CharSetMask);
631+
public bool IsObjectiveCMessageSend => (Flags & MethodFixupCellFlagsConstants.IsObjectiveCMessageSendMask) != 0;
632+
public int ObjectiveCMessageSendFunction => (Flags & MethodFixupCellFlagsConstants.ObjectiveCMessageSendFunctionMask) >> MethodFixupCellFlagsConstants.ObjectiveCMessageSendFunctionShift;
617633
}
618634

619635
internal unsafe struct CustomMarshallerKey : IEquatable<CustomMarshallerKey>

src/coreclr/nativeaot/System.Private.CoreLib/src/System.Private.CoreLib.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -212,6 +212,7 @@
212212
<Compile Include="System\Runtime\InteropServices\Marshal.NativeAot.cs" />
213213
<Compile Include="System\Runtime\InteropServices\Marshal.Com.cs" Condition="'$(FeatureCominterop)' == 'true'" />
214214
<Compile Include="System\Runtime\InteropServices\MemoryMarshal.NativeAot.cs" />
215+
<Compile Include="System\Runtime\InteropServices\ObjectiveCMarshal.NativeAot.cs" Condition="'$(FeatureObjCMarshal)' == 'true'" />
215216
<Compile Include="System\Runtime\InteropServices\UnsafeGCHandle.cs" />
216217
<Compile Include="System\Runtime\Intrinsics\X86\X86Base.NativeAot.cs" Condition="'$(SupportsX86Intrinsics)' == 'true'" />
217218
<Compile Include="System\Runtime\JitInfo.NativeAot.cs" />
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
4+
using System;
5+
using System.Diagnostics;
6+
using System.Runtime.ExceptionServices;
7+
using System.Threading;
8+
9+
namespace System.Runtime.InteropServices.ObjectiveC
10+
{
11+
public static unsafe partial class ObjectiveCMarshal
12+
{
13+
private static readonly IntPtr[] s_ObjcMessageSendFunctions = new IntPtr[(int)MessageSendFunction.MsgSendSuperStret + 1];
14+
15+
[ThreadStatic]
16+
private static Exception? t_pendingExceptionObject;
17+
18+
/// <summary>
19+
/// Sets a pending exception to be thrown the next time the runtime is entered from an Objective-C msgSend P/Invoke.
20+
/// </summary>
21+
/// <param name="exception">The exception.</param>
22+
/// <remarks>
23+
/// If <c>null</c> is supplied any pending exception is discarded.
24+
/// </remarks>
25+
public static void SetMessageSendPendingException(Exception? exception)
26+
{
27+
t_pendingExceptionObject = exception;
28+
}
29+
30+
private static bool TrySetGlobalMessageSendCallback(
31+
MessageSendFunction msgSendFunction,
32+
IntPtr func)
33+
{
34+
return Interlocked.CompareExchange(ref s_ObjcMessageSendFunctions[(int)msgSendFunction], func, IntPtr.Zero) == IntPtr.Zero;
35+
}
36+
37+
internal static bool TryGetGlobalMessageSendCallback(int msgSendFunction, out IntPtr func)
38+
{
39+
func = s_ObjcMessageSendFunctions[msgSendFunction];
40+
return func != IntPtr.Zero;
41+
}
42+
43+
[StackTraceHidden]
44+
internal static void ThrowPendingExceptionObject()
45+
{
46+
Exception? ex = t_pendingExceptionObject;
47+
if (ex != null)
48+
{
49+
t_pendingExceptionObject = null;
50+
ExceptionDispatchInfo.Throw(ex);
51+
}
52+
}
53+
54+
private static bool TryInitializeReferenceTracker(
55+
delegate* unmanaged<void> beginEndCallback,
56+
delegate* unmanaged<IntPtr, int> isReferencedCallback,
57+
delegate* unmanaged<IntPtr, void> trackedObjectEnteredFinalization)
58+
{
59+
throw new NotImplementedException();
60+
}
61+
62+
private static IntPtr CreateReferenceTrackingHandleInternal(
63+
object obj,
64+
out int memInSizeT,
65+
out IntPtr mem)
66+
{
67+
throw new NotImplementedException();
68+
}
69+
}
70+
}

src/coreclr/tools/Common/Internal/Runtime/RuntimeConstants.cs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,4 +78,15 @@ internal enum RuntimeHelperKind
7878
CastClass,
7979
AllocateArray,
8080
}
81+
82+
/// <summary>
83+
/// Constants that describe the bits of the Flags field of MethodFixupCell.
84+
/// </summary>
85+
internal static class MethodFixupCellFlagsConstants
86+
{
87+
public const int CharSetMask = 0x7;
88+
public const int IsObjectiveCMessageSendMask = 0x8;
89+
public const int ObjectiveCMessageSendFunctionMask = 0x70;
90+
public const int ObjectiveCMessageSendFunctionShift = 4;
91+
}
8192
}

src/coreclr/tools/Common/TypeSystem/IL/Stubs/PInvokeILEmitter.cs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -345,6 +345,13 @@ private void EmitPInvokeCall(PInvokeILCodeStreams ilCodeStreams)
345345
InteropTypes.GetPInvokeMarshal(context)
346346
.GetKnownMethod("SaveLastError", null)));
347347
}
348+
349+
if (MarshalHelpers.ShouldCheckForPendingException(context.Target, _pInvokeMetadata))
350+
{
351+
MetadataType lazyHelperType = context.SystemModule.GetKnownType("System.Runtime.InteropServices.ObjectiveC", "ObjectiveCMarshal");
352+
callsiteSetupCodeStream.Emit(ILOpcode.call, emitter.NewToken(lazyHelperType
353+
.GetKnownMethod("ThrowPendingExceptionObject", null)));
354+
}
348355
}
349356

350357
private void EmitCalli(PInvokeILCodeStreams ilCodeStreams, CalliMarshallingMethodThunk calliThunk)

src/coreclr/tools/Common/TypeSystem/Interop/IL/MarshalHelpers.cs

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33

44
using System;
55
using Debug = System.Diagnostics.Debug;
6+
using System.Runtime.InteropServices.ObjectiveC;
67
using Internal.TypeSystem.Ecma;
78

89
namespace Internal.TypeSystem.Interop
@@ -920,12 +921,13 @@ internal static MarshallerKind GetDisabledMarshallerKind(
920921
return MarshallerKind.Invalid;
921922
}
922923

924+
private const string ObjectiveCLibrary = "/usr/lib/libobjc.dylib";
925+
923926
internal static bool ShouldCheckForPendingException(TargetDetails target, PInvokeMetadata metadata)
924927
{
925928
if (!target.IsOSX)
926929
return false;
927930

928-
const string ObjectiveCLibrary = "/usr/lib/libobjc.dylib";
929931
const string ObjectiveCMsgSend = "objc_msgSend";
930932

931933
// This is for the objc_msgSend suite of functions.
@@ -938,6 +940,24 @@ internal static bool ShouldCheckForPendingException(TargetDetails target, PInvok
938940
&& metadata.Name.StartsWith(ObjectiveCMsgSend);
939941
}
940942

943+
internal static int? GetObjectiveCMessageSendFunction(TargetDetails target, string pinvokeModule, string pinvokeFunction)
944+
{
945+
if (!target.IsOSX || pinvokeModule != ObjectiveCLibrary)
946+
return null;
947+
948+
#pragma warning disable CA1416
949+
return pinvokeFunction switch
950+
{
951+
"objc_msgSend" => (int)ObjectiveCMarshal.MessageSendFunction.MsgSend,
952+
"objc_msgSend_fpret" => (int)ObjectiveCMarshal.MessageSendFunction.MsgSendFpret,
953+
"objc_msgSend_stret" => (int)ObjectiveCMarshal.MessageSendFunction.MsgSendStret,
954+
"objc_msgSendSuper" => (int)ObjectiveCMarshal.MessageSendFunction.MsgSendSuper,
955+
"objc_msgSendSuper_stret" => (int)ObjectiveCMarshal.MessageSendFunction.MsgSendSuperStret,
956+
_ => null,
957+
};
958+
#pragma warning restore CA1416
959+
}
960+
941961
public static bool IsRuntimeMarshallingEnabled(ModuleDesc module)
942962
{
943963
return module.Assembly is not EcmaAssembly assembly || !assembly.HasAssemblyCustomAttribute("System.Runtime.CompilerServices", "DisableRuntimeMarshallingAttribute");

src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/PInvokeMethodFixupNode.cs

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,15 @@
22
// The .NET Foundation licenses this file to you under the MIT license.
33

44
using System;
5+
using System.Diagnostics;
56
using System.Runtime.InteropServices;
67

78
using Internal.IL.Stubs;
9+
using Internal.Runtime;
810
using Internal.Text;
911
using Internal.TypeSystem;
1012
using Internal.TypeSystem.Ecma;
13+
using Internal.TypeSystem.Interop;
1114

1215
namespace ILCompiler.DependencyAnalysis
1316
{
@@ -73,7 +76,25 @@ public override ObjectData GetData(NodeFactory factory, bool relocsOnly = false)
7376
// Module fixup cell
7477
builder.EmitPointerReloc(factory.PInvokeModuleFixup(_pInvokeMethodData.ModuleData));
7578

76-
builder.EmitInt((int)_pInvokeMethodData.CharSetMangling);
79+
int flags = 0;
80+
81+
int charsetFlags = (int)_pInvokeMethodData.CharSetMangling;
82+
Debug.Assert((charsetFlags & MethodFixupCellFlagsConstants.CharSetMask) == charsetFlags);
83+
charsetFlags &= MethodFixupCellFlagsConstants.CharSetMask;
84+
flags |= charsetFlags;
85+
86+
int? objcFunction = MarshalHelpers.GetObjectiveCMessageSendFunction(factory.Target, _pInvokeMethodData.ModuleData.ModuleName, _pInvokeMethodData.EntryPointName);
87+
if (objcFunction.HasValue)
88+
{
89+
flags |= MethodFixupCellFlagsConstants.IsObjectiveCMessageSendMask;
90+
91+
int objcFunctionFlags = objcFunction.Value << MethodFixupCellFlagsConstants.ObjectiveCMessageSendFunctionShift;
92+
Debug.Assert((objcFunctionFlags & MethodFixupCellFlagsConstants.ObjectiveCMessageSendFunctionMask) == objcFunctionFlags);
93+
objcFunctionFlags &= MethodFixupCellFlagsConstants.ObjectiveCMessageSendFunctionMask;
94+
flags |= objcFunctionFlags;
95+
}
96+
97+
builder.EmitInt(flags);
7798

7899
return builder.ToObjectData();
79100
}

src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/ObjectiveC/ObjectiveCMarshal.cs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,11 @@ public static GCHandle CreateReferenceTrackingHandle(
109109
ArgumentNullException.ThrowIfNull(obj);
110110

111111
IntPtr refCountHandle = CreateReferenceTrackingHandleInternal(
112+
#if NATIVEAOT
113+
obj,
114+
#else
112115
ObjectHandleOnStack.Create(ref obj),
116+
#endif
113117
out int memInSizeT,
114118
out IntPtr mem);
115119

src/libraries/System.Runtime.InteropServices/tests/System.Runtime.InteropServices.UnitTests/System/Runtime/InteropServices/ObjectiveC/MessageSendTests.cs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@ namespace System.Runtime.InteropServices.Tests
1616
{
1717
[PlatformSpecific(TestPlatforms.OSX)]
1818
[SkipOnMono("Not currently implemented on Mono")]
19-
[ConditionalClass(typeof(PlatformDetection), nameof(PlatformDetection.IsNotNativeAot))] // https://github.com/dotnet/runtimelab/issues/155
2019
public unsafe class MessageSendTests
2120
{
2221
private static int s_count = 1;

0 commit comments

Comments
 (0)