Skip to content

Commit

Permalink
Low level API support for Objective-C interop. (dotnet#52146)
Browse files Browse the repository at this point in the history
* Add Objective-C interop support.

* Include handling of HNDTYPE_REFCOUNTED when FEATURE_OBJCMARSHAL is defined (dotnet#47534)

* Allow overriding of Objective-C message send P/Invokes (dotnet#47721)

* Add new flag to MethodTable for types with ObjectiveCTrackedTypeAttribute.
Discover attribute during type load and set bit.
Update EagerFinalizer callout to query bit.

* Add testing for API

* Bridge API for propagating managed exception to native.

* Update GCEE interface to support GCServer scenario for Objective-C.
The new callbacks now fire when before the GC scans handles and is
non-concurrent.

* Comment added for ExceptionTracker non-NULL condition.

Co-authored-by: Jeremy Koritzinsky <[email protected]>
Co-authored-by: Elinor Fung <[email protected]>
Co-authored-by: Rolf Bjarne Kvinge <[email protected]>
  • Loading branch information
4 people authored May 13, 2021
1 parent d77854a commit c1e7ca8
Show file tree
Hide file tree
Showing 69 changed files with 2,590 additions and 304 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -297,6 +297,9 @@
</Compile>
<Compile Include="$(BclSourcesRoot)\System\Threading\ClrThreadPoolBoundHandle.Windows.cs" />
</ItemGroup>
<ItemGroup Condition="'$(FeatureObjCMarshal)' == 'true'">
<Compile Include="$(BclSourcesRoot)\System\Runtime\InteropServices\ObjectiveCMarshal.CoreCLR.cs" />
</ItemGroup>
<!-- Include additional sources shared files in the compilation -->
<Import Project="$(LibrariesProjectRoot)\System.Private.CoreLib\src\System.Private.CoreLib.Shared.projitems" Label="Shared" />

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System.Diagnostics;
using System.Runtime.Versioning;
using System.Runtime.CompilerServices;

namespace System.Runtime.InteropServices.ObjectiveC
{
public static partial class ObjectiveCMarshal
{
/// <summary>
/// Sets a pending exception to be thrown the next time the runtime is entered from an overridden msgSend P/Invoke.
/// </summary>
/// <param name="exception">The exception.</param>
/// <remarks>
/// If <c>null</c> is supplied any pending exception is discarded.
/// </remarks>
public static void SetMessageSendPendingException(Exception? exception)
{
System.StubHelpers.StubHelpers.SetPendingExceptionObject(exception);
}

[DllImport(RuntimeHelpers.QCall)]
private static extern bool TrySetGlobalMessageSendCallback(
MessageSendFunction msgSendFunction,
IntPtr func);

[DllImport(RuntimeHelpers.QCall)]
private static unsafe extern bool TryInitializeReferenceTracker(
delegate* unmanaged<void> beginEndCallback,
delegate* unmanaged<IntPtr, int> isReferencedCallback,
delegate* unmanaged<IntPtr, void> trackedObjectEnteredFinalization);

[DllImport(RuntimeHelpers.QCall)]
private static extern IntPtr CreateReferenceTrackingHandleInternal(
ObjectHandleOnStack obj,
out int memInSizeT,
out IntPtr mem);

internal static bool AvailableUnhandledExceptionPropagation()
{
return s_unhandledExceptionPropagationHandler != null;
}

internal static unsafe void* InvokeUnhandledExceptionPropagation(
Exception exception,
object methodInfoStub,
out IntPtr context)
{
context = IntPtr.Zero;
if (s_unhandledExceptionPropagationHandler == null)
return null;

Debug.Assert(methodInfoStub is RuntimeMethodInfoStub);
var runtimeHandle = new RuntimeMethodHandle((RuntimeMethodInfoStub)methodInfoStub);
var callback = s_unhandledExceptionPropagationHandler(exception, runtimeHandle, out context);
if (callback != null)
return callback;

return null;
}
}
}
18 changes: 18 additions & 0 deletions src/coreclr/System.Private.CoreLib/src/System/StubHelpers.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1229,6 +1229,24 @@ internal static Exception GetCOMHRExceptionObject(int hr, IntPtr pCPCMD, object

#endif // FEATURE_COMINTEROP

[ThreadStatic]
private static Exception? s_pendingExceptionObject;

internal static Exception? GetPendingExceptionObject()
{
Exception? ex = s_pendingExceptionObject;
if (ex != null)
ex.InternalPreserveStackTrace();

s_pendingExceptionObject = null;
return ex;
}

internal static void SetPendingExceptionObject(Exception? exception)
{
s_pendingExceptionObject = exception;
}

[MethodImpl(MethodImplOptions.InternalCall)]
internal static extern IntPtr CreateCustomMarshalerHelper(IntPtr pMD, int paramToken, IntPtr hndManagedType);

Expand Down
13 changes: 8 additions & 5 deletions src/coreclr/clrdefinitions.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -87,16 +87,11 @@ add_compile_definitions($<$<NOT:$<BOOL:$<TARGET_PROPERTY:CROSSGEN_COMPONENT>>>:F
add_definitions(-DFEATURE_COLLECTIBLE_TYPES)

if(CLR_CMAKE_TARGET_WIN32)
add_definitions(-DFEATURE_COMWRAPPERS)
add_definitions(-DFEATURE_COMINTEROP)
add_definitions(-DFEATURE_COMINTEROP_APARTMENT_SUPPORT)
add_definitions(-DFEATURE_COMINTEROP_UNMANAGED_ACTIVATION)
endif(CLR_CMAKE_TARGET_WIN32)

if(CLR_CMAKE_TARGET_OSX OR CLR_CMAKE_TARGET_MACCATALYST OR CLR_CMAKE_TARGET_IOS OR CLR_CMAKE_TARGET_TVOS)
add_definitions(-DFEATURE_OBJCMARSHAL)
endif(CLR_CMAKE_TARGET_OSX OR CLR_CMAKE_TARGET_MACCATALYST OR CLR_CMAKE_TARGET_IOS OR CLR_CMAKE_TARGET_TVOS)

add_definitions(-DFEATURE_BASICFREEZE)
add_definitions(-DFEATURE_CORECLR)
add_definitions(-DFEATURE_CORESYSTEM)
Expand Down Expand Up @@ -162,6 +157,14 @@ else()
add_compile_definitions($<$<BOOL:$<TARGET_PROPERTY:CROSSGEN_COMPONENT>>:FEATURE_PREJIT>)
endif(FEATURE_PREJIT)

if(FEATURE_COMWRAPPERS)
add_compile_definitions(FEATURE_COMWRAPPERS)
endif(FEATURE_COMWRAPPERS)

if(FEATURE_OBJCMARSHAL)
add_compile_definitions(FEATURE_OBJCMARSHAL)
endif()

add_compile_definitions($<$<AND:$<NOT:$<BOOL:$<TARGET_PROPERTY:CROSSGEN_COMPONENT>>>,$<NOT:$<BOOL:$<TARGET_PROPERTY:DAC_COMPONENT>>>>:FEATURE_PROFAPI_ATTACH_DETACH>)

add_definitions(-DFEATURE_READYTORUN)
Expand Down
8 changes: 8 additions & 0 deletions src/coreclr/clrfeatures.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -31,3 +31,11 @@ endif(NOT DEFINED FEATURE_AUTO_TRACE)
if(NOT DEFINED FEATURE_SINGLE_FILE_DIAGNOSTICS)
set(FEATURE_SINGLE_FILE_DIAGNOSTICS 1)
endif(NOT DEFINED FEATURE_SINGLE_FILE_DIAGNOSTICS)

if (CLR_CMAKE_TARGET_WIN32)
set(FEATURE_COMWRAPPERS 1)
endif()

if (CLR_CMAKE_TARGET_OSX OR CLR_CMAKE_TARGET_MACCATALYST OR CLR_CMAKE_TARGET_IOS OR CLR_CMAKE_TARGET_TVOS)
set(FEATURE_OBJCMARSHAL 1)
endif()
9 changes: 7 additions & 2 deletions src/coreclr/debug/daccess/daccess.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8156,9 +8156,10 @@ void DacHandleWalker::GetRefCountedHandleInfo(
if (pIsPegged)
*pIsPegged = FALSE;

#ifdef FEATURE_COMINTEROP
#if defined(FEATURE_COMINTEROP) || defined(FEATURE_COMWRAPPERS) || defined(FEATURE_OBJCMARSHAL)
if (uType == HNDTYPE_REFCOUNTED)
{
#if defined(FEATURE_COMINTEROP)
// get refcount from the CCW
PTR_ComCallWrapper pWrap = ComCallWrapper::GetWrapperForObject(oref);
if (pWrap != NULL)
Expand All @@ -8171,8 +8172,12 @@ void DacHandleWalker::GetRefCountedHandleInfo(

return;
}
#endif
#if defined(FEATURE_OBJCMARSHAL)
// [TODO] FEATURE_OBJCMARSHAL
#endif // FEATURE_OBJCMARSHAL
}
#endif // FEATURE_COMINTEROP
#endif // FEATURE_COMINTEROP || FEATURE_COMWRAPPERS || FEATURE_OBJCMARSHAL

if (pRefCount)
*pRefCount = 0;
Expand Down
14 changes: 8 additions & 6 deletions src/coreclr/debug/daccess/dacdbiimpl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7556,13 +7556,14 @@ UINT32 DacRefWalker::GetHandleWalkerMask()
if (mHandleMask & CorHandleWeakLong)
result |= (1 << HNDTYPE_WEAK_LONG);

#ifdef FEATURE_COMINTEROP
#if defined(FEATURE_COMINTEROP) || defined(FEATURE_COMWRAPPERS) || defined(FEATURE_OBJCMARSHAL)
if ((mHandleMask & CorHandleWeakRefCount) || (mHandleMask & CorHandleStrongRefCount))
result |= (1 << HNDTYPE_REFCOUNTED);

#endif // FEATURE_COMINTEROP || FEATURE_COMWRAPPERS || FEATURE_OBJCMARSHAL
#if defined(FEATURE_COMINTEROP) || defined(FEATURE_COMWRAPPERS)
if (mHandleMask & CorHandleWeakNativeCom)
result |= (1 << HNDTYPE_WEAK_NATIVE_COM);
#endif // FEATURE_COMINTEROP
#endif // FEATURE_COMINTEROP || FEATURE_COMWRAPPERS

if (mHandleMask & CorHandleStrongDependent)
result |= (1 << HNDTYPE_DEPENDENT);
Expand Down Expand Up @@ -7729,17 +7730,18 @@ void CALLBACK DacHandleWalker::EnumCallbackDac(PTR_UNCHECKED_OBJECTREF handle, u
data.dwType = (DWORD)CorHandleWeakLong;
break;

#ifdef FEATURE_COMINTEROP
#if defined(FEATURE_COMINTEROP) || defined(FEATURE_COMWRAPPERS) || defined(FEATURE_OBJCMARSHAL)
case HNDTYPE_REFCOUNTED:
data.dwType = (DWORD)(data.i64ExtraData ? CorHandleStrongRefCount : CorHandleWeakRefCount);
GetRefCountedHandleInfo((OBJECTREF)*handle, param->Type, &refCnt, NULL, NULL, NULL);
data.i64ExtraData = refCnt;
break;

#endif // FEATURE_COMINTEROP || FEATURE_COMWRAPPERS || FEATURE_OBJCMARSHAL
#if defined(FEATURE_COMINTEROP) || defined(FEATURE_COMWRAPPERS)
case HNDTYPE_WEAK_NATIVE_COM:
data.dwType = (DWORD)CorHandleWeakNativeCom;
break;
#endif
#endif // FEATURE_COMINTEROP || FEATURE_COMWRAPPERS

case HNDTYPE_DEPENDENT:
data.dwType = (DWORD)CorHandleStrongDependent;
Expand Down
2 changes: 1 addition & 1 deletion src/coreclr/debug/daccess/dacimpl.h
Original file line number Diff line number Diff line change
Expand Up @@ -1312,7 +1312,7 @@ class ClrDataAccess
HRESULT DumpManagedObject(CLRDataEnumMemoryFlags flags, OBJECTREF objRef);
HRESULT DumpManagedExcepObject(CLRDataEnumMemoryFlags flags, OBJECTREF objRef);
HRESULT DumpManagedStackTraceStringObject(CLRDataEnumMemoryFlags flags, STRINGREF orefStackTrace);
#ifdef FEATURE_COMINTEROP
#if defined(FEATURE_COMINTEROP) || defined(FEATURE_COMWRAPPERS)
HRESULT DumpStowedExceptionObject(CLRDataEnumMemoryFlags flags, CLRDATA_ADDRESS ccwPtr);
HRESULT EnumMemStowedException(CLRDataEnumMemoryFlags flags);
#endif
Expand Down
40 changes: 23 additions & 17 deletions src/coreclr/debug/daccess/request.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3282,9 +3282,12 @@ HRESULT ClrDataAccess::GetHandleEnum(ISOSHandleEnum **ppHandleEnum)
{
unsigned int types[] = {HNDTYPE_WEAK_SHORT, HNDTYPE_WEAK_LONG, HNDTYPE_STRONG, HNDTYPE_PINNED, HNDTYPE_VARIABLE, HNDTYPE_DEPENDENT,
HNDTYPE_ASYNCPINNED, HNDTYPE_SIZEDREF,
#ifdef FEATURE_COMINTEROP
HNDTYPE_REFCOUNTED, HNDTYPE_WEAK_NATIVE_COM
#endif
#if defined(FEATURE_COMINTEROP) || defined(FEATURE_COMWRAPPERS) || defined(FEATURE_OBJCMARSHAL)
HNDTYPE_REFCOUNTED,
#endif // FEATURE_COMINTEROP || FEATURE_COMWRAPPERS || FEATURE_OBJCMARSHAL
#if defined(FEATURE_COMINTEROP) || defined(FEATURE_COMWRAPPERS)
HNDTYPE_WEAK_NATIVE_COM
#endif // FEATURE_COMINTEROP
};

return GetHandleEnumForTypes(types, _countof(types), ppHandleEnum);
Expand Down Expand Up @@ -3320,9 +3323,12 @@ HRESULT ClrDataAccess::GetHandleEnumForGC(unsigned int gen, ISOSHandleEnum **ppH

unsigned int types[] = {HNDTYPE_WEAK_SHORT, HNDTYPE_WEAK_LONG, HNDTYPE_STRONG, HNDTYPE_PINNED, HNDTYPE_VARIABLE, HNDTYPE_DEPENDENT,
HNDTYPE_ASYNCPINNED, HNDTYPE_SIZEDREF,
#ifdef FEATURE_COMINTEROP
HNDTYPE_REFCOUNTED, HNDTYPE_WEAK_NATIVE_COM
#endif
#if defined(FEATURE_COMINTEROP) || defined(FEATURE_COMWRAPPERS) || defined(FEATURE_OBJCMARSHAL)
HNDTYPE_REFCOUNTED,
#endif // FEATURE_COMINTEROP || FEATURE_COMWRAPPERS || FEATURE_OBJCMARSHAL
#if defined(FEATURE_COMINTEROP) || defined(FEATURE_COMWRAPPERS)
HNDTYPE_WEAK_NATIVE_COM
#endif // FEATURE_COMINTEROP || FEATURE_COMWRAPPERS
};

DacHandleWalker *walker = new DacHandleWalker();
Expand Down Expand Up @@ -4849,7 +4855,7 @@ HRESULT ClrDataAccess::GetObjectComWrappersData(CLRDATA_ADDRESS objAddr, CLRDATA
{
comWrappers.Push(TO_CDADDR(iter->Value()));
++iter;

}
}

Expand Down Expand Up @@ -4885,7 +4891,7 @@ HRESULT ClrDataAccess::GetObjectComWrappersData(CLRDATA_ADDRESS objAddr, CLRDATA
return E_NOTIMPL;
#endif // FEATURE_COMWRAPPERS
}

HRESULT ClrDataAccess::IsComWrappersCCW(CLRDATA_ADDRESS ccw, BOOL *isComWrappersCCW)
{
#ifdef FEATURE_COMWRAPPERS
Expand All @@ -4895,12 +4901,12 @@ HRESULT ClrDataAccess::IsComWrappersCCW(CLRDATA_ADDRESS ccw, BOOL *isComWrappers
}

SOSDacEnter();

if (isComWrappersCCW != NULL)
{
TADDR managedObjectWrapperPtr = DACGetManagedObjectWrapperFromCCW(ccw);
*isComWrappersCCW = managedObjectWrapperPtr != NULL;
hr = *isComWrappersCCW ? S_OK : S_FALSE;
hr = *isComWrappersCCW ? S_OK : S_FALSE;
}

SOSDacLeave();
Expand All @@ -4919,12 +4925,12 @@ HRESULT ClrDataAccess::GetComWrappersCCWData(CLRDATA_ADDRESS ccw, CLRDATA_ADDRES
}

SOSDacEnter();

TADDR managedObjectWrapperPtr = DACGetManagedObjectWrapperFromCCW(ccw);
if (managedObjectWrapperPtr != NULL)
{
PTR_ManagedObjectWrapper pMOW(managedObjectWrapperPtr);

if (managedObject != NULL)
{
OBJECTREF managedObjectRef;
Expand Down Expand Up @@ -4965,7 +4971,7 @@ HRESULT ClrDataAccess::IsComWrappersRCW(CLRDATA_ADDRESS rcw, BOOL *isComWrappers
}

SOSDacEnter();

if (isComWrappersRCW != NULL)
{
PTR_ExternalObjectContext pRCW(TO_TADDR(rcw));
Expand All @@ -4988,7 +4994,7 @@ HRESULT ClrDataAccess::IsComWrappersRCW(CLRDATA_ADDRESS rcw, BOOL *isComWrappers

PTR_InteropSyncBlockInfo pInfo = NULL;
if (stillValid)
{
{
pInfo = pSyncBlk->GetInteropInfoNoCreate();
if(pInfo == NULL)
{
Expand All @@ -5002,11 +5008,11 @@ HRESULT ClrDataAccess::IsComWrappersRCW(CLRDATA_ADDRESS rcw, BOOL *isComWrappers
}

*isComWrappersRCW = stillValid;
hr = *isComWrappersRCW ? S_OK : S_FALSE;
hr = *isComWrappersRCW ? S_OK : S_FALSE;
}

SOSDacLeave();
return hr;
return hr;
#else // FEATURE_COMWRAPPERS
return E_NOTIMPL;
#endif // FEATURE_COMWRAPPERS
Expand All @@ -5021,7 +5027,7 @@ HRESULT ClrDataAccess::GetComWrappersRCWData(CLRDATA_ADDRESS rcw, CLRDATA_ADDRES
}

SOSDacEnter();

PTR_ExternalObjectContext pEOC(TO_TADDR(rcw));
if (identity != NULL)
{
Expand Down
2 changes: 1 addition & 1 deletion src/coreclr/dlls/mscoree/unixinterface.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -223,7 +223,7 @@ int coreclr_initialize(

if (pinvokeOverride != nullptr)
{
PInvokeOverride::SetPInvokeOverride(pinvokeOverride);
PInvokeOverride::SetPInvokeOverride(pinvokeOverride, PInvokeOverride::Source::RuntimeConfiguration);
}

ReleaseHolder<ICLRRuntimeHost4> host;
Expand Down
6 changes: 3 additions & 3 deletions src/coreclr/gc/env/gcenv.ee.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,13 +26,13 @@ class GCToEEInterface
// start of GC call back - single threaded
static void GcStartWork(int condemned, int max_gen);

// Called before scanning roots
static void BeforeGcScanRoots(int condemned, bool is_bgc, bool is_concurrent);

//EE can perform post stack scanning action, while the
// user threads are still suspended
static void AfterGcScanRoots(int condemned, int max_gen, ScanContext* sc);

// Called before BGC starts sweeping, the heap is walkable
static void GcBeforeBGCSweepWork();

// post-gc callback.
static void GcDone(int condemned);

Expand Down
6 changes: 3 additions & 3 deletions src/coreclr/gc/gc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23683,6 +23683,7 @@ void gc_heap::mark_phase (int condemned_gen_number, BOOL mark_only_p)
grow_mark_list_piece();
#endif //USE_REGIONS

GCToEEInterface::BeforeGcScanRoots(condemned_gen_number, /* is_bgc */ false, /* is_concurrent */ false);
num_sizedrefs = GCToEEInterface::GetTotalNumSizedRefHandles();

#ifdef MULTIPLE_HEAPS
Expand Down Expand Up @@ -31731,15 +31732,14 @@ void gc_heap::background_mark_phase ()
bgc_tuning::record_bgc_sweep_start();
#endif //BGC_SERVO_TUNING

GCToEEInterface::BeforeGcScanRoots(max_generation, /* is_bgc */ true, /* is_concurrent */ false);

#ifdef MULTIPLE_HEAPS
dprintf(3, ("Joining BGC threads after absorb"));
bgc_t_join.restart();
#endif //MULTIPLE_HEAPS
}

// give VM a chance to do work
GCToEEInterface::GcBeforeBGCSweepWork();

//reset the flag, indicating that the EE no longer expect concurrent
//marking
sc.concurrent = FALSE;
Expand Down
Loading

0 comments on commit c1e7ca8

Please sign in to comment.