diff --git a/src/coreclr/System.Private.CoreLib/System.Private.CoreLib.csproj b/src/coreclr/System.Private.CoreLib/System.Private.CoreLib.csproj
index 2fb4c3e7ffa6bb..c12d6c854ac0c0 100644
--- a/src/coreclr/System.Private.CoreLib/System.Private.CoreLib.csproj
+++ b/src/coreclr/System.Private.CoreLib/System.Private.CoreLib.csproj
@@ -223,6 +223,7 @@
+
diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/Java/JavaMarshal.cs b/src/coreclr/System.Private.CoreLib/src/System/Runtime/InteropServices/Java/JavaMarshal.CoreCLR.cs
similarity index 81%
rename from src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/Java/JavaMarshal.cs
rename to src/coreclr/System.Private.CoreLib/src/System/Runtime/InteropServices/Java/JavaMarshal.CoreCLR.cs
index 42f3b023a4803c..357e3575812e5c 100644
--- a/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/Java/JavaMarshal.cs
+++ b/src/coreclr/System.Private.CoreLib/src/System/Runtime/InteropServices/Java/JavaMarshal.CoreCLR.cs
@@ -12,39 +12,24 @@ public static partial class JavaMarshal
{
public static unsafe void Initialize(delegate* unmanaged markCrossReferences)
{
-#if NATIVEAOT
- throw new NotImplementedException();
-#elif FEATURE_JAVAMARSHAL
ArgumentNullException.ThrowIfNull(markCrossReferences);
if (!InitializeInternal((IntPtr)markCrossReferences))
{
throw new InvalidOperationException(SR.InvalidOperation_ReinitializeJavaMarshal);
}
-#else
- throw new PlatformNotSupportedException();
-#endif
}
public static unsafe GCHandle CreateReferenceTrackingHandle(object obj, void* context)
{
-#if NATIVEAOT
- throw new NotImplementedException();
-#elif FEATURE_JAVAMARSHAL
ArgumentNullException.ThrowIfNull(obj);
IntPtr handle = CreateReferenceTrackingHandleInternal(ObjectHandleOnStack.Create(ref obj), context);
return GCHandle.FromIntPtr(handle);
-#else
- throw new PlatformNotSupportedException();
-#endif
}
public static unsafe void* GetContext(GCHandle obj)
{
-#if NATIVEAOT
- throw new NotImplementedException();
-#elif FEATURE_JAVAMARSHAL
IntPtr handle = GCHandle.ToIntPtr(obj);
if (handle == IntPtr.Zero
|| !GetContextInternal(handle, out void* context))
@@ -53,18 +38,12 @@ public static unsafe GCHandle CreateReferenceTrackingHandle(object obj, void* co
}
return context;
-#else
- throw new PlatformNotSupportedException();
-#endif
}
public static unsafe void FinishCrossReferenceProcessing(
MarkCrossReferencesArgs* crossReferences,
ReadOnlySpan unreachableObjectHandles)
{
-#if NATIVEAOT
- throw new NotImplementedException();
-#elif FEATURE_JAVAMARSHAL
fixed (GCHandle* pHandles = unreachableObjectHandles)
{
FinishCrossReferenceProcessing(
@@ -72,12 +51,8 @@ public static unsafe void FinishCrossReferenceProcessing(
(nuint)unreachableObjectHandles.Length,
pHandles);
}
-#else
- throw new PlatformNotSupportedException();
-#endif
}
-#if FEATURE_JAVAMARSHAL && !NATIVEAOT
[LibraryImport(RuntimeHelpers.QCall, EntryPoint = "JavaMarshal_Initialize")]
[return: MarshalAs(UnmanagedType.Bool)]
private static partial bool InitializeInternal(IntPtr callback);
@@ -92,6 +67,5 @@ public static unsafe void FinishCrossReferenceProcessing(
[SuppressGCTransition]
[return: MarshalAs(UnmanagedType.Bool)]
private static unsafe partial bool GetContextInternal(IntPtr handle, out void* context);
-#endif
}
}
diff --git a/src/coreclr/nativeaot/CMakeLists.txt b/src/coreclr/nativeaot/CMakeLists.txt
index e1c43480500970..3aaa04c774c20f 100644
--- a/src/coreclr/nativeaot/CMakeLists.txt
+++ b/src/coreclr/nativeaot/CMakeLists.txt
@@ -30,7 +30,14 @@ endif (CLR_CMAKE_HOST_UNIX)
if(CLR_CMAKE_TARGET_ANDROID)
add_definitions(-DFEATURE_EMULATED_TLS)
+ set(FEATURE_JAVAMARSHAL 1)
endif()
+if(NOT DEFINED FEATURE_JAVAMARSHAL)
+ set(FEATURE_JAVAMARSHAL $,1,0>)
+endif()
+
+add_compile_definitions($<${FEATURE_JAVAMARSHAL}:FEATURE_JAVAMARSHAL>)
+
add_subdirectory(Bootstrap)
add_subdirectory(Runtime)
diff --git a/src/coreclr/nativeaot/Runtime/CMakeLists.txt b/src/coreclr/nativeaot/Runtime/CMakeLists.txt
index c6a19f9b9bf023..61ed486a7989c8 100644
--- a/src/coreclr/nativeaot/Runtime/CMakeLists.txt
+++ b/src/coreclr/nativeaot/Runtime/CMakeLists.txt
@@ -20,6 +20,7 @@ set(COMMON_RUNTIME_SOURCES
gcenv.ee.cpp
GcStressControl.cpp
HandleTableHelpers.cpp
+ interoplibinterface_java.cpp
MathHelpers.cpp
MiscHelpers.cpp
TypeManager.cpp
@@ -38,6 +39,7 @@ set(COMMON_RUNTIME_SOURCES
yieldprocessornormalized.cpp
${GC_DIR}/gceventstatus.cpp
+ ${GC_DIR}/gcbridge.cpp
${GC_DIR}/gcload.cpp
${GC_DIR}/gcconfig.cpp
${GC_DIR}/gchandletable.cpp
diff --git a/src/coreclr/nativeaot/Runtime/HandleTableHelpers.cpp b/src/coreclr/nativeaot/Runtime/HandleTableHelpers.cpp
index 91750c078e4539..7cf154d29c0cb3 100644
--- a/src/coreclr/nativeaot/Runtime/HandleTableHelpers.cpp
+++ b/src/coreclr/nativeaot/Runtime/HandleTableHelpers.cpp
@@ -6,6 +6,7 @@
#include "objecthandle.h"
#include "RestrictedCallouts.h"
#include "gchandleutilities.h"
+#include "interoplibinterface.h"
FCIMPL2(OBJECTHANDLE, RhpHandleAlloc, Object *pObject, int type)
@@ -64,6 +65,27 @@ FCIMPL2(void, RhUnregisterRefCountedHandleCallback, void * pCallout, MethodTable
}
FCIMPLEND
+FCIMPL2(OBJECTHANDLE, RhpHandleAllocCrossReference, Object *pPrimary, void *pContext)
+{
+ return GCHandleUtilities::GetGCHandleManager()->GetGlobalHandleStore()->CreateHandleWithExtraInfo(pPrimary, HNDTYPE_CROSSREFERENCE, pContext);
+}
+FCIMPLEND
+
+FCIMPL2(FC_BOOL_RET, RhHandleTryGetCrossReferenceContext, OBJECTHANDLE handle, void **pContext)
+{
+ *pContext = nullptr;
+
+ IGCHandleManager* gcHandleManager = GCHandleUtilities::GetGCHandleManager();
+ if (gcHandleManager->HandleFetchType(handle) != HNDTYPE_CROSSREFERENCE)
+ {
+ FC_RETURN_BOOL(false);
+ }
+
+ *pContext = gcHandleManager->GetExtraInfoFromHandle(handle);
+ FC_RETURN_BOOL(true);
+}
+FCIMPLEND
+
// This structure mirrors the managed type System.Runtime.InteropServices.ComWrappers.ManagedObjectWrapper.
struct ManagedObjectWrapper
{
diff --git a/src/coreclr/nativeaot/Runtime/gcenv.ee.cpp b/src/coreclr/nativeaot/Runtime/gcenv.ee.cpp
index 9285e676354434..e2c31db91e328b 100644
--- a/src/coreclr/nativeaot/Runtime/gcenv.ee.cpp
+++ b/src/coreclr/nativeaot/Runtime/gcenv.ee.cpp
@@ -809,4 +809,11 @@ void GCToEEInterface::FreeStringConfigValue(const char* value)
delete[] value;
}
+void GCToEEInterface::TriggerClientBridgeProcessing(MarkCrossReferencesArgs* args)
+{
+#ifdef FEATURE_JAVAMARSHAL
+ JavaMarshalNative::TriggerClientBridgeProcessing(args);
+#endif
+}
+
#endif // !DACCESS_COMPILE
diff --git a/src/coreclr/nativeaot/Runtime/interoplibinterface.h b/src/coreclr/nativeaot/Runtime/interoplibinterface.h
index fce04b81f90249..c89281d152d8cc 100644
--- a/src/coreclr/nativeaot/Runtime/interoplibinterface.h
+++ b/src/coreclr/nativeaot/Runtime/interoplibinterface.h
@@ -22,3 +22,15 @@ class ObjCMarshalNative
};
#endif // FEATURE_OBJCMARSHAL
+
+#ifdef FEATURE_JAVAMARSHAL
+
+struct MarkCrossReferencesArgs;
+
+class JavaMarshalNative
+{
+public:
+ static void TriggerClientBridgeProcessing(
+ MarkCrossReferencesArgs* args);
+};
+#endif // FEATURE_JAVAMARSHAL
diff --git a/src/coreclr/nativeaot/Runtime/interoplibinterface_java.cpp b/src/coreclr/nativeaot/Runtime/interoplibinterface_java.cpp
new file mode 100644
index 00000000000000..78a65ca93ecd6a
--- /dev/null
+++ b/src/coreclr/nativeaot/Runtime/interoplibinterface_java.cpp
@@ -0,0 +1,173 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+#ifdef FEATURE_JAVAMARSHAL
+
+// Runtime headers
+#include "common.h"
+#include "gcenv.h"
+#include "gcenv.ee.h"
+#include "gcheaputilities.h"
+#include "gchandleutilities.h"
+#include "thread.h"
+#include "threadstore.h"
+#include "threadstore.inl"
+#include "event.h"
+
+#include "interoplibinterface.h"
+
+using CrossreferenceHandleCallback = void(__stdcall *)(MarkCrossReferencesArgs*);
+
+namespace
+{
+ volatile CrossreferenceHandleCallback g_MarkCrossReferences = NULL;
+
+ Volatile g_GCBridgeActive = false;
+ CLREventStatic g_bridgeFinished;
+
+ void ReleaseGCBridgeArgumentsWorker(
+ MarkCrossReferencesArgs* args)
+ {
+ _ASSERTE(args != NULL);
+
+ // Memory was allocated for the collections by the GC.
+ // See callers of GCToEEInterface::TriggerGCBridge().
+
+ // Free memory in each of the SCCs
+ for (size_t i = 0; i < args->ComponentCount; i++)
+ {
+ delete[] args->Components[i].Contexts;
+ }
+ delete[] args->Components;
+ delete[] args->CrossReferences;
+ delete args;
+ }
+}
+
+void JavaMarshalNative::TriggerClientBridgeProcessing(
+ _In_ MarkCrossReferencesArgs* args)
+{
+ _ASSERTE(GCHeapUtilities::IsGCInProgress());
+
+ if (g_GCBridgeActive)
+ {
+ // Release the memory allocated since the GCBridge
+ // is already running and we're not passing them to it.
+ ReleaseGCBridgeArgumentsWorker(args);
+ return;
+ }
+
+ // Not initialized
+ if (g_MarkCrossReferences == NULL)
+ {
+ // Release the memory allocated since we
+ // don't have a GC bridge callback.
+ ReleaseGCBridgeArgumentsWorker(args);
+ return;
+ }
+
+ g_MarkCrossReferences(args);
+
+ // This runs during GC while the world is stopped, no synchronisation required
+ g_bridgeFinished.Reset();
+
+ // Mark the GCBridge as active.
+ g_GCBridgeActive = true;
+}
+
+extern "C" BOOL QCALLTYPE JavaMarshal_Initialize(
+ void* markCrossReferences)
+{
+ _ASSERTE(markCrossReferences != NULL);
+
+ BOOL success = FALSE;
+
+ // Switch to Cooperative mode since we are setting callbacks that
+ // will be used during a GC and we want to ensure a GC isn't occurring
+ // while they are being set.
+ Thread* pThisThread = ThreadStore::GetCurrentThreadIfAvailable();
+ pThisThread->DeferTransitionFrame();
+ pThisThread->DisablePreemptiveMode();
+
+ if (PalInterlockedCompareExchangePointer((void* volatile*)&g_MarkCrossReferences, (void*)markCrossReferences, NULL) == NULL)
+ {
+ success = g_bridgeFinished.CreateManualEventNoThrow(false);
+ }
+
+ pThisThread->EnablePreemptiveMode();
+
+ return success;
+}
+
+extern "C" void QCALLTYPE JavaMarshal_FinishCrossReferenceProcessing(
+ MarkCrossReferencesArgs *crossReferences,
+ size_t length,
+ void* unreachableObjectHandles)
+{
+ _ASSERTE(crossReferences->ComponentCount >= 0);
+
+ _ASSERTE(g_GCBridgeActive);
+
+ // Mark the GCBridge as inactive.
+ // This must be synchronized with the GC so switch to cooperative mode.
+ {
+ Thread* pThisThread = ThreadStore::GetCurrentThreadIfAvailable();
+ pThisThread->DeferTransitionFrame();
+ pThisThread->DisablePreemptiveMode();
+
+ GCHeapUtilities::GetGCHeap()->NullBridgeObjectsWeakRefs(length, unreachableObjectHandles);
+
+ IGCHandleManager* pHandleManager = GCHandleUtilities::GetGCHandleManager();
+ OBJECTHANDLE* handles = (OBJECTHANDLE*)unreachableObjectHandles;
+ for (size_t i = 0; i < length; i++)
+ pHandleManager->DestroyHandleOfUnknownType(handles[i]);
+
+ g_GCBridgeActive = false;
+ g_bridgeFinished.Set();
+
+ pThisThread->EnablePreemptiveMode();
+ }
+
+ ReleaseGCBridgeArgumentsWorker(crossReferences);
+}
+
+FCIMPL2(FC_BOOL_RET, GCHandle_InternalTryGetBridgeWait, OBJECTHANDLE handle, OBJECTREF* pObjResult)
+{
+ if (g_GCBridgeActive)
+ {
+ FC_RETURN_BOOL(false);
+ }
+
+ *pObjResult = ObjectFromHandle(handle);
+ FC_RETURN_BOOL(true);
+}
+FCIMPLEND
+
+extern "C" void QCALLTYPE GCHandle_InternalGetBridgeWait(OBJECTHANDLE handle, OBJECTREF* pObj)
+{
+ _ASSERTE(pObj != NULL);
+
+ // Transition to cooperative mode to ensure that the GC is not in progress
+ Thread* pThisThread = ThreadStore::GetCurrentThreadIfAvailable();
+ pThisThread->DeferTransitionFrame();
+ pThisThread->DisablePreemptiveMode();
+
+ while (g_GCBridgeActive)
+ {
+ // This wait will transition to pre-emptive mode to wait for the bridge to finish.
+ g_bridgeFinished.Wait(INFINITE, false, false);
+ }
+
+ // If we reach here, then the bridge has finished processing and we can be sure that
+ // it isn't currently active.
+
+ // No GC can happen between the wait and obtaining of the reference, so the
+ // bridge processing status can't change, guaranteeing the nulling of weak refs
+ // took place in the bridge processing finish stage.
+ *pObj = ObjectFromHandle(handle);
+
+ // Re-enable preemptive mode before we exit the QCall to ensure we're in the right GC state.
+ pThisThread->EnablePreemptiveMode();
+}
+
+#endif // FEATURE_JAVAMARSHAL
diff --git a/src/coreclr/nativeaot/System.Private.CoreLib/src/System.Private.CoreLib.csproj b/src/coreclr/nativeaot/System.Private.CoreLib/src/System.Private.CoreLib.csproj
index f8f6e6374592c0..2c96332adf7d00 100644
--- a/src/coreclr/nativeaot/System.Private.CoreLib/src/System.Private.CoreLib.csproj
+++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System.Private.CoreLib.csproj
@@ -159,6 +159,7 @@
+
diff --git a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Runtime/InteropServices/GCHandle.NativeAot.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Runtime/InteropServices/GCHandle.NativeAot.cs
index 7b66abd31635f0..551d50a98b2bbe 100644
--- a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Runtime/InteropServices/GCHandle.NativeAot.cs
+++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Runtime/InteropServices/GCHandle.NativeAot.cs
@@ -1,6 +1,8 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
+using System.Runtime.CompilerServices;
+
namespace System.Runtime.InteropServices
{
public partial struct GCHandle
@@ -14,11 +16,24 @@ public partial struct GCHandle
internal static void InternalSet(IntPtr handle, object? value) => RuntimeImports.RhHandleSet(handle, value);
#if FEATURE_JAVAMARSHAL
- // FIXME implement waiting for bridge processing
- internal static object? InternalGetBridgeWait(IntPtr handle)
+ internal static unsafe object? InternalGetBridgeWait(IntPtr handle)
{
- return InternalGet(handle);
+ object? target = null;
+
+ if (InternalTryGetBridgeWait(handle, ref target))
+ return target;
+
+ InternalGetBridgeWait(handle, &target);
+
+ return target;
}
+
+ [MethodImpl(MethodImplOptions.InternalCall)]
+ [RuntimeImport(RuntimeImports.RuntimeLibrary, "GCHandle_InternalTryGetBridgeWait")]
+ private static extern bool InternalTryGetBridgeWait(IntPtr handle, ref object? result);
+
+ [LibraryImport(RuntimeHelpers.QCall, EntryPoint = "GCHandle_InternalGetBridgeWait")]
+ private static unsafe partial void InternalGetBridgeWait(IntPtr handle, object?* result);
#endif
}
}
diff --git a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Runtime/InteropServices/Java/JavaMarshal.NativeAot.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Runtime/InteropServices/Java/JavaMarshal.NativeAot.cs
new file mode 100644
index 00000000000000..c253114be4602d
--- /dev/null
+++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Runtime/InteropServices/Java/JavaMarshal.NativeAot.cs
@@ -0,0 +1,63 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+using System.Runtime.CompilerServices;
+using System.Runtime.Versioning;
+
+namespace System.Runtime.InteropServices.Java
+{
+ [CLSCompliant(false)]
+ [SupportedOSPlatform("android")]
+ public static partial class JavaMarshal
+ {
+ public static unsafe void Initialize(delegate* unmanaged markCrossReferences)
+ {
+ ArgumentNullException.ThrowIfNull(markCrossReferences);
+
+ if (!InitializeInternal((IntPtr)markCrossReferences))
+ {
+ throw new InvalidOperationException(SR.InvalidOperation_ReinitializeJavaMarshal);
+ }
+ }
+
+ public static unsafe GCHandle CreateReferenceTrackingHandle(object obj, void* context)
+ {
+ ArgumentNullException.ThrowIfNull(obj);
+ return GCHandle.FromIntPtr(RuntimeImports.RhHandleAllocCrossReference(obj, (IntPtr)context));
+ }
+
+ public static unsafe void* GetContext(GCHandle obj)
+ {
+ IntPtr handle = GCHandle.ToIntPtr(obj);
+ if (handle == IntPtr.Zero
+ || !RuntimeImports.RhHandleTryGetCrossReferenceContext(handle, out nint context))
+ {
+ throw new InvalidOperationException(SR.InvalidOperation_IncorrectGCHandleType);
+ }
+ return (void*)context;
+ }
+
+ public static unsafe void FinishCrossReferenceProcessing(
+ MarkCrossReferencesArgs* crossReferences,
+ ReadOnlySpan unreachableObjectHandles)
+ {
+ fixed (GCHandle* handlesPtr = unreachableObjectHandles)
+ {
+ FinishCrossReferenceProcessingBridge(
+ crossReferences,
+ (nuint)unreachableObjectHandles.Length,
+ handlesPtr);
+ }
+ }
+
+ [LibraryImport(RuntimeHelpers.QCall, EntryPoint = "JavaMarshal_Initialize")]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ internal static unsafe partial bool InitializeInternal(IntPtr markCrossReferences);
+
+ [LibraryImport(RuntimeHelpers.QCall, EntryPoint = "JavaMarshal_FinishCrossReferenceProcessing")]
+ internal static unsafe partial void FinishCrossReferenceProcessingBridge(
+ MarkCrossReferencesArgs* crossReferences,
+ nuint numHandles,
+ GCHandle* unreachableObjectHandles);
+ }
+}
diff --git a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Runtime/RuntimeImports.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Runtime/RuntimeImports.cs
index e1886df7006f31..298dc148009042 100644
--- a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Runtime/RuntimeImports.cs
+++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Runtime/RuntimeImports.cs
@@ -294,6 +294,26 @@ internal static IntPtr RhHandleAllocDependent(object primary, object secondary)
return h;
}
+ [MethodImpl(MethodImplOptions.InternalCall)]
+ [RuntimeImport(RuntimeLibrary, "RhpHandleAllocCrossReference")]
+ private static extern IntPtr RhpHandleAllocCrossReference(object value, IntPtr context);
+
+ internal static IntPtr RhHandleAllocCrossReference(object value, IntPtr context)
+ {
+ IntPtr h = RhpHandleAllocCrossReference(value, context);
+ if (h == IntPtr.Zero)
+ throw new OutOfMemoryException();
+ return h;
+ }
+
+ [MethodImpl(MethodImplOptions.InternalCall)]
+ [RuntimeImport(RuntimeLibrary, "RhHandleTryGetCrossReferenceContext")]
+ internal static extern bool RhHandleTryGetCrossReferenceContext(IntPtr handle, out IntPtr context);
+
+ [MethodImpl(MethodImplOptions.InternalCall)]
+ [RuntimeImport(RuntimeLibrary, "RhIsGCBridgeActive")]
+ internal static extern bool RhIsGCBridgeActive();
+
// Free handle.
[MethodImpl(MethodImplOptions.InternalCall)]
[RuntimeImport(RuntimeLibrary, "RhHandleFree")]
diff --git a/src/coreclr/vm/interoplibinterface_java.cpp b/src/coreclr/vm/interoplibinterface_java.cpp
index 0a30dce519f471..e4f1f07f11997b 100644
--- a/src/coreclr/vm/interoplibinterface_java.cpp
+++ b/src/coreclr/vm/interoplibinterface_java.cpp
@@ -36,11 +36,11 @@ namespace
// Free memory in each of the SCCs
for (size_t i = 0; i < args->ComponentCount; i++)
{
- free(args->Components[i].Contexts);
+ delete[] args->Components[i].Contexts;
}
- free(args->Components);
- free(args->CrossReferences);
- free(args);
+ delete[] args->Components;
+ delete[] args->CrossReferences;
+ delete args;
}
}
diff --git a/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems b/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems
index fa5371c97cad5b..1c2303c097a6aa 100644
--- a/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems
+++ b/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems
@@ -997,7 +997,7 @@
-
+
diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/Java/JavaMarshal.Unsupported.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/Java/JavaMarshal.Unsupported.cs
new file mode 100644
index 00000000000000..3914d81c2e6ab7
--- /dev/null
+++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/Java/JavaMarshal.Unsupported.cs
@@ -0,0 +1,35 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+using System.Runtime.CompilerServices;
+using System.Runtime.Versioning;
+
+namespace System.Runtime.InteropServices.Java
+{
+ [CLSCompliant(false)]
+ [SupportedOSPlatform("android")]
+ public static partial class JavaMarshal
+ {
+ public static unsafe void Initialize(delegate* unmanaged markCrossReferences)
+ {
+ throw new PlatformNotSupportedException();
+ }
+
+ public static unsafe GCHandle CreateReferenceTrackingHandle(object obj, void* context)
+ {
+ throw new PlatformNotSupportedException();
+ }
+
+ public static unsafe void* GetContext(GCHandle obj)
+ {
+ throw new PlatformNotSupportedException();
+ }
+
+ public static unsafe void FinishCrossReferenceProcessing(
+ MarkCrossReferencesArgs* crossReferences,
+ ReadOnlySpan unreachableObjectHandles)
+ {
+ throw new PlatformNotSupportedException();
+ }
+ }
+}
diff --git a/src/tests/Interop/GCBridge/BridgeTest.csproj b/src/tests/Interop/GCBridge/BridgeTest.csproj
index 1425b1f51b2c64..965f8371061bb7 100644
--- a/src/tests/Interop/GCBridge/BridgeTest.csproj
+++ b/src/tests/Interop/GCBridge/BridgeTest.csproj
@@ -4,8 +4,6 @@
true
true
true
-
- true
true
diff --git a/src/tools/illink/src/linker/Linker.Dataflow/ReflectionMethodBodyScanner.cs b/src/tools/illink/src/linker/Linker.Dataflow/ReflectionMethodBodyScanner.cs
index a4c77237e317fc..244de7b0a0c9a1 100644
--- a/src/tools/illink/src/linker/Linker.Dataflow/ReflectionMethodBodyScanner.cs
+++ b/src/tools/illink/src/linker/Linker.Dataflow/ReflectionMethodBodyScanner.cs
@@ -218,6 +218,12 @@ static bool IsComInterop(IMarshalInfoProvider marshalInfoProvider, TypeReference
if (nativeType == NativeType.None)
{
+ if (parameterType.IsPointer)
+ {
+ // Pointer types are passed without marshalling
+ return false;
+ }
+
// Resolve will look at the element type
var parameterTypeDef = context.TryResolve(parameterType);