Skip to content

Commit a90680f

Browse files
authored
Add CoreCLR support for android GC bridge (#116310)
* Add support for the new cross reference GCHandle type From Aaron's implementation. * Add interop glue for bridge From Aaron's implementation * Add GCBridge test * Implement scanning of bridge objects and construction of SCCs from Maoni * Add tarjan bridge computation * Fix object validation Checking if the object is promoted was validating the next object header in debug builds. During bridge tarjan computation, we patch the object header for some objects in order to store data used by the bridge algorithm, so we need to disable this validation. * bgc and multiple heap support for bridge obj processing * Add incorrect waiting for gc bridge to finish * Update code to new API * Clear weakrefs for bridge objects with collected java peers * Wait for bridge processing while resolving the gchandle to prevent races * Maoni review HANDLE_MAX_INTERNAL_TYPES value new instead of malloc assert for allocation failure Reuse memory for ColorData and ScanData between collections. We still do alloc/free for other type of data, for example for arrays representing edges between SCCs. Actually print class name when enabling tarjan bridge logs. Add separate IsPromoted method to the gc interface Rename TriggerGCBridge to TriggerClientBridgeProcessing to be more specific about what it is doing. * Aaron review * Update to new API * Fix build Include classes that are part of the Java Marshal API on mono as well Disable test on mono and nativeaot. * Use cross refs args directly in more places * Change unreachable handle length from int to size_t * Remove FEATURE_GCBRIDGE * Move interop javamarshal code out of interop shared file Create reset event during javamarshal initialize * Use asserts in test * Add bridge waiting to WeakReference<T> as well * Review * review * High precision timestamp * Naming consistency in gcbridge.cpp, matching rest of the runtime * Fix interface breakage * Fix test/JavaMarshal on platforms where it is not enabled The test used to fail and the JavaMarshal api would crash due to missing internal calls. * Share GetHighPrecisionTimeStamp across GC code * Fix mark function used during BGC finishing pause
1 parent 48319f4 commit a90680f

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

54 files changed

+2682
-35
lines changed

src/coreclr/System.Private.CoreLib/src/System/Runtime/InteropServices/GCHandle.CoreCLR.cs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,26 @@ private static void InternalFreeWithGCTransition(IntPtr dependentHandle)
4141
[LibraryImport(RuntimeHelpers.QCall, EntryPoint = "GCHandle_InternalFreeWithGCTransition")]
4242
private static partial void _InternalFreeWithGCTransition(IntPtr dependentHandle);
4343

44+
#if FEATURE_JAVAMARSHAL
45+
internal static object? InternalGetBridgeWait(IntPtr handle)
46+
{
47+
object? target = null;
48+
49+
if (GCHandle.InternalTryGetBridgeWait(handle, ref target))
50+
return target;
51+
52+
InternalGetBridgeWait(handle, ObjectHandleOnStack.Create(ref target));
53+
54+
return target;
55+
}
56+
57+
[MethodImpl(MethodImplOptions.InternalCall)]
58+
private static extern bool InternalTryGetBridgeWait(IntPtr handle, ref object? result);
59+
60+
[LibraryImport(RuntimeHelpers.QCall, EntryPoint = "GCHandle_InternalGetBridgeWait")]
61+
private static partial void InternalGetBridgeWait(IntPtr handle, ObjectHandleOnStack result);
62+
63+
#endif
4464
#if DEBUG
4565
// The runtime performs additional checks in debug builds
4666
[MethodImpl(MethodImplOptions.InternalCall)]

src/coreclr/clr.featuredefines.props

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,10 @@
66
<ProfilingSupportedBuild>true</ProfilingSupportedBuild>
77
</PropertyGroup>
88

9+
<PropertyGroup Condition="'$(TargetsAndroid)' == 'true' OR '$(Configuration)' == 'debug' OR '$(Configuration)' == 'checked'">
10+
<FeatureJavaMarshal>true</FeatureJavaMarshal>
11+
</PropertyGroup>
12+
913
<PropertyGroup Condition="'$(TargetsUnix)' == 'true'">
1014
<FeatureXplatEventSource Condition="'$(FeatureXplatEventSource)' == '' AND '$(TargetOS)' == 'linux'">true</FeatureXplatEventSource>
1115
<FeatureComWrappers>true</FeatureComWrappers>
@@ -28,6 +32,7 @@
2832
</PropertyGroup>
2933

3034
<PropertyGroup>
35+
<DefineConstants Condition="'$(FeatureJavaMarshal)' == 'true'">$(DefineConstants);FEATURE_JAVAMARSHAL</DefineConstants>
3136
<DefineConstants Condition="'$(FeatureComWrappers)' == 'true'">$(DefineConstants);FEATURE_COMWRAPPERS</DefineConstants>
3237
<DefineConstants Condition="'$(FeatureCominterop)' == 'true'">$(DefineConstants);FEATURE_COMINTEROP</DefineConstants>
3338
<DefineConstants Condition="'$(FeatureCominteropApartmentSupport)' == 'true'">$(DefineConstants);FEATURE_COMINTEROP_APARTMENT_SUPPORT</DefineConstants>

src/coreclr/clrdefinitions.cmake

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,8 @@ endif()
154154

155155
# add_compile_definitions(FEATURE_RUNTIME_ASYNC)
156156

157+
add_compile_definitions($<${FEATURE_JAVAMARSHAL}:FEATURE_JAVAMARSHAL>)
158+
157159
add_compile_definitions($<$<NOT:$<BOOL:$<TARGET_PROPERTY:DAC_COMPONENT>>>:FEATURE_PROFAPI_ATTACH_DETACH>)
158160

159161
add_definitions(-DFEATURE_READYTORUN)

src/coreclr/clrfeatures.cmake

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,14 @@ if (CLR_CMAKE_TARGET_APPLE)
6262
set(FEATURE_OBJCMARSHAL 1)
6363
endif()
6464

65+
if(NOT DEFINED FEATURE_JAVAMARSHAL)
66+
if(CLR_CMAKE_TARGET_ANDROID)
67+
set(FEATURE_JAVAMARSHAL 1)
68+
else()
69+
set(FEATURE_JAVAMARSHAL $<IF:$<CONFIG:Debug,Checked>,1,0>)
70+
endif()
71+
endif()
72+
6573
if (CLR_CMAKE_TARGET_WIN32)
6674
set(FEATURE_TYPEEQUIVALENCE 1)
6775
endif(CLR_CMAKE_TARGET_WIN32)

src/coreclr/debug/daccess/daccess.cpp

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7700,11 +7700,18 @@ void CALLBACK DacHandleWalker::EnumCallback(PTR_UNCHECKED_OBJECTREF handle, uint
77007700
data.Handle = TO_CDADDR(handle.GetAddr());
77017701
data.Type = param->Type;
77027702
if (param->Type == HNDTYPE_DEPENDENT)
7703+
{
77037704
data.Secondary = GetDependentHandleSecondary(handle.GetAddr()).GetAddr();
7704-
else if (param->Type == HNDTYPE_WEAK_INTERIOR_POINTER)
7705+
}
7706+
else if (param->Type == HNDTYPE_WEAK_INTERIOR_POINTER
7707+
|| param->Type == HNDTYPE_CROSSREFERENCE)
7708+
{
77057709
data.Secondary = TO_CDADDR(HndGetHandleExtraInfo(handle.GetAddr()));
7710+
}
77067711
else
7712+
{
77077713
data.Secondary = 0;
7714+
}
77087715
data.AppDomain = param->AppDomain;
77097716
GetRefCountedHandleInfo((OBJECTREF)*handle, param->Type, &data.RefCount, &data.JupiterRefCount, &data.IsPegged, &data.StrongReference);
77107717
data.StrongReference |= (BOOL)IsAlwaysStrongReference(param->Type);

src/coreclr/debug/daccess/request.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3347,6 +3347,9 @@ HRESULT ClrDataAccess::GetHandleEnum(ISOSHandleEnum **ppHandleEnum)
33473347
#if defined(FEATURE_COMINTEROP) || defined(FEATURE_COMWRAPPERS) || defined(FEATURE_OBJCMARSHAL)
33483348
HNDTYPE_REFCOUNTED,
33493349
#endif // FEATURE_COMINTEROP || FEATURE_COMWRAPPERS || FEATURE_OBJCMARSHAL
3350+
#if defined(FEATURE_JAVAMARSHAL)
3351+
HNDTYPE_CROSSREFERENCE,
3352+
#endif // FEATURE_JAVAMARSHAL
33503353
};
33513354

33523355
return GetHandleEnumForTypes(types, ARRAY_SIZE(types), ppHandleEnum);

src/coreclr/gc/CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ set(GC_SOURCES
2222
gceesvr.cpp
2323
gceewks.cpp
2424
gcload.cpp
25+
gcbridge.cpp
2526
handletablecache.cpp)
2627

2728
if(CLR_CMAKE_HOST_UNIX)
@@ -55,6 +56,7 @@ if (CLR_CMAKE_TARGET_WIN32)
5556
env/volatile.h
5657
gc.h
5758
gcconfig.h
59+
gcbridge.h
5860
gcdesc.h
5961
gcenv.ee.standalone.inl
6062
gcenv.inl

src/coreclr/gc/env/gcenv.ee.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,8 @@ class GCToEEInterface
3939
// Promote refcounted handle callback
4040
static bool RefCountedHandleCallbacks(Object * pObject);
4141

42+
static void TriggerClientBridgeProcessing(MarkCrossReferencesArgs* args);
43+
4244
// Sync block cache management
4345
static void SyncBlockCacheWeakPtrScan(HANDLESCANPROC scanProc, uintptr_t lp1, uintptr_t lp2);
4446
static void SyncBlockCacheDemote(int max_gen);

src/coreclr/gc/env/gctoeeinterface.standalone.inl

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,11 @@ namespace standalone
4949
return ::GCToEEInterface::RefCountedHandleCallbacks(pObject);
5050
}
5151

