Skip to content

Commit 1562a55

Browse files
committed
Implement GC bridge in NativeAOT
1 parent a436284 commit 1562a55

File tree

16 files changed

+343
-34
lines changed

16 files changed

+343
-34
lines changed

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -223,6 +223,7 @@
223223
<Compile Include="$(BclSourcesRoot)\System\Runtime\InteropServices\Marshal.CoreCLR.cs" />
224224
<Compile Include="$(BclSourcesRoot)\System\Runtime\InteropServices\MemoryMarshal.CoreCLR.cs" />
225225
<Compile Include="$(BclSourcesRoot)\System\Runtime\InteropServices\NativeLibrary.CoreCLR.cs" />
226+
<Compile Include="$(BclSourcesRoot)\System\Runtime\InteropServices\Java\JavaMarshal.CoreCLR.cs" Condition="'$(FeatureJavaMarshal)' == 'true'" />
226227
<Compile Include="$(BclSourcesRoot)\System\Runtime\Intrinsics\X86\X86Base.CoreCLR.cs" />
227228
<Compile Include="$(BclSourcesRoot)\System\Runtime\Loader\AssemblyLoadContext.CoreCLR.cs" />
228229
<Compile Include="$(BclSourcesRoot)\System\RuntimeArgumentHandle.cs" />

src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/Java/JavaMarshal.cs renamed to src/coreclr/System.Private.CoreLib/src/System/Runtime/InteropServices/Java/JavaMarshal.CoreCLR.cs

Lines changed: 0 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -12,39 +12,24 @@ public static partial class JavaMarshal
1212
{
1313
public static unsafe void Initialize(delegate* unmanaged<MarkCrossReferencesArgs*, void> markCrossReferences)
1414
{
15-
#if NATIVEAOT
16-
throw new NotImplementedException();
17-
#elif FEATURE_JAVAMARSHAL
1815
ArgumentNullException.ThrowIfNull(markCrossReferences);
1916

2017
if (!InitializeInternal((IntPtr)markCrossReferences))
2118
{
2219
throw new InvalidOperationException(SR.InvalidOperation_ReinitializeJavaMarshal);
2320
}
24-
#else
25-
throw new PlatformNotSupportedException();
26-
#endif
2721
}
2822

2923
public static unsafe GCHandle CreateReferenceTrackingHandle(object obj, void* context)
3024
{
31-
#if NATIVEAOT
32-
throw new NotImplementedException();
33-
#elif FEATURE_JAVAMARSHAL
3425
ArgumentNullException.ThrowIfNull(obj);
3526

3627
IntPtr handle = CreateReferenceTrackingHandleInternal(ObjectHandleOnStack.Create(ref obj), context);
3728
return GCHandle.FromIntPtr(handle);
38-
#else
39-
throw new PlatformNotSupportedException();
40-
#endif
4129
}
4230

4331
public static unsafe void* GetContext(GCHandle obj)
4432
{
45-
#if NATIVEAOT
46-
throw new NotImplementedException();
47-
#elif FEATURE_JAVAMARSHAL
4833
IntPtr handle = GCHandle.ToIntPtr(obj);
4934
if (handle == IntPtr.Zero
5035
|| !GetContextInternal(handle, out void* context))
@@ -53,31 +38,21 @@ public static unsafe GCHandle CreateReferenceTrackingHandle(object obj, void* co
5338
}
5439

5540
return context;
56-
#else
57-
throw new PlatformNotSupportedException();
58-
#endif
5941
}
6042

6143
public static unsafe void FinishCrossReferenceProcessing(
6244
MarkCrossReferencesArgs* crossReferences,
6345
ReadOnlySpan<GCHandle> unreachableObjectHandles)
6446
{
65-
#if NATIVEAOT
66-
throw new NotImplementedException();
67-
#elif FEATURE_JAVAMARSHAL
6847
fixed (GCHandle* pHandles = unreachableObjectHandles)
6948
{
7049
FinishCrossReferenceProcessing(
7150
crossReferences,
7251
(nuint)unreachableObjectHandles.Length,
7352
pHandles);
7453
}
75-
#else
76-
throw new PlatformNotSupportedException();
77-
#endif
7854
}
7955

80-
#if FEATURE_JAVAMARSHAL && !NATIVEAOT
8156
[LibraryImport(RuntimeHelpers.QCall, EntryPoint = "JavaMarshal_Initialize")]
8257
[return: MarshalAs(UnmanagedType.Bool)]
8358
private static partial bool InitializeInternal(IntPtr callback);
@@ -92,6 +67,5 @@ public static unsafe void FinishCrossReferenceProcessing(
9267
[SuppressGCTransition]
9368
[return: MarshalAs(UnmanagedType.Bool)]
9469
private static unsafe partial bool GetContextInternal(IntPtr handle, out void* context);
95-
#endif
9670
}
9771
}

