Skip to content

Commit 07b9e41

Browse files
committed
Hook up NAOT-specific GC bridge code
1 parent c3960d2 commit 07b9e41

File tree

6 files changed

+180
-78
lines changed

6 files changed

+180
-78
lines changed

src/native/clr/host/bridge-processing.cc

Lines changed: 32 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66

77
using namespace xamarin::android;
88

9-
void BridgeProcessing::initialize_on_runtime_init (JNIEnv *env, jclass runtimeClass) noexcept
9+
void BridgeProcessingShared::initialize_on_runtime_init (JNIEnv *env, jclass runtimeClass) noexcept
1010
{
1111
abort_if_invalid_pointer_argument (env, "env");
1212
abort_if_invalid_pointer_argument (runtimeClass, "runtimeClass");
@@ -17,7 +17,7 @@ void BridgeProcessing::initialize_on_runtime_init (JNIEnv *env, jclass runtimeCl
1717
abort_unless (GCUserPeer_class != nullptr && GCUserPeer_ctor != nullptr, "Failed to load mono.android.GCUserPeer!");
1818
}
1919

20-
BridgeProcessing::BridgeProcessing (MarkCrossReferencesArgs *args) noexcept
20+
BridgeProcessingShared::BridgeProcessingShared (MarkCrossReferencesArgs *args) noexcept
2121
: env{ OSBridge::ensure_jnienv () },
2222
cross_refs{ args }
2323
{
@@ -34,15 +34,15 @@ BridgeProcessing::BridgeProcessing (MarkCrossReferencesArgs *args) noexcept
3434
}
3535
}
3636

37-
void BridgeProcessing::process () noexcept
37+
void BridgeProcessingShared::process () noexcept
3838
{
3939
prepare_for_java_collection ();
4040
GCBridge::trigger_java_gc (env);
4141
cleanup_after_java_collection ();
4242
log_gc_summary ();
4343
}
4444

45-
void BridgeProcessing::prepare_for_java_collection () noexcept
45+
void BridgeProcessingShared::prepare_for_java_collection () noexcept
4646
{
4747
// Before looking at xrefs, scan the SCCs. During collection, an SCC has to behave like a
4848
// single object. If the number of objects in the SCC is anything other than 1, the SCC
@@ -75,7 +75,7 @@ void BridgeProcessing::prepare_for_java_collection () noexcept
7575
}
7676
}
7777