52+
void TriggerClientBridgeProcessing(MarkCrossReferencesArgs* args)
53+
{
54+
return ::GCToEEInterface::TriggerClientBridgeProcessing(args);
55+
}
56+
5257
void SyncBlockCacheWeakPtrScan(HANDLESCANPROC scanProc, uintptr_t lp1, uintptr_t lp2)
5358
{
5459
::GCToEEInterface::SyncBlockCacheWeakPtrScan(scanProc, lp1, lp2);

src/coreclr/gc/gc.cpp

Lines changed: 93 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -285,13 +285,6 @@ uint64_t qpf;
285285
double qpf_ms;
286286
double qpf_us;
287287

288-
uint64_t GetHighPrecisionTimeStamp()
289-
{
290-
int64_t ts = GCToOSInterface::QueryPerformanceCounter();
291-
292-
return (uint64_t)((double)ts * qpf_us);
293-
}
294-
295288
uint64_t RawGetHighPrecisionTimeStamp()
296289
{
297290
return (uint64_t)GCToOSInterface::QueryPerformanceCounter();
@@ -670,7 +663,8 @@ enum gc_join_stage
670663
// No longer in use but do not remove, see comments for this enum.
671664
gc_join_disable_software_write_watch = 38,
672665
gc_join_merge_temp_fl = 39,
673-
gc_join_max = 40
666+
gc_join_bridge_processing = 40,
667+
gc_join_max = 41
674668
};
675669

676670
enum gc_join_flavor
@@ -2865,6 +2859,11 @@ FinalizerWorkItem* gc_heap::finalizer_work;
28652859
BOOL gc_heap::proceed_with_gc_p = FALSE;
28662860
GCSpinLock gc_heap::gc_lock;
28672861

2862+
#ifdef FEATURE_JAVAMARSHAL
2863+
uint8_t** gc_heap::global_bridge_list;
2864+
size_t gc_heap::num_global_bridge_objs;
2865+
#endif //FEATURE_JAVAMARSHAL
2866+
28682867
#ifdef BACKGROUND_GC
28692868
uint64_t gc_heap::total_uoh_a_last_bgc = 0;
28702869
#endif //BACKGROUND_GC
@@ -30449,6 +30448,41 @@ void gc_heap::mark_phase (int condemned_gen_number)
3044930448
mark_queue.verify_empty();
3045030449
fire_mark_event (ETW::GC_ROOT_DH_HANDLES, current_promoted_bytes, last_promoted_bytes);
3045130450

30451+
#ifdef FEATURE_JAVAMARSHAL
30452+
30453+
#ifdef MULTIPLE_HEAPS
30454+
dprintf(3, ("Joining for short weak handle scan"));
30455+
gc_t_join.join(this, gc_join_bridge_processing);
30456+
if (gc_t_join.joined())
30457+
{
30458+
#endif //MULTIPLE_HEAPS
30459+
global_bridge_list = GCScan::GcProcessBridgeObjects (condemned_gen_number, max_generation, &sc, &num_global_bridge_objs);
30460+
30461+
#ifdef MULTIPLE_HEAPS
30462+
dprintf (3, ("Starting all gc thread after bridge processing"));
30463+
gc_t_join.restart();
30464+
}
30465+
#endif //MULTIPLE_HEAPS
30466+
30467+
{
30468+
int thread = heap_number;
30469+
// Each thread will receive an equal chunk of bridge objects, with the last thread
30470+
// handling a few more objects from the remainder.
30471+
size_t count_per_heap = num_global_bridge_objs / n_heaps;
30472+
size_t start_index = thread * count_per_heap;
30473+
size_t end_index = (thread == n_heaps - 1) ? num_global_bridge_objs : (thread + 1) * count_per_heap;
30474+
30475+
for (size_t obj_idx = start_index; obj_idx < end_index; obj_idx++)
30476+
{
30477+
mark_object_simple (&global_bridge_list[obj_idx] THREAD_NUMBER_ARG);
30478+
}
30479+
30480+
drain_mark_queue();
30481+
// using GC_ROOT_DH_HANDLES temporarily. add a new value for GC_ROOT_BRIDGE
30482+
fire_mark_event (ETW::GC_ROOT_DH_HANDLES, current_promoted_bytes, last_promoted_bytes);
30483+
}
30484+
#endif //FEATURE_JAVAMARSHAL
30485+
3045230486
#ifdef MULTIPLE_HEAPS
3045330487
dprintf(3, ("Joining for short weak handle scan"));
3045430488
gc_t_join.join(this, gc_join_null_dead_short_weak);
@@ -39180,6 +39214,41 @@ void gc_heap::background_mark_phase ()
3918039214
dprintf (2, ("after NR 1st Hov count: %zu", bgc_overflow_count));
3918139215
bgc_overflow_count = 0;
3918239216

39217+
#ifdef FEATURE_JAVAMARSHAL
39218+
39219+
// FIXME Any reason this code should be different for BGC ? Otherwise extract it to some common method ?
39220+
39221+
#ifdef MULTIPLE_HEAPS
39222+
dprintf(3, ("Joining for short weak handle scan"));
39223+
gc_t_join.join(this, gc_join_bridge_processing);
39224+
if (gc_t_join.joined())
39225+
{
39226+
#endif //MULTIPLE_HEAPS
39227+
global_bridge_list = GCScan::GcProcessBridgeObjects (max_generation, max_generation, &sc, &num_global_bridge_objs);
39228+
39229+
#ifdef MULTIPLE_HEAPS
39230+
dprintf (3, ("Starting all gc thread after bridge processing"));
39231+
gc_t_join.restart();
39232+
}
39233+
#endif //MULTIPLE_HEAPS
39234+
39235+
{
39236+
int thread = heap_number;
39237+
// Each thread will receive an equal chunk of bridge objects, with the last thread
39238+
// handling a few more objects from the remainder.
39239+
size_t count_per_heap = num_global_bridge_objs / n_heaps;
39240+
size_t start_index = thread * count_per_heap;
39241+
size_t end_index = (thread == n_heaps - 1) ? num_global_bridge_objs : (thread + 1) * count_per_heap;
39242+
39243+
for (size_t obj_idx = start_index; obj_idx < end_index; obj_idx++)
39244+
{
39245+
background_mark_simple (global_bridge_list[obj_idx] THREAD_NUMBER_ARG);
39246+
}
39247+
39248+
drain_mark_queue();
39249+
}
39250+
#endif //FEATURE_JAVAMARSHAL
39251+
3918339252
#ifdef MULTIPLE_HEAPS
3918439253
bgc_t_join.join(this, gc_join_null_dead_short_weak);
3918539254
if (bgc_t_join.joined())
@@ -49709,6 +49778,11 @@ HRESULT GCHeap::Initialize()
4970949778
////
4971049779
// GC callback functions
4971149780
bool GCHeap::IsPromoted(Object* object)
49781+
{
49782+
return IsPromoted(object, true);
49783+
}
49784+
49785+
bool GCHeap::IsPromoted(Object* object, bool bVerifyNextHeader)
4971249786
{
4971349787
uint8_t* o = (uint8_t*)object;
4971449788

@@ -49746,10 +49820,11 @@ bool GCHeap::IsPromoted(Object* object)
4974649820
#endif //USE_REGIONS
4974749821
}
4974849822

49823+
// Walking refs when objects are marked seems unexpected
4974949824
#ifdef _DEBUG
4975049825
if (o)
4975149826
{
49752-
((CObjectHeader*)o)->Validate(TRUE, TRUE, is_marked);
49827+
((CObjectHeader*)o)->Validate(TRUE, bVerifyNextHeader, is_marked);
4975349828

4975449829
// Frozen objects aren't expected to be "not promoted" here
4975549830
assert(is_marked || !IsInFrozenSegment(object));
@@ -53227,6 +53302,15 @@ void GCHeap::DiagGetGCSettings(EtwGCSettingsInfo* etw_settings)
5322753302
#endif //FEATURE_EVENT_TRACE
5322853303
}
5322953304

53305+
void GCHeap::NullBridgeObjectsWeakRefs(size_t length, void* unreachableObjectHandles)
53306+
{
53307+
#ifdef FEATURE_JAVAMARSHAL
53308+
Ref_NullBridgeObjectsWeakRefs(length, unreachableObjectHandles);
53309+
#else
53310+
assert(false);
53311+
#endif
53312+
}
53313+
5323053314
#if defined(WRITE_BARRIER_CHECK) && !defined (SERVER_GC)
5323153315
// This code is designed to catch the failure to update the write barrier
5323253316
// The way it works is to copy the whole heap right after every GC. The write

src/coreclr/gc/gc.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -394,4 +394,6 @@ FILE* CreateLogFile(const GCConfigStringHolder& temp_logfile_name, bool is_confi
394394

395395
void log_init_error_to_host (const char* format, ...);
396396

397+
uint64_t GetHighPrecisionTimeStamp();
398+
397399
#endif // __GC_H

0 commit comments

Comments
 (0)