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..ccb971d0f8b 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/automation/yaml-templates/build-linux.yaml b/build-tools/automation/yaml-templates/build-linux.yaml index 08999e2f033..ce1dc15b94e 100644 --- a/build-tools/automation/yaml-templates/build-linux.yaml +++ b/build-tools/automation/yaml-templates/build-linux.yaml @@ -53,6 +53,12 @@ stages: path: ${{ parameters.checkoutPath }} persistCredentials: ${{ parameters.checkoutPersistCredentials }} + - 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 # https://learn.microsoft.com/en-us/azure/devops/pipelines/repos/multi-repo-checkout?view=azure-devops#checkout-path - checkout: maui diff --git a/build-tools/automation/yaml-templates/build-macos.yaml b/build-tools/automation/yaml-templates/build-macos.yaml index 58817ec76da..81ad7e53f25 100644 --- a/build-tools/automation/yaml-templates/build-macos.yaml +++ b/build-tools/automation/yaml-templates/build-macos.yaml @@ -75,6 +75,12 @@ stages: path: ${{ parameters.checkoutPath }} persistCredentials: ${{ parameters.checkoutPersistCredentials }} + - script: | + git lfs install + git lfs pull + displayName: git lfs setup + workingDirectory: ${{ parameters.xaSourcePath }} + - 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..a3dff0a04f0 100644 --- a/build-tools/automation/yaml-templates/build-windows.yaml +++ b/build-tools/automation/yaml-templates/build-windows.yaml @@ -35,6 +35,12 @@ stages: path: ${{ parameters.checkoutPath }} persistCredentials: ${{ parameters.checkoutPersistCredentials }} + - script: | + git lfs install + git lfs pull + displayName: git lfs setup + workingDirectory: ${{ parameters.xaSourcePath }} + - template: /build-tools/automation/yaml-templates/kill-processes.yaml - template: /build-tools/automation/yaml-templates/clean.yaml 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 }} diff --git a/build-tools/scripts/custom-runtime.targets b/build-tools/scripts/custom-runtime.targets new file mode 100644 index 00000000000..4e623f40f3c --- /dev/null +++ b/build-tools/scripts/custom-runtime.targets @@ -0,0 +1,22 @@ + + + + + <_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..962bb77cfd4 --- /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: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 new file mode 100644 index 00000000000..32d7885b4e4 --- /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:8eb905f6f152401b6375d2e3c51ca753b2545717fd4cb89674f7ff188c3e86c7 +size 215752961 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 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..f8cb8e95f17 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..2b4d5f5ffff 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,41 @@ 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.JniObjectReferenceControlBlock); + + static unsafe void FreeHandle (GCHandle handle) + { + IntPtr context = JavaMarshal.GetContext (handle); + NativeMemory.Free ((void*) context); + } + + [UnmanagedCallersOnly] + internal static unsafe void BridgeProcessingFinished (MarkCrossReferences* mcr) + { + 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; 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/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); + } + } } /// diff --git a/src/native/clr/host/CMakeLists.txt b/src/native/clr/host/CMakeLists.txt index d2338f4f072..9ddaa13234f 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..c03da967d99 --- /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 (MarkCrossReferences* crossRefs) noexcept +{ + if (bridge_processing_finish_callback == nullptr) [[unlikely]] { + return; + } + + trigger_java_gc (); + + // Call back into managed code + bridge_processing_finish_callback (crossRefs); +} diff --git a/src/native/clr/host/generate-pinvoke-tables.cc b/src/native/clr/host/generate-pinvoke-tables.cc index 8f31936cdd7..0b354cae033 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/host.cc b/src/native/clr/host/host.cc index c48d1a7ca9c..d5b4463f63f 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 @@ -574,6 +575,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 a490a8b069e..abbb41728ba 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 @@ -53,6 +54,12 @@ bool clr_typemap_java_to_managed (const char *java_type_name, char const** assem return TypeMapper::java_to_managed (java_type_name, assembly_name, managed_type_token_id); } +MarkCrossReferencesFtn clr_initialize_gc_bridge (MarkCrossReferencesFtn callback) noexcept +{ + GCBridge::set_finish_callback (callback); + return GCBridge::mark_cross_references; +} + void monodroid_log (LogLevel level, LogCategories category, const char *message) noexcept { switch (level) { diff --git a/src/native/clr/host/pinvoke-tables.include b/src/native/clr/host/pinvoke-tables.include index 000e4ce8afb..65afe1a26d5 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)}, @@ -545,7 +546,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)}, @@ -558,6 +559,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)}, @@ -1079,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 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..e472f733256 --- /dev/null +++ b/src/native/clr/include/host/gc-bridge.hh @@ -0,0 +1,48 @@ +#pragma once + +#include + +#include + +struct StronglyConnectedComponent +{ + size_t Count; + void** ContextMemory; +}; + +struct ComponentCrossReference +{ + size_t SourceGroupIndex; + size_t DestinationGroupIndex; +}; + +struct MarkCrossReferences +{ + size_t ComponentsLen; + StronglyConnectedComponent* Components; + size_t CrossReferencesLen; + ComponentCrossReference* CrossReferences; +}; + +using MarkCrossReferencesFtn = void (*)(MarkCrossReferences*); + +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 (MarkCrossReferences* crossRefs) noexcept; + + static void set_finish_callback (MarkCrossReferencesFtn callback) noexcept + { + abort_if_invalid_pointer_argument (callback, "callback"); + bridge_processing_finish_callback = 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 a3c69c6c6e7..5a01d121633 100644 --- a/src/native/clr/include/runtime-base/internal-pinvokes.hh +++ b/src/native/clr/include/runtime-base/internal-pinvokes.hh @@ -3,6 +3,7 @@ #include #include +#include #include #include "logger.hh" #include @@ -14,6 +15,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; diff --git a/tests/Mono.Android-Tests/Mono.Android-Tests/Mono.Android.NET-Tests.csproj b/tests/Mono.Android-Tests/Mono.Android-Tests/Mono.Android.NET-Tests.csproj index b762c8be98e..b1ca5288f3d 100644 --- a/tests/Mono.Android-Tests/Mono.Android-Tests/Mono.Android.NET-Tests.csproj +++ b/tests/Mono.Android-Tests/Mono.Android-Tests/Mono.Android.NET-Tests.csproj @@ -252,6 +252,7 @@ +