78-
void BridgeProcessing::prepare_scc_for_java_collection (size_t scc_index, const StronglyConnectedComponent &scc) noexcept
78+
void BridgeProcessingShared::prepare_scc_for_java_collection (size_t scc_index, const StronglyConnectedComponent &scc) noexcept
7979
{
8080
// Count == 0 case: Some SCCs might have no IGCUserPeers associated with them, so we must create one
8181
if (scc.Count == 0) {
@@ -93,7 +93,7 @@ void BridgeProcessing::prepare_scc_for_java_collection (size_t scc_index, const
9393
add_circular_references (scc);
9494
}
9595

96-
CrossReferenceTarget BridgeProcessing::select_cross_reference_target (size_t scc_index) noexcept
96+
CrossReferenceTarget BridgeProcessingShared::select_cross_reference_target (size_t scc_index) noexcept
9797
{
9898
const StronglyConnectedComponent &scc = cross_refs->Components [scc_index];
9999

@@ -108,7 +108,7 @@ CrossReferenceTarget BridgeProcessing::select_cross_reference_target (size_t scc
108108
}
109109

110110
// caller must ensure that scc.Count > 1
111-
void BridgeProcessing::add_circular_references (const StronglyConnectedComponent &scc) noexcept
111+
void BridgeProcessingShared::add_circular_references (const StronglyConnectedComponent &scc) noexcept
112112
{
113113
auto get_control_block = [&scc](size_t index) -> JniObjectReferenceControlBlock& {
114114
abort_unless (scc.Contexts [index] != nullptr, "Context in SCC must not be null");
@@ -142,7 +142,7 @@ void BridgeProcessing::add_circular_references (const StronglyConnectedComponent
142142
}
143143
}
144144

145-
void BridgeProcessing::add_cross_reference (size_t source_index, size_t dest_index) noexcept
145+
void BridgeProcessingShared::add_cross_reference (size_t source_index, size_t dest_index) noexcept
146146
{
147147
CrossReferenceTarget from = select_cross_reference_target (source_index);
148148
CrossReferenceTarget to = select_cross_reference_target (dest_index);
@@ -152,11 +152,15 @@ void BridgeProcessing::add_cross_reference (size_t source_index, size_t dest_ind
152152
}
153153
}
154154

155-
bool BridgeProcessing::add_reference (jobject from, jobject to) noexcept
155+
bool BridgeProcessingShared::add_reference (jobject from, jobject to) noexcept
156156
{
157157
abort_if_invalid_pointer_argument (from, "from");
158158
abort_if_invalid_pointer_argument (to, "to");
159159

160+
if (maybe_call_gc_user_peerable_add_managed_reference (env, from, to)) {
161+
return true;
162+
}
163+
160164
jclass java_class = env->GetObjectClass (from);
161165
jmethodID add_method_id = env->GetMethodID (java_class, "monodroidAddReference", "(Ljava/lang/Object;)V");
162166

@@ -173,7 +177,7 @@ bool BridgeProcessing::add_reference (jobject from, jobject to) noexcept
173177
return true;
174178
}
175179

176-
void BridgeProcessing::clear_references_if_needed (const HandleContext &context) noexcept
180+
void BridgeProcessingShared::clear_references_if_needed (const HandleContext &context) noexcept
177181
{
178182
if (context.is_collected ()) {
179183
return;
@@ -193,10 +197,14 @@ void BridgeProcessing::clear_references_if_needed (const HandleContext &context)
193197
control_block->refs_added = 0;
194198
}
195199

196-
void BridgeProcessing::clear_references (jobject handle) noexcept
200+
void BridgeProcessingShared::clear_references (jobject handle) noexcept
197201
{
198202
abort_if_invalid_pointer_argument (handle, "handle");
199203

204+
if (maybe_call_gc_user_peerable_clear_managed_references (env, handle)) {
205+
return;
206+
}
207+
200208
jclass java_class = env->GetObjectClass (handle);
201209
jmethodID clear_method_id = env->GetMethodID (java_class, "monodroidClearReferences", "()V");
202210

@@ -211,7 +219,7 @@ void BridgeProcessing::clear_references (jobject handle) noexcept
211219
env->CallVoidMethod (handle, clear_method_id);
212220
}
213221

214-
void BridgeProcessing::take_global_ref (HandleContext &context) noexcept
222+
void BridgeProcessingShared::take_global_ref (HandleContext &context) noexcept
215223
{
216224
abort_unless (context.control_block != nullptr, "Control block must not be null");
217225
abort_unless (context.control_block->handle_type == JNIWeakGlobalRefType, "Expected weak global reference type for handle");
@@ -231,7 +239,7 @@ void BridgeProcessing::take_global_ref (HandleContext &context) noexcept
231239
env->DeleteWeakGlobalRef (weak);
232240
}
233241

234-
void BridgeProcessing::take_weak_global_ref (const HandleContext &context) noexcept
242+
void BridgeProcessingShared::take_weak_global_ref (const HandleContext &context) noexcept
235243
{
236244
abort_unless (context.control_block != nullptr, "Control block must not be null");
237245
abort_unless (context.control_block->handle_type == JNIGlobalRefType, "Expected global reference type for handle");
@@ -249,7 +257,7 @@ void BridgeProcessing::take_weak_global_ref (const HandleContext &context) noexc
249257
env->DeleteGlobalRef (handle);
250258
}
251259

252-
void BridgeProcessing::cleanup_after_java_collection () noexcept
260+
void BridgeProcessingShared::cleanup_after_java_collection () noexcept
253261
{
254262
for (size_t i = 0; i < cross_refs->ComponentCount; i++) {
255263
const StronglyConnectedComponent &scc = cross_refs->Components [i];
@@ -267,7 +275,7 @@ void BridgeProcessing::cleanup_after_java_collection () noexcept
267275
}
268276
}
269277

270-
void BridgeProcessing::abort_unless_all_collected_or_all_alive (const StronglyConnectedComponent &scc) noexcept
278+
void BridgeProcessingShared::abort_unless_all_collected_or_all_alive (const StronglyConnectedComponent &scc) noexcept
271279
{
272280
if (scc.Count == 0) {
273281
return;
@@ -306,7 +314,7 @@ void CrossReferenceTarget::mark_refs_added_if_needed () noexcept
306314
}
307315

308316
[[gnu::always_inline]]
309-
void BridgeProcessing::log_missing_add_references_method ([[maybe_unused]] jclass java_class) noexcept
317+
void BridgeProcessingShared::log_missing_add_references_method ([[maybe_unused]] jclass java_class) noexcept
310318
{
311319
log_error (LOG_DEFAULT, "Failed to find monodroidAddReferences method");
312320
#if DEBUG
@@ -322,7 +330,7 @@ void BridgeProcessing::log_missing_add_references_method ([[maybe_unused]] jclas
322330
}
323331

324332
[[gnu::always_inline]]
325-
void BridgeProcessing::log_missing_clear_references_method ([[maybe_unused]] jclass java_class) noexcept
333+
void BridgeProcessingShared::log_missing_clear_references_method ([[maybe_unused]] jclass java_class) noexcept
326334
{
327335
log_error (LOG_DEFAULT, "Failed to find monodroidClearReferences method");
328336
#if DEBUG
@@ -338,7 +346,7 @@ void BridgeProcessing::log_missing_clear_references_method ([[maybe_unused]] jcl
338346
}
339347

340348
[[gnu::always_inline]]
341-
void BridgeProcessing::log_weak_to_gref (jobject weak, jobject handle) noexcept
349+
void BridgeProcessingShared::log_weak_to_gref (jobject weak, jobject handle) noexcept
342350
{
343351
if (handle != nullptr) {
344352
OSBridge::_monodroid_gref_log_new (weak, OSBridge::get_object_ref_type (env, weak),
@@ -358,7 +366,7 @@ void BridgeProcessing::log_weak_to_gref (jobject weak, jobject handle) noexcept
358366
}
359367

360368
[[gnu::always_inline]]
361-
void BridgeProcessing::log_weak_ref_collected (jobject weak) noexcept
369+
void BridgeProcessingShared::log_weak_ref_collected (jobject weak) noexcept
362370
{
363371
if (Logger::gc_spew_enabled ()) [[likely]] {
364372
return;
@@ -369,7 +377,7 @@ void BridgeProcessing::log_weak_ref_collected (jobject weak) noexcept
369377
}
370378

371379
[[gnu::always_inline]]
372-
void BridgeProcessing::log_take_weak_global_ref (jobject handle) noexcept
380+
void BridgeProcessingShared::log_take_weak_global_ref (jobject handle) noexcept
373381
{
374382
if (!Logger::gref_log ()) [[likely]] {
375383
return;
@@ -379,29 +387,29 @@ void BridgeProcessing::log_take_weak_global_ref (jobject handle) noexcept
379387
}
380388

381389
[[gnu::always_inline]]
382-
void BridgeProcessing::log_weak_gref_new (jobject handle, jobject weak) noexcept
390+
void BridgeProcessingShared::log_weak_gref_new (jobject handle, jobject weak) noexcept
383391
{
384392
OSBridge::_monodroid_weak_gref_new (handle, OSBridge::get_object_ref_type (env, handle),
385393
weak, OSBridge::get_object_ref_type (env, weak),
386394
"finalizer", gettid (), " at [[clr-gc:take_weak_global_ref]]", 0);
387395
}
388396

389397
[[gnu::always_inline]]
390-
void BridgeProcessing::log_gref_delete (jobject handle) noexcept
398+
void BridgeProcessingShared::log_gref_delete (jobject handle) noexcept
391399
{
392400
OSBridge::_monodroid_gref_log_delete (handle, OSBridge::get_object_ref_type (env, handle),
393401
"finalizer", gettid (), " at [[clr-gc:take_weak_global_ref]]", 0);
394402
}
395403

396404
[[gnu::always_inline]]
397-
void BridgeProcessing::log_weak_ref_delete (jobject weak) noexcept
405+
void BridgeProcessingShared::log_weak_ref_delete (jobject weak) noexcept
398406
{
399407
OSBridge::_monodroid_weak_gref_delete (weak, OSBridge::get_object_ref_type (env, weak),
400408
"finalizer", gettid (), " at [[clr-gc:take_global_ref]]", 0);
401409
}
402410

403411
[[gnu::always_inline]]
404-
void BridgeProcessing::log_gc_summary () noexcept
412+
void BridgeProcessingShared::log_gc_summary () noexcept
405413
{
406414
if (!Logger::gc_spew_enabled ()) [[likely]] {
407415
return;
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
#pragma once
2+
3+
#include <jni.h>
4+
#include <unordered_map>
5+
6+
#include <host/gc-bridge.hh>
7+
#include <host/os-bridge.hh>
8+
#include <shared/cpp-util.hh>
9+
10+
struct CrossReferenceTarget
11+
{
12+
bool is_temporary_peer;
13+
union
14+
{
15+
jobject temporary_peer;
16+
HandleContext* context;
17+
};
18+
19+
jobject get_handle () const noexcept;
20+
void mark_refs_added_if_needed () noexcept;
21+
};
22+
23+
class BridgeProcessingShared
24+
{
25+
public:
26+
explicit BridgeProcessingShared (MarkCrossReferencesArgs *args) noexcept;
27+
static void initialize_on_runtime_init (JNIEnv *jniEnv, jclass runtimeClass) noexcept;
28+
void process () noexcept;
29+
private:
30+
JNIEnv* env;
31+
MarkCrossReferencesArgs *cross_refs;
32+
std::unordered_map<size_t, jobject> temporary_peers;
33+
34+
static inline jclass GCUserPeer_class = nullptr;
35+
static inline jmethodID GCUserPeer_ctor = nullptr;
36+
37+
void prepare_for_java_collection () noexcept;
38+
void prepare_scc_for_java_collection (size_t scc_index, const StronglyConnectedComponent &scc) noexcept;
39+
void take_weak_global_ref (const HandleContext &context) noexcept;
40+
41+
void add_circular_references (const StronglyConnectedComponent &scc) noexcept;
42+
void add_cross_reference (size_t source_index, size_t dest_index) noexcept;
43+
CrossReferenceTarget select_cross_reference_target (size_t scc_index) noexcept;
44+
bool add_reference (jobject from, jobject to) noexcept;
45+
46+
void cleanup_after_java_collection () noexcept;
47+
void cleanup_scc_for_java_collection (const StronglyConnectedComponent &scc) noexcept;
48+
void abort_unless_all_collected_or_all_alive (const StronglyConnectedComponent &scc) noexcept;
49+
void take_global_ref (HandleContext &context) noexcept;
50+
51+
void clear_references_if_needed (const HandleContext &context) noexcept;
52+
void clear_references (jobject handle) noexcept;
53+
54+
void log_missing_add_references_method (jclass java_class) noexcept;
55+
void log_missing_clear_references_method (jclass java_class) noexcept;
56+
void log_weak_to_gref (jobject weak, jobject handle) noexcept;
57+
void log_weak_ref_collected (jobject weak) noexcept;
58+
void log_take_weak_global_ref (jobject handle) noexcept;
59+
void log_weak_gref_new (jobject handle, jobject weak) noexcept;
60+
void log_gref_delete (jobject handle) noexcept;
61+
void log_weak_ref_delete (jobject weak) noexcept;
62+
void log_gc_summary () noexcept;
63+
64+
// These methods must be implemented by every host individually
65+
// Both methods below return `true` if they processed the call
66+
virtual auto maybe_call_gc_user_peerable_add_managed_reference (JNIEnv *env, jobject from, jobject to) noexcept -> bool = 0;
67+
virtual auto maybe_call_gc_user_peerable_clear_managed_references (JNIEnv *env, jobject handle) noexcept -> bool = 0;
68+
};
Lines changed: 17 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -1,63 +1,26 @@
11
#pragma once
22

3-
#include <jni.h>
4-
#include <unordered_map>
3+
#include <runtime-base/logger.hh>
54

6-
#include <host/gc-bridge.hh>
7-
#include <host/os-bridge.hh>
8-
#include <shared/cpp-util.hh>
5+
#include "bridge-processing-shared.hh"
96

10-
struct CrossReferenceTarget
11-
{
12-
bool is_temporary_peer;
13-
union
14-
{
15-
jobject temporary_peer;
16-
HandleContext* context;
17-
};
18-
19-
jobject get_handle () const noexcept;
20-
void mark_refs_added_if_needed () noexcept;
21-
};
22-
23-
class BridgeProcessing
7+
class BridgeProcessing final : public BridgeProcessingShared
248
{
259
public:
26-
BridgeProcessing (MarkCrossReferencesArgs *args) noexcept;
27-
static void initialize_on_runtime_init (JNIEnv *jniEnv, jclass runtimeClass) noexcept;
28-
void process () noexcept;
29-
private:
30-
JNIEnv* env;
31-
MarkCrossReferencesArgs *cross_refs;
32-
std::unordered_map<size_t, jobject> temporary_peers;
33-
34-
static inline jclass GCUserPeer_class = nullptr;
35-
static inline jmethodID GCUserPeer_ctor = nullptr;
10+
explicit BridgeProcessing (MarkCrossReferencesArgs *args) noexcept
11+
: BridgeProcessingShared (args)
12+
{}
3613

37-
void prepare_for_java_collection () noexcept;
38-
void prepare_scc_for_java_collection (size_t scc_index, const StronglyConnectedComponent &scc) noexcept;
39-
void take_weak_global_ref (const HandleContext &context) noexcept;
40-
41-
void add_circular_references (const StronglyConnectedComponent &scc) noexcept;
42-
void add_cross_reference (size_t source_index, size_t dest_index) noexcept;
43-
CrossReferenceTarget select_cross_reference_target (size_t scc_index) noexcept;
44-
bool add_reference (jobject from, jobject to) noexcept;
45-
46-
void cleanup_after_java_collection () noexcept;
47-
void cleanup_scc_for_java_collection (const StronglyConnectedComponent &scc) noexcept;
48-
void abort_unless_all_collected_or_all_alive (const StronglyConnectedComponent &scc) noexcept;
49-
void take_global_ref (HandleContext &context) noexcept;
50-
51-
void clear_references_if_needed (const HandleContext &context) noexcept;
52-
void clear_references (jobject handle) noexcept;
14+
private:
15+
auto maybe_call_gc_user_peerable_add_managed_reference ([[maybe_unused]] JNIEnv *env, [[maybe_unused]] jobject from, [[maybe_unused]] jobject to) noexcept -> bool override final
16+
{
17+
log_warn (LOG_ASSEMBLY, "{}", __PRETTY_FUNCTION__);
18+
return false; // no-op for CoreCLR, we didn't process the call
19+
}
5320

54-
void log_missing_add_references_method (jclass java_class) noexcept;
55-
void log_missing_clear_references_method (jclass java_class) noexcept;
56-
void log_weak_to_gref (jobject weak, jobject handle) noexcept;
57-
void log_weak_ref_collected (jobject weak) noexcept;
58-
void log_take_weak_global_ref (jobject handle) noexcept;
59-
void log_weak_gref_new (jobject handle, jobject weak) noexcept;
60-
void log_gref_delete (jobject handle) noexcept;
61-
void log_weak_ref_delete (jobject weak) noexcept;
62-
void log_gc_summary () noexcept;
21+
auto maybe_call_gc_user_peerable_clear_managed_references ([[maybe_unused]] JNIEnv *env, [[maybe_unused]] jobject handle) noexcept -> bool override final
22+
{
23+
log_warn (LOG_ASSEMBLY, "{}", __PRETTY_FUNCTION__);
24+
return false; // no-op for CoreCLR, we didn't process the call
25+
}
6326
};

src/native/nativeaot/host/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ set(XAMARIN_NAOT_ANDROID_STATIC_LIB "${XAMARIN_NAOT_ANDROID_LIB}-static")
2727
set(CLR_SOURCES_PATH "../../clr")
2828

2929
set(XAMARIN_MONODROID_SOURCES
30+
bridge-processing.cc
3031
host.cc
3132
host-jni.cc
3233
internal-pinvoke-stubs.cc

0 commit comments

Comments
 (0)