diff --git a/src/coreclr/clr.featuredefines.props b/src/coreclr/clr.featuredefines.props
index 17ed60b5f8deca..0530e2aa9db3b6 100644
--- a/src/coreclr/clr.featuredefines.props
+++ b/src/coreclr/clr.featuredefines.props
@@ -3,6 +3,9 @@
true
true
true
+
+
+ true
@@ -27,6 +30,7 @@
+ $(DefineConstants);FEATURE_JAVAMARSHAL;FEATURE_GCBRIDGE
$(DefineConstants);FEATURE_COMWRAPPERS
$(DefineConstants);FEATURE_COMINTEROP
$(DefineConstants);FEATURE_COMINTEROP_APARTMENT_SUPPORT
diff --git a/src/coreclr/clrdefinitions.cmake b/src/coreclr/clrdefinitions.cmake
index 550ce70a14ef7a..1eeec1f22fb91c 100644
--- a/src/coreclr/clrdefinitions.cmake
+++ b/src/coreclr/clrdefinitions.cmake
@@ -161,6 +161,11 @@ if(FEATURE_OBJCMARSHAL)
add_compile_definitions(FEATURE_OBJCMARSHAL)
endif()
+if(FEATURE_JAVAMARSHAL)
+ add_compile_definitions(FEATURE_JAVAMARSHAL)
+ add_compile_definitions(FEATURE_GCBRIDGE)
+endif()
+
add_compile_definitions($<$>>:FEATURE_PROFAPI_ATTACH_DETACH>)
add_definitions(-DFEATURE_READYTORUN)
diff --git a/src/coreclr/clrfeatures.cmake b/src/coreclr/clrfeatures.cmake
index 6bb761a8e0e2f8..20e9219fa7a2dc 100644
--- a/src/coreclr/clrfeatures.cmake
+++ b/src/coreclr/clrfeatures.cmake
@@ -47,6 +47,9 @@ if (CLR_CMAKE_TARGET_APPLE)
set(FEATURE_OBJCMARSHAL 1)
endif()
+# !TODO-JAVA! Limit to Android build
+set(FEATURE_JAVAMARSHAL 1)
+
if (CLR_CMAKE_TARGET_WIN32)
set(FEATURE_TYPEEQUIVALENCE 1)
endif(CLR_CMAKE_TARGET_WIN32)
diff --git a/src/coreclr/debug/daccess/daccess.cpp b/src/coreclr/debug/daccess/daccess.cpp
index 17a327dba01d1e..b8fd0d067383e3 100644
--- a/src/coreclr/debug/daccess/daccess.cpp
+++ b/src/coreclr/debug/daccess/daccess.cpp
@@ -7705,11 +7705,18 @@ void CALLBACK DacHandleWalker::EnumCallback(PTR_UNCHECKED_OBJECTREF handle, uint
data.Handle = TO_CDADDR(handle.GetAddr());
data.Type = param->Type;
if (param->Type == HNDTYPE_DEPENDENT)
+ {
data.Secondary = GetDependentHandleSecondary(handle.GetAddr()).GetAddr();
- else if (param->Type == HNDTYPE_WEAK_INTERIOR_POINTER)
+ }
+ else if (param->Type == HNDTYPE_WEAK_INTERIOR_POINTER
+ || param->Type == HNDTYPE_CROSSREFERENCE)
+ {
data.Secondary = TO_CDADDR(HndGetHandleExtraInfo(handle.GetAddr()));
+ }
else
+ {
data.Secondary = 0;
+ }
data.AppDomain = param->AppDomain;
GetRefCountedHandleInfo((OBJECTREF)*handle, param->Type, &data.RefCount, &data.JupiterRefCount, &data.IsPegged, &data.StrongReference);
data.StrongReference |= (BOOL)IsAlwaysStrongReference(param->Type);
diff --git a/src/coreclr/debug/daccess/request.cpp b/src/coreclr/debug/daccess/request.cpp
index 06b00e4ffa75f2..7098ed73e99a6e 100644
--- a/src/coreclr/debug/daccess/request.cpp
+++ b/src/coreclr/debug/daccess/request.cpp
@@ -3344,6 +3344,9 @@ HRESULT ClrDataAccess::GetHandleEnum(ISOSHandleEnum **ppHandleEnum)
#if defined(FEATURE_COMINTEROP) || defined(FEATURE_COMWRAPPERS) || defined(FEATURE_OBJCMARSHAL)
HNDTYPE_REFCOUNTED,
#endif // FEATURE_COMINTEROP || FEATURE_COMWRAPPERS || FEATURE_OBJCMARSHAL
+#if defined(FEATURE_GCBRIDGE)
+ HNDTYPE_CROSSREFERENCE,
+#endif // FEATURE_GCBRIDGE
};
return GetHandleEnumForTypes(types, ARRAY_SIZE(types), ppHandleEnum);
diff --git a/src/coreclr/gc/env/gcenv.ee.h b/src/coreclr/gc/env/gcenv.ee.h
index 865eb2902a8798..5e06b8734df254 100644
--- a/src/coreclr/gc/env/gcenv.ee.h
+++ b/src/coreclr/gc/env/gcenv.ee.h
@@ -39,6 +39,8 @@ class GCToEEInterface
// Promote refcounted handle callback
static bool RefCountedHandleCallbacks(Object * pObject);
+ static void TriggerGCBridge(size_t sccsLen, StronglyConnectedComponent* sccs, size_t ccrsLen, ComponentCrossReference* ccrs);
+
// Sync block cache management
static void SyncBlockCacheWeakPtrScan(HANDLESCANPROC scanProc, uintptr_t lp1, uintptr_t lp2);
static void SyncBlockCacheDemote(int max_gen);
diff --git a/src/coreclr/gc/env/gctoeeinterface.standalone.inl b/src/coreclr/gc/env/gctoeeinterface.standalone.inl
index 429d4f4c0248f6..494965c271f25a 100644
--- a/src/coreclr/gc/env/gctoeeinterface.standalone.inl
+++ b/src/coreclr/gc/env/gctoeeinterface.standalone.inl
@@ -49,6 +49,11 @@ namespace standalone
return ::GCToEEInterface::RefCountedHandleCallbacks(pObject);
}
+ void TriggerGCBridge(size_t sccsLen, StronglyConnectedComponent* sccs, size_t ccrsLen, ComponentCrossReference* ccrs)
+ {
+ return ::GCToEEInterface::TriggerGCBridge(sccsLen, sccs, ccrsLen, ccrs);
+ }
+
void SyncBlockCacheWeakPtrScan(HANDLESCANPROC scanProc, uintptr_t lp1, uintptr_t lp2)
{
::GCToEEInterface::SyncBlockCacheWeakPtrScan(scanProc, lp1, lp2);
diff --git a/src/coreclr/gc/gc.cpp b/src/coreclr/gc/gc.cpp
index 255e9d1199ad9e..b40433a676ed9f 100644
--- a/src/coreclr/gc/gc.cpp
+++ b/src/coreclr/gc/gc.cpp
@@ -51,7 +51,7 @@ namespace SVR {
#else // SERVER_GC
namespace WKS {
#endif // SERVER_GC
-
+
#include "gcimpl.h"
#include "gcpriv.h"
@@ -6456,9 +6456,9 @@ class heap_select
if (GCToOSInterface::CanGetCurrentProcessorNumber())
{
uint32_t proc_no = GCToOSInterface::GetCurrentProcessorNumber();
- // For a 32-bit process running on a machine with > 64 procs,
- // even though the process can only use up to 32 procs, the processor
- // index can be >= 64; or in the cpu group case, if the process is not running in cpu group #0,
+ // For a 32-bit process running on a machine with > 64 procs,
+ // even though the process can only use up to 32 procs, the processor
+ // index can be >= 64; or in the cpu group case, if the process is not running in cpu group #0,
// the GetCurrentProcessorNumber will return a number that's >= 64.
proc_no_to_heap_no[proc_no % MAX_SUPPORTED_CPUS] = (uint16_t)heap_number;
}
@@ -6482,9 +6482,9 @@ class heap_select
if (GCToOSInterface::CanGetCurrentProcessorNumber())
{
uint32_t proc_no = GCToOSInterface::GetCurrentProcessorNumber();
- // For a 32-bit process running on a machine with > 64 procs,
- // even though the process can only use up to 32 procs, the processor
- // index can be >= 64; or in the cpu group case, if the process is not running in cpu group #0,
+ // For a 32-bit process running on a machine with > 64 procs,
+ // even though the process can only use up to 32 procs, the processor
+ // index can be >= 64; or in the cpu group case, if the process is not running in cpu group #0,
// the GetCurrentProcessorNumber will return a number that's >= 64.
int adjusted_heap = proc_no_to_heap_no[proc_no % MAX_SUPPORTED_CPUS];
// with dynamic heap count, need to make sure the value is in range.
@@ -30281,6 +30281,15 @@ void gc_heap::mark_phase (int condemned_gen_number)
drain_mark_queue();
fire_mark_event (ETW::GC_ROOT_HANDLES, current_promoted_bytes, last_promoted_bytes);
+#ifdef FEATURE_GCBRIDGE
+ dprintf(3,("GCBridge to mark handles"));
+ GCScan::GcScanWithBridge(GCHeap::Promote,
+ condemned_gen_number, max_generation,
+ &sc);
+ drain_mark_queue();
+ // fire_mark_event (ETW::???, current_promoted_bytes, last_promoted_bytes);
+#endif // FEATURE_GCBRIDGE
+
if (!full_p)
{
#ifdef USE_REGIONS
@@ -42233,7 +42242,7 @@ void gc_heap::mark_through_cards_for_segments (card_fn fn, BOOL relocating CARD_
size_t card_last_obj = card_of (last_object_processed);
clear_cards(card, card_last_obj);
- // We need to be careful of the accounting here because we could be in the situation where there are more set cards between end of
+ // We need to be careful of the accounting here because we could be in the situation where there are more set cards between end of
// last set card batch and last_object_processed. We will be clearing all of them. But we can't count the set cards we haven't
// discovered yet or we can get a negative number for n_card_set. However, if last_object_processed lands before what end_card
// corresponds to, we can't count the whole batch because it will be handled by a later clear_cards.
diff --git a/src/coreclr/gc/gcenv.ee.standalone.inl b/src/coreclr/gc/gcenv.ee.standalone.inl
index 898770f717d324..a391dd68a829f3 100644
--- a/src/coreclr/gc/gcenv.ee.standalone.inl
+++ b/src/coreclr/gc/gcenv.ee.standalone.inl
@@ -72,6 +72,12 @@ inline bool GCToEEInterface::RefCountedHandleCallbacks(Object * pObject)
return g_theGCToCLR->RefCountedHandleCallbacks(pObject);
}
+inline void GCToEEInterface::TriggerGCBridge(size_t sccsLen, StronglyConnectedComponent* sccs, size_t ccrsLen, ComponentCrossReference* ccrs)
+{
+ assert(g_theGCToCLR != nullptr);
+ return g_theGCToCLR->TriggerGCBridge(sccsLen, sccs, ccrsLen, ccrs);
+}
+
inline void GCToEEInterface::SyncBlockCacheWeakPtrScan(HANDLESCANPROC scanProc, uintptr_t lp1, uintptr_t lp2)
{
assert(g_theGCToCLR != nullptr);
diff --git a/src/coreclr/gc/gchandletable.cpp b/src/coreclr/gc/gchandletable.cpp
index ef0bbf8c93aef7..d503aca269b6cd 100644
--- a/src/coreclr/gc/gchandletable.cpp
+++ b/src/coreclr/gc/gchandletable.cpp
@@ -46,7 +46,7 @@ HHANDLETABLE GCHandleStore::GetTable()
// high 16-bits are for the handle info.
int handleInfo = (uint32_t)(ctx->alloc_count) >> 16;
- // high 10 bits store the cpu index.
+ // high 10 bits store the cpu index.
// low 6 bits store the # of handles allocated so far (before the next reset).
int numHandles = handleInfo & 0x3f;
int cpuIndex = handleInfo >> 6;
@@ -213,7 +213,7 @@ Object* GCHandleManager::InterlockedCompareExchangeObjectInHandle(OBJECTHANDLE h
HandleType GCHandleManager::HandleFetchType(OBJECTHANDLE handle)
{
uint32_t type = ::HandleFetchType(handle);
- assert(type >= HNDTYPE_WEAK_SHORT && type <= HNDTYPE_WEAK_INTERIOR_POINTER);
+ assert(type >= HNDTYPE_WEAK_SHORT && type <= HNDTYPE_CROSSREFERENCE);
return static_cast(type);
}
diff --git a/src/coreclr/gc/gcinterface.ee.h b/src/coreclr/gc/gcinterface.ee.h
index afc29e837a9146..0f66dabc66545a 100644
--- a/src/coreclr/gc/gcinterface.ee.h
+++ b/src/coreclr/gc/gcinterface.ee.h
@@ -117,10 +117,10 @@ class IGCToCLREventSink
void FireGCAllocationTick_V1(uint32_t allocationAmount, uint32_t allocationKind) PURE_VIRTUAL
virtual
- void FireGCAllocationTick_V4(uint64_t allocationAmount,
- uint32_t allocationKind,
- uint32_t heapIndex,
- void* objectAddress,
+ void FireGCAllocationTick_V4(uint64_t allocationAmount,
+ uint32_t allocationKind,
+ uint32_t heapIndex,
+ void* objectAddress,
uint64_t objectSize) PURE_VIRTUAL
virtual
@@ -239,6 +239,9 @@ class IGCToCLR {
virtual
bool RefCountedHandleCallbacks(Object * pObject) PURE_VIRTUAL
+ virtual
+ void TriggerGCBridge(size_t sccsLen, StronglyConnectedComponent* sccs, size_t ccrsLen, ComponentCrossReference* ccrs) PURE_VIRTUAL
+
// Performs a weak pointer scan of the sync block cache.
virtual
void SyncBlockCacheWeakPtrScan(HANDLESCANPROC scanProc, uintptr_t lp1, uintptr_t lp2) PURE_VIRTUAL
diff --git a/src/coreclr/gc/gcinterface.h b/src/coreclr/gc/gcinterface.h
index bb1e5bc173e1b7..c65485ab76a036 100644
--- a/src/coreclr/gc/gcinterface.h
+++ b/src/coreclr/gc/gcinterface.h
@@ -143,6 +143,19 @@ struct EtwGCSettingsInfo
bool no_affinitize_p;
};
+// These definitions are also in managed code.
+struct StronglyConnectedComponent
+{
+ size_t Count;
+ uintptr_t* Context;
+};
+
+struct ComponentCrossReference
+{
+ size_t SourceGroupIndex;
+ size_t DestinationGroupIndex;
+};
+
// Opaque type for tracking object pointers
#ifndef DACCESS_COMPILE
struct OBJECTHANDLE__
@@ -506,7 +519,14 @@ typedef enum
* have an extra pointer which points at an interior pointer into the first object.
*
*/
- HNDTYPE_WEAK_INTERIOR_POINTER = 10
+ HNDTYPE_WEAK_INTERIOR_POINTER = 10,
+
+ /*
+ * CROSSREFERENCE HANDLES
+ *
+ * Crossreference handles are used to track the lifetime of an object in another VM heap.
+ */
+ HNDTYPE_CROSSREFERENCE = 11
} HandleType;
typedef enum
diff --git a/src/coreclr/gc/gcscan.cpp b/src/coreclr/gc/gcscan.cpp
index 95dab9e11c519f..6d4f73a1728e67 100644
--- a/src/coreclr/gc/gcscan.cpp
+++ b/src/coreclr/gc/gcscan.cpp
@@ -177,6 +177,17 @@ void GCScan::GcScanHandles (promote_func* fn, int condemned, int max_gen,
}
}
+#ifdef FEATURE_GCBRIDGE
+void GCScan::GcScanWithBridge (promote_func* fn, int condemned,
+ int max_gen, ScanContext* sc)
+{
+ STRESS_LOG0(LF_GC|LF_GCROOTS, LL_INFO10, "GcScanWithBridge\n");
+ _ASSERTE(sc->promotion);
+ _ASSERTE(!sc->concurrent);
+ Ref_TraceGCBridge(condemned, max_gen, sc, fn);
+}
+#endif // FEATURE_GCBRIDGE
+
/*
* Scan all handle roots in this 'namespace' for profiling
*/
diff --git a/src/coreclr/gc/gcscan.h b/src/coreclr/gc/gcscan.h
index f569d9ff2a8f3b..6367e3c87b8984 100644
--- a/src/coreclr/gc/gcscan.h
+++ b/src/coreclr/gc/gcscan.h
@@ -43,6 +43,10 @@ class GCScan
//
static void GcScanHandles (promote_func* fn, int condemned, int max_gen, ScanContext* sc);
+#ifdef FEATURE_GCBRIDGE
+ static void GcScanWithBridge (promote_func* fn, int condemned, int max_gen, ScanContext* sc);
+#endif // FEATURE_GCBRIDGE
+
static void GcRuntimeStructuresValid (BOOL bValid);
static bool GetGcRuntimeStructuresValid ();
diff --git a/src/coreclr/gc/handletableconstants.h b/src/coreclr/gc/handletableconstants.h
index a334cc7d5646c6..a838016f227536 100644
--- a/src/coreclr/gc/handletableconstants.h
+++ b/src/coreclr/gc/handletableconstants.h
@@ -14,7 +14,7 @@
#endif
#define INITIAL_HANDLE_TABLE_ARRAY_SIZE 10
-#define HANDLE_MAX_INTERNAL_TYPES 12
+#define HANDLE_MAX_INTERNAL_TYPES 16
/*--------------------------------------------------------------------------*/
diff --git a/src/coreclr/gc/objecthandle.cpp b/src/coreclr/gc/objecthandle.cpp
index 6f3bb7a52fa338..d580c9ee9964c3 100644
--- a/src/coreclr/gc/objecthandle.cpp
+++ b/src/coreclr/gc/objecthandle.cpp
@@ -478,7 +478,10 @@ void CALLBACK ScanPointerForProfilerAndETW(_UNCHECKED_OBJECTREF *pObjRef, uintpt
case HNDTYPE_STRONG:
#ifdef FEATURE_SIZED_REF_HANDLES
case HNDTYPE_SIZEDREF:
-#endif
+#endif // FEATURE_SIZED_REF_HANDLES
+#ifdef FEATURE_GCBRIDGE
+ case HNDTYPE_CROSSREFERENCE:
+#endif // FEATURE_GCBRIDGE
break;
case HNDTYPE_PINNED:
@@ -572,6 +575,7 @@ static const uint32_t s_rgTypeFlags[] =
HNDF_EXTRAINFO, // HNDTYPE_SIZEDREF
HNDF_EXTRAINFO, // HNDTYPE_WEAK_NATIVE_COM
HNDF_EXTRAINFO, // HNDTYPE_WEAK_INTERIOR_POINTER
+ HNDF_EXTRAINFO, // HNDTYPE_CROSSREFERENCE
};
int getNumberOfSlots()
@@ -1529,6 +1533,162 @@ void Ref_ScanSizedRefHandles(uint32_t condemned, uint32_t maxgen, ScanContext* s
}
#endif // FEATURE_SIZED_REF_HANDLES
+#ifdef FEATURE_GCBRIDGE
+
+// [REMOVE] This is for a prototype implementation of the SCC algorithm.
+class CrossReferenceList final
+{
+private:
+ struct Node
+ {
+ _UNCHECKED_OBJECTREF* pObjRef;
+ uintptr_t pExtraInfo;
+ Node* next;
+ };
+
+ Node* head;
+ size_t count;
+
+public:
+ CrossReferenceList() : head(nullptr), count(0) {}
+
+ ~CrossReferenceList()
+ {
+ Node* current = head;
+ while (current != nullptr)
+ {
+ Node* next = current->next;
+ delete current;
+ current = next;
+ }
+ }
+
+ void Add(_UNCHECKED_OBJECTREF* pObjRef, uintptr_t pExtraInfo)
+ {
+ Node* newNode = new Node{ pObjRef, pExtraInfo, head };
+ head = newNode;
+ ++count;
+ }
+
+ size_t Count() const
+ {
+ return count;
+ }
+
+ class Iterator
+ {
+ private:
+ Node* current;
+
+ public:
+ Iterator(Node* start) : current(start) {}
+
+ bool operator!=(const Iterator& other) const
+ {
+ return current != other.current;
+ }
+
+ void operator++()
+ {
+ if (current != nullptr)
+ current = current->next;
+ }
+
+ std::pair<_UNCHECKED_OBJECTREF*, uintptr_t> operator*() const
+ {
+ return { current->pObjRef, current->pExtraInfo };
+ }
+ };
+
+ Iterator begin() const
+ {
+ return Iterator(head);
+ }
+
+ Iterator end() const
+ {
+ return Iterator(nullptr);
+ }
+};
+
+void CALLBACK CollectCrossReferenceEntries(_UNCHECKED_OBJECTREF *pObjRef, uintptr_t *pExtraInfo, uintptr_t lp1, uintptr_t lp2)
+{
+ WRAPPER_NO_CONTRACT;
+ _ASSERTE(pObjRef != NULL);
+ _ASSERTE(lp1 != NULL);
+
+ Object** pRef = (Object** )pObjRef;
+ _ASSERTE(*pRef != NULL);
+
+ // The object is already marked, so we don't need to ask the bridge about it.
+ if (g_theGCHeap->IsPromoted(*pRef))
+ return;
+
+ // The object is not marked, so we need to ask the bridge about it.
+ CrossReferenceList* list = (CrossReferenceList*)lp1;
+ list->Add(pObjRef, *pExtraInfo);
+}
+
+void Ref_TraceGCBridge(uint32_t condemned, uint32_t maxgen, ScanContext* sc, Ref_promote_func* fn)
+{
+ WRAPPER_NO_CONTRACT;
+ _ASSERTE(!sc->concurrent);
+
+ uint32_t types[] =
+ {
+ HNDTYPE_CROSSREFERENCE
+ };
+ uint32_t flags = HNDGCF_NORMAL | HNDGCF_EXTRAINFO;
+
+ CrossReferenceList list;
+ HandleTableMap *walk = &g_HandleTableMap;
+ while (walk)
+ {
+ for (uint32_t i = 0; i < INITIAL_HANDLE_TABLE_ARRAY_SIZE; i ++)
+ {
+ if (walk->pBuckets[i] != NULL)
+ {
+ int uCPUindex = getSlotNumber(sc);
+ int uCPUlimit = getNumberOfSlots();
+ assert(uCPUlimit > 0);
+ int uCPUstep = getThreadCount(sc);
+ HHANDLETABLE* pTable = walk->pBuckets[i]->pTable;
+ for ( ; uCPUindex < uCPUlimit; uCPUindex += uCPUstep)
+ {
+ HHANDLETABLE hTable = pTable[uCPUindex];
+ if (hTable)
+ HndScanHandlesForGC(hTable, CollectCrossReferenceEntries, (uintptr_t)&list, 0, types, ARRAY_SIZE(types), condemned, maxgen, flags);
+ }
+ }
+ }
+ walk = walk->pNext;
+ }
+
+ if (list.Count() != 0)
+ {
+ // [TODO] Implement the SCC algorithm.
+ size_t sccsCount = 1;
+ StronglyConnectedComponent* sccs = (StronglyConnectedComponent*)malloc(sizeof(StronglyConnectedComponent) * sccsCount);
+ sccs->Count = list.Count();
+ sccs->Context = (uintptr_t*)malloc(sizeof(uintptr_t) * sccs->Count);
+
+ uintptr_t* curr = sccs->Context;
+ for (auto& entry : list)
+ {
+ // Promote the object and let the bridge indicate when the
+ // object is actually dead.
+ fn(entry.first, sc, 0);
+
+ *curr = entry.second;
+ curr++;
+ }
+
+ // The callee here will free the allocated memory.
+ GCToEEInterface::TriggerGCBridge(sccsCount, sccs, 0, nullptr);
+ }
+}
+#endif // FEATURE_GCBRIDGE
+
void Ref_CheckAlive(uint32_t condemned, uint32_t maxgen, ScanContext *sc)
{
WRAPPER_NO_CONTRACT;
@@ -1613,6 +1773,9 @@ void Ref_UpdatePointers(uint32_t condemned, uint32_t maxgen, ScanContext* sc, Re
#endif
#ifdef FEATURE_SIZED_REF_HANDLES
HNDTYPE_SIZEDREF,
+#endif
+#ifdef FEATURE_GCBRIDGE
+ HNDTYPE_CROSSREFERENCE,
#endif
};
@@ -1679,7 +1842,10 @@ void Ref_ScanHandlesForProfilerAndETW(uint32_t maxgen, uintptr_t lp1, handle_sca
#ifdef FEATURE_SIZED_REF_HANDLES
HNDTYPE_SIZEDREF,
#endif
- HNDTYPE_WEAK_INTERIOR_POINTER
+ HNDTYPE_WEAK_INTERIOR_POINTER,
+#ifdef FEATURE_GCBRIDGE
+ HNDTYPE_CROSSREFERENCE,
+#endif
};
uint32_t flags = HNDGCF_NORMAL;
@@ -1804,7 +1970,10 @@ void Ref_AgeHandles(uint32_t condemned, uint32_t maxgen, ScanContext* sc)
#ifdef FEATURE_SIZED_REF_HANDLES
HNDTYPE_SIZEDREF,
#endif
- HNDTYPE_WEAK_INTERIOR_POINTER
+ HNDTYPE_WEAK_INTERIOR_POINTER,
+#ifdef FEATURE_GCBRIDGE
+ HNDTYPE_CROSSREFERENCE,
+#endif
};
// perform a multi-type scan that ages the handles
@@ -1861,7 +2030,10 @@ void Ref_RejuvenateHandles(uint32_t condemned, uint32_t maxgen, ScanContext* sc)
#ifdef FEATURE_SIZED_REF_HANDLES
HNDTYPE_SIZEDREF,
#endif
- HNDTYPE_WEAK_INTERIOR_POINTER
+ HNDTYPE_WEAK_INTERIOR_POINTER,
+#ifdef FEATURE_GCBRIDGE
+ HNDTYPE_CROSSREFERENCE,
+#endif
};
// reset the ages of these handles
@@ -1917,7 +2089,10 @@ void Ref_VerifyHandleTable(uint32_t condemned, uint32_t maxgen, ScanContext* sc)
HNDTYPE_SIZEDREF,
#endif
HNDTYPE_DEPENDENT,
- HNDTYPE_WEAK_INTERIOR_POINTER
+ HNDTYPE_WEAK_INTERIOR_POINTER,
+#ifdef FEATURE_GCBRIDGE
+ HNDTYPE_CROSSREFERENCE,
+#endif
};
// verify these handles
diff --git a/src/coreclr/gc/objecthandle.h b/src/coreclr/gc/objecthandle.h
index 634510758c322b..2f2f7a023bee50 100644
--- a/src/coreclr/gc/objecthandle.h
+++ b/src/coreclr/gc/objecthandle.h
@@ -104,6 +104,9 @@ void Ref_ScanDependentHandlesForClearing(uint32_t condemned, uint32_t maxgen, Sc
void Ref_ScanDependentHandlesForRelocation(uint32_t condemned, uint32_t maxgen, ScanContext* sc, Ref_promote_func* fn);
void Ref_ScanWeakInteriorPointersForRelocation(uint32_t condemned, uint32_t maxgen, ScanContext* sc, Ref_promote_func* fn);
void Ref_ScanSizedRefHandles(uint32_t condemned, uint32_t maxgen, ScanContext* sc, Ref_promote_func* fn);
+#ifdef FEATURE_GCBRIDGE
+void Ref_TraceGCBridge(uint32_t condemned, uint32_t maxgen, ScanContext* sc, Ref_promote_func* fn);
+#endif // FEATURE_GCBRIDGE
void Ref_CheckReachable (uint32_t uCondemnedGeneration, uint32_t uMaxGeneration, ScanContext* sc);
void Ref_CheckAlive (uint32_t uCondemnedGeneration, uint32_t uMaxGeneration, ScanContext *sc);
diff --git a/src/coreclr/gc/sample/gcenv.ee.cpp b/src/coreclr/gc/sample/gcenv.ee.cpp
index 4aba23c9a077dc..8d0d4805d01506 100644
--- a/src/coreclr/gc/sample/gcenv.ee.cpp
+++ b/src/coreclr/gc/sample/gcenv.ee.cpp
@@ -164,6 +164,10 @@ bool GCToEEInterface::RefCountedHandleCallbacks(Object * pObject)
return false;
}
+void GCToEEInterface::TriggerGCBridge(size_t sccsLen, StronglyConnectedComponent* sccs, size_t ccrsLen, ComponentCrossReference* ccrs)
+{
+}
+
bool GCToEEInterface::IsPreemptiveGCDisabled()
{
Thread* pThread = ::GetThread();
diff --git a/src/coreclr/nativeaot/Directory.Build.props b/src/coreclr/nativeaot/Directory.Build.props
index 52f437404776f3..d761ff4eb07301 100644
--- a/src/coreclr/nativeaot/Directory.Build.props
+++ b/src/coreclr/nativeaot/Directory.Build.props
@@ -71,7 +71,13 @@
FEATURE_PERFTRACING;$(DefineConstants)
-
+
+
+ true
+
+
+ FEATURE_JAVAMARSHAL;FEATURE_GCBRIDGE;$(DefineConstants)
+
diff --git a/src/coreclr/vm/CMakeLists.txt b/src/coreclr/vm/CMakeLists.txt
index ed401ea0ab99aa..61b1cf56f092e7 100644
--- a/src/coreclr/vm/CMakeLists.txt
+++ b/src/coreclr/vm/CMakeLists.txt
@@ -541,6 +541,12 @@ if(FEATURE_OBJCMARSHAL)
)
endif(FEATURE_OBJCMARSHAL)
+if(FEATURE_JAVAMARSHAL)
+ list(APPEND VM_SOURCES_WKS
+ interoplibinterface_java.cpp
+ )
+endif(FEATURE_JAVAMARSHAL)
+
if(CLR_CMAKE_TARGET_WIN32)
set(VM_SOURCES_DAC_AND_WKS_WIN32
diff --git a/src/coreclr/vm/appdomain.hpp b/src/coreclr/vm/appdomain.hpp
index 118daed24af7ae..fc886d877affd9 100644
--- a/src/coreclr/vm/appdomain.hpp
+++ b/src/coreclr/vm/appdomain.hpp
@@ -784,6 +784,12 @@ class AppDomain final
return ::CreateWeakInteriorHandle(m_handleStore, object, pInteriorPointerLocation);
}
+ OBJECTHANDLE CreateCrossReferenceHandle(OBJECTREF object, void* userContext)
+ {
+ WRAPPER_NO_CONTRACT;
+ return ::CreateCrossReferenceHandle(m_handleStore, object, userContext);
+ }
+
#if defined(FEATURE_COMINTEROP) || defined(FEATURE_COMWRAPPERS)
OBJECTHANDLE CreateRefcountedHandle(OBJECTREF object)
{
diff --git a/src/coreclr/vm/gcenv.ee.cpp b/src/coreclr/vm/gcenv.ee.cpp
index 4738b0d7aeb8fa..fd0ad1d276e2bd 100644
--- a/src/coreclr/vm/gcenv.ee.cpp
+++ b/src/coreclr/vm/gcenv.ee.cpp
@@ -400,6 +400,20 @@ bool GCToEEInterface::RefCountedHandleCallbacks(Object * pObject)
return false;
}
+void GCToEEInterface::TriggerGCBridge(size_t sccsLen, StronglyConnectedComponent* sccs, size_t ccrsLen, ComponentCrossReference* ccrs)
+{
+ CONTRACTL
+ {
+ NOTHROW;
+ GC_NOTRIGGER;
+ }
+ CONTRACTL_END;
+
+#ifdef FEATURE_GCBRIDGE
+ Interop::TriggerGCBridge(sccsLen, sccs, ccrsLen, ccrs);
+#endif // FEATURE_GCBRIDGE
+}
+
void GCToEEInterface::SyncBlockCacheDemote(int max_gen)
{
CONTRACTL
diff --git a/src/coreclr/vm/gchandleutilities.h b/src/coreclr/vm/gchandleutilities.h
index ea1a826c9ddd82..f6f08499222206 100644
--- a/src/coreclr/vm/gchandleutilities.h
+++ b/src/coreclr/vm/gchandleutilities.h
@@ -150,6 +150,18 @@ inline OBJECTHANDLE CreateWeakInteriorHandle(IGCHandleStore* store, OBJECTREF pr
return hnd;
}
+inline OBJECTHANDLE CreateCrossReferenceHandle(IGCHandleStore* store, OBJECTREF primary, void* userContext)
+{
+ OBJECTHANDLE hnd = store->CreateHandleWithExtraInfo(OBJECTREFToObject(primary), HNDTYPE_CROSSREFERENCE, userContext);
+ if (!hnd)
+ {
+ COMPlusThrowOM();
+ }
+
+ DiagHandleCreated(hnd, primary);
+ return hnd;
+}
+
// Global handle creation convenience functions
inline OBJECTHANDLE CreateGlobalHandleCommon(OBJECTREF object, HandleType type)
{
diff --git a/src/coreclr/vm/interoplibinterface.h b/src/coreclr/vm/interoplibinterface.h
index c4f23ce654016c..7a1273bb3a06d4 100644
--- a/src/coreclr/vm/interoplibinterface.h
+++ b/src/coreclr/vm/interoplibinterface.h
@@ -153,7 +153,6 @@ class ObjCMarshalNative
static void OnEnteredFinalizerQueue(_In_ OBJECTREF object);
};
-
extern "C" BOOL QCALLTYPE ObjCMarshal_TryInitializeReferenceTracker(
_In_ ObjCMarshalNative::BeginEndCallback beginEndCallback,
_In_ ObjCMarshalNative::IsReferencedCallback isReferencedCallback,
@@ -169,6 +168,34 @@ extern "C" BOOL QCALLTYPE ObjCMarshal_TrySetGlobalMessageSendCallback(
_In_ void* fptr);
#endif // FEATURE_OBJCMARSHAL
+#ifdef FEATURE_JAVAMARSHAL
+class JavaNative
+{
+public: // GC interaction
+ static bool TriggerGCBridge(
+ _In_ size_t sccsLen,
+ _In_ StronglyConnectedComponent* sccs,
+ _In_ size_t ccrsLen,
+ _In_ ComponentCrossReference* ccrs);
+};
+
+extern "C" BOOL QCALLTYPE JavaMarshal_Initialize(
+ _In_ void* markCrossReferences);
+
+extern "C" void* QCALLTYPE JavaMarshal_CreateReferenceTrackingHandle(
+ _In_ QCall::ObjectHandleOnStack obj,
+ _In_ void* context);
+
+extern "C" void QCALLTYPE JavaMarshal_ReleaseMarkCrossReferenceResources(
+ _In_ int32_t sccsLen,
+ _In_ StronglyConnectedComponent* sccs,
+ _In_ ComponentCrossReference* ccrs);
+
+extern "C" BOOL QCALLTYPE JavaMarshal_GetContext(
+ _In_ OBJECTHANDLE handle,
+ _Out_ void** context);
+#endif // FEATURE_JAVAMARSHAL
+
class Interop
{
public:
@@ -198,6 +225,19 @@ class Interop
// and OnGCFinished.
static void OnBeforeGCScanRoots(_In_ bool isConcurrent);
static void OnAfterGCScanRoots(_In_ bool isConcurrent);
+
+#ifdef FEATURE_GCBRIDGE
+ static void TriggerGCBridge(
+ _In_ size_t sccsLen,
+ _In_ StronglyConnectedComponent* sccs,
+ _In_ size_t ccrsLen,
+ _In_ ComponentCrossReference* ccrs);
+
+ static void ReleaseGCBridgeArguments(
+ _In_ size_t sccsLen,
+ _In_ StronglyConnectedComponent* sccs,
+ _In_ ComponentCrossReference* ccrs);
+#endif // FEATURE_GCBRIDGE
};
#endif // _INTEROPLIBINTERFACE_H_
diff --git a/src/coreclr/vm/interoplibinterface_java.cpp b/src/coreclr/vm/interoplibinterface_java.cpp
new file mode 100644
index 00000000000000..641819541782c4
--- /dev/null
+++ b/src/coreclr/vm/interoplibinterface_java.cpp
@@ -0,0 +1,120 @@
+// 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"
+
+// Interop library header
+#include
+
+#include "interoplibinterface.h"
+
+using CrossreferenceHandleCallback = void(STDMETHODCALLTYPE *)(size_t, StronglyConnectedComponent*, size_t, ComponentCrossReference*);
+
+namespace
+{
+ BOOL g_Initialized;
+ CrossreferenceHandleCallback g_MarkCrossReferences;
+}
+
+extern "C" BOOL QCALLTYPE JavaMarshal_Initialize(
+ _In_ void* markCrossReferences)
+{
+ QCALL_CONTRACT;
+ _ASSERTE(markCrossReferences != NULL);
+
+ BOOL success = FALSE;
+
+ BEGIN_QCALL;
+
+ // 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.
+ {
+ GCX_COOP();
+ if (InterlockedCompareExchange((LONG*)&g_Initialized, TRUE, FALSE) == FALSE)
+ {
+ g_MarkCrossReferences = (CrossreferenceHandleCallback)markCrossReferences;
+ success = TRUE;
+ }
+ }
+
+ END_QCALL;
+
+ return success;
+}
+
+extern "C" void* QCALLTYPE JavaMarshal_CreateReferenceTrackingHandle(
+ _In_ QCall::ObjectHandleOnStack obj,
+ _In_ void* context)
+{
+ QCALL_CONTRACT;
+
+ OBJECTHANDLE instHandle = NULL;
+
+ BEGIN_QCALL;
+
+ GCX_COOP();
+ instHandle = GetAppDomain()->CreateCrossReferenceHandle(obj.Get(), context);
+
+ END_QCALL;
+
+ return (void*)instHandle;
+}
+
+extern "C" void QCALLTYPE JavaMarshal_ReleaseMarkCrossReferenceResources(
+ _In_ int32_t sccsLen,
+ _In_ StronglyConnectedComponent* sccs,
+ _In_ ComponentCrossReference* ccrs)
+{
+ QCALL_CONTRACT;
+ _ASSERTE(sccsLen >= 0);
+
+ BEGIN_QCALL;
+
+ Interop::ReleaseGCBridgeArguments(sccsLen, sccs, ccrs);
+
+ END_QCALL;
+}
+
+extern "C" BOOL QCALLTYPE JavaMarshal_GetContext(
+ _In_ OBJECTHANDLE handle,
+ _Out_ void** context)
+{
+ QCALL_CONTRACT_NO_GC_TRANSITION;
+ _ASSERTE(handle != NULL);
+ _ASSERTE(context != NULL);
+
+ IGCHandleManager* mgr = GCHandleUtilities::GetGCHandleManager();
+ HandleType type = mgr->HandleFetchType(handle);
+ if (type != HNDTYPE_CROSSREFERENCE)
+ return FALSE;
+
+ *context = mgr->GetExtraInfoFromHandle(handle);
+ return TRUE;
+}
+
+bool JavaNative::TriggerGCBridge(
+ _In_ size_t sccsLen,
+ _In_ StronglyConnectedComponent* sccs,
+ _In_ size_t ccrsLen,
+ _In_ ComponentCrossReference* ccrs)
+{
+ CONTRACTL
+ {
+ NOTHROW;
+ GC_NOTRIGGER;
+ }
+ CONTRACTL_END;
+
+ // Not initialized
+ if (g_MarkCrossReferences == NULL)
+ return false;
+
+ g_MarkCrossReferences(sccsLen, sccs, ccrsLen, ccrs);
+ return true;
+}
+
+#endif // FEATURE_JAVAMARSHAL
diff --git a/src/coreclr/vm/interoplibinterface_shared.cpp b/src/coreclr/vm/interoplibinterface_shared.cpp
index f31b128e47cfb1..5f11879fb05dc3 100644
--- a/src/coreclr/vm/interoplibinterface_shared.cpp
+++ b/src/coreclr/vm/interoplibinterface_shared.cpp
@@ -154,3 +154,93 @@ void Interop::OnAfterGCScanRoots(_In_ bool isConcurrent)
ObjCMarshalNative::AfterRefCountedHandleCallbacks();
#endif // FEATURE_OBJCMARSHAL
}
+
+#ifdef FEATURE_GCBRIDGE
+
+namespace
+{
+ Volatile g_GCBridgeActive = FALSE;
+
+ void ReleaseGCBridgeArgumentsWorker(
+ _In_ size_t sccsLen,
+ _In_ StronglyConnectedComponent* sccs,
+ _In_ ComponentCrossReference* ccrs)
+ {
+ CONTRACTL
+ {
+ NOTHROW;
+ GC_NOTRIGGER;
+ }
+ CONTRACTL_END;
+
+ // 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 < sccsLen; i++)
+ {
+ free(sccs[i].Context);
+ }
+ free(sccs);
+ free(ccrs);
+ }
+}
+
+void Interop::TriggerGCBridge(
+ _In_ size_t sccsLen,
+ _In_ StronglyConnectedComponent* sccs,
+ _In_ size_t ccrsLen,
+ _In_ ComponentCrossReference* ccrs)
+{
+ CONTRACTL
+ {
+ NOTHROW;
+ GC_NOTRIGGER;
+ }
+ CONTRACTL_END;
+
+ if (g_GCBridgeActive)
+ {
+ // Release the memory allocated since the GCBridge
+ // is already running and we're not passing them to it.
+ ReleaseGCBridgeArgumentsWorker(sccsLen, sccs, ccrs);
+ return;
+ }
+
+ bool gcBridgeTriggered;
+
+#ifdef FEATURE_JAVAMARSHAL
+ gcBridgeTriggered = JavaNative::TriggerGCBridge(sccsLen, sccs, ccrsLen, ccrs);
+#endif // FEATURE_JAVAMARSHAL
+
+ if (!gcBridgeTriggered)
+ {
+ // Release the memory allocated since the GCBridge
+ // wasn't trigger for some reason.
+ ReleaseGCBridgeArgumentsWorker(sccsLen, sccs, ccrs);
+ return;
+ }
+
+ // Mark the GCBridge as active.
+ g_GCBridgeActive = TRUE;
+}
+
+void Interop::ReleaseGCBridgeArguments(
+ _In_ size_t sccsLen,
+ _In_ StronglyConnectedComponent* sccs,
+ _In_ ComponentCrossReference* ccrs)
+{
+ STANDARD_VM_CONTRACT;
+ _ASSERTE(g_GCBridgeActive);
+
+ // Mark the GCBridge as inactive.
+ // This much be synchronized with the GC so switch to cooperative mode.
+ {
+ GCX_COOP();
+ g_GCBridgeActive = FALSE;
+ }
+
+ ReleaseGCBridgeArgumentsWorker(sccsLen, sccs, ccrs);
+}
+
+#endif // FEATURE_GCBRIDGE
diff --git a/src/coreclr/vm/qcallentrypoints.cpp b/src/coreclr/vm/qcallentrypoints.cpp
index 19ce7a5ffa05ab..016df694826043 100644
--- a/src/coreclr/vm/qcallentrypoints.cpp
+++ b/src/coreclr/vm/qcallentrypoints.cpp
@@ -436,6 +436,12 @@ static const Entry s_QCall[] =
DllImportEntry(ObjCMarshal_TryInitializeReferenceTracker)
DllImportEntry(ObjCMarshal_CreateReferenceTrackingHandle)
#endif
+#if defined(FEATURE_JAVAMARSHAL)
+ DllImportEntry(JavaMarshal_Initialize)
+ DllImportEntry(JavaMarshal_CreateReferenceTrackingHandle)
+ DllImportEntry(JavaMarshal_ReleaseMarkCrossReferenceResources)
+ DllImportEntry(JavaMarshal_GetContext)
+#endif
#if defined(FEATURE_EVENTSOURCE_XPLAT)
DllImportEntry(IsEventSourceLoggingEnabled)
DllImportEntry(LogEventSource)
diff --git a/src/libraries/System.Private.CoreLib/src/Resources/Strings.resx b/src/libraries/System.Private.CoreLib/src/Resources/Strings.resx
index 487028d306a3fa..8f4a539e03fb73 100644
--- a/src/libraries/System.Private.CoreLib/src/Resources/Strings.resx
+++ b/src/libraries/System.Private.CoreLib/src/Resources/Strings.resx
@@ -3908,6 +3908,12 @@
Attempt to track an Objective-C Type without a finalizer.
+
+ Attempt to reinitialize JavaMarshal.
+
+
+ Attempt to get context from an unsupport GCHandle type.
+
Supplying a non-null inner should also be marked as Aggregated.
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 9de275bad2cbc8..11c6c6d898f067 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
@@ -2772,6 +2772,11 @@
+
+
+
+
+
diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/Java/ComponentCrossReference.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/Java/ComponentCrossReference.cs
new file mode 100644
index 00000000000000..b3465d9998215d
--- /dev/null
+++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/Java/ComponentCrossReference.cs
@@ -0,0 +1,21 @@
+// 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.Versioning;
+
+namespace System.Runtime.InteropServices.Java
+{
+ [SupportedOSPlatform("android")]
+ public struct ComponentCrossReference
+ {
+ ///
+ /// Index of the source group.
+ ///
+ public nint SourceGroupIndex;
+
+ ///
+ /// Index of the destination group.
+ ///
+ public nint DestinationGroupIndex;
+ }
+}
diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/Java/JavaMarshal.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/Java/JavaMarshal.cs
new file mode 100644
index 00000000000000..3e4193fd826e9e
--- /dev/null
+++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/Java/JavaMarshal.cs
@@ -0,0 +1,101 @@
+// 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(
+ // Callback used to perform the marking of SCCs.
+ delegate* unmanaged<
+ nint, // Length of SCC collection
+ StronglyConnectedComponent*, // SCC collection
+ nint, // Length of CCR collection
+ ComponentCrossReference*, // CCR collection
+ void> markCrossReferences)
+ {
+#if NATIVEAOT
+ throw new NotImplementedException();
+#elif MONO
+ throw new NotSupportedException();
+#else
+ ArgumentNullException.ThrowIfNull(markCrossReferences);
+
+ if (!InitializeInternal((IntPtr)markCrossReferences))
+ {
+ throw new InvalidOperationException(SR.InvalidOperation_ReinitializeJavaMarshal);
+ }
+#endif
+ }
+
+ public static GCHandle CreateReferenceTrackingHandle(object obj, IntPtr context)
+ {
+#if NATIVEAOT
+ throw new NotImplementedException();
+#elif MONO
+ throw new NotSupportedException();
+#else
+ ArgumentNullException.ThrowIfNull(obj);
+
+ IntPtr handle = CreateReferenceTrackingHandleInternal(ObjectHandleOnStack.Create(ref obj), context);
+ return GCHandle.FromIntPtr(handle);
+#endif
+ }
+
+ public static IntPtr GetContext(GCHandle obj)
+ {
+#if NATIVEAOT
+ throw new NotImplementedException();
+#elif MONO
+ throw new NotSupportedException();
+#else
+ IntPtr handle = GCHandle.ToIntPtr(obj);
+ if (handle == IntPtr.Zero
+ || !GetContextInternal(handle, out IntPtr context))
+ {
+ throw new InvalidOperationException(SR.InvalidOperation_IncorrectGCHandleType);
+ }
+
+ return context;
+#endif
+ }
+
+ public static unsafe void ReleaseMarkCrossReferenceResources(
+ Span sccs,
+ Span ccrs)
+ {
+#if NATIVEAOT
+ throw new NotImplementedException();
+#elif MONO
+ throw new NotSupportedException();
+#else
+ ReleaseMarkCrossReferenceResources(
+ sccs.Length,
+ Unsafe.AsPointer(ref MemoryMarshal.GetReference(sccs)),
+ Unsafe.AsPointer(ref MemoryMarshal.GetReference(ccrs)));
+#endif
+ }
+
+#if CORECLR
+ [LibraryImport(RuntimeHelpers.QCall, EntryPoint = "JavaMarshal_Initialize")]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ private static partial bool InitializeInternal(IntPtr callback);
+
+ [LibraryImport(RuntimeHelpers.QCall, EntryPoint = "JavaMarshal_CreateReferenceTrackingHandle")]
+ private static partial IntPtr CreateReferenceTrackingHandleInternal(ObjectHandleOnStack obj, IntPtr context);
+
+ [LibraryImport(RuntimeHelpers.QCall, EntryPoint = "JavaMarshal_ReleaseMarkCrossReferenceResources")]
+ private static unsafe partial void ReleaseMarkCrossReferenceResources(int length, void* sccs, void* ccrs);
+
+ [LibraryImport(RuntimeHelpers.QCall, EntryPoint = "JavaMarshal_GetContext")]
+ [SuppressGCTransition]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ private static partial bool GetContextInternal(IntPtr handle, out IntPtr context);
+#endif
+ }
+}
diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/Java/StronglyConnectedComponent.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/Java/StronglyConnectedComponent.cs
new file mode 100644
index 00000000000000..f9cc049962e804
--- /dev/null
+++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/Java/StronglyConnectedComponent.cs
@@ -0,0 +1,23 @@
+// 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.Versioning;
+
+namespace System.Runtime.InteropServices.Java
+{
+ [CLSCompliant(false)]
+ [SupportedOSPlatform("android")]
+ public unsafe struct StronglyConnectedComponent
+ {
+ ///
+ /// Number of objects in each collection.
+ ///
+ public nint Count;
+
+ ///
+ /// Contains pointers to context passed during
+ /// creation of each GCHandle.
+ ///
+ public IntPtr* Context;
+ }
+}
diff --git a/src/libraries/System.Runtime.InteropServices/ref/System.Runtime.InteropServices.cs b/src/libraries/System.Runtime.InteropServices/ref/System.Runtime.InteropServices.cs
index eb2130e4f80bc8..133fcf75a1c5ec 100644
--- a/src/libraries/System.Runtime.InteropServices/ref/System.Runtime.InteropServices.cs
+++ b/src/libraries/System.Runtime.InteropServices/ref/System.Runtime.InteropServices.cs
@@ -2366,6 +2366,38 @@ public enum VARKIND
VAR_DISPATCH = 3,
}
}
+namespace System.Runtime.InteropServices.Java
+{
+ [System.Runtime.Versioning.SupportedOSPlatform("android")]
+ public struct ComponentCrossReference
+ {
+ public System.IntPtr SourceGroupIndex;
+ public System.IntPtr DestinationGroupIndex;
+ }
+ [System.Runtime.Versioning.SupportedOSPlatform("android")]
+ [System.CLSCompliantAttribute(false)]
+ public static class JavaMarshal
+ {
+ public static unsafe void Initialize(
+ delegate* unmanaged<
+ System.IntPtr,
+ StronglyConnectedComponent*,
+ System.IntPtr,
+ ComponentCrossReference*,
+ void> markCrossReferences) => throw null;
+
+ public static GCHandle CreateReferenceTrackingHandle(object obj, System.IntPtr context) => throw null;
+ public static System.IntPtr GetContext(GCHandle obj) => throw null;
+ public static unsafe void ReleaseMarkCrossReferenceResources(System.Span sccs, System.Span ccrs) => throw null;
+ }
+ [System.Runtime.Versioning.SupportedOSPlatform("android")]
+ [System.CLSCompliantAttribute(false)]
+ public unsafe struct StronglyConnectedComponent
+ {
+ public System.IntPtr Count;
+ public System.IntPtr* Context;
+ }
+}
namespace System.Runtime.InteropServices.ObjectiveC
{
[System.Runtime.Versioning.SupportedOSPlatformAttribute("macos")]