src/coreclr/nativeaot/CMakeLists.txt

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,14 @@ endif (CLR_CMAKE_HOST_UNIX)
3030

3131
if(CLR_CMAKE_TARGET_ANDROID)
3232
add_definitions(-DFEATURE_EMULATED_TLS)
33+
set(FEATURE_JAVAMARSHAL 1)
3334
endif()
3435

36+
if(NOT DEFINED FEATURE_JAVAMARSHAL)
37+
set(FEATURE_JAVAMARSHAL $<IF:$<CONFIG:Debug,Checked>,1,0>)
38+
endif()
39+
40+
add_compile_definitions($<${FEATURE_JAVAMARSHAL}:FEATURE_JAVAMARSHAL>)
41+
3542
add_subdirectory(Bootstrap)
3643
add_subdirectory(Runtime)

src/coreclr/nativeaot/Runtime/CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ set(COMMON_RUNTIME_SOURCES
2020
gcenv.ee.cpp
2121
GcStressControl.cpp
2222
HandleTableHelpers.cpp
23+
interoplibinterface_java.cpp
2324
MathHelpers.cpp
2425
MiscHelpers.cpp
2526
TypeManager.cpp
@@ -38,6 +39,7 @@ set(COMMON_RUNTIME_SOURCES
3839
yieldprocessornormalized.cpp
3940

4041
${GC_DIR}/gceventstatus.cpp
42+
${GC_DIR}/gcbridge.cpp
4143
${GC_DIR}/gcload.cpp
4244
${GC_DIR}/gcconfig.cpp
4345
${GC_DIR}/gchandletable.cpp

src/coreclr/nativeaot/Runtime/HandleTableHelpers.cpp

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
#include "objecthandle.h"
77
#include "RestrictedCallouts.h"
88
#include "gchandleutilities.h"
9+
#include "interoplibinterface.h"
910

1011

1112
FCIMPL2(OBJECTHANDLE, RhpHandleAlloc, Object *pObject, int type)
@@ -64,6 +65,27 @@ FCIMPL2(void, RhUnregisterRefCountedHandleCallback, void * pCallout, MethodTable
6465
}
6566
FCIMPLEND
6667

68+
FCIMPL2(OBJECTHANDLE, RhpHandleAllocCrossReference, Object *pPrimary, void *pContext)
69+
{
70+
return GCHandleUtilities::GetGCHandleManager()->GetGlobalHandleStore()->CreateHandleWithExtraInfo(pPrimary, HNDTYPE_CROSSREFERENCE, pContext);
71+
}
72+
FCIMPLEND
73+
74+
FCIMPL2(FC_BOOL_RET, RhHandleTryGetCrossReferenceContext, OBJECTHANDLE handle, void **pContext)
75+
{
76+
*pContext = nullptr;
77+
78+
IGCHandleManager* gcHandleManager = GCHandleUtilities::GetGCHandleManager();
79+
if (gcHandleManager->HandleFetchType(handle) != HNDTYPE_CROSSREFERENCE)
80+
{
81+
FC_RETURN_BOOL(false);
82+
}
83+
84+
*pContext = gcHandleManager->GetExtraInfoFromHandle(handle);
85+
FC_RETURN_BOOL(true);
86+
}
87+
FCIMPLEND
88+
6789
// This structure mirrors the managed type System.Runtime.InteropServices.ComWrappers.ManagedObjectWrapper.
6890
struct ManagedObjectWrapper
6991
{

src/coreclr/nativeaot/Runtime/gcenv.ee.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -809,4 +809,11 @@ void GCToEEInterface::FreeStringConfigValue(const char* value)
809809
delete[] value;
810810
}
811811

812+
void GCToEEInterface::TriggerClientBridgeProcessing(MarkCrossReferencesArgs* args)
813+
{
814+
#ifdef FEATURE_JAVAMARSHAL
815+
JavaMarshalNative::TriggerClientBridgeProcessing(args);
816+
#endif
817+
}
818+
812819
#endif // !DACCESS_COMPILE

src/coreclr/nativeaot/Runtime/interoplibinterface.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,3 +22,15 @@ class ObjCMarshalNative
2222
};
2323

2424
#endif // FEATURE_OBJCMARSHAL
25+
26+
#ifdef FEATURE_JAVAMARSHAL
27+
28+
struct MarkCrossReferencesArgs;
29+
30+
class JavaMarshalNative
31+
{
32+
public:
33+
static void TriggerClientBridgeProcessing(
34+
MarkCrossReferencesArgs* args);
35+
};
36+
#endif
Lines changed: 157 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,157 @@
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+
#ifdef FEATURE_JAVAMARSHAL
5+
6+
// Runtime headers
7+
#include "common.h"
8+
#include "gcenv.h"
9+
#include "gcenv.ee.h"
10+
#include "gcheaputilities.h"
11+
#include "gchandleutilities.h"
12+
#include "thread.h"
13+
#include "threadstore.h"
14+
#include "threadstore.inl"
15+
#include "event.h"
16+
17+
#include "interoplibinterface.h"
18+
19+
using CrossreferenceHandleCallback = void(__stdcall *)(MarkCrossReferencesArgs*);
20+
21+
namespace
22+
{
23+
volatile CrossreferenceHandleCallback g_MarkCrossReferences = NULL;
24+
25+
Volatile<bool> g_GCBridgeActive = false;
26+
CLREventStatic g_bridgeFinished;
27+
28+
void ReleaseGCBridgeArgumentsWorker(
29+
MarkCrossReferencesArgs* args)
30+
{
31+
// Memory was allocated for the collections by the GC.
32+
// See callers of GCToEEInterface::TriggerGCBridge().
33+
34+
// Free memory in each of the SCCs
35+
for (size_t i = 0; i < args->ComponentCount; i++)
36+
{
37+
delete[] args->Components[i].Contexts;
38+
}
39+
delete[] args->Components;
40+
delete[] args->CrossReferences;
41+
delete args;
42+
}
43+
}
44+
45+
void JavaMarshalNative::TriggerClientBridgeProcessing(
46+
_In_ MarkCrossReferencesArgs* args)
47+
{
48+
_ASSERTE(GCHeapUtilities::IsGCInProgress());
49+
50+
if (g_GCBridgeActive)
51+
{
52+
// Release the memory allocated since the GCBridge
53+
// is already running and we're not passing them to it.
54+
ReleaseGCBridgeArgumentsWorker(args);
55+
return;
56+
}
57+
58+
bool gcBridgeTriggered = false;
59+
// Not initialized
60+
if (g_MarkCrossReferences != NULL)
61+
{
62+
g_MarkCrossReferences(args);
63+
gcBridgeTriggered = true;
64+
}
65+
66+
if (!gcBridgeTriggered)
67+
{
68+
// Release the memory allocated since the GCBridge
69+
// wasn't trigger for some reason.
70+
ReleaseGCBridgeArgumentsWorker(args);
71+
return;
72+
}
73+
74+
// This runs during GC while the world is stopped, no synchronisation required
75+
g_bridgeFinished.Reset();
76+
77+
// Mark the GCBridge as active.
78+
g_GCBridgeActive = true;
79+
}
80+
81+
extern "C" BOOL QCALLTYPE JavaMarshal_Initialize(
82+
void* markCrossReferences)
83+
{
84+
_ASSERTE(markCrossReferences != NULL);
85+
86+
BOOL success = FALSE;
87+
88+
89+
// Switch to Cooperative mode since we are setting callbacks that
90+
// will be used during a GC and we want to ensure a GC isn't occurring
91+
// while they are being set.
92+
{
93+
bool wasCooperative = false;
94+
Thread* pThisThread = ThreadStore::GetCurrentThreadIfAvailable();
95+
pThisThread->DeferTransitionFrame();
96+
pThisThread->DisablePreemptiveMode();
97+
98+
if (PalInterlockedCompareExchangePointer((void* volatile*)&g_MarkCrossReferences, (void*)markCrossReferences, NULL) == NULL)
99+
{
100+
success = g_bridgeFinished.CreateManualEventNoThrow(false);
101+
}
102+
103+
pThisThread->EnablePreemptiveMode();
104+
}
105+
106+
return success;
107+
}
108+
109+
extern "C" void QCALLTYPE JavaMarshal_FinishCrossReferenceProcessing(
110+
MarkCrossReferencesArgs *crossReferences,
111+
size_t length,
112+
void* unreachableObjectHandles)
113+
{
114+
_ASSERTE(crossReferences->ComponentCount >= 0);
115+
116+
_ASSERTE(g_GCBridgeActive);
117+
118+
// Mark the GCBridge as inactive.
119+
// This must be synchronized with the GC so switch to cooperative mode.
120+
{
121+
bool wasCooperative = false;
122+
Thread* pThisThread = ThreadStore::GetCurrentThreadIfAvailable();
123+
pThisThread->DeferTransitionFrame();
124+
pThisThread->DisablePreemptiveMode();
125+
126+
GCHeapUtilities::GetGCHeap()->NullBridgeObjectsWeakRefs(length, unreachableObjectHandles);
127+
128+
IGCHandleManager* pHandleManager = GCHandleUtilities::GetGCHandleManager();
129+
for (size_t i = 0; i < length; i++)
130+
pHandleManager->DestroyHandleOfUnknownType(((OBJECTHANDLE*)unreachableObjectHandles)[i]);
131+
132+
g_GCBridgeActive = false;
133+
g_bridgeFinished.Set();
134+
135+
pThisThread->EnablePreemptiveMode();
136+
}
137+
138+
ReleaseGCBridgeArgumentsWorker(crossReferences);
139+
}
140+
141+
FCIMPL0(FC_BOOL_RET, RhIsGCBridgeActive)
142+
{
143+
FC_RETURN_BOOL(g_GCBridgeActive);
144+
}
145+
FCIMPLEND
146+
147+
extern "C" void QCALLTYPE JavaMarshal_WaitForGCBridgeFinish()
148+
{
149+
// We will transition to pre-emptive mode to wait for the bridge to finish.
150+
Thread* pThisThread = ThreadStore::GetCurrentThreadIfAvailable();
151+
while (g_GCBridgeActive)
152+
{
153+
g_bridgeFinished.Wait(INFINITE, false, false);
154+
}
155+
}
156+
157+
#endif // FEATURE_JAVAMARSHAL

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
@@ -159,6 +159,7 @@
159159
<Compile Include="System\CrashInfo.cs" />
160160
<Compile Include="System\Runtime\InteropServices\ComAwareWeakReference.NativeAot.cs" />
161161
<Compile Include="System\Runtime\InteropServices\CriticalHandle.NativeAot.cs" />
162+
<Compile Include="System\Runtime\InteropServices\Java\JavaMarshal.NativeAot.cs" Condition="'$(FeatureJavaMarshal)' == 'true'" />
162163
<Compile Include="System\Activator.NativeAot.cs" />
163164
<Compile Include="System\AppContext.NativeAot.cs" />
164165
<Compile Include="System\ArgIterator.cs" />

src/coreclr/nativeaot/System.Private.CoreLib/src/System/Runtime/InteropServices/GCHandle.NativeAot.cs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
// Licensed to the .NET Foundation under one or more agreements.
22
// The .NET Foundation licenses this file to you under the MIT license.
33

4+
using System.Runtime.InteropServices.Java;
5+
46
namespace System.Runtime.InteropServices
57
{
68
public partial struct GCHandle
@@ -14,9 +16,14 @@ public partial struct GCHandle
1416
internal static void InternalSet(IntPtr handle, object? value) => RuntimeImports.RhHandleSet(handle, value);
1517

1618
#if FEATURE_JAVAMARSHAL
17-
// FIXME implement waiting for bridge processing
1819
internal static object? InternalGetBridgeWait(IntPtr handle)
1920
{
21+
if (RuntimeImports.RhIsGCBridgeActive())
22+
{
23+
#pragma warning disable CA1416 // Validate platform compatibility
24+
JavaMarshal.WaitForGCBridgeFinish();
25+
#pragma warning restore CA1416 // Validate platform compatibility
26+
}
2027
return InternalGet(handle);
2128
}
2229
#endif

0 commit comments

Comments
 (0)