From 0ae638d5b51825a634c600fa9776f8b62a33a930 Mon Sep 17 00:00:00 2001 From: Jonathan Peppers Date: Thu, 8 May 2025 10:47:49 -0500 Subject: [PATCH 01/32] [Mono.Android] call new Java "GC Bridge" APIs Context: https://github.com/dotnet/runtime/pull/114184 Context: https://github.com/jonathanpeppers/BridgeSandbox Context: https://github.com/dotnet/runtime/compare/main...BrzVlad:runtime:feature-clr-gcbridge So far, I: * Built dotnet/runtime, I built this branch: https://github.com/jonathanpeppers/runtime/tree/gcbridge_impl * Put the relevant arm64 packs in `packages/` folder and configured a `NuGet.config` to use them. * Setup `build-tools\scripts\custom-runtime.targets` to use the 10.0.0-dev dotnet/runtime packs. * In `ManagedValueManager.cs`... * Call a new native method on startup: var mark_cross_references_ftn = RuntimeNativeMethods.clr_initialize_gc_bridge (&BridgeProcessingFinished); * Pass the returned function pointer to: JavaMarshal.Initialize (mark_cross_references_ftn); * In `AddPeer(IJavaPeerable value)` call `JavaMarshal.CreateReferenceTrackingHandle()` * In `RemovePeer(IJavaPeerable value)` call: static unsafe void FreeHandle (GCHandle handle) { IntPtr context = JavaMarshal.GetContext (handle); NativeMemory.Free((void*)context); } --- .gitattributes | 2 + Documentation/workflow/DevelopmentTips.md | 25 ++++++-- NuGet.config | 1 + build-tools/scripts/custom-runtime.targets | 21 ++++++ ...Microsoft.NETCore.App.Ref.10.0.0-dev.nupkg | 3 + ...App.Runtime.android-arm64.10.0.0-dev.nupkg | 3 + .../Mono.Android.Runtime.csproj | 1 + .../Android.Runtime/RuntimeNativeMethods.cs | 14 +++- .../ManagedValueManager.cs | 64 +++++++++++++------ src/Mono.Android/Mono.Android.csproj | 1 + .../clr/host/generate-pinvoke-tables.cc | 1 + src/native/clr/host/internal-pinvokes.cc | 10 +++ .../include/runtime-base/internal-pinvokes.hh | 15 +++++ 13 files changed, 135 insertions(+), 26 deletions(-) create mode 100644 build-tools/scripts/custom-runtime.targets create mode 100644 packages/Microsoft.NETCore.App.Ref.10.0.0-dev.nupkg create mode 100644 packages/Microsoft.NETCore.App.Runtime.android-arm64.10.0.0-dev.nupkg diff --git a/.gitattributes b/.gitattributes index fa7720b693b..67b0c8d4a26 100644 --- a/.gitattributes +++ b/.gitattributes @@ -35,3 +35,5 @@ Makefile eol=lf *.wixproj eol=crlf *.wxs eol=crlf *.rtf eol=crlf + +packages/* filter=lfs diff=lfs merge=lfs -text diff --git a/Documentation/workflow/DevelopmentTips.md b/Documentation/workflow/DevelopmentTips.md index 768cc60a55f..53e74606f1b 100644 --- a/Documentation/workflow/DevelopmentTips.md +++ b/Documentation/workflow/DevelopmentTips.md @@ -450,13 +450,26 @@ A second (better) way is to add this MSBuild target to your Android `.csproj` file: ```xml - + + + + <_Version>10.0.0-dev + - + + + + ``` diff --git a/NuGet.config b/NuGet.config index 2343f543fbf..ea03f18b3e3 100644 --- a/NuGet.config +++ b/NuGet.config @@ -7,6 +7,7 @@ + diff --git a/build-tools/scripts/custom-runtime.targets b/build-tools/scripts/custom-runtime.targets new file mode 100644 index 00000000000..c25059b3315 --- /dev/null +++ b/build-tools/scripts/custom-runtime.targets @@ -0,0 +1,21 @@ + + + + + <_Version>10.0.0-dev + + + + + + + diff --git a/packages/Microsoft.NETCore.App.Ref.10.0.0-dev.nupkg b/packages/Microsoft.NETCore.App.Ref.10.0.0-dev.nupkg new file mode 100644 index 00000000000..4c125dbe84a --- /dev/null +++ b/packages/Microsoft.NETCore.App.Ref.10.0.0-dev.nupkg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:d23f78cb9dec82f9ed64e0b9b803fe533d2628d63e1af54685ff8827b1d799bb +size 5313525 diff --git a/packages/Microsoft.NETCore.App.Runtime.android-arm64.10.0.0-dev.nupkg b/packages/Microsoft.NETCore.App.Runtime.android-arm64.10.0.0-dev.nupkg new file mode 100644 index 00000000000..41851a6a435 --- /dev/null +++ b/packages/Microsoft.NETCore.App.Runtime.android-arm64.10.0.0-dev.nupkg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:7c6e9746aaf2b91c7009d940eeda588129f4be8fc864ca6259dc6e5845abe48f +size 215347082 diff --git a/src/Mono.Android.Runtime/Mono.Android.Runtime.csproj b/src/Mono.Android.Runtime/Mono.Android.Runtime.csproj index aac8b3bfe4c..c416d7f8830 100644 --- a/src/Mono.Android.Runtime/Mono.Android.Runtime.csproj +++ b/src/Mono.Android.Runtime/Mono.Android.Runtime.csproj @@ -64,5 +64,6 @@ + diff --git a/src/Mono.Android/Android.Runtime/RuntimeNativeMethods.cs b/src/Mono.Android/Android.Runtime/RuntimeNativeMethods.cs index e740dfdb4c9..13a55b90319 100644 --- a/src/Mono.Android/Android.Runtime/RuntimeNativeMethods.cs +++ b/src/Mono.Android/Android.Runtime/RuntimeNativeMethods.cs @@ -2,6 +2,7 @@ using System; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; +using System.Runtime.InteropServices.Java; using System.Text; namespace Android.Runtime @@ -18,7 +19,7 @@ enum TraceKind : uint All = Java | Managed | Native | Signals, } - internal static class RuntimeNativeMethods + internal unsafe static class RuntimeNativeMethods { [DllImport (RuntimeConstants.InternalDllName, CallingConvention = CallingConvention.Cdecl)] internal extern static void monodroid_log (LogLevel level, LogCategories category, string message); @@ -92,6 +93,17 @@ internal static class RuntimeNativeMethods [DllImport (RuntimeConstants.InternalDllName, CallingConvention = CallingConvention.Cdecl)] internal static extern bool clr_typemap_java_to_managed (string java_type_name, out IntPtr managed_assembly_name, out uint managed_type_token_id); + /// + /// TODO: implement this in the native side. + /// Initializes the "GC Bridge" implementation for the CoreCLR runtime. + /// + /// A function pointer to a C# callback that will be invoked when bridge processing has completed. + /// A function pointer that should be passed to JavaMarshal.Initialize() on startup. + [DllImport (RuntimeConstants.InternalDllName, CallingConvention = CallingConvention.Cdecl)] + internal static extern delegate* unmanaged clr_initialize_gc_bridge ( + delegate* unmanaged bridge_processing_finished_callback + ); + [MethodImplAttribute(MethodImplOptions.InternalCall)] internal static extern void monodroid_unhandled_exception (Exception javaException); diff --git a/src/Mono.Android/Microsoft.Android.Runtime/ManagedValueManager.cs b/src/Mono.Android/Microsoft.Android.Runtime/ManagedValueManager.cs index c58cfbab431..084891fc0f9 100644 --- a/src/Mono.Android/Microsoft.Android.Runtime/ManagedValueManager.cs +++ b/src/Mono.Android/Microsoft.Android.Runtime/ManagedValueManager.cs @@ -10,6 +10,7 @@ using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; +using System.Runtime.InteropServices.Java; using System.Threading; using Android.Runtime; using Java.Interop; @@ -20,10 +21,12 @@ class ManagedValueManager : JniRuntime.JniValueManager { const DynamicallyAccessedMemberTypes Constructors = DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.NonPublicConstructors; - Dictionary>? RegisteredInstances = new Dictionary>(); + Dictionary>? RegisteredInstances = new (); - internal ManagedValueManager () + internal unsafe ManagedValueManager () { + var mark_cross_references_ftn = RuntimeNativeMethods.clr_initialize_gc_bridge (&BridgeProcessingFinished); + JavaMarshal.Initialize (mark_cross_references_ftn); } public override void WaitForGCBridgeProcessing () @@ -35,7 +38,7 @@ public override void CollectPeers () if (RegisteredInstances == null) throw new ObjectDisposedException (nameof (ManagedValueManager)); - var peers = new List (); + var peers = new List (); lock (RegisteredInstances) { foreach (var ps in RegisteredInstances.Values) { @@ -48,7 +51,8 @@ public override void CollectPeers () List? exceptions = null; foreach (var peer in peers) { try { - peer.Dispose (); + if (peer.Target is IDisposable disposable) + disposable.Dispose (); } catch (Exception e) { exceptions = exceptions ?? new List (); @@ -74,10 +78,10 @@ public override void AddPeer (IJavaPeerable value) } int key = value.JniIdentityHashCode; lock (RegisteredInstances) { - List? peers; + List? peers; if (!RegisteredInstances.TryGetValue (key, out peers)) { - peers = new List () { - value, + peers = new List () { + CreateReferenceTrackingHandle (value) }; RegisteredInstances.Add (key, peers); return; @@ -85,22 +89,24 @@ public override void AddPeer (IJavaPeerable value) for (int i = peers.Count - 1; i >= 0; i--) { var p = peers [i]; - if (!JniEnvironment.Types.IsSameObject (p.PeerReference, value.PeerReference)) + if (p.Target is not IJavaPeerable peer) + continue; + if (!JniEnvironment.Types.IsSameObject (peer.PeerReference, value.PeerReference)) continue; if (Replaceable (p)) { - peers [i] = value; + peers [i] = CreateReferenceTrackingHandle (value); } else { - WarnNotReplacing (key, value, p); + WarnNotReplacing (key, value, peer); } return; } - peers.Add (value); + peers.Add (CreateReferenceTrackingHandle (value)); } } - static bool Replaceable (IJavaPeerable peer) + static bool Replaceable (GCHandle handle) { - if (peer == null) + if (handle.Target is not IJavaPeerable peer) return true; return peer.JniManagedPeerState.HasFlag (JniManagedPeerStates.Replaceable); } @@ -132,14 +138,14 @@ void WarnNotReplacing (int key, IJavaPeerable ignoreValue, IJavaPeerable keepVal int key = GetJniIdentityHashCode (reference); lock (RegisteredInstances) { - List? peers; + List? peers; if (!RegisteredInstances.TryGetValue (key, out peers)) return null; for (int i = peers.Count - 1; i >= 0; i--) { var p = peers [i]; - if (JniEnvironment.Types.IsSameObject (reference, p.PeerReference)) - return p; + if (p.Target is IJavaPeerable peer && JniEnvironment.Types.IsSameObject (reference, peer.PeerReference)) + return peer; } if (peers.Count == 0) RegisteredInstances.Remove (key); @@ -157,14 +163,15 @@ public override void RemovePeer (IJavaPeerable value) int key = value.JniIdentityHashCode; lock (RegisteredInstances) { - List? peers; + List? peers; if (!RegisteredInstances.TryGetValue (key, out peers)) return; for (int i = peers.Count - 1; i >= 0; i--) { var p = peers [i]; - if (object.ReferenceEquals (value, p)) { + if (object.ReferenceEquals (value, p.Target)) { peers.RemoveAt (i); + FreeHandle (p); } } if (peers.Count == 0) @@ -251,13 +258,32 @@ public override List GetSurfacedPeers () var peers = new List (RegisteredInstances.Count); foreach (var e in RegisteredInstances) { foreach (var p in e.Value) { - peers.Add (new JniSurfacedPeerInfo (e.Key, new WeakReference (p))); + if (p.Target is not IJavaPeerable peer) + continue; + peers.Add (new JniSurfacedPeerInfo (e.Key, new WeakReference (peer))); } } return peers; } } + static GCHandle CreateReferenceTrackingHandle (IJavaPeerable value) => + JavaMarshal.CreateReferenceTrackingHandle (value, value.PeerReference.Handle); + + static unsafe void FreeHandle (GCHandle handle) + { + IntPtr context = JavaMarshal.GetContext (handle); + NativeMemory.Free ((void*) context); + } + + [UnmanagedCallersOnly] + internal static unsafe void BridgeProcessingFinished (nint sccsLen, StronglyConnectedComponent* sccs, nint ccrsLen, ComponentCrossReference* ccrs) + { + JavaMarshal.ReleaseMarkCrossReferenceResources ( + new Span (sccs, (int) sccsLen), + new Span (ccrs, (int) ccrsLen)); + } + const BindingFlags ActivationConstructorBindingFlags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance; static readonly Type[] XAConstructorSignature = new Type [] { typeof (IntPtr), typeof (JniHandleOwnership) }; diff --git a/src/Mono.Android/Mono.Android.csproj b/src/Mono.Android/Mono.Android.csproj index ec9eff97c93..f15a5b077d2 100644 --- a/src/Mono.Android/Mono.Android.csproj +++ b/src/Mono.Android/Mono.Android.csproj @@ -113,6 +113,7 @@ + diff --git a/src/native/clr/host/generate-pinvoke-tables.cc b/src/native/clr/host/generate-pinvoke-tables.cc index 1619a09b32a..cbf8bb01d19 100644 --- a/src/native/clr/host/generate-pinvoke-tables.cc +++ b/src/native/clr/host/generate-pinvoke-tables.cc @@ -72,6 +72,7 @@ const std::vector internal_pinvoke_names = { "monodroid_TypeManager_get_java_class_name", "clr_typemap_managed_to_java", "clr_typemap_java_to_managed", + "clr_initialize_gc_bridge", "_monodroid_weak_gref_delete", "_monodroid_weak_gref_get", "_monodroid_weak_gref_new", diff --git a/src/native/clr/host/internal-pinvokes.cc b/src/native/clr/host/internal-pinvokes.cc index 4d801afe032..3f1e4ed03aa 100644 --- a/src/native/clr/host/internal-pinvokes.cc +++ b/src/native/clr/host/internal-pinvokes.cc @@ -36,6 +36,16 @@ bool clr_typemap_java_to_managed (const char *java_type_name, char const** assem return TypeMapper::typemap_java_to_managed (java_type_name, assembly_name, managed_type_token_id); } +static void clr_mark_cross_references (size_t sccsLen, StronglyConnectedComponent* sccs, size_t ccrsLen, ComponentCrossReference* ccrs) +{ + // TODO: implement this +} + +MarkCrossReferencesFtn clr_initialize_gc_bridge (MarkCrossReferencesFtn callback) noexcept +{ + return clr_mark_cross_references; +} + void monodroid_log (LogLevel level, LogCategories category, const char *message) noexcept { switch (level) { diff --git a/src/native/clr/include/runtime-base/internal-pinvokes.hh b/src/native/clr/include/runtime-base/internal-pinvokes.hh index a3c69c6c6e7..0d2c80661ff 100644 --- a/src/native/clr/include/runtime-base/internal-pinvokes.hh +++ b/src/native/clr/include/runtime-base/internal-pinvokes.hh @@ -7,6 +7,20 @@ #include "logger.hh" #include +struct StronglyConnectedComponent +{ + size_t Count; + void** ContextMemory; +}; + +struct ComponentCrossReference +{ + size_t SourceGroupIndex; + size_t DestinationGroupIndex; +}; + +typedef void (*MarkCrossReferencesFtn)(size_t, StronglyConnectedComponent*, size_t, ComponentCrossReference*); + extern "C" { int _monodroid_gref_get () noexcept; void _monodroid_gref_log (const char *message) noexcept; @@ -14,6 +28,7 @@ extern "C" { void _monodroid_gref_log_delete (jobject handle, char type, const char *threadName, int threadId, const char *from, int from_writable) noexcept; const char* clr_typemap_managed_to_java (const char *typeName, const uint8_t *mvid) noexcept; bool clr_typemap_java_to_managed (const char *java_type_name, char const** assembly_name, uint32_t *managed_type_token_id) noexcept; + MarkCrossReferencesFtn clr_initialize_gc_bridge (MarkCrossReferencesFtn callback) noexcept; void monodroid_log (xamarin::android::LogLevel level, LogCategories category, const char *message) noexcept; char* monodroid_TypeManager_get_java_class_name (jclass klass) noexcept; void monodroid_free (void *ptr) noexcept; From f4a21484a015a5727a3593335b7841ab9f402ef5 Mon Sep 17 00:00:00 2001 From: Jonathan Peppers Date: Thu, 8 May 2025 16:05:58 -0500 Subject: [PATCH 02/32] What if everything was managed-only? --- .../Mono.Android.Runtime.csproj | 1 - .../Android.Runtime/RuntimeNativeMethods.cs | 14 +------------- .../ManagedValueManager.cs | 7 ++++--- src/native/clr/host/generate-pinvoke-tables.cc | 1 - src/native/clr/host/internal-pinvokes.cc | 10 ---------- .../clr/include/runtime-base/internal-pinvokes.hh | 15 --------------- 6 files changed, 5 insertions(+), 43 deletions(-) diff --git a/src/Mono.Android.Runtime/Mono.Android.Runtime.csproj b/src/Mono.Android.Runtime/Mono.Android.Runtime.csproj index c416d7f8830..aac8b3bfe4c 100644 --- a/src/Mono.Android.Runtime/Mono.Android.Runtime.csproj +++ b/src/Mono.Android.Runtime/Mono.Android.Runtime.csproj @@ -64,6 +64,5 @@ - diff --git a/src/Mono.Android/Android.Runtime/RuntimeNativeMethods.cs b/src/Mono.Android/Android.Runtime/RuntimeNativeMethods.cs index 13a55b90319..e740dfdb4c9 100644 --- a/src/Mono.Android/Android.Runtime/RuntimeNativeMethods.cs +++ b/src/Mono.Android/Android.Runtime/RuntimeNativeMethods.cs @@ -2,7 +2,6 @@ using System; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; -using System.Runtime.InteropServices.Java; using System.Text; namespace Android.Runtime @@ -19,7 +18,7 @@ enum TraceKind : uint All = Java | Managed | Native | Signals, } - internal unsafe static class RuntimeNativeMethods + internal static class RuntimeNativeMethods { [DllImport (RuntimeConstants.InternalDllName, CallingConvention = CallingConvention.Cdecl)] internal extern static void monodroid_log (LogLevel level, LogCategories category, string message); @@ -93,17 +92,6 @@ internal unsafe static class RuntimeNativeMethods [DllImport (RuntimeConstants.InternalDllName, CallingConvention = CallingConvention.Cdecl)] internal static extern bool clr_typemap_java_to_managed (string java_type_name, out IntPtr managed_assembly_name, out uint managed_type_token_id); - /// - /// TODO: implement this in the native side. - /// Initializes the "GC Bridge" implementation for the CoreCLR runtime. - /// - /// A function pointer to a C# callback that will be invoked when bridge processing has completed. - /// A function pointer that should be passed to JavaMarshal.Initialize() on startup. - [DllImport (RuntimeConstants.InternalDllName, CallingConvention = CallingConvention.Cdecl)] - internal static extern delegate* unmanaged clr_initialize_gc_bridge ( - delegate* unmanaged bridge_processing_finished_callback - ); - [MethodImplAttribute(MethodImplOptions.InternalCall)] internal static extern void monodroid_unhandled_exception (Exception javaException); diff --git a/src/Mono.Android/Microsoft.Android.Runtime/ManagedValueManager.cs b/src/Mono.Android/Microsoft.Android.Runtime/ManagedValueManager.cs index 084891fc0f9..91bba6755e7 100644 --- a/src/Mono.Android/Microsoft.Android.Runtime/ManagedValueManager.cs +++ b/src/Mono.Android/Microsoft.Android.Runtime/ManagedValueManager.cs @@ -25,8 +25,7 @@ class ManagedValueManager : JniRuntime.JniValueManager internal unsafe ManagedValueManager () { - var mark_cross_references_ftn = RuntimeNativeMethods.clr_initialize_gc_bridge (&BridgeProcessingFinished); - JavaMarshal.Initialize (mark_cross_references_ftn); + JavaMarshal.Initialize (&FinishBridgeProcessing); } public override void WaitForGCBridgeProcessing () @@ -277,8 +276,10 @@ static unsafe void FreeHandle (GCHandle handle) } [UnmanagedCallersOnly] - internal static unsafe void BridgeProcessingFinished (nint sccsLen, StronglyConnectedComponent* sccs, nint ccrsLen, ComponentCrossReference* ccrs) + internal static unsafe void FinishBridgeProcessing (nint sccsLen, StronglyConnectedComponent* sccs, nint ccrsLen, ComponentCrossReference* ccrs) { + Java.Lang.JavaSystem.Gc (); + JavaMarshal.ReleaseMarkCrossReferenceResources ( new Span (sccs, (int) sccsLen), new Span (ccrs, (int) ccrsLen)); diff --git a/src/native/clr/host/generate-pinvoke-tables.cc b/src/native/clr/host/generate-pinvoke-tables.cc index cbf8bb01d19..1619a09b32a 100644 --- a/src/native/clr/host/generate-pinvoke-tables.cc +++ b/src/native/clr/host/generate-pinvoke-tables.cc @@ -72,7 +72,6 @@ const std::vector internal_pinvoke_names = { "monodroid_TypeManager_get_java_class_name", "clr_typemap_managed_to_java", "clr_typemap_java_to_managed", - "clr_initialize_gc_bridge", "_monodroid_weak_gref_delete", "_monodroid_weak_gref_get", "_monodroid_weak_gref_new", diff --git a/src/native/clr/host/internal-pinvokes.cc b/src/native/clr/host/internal-pinvokes.cc index 3f1e4ed03aa..4d801afe032 100644 --- a/src/native/clr/host/internal-pinvokes.cc +++ b/src/native/clr/host/internal-pinvokes.cc @@ -36,16 +36,6 @@ bool clr_typemap_java_to_managed (const char *java_type_name, char const** assem return TypeMapper::typemap_java_to_managed (java_type_name, assembly_name, managed_type_token_id); } -static void clr_mark_cross_references (size_t sccsLen, StronglyConnectedComponent* sccs, size_t ccrsLen, ComponentCrossReference* ccrs) -{ - // TODO: implement this -} - -MarkCrossReferencesFtn clr_initialize_gc_bridge (MarkCrossReferencesFtn callback) noexcept -{ - return clr_mark_cross_references; -} - void monodroid_log (LogLevel level, LogCategories category, const char *message) noexcept { switch (level) { diff --git a/src/native/clr/include/runtime-base/internal-pinvokes.hh b/src/native/clr/include/runtime-base/internal-pinvokes.hh index 0d2c80661ff..a3c69c6c6e7 100644 --- a/src/native/clr/include/runtime-base/internal-pinvokes.hh +++ b/src/native/clr/include/runtime-base/internal-pinvokes.hh @@ -7,20 +7,6 @@ #include "logger.hh" #include -struct StronglyConnectedComponent -{ - size_t Count; - void** ContextMemory; -}; - -struct ComponentCrossReference -{ - size_t SourceGroupIndex; - size_t DestinationGroupIndex; -}; - -typedef void (*MarkCrossReferencesFtn)(size_t, StronglyConnectedComponent*, size_t, ComponentCrossReference*); - extern "C" { int _monodroid_gref_get () noexcept; void _monodroid_gref_log (const char *message) noexcept; @@ -28,7 +14,6 @@ extern "C" { void _monodroid_gref_log_delete (jobject handle, char type, const char *threadName, int threadId, const char *from, int from_writable) noexcept; const char* clr_typemap_managed_to_java (const char *typeName, const uint8_t *mvid) noexcept; bool clr_typemap_java_to_managed (const char *java_type_name, char const** assembly_name, uint32_t *managed_type_token_id) noexcept; - MarkCrossReferencesFtn clr_initialize_gc_bridge (MarkCrossReferencesFtn callback) noexcept; void monodroid_log (xamarin::android::LogLevel level, LogCategories category, const char *message) noexcept; char* monodroid_TypeManager_get_java_class_name (jclass klass) noexcept; void monodroid_free (void *ptr) noexcept; From aa0a4aed4f2f47acf458ee5d408db9e79e54c994 Mon Sep 17 00:00:00 2001 From: Jonathan Peppers Date: Mon, 12 May 2025 12:11:27 -0500 Subject: [PATCH 03/32] Now uses: https://github.com/dotnet/java-interop/pull/1334 --- external/Java.Interop | 2 +- .../Microsoft.Android.Runtime/ManagedValueManager.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/external/Java.Interop b/external/Java.Interop index d07ed327dbd..174fd85c7fd 160000 --- a/external/Java.Interop +++ b/external/Java.Interop @@ -1 +1 @@ -Subproject commit d07ed327dbd4477f0eab5d277b92fd4f57bfb893 +Subproject commit 174fd85c7fd5c81d48554c89afa7e5b618348160 diff --git a/src/Mono.Android/Microsoft.Android.Runtime/ManagedValueManager.cs b/src/Mono.Android/Microsoft.Android.Runtime/ManagedValueManager.cs index 91bba6755e7..0e0b5eff635 100644 --- a/src/Mono.Android/Microsoft.Android.Runtime/ManagedValueManager.cs +++ b/src/Mono.Android/Microsoft.Android.Runtime/ManagedValueManager.cs @@ -267,7 +267,7 @@ public override List GetSurfacedPeers () } static GCHandle CreateReferenceTrackingHandle (IJavaPeerable value) => - JavaMarshal.CreateReferenceTrackingHandle (value, value.PeerReference.Handle); + JavaMarshal.CreateReferenceTrackingHandle (value, value.JniObjectReferenceControlBlock); static unsafe void FreeHandle (GCHandle handle) { From 0bc80b23e6dbfe053c4979663e037d797f97fcce Mon Sep 17 00:00:00 2001 From: Jonathan Peppers Date: Mon, 19 May 2025 16:15:36 -0500 Subject: [PATCH 04/32] Revert "What if everything was managed-only?" This reverts commit f4a21484a015a5727a3593335b7841ab9f402ef5. --- .../Mono.Android.Runtime.csproj | 1 + .../Android.Runtime/RuntimeNativeMethods.cs | 14 +++++++++++++- .../ManagedValueManager.cs | 7 +++---- src/native/clr/host/generate-pinvoke-tables.cc | 1 + src/native/clr/host/internal-pinvokes.cc | 10 ++++++++++ .../clr/include/runtime-base/internal-pinvokes.hh | 15 +++++++++++++++ 6 files changed, 43 insertions(+), 5 deletions(-) diff --git a/src/Mono.Android.Runtime/Mono.Android.Runtime.csproj b/src/Mono.Android.Runtime/Mono.Android.Runtime.csproj index aac8b3bfe4c..c416d7f8830 100644 --- a/src/Mono.Android.Runtime/Mono.Android.Runtime.csproj +++ b/src/Mono.Android.Runtime/Mono.Android.Runtime.csproj @@ -64,5 +64,6 @@ + diff --git a/src/Mono.Android/Android.Runtime/RuntimeNativeMethods.cs b/src/Mono.Android/Android.Runtime/RuntimeNativeMethods.cs index e740dfdb4c9..13a55b90319 100644 --- a/src/Mono.Android/Android.Runtime/RuntimeNativeMethods.cs +++ b/src/Mono.Android/Android.Runtime/RuntimeNativeMethods.cs @@ -2,6 +2,7 @@ using System; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; +using System.Runtime.InteropServices.Java; using System.Text; namespace Android.Runtime @@ -18,7 +19,7 @@ enum TraceKind : uint All = Java | Managed | Native | Signals, } - internal static class RuntimeNativeMethods + internal unsafe static class RuntimeNativeMethods { [DllImport (RuntimeConstants.InternalDllName, CallingConvention = CallingConvention.Cdecl)] internal extern static void monodroid_log (LogLevel level, LogCategories category, string message); @@ -92,6 +93,17 @@ internal static class RuntimeNativeMethods [DllImport (RuntimeConstants.InternalDllName, CallingConvention = CallingConvention.Cdecl)] internal static extern bool clr_typemap_java_to_managed (string java_type_name, out IntPtr managed_assembly_name, out uint managed_type_token_id); + /// + /// TODO: implement this in the native side. + /// Initializes the "GC Bridge" implementation for the CoreCLR runtime. + /// + /// A function pointer to a C# callback that will be invoked when bridge processing has completed. + /// A function pointer that should be passed to JavaMarshal.Initialize() on startup. + [DllImport (RuntimeConstants.InternalDllName, CallingConvention = CallingConvention.Cdecl)] + internal static extern delegate* unmanaged clr_initialize_gc_bridge ( + delegate* unmanaged bridge_processing_finished_callback + ); + [MethodImplAttribute(MethodImplOptions.InternalCall)] internal static extern void monodroid_unhandled_exception (Exception javaException); diff --git a/src/Mono.Android/Microsoft.Android.Runtime/ManagedValueManager.cs b/src/Mono.Android/Microsoft.Android.Runtime/ManagedValueManager.cs index 0e0b5eff635..265217765d8 100644 --- a/src/Mono.Android/Microsoft.Android.Runtime/ManagedValueManager.cs +++ b/src/Mono.Android/Microsoft.Android.Runtime/ManagedValueManager.cs @@ -25,7 +25,8 @@ class ManagedValueManager : JniRuntime.JniValueManager internal unsafe ManagedValueManager () { - JavaMarshal.Initialize (&FinishBridgeProcessing); + var mark_cross_references_ftn = RuntimeNativeMethods.clr_initialize_gc_bridge (&BridgeProcessingFinished); + JavaMarshal.Initialize (mark_cross_references_ftn); } public override void WaitForGCBridgeProcessing () @@ -276,10 +277,8 @@ static unsafe void FreeHandle (GCHandle handle) } [UnmanagedCallersOnly] - internal static unsafe void FinishBridgeProcessing (nint sccsLen, StronglyConnectedComponent* sccs, nint ccrsLen, ComponentCrossReference* ccrs) + internal static unsafe void BridgeProcessingFinished (nint sccsLen, StronglyConnectedComponent* sccs, nint ccrsLen, ComponentCrossReference* ccrs) { - Java.Lang.JavaSystem.Gc (); - JavaMarshal.ReleaseMarkCrossReferenceResources ( new Span (sccs, (int) sccsLen), new Span (ccrs, (int) ccrsLen)); diff --git a/src/native/clr/host/generate-pinvoke-tables.cc b/src/native/clr/host/generate-pinvoke-tables.cc index 1619a09b32a..cbf8bb01d19 100644 --- a/src/native/clr/host/generate-pinvoke-tables.cc +++ b/src/native/clr/host/generate-pinvoke-tables.cc @@ -72,6 +72,7 @@ const std::vector internal_pinvoke_names = { "monodroid_TypeManager_get_java_class_name", "clr_typemap_managed_to_java", "clr_typemap_java_to_managed", + "clr_initialize_gc_bridge", "_monodroid_weak_gref_delete", "_monodroid_weak_gref_get", "_monodroid_weak_gref_new", diff --git a/src/native/clr/host/internal-pinvokes.cc b/src/native/clr/host/internal-pinvokes.cc index 4d801afe032..3f1e4ed03aa 100644 --- a/src/native/clr/host/internal-pinvokes.cc +++ b/src/native/clr/host/internal-pinvokes.cc @@ -36,6 +36,16 @@ bool clr_typemap_java_to_managed (const char *java_type_name, char const** assem return TypeMapper::typemap_java_to_managed (java_type_name, assembly_name, managed_type_token_id); } +static void clr_mark_cross_references (size_t sccsLen, StronglyConnectedComponent* sccs, size_t ccrsLen, ComponentCrossReference* ccrs) +{ + // TODO: implement this +} + +MarkCrossReferencesFtn clr_initialize_gc_bridge (MarkCrossReferencesFtn callback) noexcept +{ + return clr_mark_cross_references; +} + void monodroid_log (LogLevel level, LogCategories category, const char *message) noexcept { switch (level) { diff --git a/src/native/clr/include/runtime-base/internal-pinvokes.hh b/src/native/clr/include/runtime-base/internal-pinvokes.hh index a3c69c6c6e7..0d2c80661ff 100644 --- a/src/native/clr/include/runtime-base/internal-pinvokes.hh +++ b/src/native/clr/include/runtime-base/internal-pinvokes.hh @@ -7,6 +7,20 @@ #include "logger.hh" #include +struct StronglyConnectedComponent +{ + size_t Count; + void** ContextMemory; +}; + +struct ComponentCrossReference +{ + size_t SourceGroupIndex; + size_t DestinationGroupIndex; +}; + +typedef void (*MarkCrossReferencesFtn)(size_t, StronglyConnectedComponent*, size_t, ComponentCrossReference*); + extern "C" { int _monodroid_gref_get () noexcept; void _monodroid_gref_log (const char *message) noexcept; @@ -14,6 +28,7 @@ extern "C" { void _monodroid_gref_log_delete (jobject handle, char type, const char *threadName, int threadId, const char *from, int from_writable) noexcept; const char* clr_typemap_managed_to_java (const char *typeName, const uint8_t *mvid) noexcept; bool clr_typemap_java_to_managed (const char *java_type_name, char const** assembly_name, uint32_t *managed_type_token_id) noexcept; + MarkCrossReferencesFtn clr_initialize_gc_bridge (MarkCrossReferencesFtn callback) noexcept; void monodroid_log (xamarin::android::LogLevel level, LogCategories category, const char *message) noexcept; char* monodroid_TypeManager_get_java_class_name (jclass klass) noexcept; void monodroid_free (void *ptr) noexcept; From 8f9c0fc5cf3fbd1a115cbbf7f907dc07f9d6ad7f Mon Sep 17 00:00:00 2001 From: Jonathan Peppers Date: Mon, 19 May 2025 16:26:29 -0500 Subject: [PATCH 05/32] Setup `g_bpFinishCallback` --- src/native/clr/host/internal-pinvokes.cc | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/native/clr/host/internal-pinvokes.cc b/src/native/clr/host/internal-pinvokes.cc index 3f1e4ed03aa..cb682a37f88 100644 --- a/src/native/clr/host/internal-pinvokes.cc +++ b/src/native/clr/host/internal-pinvokes.cc @@ -36,13 +36,19 @@ bool clr_typemap_java_to_managed (const char *java_type_name, char const** assem return TypeMapper::typemap_java_to_managed (java_type_name, assembly_name, managed_type_token_id); } +MarkCrossReferencesFtn g_bpFinishCallback; + static void clr_mark_cross_references (size_t sccsLen, StronglyConnectedComponent* sccs, size_t ccrsLen, ComponentCrossReference* ccrs) { // TODO: implement this + + // Call back into managed code + g_bpFinishCallback (sccsLen, sccs, ccrsLen, ccrs); } MarkCrossReferencesFtn clr_initialize_gc_bridge (MarkCrossReferencesFtn callback) noexcept { + g_bpFinishCallback = callback; return clr_mark_cross_references; } From fda9d43910100fbb5cc8e5e8963cb02bcba35df0 Mon Sep 17 00:00:00 2001 From: Jonathan Peppers Date: Tue, 20 May 2025 07:42:34 -0500 Subject: [PATCH 06/32] Update src/native/clr/host/internal-pinvokes.cc Co-authored-by: Marek Habersack --- src/native/clr/host/internal-pinvokes.cc | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/native/clr/host/internal-pinvokes.cc b/src/native/clr/host/internal-pinvokes.cc index cb682a37f88..9e728fd9fe1 100644 --- a/src/native/clr/host/internal-pinvokes.cc +++ b/src/native/clr/host/internal-pinvokes.cc @@ -36,7 +36,9 @@ bool clr_typemap_java_to_managed (const char *java_type_name, char const** assem return TypeMapper::typemap_java_to_managed (java_type_name, assembly_name, managed_type_token_id); } -MarkCrossReferencesFtn g_bpFinishCallback; +namespace { + MarkCrossReferencesFtn g_bpFinishCallback = nullptr; +} static void clr_mark_cross_references (size_t sccsLen, StronglyConnectedComponent* sccs, size_t ccrsLen, ComponentCrossReference* ccrs) { From eba552f9664669b95a057b5e205a810cd206ec1d Mon Sep 17 00:00:00 2001 From: Jonathan Peppers Date: Tue, 20 May 2025 07:42:41 -0500 Subject: [PATCH 07/32] Update src/native/clr/host/internal-pinvokes.cc Co-authored-by: Marek Habersack --- src/native/clr/host/internal-pinvokes.cc | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/native/clr/host/internal-pinvokes.cc b/src/native/clr/host/internal-pinvokes.cc index 9e728fd9fe1..f5c79eacfee 100644 --- a/src/native/clr/host/internal-pinvokes.cc +++ b/src/native/clr/host/internal-pinvokes.cc @@ -42,6 +42,9 @@ namespace { static void clr_mark_cross_references (size_t sccsLen, StronglyConnectedComponent* sccs, size_t ccrsLen, ComponentCrossReference* ccrs) { + if (g_bpFinishCallback == nullptr) [[unlikely]] { + return; + } // TODO: implement this // Call back into managed code From 4313f89f8e7331f1ebe94ae9301dd40ce9d31123 Mon Sep 17 00:00:00 2001 From: Jonathan Peppers Date: Tue, 20 May 2025 08:51:10 -0500 Subject: [PATCH 08/32] dotnet/runtime builds from BrzVlad:runtime:feature-clr-gcbridge Context: https://github.com/dotnet/runtime/compare/main...BrzVlad:runtime:feature-clr-gcbridge --- packages/Microsoft.NETCore.App.Ref.10.0.0-dev.nupkg | 4 ++-- ...crosoft.NETCore.App.Runtime.android-arm64.10.0.0-dev.nupkg | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/Microsoft.NETCore.App.Ref.10.0.0-dev.nupkg b/packages/Microsoft.NETCore.App.Ref.10.0.0-dev.nupkg index 4c125dbe84a..962bb77cfd4 100644 --- a/packages/Microsoft.NETCore.App.Ref.10.0.0-dev.nupkg +++ b/packages/Microsoft.NETCore.App.Ref.10.0.0-dev.nupkg @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:d23f78cb9dec82f9ed64e0b9b803fe533d2628d63e1af54685ff8827b1d799bb -size 5313525 +oid sha256:5240fb5a42a71dc7b9e01f8d75c2251cf81ee6f4ffc571ce50ed0d2d9cb23d1f +size 5313568 diff --git a/packages/Microsoft.NETCore.App.Runtime.android-arm64.10.0.0-dev.nupkg b/packages/Microsoft.NETCore.App.Runtime.android-arm64.10.0.0-dev.nupkg index 41851a6a435..32d7885b4e4 100644 --- a/packages/Microsoft.NETCore.App.Runtime.android-arm64.10.0.0-dev.nupkg +++ b/packages/Microsoft.NETCore.App.Runtime.android-arm64.10.0.0-dev.nupkg @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:7c6e9746aaf2b91c7009d940eeda588129f4be8fc864ca6259dc6e5845abe48f -size 215347082 +oid sha256:8eb905f6f152401b6375d2e3c51ca753b2545717fd4cb89674f7ff188c3e86c7 +size 215752961 From f4f8dcf1b82ff4cd11a4c901fca85d19b0c65bbe Mon Sep 17 00:00:00 2001 From: Marek Habersack Date: Wed, 21 May 2025 11:16:37 +0200 Subject: [PATCH 09/32] Add native portion of the GC interface --- src/native/clr/host/CMakeLists.txt | 1 + src/native/clr/host/gc-bridge.cc | 44 ++++++++++++++++++ src/native/clr/host/host.cc | 2 + src/native/clr/host/internal-pinvokes.cc | 20 ++------- src/native/clr/include/host/gc-bridge.hh | 45 +++++++++++++++++++ .../include/runtime-base/internal-pinvokes.hh | 15 +------ 6 files changed, 96 insertions(+), 31 deletions(-) create mode 100644 src/native/clr/host/gc-bridge.cc create mode 100644 src/native/clr/include/host/gc-bridge.hh diff --git a/src/native/clr/host/CMakeLists.txt b/src/native/clr/host/CMakeLists.txt index d53734eaf8c..44f3edab57d 100644 --- a/src/native/clr/host/CMakeLists.txt +++ b/src/native/clr/host/CMakeLists.txt @@ -29,6 +29,7 @@ set(XAMARIN_NET_ANDROID_STATIC_LIB "${XAMARIN_NET_ANDROID_LIB}-static") set(XAMARIN_MONODROID_SOURCES assembly-store.cc + gc-bridge.cc host.cc host-jni.cc host-util.cc diff --git a/src/native/clr/host/gc-bridge.cc b/src/native/clr/host/gc-bridge.cc new file mode 100644 index 00000000000..176d0f371e5 --- /dev/null +++ b/src/native/clr/host/gc-bridge.cc @@ -0,0 +1,44 @@ +#include +#include +#include + +using namespace xamarin::android; + +void GCBridge::initialize_on_load (JNIEnv *env) noexcept +{ + abort_if_invalid_pointer_argument (env, "env"); + + jclass lref = env->FindClass ("java/lang/Runtime"); + jmethodID Runtime_getRuntime = env->GetStaticMethodID (lref, "getRuntime", "()Ljava/lang/Runtime;"); + Runtime_gc = env->GetMethodID (lref, "gc", "()V"); + Runtime_instance = OSBridge::lref_to_gref (env, env->CallStaticObjectMethod (lref, Runtime_getRuntime)); + env->DeleteLocalRef (lref); + + abort_unless ( + Runtime_gc != nullptr && Runtime_instance != nullptr, + "Failed to look up Java GC runtime API." + ); +} + +[[gnu::always_inline]] +void GCBridge::trigger_java_gc () noexcept +{ + JNIEnv *env = OSBridge::ensure_jnienv (); + + // NOTE: Mono has a number of pre- and post- calls before invoking the Java GC. At this point + // it is unknown whether the CoreCLR GC bridge will need anything of that sort, so we just trigger + // the Java GC here. + env->CallVoidMethod (Runtime_instance, Runtime_gc); +} + +void GCBridge::mark_cross_references (size_t sccsLen, StronglyConnectedComponent* sccs, size_t ccrsLen, ComponentCrossReference* ccrs) noexcept +{ + if (bridge_processing_finish_callback == nullptr) [[unlikely]] { + return; + } + + trigger_java_gc (); + + // Call back into managed code + bridge_processing_finish_callback (sccsLen, sccs, ccrsLen, ccrs); +} diff --git a/src/native/clr/host/host.cc b/src/native/clr/host/host.cc index 5ca6b4f7877..595e8a1da57 100644 --- a/src/native/clr/host/host.cc +++ b/src/native/clr/host/host.cc @@ -9,6 +9,7 @@ #include #include +#include #include #include #include @@ -492,6 +493,7 @@ auto Host::Java_JNI_OnLoad (JavaVM *vm, [[maybe_unused]] void *reserved) noexcep JNIEnv *env = nullptr; vm->GetEnv ((void**)&env, JNI_VERSION_1_6); OSBridge::initialize_on_onload (vm, env); + GCBridge::initialize_on_load (env); AndroidSystem::init_max_gref_count (); return JNI_VERSION_1_6; diff --git a/src/native/clr/host/internal-pinvokes.cc b/src/native/clr/host/internal-pinvokes.cc index f5c79eacfee..bf5a0ba4918 100644 --- a/src/native/clr/host/internal-pinvokes.cc +++ b/src/native/clr/host/internal-pinvokes.cc @@ -1,3 +1,4 @@ +#include #include #include #include @@ -36,25 +37,10 @@ bool clr_typemap_java_to_managed (const char *java_type_name, char const** assem return TypeMapper::typemap_java_to_managed (java_type_name, assembly_name, managed_type_token_id); } -namespace { - MarkCrossReferencesFtn g_bpFinishCallback = nullptr; -} - -static void clr_mark_cross_references (size_t sccsLen, StronglyConnectedComponent* sccs, size_t ccrsLen, ComponentCrossReference* ccrs) -{ - if (g_bpFinishCallback == nullptr) [[unlikely]] { - return; - } - // TODO: implement this - - // Call back into managed code - g_bpFinishCallback (sccsLen, sccs, ccrsLen, ccrs); -} - MarkCrossReferencesFtn clr_initialize_gc_bridge (MarkCrossReferencesFtn callback) noexcept { - g_bpFinishCallback = callback; - return clr_mark_cross_references; + GCBridge::set_finish_callback (callback); + return GCBridge::mark_cross_references; } void monodroid_log (LogLevel level, LogCategories category, const char *message) noexcept diff --git a/src/native/clr/include/host/gc-bridge.hh b/src/native/clr/include/host/gc-bridge.hh new file mode 100644 index 00000000000..f92eed3bfbc --- /dev/null +++ b/src/native/clr/include/host/gc-bridge.hh @@ -0,0 +1,45 @@ +#pragma once + +#include + +#include + +struct StronglyConnectedComponent +{ + size_t Count; + void** ContextMemory; +}; + +struct ComponentCrossReference +{ + size_t SourceGroupIndex; + size_t DestinationGroupIndex; +}; + +using MarkCrossReferencesFtn = void (*)(size_t, StronglyConnectedComponent*, size_t, ComponentCrossReference*); + +namespace xamarin::android { + class GCBridge + { + public: + static void initialize_on_load (JNIEnv *env) noexcept; + static void trigger_java_gc () noexcept; + static void mark_cross_references (size_t sccsLen, StronglyConnectedComponent* sccs, size_t ccrsLen, ComponentCrossReference* ccrs) noexcept; + + static void set_finish_callback (MarkCrossReferencesFtn callback) noexcept + { + abort_if_invalid_pointer_argument (callback, "callback"); + bridge_processing_finish_callback = callback; + } + + static auto get_finish_callback () noexcept -> MarkCrossReferencesFtn + { + return bridge_processing_finish_callback; + } + + private: + static inline jobject Runtime_instance = nullptr; + static inline jmethodID Runtime_gc = nullptr; + static inline MarkCrossReferencesFtn bridge_processing_finish_callback = nullptr; + }; +} diff --git a/src/native/clr/include/runtime-base/internal-pinvokes.hh b/src/native/clr/include/runtime-base/internal-pinvokes.hh index 0d2c80661ff..5a01d121633 100644 --- a/src/native/clr/include/runtime-base/internal-pinvokes.hh +++ b/src/native/clr/include/runtime-base/internal-pinvokes.hh @@ -3,24 +3,11 @@ #include #include +#include #include #include "logger.hh" #include -struct StronglyConnectedComponent -{ - size_t Count; - void** ContextMemory; -}; - -struct ComponentCrossReference -{ - size_t SourceGroupIndex; - size_t DestinationGroupIndex; -}; - -typedef void (*MarkCrossReferencesFtn)(size_t, StronglyConnectedComponent*, size_t, ComponentCrossReference*); - extern "C" { int _monodroid_gref_get () noexcept; void _monodroid_gref_log (const char *message) noexcept; From 4d8bd88a44a67af5d6b7ade774b9b6cb71fe37f1 Mon Sep 17 00:00:00 2001 From: Marek Habersack Date: Wed, 21 May 2025 11:19:05 +0200 Subject: [PATCH 10/32] Don't need this anymore --- src/native/clr/include/host/gc-bridge.hh | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/native/clr/include/host/gc-bridge.hh b/src/native/clr/include/host/gc-bridge.hh index f92eed3bfbc..b93c3b135a5 100644 --- a/src/native/clr/include/host/gc-bridge.hh +++ b/src/native/clr/include/host/gc-bridge.hh @@ -32,11 +32,6 @@ namespace xamarin::android { bridge_processing_finish_callback = callback; } - static auto get_finish_callback () noexcept -> MarkCrossReferencesFtn - { - return bridge_processing_finish_callback; - } - private: static inline jobject Runtime_instance = nullptr; static inline jmethodID Runtime_gc = nullptr; From fccda54cc76bc19c1000eaee187c0fa3f68b8c92 Mon Sep 17 00:00:00 2001 From: Jonathan Peppers Date: Wed, 21 May 2025 08:34:08 -0500 Subject: [PATCH 11/32] Enable git lfs on AzDO --- build-tools/automation/azure-pipelines.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/build-tools/automation/azure-pipelines.yaml b/build-tools/automation/azure-pipelines.yaml index 144c5aa2877..1133cbc419f 100644 --- a/build-tools/automation/azure-pipelines.yaml +++ b/build-tools/automation/azure-pipelines.yaml @@ -345,6 +345,7 @@ extends: steps: - checkout: self clean: true + lfs: true submodules: recursive - template: /build-tools/automation/yaml-templates/use-dot-net.yaml@self From 5b2e13e2af2dfbe21c0bd705a11f8a8e6eb328f6 Mon Sep 17 00:00:00 2001 From: Jonathan Peppers Date: Wed, 21 May 2025 09:45:53 -0500 Subject: [PATCH 12/32] Enable `$(system.debug)` --- build-tools/automation/yaml-templates/variables.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/build-tools/automation/yaml-templates/variables.yaml b/build-tools/automation/yaml-templates/variables.yaml index a2822871012..5e971c81f63 100644 --- a/build-tools/automation/yaml-templates/variables.yaml +++ b/build-tools/automation/yaml-templates/variables.yaml @@ -1,4 +1,6 @@ variables: +- name: system.debug + value: true - name: RunningOnCI value: true - name: XA.Build.Configuration From 461d12712da68a509c672639bdf4577ac56ffe6d Mon Sep 17 00:00:00 2001 From: Jonathan Peppers Date: Wed, 21 May 2025 10:01:57 -0500 Subject: [PATCH 13/32] Revert "Enable `$(system.debug)`" This reverts commit 5b2e13e2af2dfbe21c0bd705a11f8a8e6eb328f6. --- build-tools/automation/yaml-templates/variables.yaml | 2 -- 1 file changed, 2 deletions(-) diff --git a/build-tools/automation/yaml-templates/variables.yaml b/build-tools/automation/yaml-templates/variables.yaml index 5e971c81f63..a2822871012 100644 --- a/build-tools/automation/yaml-templates/variables.yaml +++ b/build-tools/automation/yaml-templates/variables.yaml @@ -1,6 +1,4 @@ variables: -- name: system.debug - value: true - name: RunningOnCI value: true - name: XA.Build.Configuration From 6cac797288b54f7786c20ffed1b4786f059d04fe Mon Sep 17 00:00:00 2001 From: Jonathan Peppers Date: Wed, 21 May 2025 10:02:00 -0500 Subject: [PATCH 14/32] Revert "Enable git lfs on AzDO" This reverts commit fccda54cc76bc19c1000eaee187c0fa3f68b8c92. --- build-tools/automation/azure-pipelines.yaml | 1 - 1 file changed, 1 deletion(-) diff --git a/build-tools/automation/azure-pipelines.yaml b/build-tools/automation/azure-pipelines.yaml index 1133cbc419f..144c5aa2877 100644 --- a/build-tools/automation/azure-pipelines.yaml +++ b/build-tools/automation/azure-pipelines.yaml @@ -345,7 +345,6 @@ extends: steps: - checkout: self clean: true - lfs: true submodules: recursive - template: /build-tools/automation/yaml-templates/use-dot-net.yaml@self From 0654d760add4ec65e437a7c4a3620f7e42f95086 Mon Sep 17 00:00:00 2001 From: Jonathan Peppers Date: Wed, 21 May 2025 10:03:02 -0500 Subject: [PATCH 15/32] Update azure-pipelines.yaml --- build-tools/automation/azure-pipelines.yaml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/build-tools/automation/azure-pipelines.yaml b/build-tools/automation/azure-pipelines.yaml index 144c5aa2877..105f8914e3c 100644 --- a/build-tools/automation/azure-pipelines.yaml +++ b/build-tools/automation/azure-pipelines.yaml @@ -347,6 +347,9 @@ extends: clean: true submodules: recursive + - script: git lfs pull + displayName: git lfs pull + - template: /build-tools/automation/yaml-templates/use-dot-net.yaml@self parameters: version: $(DotNetPreviewSdkVersion) From a0f25618cac20fc9589383fa9d8ebafc2070e791 Mon Sep 17 00:00:00 2001 From: Jonathan Peppers Date: Wed, 21 May 2025 10:11:46 -0500 Subject: [PATCH 16/32] Working on yaml/git lfs --- build-tools/automation/yaml-templates/build-linux.yaml | 3 +++ build-tools/automation/yaml-templates/build-macos.yaml | 3 +++ build-tools/automation/yaml-templates/build-windows.yaml | 3 +++ 3 files changed, 9 insertions(+) diff --git a/build-tools/automation/yaml-templates/build-linux.yaml b/build-tools/automation/yaml-templates/build-linux.yaml index 08999e2f033..442ff65d88b 100644 --- a/build-tools/automation/yaml-templates/build-linux.yaml +++ b/build-tools/automation/yaml-templates/build-linux.yaml @@ -57,6 +57,9 @@ stages: # https://learn.microsoft.com/en-us/azure/devops/pipelines/repos/multi-repo-checkout?view=azure-devops#checkout-path - checkout: maui + - script: git lfs pull + displayName: git lfs pull + - template: /build-tools/automation/yaml-templates/setup-jdk-variables.yaml parameters: useAgentJdkPath: false diff --git a/build-tools/automation/yaml-templates/build-macos.yaml b/build-tools/automation/yaml-templates/build-macos.yaml index 58817ec76da..70bf00e9b65 100644 --- a/build-tools/automation/yaml-templates/build-macos.yaml +++ b/build-tools/automation/yaml-templates/build-macos.yaml @@ -75,6 +75,9 @@ stages: path: ${{ parameters.checkoutPath }} persistCredentials: ${{ parameters.checkoutPersistCredentials }} + - script: git lfs pull + displayName: git lfs pull + - template: /build-tools/automation/yaml-templates/commercial-build.yaml parameters: xaSourcePath: ${{ parameters.xaSourcePath }} diff --git a/build-tools/automation/yaml-templates/build-windows.yaml b/build-tools/automation/yaml-templates/build-windows.yaml index 95db7e69485..f2cfb032aa6 100644 --- a/build-tools/automation/yaml-templates/build-windows.yaml +++ b/build-tools/automation/yaml-templates/build-windows.yaml @@ -35,6 +35,9 @@ stages: path: ${{ parameters.checkoutPath }} persistCredentials: ${{ parameters.checkoutPersistCredentials }} + - script: git lfs pull + displayName: git lfs pull + - template: /build-tools/automation/yaml-templates/kill-processes.yaml - template: /build-tools/automation/yaml-templates/clean.yaml From 0221203df0e5ec1c5407c704f8c72c460d4cc298 Mon Sep 17 00:00:00 2001 From: Jonathan Peppers Date: Wed, 21 May 2025 10:26:20 -0500 Subject: [PATCH 17/32] git lfs working directory --- build-tools/automation/azure-pipelines.yaml | 3 --- build-tools/automation/yaml-templates/build-linux.yaml | 1 + build-tools/automation/yaml-templates/build-macos.yaml | 1 + build-tools/automation/yaml-templates/build-windows.yaml | 1 + 4 files changed, 3 insertions(+), 3 deletions(-) diff --git a/build-tools/automation/azure-pipelines.yaml b/build-tools/automation/azure-pipelines.yaml index 105f8914e3c..144c5aa2877 100644 --- a/build-tools/automation/azure-pipelines.yaml +++ b/build-tools/automation/azure-pipelines.yaml @@ -347,9 +347,6 @@ extends: clean: true submodules: recursive - - script: git lfs pull - displayName: git lfs pull - - template: /build-tools/automation/yaml-templates/use-dot-net.yaml@self parameters: version: $(DotNetPreviewSdkVersion) diff --git a/build-tools/automation/yaml-templates/build-linux.yaml b/build-tools/automation/yaml-templates/build-linux.yaml index 442ff65d88b..6b203196aaf 100644 --- a/build-tools/automation/yaml-templates/build-linux.yaml +++ b/build-tools/automation/yaml-templates/build-linux.yaml @@ -59,6 +59,7 @@ stages: - script: git lfs pull displayName: git lfs pull + workingDirectory: ${{ parameters.checkoutPath }} - template: /build-tools/automation/yaml-templates/setup-jdk-variables.yaml parameters: diff --git a/build-tools/automation/yaml-templates/build-macos.yaml b/build-tools/automation/yaml-templates/build-macos.yaml index 70bf00e9b65..d4efea67009 100644 --- a/build-tools/automation/yaml-templates/build-macos.yaml +++ b/build-tools/automation/yaml-templates/build-macos.yaml @@ -77,6 +77,7 @@ stages: - script: git lfs pull displayName: git lfs pull + workingDirectory: ${{ parameters.checkoutPath }} - template: /build-tools/automation/yaml-templates/commercial-build.yaml parameters: diff --git a/build-tools/automation/yaml-templates/build-windows.yaml b/build-tools/automation/yaml-templates/build-windows.yaml index f2cfb032aa6..89c4f5e099f 100644 --- a/build-tools/automation/yaml-templates/build-windows.yaml +++ b/build-tools/automation/yaml-templates/build-windows.yaml @@ -37,6 +37,7 @@ stages: - script: git lfs pull displayName: git lfs pull + workingDirectory: ${{ parameters.checkoutPath }} - template: /build-tools/automation/yaml-templates/kill-processes.yaml From c99018446479f3be29c993c60242e8559f8dc30d Mon Sep 17 00:00:00 2001 From: Jonathan Peppers Date: Wed, 21 May 2025 10:38:13 -0500 Subject: [PATCH 18/32] workingDirectory: ${{ parameters.xaSourcePath }} --- build-tools/automation/yaml-templates/build-linux.yaml | 8 ++++---- build-tools/automation/yaml-templates/build-macos.yaml | 2 +- build-tools/automation/yaml-templates/build-windows.yaml | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/build-tools/automation/yaml-templates/build-linux.yaml b/build-tools/automation/yaml-templates/build-linux.yaml index 6b203196aaf..8e38e5d2fc3 100644 --- a/build-tools/automation/yaml-templates/build-linux.yaml +++ b/build-tools/automation/yaml-templates/build-linux.yaml @@ -53,14 +53,14 @@ stages: path: ${{ parameters.checkoutPath }} persistCredentials: ${{ parameters.checkoutPersistCredentials }} + - script: git lfs pull + displayName: git lfs pull + workingDirectory: ${{ parameters.xaSourcePath }} + # Always checkout a second resource to ensure we are using multi-repo checkout behavior # https://learn.microsoft.com/en-us/azure/devops/pipelines/repos/multi-repo-checkout?view=azure-devops#checkout-path - checkout: maui - - script: git lfs pull - displayName: git lfs pull - workingDirectory: ${{ parameters.checkoutPath }} - - template: /build-tools/automation/yaml-templates/setup-jdk-variables.yaml parameters: useAgentJdkPath: false diff --git a/build-tools/automation/yaml-templates/build-macos.yaml b/build-tools/automation/yaml-templates/build-macos.yaml index d4efea67009..f5a3388e549 100644 --- a/build-tools/automation/yaml-templates/build-macos.yaml +++ b/build-tools/automation/yaml-templates/build-macos.yaml @@ -77,7 +77,7 @@ stages: - script: git lfs pull displayName: git lfs pull - workingDirectory: ${{ parameters.checkoutPath }} + workingDirectory: ${{ parameters.xaSourcePath }} - template: /build-tools/automation/yaml-templates/commercial-build.yaml parameters: diff --git a/build-tools/automation/yaml-templates/build-windows.yaml b/build-tools/automation/yaml-templates/build-windows.yaml index 89c4f5e099f..8fca0e97cdb 100644 --- a/build-tools/automation/yaml-templates/build-windows.yaml +++ b/build-tools/automation/yaml-templates/build-windows.yaml @@ -37,7 +37,7 @@ stages: - script: git lfs pull displayName: git lfs pull - workingDirectory: ${{ parameters.checkoutPath }} + workingDirectory: ${{ parameters.xaSourcePath }} - template: /build-tools/automation/yaml-templates/kill-processes.yaml From f42f32833356f548b182d903400d47e4a9e3b85e Mon Sep 17 00:00:00 2001 From: Jonathan Peppers Date: Wed, 21 May 2025 11:56:06 -0500 Subject: [PATCH 19/32] `git lfs install` Skipping object checkout, Git LFS is not installed for this repository. Consider installing it with 'git lfs install'. --- build-tools/automation/yaml-templates/build-linux.yaml | 6 ++++-- build-tools/automation/yaml-templates/build-macos.yaml | 6 ++++-- build-tools/automation/yaml-templates/build-windows.yaml | 6 ++++-- 3 files changed, 12 insertions(+), 6 deletions(-) diff --git a/build-tools/automation/yaml-templates/build-linux.yaml b/build-tools/automation/yaml-templates/build-linux.yaml index 8e38e5d2fc3..ce1dc15b94e 100644 --- a/build-tools/automation/yaml-templates/build-linux.yaml +++ b/build-tools/automation/yaml-templates/build-linux.yaml @@ -53,8 +53,10 @@ stages: path: ${{ parameters.checkoutPath }} persistCredentials: ${{ parameters.checkoutPersistCredentials }} - - script: git lfs pull - displayName: git lfs pull + - script: | + git lfs install + git lfs pull + displayName: git lfs setup workingDirectory: ${{ parameters.xaSourcePath }} # Always checkout a second resource to ensure we are using multi-repo checkout behavior diff --git a/build-tools/automation/yaml-templates/build-macos.yaml b/build-tools/automation/yaml-templates/build-macos.yaml index f5a3388e549..81ad7e53f25 100644 --- a/build-tools/automation/yaml-templates/build-macos.yaml +++ b/build-tools/automation/yaml-templates/build-macos.yaml @@ -75,8 +75,10 @@ stages: path: ${{ parameters.checkoutPath }} persistCredentials: ${{ parameters.checkoutPersistCredentials }} - - script: git lfs pull - displayName: git lfs pull + - script: | + git lfs install + git lfs pull + displayName: git lfs setup workingDirectory: ${{ parameters.xaSourcePath }} - template: /build-tools/automation/yaml-templates/commercial-build.yaml diff --git a/build-tools/automation/yaml-templates/build-windows.yaml b/build-tools/automation/yaml-templates/build-windows.yaml index 8fca0e97cdb..a3dff0a04f0 100644 --- a/build-tools/automation/yaml-templates/build-windows.yaml +++ b/build-tools/automation/yaml-templates/build-windows.yaml @@ -35,8 +35,10 @@ stages: path: ${{ parameters.checkoutPath }} persistCredentials: ${{ parameters.checkoutPersistCredentials }} - - script: git lfs pull - displayName: git lfs pull + - script: | + git lfs install + git lfs pull + displayName: git lfs setup workingDirectory: ${{ parameters.xaSourcePath }} - template: /build-tools/automation/yaml-templates/kill-processes.yaml From 0ebf234d257df7f73dc7cad997c998389f26e18d Mon Sep 17 00:00:00 2001 From: Jonathan Peppers Date: Wed, 21 May 2025 14:53:25 -0500 Subject: [PATCH 20/32] [native\mono] use `JniObjectReferenceControlBlock` structure Context: https://github.com/dotnet/java-interop/compare/d07ed327dbd4477f0eab5d277b92fd4f57bfb893...174fd85c7fd5c81d48554c89afa7e5b618348160 Changes to make Mono's GC bridge use the new `JniObjectReferenceControlBlock` structure. --- src/native/mono/monodroid/monodroid-glue.cc | 17 ++--- src/native/mono/monodroid/osbridge.cc | 85 ++++++++++++--------- src/native/mono/monodroid/osbridge.hh | 13 +++- 3 files changed, 66 insertions(+), 49 deletions(-) diff --git a/src/native/mono/monodroid/monodroid-glue.cc b/src/native/mono/monodroid/monodroid-glue.cc index d8c722f48f2..8bf9b2a62ff 100644 --- a/src/native/mono/monodroid/monodroid-glue.cc +++ b/src/native/mono/monodroid/monodroid-glue.cc @@ -793,22 +793,19 @@ MonodroidRuntime::create_domain (JNIEnv *env, jstring_array_wrapper &runtimeApks MonodroidRuntime::lookup_bridge_info (MonoClass *klass, const OSBridge::MonoJavaGCBridgeType *type, OSBridge::MonoJavaGCBridgeInfo *info) noexcept { info->klass = klass; - info->handle = mono_class_get_field_from_name (info->klass, const_cast ("handle")); - info->handle_type = mono_class_get_field_from_name (info->klass, const_cast ("handle_type")); - info->refs_added = mono_class_get_field_from_name (info->klass, const_cast ("refs_added")); - info->key_handle = mono_class_get_field_from_name (info->klass, const_cast ("key_handle")); + info->jniObjectReferenceControlBlock = mono_class_get_field_from_name (info->klass, const_cast ("jniObjectReferenceControlBlock")); // key_handle is optional, as Java.Interop.JavaObject doesn't currently have it - if (info->klass == nullptr || info->handle == nullptr || info->handle_type == nullptr || info->refs_added == nullptr) { + if (info->klass == nullptr || ((OSBridge::JniObjectReferenceControlBlock*)info->jniObjectReferenceControlBlock)->handle == nullptr || ((OSBridge::JniObjectReferenceControlBlock*)info->jniObjectReferenceControlBlock)->handle_type == 0 || ((OSBridge::JniObjectReferenceControlBlock*)info->jniObjectReferenceControlBlock)->refs_added == 0) { Helpers::abort_application ( Util::monodroid_strdup_printf ( - "The type `%s.%s` is missing required instance fields! handle=%p handle_type=%p refs_added=%p key_handle=%p", + "The type `%s.%s` is missing required instance fields! handle=%p handle_type=%p refs_added=%p weak_handle=%p", type->_namespace, type->_typename, - info->handle, - info->handle_type, - info->refs_added, - info->key_handle + ((OSBridge::JniObjectReferenceControlBlock*)info->jniObjectReferenceControlBlock)->handle, + ((OSBridge::JniObjectReferenceControlBlock*)info->jniObjectReferenceControlBlock)->handle_type, + ((OSBridge::JniObjectReferenceControlBlock*)info->jniObjectReferenceControlBlock)->refs_added, + ((OSBridge::JniObjectReferenceControlBlock*)info->jniObjectReferenceControlBlock)->weak_handle ) ); } diff --git a/src/native/mono/monodroid/osbridge.cc b/src/native/mono/monodroid/osbridge.cc index 919506d3fda..f2f13afff71 100644 --- a/src/native/mono/monodroid/osbridge.cc +++ b/src/native/mono/monodroid/osbridge.cc @@ -42,9 +42,6 @@ const uint32_t OSBridge::NUM_GC_BRIDGE_TYPES = NUM_XA_GC_BRIDGE_TYPES + NUM_J OSBridge::MonoJavaGCBridgeInfo OSBridge::mono_java_gc_bridge_info [NUM_GC_BRIDGE_TYPES]; OSBridge::MonoJavaGCBridgeInfo OSBridge::empty_bridge_info = { - nullptr, - nullptr, - nullptr, nullptr, nullptr }; @@ -76,9 +73,12 @@ OSBridge::clear_mono_java_gc_bridge_info () for (uint32_t c = 0; c < NUM_GC_BRIDGE_TYPES; c++) { MonoJavaGCBridgeInfo *info = &mono_java_gc_bridge_info [c]; info->klass = nullptr; - info->handle = nullptr; - info->handle_type = nullptr; - info->refs_added = nullptr; + JniObjectReferenceControlBlock *control_block = (JniObjectReferenceControlBlock*) info->jniObjectReferenceControlBlock; + if (control_block == nullptr) + continue; + control_block->handle = nullptr; + control_block->handle_type = 0; + control_block->refs_added = 0; } } @@ -102,6 +102,18 @@ OSBridge::get_gc_bridge_index (MonoClass *klass) : -1; } +OSBridge::JniObjectReferenceControlBlock* +OSBridge::get_gc_control_block_for_object (MonoObject *obj) +{ + MonoJavaGCBridgeInfo *bridge_info = get_gc_bridge_info_for_object (obj); + if (bridge_info == nullptr) + return nullptr; + + JniObjectReferenceControlBlock *control_block; + mono_field_get_value (obj, bridge_info->jniObjectReferenceControlBlock, &control_block); + return control_block; +} + OSBridge::MonoJavaGCBridgeInfo * OSBridge::get_gc_bridge_info_for_class (MonoClass *klass) { @@ -459,11 +471,11 @@ OSBridge::take_global_ref_jni (JNIEnv *env, MonoObject *obj) jobject handle, weak; int type = JNIGlobalRefType; - MonoJavaGCBridgeInfo *bridge_info = get_gc_bridge_info_for_object (obj); - if (bridge_info == nullptr) + JniObjectReferenceControlBlock *control_block = get_gc_control_block_for_object (obj); + if (control_block == nullptr) return 0; - mono_field_get_value (obj, bridge_info->handle, &weak); + mono_field_get_value (obj, (MonoClassField*) control_block->handle, &weak); handle = env->NewGlobalRef (weak); if (gref_log) { fprintf (gref_log, "*try_take_global obj=%p -> wref=%p handle=%p\n", obj, weak, handle); @@ -476,8 +488,8 @@ OSBridge::take_global_ref_jni (JNIEnv *env, MonoObject *obj) " at [[gc:take_global_ref_jni]]", 0); } else if (Logger::gc_spew_enabled ()) [[unlikely]] { void *key_handle = nullptr; - if (bridge_info->key_handle) { - mono_field_get_value (obj, bridge_info->key_handle, &key_handle); + if (control_block->weak_handle) { + mono_field_get_value (obj, (MonoClassField*) control_block->weak_handle, &key_handle); } MonoClass *klass = mono_object_get_class (obj); @@ -491,8 +503,8 @@ OSBridge::take_global_ref_jni (JNIEnv *env, MonoObject *obj) free (message); } - mono_field_set_value (obj, bridge_info->handle, &handle); - mono_field_set_value (obj, bridge_info->handle_type, &type); + mono_field_set_value (obj, (MonoClassField*) control_block->handle, &handle); + mono_field_set_value (obj, (MonoClassField*) control_block->handle_type, &type); _monodroid_weak_gref_delete (weak, get_object_ref_type (env, weak), "finalizer", gettid (), " at [[gc:take_global_ref_jni]]", 0); @@ -507,11 +519,11 @@ OSBridge::take_weak_global_ref_jni (JNIEnv *env, MonoObject *obj) jobject handle, weak; int type = JNIWeakGlobalRefType; - MonoJavaGCBridgeInfo *bridge_info = get_gc_bridge_info_for_object (obj); - if (bridge_info == nullptr) + JniObjectReferenceControlBlock *control_block = get_gc_control_block_for_object (obj); + if (control_block == nullptr) return 0; - mono_field_get_value (obj, bridge_info->handle, &handle); + mono_field_get_value (obj, (MonoClassField*) control_block->handle, &handle); if (gref_log) { fprintf (gref_log, "*take_weak obj=%p; handle=%p\n", obj, handle); fflush (gref_log); @@ -522,8 +534,8 @@ OSBridge::take_weak_global_ref_jni (JNIEnv *env, MonoObject *obj) weak, get_object_ref_type (env, weak), "finalizer", gettid (), " at [[gc:take_weak_global_ref_jni]]", 0); - mono_field_set_value (obj, bridge_info->handle, &weak); - mono_field_set_value (obj, bridge_info->handle_type, &type); + mono_field_set_value (obj, (MonoClassField*) control_block->handle, &weak); + mono_field_set_value (obj, (MonoClassField*) control_block->handle_type, &type); _monodroid_gref_log_delete (handle, get_object_ref_type (env, handle), "finalizer", gettid (), " at [[gc:take_weak_global_ref_jni]]", 0); @@ -560,11 +572,11 @@ OSBridge::gc_is_bridge_object (MonoObject *object) { void *handle; - MonoJavaGCBridgeInfo *bridge_info = get_gc_bridge_info_for_object (object); - if (bridge_info == nullptr) + JniObjectReferenceControlBlock *control_block = get_gc_control_block_for_object (object); + if (control_block == nullptr) return 0; - mono_field_get_value (object, bridge_info->handle, &handle); + mono_field_get_value (object, (MonoClassField*) control_block->handle, &handle); if (handle == nullptr) { #if DEBUG MonoClass *mclass = mono_object_get_class (object); @@ -604,10 +616,10 @@ mono_bool OSBridge::load_reference_target (OSBridge::AddReferenceTarget target, OSBridge::MonoJavaGCBridgeInfo** bridge_info, jobject *handle) { if (target.is_mono_object) { - *bridge_info = get_gc_bridge_info_for_object (target.obj); - if (!*bridge_info) + JniObjectReferenceControlBlock *control_block = get_gc_control_block_for_object (target.obj); + if (control_block == nullptr) return FALSE; - mono_field_get_value (target.obj, (*bridge_info)->handle, handle); + mono_field_get_value (target.obj, (MonoClassField*) control_block->handle, handle); } else { *handle = target.jobj; } @@ -649,7 +661,10 @@ OSBridge::add_reference (JNIEnv *env, OSBridge::AddReferenceTarget target, OSBri // Java temporaries do not need this because the entire GCUserPeer is discarded. if (success && target.is_mono_object) { int ref_val = 1; - mono_field_set_value (target.obj, bridge_info->refs_added, &ref_val); + JniObjectReferenceControlBlock *control_block = get_gc_control_block_for_object (target.obj); + if (control_block == nullptr) + return FALSE; + mono_field_set_value (target.obj, (MonoClassField*) control_block->refs_added, &ref_val); } #if DEBUG @@ -867,14 +882,14 @@ OSBridge::gc_cleanup_after_java_collection (JNIEnv *env, int num_sccs, MonoGCBri sccs [i]->is_alive = 0; for (j = 0; j < sccs [i]->num_objs; j++) { - MonoJavaGCBridgeInfo *bridge_info; + JniObjectReferenceControlBlock *control_block; obj = sccs [i]->objs [j]; - bridge_info = get_gc_bridge_info_for_object (obj); - if (bridge_info == nullptr) + control_block = get_gc_control_block_for_object (obj); + if (control_block == nullptr) continue; - mono_field_get_value (obj, bridge_info->handle, &jref); + mono_field_get_value (obj, (MonoClassField*) control_block->handle, &jref); if (jref) { alive++; if (j > 0) { @@ -884,7 +899,7 @@ OSBridge::gc_cleanup_after_java_collection (JNIEnv *env, int num_sccs, MonoGCBri ); } sccs [i]->is_alive = 1; - mono_field_get_value (obj, bridge_info->refs_added, &refs_added); + mono_field_get_value (obj, (MonoClassField*) control_block->refs_added, &refs_added); if (refs_added) { jclass java_class = env->GetObjectClass (jref); clear_method_id = env->GetMethodID (java_class, "monodroidClearReferences", "()V"); @@ -951,13 +966,13 @@ OSBridge::gc_cross_references (int num_sccs, MonoGCBridgeSCC **sccs, int num_xre for (j = 0; j < sccs [i]->num_objs; ++j) { MonoObject *obj = sccs [i]->objs [j]; - MonoJavaGCBridgeInfo *bridge_info = get_gc_bridge_info_for_object (obj); + JniObjectReferenceControlBlock *control_block = get_gc_control_block_for_object (obj); jobject handle = 0; void *key_handle = nullptr; - if (bridge_info != nullptr) { - mono_field_get_value (obj, bridge_info->handle, &handle); - if (bridge_info->key_handle != nullptr) { - mono_field_get_value (obj, bridge_info->key_handle, &key_handle); + if (control_block != nullptr) { + mono_field_get_value (obj, (MonoClassField*) control_block->handle, &handle); + if (control_block->weak_handle != nullptr) { + mono_field_get_value (obj, (MonoClassField*) control_block->weak_handle, &key_handle); } } MonoClass *klass = mono_object_get_class (obj); diff --git a/src/native/mono/monodroid/osbridge.hh b/src/native/mono/monodroid/osbridge.hh index 46f4af69ef8..f39b2e26a8a 100644 --- a/src/native/mono/monodroid/osbridge.hh +++ b/src/native/mono/monodroid/osbridge.hh @@ -37,12 +37,16 @@ namespace xamarin::android::internal struct MonoJavaGCBridgeInfo { MonoClass *klass; - MonoClassField *handle; - MonoClassField *handle_type; - MonoClassField *refs_added; - MonoClassField *key_handle; + MonoClassField *jniObjectReferenceControlBlock; }; + typedef struct JniObjectReferenceControlBlock { + jobject handle; + int handle_type; + jobject weak_handle; + int refs_added; + } JniObjectReferenceControlBlock; + // add_reference can work with objects which are either MonoObjects with java peers, or raw jobjects struct AddReferenceTarget { @@ -127,6 +131,7 @@ namespace xamarin::android::internal private: int get_gc_bridge_index (MonoClass *klass); + JniObjectReferenceControlBlock* get_gc_control_block_for_object (MonoObject *obj); MonoJavaGCBridgeInfo* get_gc_bridge_info_for_class (MonoClass *klass); MonoJavaGCBridgeInfo* get_gc_bridge_info_for_object (MonoObject *object); char get_object_ref_type (JNIEnv *env, void *handle); From ba60ff78eb5111c58ee45c1cf7cc164251577d31 Mon Sep 17 00:00:00 2001 From: Jonathan Peppers Date: Wed, 21 May 2025 15:21:13 -0500 Subject: [PATCH 21/32] Update to APIs from BrzVlad's branch Context: https://github.com/dotnet/runtime/compare/main...BrzVlad:runtime:feature-clr-gcbridge --- .../Android.Runtime/RuntimeNativeMethods.cs | 4 ++-- .../ManagedValueManager.cs | 17 +++++++++++++---- src/native/clr/host/gc-bridge.cc | 4 ++-- src/native/clr/include/host/gc-bridge.hh | 12 ++++++++++-- 4 files changed, 27 insertions(+), 10 deletions(-) diff --git a/src/Mono.Android/Android.Runtime/RuntimeNativeMethods.cs b/src/Mono.Android/Android.Runtime/RuntimeNativeMethods.cs index 13a55b90319..f8cb8e95f17 100644 --- a/src/Mono.Android/Android.Runtime/RuntimeNativeMethods.cs +++ b/src/Mono.Android/Android.Runtime/RuntimeNativeMethods.cs @@ -100,8 +100,8 @@ internal unsafe static class RuntimeNativeMethods /// A function pointer to a C# callback that will be invoked when bridge processing has completed. /// A function pointer that should be passed to JavaMarshal.Initialize() on startup. [DllImport (RuntimeConstants.InternalDllName, CallingConvention = CallingConvention.Cdecl)] - internal static extern delegate* unmanaged clr_initialize_gc_bridge ( - delegate* unmanaged bridge_processing_finished_callback + internal static extern delegate* unmanaged clr_initialize_gc_bridge ( + delegate* unmanaged bridge_processing_finished_callback ); [MethodImplAttribute(MethodImplOptions.InternalCall)] diff --git a/src/Mono.Android/Microsoft.Android.Runtime/ManagedValueManager.cs b/src/Mono.Android/Microsoft.Android.Runtime/ManagedValueManager.cs index 265217765d8..2b4d5f5ffff 100644 --- a/src/Mono.Android/Microsoft.Android.Runtime/ManagedValueManager.cs +++ b/src/Mono.Android/Microsoft.Android.Runtime/ManagedValueManager.cs @@ -277,11 +277,20 @@ static unsafe void FreeHandle (GCHandle handle) } [UnmanagedCallersOnly] - internal static unsafe void BridgeProcessingFinished (nint sccsLen, StronglyConnectedComponent* sccs, nint ccrsLen, ComponentCrossReference* ccrs) + internal static unsafe void BridgeProcessingFinished (MarkCrossReferences* mcr) { - JavaMarshal.ReleaseMarkCrossReferenceResources ( - new Span (sccs, (int) sccsLen), - new Span (ccrs, (int) ccrsLen)); + List handlesToFree = []; + for (int i = 0; i < mcr->ComponentsLen; i++) + { + for (int j = 0; j < mcr->Components [i].Count; j++) + { + IntPtr *pContext = (IntPtr*) mcr->Components [i].Context [j]; + handlesToFree.Add (GCHandle.FromIntPtr (*pContext)); + NativeMemory.Free (pContext); + } + } + + JavaMarshal.FinishCrossReferenceProcessing (mcr, CollectionsMarshal.AsSpan (handlesToFree)); } const BindingFlags ActivationConstructorBindingFlags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance; diff --git a/src/native/clr/host/gc-bridge.cc b/src/native/clr/host/gc-bridge.cc index 176d0f371e5..c03da967d99 100644 --- a/src/native/clr/host/gc-bridge.cc +++ b/src/native/clr/host/gc-bridge.cc @@ -31,7 +31,7 @@ void GCBridge::trigger_java_gc () noexcept env->CallVoidMethod (Runtime_instance, Runtime_gc); } -void GCBridge::mark_cross_references (size_t sccsLen, StronglyConnectedComponent* sccs, size_t ccrsLen, ComponentCrossReference* ccrs) noexcept +void GCBridge::mark_cross_references (MarkCrossReferences* crossRefs) noexcept { if (bridge_processing_finish_callback == nullptr) [[unlikely]] { return; @@ -40,5 +40,5 @@ void GCBridge::mark_cross_references (size_t sccsLen, StronglyConnectedComponent trigger_java_gc (); // Call back into managed code - bridge_processing_finish_callback (sccsLen, sccs, ccrsLen, ccrs); + bridge_processing_finish_callback (crossRefs); } diff --git a/src/native/clr/include/host/gc-bridge.hh b/src/native/clr/include/host/gc-bridge.hh index b93c3b135a5..e472f733256 100644 --- a/src/native/clr/include/host/gc-bridge.hh +++ b/src/native/clr/include/host/gc-bridge.hh @@ -16,7 +16,15 @@ struct ComponentCrossReference size_t DestinationGroupIndex; }; -using MarkCrossReferencesFtn = void (*)(size_t, StronglyConnectedComponent*, size_t, ComponentCrossReference*); +struct MarkCrossReferences +{ + size_t ComponentsLen; + StronglyConnectedComponent* Components; + size_t CrossReferencesLen; + ComponentCrossReference* CrossReferences; +}; + +using MarkCrossReferencesFtn = void (*)(MarkCrossReferences*); namespace xamarin::android { class GCBridge @@ -24,7 +32,7 @@ namespace xamarin::android { public: static void initialize_on_load (JNIEnv *env) noexcept; static void trigger_java_gc () noexcept; - static void mark_cross_references (size_t sccsLen, StronglyConnectedComponent* sccs, size_t ccrsLen, ComponentCrossReference* ccrs) noexcept; + static void mark_cross_references (MarkCrossReferences* crossRefs) noexcept; static void set_finish_callback (MarkCrossReferencesFtn callback) noexcept { From 02c25626c6a2c85792f38d882aa2dd558d253c14 Mon Sep 17 00:00:00 2001 From: Marek Habersack Date: Wed, 21 May 2025 22:42:18 +0200 Subject: [PATCH 22/32] Some updates to the recent native code changes --- src/native/mono/monodroid/monodroid-glue.cc | 13 ++-- src/native/mono/monodroid/osbridge.cc | 72 +++++++++++---------- src/native/mono/monodroid/osbridge.hh | 5 +- 3 files changed, 47 insertions(+), 43 deletions(-) diff --git a/src/native/mono/monodroid/monodroid-glue.cc b/src/native/mono/monodroid/monodroid-glue.cc index 8bf9b2a62ff..c82db0a78c6 100644 --- a/src/native/mono/monodroid/monodroid-glue.cc +++ b/src/native/mono/monodroid/monodroid-glue.cc @@ -793,19 +793,16 @@ MonodroidRuntime::create_domain (JNIEnv *env, jstring_array_wrapper &runtimeApks MonodroidRuntime::lookup_bridge_info (MonoClass *klass, const OSBridge::MonoJavaGCBridgeType *type, OSBridge::MonoJavaGCBridgeInfo *info) noexcept { info->klass = klass; - info->jniObjectReferenceControlBlock = mono_class_get_field_from_name (info->klass, const_cast ("jniObjectReferenceControlBlock")); + info->jniObjectReferenceControlBlock = mono_class_get_field_from_name (info->klass, const_cast("jniObjectReferenceControlBlock")); // key_handle is optional, as Java.Interop.JavaObject doesn't currently have it - if (info->klass == nullptr || ((OSBridge::JniObjectReferenceControlBlock*)info->jniObjectReferenceControlBlock)->handle == nullptr || ((OSBridge::JniObjectReferenceControlBlock*)info->jniObjectReferenceControlBlock)->handle_type == 0 || ((OSBridge::JniObjectReferenceControlBlock*)info->jniObjectReferenceControlBlock)->refs_added == 0) { + if (info->klass == nullptr || info->jniObjectReferenceControlBlock == nullptr) { Helpers::abort_application ( - Util::monodroid_strdup_printf ( - "The type `%s.%s` is missing required instance fields! handle=%p handle_type=%p refs_added=%p weak_handle=%p", + std::format ( + "The type `{}.{} is missing required instance fields! jniObjectReferenceControlBlock={:p}", type->_namespace, type->_typename, - ((OSBridge::JniObjectReferenceControlBlock*)info->jniObjectReferenceControlBlock)->handle, - ((OSBridge::JniObjectReferenceControlBlock*)info->jniObjectReferenceControlBlock)->handle_type, - ((OSBridge::JniObjectReferenceControlBlock*)info->jniObjectReferenceControlBlock)->refs_added, - ((OSBridge::JniObjectReferenceControlBlock*)info->jniObjectReferenceControlBlock)->weak_handle + static_cast(info->jniObjectReferenceControlBlock) ) ); } diff --git a/src/native/mono/monodroid/osbridge.cc b/src/native/mono/monodroid/osbridge.cc index f2f13afff71..16793ebbdb2 100644 --- a/src/native/mono/monodroid/osbridge.cc +++ b/src/native/mono/monodroid/osbridge.cc @@ -73,9 +73,10 @@ OSBridge::clear_mono_java_gc_bridge_info () for (uint32_t c = 0; c < NUM_GC_BRIDGE_TYPES; c++) { MonoJavaGCBridgeInfo *info = &mono_java_gc_bridge_info [c]; info->klass = nullptr; - JniObjectReferenceControlBlock *control_block = (JniObjectReferenceControlBlock*) info->jniObjectReferenceControlBlock; - if (control_block == nullptr) + auto control_block = reinterpret_cast(info->jniObjectReferenceControlBlock); + if (control_block == nullptr) [[unlikely]] { continue; + } control_block->handle = nullptr; control_block->handle_type = 0; control_block->refs_added = 0; @@ -105,11 +106,12 @@ OSBridge::get_gc_bridge_index (MonoClass *klass) OSBridge::JniObjectReferenceControlBlock* OSBridge::get_gc_control_block_for_object (MonoObject *obj) { - MonoJavaGCBridgeInfo *bridge_info = get_gc_bridge_info_for_object (obj); - if (bridge_info == nullptr) + MonoJavaGCBridgeInfo *bridge_info = get_gc_bridge_info_for_object (obj); + if (bridge_info == nullptr) { return nullptr; + } - JniObjectReferenceControlBlock *control_block; + JniObjectReferenceControlBlock *control_block = nullptr; mono_field_get_value (obj, bridge_info->jniObjectReferenceControlBlock, &control_block); return control_block; } @@ -471,11 +473,12 @@ OSBridge::take_global_ref_jni (JNIEnv *env, MonoObject *obj) jobject handle, weak; int type = JNIGlobalRefType; - JniObjectReferenceControlBlock *control_block = get_gc_control_block_for_object (obj); - if (control_block == nullptr) + JniObjectReferenceControlBlock *control_block = get_gc_control_block_for_object (obj); + if (control_block == nullptr) { return 0; + } - mono_field_get_value (obj, (MonoClassField*) control_block->handle, &weak); + mono_field_get_value (obj, reinterpret_cast(control_block->handle), &weak); handle = env->NewGlobalRef (weak); if (gref_log) { fprintf (gref_log, "*try_take_global obj=%p -> wref=%p handle=%p\n", obj, weak, handle); @@ -489,7 +492,7 @@ OSBridge::take_global_ref_jni (JNIEnv *env, MonoObject *obj) } else if (Logger::gc_spew_enabled ()) [[unlikely]] { void *key_handle = nullptr; if (control_block->weak_handle) { - mono_field_get_value (obj, (MonoClassField*) control_block->weak_handle, &key_handle); + mono_field_get_value (obj, reinterpret_cast(control_block->weak_handle), &key_handle); } MonoClass *klass = mono_object_get_class (obj); @@ -503,8 +506,8 @@ OSBridge::take_global_ref_jni (JNIEnv *env, MonoObject *obj) free (message); } - mono_field_set_value (obj, (MonoClassField*) control_block->handle, &handle); - mono_field_set_value (obj, (MonoClassField*) control_block->handle_type, &type); + mono_field_set_value (obj, reinterpret_cast(control_block->handle), &handle); + mono_field_set_value (obj, reinterpret_cast(control_block->handle_type), &type); _monodroid_weak_gref_delete (weak, get_object_ref_type (env, weak), "finalizer", gettid (), " at [[gc:take_global_ref_jni]]", 0); @@ -519,11 +522,12 @@ OSBridge::take_weak_global_ref_jni (JNIEnv *env, MonoObject *obj) jobject handle, weak; int type = JNIWeakGlobalRefType; - JniObjectReferenceControlBlock *control_block = get_gc_control_block_for_object (obj); - if (control_block == nullptr) + JniObjectReferenceControlBlock *control_block = get_gc_control_block_for_object (obj); + if (control_block == nullptr) { return 0; + } - mono_field_get_value (obj, (MonoClassField*) control_block->handle, &handle); + mono_field_get_value (obj, reinterpret_cast(control_block->handle), &handle); if (gref_log) { fprintf (gref_log, "*take_weak obj=%p; handle=%p\n", obj, handle); fflush (gref_log); @@ -534,8 +538,8 @@ OSBridge::take_weak_global_ref_jni (JNIEnv *env, MonoObject *obj) weak, get_object_ref_type (env, weak), "finalizer", gettid (), " at [[gc:take_weak_global_ref_jni]]", 0); - mono_field_set_value (obj, (MonoClassField*) control_block->handle, &weak); - mono_field_set_value (obj, (MonoClassField*) control_block->handle_type, &type); + mono_field_set_value (obj, reinterpret_cast(control_block->handle), &weak); + mono_field_set_value (obj, reinterpret_cast(control_block->handle_type), &type); _monodroid_gref_log_delete (handle, get_object_ref_type (env, handle), "finalizer", gettid (), " at [[gc:take_weak_global_ref_jni]]", 0); @@ -572,11 +576,12 @@ OSBridge::gc_is_bridge_object (MonoObject *object) { void *handle; - JniObjectReferenceControlBlock *control_block = get_gc_control_block_for_object (object); - if (control_block == nullptr) + JniObjectReferenceControlBlock *control_block = get_gc_control_block_for_object (object); + if (control_block == nullptr) { return 0; + } - mono_field_get_value (object, (MonoClassField*) control_block->handle, &handle); + mono_field_get_value (object, reinterpret_cast(control_block->handle), &handle); if (handle == nullptr) { #if DEBUG MonoClass *mclass = mono_object_get_class (object); @@ -616,10 +621,11 @@ mono_bool OSBridge::load_reference_target (OSBridge::AddReferenceTarget target, OSBridge::MonoJavaGCBridgeInfo** bridge_info, jobject *handle) { if (target.is_mono_object) { - JniObjectReferenceControlBlock *control_block = get_gc_control_block_for_object (target.obj); - if (control_block == nullptr) + JniObjectReferenceControlBlock *control_block = get_gc_control_block_for_object (target.obj); + if (control_block == nullptr) { return FALSE; - mono_field_get_value (target.obj, (MonoClassField*) control_block->handle, handle); + } + mono_field_get_value (target.obj, reinterpret_cast(control_block->handle), handle); } else { *handle = target.jobj; } @@ -661,10 +667,11 @@ OSBridge::add_reference (JNIEnv *env, OSBridge::AddReferenceTarget target, OSBri // Java temporaries do not need this because the entire GCUserPeer is discarded. if (success && target.is_mono_object) { int ref_val = 1; - JniObjectReferenceControlBlock *control_block = get_gc_control_block_for_object (target.obj); - if (control_block == nullptr) + JniObjectReferenceControlBlock *control_block = get_gc_control_block_for_object (target.obj); + if (control_block == nullptr) { return FALSE; - mono_field_set_value (target.obj, (MonoClassField*) control_block->refs_added, &ref_val); + } + mono_field_set_value (target.obj, reinterpret_cast(control_block->refs_added), &ref_val); } #if DEBUG @@ -882,14 +889,13 @@ OSBridge::gc_cleanup_after_java_collection (JNIEnv *env, int num_sccs, MonoGCBri sccs [i]->is_alive = 0; for (j = 0; j < sccs [i]->num_objs; j++) { - JniObjectReferenceControlBlock *control_block; - obj = sccs [i]->objs [j]; - control_block = get_gc_control_block_for_object (obj); - if (control_block == nullptr) + JniObjectReferenceControlBlock *control_block = get_gc_control_block_for_object (obj); + if (control_block == nullptr) { continue; - mono_field_get_value (obj, (MonoClassField*) control_block->handle, &jref); + } + mono_field_get_value (obj, reinterpret_cast(control_block->handle), &jref); if (jref) { alive++; if (j > 0) { @@ -966,13 +972,13 @@ OSBridge::gc_cross_references (int num_sccs, MonoGCBridgeSCC **sccs, int num_xre for (j = 0; j < sccs [i]->num_objs; ++j) { MonoObject *obj = sccs [i]->objs [j]; - JniObjectReferenceControlBlock *control_block = get_gc_control_block_for_object (obj); + JniObjectReferenceControlBlock *control_block = get_gc_control_block_for_object (obj); jobject handle = 0; void *key_handle = nullptr; if (control_block != nullptr) { - mono_field_get_value (obj, (MonoClassField*) control_block->handle, &handle); + mono_field_get_value (obj, reinterpret_cast(control_block->handle), &handle); if (control_block->weak_handle != nullptr) { - mono_field_get_value (obj, (MonoClassField*) control_block->weak_handle, &key_handle); + mono_field_get_value (obj, reinterpret_cast(control_block->weak_handle), &key_handle); } } MonoClass *klass = mono_object_get_class (obj); diff --git a/src/native/mono/monodroid/osbridge.hh b/src/native/mono/monodroid/osbridge.hh index f39b2e26a8a..f439a57aedd 100644 --- a/src/native/mono/monodroid/osbridge.hh +++ b/src/native/mono/monodroid/osbridge.hh @@ -40,12 +40,13 @@ namespace xamarin::android::internal MonoClassField *jniObjectReferenceControlBlock; }; - typedef struct JniObjectReferenceControlBlock { + struct JniObjectReferenceControlBlock + { jobject handle; int handle_type; jobject weak_handle; int refs_added; - } JniObjectReferenceControlBlock; + }; // add_reference can work with objects which are either MonoObjects with java peers, or raw jobjects struct AddReferenceTarget From 664be1a26eff6a000c532500858f8e24971aea33 Mon Sep 17 00:00:00 2001 From: Jonathan Peppers Date: Wed, 21 May 2025 16:12:24 -0500 Subject: [PATCH 23/32] android-x64 runtime pack --- .../Microsoft.NETCore.App.Runtime.android-x64.10.0.0-dev.nupkg | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 packages/Microsoft.NETCore.App.Runtime.android-x64.10.0.0-dev.nupkg diff --git a/packages/Microsoft.NETCore.App.Runtime.android-x64.10.0.0-dev.nupkg b/packages/Microsoft.NETCore.App.Runtime.android-x64.10.0.0-dev.nupkg new file mode 100644 index 00000000000..3a361daf778 --- /dev/null +++ b/packages/Microsoft.NETCore.App.Runtime.android-x64.10.0.0-dev.nupkg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:78a57312c28961bb0e36aea2ae337dc57141652b58723f0229014e13cb3826b0 +size 217468673 From 96e1b9cf1b24bc4f7865f03fb0dc7538dfd98e80 Mon Sep 17 00:00:00 2001 From: Marek Habersack Date: Thu, 22 May 2025 09:02:42 +0200 Subject: [PATCH 24/32] Remove comment that no longer applies --- src/native/mono/monodroid/monodroid-glue.cc | 1 - 1 file changed, 1 deletion(-) diff --git a/src/native/mono/monodroid/monodroid-glue.cc b/src/native/mono/monodroid/monodroid-glue.cc index c82db0a78c6..9cffb809d0b 100644 --- a/src/native/mono/monodroid/monodroid-glue.cc +++ b/src/native/mono/monodroid/monodroid-glue.cc @@ -795,7 +795,6 @@ MonodroidRuntime::lookup_bridge_info (MonoClass *klass, const OSBridge::MonoJava info->klass = klass; info->jniObjectReferenceControlBlock = mono_class_get_field_from_name (info->klass, const_cast("jniObjectReferenceControlBlock")); - // key_handle is optional, as Java.Interop.JavaObject doesn't currently have it if (info->klass == nullptr || info->jniObjectReferenceControlBlock == nullptr) { Helpers::abort_application ( std::format ( From 75cfd4dbab14d6d566b910a56cbabce74ddf6d5c Mon Sep 17 00:00:00 2001 From: Jonathan Peppers Date: Thu, 22 May 2025 08:15:20 -0500 Subject: [PATCH 25/32] git lfs for test lanes --- .../automation/yaml-templates/setup-test-environment.yaml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/build-tools/automation/yaml-templates/setup-test-environment.yaml b/build-tools/automation/yaml-templates/setup-test-environment.yaml index 19a98a86fad..d54ba8005bb 100644 --- a/build-tools/automation/yaml-templates/setup-test-environment.yaml +++ b/build-tools/automation/yaml-templates/setup-test-environment.yaml @@ -22,6 +22,12 @@ steps: clean: true submodules: recursive +- script: | + git lfs install + git lfs pull + displayName: git lfs setup + workingDirectory: ${{ parameters.xaSourcePath }} + - template: /build-tools/automation/yaml-templates/setup-jdk-variables.yaml parameters: jdkMajorVersion: ${{ parameters.jdkMajorVersion }} From d51469c1f6b94475785de19f5617e68781a994b1 Mon Sep 17 00:00:00 2001 From: Jonathan Peppers Date: Thu, 22 May 2025 08:21:45 -0500 Subject: [PATCH 26/32] Copy `packages` folder Hoping this gets MSBuild tests working --- .../Xamarin.ProjectTools/Common/XamarinProject.cs | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Common/XamarinProject.cs b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Common/XamarinProject.cs index 601406c0748..9ec46e97ca9 100644 --- a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Common/XamarinProject.cs +++ b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Common/XamarinProject.cs @@ -391,6 +391,17 @@ public void CopyNuGetConfig (string relativeDirectory) doc.Save (projNugetConfig); } } + + // Copy packages folder + var repoPackages = Path.Combine (XABuildPaths.TopDirectory, "packages"); + var projPackages = Path.Combine (Root, relativeDirectory, "packages"); + if (Directory.Exists (repoPackages)) { + Directory.CreateDirectory (projPackages); + foreach (var package in Directory.GetFiles (repoPackages, "*.nupkg")) { + var destination = Path.Combine (projPackages, Path.GetFileName (package)); + File.Copy (package, destination, overwrite: true); + } + } } /// From 1c2593872f0ba30062e59033905ed9d0394a49e9 Mon Sep 17 00:00:00 2001 From: Jonathan Peppers Date: Thu, 22 May 2025 11:58:14 -0500 Subject: [PATCH 27/32] On-device tests use `custom-runtime.targets` --- Documentation/workflow/DevelopmentTips.md | 2 +- build-tools/scripts/custom-runtime.targets | 5 +++-- .../Mono.Android-Tests/Mono.Android.NET-Tests.csproj | 1 + 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/Documentation/workflow/DevelopmentTips.md b/Documentation/workflow/DevelopmentTips.md index 53e74606f1b..ccb971d0f8b 100644 --- a/Documentation/workflow/DevelopmentTips.md +++ b/Documentation/workflow/DevelopmentTips.md @@ -465,7 +465,7 @@ A second (better) way is to add this MSBuild target to your Android 10.0.0-dev - + From 502337828338b6c6a12ec6dbe2f3d22dd8c9e21d Mon Sep 17 00:00:00 2001 From: Jonathan Peppers Date: Thu, 22 May 2025 12:02:03 -0500 Subject: [PATCH 28/32] Update pinvoke-tables.include --- src/native/clr/host/pinvoke-tables.include | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/native/clr/host/pinvoke-tables.include b/src/native/clr/host/pinvoke-tables.include index d02e8bcf825..4872eb0d97e 100644 --- a/src/native/clr/host/pinvoke-tables.include +++ b/src/native/clr/host/pinvoke-tables.include @@ -11,7 +11,7 @@ namespace { #if INTPTR_MAX == INT64_MAX //64-bit internal p/invoke table - std::array internal_pinvokes {{ + std::array internal_pinvokes {{ {0xa50ce5de13bf8b5, "_monodroid_timezone_get_default_id", reinterpret_cast(&_monodroid_timezone_get_default_id)}, {0x3ade4348ac8ce0fa, "_monodroid_freeifaddrs", reinterpret_cast(&_monodroid_freeifaddrs)}, {0x3b2467e7eadd4a6a, "_monodroid_lref_log_new", reinterpret_cast(&_monodroid_lref_log_new)}, @@ -21,6 +21,7 @@ namespace { {0x5f0b4e426eff086b, "_monodroid_detect_cpu_and_architecture", reinterpret_cast(&_monodroid_detect_cpu_and_architecture)}, {0x9099a4b95e3c3a89, "_monodroid_lref_log_delete", reinterpret_cast(&_monodroid_lref_log_delete)}, {0x9187e6bc6294cacf, "clr_typemap_managed_to_java", reinterpret_cast(&clr_typemap_managed_to_java)}, + {0x920bf58357fb56f3, "clr_initialize_gc_bridge", reinterpret_cast(&clr_initialize_gc_bridge)}, {0x9a946dfe9916a942, "clr_typemap_java_to_managed", reinterpret_cast(&clr_typemap_java_to_managed)}, {0xa6ec846592d99536, "_monodroid_weak_gref_delete", reinterpret_cast(&_monodroid_weak_gref_delete)}, {0xa7f58f3ee428cc6b, "_monodroid_gref_log_delete", reinterpret_cast(&_monodroid_gref_log_delete)}, @@ -531,7 +532,7 @@ constexpr hash_t system_security_cryptography_native_android_library_hash = 0x18 constexpr hash_t system_globalization_native_library_hash = 0x28b5c8fca080abd5; #else //32-bit internal p/invoke table - std::array internal_pinvokes {{ + std::array internal_pinvokes {{ {0xb7a486a, "monodroid_TypeManager_get_java_class_name", reinterpret_cast(&monodroid_TypeManager_get_java_class_name)}, {0x2aea7c33, "_monodroid_max_gref_get", reinterpret_cast(&_monodroid_max_gref_get)}, {0x3227d81a, "monodroid_timing_start", reinterpret_cast(&monodroid_timing_start)}, @@ -544,6 +545,7 @@ constexpr hash_t system_globalization_native_library_hash = 0x28b5c8fca080abd5; {0x9a734f16, "_monodroid_weak_gref_get", reinterpret_cast(&_monodroid_weak_gref_get)}, {0x9c5b24a8, "_monodroid_weak_gref_new", reinterpret_cast(&_monodroid_weak_gref_new)}, {0xa04e5d1c, "monodroid_free", reinterpret_cast(&monodroid_free)}, + {0xa3c1e548, "clr_initialize_gc_bridge", reinterpret_cast(&clr_initialize_gc_bridge)}, {0xad511c82, "_monodroid_timezone_get_default_id", reinterpret_cast(&_monodroid_timezone_get_default_id)}, {0xb02468aa, "_monodroid_gref_get", reinterpret_cast(&_monodroid_gref_get)}, {0xb6431f9a, "clr_typemap_java_to_managed", reinterpret_cast(&clr_typemap_java_to_managed)}, @@ -1051,6 +1053,6 @@ constexpr hash_t system_security_cryptography_native_android_library_hash = 0x93 constexpr hash_t system_globalization_native_library_hash = 0xa66f1e5a; #endif -constexpr size_t internal_pinvokes_count = 26; +constexpr size_t internal_pinvokes_count = 27; constexpr size_t dotnet_pinvokes_count = 477; } // end of anonymous namespace From 1fba234ffcae59305df57fb1293c379843f1abca Mon Sep 17 00:00:00 2001 From: Marek Habersack Date: Thu, 22 May 2025 21:40:02 +0200 Subject: [PATCH 29/32] Let's see... --- src/native/mono/monodroid/osbridge.cc | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/src/native/mono/monodroid/osbridge.cc b/src/native/mono/monodroid/osbridge.cc index 16793ebbdb2..4c8cd6a77a8 100644 --- a/src/native/mono/monodroid/osbridge.cc +++ b/src/native/mono/monodroid/osbridge.cc @@ -574,13 +574,22 @@ OSBridge::gc_bridge_class_kind (MonoClass *klass) mono_bool OSBridge::gc_is_bridge_object (MonoObject *object) { - void *handle; + if (object == nullptr) [[unlikely]] { + log_debug (LOG_GC, "gc_is_bridge_object was passed a NULL object pointer"); + return FALSE; + } JniObjectReferenceControlBlock *control_block = get_gc_control_block_for_object (object); if (control_block == nullptr) { - return 0; + return FALSE; } + if (control_block->handle == nullptr) { + log_warn (LOG_GC, "gc_is_bridge_object: control block's handle is NULL"); + return FALSE; + } + + void *handle; mono_field_get_value (object, reinterpret_cast(control_block->handle), &handle); if (handle == nullptr) { #if DEBUG @@ -591,10 +600,10 @@ OSBridge::gc_is_bridge_object (MonoObject *object) optional_string (mono_class_get_name (mclass)) ); #endif - return 0; + return FALSE; } - return 1; + return TRUE; } // Add a reference from an IGCUserPeer jobject to another jobject From b5b05f21e5819c314e99b925e3d8af1ce6e6ab26 Mon Sep 17 00:00:00 2001 From: Marek Habersack Date: Fri, 23 May 2025 17:06:17 +0200 Subject: [PATCH 30/32] Bump to updated version of JI --- external/Java.Interop | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/external/Java.Interop b/external/Java.Interop index 174fd85c7fd..ad451f96f1c 160000 --- a/external/Java.Interop +++ b/external/Java.Interop @@ -1 +1 @@ -Subproject commit 174fd85c7fd5c81d48554c89afa7e5b618348160 +Subproject commit ad451f96f1ca15fcaee0fb0db1e7801b4adfb6f6 From 7e56838df535dd039b70ec69d7e5136c19aabdad Mon Sep 17 00:00:00 2001 From: Marek Habersack Date: Fri, 23 May 2025 17:26:52 +0200 Subject: [PATCH 31/32] Don't use HEAD of the JI PR, it doesn't build --- external/Java.Interop | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/external/Java.Interop b/external/Java.Interop index ad451f96f1c..7174669897e 160000 --- a/external/Java.Interop +++ b/external/Java.Interop @@ -1 +1 @@ -Subproject commit ad451f96f1ca15fcaee0fb0db1e7801b4adfb6f6 +Subproject commit 7174669897efbf38fcf9a340d3127b65a4b8d352 From b67723636481e5dbec040862de22a02ace43133d Mon Sep 17 00:00:00 2001 From: Jonathan Peppers Date: Tue, 3 Jun 2025 10:43:11 -0500 Subject: [PATCH 32/32] Update pinvoke-tables.include --- src/native/clr/host/pinvoke-tables.include | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/native/clr/host/pinvoke-tables.include b/src/native/clr/host/pinvoke-tables.include index cb72e59d0c0..65afe1a26d5 100644 --- a/src/native/clr/host/pinvoke-tables.include +++ b/src/native/clr/host/pinvoke-tables.include @@ -1081,6 +1081,6 @@ constexpr hash_t system_security_cryptography_native_android_library_hash = 0x93 constexpr hash_t system_globalization_native_library_hash = 0xa66f1e5a; #endif -constexpr size_t internal_pinvokes_count = 26; +constexpr size_t internal_pinvokes_count = 27; constexpr size_t dotnet_pinvokes_count = 491; } // end of anonymous namespace