diff --git a/.gitmodules b/.gitmodules
index c9883e88b80..dae435f0c82 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -22,3 +22,7 @@
path = external/xamarin-android-tools
url = https://github.com/xamarin/xamarin-android-tools
branch = main
+[submodule "external/libunwind"]
+ path = external/libunwind
+ url = https://github.com/libunwind/libunwind.git
+ branch = v1.7-stable
diff --git a/Configuration.props b/Configuration.props
index 1a467652e80..0890b5b7103 100644
--- a/Configuration.props
+++ b/Configuration.props
@@ -104,6 +104,8 @@
True
$(MSBuildThisFileDirectory)external\opentk
$(MSBuildThisFileDirectory)external\sqlite
+ $(MSBuildThisFileDirectory)external\libunwind
+ $(BootstrapOutputDirectory)\libunwind
$(MSBuildThisFileDirectory)
$(MSBuildThisFileDirectory)src-ThirdParty\
armeabi-v7a;x86
@@ -144,6 +146,8 @@
$([System.IO.Path]::GetFullPath ('$(JavaInteropSourceDirectory)'))
$([System.IO.Path]::GetFullPath ('$(MonoSourceDirectory)'))
$([System.IO.Path]::GetFullPath ('$(SqliteSourceDirectory)'))
+ $([System.IO.Path]::GetFullPath ('$(LibUnwindSourceDirectory)'))
+ $([System.IO.Path]::GetFullPath ('$(LibUnwindGeneratedHeadersDirectory)'))
$([System.IO.Path]::GetFullPath ('$(OpenTKSourceDirectory)'))
net8.0
diff --git a/TheoriesToTest.txt b/TheoriesToTest.txt
new file mode 100644
index 00000000000..7517af47f8a
--- /dev/null
+++ b/TheoriesToTest.txt
@@ -0,0 +1,4 @@
+* See if it's a threading issue - add full locking to `get_function_pointer` instead of atomics that we use now
+* See if it's an ALC issue - call `get_function_pointer` every time and check the returned pointer value
+* Implement Jon's idea to always have the "old" dynamic registration stuff in JCW and only use it when some flag
+ is set and marshal methods are active.
diff --git a/Xamarin.Android.sln b/Xamarin.Android.sln
index 50918d1e4e3..adb1f590ba4 100644
--- a/Xamarin.Android.sln
+++ b/Xamarin.Android.sln
@@ -47,6 +47,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Java.Interop.Tools.Diagnost
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Java.Interop.Tools.Cecil", "external\Java.Interop\src\Java.Interop.Tools.Cecil\Java.Interop.Tools.Cecil.csproj", "{D48EE8D0-0A0A-4493-AEF5-DAF5F8CF86AD}"
EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "libunwind", "src\libunwind-xamarin\libunwind-xamarin.csproj", "{F8E4961B-C427-47F9-92D6-0BEB5B76B3D7}"
+EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "monodroid", "src\monodroid\monodroid.csproj", "{53EE4C57-1C03-405A-8243-8DA539546C88}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tests", "Tests", "{CAB438D8-B0F5-4AF0-BEBD-9E2ADBD7B483}"
diff --git a/build-tools/cmake/xa_macros.cmake b/build-tools/cmake/xa_macros.cmake
index 58e75192bfd..24812dfd82b 100644
--- a/build-tools/cmake/xa_macros.cmake
+++ b/build-tools/cmake/xa_macros.cmake
@@ -200,7 +200,8 @@ function(xa_common_prepare)
-fstack-protector-strong
-fstrict-return
-fno-strict-aliasing
- -ffunction-sections
+ -fno-function-sections
+ -fno-data-sections
-funswitch-loops
-finline-limit=300
-Wa,-noexecstack
diff --git a/build-tools/create-packs/Microsoft.Android.Runtime.proj b/build-tools/create-packs/Microsoft.Android.Runtime.proj
index 8982eb6f911..41fbd68991d 100644
--- a/build-tools/create-packs/Microsoft.Android.Runtime.proj
+++ b/build-tools/create-packs/Microsoft.Android.Runtime.proj
@@ -41,6 +41,8 @@ projects that use the Microsoft.Android framework in .NET 6+.
<_AndroidRuntimePackAssets Include="$(MicrosoftAndroidSdkOutDir)lib\$(AndroidRID)\libmono-android.debug.so" />
<_AndroidRuntimePackAssets Include="$(MicrosoftAndroidSdkOutDir)lib\$(AndroidRID)\libmono-android.release.so" />
<_AndroidRuntimePackAssets Include="$(MicrosoftAndroidSdkOutDir)lib\$(AndroidRID)\libxamarin-debug-app-helper.so" />
+ <_AndroidRuntimePackAssets Include="$(MicrosoftAndroidSdkOutDir)lib\$(AndroidRID)\libmarshal-methods-tracing.a" />
+ <_AndroidRuntimePackAssets Include="$(MicrosoftAndroidSdkOutDir)lib\$(AndroidRID)\libxamarin-native-tracing.so" />
diff --git a/build-tools/installers/create-installers.targets b/build-tools/installers/create-installers.targets
index dbd3982b5bf..562180003e0 100644
--- a/build-tools/installers/create-installers.targets
+++ b/build-tools/installers/create-installers.targets
@@ -170,12 +170,20 @@
<_MSBuildFiles Include="$(MicrosoftAndroidSdkOutDir)ManifestOverlays\Timing.xml" />
<_MSBuildFiles Include="$(MicrosoftAndroidSdkOutDir)libstubs\android-arm64\libc.so" />
<_MSBuildFiles Include="$(MicrosoftAndroidSdkOutDir)libstubs\android-arm64\libm.so" />
+ <_MSBuildFiles Include="$(MicrosoftAndroidSdkOutDir)libstubs\android-arm64\libdl.so" />
+ <_MSBuildFiles Include="$(MicrosoftAndroidSdkOutDir)libstubs\android-arm64\liblog.so" />
<_MSBuildFiles Include="$(MicrosoftAndroidSdkOutDir)libstubs\android-arm\libc.so" />
<_MSBuildFiles Include="$(MicrosoftAndroidSdkOutDir)libstubs\android-arm\libm.so" />
+ <_MSBuildFiles Include="$(MicrosoftAndroidSdkOutDir)libstubs\android-arm\libdl.so" />
+ <_MSBuildFiles Include="$(MicrosoftAndroidSdkOutDir)libstubs\android-arm\liblog.so" />
<_MSBuildFiles Include="$(MicrosoftAndroidSdkOutDir)libstubs\android-x64\libc.so" />
<_MSBuildFiles Include="$(MicrosoftAndroidSdkOutDir)libstubs\android-x64\libm.so" />
+ <_MSBuildFiles Include="$(MicrosoftAndroidSdkOutDir)libstubs\android-x64\libdl.so" />
+ <_MSBuildFiles Include="$(MicrosoftAndroidSdkOutDir)libstubs\android-x64\liblog.so" />
<_MSBuildFiles Include="$(MicrosoftAndroidSdkOutDir)libstubs\android-x86\libc.so" />
<_MSBuildFiles Include="$(MicrosoftAndroidSdkOutDir)libstubs\android-x86\libm.so" />
+ <_MSBuildFiles Include="$(MicrosoftAndroidSdkOutDir)libstubs\android-x86\libdl.so" />
+ <_MSBuildFiles Include="$(MicrosoftAndroidSdkOutDir)libstubs\android-x86\liblog.so" />
<_MSBuildTargetsSrcFiles Include="$(MSBuildTargetsSrcDir)\Xamarin.Android.AvailableItems.targets" />
diff --git a/build-tools/xaprepare/xaprepare/Application/KnownProperties.cs b/build-tools/xaprepare/xaprepare/Application/KnownProperties.cs
index 2d9fd7efcfa..32f56aa57ff 100644
--- a/build-tools/xaprepare/xaprepare/Application/KnownProperties.cs
+++ b/build-tools/xaprepare/xaprepare/Application/KnownProperties.cs
@@ -38,6 +38,8 @@ static class KnownProperties
public const string JavaInteropFullPath = "JavaInteropFullPath";
public const string JavaSdkDirectory = "JavaSdkDirectory";
public const string JdkIncludePath = "JdkIncludePath";
+ public const string LibUnwindGeneratedHeadersFullPath = nameof (LibUnwindGeneratedHeadersFullPath);
+ public const string LibUnwindSourceFullPath = nameof (LibUnwindSourceFullPath);
public const string LibZipSourceFullPath = "LibZipSourceFullPath";
public const string ManagedRuntime = "ManagedRuntime";
public const string MicrosoftAndroidSdkOutDir = "MicrosoftAndroidSdkOutDir";
diff --git a/build-tools/xaprepare/xaprepare/Application/Properties.Defaults.cs.in b/build-tools/xaprepare/xaprepare/Application/Properties.Defaults.cs.in
index 6e59af3ab6e..39b44422eb7 100644
--- a/build-tools/xaprepare/xaprepare/Application/Properties.Defaults.cs.in
+++ b/build-tools/xaprepare/xaprepare/Application/Properties.Defaults.cs.in
@@ -42,6 +42,8 @@ namespace Xamarin.Android.Prepare
properties.Add (KnownProperties.JavaInteropFullPath, StripQuotes (@"@JavaInteropFullPath@"));
properties.Add (KnownProperties.JavaSdkDirectory, StripQuotes (@"@JavaSdkDirectory@"));
properties.Add (KnownProperties.JdkIncludePath, StripQuotes (@"@JdkIncludePath@"));
+ properties.Add (KnownProperties.LibUnwindGeneratedHeadersFullPath, StripQuotes (@"@LibUnwindGeneratedHeadersFullPath@"));
+ properties.Add (KnownProperties.LibUnwindSourceFullPath, StripQuotes (@"@LibUnwindSourceFullPath"));
properties.Add (KnownProperties.LibZipSourceFullPath, StripQuotes (@"@LibZipSourceFullPath@"));
properties.Add (KnownProperties.ManagedRuntime, StripQuotes (@"@ManagedRuntime@"));
properties.Add (KnownProperties.MicrosoftAndroidSdkOutDir, StripQuotes (@"@MicrosoftAndroidSdkOutDir@"));
diff --git a/build-tools/xaprepare/xaprepare/xaprepare.targets b/build-tools/xaprepare/xaprepare/xaprepare.targets
index 4c8e3be8906..dc8465d148b 100644
--- a/build-tools/xaprepare/xaprepare/xaprepare.targets
+++ b/build-tools/xaprepare/xaprepare/xaprepare.targets
@@ -75,6 +75,7 @@
+
diff --git a/external/libunwind b/external/libunwind
new file mode 160000
index 00000000000..688caaf6ef9
--- /dev/null
+++ b/external/libunwind
@@ -0,0 +1 @@
+Subproject commit 688caaf6ef9853cc26ad8bd1706804d48a0df0bc
diff --git a/java.interop-tracing.diff b/java.interop-tracing.diff
new file mode 100644
index 00000000000..bb00e359fa4
--- /dev/null
+++ b/java.interop-tracing.diff
@@ -0,0 +1,213 @@
+diff --git a/src/Java.Interop.Tools.JavaCallableWrappers/Java.Interop.Tools.JavaCallableWrappers/JavaCallableWrapperGenerator.cs b/src/Java.Interop.Tools.JavaCallableWrappers/Java.Interop.Tools.JavaCallableWrappers/JavaCallableWrapperGenerator.cs
+index 76f2bfc0..7a57f6b2 100644
+--- a/src/Java.Interop.Tools.JavaCallableWrappers/Java.Interop.Tools.JavaCallableWrappers/JavaCallableWrapperGenerator.cs
++++ b/src/Java.Interop.Tools.JavaCallableWrappers/Java.Interop.Tools.JavaCallableWrappers/JavaCallableWrapperGenerator.cs
+@@ -133,6 +133,7 @@ namespace Java.Interop.Tools.JavaCallableWrappers {
+
+ JavaCallableWrapperGenerator (TypeDefinition type, string? outerType, Action log, IMetadataResolver resolver, JavaCallableMethodClassifier? methodClassifier = null)
+ {
++ Console.WriteLine ($"JCWG: processing {type}");
+ this.methodClassifier = methodClassifier;
+ this.type = type;
+ this.log = log;
+@@ -224,6 +225,8 @@ namespace Java.Interop.Tools.JavaCallableWrappers {
+ curCtors = new List ();
+ AddConstructors (ctorTypes [i], outerType, baseCtors, curCtors, false);
+ }
++
++ Console.WriteLine ($"JCWG: done processing {type}");
+ }
+
+ static void ExtractJavaNames (string jniName, out string package, out string type)
+@@ -285,8 +288,10 @@ namespace Java.Interop.Tools.JavaCallableWrappers {
+
+ void AddConstructor (MethodDefinition ctor, TypeDefinition type, string? outerType, List? baseCtors, List curCtors, bool onlyRegisteredOrExportedCtors, bool skipParameterCheck)
+ {
++ Console.WriteLine ($" JCWG: AddConstructor ({ctor}, {type}, ..., onlyRegisteredOrExportedCtors: {onlyRegisteredOrExportedCtors}, skipParameterCheck: {skipParameterCheck});");
+ string managedParameters = GetManagedParameters (ctor, outerType);
+ if (!skipParameterCheck && (managedParameters == null || ctors.Any (c => c.ManagedParameters == managedParameters))) {
++ Console.WriteLine (" JCWG: skip #1");
+ return;
+ }
+
+@@ -297,28 +302,38 @@ namespace Java.Interop.Tools.JavaCallableWrappers {
+ }
+ ctors.Add (new Signature (ctor, eattr, cache));
+ curCtors.Add (ctor);
++ Console.WriteLine (" JCWG: add #1");
+ return;
+ }
+
+ RegisterAttribute rattr = GetMethodRegistrationAttributes (ctor).FirstOrDefault ();
+ if (rattr != null) {
+- if (ctors.Any (c => c.JniSignature == rattr.Signature))
++ if (ctors.Any (c => c.JniSignature == rattr.Signature)) {
++ Console.WriteLine (" JCWG: skip #2");
+ return;
++ }
+ ctors.Add (new Signature (ctor, rattr, managedParameters, outerType, cache));
+ curCtors.Add (ctor);
++ Console.WriteLine (" JCWG: add #2");
+ return;
+ }
+
+- if (onlyRegisteredOrExportedCtors)
++ if (onlyRegisteredOrExportedCtors) {
++ Console.WriteLine (" JCWG: skip #1");
+ return;
++ }
+
+ string? jniSignature = GetJniSignature (ctor, cache);
+
+- if (jniSignature == null)
++ if (jniSignature == null) {
++ Console.WriteLine (" JCWG: skip #3");
+ return;
++ }
+
+- if (ctors.Any (c => c.JniSignature == jniSignature))
++ if (ctors.Any (c => c.JniSignature == jniSignature)) {
++ Console.WriteLine (" JCWG: skip #4");
+ return;
++ }
+
+ if (baseCtors == null) {
+ throw new InvalidOperationException ("`baseCtors` should not be null!");
+@@ -327,11 +342,13 @@ namespace Java.Interop.Tools.JavaCallableWrappers {
+ if (baseCtors.Any (m => m.Parameters.AreParametersCompatibleWith (ctor.Parameters, cache))) {
+ ctors.Add (new Signature (".ctor", jniSignature, "", managedParameters, outerType, null));
+ curCtors.Add (ctor);
++ Console.WriteLine (" JCWG: add #3");
+ return;
+ }
+ if (baseCtors.Any (m => !m.HasParameters)) {
+ ctors.Add (new Signature (".ctor", jniSignature, "", managedParameters, outerType, ""));
+ curCtors.Add (ctor);
++ Console.WriteLine (" JCWG: add #4");
+ return;
+ }
+ }
+@@ -549,17 +566,17 @@ namespace Java.Interop.Tools.JavaCallableWrappers {
+ GenerateHeader (writer);
+
+ bool needCtor = false;
+- if (HasDynamicallyRegisteredMethods) {
++// if (HasDynamicallyRegisteredMethods) {
+ needCtor = true;
+ writer.WriteLine ("/** @hide */");
+ writer.WriteLine ("\tpublic static final String __md_methods;");
+- }
++// }
+
+ if (children != null) {
+ for (int i = 0; i < children.Count; i++) {
+- if (!children[i].HasDynamicallyRegisteredMethods) {
+- continue;
+- }
++ // if (!children[i].HasDynamicallyRegisteredMethods) {
++ // continue;
++ // }
+ needCtor = true;
+ writer.Write ("\tstatic final String __md_");
+ writer.Write (i + 1);
+@@ -570,9 +587,9 @@ namespace Java.Interop.Tools.JavaCallableWrappers {
+ if (needCtor) {
+ writer.WriteLine ("\tstatic {");
+
+- if (HasDynamicallyRegisteredMethods) {
++// if (HasDynamicallyRegisteredMethods) {
+ GenerateRegisterType (writer, this, "__md_methods");
+- }
++// }
+
+ if (children != null) {
+ for (int i = 0; i < children.Count; ++i) {
+@@ -687,9 +704,12 @@ namespace Java.Interop.Tools.JavaCallableWrappers {
+
+ void GenerateBody (TextWriter sw)
+ {
++ Console.WriteLine ($" JCWG: GenerateBody for {name} (ctors size: {ctors.Count})");
+ foreach (Signature ctor in ctors) {
+- if (string.IsNullOrEmpty (ctor.Params) && JavaNativeTypeManager.IsApplication (type, cache))
++ if (string.IsNullOrEmpty (ctor.Params) && JavaNativeTypeManager.IsApplication (type, cache)) {
++ Console.WriteLine ($" JCWG: skipping constructor generation; params empty? {string.IsNullOrEmpty (ctor.Params)}; is application? {JavaNativeTypeManager.IsApplication (type, cache)}");
+ continue;
++ }
+ GenerateConstructor (ctor, sw);
+ }
+
+@@ -745,9 +765,9 @@ namespace Java.Interop.Tools.JavaCallableWrappers {
+
+ void GenerateRegisterType (TextWriter sw, JavaCallableWrapperGenerator self, string field)
+ {
+- if (!self.HasDynamicallyRegisteredMethods) {
+- return;
+- }
++ // if (!self.HasDynamicallyRegisteredMethods) {
++ // return;
++ // }
+
+ sw.Write ("\t\t");
+ sw.Write (field);
+@@ -818,9 +838,13 @@ namespace Java.Interop.Tools.JavaCallableWrappers {
+ return jniName.Replace ('/', '.').Replace ('$', '.');
+ }
+
+- bool CannotRegisterInStaticConstructor (TypeDefinition type)
++ bool CannotRegisterInStaticConstructor (TypeDefinition type, bool dolog = false)
+ {
+- return JavaNativeTypeManager.IsApplication (type, cache) || JavaNativeTypeManager.IsInstrumentation (type, cache);
++ Console.WriteLine ($" JCWG: CannotRegisterInStaticConstructor ({type})");
++ bool ret = JavaNativeTypeManager.IsApplication (type, cache) || JavaNativeTypeManager.IsInstrumentation (type, cache);
++ Console.WriteLine ($" JCWG: CannotRegisterInStaticConstructor for type {type}; ret == {ret}; IsApplication: {JavaNativeTypeManager.IsApplication (type, cache)}; IsInstrumentation: {JavaNativeTypeManager.IsInstrumentation (type, cache)}");
++
++ return ret;
+ }
+
+ class Signature {
+@@ -941,6 +965,8 @@ namespace Java.Interop.Tools.JavaCallableWrappers {
+
+ void GenerateConstructor (Signature ctor, TextWriter sw)
+ {
++ Console.WriteLine ($" JCWG: GenerateConstructor for {name}");
++
+ // TODO: we only generate constructors so that Android types w/ no
+ // default constructor can be subclasses by our generated code.
+ //
+diff --git a/tools/java-source-utils/.classpath b/tools/java-source-utils/.classpath
+index 30230c1c..cbded110 100644
+--- a/tools/java-source-utils/.classpath
++++ b/tools/java-source-utils/.classpath
+@@ -20,6 +20,12 @@
+
+
+
++
++
++
++
++
++
+
+
+
+diff --git a/tools/java-source-utils/.project b/tools/java-source-utils/.project
+index 8337a1c5..613733c8 100644
+--- a/tools/java-source-utils/.project
++++ b/tools/java-source-utils/.project
+@@ -20,4 +20,15 @@
+ org.eclipse.jdt.core.javanature
+ org.eclipse.buildship.core.gradleprojectnature
+
++
++
++ 1682588570543
++
++ 30
++
++ org.eclipse.core.resources.regexFilterMatcher
++ node_modules|.metadata|archetype-resources|META-INF/maven|__CREATED_BY_JAVA_LANGUAGE_SERVER__
++
++
++
+
diff --git a/src/Mono.Android/Android.Runtime/AndroidRuntime.cs b/src/Mono.Android/Android.Runtime/AndroidRuntime.cs
index d7876273983..60b7b52eae0 100644
--- a/src/Mono.Android/Android.Runtime/AndroidRuntime.cs
+++ b/src/Mono.Android/Android.Runtime/AndroidRuntime.cs
@@ -491,8 +491,11 @@ public void RegisterNativeMembers (
{
try {
if (methods.IsEmpty) {
- if (jniAddNativeMethodRegistrationAttributePresent)
+ RuntimeNativeMethods.monodroid_log (LogLevel.Info, LogCategories.Assembly, $"RegisterJniNatives: Type {type.FullName} registers no methods");
+ if (jniAddNativeMethodRegistrationAttributePresent) {
+ RuntimeNativeMethods.monodroid_log (LogLevel.Info, LogCategories.Assembly, $"RegisterJniNatives: Type {type.FullName} has [AddNativeMethodRegistration] attribute");
base.RegisterNativeMembers (nativeClass, type, methods.ToString ());
+ }
return;
} else if (FastRegisterNativeMembers (nativeClass, type, methods)) {
return;
@@ -539,6 +542,7 @@ public void RegisterNativeMembers (
throw new InvalidOperationException (FormattableString.Invariant ($"Specified managed method '{mname.ToString ()}' was not found. Signature: {signature.ToString ()}"));
callback = CreateDynamicCallback (minfo);
needToRegisterNatives = true;
+ RuntimeNativeMethods.monodroid_log (LogLevel.Info, LogCategories.Assembly, $"RegisterJniNativesMethod: [ ] {type.FullName}: __export__ found for method '{name.ToString ()}'");
} else {
Type callbackDeclaringType = type;
if (!callbackDeclaringTypeString.IsEmpty) {
@@ -556,6 +560,7 @@ public void RegisterNativeMembers (
if (callback != null) {
needToRegisterNatives = true;
natives [nativesIndex++] = new JniNativeMethodRegistration (name.ToString (), signature.ToString (), callback);
+ RuntimeNativeMethods.monodroid_log (LogLevel.Info, LogCategories.Assembly, $"RegisterJniNativesMethod: [ ] {type.FullName}.{name.ToString ()}");
}
}
@@ -563,20 +568,12 @@ public void RegisterNativeMembers (
}
if (needToRegisterNatives) {
+ RuntimeNativeMethods.monodroid_log (LogLevel.Info, LogCategories.Assembly, $"RegisterJniNatives: Type {type.FullName} calling JniEnvironment.Types.RegisterNatives");
JniEnvironment.Types.RegisterNatives (nativeClass.PeerReference, natives, nativesIndex);
}
} catch (Exception e) {
JniEnvironment.Runtime.RaisePendingException (e);
}
-
- bool ShouldRegisterDynamically (string callbackTypeName, string callbackString, string typeName, string callbackName)
- {
- if (String.Compare (typeName, callbackTypeName, StringComparison.Ordinal) != 0) {
- return false;
- }
-
- return String.Compare (callbackName, callbackString, StringComparison.Ordinal) == 0;
- }
}
static int CountMethods (ReadOnlySpan methodsSpan)
diff --git a/src/Mono.Android/Android.Runtime/InputStreamAdapter.cs b/src/Mono.Android/Android.Runtime/InputStreamAdapter.cs
index 5eb3b04bd87..795ed57d217 100644
--- a/src/Mono.Android/Android.Runtime/InputStreamAdapter.cs
+++ b/src/Mono.Android/Android.Runtime/InputStreamAdapter.cs
@@ -8,11 +8,18 @@ public sealed class InputStreamAdapter : Java.IO.InputStream {
public Stream BaseStream {get; private set;}
+ InputStreamAdapter () {
+ Console.WriteLine ("InputStreamAdapter () invoked");
+ Console.WriteLine (new System.Diagnostics.StackTrace(true));
+ }
+
public InputStreamAdapter (System.IO.Stream stream)
: base (
JNIEnv.StartCreateInstance ("mono/android/runtime/InputStreamAdapter", "()V"),
JniHandleOwnership.TransferLocalRef)
{
+ Console.WriteLine ("InputStreamAdapter (System.IO.Stream) invoked");
+ Console.WriteLine (new System.Diagnostics.StackTrace(true));
JNIEnv.FinishCreateInstance (Handle, "()V");
this.BaseStream = stream;
@@ -54,4 +61,3 @@ public static IntPtr ToLocalJniHandle (Stream? value)
}
}
}
-
diff --git a/src/Mono.Android/Android.Runtime/JNIEnvInit.cs b/src/Mono.Android/Android.Runtime/JNIEnvInit.cs
index 2f65464716b..22ba4dc13f3 100644
--- a/src/Mono.Android/Android.Runtime/JNIEnvInit.cs
+++ b/src/Mono.Android/Android.Runtime/JNIEnvInit.cs
@@ -76,6 +76,9 @@ static unsafe void RegisterJniNatives (IntPtr typeName_ptr, int typeName_len, In
[UnmanagedCallersOnly]
internal static unsafe void Initialize (JnienvInitializeArgs* args)
{
+#if NETCOREAPP
+ RuntimeNativeMethods.monodroid_log_traces (TraceKind.All, "In JNIEnvInit.Initialize");
+#endif
IntPtr total_timing_sequence = IntPtr.Zero;
IntPtr partial_timing_sequence = IntPtr.Zero;
diff --git a/src/Mono.Android/Android.Runtime/RuntimeNativeMethods.cs b/src/Mono.Android/Android.Runtime/RuntimeNativeMethods.cs
index a0c936c59ff..da635032800 100644
--- a/src/Mono.Android/Android.Runtime/RuntimeNativeMethods.cs
+++ b/src/Mono.Android/Android.Runtime/RuntimeNativeMethods.cs
@@ -6,8 +6,23 @@
namespace Android.Runtime
{
+ // Values must be identical to those in src/monodroid/jni/monodroid-glue-internal.hh
+ [Flags]
+ enum TraceKind : uint
+ {
+ Java = 0x01,
+ Managed = 0x02,
+ Native = 0x04,
+ Signals = 0x08,
+
+ All = Java | Managed | Native | Signals,
+ }
+
internal static class RuntimeNativeMethods
{
+ [DllImport (RuntimeConstants.InternalDllName, CallingConvention = CallingConvention.Cdecl)]
+ internal extern static void monodroid_log_traces (TraceKind kind, string first_line);
+
[DllImport (RuntimeConstants.InternalDllName, CallingConvention = CallingConvention.Cdecl)]
internal extern static void monodroid_log (LogLevel level, LogCategories category, string message);
diff --git a/src/Mono.Android/Java.Interop/TypeManager.cs b/src/Mono.Android/Java.Interop/TypeManager.cs
index fb4e87216a4..924a1d02ef3 100644
--- a/src/Mono.Android/Java.Interop/TypeManager.cs
+++ b/src/Mono.Android/Java.Interop/TypeManager.cs
@@ -224,8 +224,10 @@ static Exception CreateJavaLocationException ()
if (!JNIEnvInit.IsRunningOnDesktop) {
// Miss message is logged in the native runtime
- if (JNIEnvInit.LogAssemblyCategory)
+ if (JNIEnvInit.LogAssemblyCategory) {
JNIEnv.LogTypemapTrace (new System.Diagnostics.StackTrace (true));
+ RuntimeNativeMethods.monodroid_log (LogLevel.Warn, LogCategories.Assembly, CreateJavaLocationException ().ToString ());
+ }
return null;
}
diff --git a/src/Mono.Android/Java.Lang/Thread.cs b/src/Mono.Android/Java.Lang/Thread.cs
index 8c6155f41d3..a17aeebc16f 100644
--- a/src/Mono.Android/Java.Lang/Thread.cs
+++ b/src/Mono.Android/Java.Lang/Thread.cs
@@ -41,7 +41,15 @@ public void Run ()
Dispose ();
}
- static Dictionary instances = new Dictionary ();
+ static Dictionary instances;// = new Dictionary ();
+
+ static RunnableImplementor ()
+ {
+ Console.WriteLine ("RunnableImplementor.cctor (): begin");
+ Console.WriteLine (new System.Diagnostics.StackTrace(true));
+ instances = new ();
+ Console.WriteLine ("RunnableImplementor.cctor (): end");
+ }
public static RunnableImplementor Remove (Action handler)
{
@@ -65,4 +73,3 @@ public Thread (Action runHandler, string threadName) : this (new RunnableImpleme
public Thread (ThreadGroup group, Action runHandler, string threadName, long stackSize) : this (group, new RunnableImplementor (runHandler), threadName, stackSize) {}
}
}
-
diff --git a/src/Mono.Android/java/mono/android/TypeManager.java b/src/Mono.Android/java/mono/android/TypeManager.java
index bf64780bf9e..ab3c1beeef9 100644
--- a/src/Mono.Android/java/mono/android/TypeManager.java
+++ b/src/Mono.Android/java/mono/android/TypeManager.java
@@ -1,20 +1,26 @@
package mono.android;
+//#NOTE: make sure the `#FEATURE=*:START` and `#FEATURE=*:END` lines for different values of FEATURE don't overlap or interlace.
+//#NOTE: Each FEATURE block should be self-contained, with no other FEATURE blocks nested.
+//#NOTE: This is because the code that skips over those FEATURE blocks is VERY primitive (see the `CreateTypeManagerJava` task in XABT)
public class TypeManager {
public static void Activate (String typeName, String sig, Object instance, Object[] parameterList)
{
+//#FEATURE=CALL_TRACING:START - do not remove or modify this line, it is required during application build
+ android.util.Log.i ("monodroid-trace", String.format ("java: activating type: '%s' [%s]", typeName, sig));
+//#FEATURE=CALL_TRACING:END - do not remove or modify this line, it is required during application build
n_activate (typeName, sig, instance, parameterList);
}
private static native void n_activate (String typeName, String sig, Object instance, Object[] parameterList);
-//#MARSHAL_METHODS:START - do not remove or modify this line, it is required during application build
static {
- String methods =
+ String methods =
+//#FEATURE=MARSHAL_METHODS:START - do not remove or modify this line, it is required during application build
"n_activate:(Ljava/lang/String;Ljava/lang/String;Ljava/lang/Object;[Ljava/lang/Object;)V:GetActivateHandler\n" +
+//#FEATURE=MARSHAL_METHODS:END - do not remove or modify this line, it is required during application build
"";
mono.android.Runtime.register ("Java.Interop.TypeManager+JavaTypeManager, Mono.Android, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null", TypeManager.class, methods);
}
-//#MARSHAL_METHODS:END - do not remove or modify this line, it is required during application build
}
diff --git a/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.AssemblyResolution.targets b/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.AssemblyResolution.targets
index ae35d401aee..1d689da575f 100644
--- a/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.AssemblyResolution.targets
+++ b/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.AssemblyResolution.targets
@@ -224,7 +224,8 @@ _ResolveAssemblies MSBuild target.
InputLibraries="@(_ResolvedNativeLibraries)"
ExcludedLibraries="@(_MonoExcludedLibraries)"
Components="@(_MonoComponent->Distinct())"
- IncludeDebugSymbols="$(AndroidIncludeDebugSymbols)">
+ IncludeDebugSymbols="$(AndroidIncludeDebugSymbols)"
+ IncludeNativeTracing="$(_UseNativeStackTraces)">
diff --git a/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.DefaultProperties.targets b/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.DefaultProperties.targets
index 8504ad98ec8..8de29b960d5 100644
--- a/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.DefaultProperties.targets
+++ b/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.DefaultProperties.targets
@@ -45,6 +45,18 @@
false
+
+
+
+ <_AndroidMarshalMethodsTracingMode Condition=" '$(_AndroidMarshalMethodsTracingMode)' == '' ">none
+ <_AndroidUseNativeStackTraces Condition=" '$(_AndroidUseNativeStackTraces)' == '' And '$(_AndroidMarshalMethodsTracingMode)' == 'none' ">false
+ <_AndroidUseNativeStackTraces Condition=" '$(_AndroidUseNativeStackTraces)' == '' And '$(_AndroidMarshalMethodsTracingMode)' != 'none' ">true
+ <_UseNativeStackTraces Condition=" '$(_AndroidUseNativeStackTraces)' == 'true' Or '$(_AndroidMarshalMethodsTracingMode)' != 'none' ">true
+
diff --git a/src/Xamarin.Android.Build.Tasks/Tasks/CreateTypeManagerJava.cs b/src/Xamarin.Android.Build.Tasks/Tasks/CreateTypeManagerJava.cs
index 37872f31927..87309b463d9 100644
--- a/src/Xamarin.Android.Build.Tasks/Tasks/CreateTypeManagerJava.cs
+++ b/src/Xamarin.Android.Build.Tasks/Tasks/CreateTypeManagerJava.cs
@@ -15,6 +15,9 @@ public class CreateTypeManagerJava : AndroidTask
[Required]
public string ResourceName { get; set; }
+ public bool CallTracingEnabled { get; set; }
+ public bool MarshalMethodsEnabled { get; set; }
+
[Required]
public string OutputFilePath { get; set; }
@@ -31,12 +34,18 @@ public override bool RunTask ()
var result = new StringBuilder ();
bool ignoring = false;
foreach (string line in content.Split ('\n')) {
+ if (SkipNoteLine (line)) {
+ continue;
+ }
+
if (!ignoring) {
- if (ignoring = line.StartsWith ("//#MARSHAL_METHODS:START", StringComparison.Ordinal)) {
+ ignoring = StartIgnoring (line, out bool skipLine);
+ if (ignoring || skipLine) {
continue;
}
+
result.AppendLine (line);
- } else if (line.StartsWith ("//#MARSHAL_METHODS:END", StringComparison.Ordinal)) {
+ } else if (EndIgnoring (line)) {
ignoring = false;
}
}
@@ -62,6 +71,38 @@ public override bool RunTask ()
return !Log.HasLoggedErrors;
}
+ bool SkipNoteLine (string l) => l.Trim ().StartsWith ("//#NOTE:");
+
+ bool StartIgnoring (string l, out bool skipLine)
+ {
+ string line = l.Trim ();
+ skipLine = true;
+ if (MarshalMethodsEnabled && line.StartsWith ("//#FEATURE=MARSHAL_METHODS:START", StringComparison.Ordinal)) {
+ return true;
+ }
+
+ if (!CallTracingEnabled && line.StartsWith ("//#FEATURE=CALL_TRACING:START", StringComparison.Ordinal)) {
+ return true;
+ }
+
+ skipLine = line.StartsWith ("//#FEATURE", StringComparison.Ordinal);
+ return false;
+ }
+
+ bool EndIgnoring (string l)
+ {
+ string line = l.Trim ();
+ if (MarshalMethodsEnabled && line.StartsWith ("//#FEATURE=MARSHAL_METHODS:END", StringComparison.Ordinal)) {
+ return true;
+ }
+
+ if (!CallTracingEnabled && line.StartsWith ("//#FEATURE=CALL_TRACING:END", StringComparison.Ordinal)) {
+ return true;
+ }
+
+ return false;
+ }
+
string? ReadResource (string resourceName)
{
using (var from = ExecutingAssembly.GetManifestResourceStream (resourceName)) {
diff --git a/src/Xamarin.Android.Build.Tasks/Tasks/GenerateJavaStubs.cs b/src/Xamarin.Android.Build.Tasks/Tasks/GenerateJavaStubs.cs
index 453885d1758..50f4c54ddaf 100644
--- a/src/Xamarin.Android.Build.Tasks/Tasks/GenerateJavaStubs.cs
+++ b/src/Xamarin.Android.Build.Tasks/Tasks/GenerateJavaStubs.cs
@@ -229,7 +229,7 @@ void Run (XAAssemblyResolver res, bool useMarshalMethods)
MarshalMethodsClassifier classifier = null;
if (useMarshalMethods) {
- classifier = new MarshalMethodsClassifier (cache, res, Log);
+ classifier = new MarshalMethodsClassifier (cache, res, Log, IntermediateOutputDirectory);
}
// Step 2 - Generate Java stub code
@@ -374,9 +374,9 @@ void Run (XAAssemblyResolver res, bool useMarshalMethods)
foreach (JavaType jt in javaTypes) {
TypeDefinition type = jt.Type;
if (JavaNativeTypeManager.IsApplication (type, cache) || JavaNativeTypeManager.IsInstrumentation (type, cache)) {
- if (classifier != null && !classifier.FoundDynamicallyRegisteredMethods (type)) {
- continue;
- }
+ // if (classifier != null && !classifier.FoundDynamicallyRegisteredMethods (type)) {
+ // continue;
+ // }
string javaKey = JavaNativeTypeManager.ToJniName (type, cache).Replace ('/', '.');
regCallsWriter.WriteLine ("\t\tmono.android.Runtime.register (\"{0}\", {1}.class, {1}.__md_methods);",
@@ -392,6 +392,7 @@ void Run (XAAssemblyResolver res, bool useMarshalMethods)
if (useMarshalMethods) {
classifier.AddSpecialCaseMethods ();
+ classifier.FlushAndCloseOutputs ();
Log.LogDebugMessage ($"Number of generated marshal methods: {classifier.MarshalMethods.Count}");
@@ -485,7 +486,7 @@ bool CreateJavaSources (IEnumerable newJavaTypes, TypeDefinitionCache
using (var writer = MemoryStreamPool.Shared.CreateStreamWriter ()) {
try {
var jcw_type = CecilImporter.CreateType (t, cache, reader_options);
-
+
jcw_type.Generate (writer, writer_options);
if (useMarshalMethods) {
diff --git a/src/Xamarin.Android.Build.Tasks/Tasks/GeneratePackageManagerJava.cs b/src/Xamarin.Android.Build.Tasks/Tasks/GeneratePackageManagerJava.cs
index 101f70f84c6..58b8fa7ed16 100644
--- a/src/Xamarin.Android.Build.Tasks/Tasks/GeneratePackageManagerJava.cs
+++ b/src/Xamarin.Android.Build.Tasks/Tasks/GeneratePackageManagerJava.cs
@@ -23,6 +23,7 @@ public class GeneratePackageManagerJava : AndroidTask
public override string TaskPrefix => "GPM";
Guid buildId = Guid.NewGuid ();
+ MarshalMethodsTracingMode mmTracingMode;
[Required]
public ITaskItem[] ResolvedAssemblies { get; set; }
@@ -66,6 +67,7 @@ public class GeneratePackageManagerJava : AndroidTask
public bool InstantRunEnabled { get; set; }
public bool EnableMarshalMethods { get; set; }
+ public string MarshalMethodsTracingMode { get; set; }
public string RuntimeConfigBinFilePath { get; set; }
public string BoundExceptionType { get; set; }
@@ -91,6 +93,8 @@ bool _Debug {
public override bool RunTask ()
{
+ mmTracingMode = MonoAndroidHelper.ParseMarshalMethodsTracingMode (MarshalMethodsTracingMode);
+
BuildId = buildId.ToString ();
Log.LogDebugMessage (" [Output] BuildId: {0}", BuildId);
@@ -389,7 +393,8 @@ void AddEnvironment ()
Log,
assemblyCount,
uniqueAssemblyNames,
- marshalMethodsState?.MarshalMethods
+ marshalMethodsState?.MarshalMethods,
+ mmTracingMode
);
} else {
marshalMethodsAsmGen = new MarshalMethodsNativeAssemblyGenerator (Log, assemblyCount, uniqueAssemblyNames);
diff --git a/src/Xamarin.Android.Build.Tasks/Tasks/LinkApplicationSharedLibraries.cs b/src/Xamarin.Android.Build.Tasks/Tasks/LinkApplicationSharedLibraries.cs
index 5f4b09ececa..1d8b17327ec 100644
--- a/src/Xamarin.Android.Build.Tasks/Tasks/LinkApplicationSharedLibraries.cs
+++ b/src/Xamarin.Android.Build.Tasks/Tasks/LinkApplicationSharedLibraries.cs
@@ -44,8 +44,16 @@ sealed class InputFiles
[Required]
public string AndroidBinUtilsDirectory { get; set; }
+ public string MarshalMethodsTracingMode { get; set; }
+
+ MarshalMethodsTracingMode mmTracingMode;
+ bool mmTracingEnabled;
+
public override System.Threading.Tasks.Task RunTaskAsync ()
{
+ mmTracingMode = MonoAndroidHelper.ParseMarshalMethodsTracingMode (MarshalMethodsTracingMode);
+ mmTracingEnabled = mmTracingMode != Tasks.MarshalMethodsTracingMode.None;
+
return this.WhenAll (GetLinkerConfigs (), RunLinker);
}
@@ -122,6 +130,7 @@ IEnumerable GetLinkerConfigs ()
abis [abi] = GatherFilesForABI (item.ItemSpec, abi, ObjectFiles, runtimeNativeLibsDir, runtimeNativeLibStubsDir);
}
+ // "--eh-frame-hdr " +
const string commonLinkerArgs =
"--shared " +
"--allow-shlib-undefined " +
@@ -134,7 +143,7 @@ IEnumerable GetLinkerConfigs ()
"--warn-shared-textrel " +
"--fatal-warnings";
- string stripSymbolsArg = DebugBuild ? String.Empty : " -s";
+ string stripSymbolsArg = DebugBuild || mmTracingEnabled ? String.Empty : " -s";
string ld = Path.Combine (AndroidBinUtilsDirectory, MonoAndroidHelper.GetExecutablePath (AndroidBinUtilsDirectory, "ld"));
var targetLinkerArgs = new List ();
@@ -208,6 +217,11 @@ InputFiles GatherFilesForABI (string runtimeSharedLibrary, string abi, ITaskItem
"-lc",
};
+ if (mmTracingEnabled) {
+ extraLibraries.Add (Path.Combine (runtimeLibsDir, "libmarshal-methods-tracing.a"));
+ extraLibraries.Add ("-lxamarin-native-tracing");
+ }
+
return new InputFiles {
OutputSharedLibrary = runtimeSharedLibrary,
ObjectFiles = GetItemsForABI (abi, objectFiles),
diff --git a/src/Xamarin.Android.Build.Tasks/Tasks/ProcessNativeLibraries.cs b/src/Xamarin.Android.Build.Tasks/Tasks/ProcessNativeLibraries.cs
index 4970875d659..30a57d1398b 100644
--- a/src/Xamarin.Android.Build.Tasks/Tasks/ProcessNativeLibraries.cs
+++ b/src/Xamarin.Android.Build.Tasks/Tasks/ProcessNativeLibraries.cs
@@ -30,6 +30,7 @@ public class ProcessNativeLibraries : AndroidTask
public string [] ExcludedLibraries { get; set; }
public bool IncludeDebugSymbols { get; set; }
+ public bool IncludeNativeTracing { get; set; }
[Output]
public ITaskItem [] OutputLibraries { get; set; }
@@ -82,6 +83,9 @@ public override bool RunTask ()
if (!wantedComponents.Contains (fileName)) {
continue;
}
+ } else if (!IncludeNativeTracing && String.Compare ("libxamarin-native-tracing", fileName, StringComparison.Ordinal) == 0) {
+ Log.LogDebugMessage ($"Excluding '{library.ItemSpec}' because native stack traces support is disabled");
+ continue;
} else if (ExcludedLibraries != null && ExcludedLibraries.Contains (fileName, StringComparer.OrdinalIgnoreCase)) {
Log.LogDebugMessage ($"Excluding '{library.ItemSpec}'");
continue;
diff --git a/src/Xamarin.Android.Build.Tasks/Utilities/ApplicationConfigNativeAssemblyGenerator.cs b/src/Xamarin.Android.Build.Tasks/Utilities/ApplicationConfigNativeAssemblyGenerator.cs
index cee11386b4a..e0109172d26 100644
--- a/src/Xamarin.Android.Build.Tasks/Utilities/ApplicationConfigNativeAssemblyGenerator.cs
+++ b/src/Xamarin.Android.Build.Tasks/Utilities/ApplicationConfigNativeAssemblyGenerator.cs
@@ -7,6 +7,7 @@
using Microsoft.Build.Framework;
using Microsoft.Build.Utilities;
using Microsoft.Android.Build.Tasks;
+
using Xamarin.Android.Tasks.LLVMIR;
namespace Xamarin.Android.Tasks
@@ -298,7 +299,6 @@ void HashAndSortDSOCache (LlvmIrVariable variable, LlvmIrModuleTarget target, ob
if (entry == null) {
throw new InvalidOperationException ($"Internal error: DSO cache entry has unexpected type {instance.Obj.GetType ()}");
}
-
entry.hash = MonoAndroidHelper.GetXxHash (entry.HashedName, is64Bit);
}
diff --git a/src/Xamarin.Android.Build.Tasks/Utilities/JniRemappingAssemblyGenerator.cs b/src/Xamarin.Android.Build.Tasks/Utilities/JniRemappingAssemblyGenerator.cs
index dd6d0924fff..375025bfeb9 100644
--- a/src/Xamarin.Android.Build.Tasks/Utilities/JniRemappingAssemblyGenerator.cs
+++ b/src/Xamarin.Android.Build.Tasks/Utilities/JniRemappingAssemblyGenerator.cs
@@ -210,6 +210,8 @@ public JniRemappingAssemblyGenerator (TaskLoggingHelper log, List> ();
+ Console.WriteLine ($"Type replacement input count: {typeReplacementsInput.Count}");
+
foreach (JniRemappingTypeReplacement mtr in typeReplacementsInput) {
var entry = new JniRemappingTypeReplacementEntry {
name = MakeJniRemappingString (mtr.From),
diff --git a/src/Xamarin.Android.Build.Tasks/Utilities/MarshalMethodsAssemblyRewriter.cs b/src/Xamarin.Android.Build.Tasks/Utilities/MarshalMethodsAssemblyRewriter.cs
index 96063bf2126..01c7412811a 100644
--- a/src/Xamarin.Android.Build.Tasks/Utilities/MarshalMethodsAssemblyRewriter.cs
+++ b/src/Xamarin.Android.Build.Tasks/Utilities/MarshalMethodsAssemblyRewriter.cs
@@ -299,6 +299,12 @@ void GenerateNonBlittableConversion (TypeReference sourceType, TypeReference tar
return;
}
+ if (IsCharConversion (sourceType, targetType)) {
+ // No need to generate any code. Java's `char` is unsigned 16-bit type, the same as
+ // .NET's
+ return;
+ }
+
ThrowUnsupportedType (sourceType);
}
@@ -332,6 +338,19 @@ bool IsBooleanConversion (TypeReference sourceType, TypeReference targetType)
return false;
}
+ bool IsCharConversion (TypeReference sourceType, TypeReference targetType)
+ {
+ if (String.Compare ("System.Char", sourceType.FullName, StringComparison.Ordinal) == 0) {
+ if (String.Compare ("System.UInt16", targetType.FullName, StringComparison.Ordinal) != 0) {
+ throw new InvalidOperationException ($"Unexpected conversion from '{sourceType.FullName}' to '{targetType.FullName}'");
+ }
+
+ return true;
+ }
+
+ return false;
+ }
+
void ThrowUnsupportedType (TypeReference type)
{
throw new InvalidOperationException ($"Unsupported non-blittable type '{type.FullName}'");
@@ -436,6 +455,12 @@ TypeReference MapToBlittableTypeIfNecessary (TypeReference type, out bool typeMa
return ReturnValid (typeof(byte));
}
+ if (String.Compare ("System.Char", type.FullName, StringComparison.Ordinal) == 0) {
+ // Maps to Java JNI's jchar which is an unsigned 16-bit type
+ typeMapped = true;
+ return ReturnValid (typeof(ushort));
+ }
+
throw new NotSupportedException ($"Cannot map unsupported blittable type '{type.FullName}'");
TypeReference ReturnValid (Type typeToLookUp)
diff --git a/src/Xamarin.Android.Build.Tasks/Utilities/MarshalMethodsClassifier.cs b/src/Xamarin.Android.Build.Tasks/Utilities/MarshalMethodsClassifier.cs
index 0792f992daa..0611a6a454b 100644
--- a/src/Xamarin.Android.Build.Tasks/Utilities/MarshalMethodsClassifier.cs
+++ b/src/Xamarin.Android.Build.Tasks/Utilities/MarshalMethodsClassifier.cs
@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
+using System.IO;
using System.Linq;
using Java.Interop.Tools.Cecil;
@@ -233,13 +234,14 @@ public bool Matches (MethodDefinition method)
HashSet typesWithDynamicallyRegisteredMethods;
ulong rejectedMethodCount = 0;
ulong wrappedMethodCount = 0;
+ StreamWriter ignoredMethodsLog;
public IDictionary> MarshalMethods => marshalMethods;
public ICollection Assemblies => assemblies;
public ulong RejectedMethodCount => rejectedMethodCount;
public ulong WrappedMethodCount => wrappedMethodCount;
- public MarshalMethodsClassifier (TypeDefinitionCache tdCache, XAAssemblyResolver res, TaskLoggingHelper log)
+ public MarshalMethodsClassifier (TypeDefinitionCache tdCache, DirectoryAssemblyResolver res, TaskLoggingHelper log, string intermediateOutputDirectory)
{
this.log = log ?? throw new ArgumentNullException (nameof (log));
this.tdCache = tdCache ?? throw new ArgumentNullException (nameof (tdCache));
@@ -247,6 +249,17 @@ public MarshalMethodsClassifier (TypeDefinitionCache tdCache, XAAssemblyResolver
marshalMethods = new Dictionary> (StringComparer.Ordinal);
assemblies = new HashSet ();
typesWithDynamicallyRegisteredMethods = new HashSet ();
+
+ var fs = File.Open (Path.Combine (intermediateOutputDirectory, "marshal-methods-ignored.txt"), FileMode.Create);
+ ignoredMethodsLog = new StreamWriter (fs, Files.UTF8withoutBOM);
+ }
+
+ public void FlushAndCloseOutputs ()
+ {
+ ignoredMethodsLog.WriteLine ();
+ ignoredMethodsLog.WriteLine ($"Marshal methods count: {MarshalMethods.Count}; Rejected methods count: {RejectedMethodCount}");
+ ignoredMethodsLog.Flush ();
+ ignoredMethodsLog.Close ();
}
public override bool ShouldBeDynamicallyRegistered (TypeDefinition topType, MethodDefinition registeredMethod, MethodDefinition implementedMethod, CustomAttribute? registerAttribute)
@@ -422,6 +435,15 @@ bool IsDynamicallyRegistered (TypeDefinition topType, MethodDefinition registere
return true;
}
+ void LogIgnored (TypeDefinition type, MethodDefinition method, string message, bool logWarning = true)
+ {
+ if (logWarning) {
+ log.LogWarning (message);
+ }
+
+ ignoredMethodsLog.WriteLine ($"{type.FullName}\t{method.FullName}\t{message}");
+ }
+
bool IsStandardHandler (TypeDefinition topType, ConnectorInfo connector, MethodDefinition registeredMethod, MethodDefinition implementedMethod, string jniName, string jniSignature)
{
const string HandlerNameStart = "Get";
@@ -446,23 +468,23 @@ bool IsStandardHandler (TypeDefinition topType, ConnectorInfo connector, MethodD
MethodDefinition connectorMethod = FindMethod (connectorDeclaringType, connectorName);
if (connectorMethod == null) {
- log.LogWarning ($"\tConnector method '{connectorName}' not found in type '{connectorDeclaringType.FullName}'");
+ LogIgnored (topType, registeredMethod, $"\tConnector method '{connectorName}' not found in type '{connectorDeclaringType.FullName}'");
return false;
}
if (String.Compare ("System.Delegate", connectorMethod.ReturnType.FullName, StringComparison.Ordinal) != 0) {
- log.LogWarning ($"\tConnector '{connectorName}' in type '{connectorDeclaringType.FullName}' has invalid return type, expected 'System.Delegate', found '{connectorMethod.ReturnType.FullName}'");
+ LogIgnored (topType, registeredMethod, $"\tConnector '{connectorName}' in type '{connectorDeclaringType.FullName}' has invalid return type, expected 'System.Delegate', found '{connectorMethod.ReturnType.FullName}'");
return false;
}
var ncbs = new NativeCallbackSignature (registeredMethod, log, tdCache);
MethodDefinition nativeCallbackMethod = FindMethod (connectorDeclaringType, nativeCallbackName, ncbs);
if (nativeCallbackMethod == null) {
- log.LogWarning ($"\tUnable to find native callback method '{nativeCallbackName}' in type '{connectorDeclaringType.FullName}', matching the '{registeredMethod.FullName}' signature (jniName: '{jniName}')");
+ LogIgnored (topType, registeredMethod, $"\tUnable to find native callback method '{nativeCallbackName}' in type '{connectorDeclaringType.FullName}', matching the '{registeredMethod.FullName}' signature (jniName: '{jniName}')");
return false;
}
- if (!EnsureIsValidUnmanagedCallersOnlyTarget (nativeCallbackMethod, out bool needsBlittableWorkaround)) {
+ if (!EnsureIsValidUnmanagedCallersOnlyTarget (topType, registeredMethod, nativeCallbackMethod, out bool needsBlittableWorkaround)) {
return false;
}
@@ -471,7 +493,7 @@ bool IsStandardHandler (TypeDefinition topType, ConnectorInfo connector, MethodD
FieldDefinition delegateField = FindField (nativeCallbackMethod.DeclaringType, delegateFieldName);
if (delegateField != null) {
if (String.Compare ("System.Delegate", delegateField.FieldType.FullName, StringComparison.Ordinal) != 0) {
- log.LogWarning ($"\tdelegate field '{delegateFieldName}' in type '{nativeCallbackMethod.DeclaringType.FullName}' has invalid type, expected 'System.Delegate', found '{delegateField.FieldType.FullName}'");
+ LogIgnored (topType, registeredMethod, $"\tdelegate field '{delegateFieldName}' in type '{nativeCallbackMethod.DeclaringType.FullName}' has invalid type, expected 'System.Delegate', found '{delegateField.FieldType.FullName}'");
return false;
}
}
@@ -530,23 +552,23 @@ bool IsStandardHandler (TypeDefinition topType, ConnectorInfo connector, MethodD
return true;
}
- bool EnsureIsValidUnmanagedCallersOnlyTarget (MethodDefinition method, out bool needsBlittableWorkaround)
+ bool EnsureIsValidUnmanagedCallersOnlyTarget (TypeDefinition topType, MethodDefinition registeredMethod, MethodDefinition nativeCallbackMethod, out bool needsBlittableWorkaround)
{
needsBlittableWorkaround = false;
// Requirements: https://docs.microsoft.com/en-us/dotnet/api/system.runtime.interopservices.unmanagedcallersonlyattribute?view=net-6.0#remarks
- if (!method.IsStatic) {
+ if (!nativeCallbackMethod.IsStatic) {
return LogReasonWhyAndReturnFailure ($"is not static");
}
- if (method.HasGenericParameters) {
+ if (nativeCallbackMethod.HasGenericParameters) {
return LogReasonWhyAndReturnFailure ($"has generic parameters");
}
TypeReference type;
bool needsWrapper = false;
- if (String.Compare ("System.Void", method.ReturnType.FullName, StringComparison.Ordinal) != 0) {
- type = GetRealType (method.ReturnType);
+ if (String.Compare ("System.Void", nativeCallbackMethod.ReturnType.FullName, StringComparison.Ordinal) != 0) {
+ type = GetRealType (nativeCallbackMethod.ReturnType);
if (!IsAcceptable (type)) {
needsBlittableWorkaround = true;
WarnWhy ($"has a non-blittable return type '{type.FullName}'");
@@ -554,15 +576,15 @@ bool EnsureIsValidUnmanagedCallersOnlyTarget (MethodDefinition method, out bool
}
}
- if (method.DeclaringType.HasGenericParameters) {
+ if (nativeCallbackMethod.DeclaringType.HasGenericParameters) {
return LogReasonWhyAndReturnFailure ($"is declared in a type with generic parameters");
}
- if (!method.HasParameters) {
+ if (!nativeCallbackMethod.HasParameters) {
return UpdateWrappedCountAndReturn (true);
}
- foreach (ParameterDefinition pdef in method.Parameters) {
+ foreach (ParameterDefinition pdef in nativeCallbackMethod.Parameters) {
type = GetRealType (pdef.ParameterType);
if (!IsAcceptable (type)) {
@@ -606,14 +628,14 @@ TypeReference GetRealType (TypeReference type)
bool LogReasonWhyAndReturnFailure (string why)
{
- log.LogWarning ($"Method '{method.FullName}' {why}. It cannot be used with the `[UnmanagedCallersOnly]` attribute");
+ LogIgnored (topType, registeredMethod, $"Method '{nativeCallbackMethod.FullName}' {why}. It cannot be used with the `[UnmanagedCallersOnly]` attribute");
return false;
}
void WarnWhy (string why)
{
// TODO: change to LogWarning once the generator can output code which requires no non-blittable wrappers
- log.LogDebugMessage ($"Method '{method.FullName}' {why}. A workaround is required, this may make the application slower");
+ log.LogDebugMessage ($"Method '{nativeCallbackMethod.FullName}' {why}. A workaround is required, this may make the application slower");
}
}
diff --git a/src/Xamarin.Android.Build.Tasks/Utilities/MarshalMethodsNativeAssemblyGenerator.Tracing.cs b/src/Xamarin.Android.Build.Tasks/Utilities/MarshalMethodsNativeAssemblyGenerator.Tracing.cs
new file mode 100644
index 00000000000..7f4afc832c9
--- /dev/null
+++ b/src/Xamarin.Android.Build.Tasks/Utilities/MarshalMethodsNativeAssemblyGenerator.Tracing.cs
@@ -0,0 +1,603 @@
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.Text;
+
+using Xamarin.Android.Tools;
+using Xamarin.Android.Tasks.LLVMIR;
+
+namespace Xamarin.Android.Tasks;
+
+using CecilMethodDefinition = global::Mono.Cecil.MethodDefinition;
+using CecilParameterDefinition = global::Mono.Cecil.ParameterDefinition;
+
+partial class MarshalMethodsNativeAssemblyGenerator
+{
+ sealed class LlvmLifetimePointerSizeArgumentPlaceholder : LlvmIrInstructionPointerSizeArgumentPlaceholder
+ {
+ public override object? GetValue (LlvmIrModuleTarget target)
+ {
+ // the llvm.lifetime functions need a 64-bit integer, target.NativePointerSize is 32-bit
+ return (ulong)(uint)base.GetValue (target);
+ }
+ }
+
+ enum TracingRenderArgumentFunction
+ {
+ None,
+ GetClassName,
+ GetObjectClassname,
+ GetCString,
+ GetBooleanString,
+ }
+
+ sealed class TracingState
+ {
+ public List