diff --git a/samples/Hello/Program.cs b/samples/Hello/Program.cs
index 293b6305e..07e573414 100644
--- a/samples/Hello/Program.cs
+++ b/samples/Hello/Program.cs
@@ -1,4 +1,5 @@
using System;
+using System.Diagnostics;
using System.Threading;
using Mono.Options;
@@ -9,10 +10,13 @@ namespace Hello
{
class App
{
+ const int N = 1000000;
+
public static void Main (string[] args)
{
string? jvmPath = global::Java.InteropTests.TestJVM.GetJvmLibraryPath ();
bool createMultipleVMs = false;
+ bool reportTiming = false;
bool showHelp = false;
var options = new OptionSet () {
"Using the JVM from C#!",
@@ -24,6 +28,9 @@ public static void Main (string[] args)
{ "m",
"Create multiple Java VMs. This will likely creash.",
v => createMultipleVMs = v != null },
+ { "t",
+ $"Timing; invoke Object.hashCode() {N} times, print average.",
+ v => reportTiming = v != null },
{ "h|help",
"Show this message and exit.",
v => showHelp = v != null },
@@ -33,23 +40,25 @@ public static void Main (string[] args)
options.WriteOptionDescriptions (Console.Out);
return;
}
- Console.WriteLine ("Hello World!");
var builder = new JreRuntimeOptions () {
JniAddNativeMethodRegistrationAttributePresent = true,
JvmLibraryPath = jvmPath,
};
builder.AddOption ("-Xcheck:jni");
+
var jvm = builder.CreateJreVM ();
- Console.WriteLine ($"JniRuntime.CurrentRuntime == jvm? {ReferenceEquals (JniRuntime.CurrentRuntime, jvm)}");
- foreach (var h in JniRuntime.GetAvailableInvocationPointers ()) {
- Console.WriteLine ("PRE: GetCreatedJavaVMHandles: {0}", h);
- }
- CreateJLO ();
+ if (reportTiming) {
+ ReportTiming ();
+ return;
+ }
if (createMultipleVMs) {
CreateAnotherJVM ();
+ return;
}
+
+ CreateJLO ();
}
static void CreateJLO ()
@@ -58,6 +67,17 @@ static void CreateJLO ()
Console.WriteLine ($"binding? {jlo.ToString ()}");
}
+ static void ReportTiming ()
+ {
+ var jlo = new Java.Lang.Object ();
+ var t = Stopwatch.StartNew ();
+ for (int i = 0; i < N; ++i) {
+ jlo.GetHashCode ();
+ }
+ t.Stop ();
+ Console.WriteLine ($"Object.hashCode: {N} invocations. Total={t.Elapsed}; Average={t.Elapsed.TotalMilliseconds / (double) N}ms");
+ }
+
static unsafe void CreateAnotherJVM ()
{
Console.WriteLine ("Part 2!");
diff --git a/src/Java.Interop/Java.Interop.csproj b/src/Java.Interop/Java.Interop.csproj
index 0d666353f..95d0802f0 100644
--- a/src/Java.Interop/Java.Interop.csproj
+++ b/src/Java.Interop/Java.Interop.csproj
@@ -26,7 +26,8 @@
$(ToolOutputFullPath)
$(ToolOutputFullPath)Java.Interop.xml
$(BuildToolOutputFullPath)
- 8.0
+ 9.0
+ 8.0
enable
true
NU1702
diff --git a/src/Java.Interop/Java.Interop/JavaArray.cs b/src/Java.Interop/Java.Interop/JavaArray.cs
index d2c69234b..5b05131b4 100644
--- a/src/Java.Interop/Java.Interop/JavaArray.cs
+++ b/src/Java.Interop/Java.Interop/JavaArray.cs
@@ -231,9 +231,9 @@ bool IList.IsFixedSize {
object? IList.this [int index] {
get {return this [index];}
-#pragma warning disable 8601
+#pragma warning disable 8600,8601
set {this [index] = (T) value;}
-#pragma warning restore 8601
+#pragma warning restore 8600,8601
}
void ICollection.CopyTo (Array array, int index)
diff --git a/src/Java.Interop/Java.Interop/JniEnvironment.Types.cs b/src/Java.Interop/Java.Interop/JniEnvironment.Types.cs
index cfa49f8d9..af0ca4ff1 100644
--- a/src/Java.Interop/Java.Interop/JniEnvironment.Types.cs
+++ b/src/Java.Interop/Java.Interop/JniEnvironment.Types.cs
@@ -31,7 +31,12 @@ static Types ()
}
}
- public static unsafe JniObjectReference FindClass (string classname)
+ public static JniObjectReference FindClass (string classname)
+ {
+ return TryFindClass (classname, throwOnError: true);
+ }
+
+ static unsafe JniObjectReference TryFindClass (string classname, bool throwOnError)
{
if (classname == null)
throw new ArgumentNullException (nameof (classname));
@@ -85,6 +90,10 @@ public static unsafe JniObjectReference FindClass (string classname)
}
}
+ if (!throwOnError) {
+ (pendingException as IJavaPeerable)?.Dispose ();
+ return default;
+ }
throw pendingException!;
#endif // !FEATURE_JNIENVIRONMENT_JI_PINVOKES
#if FEATURE_JNIOBJECTREFERENCE_SAFEHANDLES
@@ -120,10 +129,27 @@ public static unsafe JniObjectReference FindClass (string classname)
var loadClassThrown = new JniObjectReference (thrown, JniObjectReferenceType.Local);
LogCreateLocalRef (loadClassThrown);
pendingException = info.Runtime.GetExceptionForThrowable (ref loadClassThrown, JniObjectReferenceOptions.CopyAndDispose);
+ if (!throwOnError) {
+ (pendingException as IJavaPeerable)?.Dispose ();
+ return default;
+ }
throw pendingException!;
#endif // !FEATURE_JNIOBJECTREFERENCE_SAFEHANDLES
}
+#if NET
+ public static bool TryFindClass (string classname, out JniObjectReference instance)
+ {
+ if (classname == null)
+ throw new ArgumentNullException (nameof (classname));
+ if (classname.Length == 0)
+ throw new ArgumentException ("'classname' cannot be a zero-length string.", nameof (classname));
+
+ instance = TryFindClass (classname, throwOnError: false);
+ return instance.IsValid;
+ }
+#endif // NET
+
public static JniType? GetTypeFromInstance (JniObjectReference instance)
{
if (!instance.IsValid)
diff --git a/src/Java.Interop/Java.Interop/JniMemberSignature.cs b/src/Java.Interop/Java.Interop/JniMemberSignature.cs
new file mode 100644
index 000000000..946cf7bb5
--- /dev/null
+++ b/src/Java.Interop/Java.Interop/JniMemberSignature.cs
@@ -0,0 +1,134 @@
+#nullable enable
+
+#if NET
+
+using System;
+using System.Diagnostics.CodeAnalysis;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.Reflection;
+using System.Runtime.InteropServices;
+using System.Runtime.Versioning;
+
+namespace Java.Interop
+{
+ public struct JniMemberSignature : IEquatable
+ {
+ public static readonly JniMemberSignature Empty;
+
+ string? memberName;
+ string? memberSignature;
+
+ public string MemberName => memberName ?? throw new InvalidOperationException ();
+ public string MemberSignature => memberSignature ?? throw new InvalidOperationException ();
+
+ public JniMemberSignature (string memberName, string memberSignature)
+ {
+ if (string.IsNullOrEmpty (memberName)) {
+ throw new ArgumentNullException (nameof (memberName));
+ }
+ if (string.IsNullOrEmpty (memberSignature)) {
+ throw new ArgumentNullException (nameof (memberSignature));
+ }
+ this.memberName = memberName;
+ this.memberSignature = memberSignature;
+ }
+
+ public static int GetParameterCountFromMethodSignature (string jniMethodSignature)
+ {
+ if (jniMethodSignature.Length < "()V".Length || jniMethodSignature [0] != '(' ) {
+ throw new ArgumentException (
+ $"Member signature `{jniMethodSignature}` is not a method signature. Method signatures must start with `(`.",
+ nameof (jniMethodSignature));
+ }
+ int count = 0;
+ int index = 1;
+ while (index < jniMethodSignature.Length &&
+ jniMethodSignature [index] != ')') {
+ ExtractType (jniMethodSignature, ref index);
+ count++;
+ }
+ return count;
+ }
+
+ internal static (int StartIndex, int Length) ExtractType (string signature, ref int index)
+ {
+ AssertSignatureIndex (signature, index);
+ var i = index++;
+ switch (signature [i]) {
+ case '[':
+ if ((i+1) >= signature.Length)
+ throw new InvalidOperationException ($"Missing array type after '[' at index {i} in: `{signature}`");
+ var rest = ExtractType (signature, ref index);
+ return (StartIndex: i, Length: index - i);
+ case 'B':
+ case 'C':
+ case 'D':
+ case 'F':
+ case 'I':
+ case 'J':
+ case 'S':
+ case 'V':
+ case 'Z':
+ return (StartIndex: i, Length: 1);
+ case 'L':
+ int depth = 0;
+ int e = index;
+ while (e < signature.Length) {
+ var c = signature [e++];
+ if (depth == 0 && c == ';')
+ break;
+ }
+ if (e > signature.Length)
+ throw new InvalidOperationException ($"Missing reference type after `{signature [i]}` at index {i} in `{signature}`!");
+ index = e;
+ return (StartIndex: i, Length: (e - i));
+ default:
+ throw new InvalidOperationException ($"Unknown JNI Type `{signature [i]}` within: `{signature}`!");
+ }
+ }
+
+ internal static void AssertSignatureIndex (string signature, int index)
+ {
+ if (signature == null)
+ throw new ArgumentNullException (nameof (signature));
+ if (signature.Length == 0)
+ throw new ArgumentException ("Descriptor cannot be empty string", nameof (signature));
+ if (index >= signature.Length)
+ throw new ArgumentException ("index >= descriptor.Length", nameof (index));
+ }
+
+ public override int GetHashCode ()
+ {
+ return (memberName?.GetHashCode () ?? 0) ^
+ (memberSignature?.GetHashCode () ?? 0);
+ }
+
+ public override bool Equals (object? obj)
+ {
+ var v = obj as JniMemberSignature?;
+ if (v.HasValue)
+ return Equals (v.Value);
+ return false;
+ }
+
+ public bool Equals (JniMemberSignature other)
+ {
+ return memberName == other.memberName &&
+ memberSignature == other.memberSignature;
+ }
+
+ public override string ToString ()
+ {
+ return $"{nameof (JniMemberSignature)} {{ " +
+ $"{nameof (MemberName)} = {(memberName == null ? "null" : "\"" + memberName + "\"")}" +
+ $", {nameof (MemberSignature)} = {(memberSignature == null ? "null" : "\"" + memberSignature + "\"")}" +
+ $"}}";
+ }
+
+ public static bool operator== (JniMemberSignature a, JniMemberSignature b) => a.Equals (b);
+ public static bool operator!= (JniMemberSignature a, JniMemberSignature b) => !a.Equals (b);
+ }
+}
+
+#endif // NET
diff --git a/src/Java.Interop/Java.Interop/JniMethodInfo.cs b/src/Java.Interop/Java.Interop/JniMethodInfo.cs
index b2458fae7..d8f4bf3bc 100644
--- a/src/Java.Interop/Java.Interop/JniMethodInfo.cs
+++ b/src/Java.Interop/Java.Interop/JniMethodInfo.cs
@@ -10,6 +10,11 @@ public sealed class JniMethodInfo
public bool IsStatic {get; private set;}
+#if NET
+ internal JniType? StaticRedirect;
+ internal int? ParameterCount;
+#endif //NET
+
internal bool IsValid {
get {return ID != IntPtr.Zero;}
}
diff --git a/src/Java.Interop/Java.Interop/JniPeerMembers.JniInstanceMethods.cs b/src/Java.Interop/Java.Interop/JniPeerMembers.JniInstanceMethods.cs
index 2a825486c..cee7af696 100644
--- a/src/Java.Interop/Java.Interop/JniPeerMembers.JniInstanceMethods.cs
+++ b/src/Java.Interop/Java.Interop/JniPeerMembers.JniInstanceMethods.cs
@@ -84,14 +84,46 @@ internal JniInstanceMethods GetConstructorsForType (Type declaringType)
public JniMethodInfo GetMethodInfo (string encodedMember)
{
lock (InstanceMethods) {
- if (!InstanceMethods.TryGetValue (encodedMember, out var m)) {
- string method, signature;
- JniPeerMembers.GetNameAndSignature (encodedMember, out method, out signature);
- m = JniPeerType.GetInstanceMethod (method, signature);
- InstanceMethods.Add (encodedMember, m);
+ if (InstanceMethods.TryGetValue (encodedMember, out var m)) {
+ return m;
}
- return m;
}
+ string method, signature;
+ JniPeerMembers.GetNameAndSignature (encodedMember, out method, out signature);
+ var info = GetMethodInfo (method, signature);
+ lock (InstanceMethods) {
+ if (InstanceMethods.TryGetValue (encodedMember, out var m)) {
+ return m;
+ }
+ InstanceMethods.Add (encodedMember, info);
+ }
+ return info;
+ }
+
+ JniMethodInfo GetMethodInfo (string method, string signature)
+ {
+#if NET
+ var m = (JniMethodInfo?) null;
+ var newMethod = JniEnvironment.Runtime.TypeManager.GetReplacementMethodInfo (Members.JniPeerTypeName, method, signature);
+ if (newMethod.HasValue) {
+ var typeName = newMethod.Value.TargetJniType ?? Members.JniPeerTypeName;
+ var methodName = newMethod.Value.TargetJniMethodName ?? method;
+ var methodSig = newMethod.Value.TargetJniMethodSignature ?? signature;
+
+ using var t = new JniType (typeName);
+ if (newMethod.Value.TargetJniMethodInstanceToStatic &&
+ t.TryGetStaticMethod (methodName, methodSig, out m)) {
+ m.ParameterCount = newMethod.Value.TargetJniMethodParameterCount;
+ m.StaticRedirect = new JniType (typeName);
+ return m;
+ }
+ if (t.TryGetInstanceMethod (methodName, methodSig, out m)) {
+ return m;
+ }
+ Console.Error.WriteLine ($"warning: For declared method `{Members.JniPeerTypeName}.{method}.{signature}`, could not find requested method `{typeName}.{methodName}.{methodSig}`!");
+ }
+#endif // NET
+ return JniPeerType.GetInstanceMethod (method, signature);
}
public unsafe JniObjectReference StartCreateInstance (string constructorSignature, Type declaringType, JniArgumentValue* parameters)
diff --git a/src/Java.Interop/Java.Interop/JniPeerMembers.JniInstanceMethods_Invoke.cs b/src/Java.Interop/Java.Interop/JniPeerMembers.JniInstanceMethods_Invoke.cs
index df5325a22..0e96fa29c 100644
--- a/src/Java.Interop/Java.Interop/JniPeerMembers.JniInstanceMethods_Invoke.cs
+++ b/src/Java.Interop/Java.Interop/JniPeerMembers.JniInstanceMethods_Invoke.cs
@@ -1,6 +1,7 @@
#nullable enable
using System;
+using System.Diagnostics;
namespace Java.Interop {
@@ -8,33 +9,76 @@ partial class JniPeerMembers {
partial class JniInstanceMethods {
+#pragma warning disable CA1801
+ static unsafe bool TryInvokeVoidStaticRedirect (JniMethodInfo method, IJavaPeerable self, JniArgumentValue* parameters)
+ {
+
+#if !NET
+ return false;
+#else // NET
+ if (method.StaticRedirect == null || !method.ParameterCount.HasValue) {
+ return false;
+ }
+
+ int c = method.ParameterCount.Value;
+ Debug.Assert (c > 0);
+ var p = stackalloc JniArgumentValue [c];
+ p [0] = new JniArgumentValue (self);
+ for (int i = 0; i < c-1; ++i) {
+ p [i+1] = parameters [i];
+ }
+
+ JniEnvironment.StaticMethods.CallStaticVoidMethod (method.StaticRedirect.PeerReference, method, p);
+ return true;
+#endif // NET
+ }
+#pragma warning restore CA1801
+
public unsafe void InvokeAbstractVoidMethod (string encodedMember, IJavaPeerable self, JniArgumentValue* parameters)
{
JniPeerMembers.AssertSelf (self);
- var m = GetMethodInfo (encodedMember);
+ try {
+ var m = GetMethodInfo (encodedMember);
+ if (TryInvokeVoidStaticRedirect (m, self, parameters)) {
+ return;
+ }
- JniEnvironment.InstanceMethods.CallVoidMethod (self.PeerReference, m, parameters);
- GC.KeepAlive (self);
- return;
+ JniEnvironment.InstanceMethods.CallVoidMethod (self.PeerReference, m, parameters);
+ return;
+ }
+ finally {
+ GC.KeepAlive (self);
+ }
}
public unsafe void InvokeVirtualVoidMethod (string encodedMember, IJavaPeerable self, JniArgumentValue* parameters)
{
JniPeerMembers.AssertSelf (self);
- var declaringType = DeclaringType;
- if (Members.UsesVirtualDispatch (self, declaringType)) {
- var m = GetMethodInfo (encodedMember);
- JniEnvironment.InstanceMethods.CallVoidMethod (self.PeerReference, m, parameters);
+ try {
+ var declaringType = DeclaringType;
+ if (Members.UsesVirtualDispatch (self, declaringType)) {
+ var m = GetMethodInfo (encodedMember);
+ if (TryInvokeVoidStaticRedirect (m, self, parameters)) {
+ return;
+ }
+ JniEnvironment.InstanceMethods.CallVoidMethod (self.PeerReference, m, parameters);
+ return;
+ }
+ var j = Members.GetPeerMembers (self);
+ var n = j.InstanceMethods.GetMethodInfo (encodedMember);
+ do {
+ if (TryInvokeVoidStaticRedirect (n, self, parameters)) {
+ return;
+ }
+ JniEnvironment.InstanceMethods.CallNonvirtualVoidMethod (self.PeerReference, j.JniPeerType.PeerReference, n, parameters);
+ return;
+ } while (false);
+ }
+ finally {
GC.KeepAlive (self);
- return;
}
- var j = Members.GetPeerMembers (self);
- var n = j.InstanceMethods.GetMethodInfo (encodedMember);
- JniEnvironment.InstanceMethods.CallNonvirtualVoidMethod (self.PeerReference, j.JniPeerType.PeerReference, n, parameters);
- GC.KeepAlive (self);
- return;
}
public unsafe void InvokeNonvirtualVoidMethod (string encodedMember, IJavaPeerable self, JniArgumentValue* parameters)
@@ -42,39 +86,88 @@ public unsafe void InvokeNonvirtualVoidMethod (string encodedMember, IJavaPeerab
JniPeerMembers.AssertSelf (self);
var m = GetMethodInfo (encodedMember);
+ try {
+ if (TryInvokeVoidStaticRedirect (m, self, parameters)) {
+ return;
+ }
+ JniEnvironment.InstanceMethods.CallNonvirtualVoidMethod (self.PeerReference, JniPeerType.PeerReference, m, parameters);
+ return;
+ }
+ finally {
+ GC.KeepAlive (self);
+ }
+ }
+
+#pragma warning disable CA1801
+ static unsafe bool TryInvokeBooleanStaticRedirect (JniMethodInfo method, IJavaPeerable self, JniArgumentValue* parameters, out bool r)
+ {
+ r = default;
+#if !NET
+ return false;
+#else // NET
+ if (method.StaticRedirect == null || !method.ParameterCount.HasValue) {
+ return false;
+ }
- JniEnvironment.InstanceMethods.CallNonvirtualVoidMethod (self.PeerReference, JniPeerType.PeerReference, m, parameters);
- GC.KeepAlive (self);
- return;
+ int c = method.ParameterCount.Value;
+ Debug.Assert (c > 0);
+ var p = stackalloc JniArgumentValue [c];
+ p [0] = new JniArgumentValue (self);
+ for (int i = 0; i < c-1; ++i) {
+ p [i+1] = parameters [i];
+ }
+
+ r = JniEnvironment.StaticMethods.CallStaticBooleanMethod (method.StaticRedirect.PeerReference, method, p);
+ return true;
+#endif // NET
}
+#pragma warning restore CA1801
public unsafe bool InvokeAbstractBooleanMethod (string encodedMember, IJavaPeerable self, JniArgumentValue* parameters)
{
JniPeerMembers.AssertSelf (self);
- var m = GetMethodInfo (encodedMember);
+ try {
+ var m = GetMethodInfo (encodedMember);
+ if (TryInvokeBooleanStaticRedirect (m, self, parameters, out bool r)) {
+ return r;
+ }
- var r = JniEnvironment.InstanceMethods.CallBooleanMethod (self.PeerReference, m, parameters);
- GC.KeepAlive (self);
- return r;
+ r = JniEnvironment.InstanceMethods.CallBooleanMethod (self.PeerReference, m, parameters);
+ return r;
+ }
+ finally {
+ GC.KeepAlive (self);
+ }
}
public unsafe bool InvokeVirtualBooleanMethod (string encodedMember, IJavaPeerable self, JniArgumentValue* parameters)
{
JniPeerMembers.AssertSelf (self);
- var declaringType = DeclaringType;
- if (Members.UsesVirtualDispatch (self, declaringType)) {
- var m = GetMethodInfo (encodedMember);
- var _nr = JniEnvironment.InstanceMethods.CallBooleanMethod (self.PeerReference, m, parameters);
+ try {
+ var declaringType = DeclaringType;
+ if (Members.UsesVirtualDispatch (self, declaringType)) {
+ var m = GetMethodInfo (encodedMember);
+ if (TryInvokeBooleanStaticRedirect (m, self, parameters, out bool r)) {
+ return r;
+ }
+ r = JniEnvironment.InstanceMethods.CallBooleanMethod (self.PeerReference, m, parameters);
+ return r;
+ }
+ var j = Members.GetPeerMembers (self);
+ var n = j.InstanceMethods.GetMethodInfo (encodedMember);
+ do {
+ if (TryInvokeBooleanStaticRedirect (n, self, parameters, out bool r)) {
+ return r;
+ }
+ r = JniEnvironment.InstanceMethods.CallNonvirtualBooleanMethod (self.PeerReference, j.JniPeerType.PeerReference, n, parameters);
+ return r;
+ } while (false);
+ }
+ finally {
GC.KeepAlive (self);
- return _nr;
}
- var j = Members.GetPeerMembers (self);
- var n = j.InstanceMethods.GetMethodInfo (encodedMember);
- var r = JniEnvironment.InstanceMethods.CallNonvirtualBooleanMethod (self.PeerReference, j.JniPeerType.PeerReference, n, parameters);
- GC.KeepAlive (self);
- return r;
}
public unsafe bool InvokeNonvirtualBooleanMethod (string encodedMember, IJavaPeerable self, JniArgumentValue* parameters)
@@ -82,39 +175,88 @@ public unsafe bool InvokeNonvirtualBooleanMethod (string encodedMember, IJavaPee
JniPeerMembers.AssertSelf (self);
var m = GetMethodInfo (encodedMember);
+ try {
+ if (TryInvokeBooleanStaticRedirect (m, self, parameters, out bool r)) {
+ return r;
+ }
+ r = JniEnvironment.InstanceMethods.CallNonvirtualBooleanMethod (self.PeerReference, JniPeerType.PeerReference, m, parameters);
+ return r;
+ }
+ finally {
+ GC.KeepAlive (self);
+ }
+ }
+
+#pragma warning disable CA1801
+ static unsafe bool TryInvokeSByteStaticRedirect (JniMethodInfo method, IJavaPeerable self, JniArgumentValue* parameters, out sbyte r)
+ {
+ r = default;
+#if !NET
+ return false;
+#else // NET
+ if (method.StaticRedirect == null || !method.ParameterCount.HasValue) {
+ return false;
+ }
- var r = JniEnvironment.InstanceMethods.CallNonvirtualBooleanMethod (self.PeerReference, JniPeerType.PeerReference, m, parameters);
- GC.KeepAlive (self);
- return r;
+ int c = method.ParameterCount.Value;
+ Debug.Assert (c > 0);
+ var p = stackalloc JniArgumentValue [c];
+ p [0] = new JniArgumentValue (self);
+ for (int i = 0; i < c-1; ++i) {
+ p [i+1] = parameters [i];
+ }
+
+ r = JniEnvironment.StaticMethods.CallStaticByteMethod (method.StaticRedirect.PeerReference, method, p);
+ return true;
+#endif // NET
}
+#pragma warning restore CA1801
public unsafe sbyte InvokeAbstractSByteMethod (string encodedMember, IJavaPeerable self, JniArgumentValue* parameters)
{
JniPeerMembers.AssertSelf (self);
- var m = GetMethodInfo (encodedMember);
+ try {
+ var m = GetMethodInfo (encodedMember);
+ if (TryInvokeSByteStaticRedirect (m, self, parameters, out sbyte r)) {
+ return r;
+ }
- var r = JniEnvironment.InstanceMethods.CallByteMethod (self.PeerReference, m, parameters);
- GC.KeepAlive (self);
- return r;
+ r = JniEnvironment.InstanceMethods.CallByteMethod (self.PeerReference, m, parameters);
+ return r;
+ }
+ finally {
+ GC.KeepAlive (self);
+ }
}
public unsafe sbyte InvokeVirtualSByteMethod (string encodedMember, IJavaPeerable self, JniArgumentValue* parameters)
{
JniPeerMembers.AssertSelf (self);
- var declaringType = DeclaringType;
- if (Members.UsesVirtualDispatch (self, declaringType)) {
- var m = GetMethodInfo (encodedMember);
- var _nr = JniEnvironment.InstanceMethods.CallByteMethod (self.PeerReference, m, parameters);
+ try {
+ var declaringType = DeclaringType;
+ if (Members.UsesVirtualDispatch (self, declaringType)) {
+ var m = GetMethodInfo (encodedMember);
+ if (TryInvokeSByteStaticRedirect (m, self, parameters, out sbyte r)) {
+ return r;
+ }
+ r = JniEnvironment.InstanceMethods.CallByteMethod (self.PeerReference, m, parameters);
+ return r;
+ }
+ var j = Members.GetPeerMembers (self);
+ var n = j.InstanceMethods.GetMethodInfo (encodedMember);
+ do {
+ if (TryInvokeSByteStaticRedirect (n, self, parameters, out sbyte r)) {
+ return r;
+ }
+ r = JniEnvironment.InstanceMethods.CallNonvirtualByteMethod (self.PeerReference, j.JniPeerType.PeerReference, n, parameters);
+ return r;
+ } while (false);
+ }
+ finally {
GC.KeepAlive (self);
- return _nr;
}
- var j = Members.GetPeerMembers (self);
- var n = j.InstanceMethods.GetMethodInfo (encodedMember);
- var r = JniEnvironment.InstanceMethods.CallNonvirtualByteMethod (self.PeerReference, j.JniPeerType.PeerReference, n, parameters);
- GC.KeepAlive (self);
- return r;
}
public unsafe sbyte InvokeNonvirtualSByteMethod (string encodedMember, IJavaPeerable self, JniArgumentValue* parameters)
@@ -122,39 +264,88 @@ public unsafe sbyte InvokeNonvirtualSByteMethod (string encodedMember, IJavaPeer
JniPeerMembers.AssertSelf (self);
var m = GetMethodInfo (encodedMember);
+ try {
+ if (TryInvokeSByteStaticRedirect (m, self, parameters, out sbyte r)) {
+ return r;
+ }
+ r = JniEnvironment.InstanceMethods.CallNonvirtualByteMethod (self.PeerReference, JniPeerType.PeerReference, m, parameters);
+ return r;
+ }
+ finally {
+ GC.KeepAlive (self);
+ }
+ }
+
+#pragma warning disable CA1801
+ static unsafe bool TryInvokeCharStaticRedirect (JniMethodInfo method, IJavaPeerable self, JniArgumentValue* parameters, out char r)
+ {
+ r = default;
+#if !NET
+ return false;
+#else // NET
+ if (method.StaticRedirect == null || !method.ParameterCount.HasValue) {
+ return false;
+ }
- var r = JniEnvironment.InstanceMethods.CallNonvirtualByteMethod (self.PeerReference, JniPeerType.PeerReference, m, parameters);
- GC.KeepAlive (self);
- return r;
+ int c = method.ParameterCount.Value;
+ Debug.Assert (c > 0);
+ var p = stackalloc JniArgumentValue [c];
+ p [0] = new JniArgumentValue (self);
+ for (int i = 0; i < c-1; ++i) {
+ p [i+1] = parameters [i];
+ }
+
+ r = JniEnvironment.StaticMethods.CallStaticCharMethod (method.StaticRedirect.PeerReference, method, p);
+ return true;
+#endif // NET
}
+#pragma warning restore CA1801
public unsafe char InvokeAbstractCharMethod (string encodedMember, IJavaPeerable self, JniArgumentValue* parameters)
{
JniPeerMembers.AssertSelf (self);
- var m = GetMethodInfo (encodedMember);
+ try {
+ var m = GetMethodInfo (encodedMember);
+ if (TryInvokeCharStaticRedirect (m, self, parameters, out char r)) {
+ return r;
+ }
- var r = JniEnvironment.InstanceMethods.CallCharMethod (self.PeerReference, m, parameters);
- GC.KeepAlive (self);
- return r;
+ r = JniEnvironment.InstanceMethods.CallCharMethod (self.PeerReference, m, parameters);
+ return r;
+ }
+ finally {
+ GC.KeepAlive (self);
+ }
}
public unsafe char InvokeVirtualCharMethod (string encodedMember, IJavaPeerable self, JniArgumentValue* parameters)
{
JniPeerMembers.AssertSelf (self);
- var declaringType = DeclaringType;
- if (Members.UsesVirtualDispatch (self, declaringType)) {
- var m = GetMethodInfo (encodedMember);
- var _nr = JniEnvironment.InstanceMethods.CallCharMethod (self.PeerReference, m, parameters);
+ try {
+ var declaringType = DeclaringType;
+ if (Members.UsesVirtualDispatch (self, declaringType)) {
+ var m = GetMethodInfo (encodedMember);
+ if (TryInvokeCharStaticRedirect (m, self, parameters, out char r)) {
+ return r;
+ }
+ r = JniEnvironment.InstanceMethods.CallCharMethod (self.PeerReference, m, parameters);
+ return r;
+ }
+ var j = Members.GetPeerMembers (self);
+ var n = j.InstanceMethods.GetMethodInfo (encodedMember);
+ do {
+ if (TryInvokeCharStaticRedirect (n, self, parameters, out char r)) {
+ return r;
+ }
+ r = JniEnvironment.InstanceMethods.CallNonvirtualCharMethod (self.PeerReference, j.JniPeerType.PeerReference, n, parameters);
+ return r;
+ } while (false);
+ }
+ finally {
GC.KeepAlive (self);
- return _nr;
}
- var j = Members.GetPeerMembers (self);
- var n = j.InstanceMethods.GetMethodInfo (encodedMember);
- var r = JniEnvironment.InstanceMethods.CallNonvirtualCharMethod (self.PeerReference, j.JniPeerType.PeerReference, n, parameters);
- GC.KeepAlive (self);
- return r;
}
public unsafe char InvokeNonvirtualCharMethod (string encodedMember, IJavaPeerable self, JniArgumentValue* parameters)
@@ -162,39 +353,88 @@ public unsafe char InvokeNonvirtualCharMethod (string encodedMember, IJavaPeerab
JniPeerMembers.AssertSelf (self);
var m = GetMethodInfo (encodedMember);
+ try {
+ if (TryInvokeCharStaticRedirect (m, self, parameters, out char r)) {
+ return r;
+ }
+ r = JniEnvironment.InstanceMethods.CallNonvirtualCharMethod (self.PeerReference, JniPeerType.PeerReference, m, parameters);
+ return r;
+ }
+ finally {
+ GC.KeepAlive (self);
+ }
+ }
+
+#pragma warning disable CA1801
+ static unsafe bool TryInvokeInt16StaticRedirect (JniMethodInfo method, IJavaPeerable self, JniArgumentValue* parameters, out short r)
+ {
+ r = default;
+#if !NET
+ return false;
+#else // NET
+ if (method.StaticRedirect == null || !method.ParameterCount.HasValue) {
+ return false;
+ }
- var r = JniEnvironment.InstanceMethods.CallNonvirtualCharMethod (self.PeerReference, JniPeerType.PeerReference, m, parameters);
- GC.KeepAlive (self);
- return r;
+ int c = method.ParameterCount.Value;
+ Debug.Assert (c > 0);
+ var p = stackalloc JniArgumentValue [c];
+ p [0] = new JniArgumentValue (self);
+ for (int i = 0; i < c-1; ++i) {
+ p [i+1] = parameters [i];
+ }
+
+ r = JniEnvironment.StaticMethods.CallStaticShortMethod (method.StaticRedirect.PeerReference, method, p);
+ return true;
+#endif // NET
}
+#pragma warning restore CA1801
public unsafe short InvokeAbstractInt16Method (string encodedMember, IJavaPeerable self, JniArgumentValue* parameters)
{
JniPeerMembers.AssertSelf (self);
- var m = GetMethodInfo (encodedMember);
+ try {
+ var m = GetMethodInfo (encodedMember);
+ if (TryInvokeInt16StaticRedirect (m, self, parameters, out short r)) {
+ return r;
+ }
- var r = JniEnvironment.InstanceMethods.CallShortMethod (self.PeerReference, m, parameters);
- GC.KeepAlive (self);
- return r;
+ r = JniEnvironment.InstanceMethods.CallShortMethod (self.PeerReference, m, parameters);
+ return r;
+ }
+ finally {
+ GC.KeepAlive (self);
+ }
}
public unsafe short InvokeVirtualInt16Method (string encodedMember, IJavaPeerable self, JniArgumentValue* parameters)
{
JniPeerMembers.AssertSelf (self);
- var declaringType = DeclaringType;
- if (Members.UsesVirtualDispatch (self, declaringType)) {
- var m = GetMethodInfo (encodedMember);
- var _nr = JniEnvironment.InstanceMethods.CallShortMethod (self.PeerReference, m, parameters);
+ try {
+ var declaringType = DeclaringType;
+ if (Members.UsesVirtualDispatch (self, declaringType)) {
+ var m = GetMethodInfo (encodedMember);
+ if (TryInvokeInt16StaticRedirect (m, self, parameters, out short r)) {
+ return r;
+ }
+ r = JniEnvironment.InstanceMethods.CallShortMethod (self.PeerReference, m, parameters);
+ return r;
+ }
+ var j = Members.GetPeerMembers (self);
+ var n = j.InstanceMethods.GetMethodInfo (encodedMember);
+ do {
+ if (TryInvokeInt16StaticRedirect (n, self, parameters, out short r)) {
+ return r;
+ }
+ r = JniEnvironment.InstanceMethods.CallNonvirtualShortMethod (self.PeerReference, j.JniPeerType.PeerReference, n, parameters);
+ return r;
+ } while (false);
+ }
+ finally {
GC.KeepAlive (self);
- return _nr;
}
- var j = Members.GetPeerMembers (self);
- var n = j.InstanceMethods.GetMethodInfo (encodedMember);
- var r = JniEnvironment.InstanceMethods.CallNonvirtualShortMethod (self.PeerReference, j.JniPeerType.PeerReference, n, parameters);
- GC.KeepAlive (self);
- return r;
}
public unsafe short InvokeNonvirtualInt16Method (string encodedMember, IJavaPeerable self, JniArgumentValue* parameters)
@@ -202,39 +442,88 @@ public unsafe short InvokeNonvirtualInt16Method (string encodedMember, IJavaPeer
JniPeerMembers.AssertSelf (self);
var m = GetMethodInfo (encodedMember);
+ try {
+ if (TryInvokeInt16StaticRedirect (m, self, parameters, out short r)) {
+ return r;
+ }
+ r = JniEnvironment.InstanceMethods.CallNonvirtualShortMethod (self.PeerReference, JniPeerType.PeerReference, m, parameters);
+ return r;
+ }
+ finally {
+ GC.KeepAlive (self);
+ }
+ }
+
+#pragma warning disable CA1801
+ static unsafe bool TryInvokeInt32StaticRedirect (JniMethodInfo method, IJavaPeerable self, JniArgumentValue* parameters, out int r)
+ {
+ r = default;
+#if !NET
+ return false;
+#else // NET
+ if (method.StaticRedirect == null || !method.ParameterCount.HasValue) {
+ return false;
+ }
- var r = JniEnvironment.InstanceMethods.CallNonvirtualShortMethod (self.PeerReference, JniPeerType.PeerReference, m, parameters);
- GC.KeepAlive (self);
- return r;
+ int c = method.ParameterCount.Value;
+ Debug.Assert (c > 0);
+ var p = stackalloc JniArgumentValue [c];
+ p [0] = new JniArgumentValue (self);
+ for (int i = 0; i < c-1; ++i) {
+ p [i+1] = parameters [i];
+ }
+
+ r = JniEnvironment.StaticMethods.CallStaticIntMethod (method.StaticRedirect.PeerReference, method, p);
+ return true;
+#endif // NET
}
+#pragma warning restore CA1801
public unsafe int InvokeAbstractInt32Method (string encodedMember, IJavaPeerable self, JniArgumentValue* parameters)
{
JniPeerMembers.AssertSelf (self);
- var m = GetMethodInfo (encodedMember);
+ try {
+ var m = GetMethodInfo (encodedMember);
+ if (TryInvokeInt32StaticRedirect (m, self, parameters, out int r)) {
+ return r;
+ }
- var r = JniEnvironment.InstanceMethods.CallIntMethod (self.PeerReference, m, parameters);
- GC.KeepAlive (self);
- return r;
+ r = JniEnvironment.InstanceMethods.CallIntMethod (self.PeerReference, m, parameters);
+ return r;
+ }
+ finally {
+ GC.KeepAlive (self);
+ }
}
public unsafe int InvokeVirtualInt32Method (string encodedMember, IJavaPeerable self, JniArgumentValue* parameters)
{
JniPeerMembers.AssertSelf (self);
- var declaringType = DeclaringType;
- if (Members.UsesVirtualDispatch (self, declaringType)) {
- var m = GetMethodInfo (encodedMember);
- var _nr = JniEnvironment.InstanceMethods.CallIntMethod (self.PeerReference, m, parameters);
+ try {
+ var declaringType = DeclaringType;
+ if (Members.UsesVirtualDispatch (self, declaringType)) {
+ var m = GetMethodInfo (encodedMember);
+ if (TryInvokeInt32StaticRedirect (m, self, parameters, out int r)) {
+ return r;
+ }
+ r = JniEnvironment.InstanceMethods.CallIntMethod (self.PeerReference, m, parameters);
+ return r;
+ }
+ var j = Members.GetPeerMembers (self);
+ var n = j.InstanceMethods.GetMethodInfo (encodedMember);
+ do {
+ if (TryInvokeInt32StaticRedirect (n, self, parameters, out int r)) {
+ return r;
+ }
+ r = JniEnvironment.InstanceMethods.CallNonvirtualIntMethod (self.PeerReference, j.JniPeerType.PeerReference, n, parameters);
+ return r;
+ } while (false);
+ }
+ finally {
GC.KeepAlive (self);
- return _nr;
}
- var j = Members.GetPeerMembers (self);
- var n = j.InstanceMethods.GetMethodInfo (encodedMember);
- var r = JniEnvironment.InstanceMethods.CallNonvirtualIntMethod (self.PeerReference, j.JniPeerType.PeerReference, n, parameters);
- GC.KeepAlive (self);
- return r;
}
public unsafe int InvokeNonvirtualInt32Method (string encodedMember, IJavaPeerable self, JniArgumentValue* parameters)
@@ -242,39 +531,88 @@ public unsafe int InvokeNonvirtualInt32Method (string encodedMember, IJavaPeerab
JniPeerMembers.AssertSelf (self);
var m = GetMethodInfo (encodedMember);
+ try {
+ if (TryInvokeInt32StaticRedirect (m, self, parameters, out int r)) {
+ return r;
+ }
+ r = JniEnvironment.InstanceMethods.CallNonvirtualIntMethod (self.PeerReference, JniPeerType.PeerReference, m, parameters);
+ return r;
+ }
+ finally {
+ GC.KeepAlive (self);
+ }
+ }
+
+#pragma warning disable CA1801
+ static unsafe bool TryInvokeInt64StaticRedirect (JniMethodInfo method, IJavaPeerable self, JniArgumentValue* parameters, out long r)
+ {
+ r = default;
+#if !NET
+ return false;
+#else // NET
+ if (method.StaticRedirect == null || !method.ParameterCount.HasValue) {
+ return false;
+ }
+
+ int c = method.ParameterCount.Value;
+ Debug.Assert (c > 0);
+ var p = stackalloc JniArgumentValue [c];
+ p [0] = new JniArgumentValue (self);
+ for (int i = 0; i < c-1; ++i) {
+ p [i+1] = parameters [i];
+ }
- var r = JniEnvironment.InstanceMethods.CallNonvirtualIntMethod (self.PeerReference, JniPeerType.PeerReference, m, parameters);
- GC.KeepAlive (self);
- return r;
+ r = JniEnvironment.StaticMethods.CallStaticLongMethod (method.StaticRedirect.PeerReference, method, p);
+ return true;
+#endif // NET
}
+#pragma warning restore CA1801
public unsafe long InvokeAbstractInt64Method (string encodedMember, IJavaPeerable self, JniArgumentValue* parameters)
{
JniPeerMembers.AssertSelf (self);
- var m = GetMethodInfo (encodedMember);
+ try {
+ var m = GetMethodInfo (encodedMember);
+ if (TryInvokeInt64StaticRedirect (m, self, parameters, out long r)) {
+ return r;
+ }
- var r = JniEnvironment.InstanceMethods.CallLongMethod (self.PeerReference, m, parameters);
- GC.KeepAlive (self);
- return r;
+ r = JniEnvironment.InstanceMethods.CallLongMethod (self.PeerReference, m, parameters);
+ return r;
+ }
+ finally {
+ GC.KeepAlive (self);
+ }
}
public unsafe long InvokeVirtualInt64Method (string encodedMember, IJavaPeerable self, JniArgumentValue* parameters)
{
JniPeerMembers.AssertSelf (self);
- var declaringType = DeclaringType;
- if (Members.UsesVirtualDispatch (self, declaringType)) {
- var m = GetMethodInfo (encodedMember);
- var _nr = JniEnvironment.InstanceMethods.CallLongMethod (self.PeerReference, m, parameters);
+ try {
+ var declaringType = DeclaringType;
+ if (Members.UsesVirtualDispatch (self, declaringType)) {
+ var m = GetMethodInfo (encodedMember);
+ if (TryInvokeInt64StaticRedirect (m, self, parameters, out long r)) {
+ return r;
+ }
+ r = JniEnvironment.InstanceMethods.CallLongMethod (self.PeerReference, m, parameters);
+ return r;
+ }
+ var j = Members.GetPeerMembers (self);
+ var n = j.InstanceMethods.GetMethodInfo (encodedMember);
+ do {
+ if (TryInvokeInt64StaticRedirect (n, self, parameters, out long r)) {
+ return r;
+ }
+ r = JniEnvironment.InstanceMethods.CallNonvirtualLongMethod (self.PeerReference, j.JniPeerType.PeerReference, n, parameters);
+ return r;
+ } while (false);
+ }
+ finally {
GC.KeepAlive (self);
- return _nr;
}
- var j = Members.GetPeerMembers (self);
- var n = j.InstanceMethods.GetMethodInfo (encodedMember);
- var r = JniEnvironment.InstanceMethods.CallNonvirtualLongMethod (self.PeerReference, j.JniPeerType.PeerReference, n, parameters);
- GC.KeepAlive (self);
- return r;
}
public unsafe long InvokeNonvirtualInt64Method (string encodedMember, IJavaPeerable self, JniArgumentValue* parameters)
@@ -282,39 +620,88 @@ public unsafe long InvokeNonvirtualInt64Method (string encodedMember, IJavaPeera
JniPeerMembers.AssertSelf (self);
var m = GetMethodInfo (encodedMember);
+ try {
+ if (TryInvokeInt64StaticRedirect (m, self, parameters, out long r)) {
+ return r;
+ }
+ r = JniEnvironment.InstanceMethods.CallNonvirtualLongMethod (self.PeerReference, JniPeerType.PeerReference, m, parameters);
+ return r;
+ }
+ finally {
+ GC.KeepAlive (self);
+ }
+ }
+
+#pragma warning disable CA1801
+ static unsafe bool TryInvokeSingleStaticRedirect (JniMethodInfo method, IJavaPeerable self, JniArgumentValue* parameters, out float r)
+ {
+ r = default;
+#if !NET
+ return false;
+#else // NET
+ if (method.StaticRedirect == null || !method.ParameterCount.HasValue) {
+ return false;
+ }
+
+ int c = method.ParameterCount.Value;
+ Debug.Assert (c > 0);
+ var p = stackalloc JniArgumentValue [c];
+ p [0] = new JniArgumentValue (self);
+ for (int i = 0; i < c-1; ++i) {
+ p [i+1] = parameters [i];
+ }
- var r = JniEnvironment.InstanceMethods.CallNonvirtualLongMethod (self.PeerReference, JniPeerType.PeerReference, m, parameters);
- GC.KeepAlive (self);
- return r;
+ r = JniEnvironment.StaticMethods.CallStaticFloatMethod (method.StaticRedirect.PeerReference, method, p);
+ return true;
+#endif // NET
}
+#pragma warning restore CA1801
public unsafe float InvokeAbstractSingleMethod (string encodedMember, IJavaPeerable self, JniArgumentValue* parameters)
{
JniPeerMembers.AssertSelf (self);
- var m = GetMethodInfo (encodedMember);
+ try {
+ var m = GetMethodInfo (encodedMember);
+ if (TryInvokeSingleStaticRedirect (m, self, parameters, out float r)) {
+ return r;
+ }
- var r = JniEnvironment.InstanceMethods.CallFloatMethod (self.PeerReference, m, parameters);
- GC.KeepAlive (self);
- return r;
+ r = JniEnvironment.InstanceMethods.CallFloatMethod (self.PeerReference, m, parameters);
+ return r;
+ }
+ finally {
+ GC.KeepAlive (self);
+ }
}
public unsafe float InvokeVirtualSingleMethod (string encodedMember, IJavaPeerable self, JniArgumentValue* parameters)
{
JniPeerMembers.AssertSelf (self);
- var declaringType = DeclaringType;
- if (Members.UsesVirtualDispatch (self, declaringType)) {
- var m = GetMethodInfo (encodedMember);
- var _nr = JniEnvironment.InstanceMethods.CallFloatMethod (self.PeerReference, m, parameters);
+ try {
+ var declaringType = DeclaringType;
+ if (Members.UsesVirtualDispatch (self, declaringType)) {
+ var m = GetMethodInfo (encodedMember);
+ if (TryInvokeSingleStaticRedirect (m, self, parameters, out float r)) {
+ return r;
+ }
+ r = JniEnvironment.InstanceMethods.CallFloatMethod (self.PeerReference, m, parameters);
+ return r;
+ }
+ var j = Members.GetPeerMembers (self);
+ var n = j.InstanceMethods.GetMethodInfo (encodedMember);
+ do {
+ if (TryInvokeSingleStaticRedirect (n, self, parameters, out float r)) {
+ return r;
+ }
+ r = JniEnvironment.InstanceMethods.CallNonvirtualFloatMethod (self.PeerReference, j.JniPeerType.PeerReference, n, parameters);
+ return r;
+ } while (false);
+ }
+ finally {
GC.KeepAlive (self);
- return _nr;
}
- var j = Members.GetPeerMembers (self);
- var n = j.InstanceMethods.GetMethodInfo (encodedMember);
- var r = JniEnvironment.InstanceMethods.CallNonvirtualFloatMethod (self.PeerReference, j.JniPeerType.PeerReference, n, parameters);
- GC.KeepAlive (self);
- return r;
}
public unsafe float InvokeNonvirtualSingleMethod (string encodedMember, IJavaPeerable self, JniArgumentValue* parameters)
@@ -322,39 +709,88 @@ public unsafe float InvokeNonvirtualSingleMethod (string encodedMember, IJavaPee
JniPeerMembers.AssertSelf (self);
var m = GetMethodInfo (encodedMember);
+ try {
+ if (TryInvokeSingleStaticRedirect (m, self, parameters, out float r)) {
+ return r;
+ }
+ r = JniEnvironment.InstanceMethods.CallNonvirtualFloatMethod (self.PeerReference, JniPeerType.PeerReference, m, parameters);
+ return r;
+ }
+ finally {
+ GC.KeepAlive (self);
+ }
+ }
- var r = JniEnvironment.InstanceMethods.CallNonvirtualFloatMethod (self.PeerReference, JniPeerType.PeerReference, m, parameters);
- GC.KeepAlive (self);
- return r;
+#pragma warning disable CA1801
+ static unsafe bool TryInvokeDoubleStaticRedirect (JniMethodInfo method, IJavaPeerable self, JniArgumentValue* parameters, out double r)
+ {
+ r = default;
+#if !NET
+ return false;
+#else // NET
+ if (method.StaticRedirect == null || !method.ParameterCount.HasValue) {
+ return false;
+ }
+
+ int c = method.ParameterCount.Value;
+ Debug.Assert (c > 0);
+ var p = stackalloc JniArgumentValue [c];
+ p [0] = new JniArgumentValue (self);
+ for (int i = 0; i < c-1; ++i) {
+ p [i+1] = parameters [i];
+ }
+
+ r = JniEnvironment.StaticMethods.CallStaticDoubleMethod (method.StaticRedirect.PeerReference, method, p);
+ return true;
+#endif // NET
}
+#pragma warning restore CA1801
public unsafe double InvokeAbstractDoubleMethod (string encodedMember, IJavaPeerable self, JniArgumentValue* parameters)
{
JniPeerMembers.AssertSelf (self);
- var m = GetMethodInfo (encodedMember);
+ try {
+ var m = GetMethodInfo (encodedMember);
+ if (TryInvokeDoubleStaticRedirect (m, self, parameters, out double r)) {
+ return r;
+ }
- var r = JniEnvironment.InstanceMethods.CallDoubleMethod (self.PeerReference, m, parameters);
- GC.KeepAlive (self);
- return r;
+ r = JniEnvironment.InstanceMethods.CallDoubleMethod (self.PeerReference, m, parameters);
+ return r;
+ }
+ finally {
+ GC.KeepAlive (self);
+ }
}
public unsafe double InvokeVirtualDoubleMethod (string encodedMember, IJavaPeerable self, JniArgumentValue* parameters)
{
JniPeerMembers.AssertSelf (self);
- var declaringType = DeclaringType;
- if (Members.UsesVirtualDispatch (self, declaringType)) {
- var m = GetMethodInfo (encodedMember);
- var _nr = JniEnvironment.InstanceMethods.CallDoubleMethod (self.PeerReference, m, parameters);
+ try {
+ var declaringType = DeclaringType;
+ if (Members.UsesVirtualDispatch (self, declaringType)) {
+ var m = GetMethodInfo (encodedMember);
+ if (TryInvokeDoubleStaticRedirect (m, self, parameters, out double r)) {
+ return r;
+ }
+ r = JniEnvironment.InstanceMethods.CallDoubleMethod (self.PeerReference, m, parameters);
+ return r;
+ }
+ var j = Members.GetPeerMembers (self);
+ var n = j.InstanceMethods.GetMethodInfo (encodedMember);
+ do {
+ if (TryInvokeDoubleStaticRedirect (n, self, parameters, out double r)) {
+ return r;
+ }
+ r = JniEnvironment.InstanceMethods.CallNonvirtualDoubleMethod (self.PeerReference, j.JniPeerType.PeerReference, n, parameters);
+ return r;
+ } while (false);
+ }
+ finally {
GC.KeepAlive (self);
- return _nr;
}
- var j = Members.GetPeerMembers (self);
- var n = j.InstanceMethods.GetMethodInfo (encodedMember);
- var r = JniEnvironment.InstanceMethods.CallNonvirtualDoubleMethod (self.PeerReference, j.JniPeerType.PeerReference, n, parameters);
- GC.KeepAlive (self);
- return r;
}
public unsafe double InvokeNonvirtualDoubleMethod (string encodedMember, IJavaPeerable self, JniArgumentValue* parameters)
@@ -362,39 +798,88 @@ public unsafe double InvokeNonvirtualDoubleMethod (string encodedMember, IJavaPe
JniPeerMembers.AssertSelf (self);
var m = GetMethodInfo (encodedMember);
+ try {
+ if (TryInvokeDoubleStaticRedirect (m, self, parameters, out double r)) {
+ return r;
+ }
+ r = JniEnvironment.InstanceMethods.CallNonvirtualDoubleMethod (self.PeerReference, JniPeerType.PeerReference, m, parameters);
+ return r;
+ }
+ finally {
+ GC.KeepAlive (self);
+ }
+ }
+
+#pragma warning disable CA1801
+ static unsafe bool TryInvokeObjectStaticRedirect (JniMethodInfo method, IJavaPeerable self, JniArgumentValue* parameters, out JniObjectReference r)
+ {
+ r = default;
+#if !NET
+ return false;
+#else // NET
+ if (method.StaticRedirect == null || !method.ParameterCount.HasValue) {
+ return false;
+ }
- var r = JniEnvironment.InstanceMethods.CallNonvirtualDoubleMethod (self.PeerReference, JniPeerType.PeerReference, m, parameters);
- GC.KeepAlive (self);
- return r;
+ int c = method.ParameterCount.Value;
+ Debug.Assert (c > 0);
+ var p = stackalloc JniArgumentValue [c];
+ p [0] = new JniArgumentValue (self);
+ for (int i = 0; i < c-1; ++i) {
+ p [i+1] = parameters [i];
+ }
+
+ r = JniEnvironment.StaticMethods.CallStaticObjectMethod (method.StaticRedirect.PeerReference, method, p);
+ return true;
+#endif // NET
}
+#pragma warning restore CA1801
public unsafe JniObjectReference InvokeAbstractObjectMethod (string encodedMember, IJavaPeerable self, JniArgumentValue* parameters)
{
JniPeerMembers.AssertSelf (self);
- var m = GetMethodInfo (encodedMember);
+ try {
+ var m = GetMethodInfo (encodedMember);
+ if (TryInvokeObjectStaticRedirect (m, self, parameters, out JniObjectReference r)) {
+ return r;
+ }
- var r = JniEnvironment.InstanceMethods.CallObjectMethod (self.PeerReference, m, parameters);
- GC.KeepAlive (self);
- return r;
+ r = JniEnvironment.InstanceMethods.CallObjectMethod (self.PeerReference, m, parameters);
+ return r;
+ }
+ finally {
+ GC.KeepAlive (self);
+ }
}
public unsafe JniObjectReference InvokeVirtualObjectMethod (string encodedMember, IJavaPeerable self, JniArgumentValue* parameters)
{
JniPeerMembers.AssertSelf (self);
- var declaringType = DeclaringType;
- if (Members.UsesVirtualDispatch (self, declaringType)) {
- var m = GetMethodInfo (encodedMember);
- var _nr = JniEnvironment.InstanceMethods.CallObjectMethod (self.PeerReference, m, parameters);
+ try {
+ var declaringType = DeclaringType;
+ if (Members.UsesVirtualDispatch (self, declaringType)) {
+ var m = GetMethodInfo (encodedMember);
+ if (TryInvokeObjectStaticRedirect (m, self, parameters, out JniObjectReference r)) {
+ return r;
+ }
+ r = JniEnvironment.InstanceMethods.CallObjectMethod (self.PeerReference, m, parameters);
+ return r;
+ }
+ var j = Members.GetPeerMembers (self);
+ var n = j.InstanceMethods.GetMethodInfo (encodedMember);
+ do {
+ if (TryInvokeObjectStaticRedirect (n, self, parameters, out JniObjectReference r)) {
+ return r;
+ }
+ r = JniEnvironment.InstanceMethods.CallNonvirtualObjectMethod (self.PeerReference, j.JniPeerType.PeerReference, n, parameters);
+ return r;
+ } while (false);
+ }
+ finally {
GC.KeepAlive (self);
- return _nr;
}
- var j = Members.GetPeerMembers (self);
- var n = j.InstanceMethods.GetMethodInfo (encodedMember);
- var r = JniEnvironment.InstanceMethods.CallNonvirtualObjectMethod (self.PeerReference, j.JniPeerType.PeerReference, n, parameters);
- GC.KeepAlive (self);
- return r;
}
public unsafe JniObjectReference InvokeNonvirtualObjectMethod (string encodedMember, IJavaPeerable self, JniArgumentValue* parameters)
@@ -402,10 +887,16 @@ public unsafe JniObjectReference InvokeNonvirtualObjectMethod (string encodedMem
JniPeerMembers.AssertSelf (self);
var m = GetMethodInfo (encodedMember);
-
- var r = JniEnvironment.InstanceMethods.CallNonvirtualObjectMethod (self.PeerReference, JniPeerType.PeerReference, m, parameters);
- GC.KeepAlive (self);
- return r;
+ try {
+ if (TryInvokeObjectStaticRedirect (m, self, parameters, out JniObjectReference r)) {
+ return r;
+ }
+ r = JniEnvironment.InstanceMethods.CallNonvirtualObjectMethod (self.PeerReference, JniPeerType.PeerReference, m, parameters);
+ return r;
+ }
+ finally {
+ GC.KeepAlive (self);
+ }
}
}
}
diff --git a/src/Java.Interop/Java.Interop/JniPeerMembers.JniInstanceMethods_Invoke.tt b/src/Java.Interop/Java.Interop/JniPeerMembers.JniInstanceMethods_Invoke.tt
index 04f8178fd..a326b6b1f 100644
--- a/src/Java.Interop/Java.Interop/JniPeerMembers.JniInstanceMethods_Invoke.tt
+++ b/src/Java.Interop/Java.Interop/JniPeerMembers.JniInstanceMethods_Invoke.tt
@@ -21,6 +21,7 @@
#nullable enable
using System;
+using System.Diagnostics;
namespace Java.Interop {
@@ -29,35 +30,83 @@ namespace Java.Interop {
partial class JniInstanceMethods {
<#
foreach (var returnType in jniReturnTypes) {
+ string byRefParamDecl = returnType.ReturnType == "void" ? "" : ", out " + returnType.ReturnType + " r";
+ // string byRefParam = returnType.ReturnType == "void" ? "" : " r";
+ string setByRefToDefault = returnType.ReturnType == "void" ? "" : "r = default;";
+ string setByRefParam = returnType.ReturnType == "void" ? "" : "r = ";
+ string returnByRefParam = returnType.ReturnType == "void" ? "return" : "return r";
#>
+#pragma warning disable CA1801
+ static unsafe bool TryInvoke<#= returnType.ManagedType #>StaticRedirect (JniMethodInfo method, IJavaPeerable self, JniArgumentValue* parameters<#= byRefParamDecl #>)
+ {
+ <#= setByRefToDefault #>
+#if !NET
+ return false;
+#else // NET
+ if (method.StaticRedirect == null || !method.ParameterCount.HasValue) {
+ return false;
+ }
+
+ int c = method.ParameterCount.Value;
+ Debug.Assert (c > 0);
+ var p = stackalloc JniArgumentValue [c];
+ p [0] = new JniArgumentValue (self);
+ for (int i = 0; i < c-1; ++i) {
+ p [i+1] = parameters [i];
+ }
+
+ <#= setByRefParam #>JniEnvironment.StaticMethods.CallStatic<#= returnType.JniCallType #>Method (method.StaticRedirect.PeerReference, method, p);
+ return true;
+#endif // NET
+ }
+#pragma warning restore CA1801
+
public unsafe <#= returnType.ReturnType #> InvokeAbstract<#= returnType.ManagedType #>Method (string encodedMember, IJavaPeerable self, JniArgumentValue* parameters)
{
JniPeerMembers.AssertSelf (self);
- var m = GetMethodInfo (encodedMember);
+ try {
+ var m = GetMethodInfo (encodedMember);
+ if (TryInvoke<#= returnType.ManagedType #>StaticRedirect (m, self, parameters<#= byRefParamDecl #>)) {
+ <#= returnByRefParam #>;
+ }
- <#= returnType.ReturnType != "void" ? "var r = " : "" #>JniEnvironment.InstanceMethods.Call<#= returnType.JniCallType #>Method (self.PeerReference, m, parameters);
- GC.KeepAlive (self);
- return<#= returnType.ReturnType == "void" ? "" : " r" #>;
+ <#= setByRefParam #>JniEnvironment.InstanceMethods.Call<#= returnType.JniCallType #>Method (self.PeerReference, m, parameters);
+ <#= returnByRefParam #>;
+ }
+ finally {
+ GC.KeepAlive (self);
+ }
}
public unsafe <#= returnType.ReturnType #> InvokeVirtual<#= returnType.ManagedType #>Method (string encodedMember, IJavaPeerable self, JniArgumentValue* parameters)
{
JniPeerMembers.AssertSelf (self);
- var declaringType = DeclaringType;
- if (Members.UsesVirtualDispatch (self, declaringType)) {
- var m = GetMethodInfo (encodedMember);
- <#= returnType.ReturnType != "void" ? "var _nr = " : "" #>JniEnvironment.InstanceMethods.Call<#= returnType.JniCallType #>Method (self.PeerReference, m, parameters);
+ try {
+ var declaringType = DeclaringType;
+ if (Members.UsesVirtualDispatch (self, declaringType)) {
+ var m = GetMethodInfo (encodedMember);
+ if (TryInvoke<#= returnType.ManagedType #>StaticRedirect (m, self, parameters<#= byRefParamDecl #>)) {
+ <#= returnByRefParam #>;
+ }
+ <#= setByRefParam #>JniEnvironment.InstanceMethods.Call<#= returnType.JniCallType #>Method (self.PeerReference, m, parameters);
+ <#= returnByRefParam #>;
+ }
+ var j = Members.GetPeerMembers (self);
+ var n = j.InstanceMethods.GetMethodInfo (encodedMember);
+ do {
+ if (TryInvoke<#= returnType.ManagedType #>StaticRedirect (n, self, parameters<#= byRefParamDecl #>)) {
+ <#= returnByRefParam #>;
+ }
+ <#= setByRefParam #>JniEnvironment.InstanceMethods.CallNonvirtual<#= returnType.JniCallType #>Method (self.PeerReference, j.JniPeerType.PeerReference, n, parameters);
+ <#= returnByRefParam #>;
+ } while (false);
+ }
+ finally {
GC.KeepAlive (self);
- return<#= returnType.ReturnType == "void" ? "" : " _nr" #>;
}
- var j = Members.GetPeerMembers (self);
- var n = j.InstanceMethods.GetMethodInfo (encodedMember);
- <#= returnType.ReturnType != "void" ? "var r = " : "" #>JniEnvironment.InstanceMethods.CallNonvirtual<#= returnType.JniCallType #>Method (self.PeerReference, j.JniPeerType.PeerReference, n, parameters);
- GC.KeepAlive (self);
- return<#= returnType.ReturnType == "void" ? "" : " r" #>;
}
public unsafe <#= returnType.ReturnType #> InvokeNonvirtual<#= returnType.ManagedType #>Method (string encodedMember, IJavaPeerable self, JniArgumentValue* parameters)
@@ -65,10 +114,16 @@ namespace Java.Interop {
JniPeerMembers.AssertSelf (self);
var m = GetMethodInfo (encodedMember);
-
- <#= returnType.ReturnType != "void" ? "var r = " : "" #>JniEnvironment.InstanceMethods.CallNonvirtual<#= returnType.JniCallType #>Method (self.PeerReference, JniPeerType.PeerReference, m, parameters);
- GC.KeepAlive (self);
- return<#= returnType.ReturnType == "void" ? "" : " r" #>;
+ try {
+ if (TryInvoke<#= returnType.ManagedType #>StaticRedirect (m, self, parameters<#= byRefParamDecl #>)) {
+ <#= returnByRefParam #>;
+ }
+ <#= setByRefParam #>JniEnvironment.InstanceMethods.CallNonvirtual<#= returnType.JniCallType #>Method (self.PeerReference, JniPeerType.PeerReference, m, parameters);
+ <#= returnByRefParam #>;
+ }
+ finally {
+ GC.KeepAlive (self);
+ }
}
<#
}
diff --git a/src/Java.Interop/Java.Interop/JniPeerMembers.JniStaticMethods.cs b/src/Java.Interop/Java.Interop/JniPeerMembers.JniStaticMethods.cs
index 7218668af..d27920a58 100644
--- a/src/Java.Interop/Java.Interop/JniPeerMembers.JniStaticMethods.cs
+++ b/src/Java.Interop/Java.Interop/JniPeerMembers.JniStaticMethods.cs
@@ -25,15 +25,71 @@ internal void Dispose ()
public JniMethodInfo GetMethodInfo (string encodedMember)
{
lock (StaticMethods) {
- if (!StaticMethods.TryGetValue (encodedMember, out var m)) {
- string method, signature;
- JniPeerMembers.GetNameAndSignature (encodedMember, out method, out signature);
- m = Members.JniPeerType.GetStaticMethod (method, signature);
- StaticMethods.Add (encodedMember, m);
+ if (StaticMethods.TryGetValue (encodedMember, out var m)) {
+ return m;
}
+ }
+ string method, signature;
+ JniPeerMembers.GetNameAndSignature (encodedMember, out method, out signature);
+ var info = GetMethodInfo (method, signature);
+ lock (StaticMethods) {
+ if (StaticMethods.TryGetValue (encodedMember, out var m)) {
+ return m;
+ }
+ StaticMethods.Add (encodedMember, info);
+ }
+ return info;
+ }
+
+ JniMethodInfo GetMethodInfo (string method, string signature)
+ {
+#if NET
+ var m = (JniMethodInfo?) null;
+ var newMethod = JniEnvironment.Runtime.TypeManager.GetReplacementMethodInfo (Members.JniPeerTypeName, method, signature);
+ if (newMethod.HasValue) {
+ using var t = new JniType (newMethod.Value.TargetJniType ?? Members.JniPeerTypeName);
+ if (t.TryGetStaticMethod (
+ newMethod.Value.TargetJniMethodName ?? method,
+ newMethod.Value.TargetJniMethodSignature ?? signature,
+ out m)) {
+ return m;
+ }
+ }
+ if (Members.JniPeerType.TryGetStaticMethod (method, signature, out m)) {
return m;
}
+ m = FindInFallbackTypes (method, signature);
+ if (m != null) {
+ return m;
+ }
+#endif // NET
+ return Members.JniPeerType.GetStaticMethod (method, signature);
+ }
+
+#if NET
+ JniMethodInfo? FindInFallbackTypes (string method, string signature)
+ {
+ var fallbackTypes = JniEnvironment.Runtime.TypeManager.GetStaticMethodFallbackTypes (Members.JniPeerTypeName);
+ if (fallbackTypes == null) {
+ return null;
+ }
+ foreach (var ft in fallbackTypes) {
+ JniType? t = null;
+ try {
+ if (!JniType.TryParse (ft, out t)) {
+ continue;
+ }
+ if (t.TryGetStaticMethod (method, signature, out var m)) {
+ return m;
+ }
+ }
+ finally {
+ t?.Dispose ();
+ }
+ }
+ return null;
}
+#endif // NET
public unsafe void InvokeVoidMethod (string encodedMember, JniArgumentValue* parameters)
{
diff --git a/src/Java.Interop/Java.Interop/JniPeerMembers.cs b/src/Java.Interop/Java.Interop/JniPeerMembers.cs
index 29be44adb..9e445be47 100644
--- a/src/Java.Interop/Java.Interop/JniPeerMembers.cs
+++ b/src/Java.Interop/Java.Interop/JniPeerMembers.cs
@@ -17,21 +17,18 @@ public JniPeerMembers (string jniPeerTypeName, Type managedPeerType, bool isInte
}
public JniPeerMembers (string jniPeerTypeName, Type managedPeerType)
- : this (jniPeerTypeName, managedPeerType, checkManagedPeerType: true, isInterface: false)
+ : this (jniPeerTypeName = GetReplacementType (jniPeerTypeName), managedPeerType, checkManagedPeerType: true, isInterface: false)
{
- if (managedPeerType == null)
- throw new ArgumentNullException (nameof (managedPeerType));
- if (!typeof (IJavaPeerable).IsAssignableFrom (managedPeerType))
- throw new ArgumentException ("'managedPeerType' must implement the IJavaPeerable interface.", nameof (managedPeerType));
-
- Debug.Assert (
- JniEnvironment.Runtime.TypeManager.GetTypeSignature (managedPeerType).SimpleReference == jniPeerTypeName,
- string.Format ("ManagedPeerType <=> JniTypeName Mismatch! javaVM.GetJniTypeInfoForType(typeof({0})).JniTypeName=\"{1}\" != \"{2}\"",
- managedPeerType.FullName,
- JniEnvironment.Runtime.TypeManager.GetTypeSignature (managedPeerType).SimpleReference,
- jniPeerTypeName));
+ }
- ManagedPeerType = managedPeerType;
+ static string GetReplacementType (string jniPeerTypeName)
+ {
+#if NET
+ var replacement = JniEnvironment.Runtime.TypeManager.GetReplacementType (jniPeerTypeName);
+ if (replacement != null)
+ return replacement;
+#endif // NET
+ return jniPeerTypeName;
}
JniPeerMembers (string jniPeerTypeName, Type managedPeerType, bool checkManagedPeerType, bool isInterface = false)
@@ -45,12 +42,16 @@ public JniPeerMembers (string jniPeerTypeName, Type managedPeerType)
if (!typeof (IJavaPeerable).IsAssignableFrom (managedPeerType))
throw new ArgumentException ("'managedPeerType' must implement the IJavaPeerable interface.", nameof (managedPeerType));
- Debug.Assert (
- JniEnvironment.Runtime.TypeManager.GetTypeSignature (managedPeerType).SimpleReference == jniPeerTypeName,
- string.Format ("ManagedPeerType <=> JniTypeName Mismatch! javaVM.GetJniTypeInfoForType(typeof({0})).JniTypeName=\"{1}\" != \"{2}\"",
- managedPeerType.FullName,
- JniEnvironment.Runtime.TypeManager.GetTypeSignature (managedPeerType).SimpleReference,
- jniPeerTypeName));
+#if DEBUG
+ var signatureFromType = JniEnvironment.Runtime.TypeManager.GetTypeSignature (managedPeerType);
+ if (signatureFromType.SimpleReference != jniPeerTypeName) {
+ Debug.WriteLine ("WARNING-Java.Interop: ManagedPeerType <=> JniTypeName Mismatch! javaVM.GetJniTypeInfoForType(typeof({0})).JniTypeName=\"{1}\" != \"{2}\"",
+ managedPeerType.FullName,
+ signatureFromType.SimpleReference,
+ jniPeerTypeName);
+ Debug.WriteLine (new System.Diagnostics.StackTrace (true));
+ }
+#endif // DEBUG
}
JniPeerTypeName = jniPeerTypeName;
diff --git a/src/Java.Interop/Java.Interop/JniRuntime.JniTypeManager.cs b/src/Java.Interop/Java.Interop/JniRuntime.JniTypeManager.cs
index 66f7ccb6d..8e6738fa6 100644
--- a/src/Java.Interop/Java.Interop/JniRuntime.JniTypeManager.cs
+++ b/src/Java.Interop/Java.Interop/JniRuntime.JniTypeManager.cs
@@ -3,15 +3,82 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
+using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
+using System.Runtime.Versioning;
using System.Threading;
namespace Java.Interop {
public partial class JniRuntime {
+#if NET
+ [SuppressMessage ("Design", "CA1034:Nested types should not be visible",
+ Justification = "Deliberate choice to 'hide' these types from code completion for `Java.Interop.`; see 045b8af7.")]
+ public struct ReplacementMethodInfo : IEquatable
+ {
+ public string? SourceJniType {get; set;}
+ public string? SourceJniMethodName {get; set;}
+ public string? SourceJniMethodSignature {get; set;}
+ public string? TargetJniType {get; set;}
+ public string? TargetJniMethodName {get; set;}
+ public string? TargetJniMethodSignature {get; set;}
+ public int? TargetJniMethodParameterCount {get; set;}
+ public bool TargetJniMethodInstanceToStatic {get; set;}
+
+ public override bool Equals (object? obj)
+ {
+ if (obj is ReplacementMethodInfo o) {
+ return Equals (o);
+ }
+ return false;
+ }
+
+ public bool Equals (ReplacementMethodInfo other)
+ {
+ return string.Equals (SourceJniType, other.SourceJniType) &&
+ string.Equals (SourceJniMethodName, other.SourceJniMethodName) &&
+ string.Equals (SourceJniMethodSignature, other.SourceJniMethodSignature) &&
+ string.Equals (TargetJniType, other.TargetJniType) &&
+ string.Equals (TargetJniMethodName, other.TargetJniMethodName) &&
+ string.Equals (TargetJniMethodSignature, other.TargetJniMethodSignature) &&
+ TargetJniMethodParameterCount == other.TargetJniMethodParameterCount &&
+ TargetJniMethodInstanceToStatic == other.TargetJniMethodInstanceToStatic;
+ }
+
+ public override int GetHashCode ()
+ {
+ return (SourceJniType?.GetHashCode () ?? 0) ^
+ (SourceJniMethodName?.GetHashCode () ?? 0) ^
+ (SourceJniMethodSignature?.GetHashCode () ?? 0) ^
+ (TargetJniType?.GetHashCode () ?? 0) ^
+ (TargetJniMethodName?.GetHashCode () ?? 0) ^
+ (TargetJniMethodSignature?.GetHashCode () ?? 0) ^
+ (TargetJniMethodParameterCount?.GetHashCode () ?? 0) ^
+ TargetJniMethodInstanceToStatic.GetHashCode ();
+ }
+
+ public override string ToString ()
+ {
+ return $"{nameof (ReplacementMethodInfo)} {{ " +
+ $"{nameof (SourceJniType)} = \"{SourceJniType}\"" +
+ $", {nameof (SourceJniMethodName)} = \"{SourceJniMethodName}\"" +
+ $", {nameof (SourceJniMethodSignature)} = \"{SourceJniMethodSignature}\"" +
+ $", {nameof (TargetJniType)} = \"{TargetJniType}\"" +
+ $", {nameof (TargetJniMethodName)} = \"{TargetJniMethodName}\"" +
+ $", {nameof (TargetJniMethodSignature)} = \"{TargetJniMethodSignature}\"" +
+ $", {nameof (TargetJniMethodParameterCount)} = {TargetJniMethodParameterCount?.ToString () ?? "null"}" +
+ $", {nameof (TargetJniMethodInstanceToStatic)} = {TargetJniMethodInstanceToStatic}" +
+ $"}}";
+ }
+
+ public static bool operator==(ReplacementMethodInfo a, ReplacementMethodInfo b) => a.Equals (b);
+ public static bool operator!=(ReplacementMethodInfo a, ReplacementMethodInfo b) => !a.Equals (b);
+ }
+#endif // NET
+
public class JniTypeManager : IDisposable, ISetRuntime {
JniRuntime? runtime;
@@ -46,6 +113,18 @@ void AssertValid ()
throw new ObjectDisposedException (nameof (JniTypeManager));
}
+ internal static void AssertSimpleReference (string jniSimpleReference, string argumentName = "jniSimpleReference")
+ {
+ if (jniSimpleReference == null)
+ throw new ArgumentNullException (argumentName);
+ if (jniSimpleReference != null && jniSimpleReference.IndexOf (".", StringComparison.Ordinal) >= 0)
+ throw new ArgumentException ("JNI type names do not contain '.', they use '/'. Are you sure you're using a JNI type name?", argumentName);
+ if (jniSimpleReference != null && jniSimpleReference.StartsWith ("[", StringComparison.Ordinal))
+ throw new ArgumentException ("Arrays cannot be present in simplified type references.", argumentName);
+ if (jniSimpleReference != null && jniSimpleReference.StartsWith ("L", StringComparison.Ordinal) && jniSimpleReference.EndsWith (";", StringComparison.Ordinal))
+ throw new ArgumentException ("JNI type references are not supported.", argumentName);
+ }
+
// NOTE: This method needs to be kept in sync with GetTypeSignatures()
// This version of the method has removed IEnumerable for performance reasons.
public JniTypeSignature GetTypeSignature (Type type)
@@ -71,6 +150,12 @@ public JniTypeSignature GetTypeSignature (Type type)
var name = type.GetCustomAttribute (inherit: false);
if (name != null) {
+#if NET
+ var altRef = GetReplacementType (name.SimpleReference);
+ if (altRef != null) {
+ return new JniTypeSignature (altRef, name.ArrayRank + rank, name.IsKeyword);
+ }
+#endif // NET
return new JniTypeSignature (name.SimpleReference, name.ArrayRank + rank, name.IsKeyword);
}
@@ -229,15 +314,7 @@ IEnumerable CreateGetTypesEnumerator (JniTypeSignature typeSignature)
protected virtual IEnumerable GetTypesForSimpleReference (string jniSimpleReference)
{
AssertValid ();
-
- if (jniSimpleReference == null)
- throw new ArgumentNullException (nameof (jniSimpleReference));
- if (jniSimpleReference != null && jniSimpleReference.IndexOf (".", StringComparison.Ordinal) >= 0)
- throw new ArgumentException ("JNI type names do not contain '.', they use '/'. Are you sure you're using a JNI type name?", nameof (jniSimpleReference));
- if (jniSimpleReference != null && jniSimpleReference.StartsWith ("[", StringComparison.Ordinal))
- throw new ArgumentException ("Only simplified type references are supported.", nameof (jniSimpleReference));
- if (jniSimpleReference != null && jniSimpleReference.StartsWith ("L", StringComparison.Ordinal) && jniSimpleReference.EndsWith (";", StringComparison.Ordinal))
- throw new ArgumentException ("Only simplified type references are supported.", nameof (jniSimpleReference));
+ AssertSimpleReference (jniSimpleReference);
// Not sure why CS8604 is reported on following line when we check against null ~9 lines above...
return CreateGetTypesForSimpleReferenceEnumerator (jniSimpleReference!);
@@ -252,6 +329,43 @@ IEnumerable CreateGetTypesForSimpleReferenceEnumerator (string jniSimpleRe
}
#if NET
+
+ public IReadOnlyList? GetStaticMethodFallbackTypes (string jniSimpleReference)
+ {
+ AssertValid ();
+ AssertSimpleReference (jniSimpleReference, nameof (jniSimpleReference));
+
+ return GetStaticMethodFallbackTypesCore (jniSimpleReference);
+ }
+
+ protected virtual IReadOnlyList? GetStaticMethodFallbackTypesCore (string jniSimple) => null;
+
+ public string? GetReplacementType (string jniSimpleReference)
+ {
+ AssertValid ();
+ AssertSimpleReference (jniSimpleReference, nameof (jniSimpleReference));
+
+ return GetReplacementTypeCore (jniSimpleReference);
+ }
+
+ protected virtual string? GetReplacementTypeCore (string jniSimpleReference) => null;
+
+ public ReplacementMethodInfo? GetReplacementMethodInfo (string jniSimpleReference, string jniMethodName, string jniMethodSignature)
+ {
+ AssertValid ();
+ AssertSimpleReference (jniSimpleReference, nameof (jniSimpleReference));
+ if (string.IsNullOrEmpty (jniMethodName)) {
+ throw new ArgumentNullException (nameof (jniMethodName));
+ }
+ if (string.IsNullOrEmpty (jniMethodSignature)) {
+ throw new ArgumentNullException (nameof (jniMethodSignature));
+ }
+
+ return GetReplacementMethodInfoCore (jniSimpleReference, jniMethodName, jniMethodSignature);
+ }
+
+ protected virtual ReplacementMethodInfo? GetReplacementMethodInfoCore (string jniSimpleReference, string jniMethodName, string jniMethodSignature) => null;
+
public virtual void RegisterNativeMembers (JniType nativeClass, Type type, ReadOnlySpan methods)
{
TryRegisterNativeMembers (nativeClass, type, methods);
diff --git a/src/Java.Interop/Java.Interop/JniRuntime.JniValueManager.cs b/src/Java.Interop/Java.Interop/JniRuntime.JniValueManager.cs
index a233ac81a..8f22e3269 100644
--- a/src/Java.Interop/Java.Interop/JniRuntime.JniValueManager.cs
+++ b/src/Java.Interop/Java.Interop/JniRuntime.JniValueManager.cs
@@ -402,9 +402,9 @@ public T CreateValue (ref JniObjectReference reference, JniObjectReferenceOpt
targetType = targetType ?? typeof (T);
if (typeof (IJavaPeerable).IsAssignableFrom (targetType)) {
-#pragma warning disable CS8601 // Possible null reference assignment.
+#pragma warning disable CS8600,CS8601 // Possible null reference assignment.
return (T) JavaPeerableValueMarshaler.Instance.CreateGenericValue (ref reference, options, targetType);
-#pragma warning restore CS8601 // Possible null reference assignment.
+#pragma warning restore CS8600,CS8601 // Possible null reference assignment.
}
var marshaler = GetValueMarshaler ();
@@ -481,9 +481,9 @@ public T GetValue (ref JniObjectReference reference, JniObjectReferenceOption
}
if (typeof (IJavaPeerable).IsAssignableFrom (targetType)) {
-#pragma warning disable CS8601 // Possible null reference assignment.
+#pragma warning disable CS8600,CS8601 // Possible null reference assignment.
return (T) JavaPeerableValueMarshaler.Instance.CreateGenericValue (ref reference, options, targetType);
-#pragma warning restore CS8601 // Possible null reference assignment.
+#pragma warning restore CS8600,CS8601 // Possible null reference assignment.
}
var marshaler = GetValueMarshaler ();
diff --git a/src/Java.Interop/Java.Interop/JniType.cs b/src/Java.Interop/Java.Interop/JniType.cs
index 2639cdaee..5f0491620 100644
--- a/src/Java.Interop/Java.Interop/JniType.cs
+++ b/src/Java.Interop/Java.Interop/JniType.cs
@@ -25,6 +25,18 @@ public sealed class JniType : IDisposable {
}
}
+#if NET
+ public static bool TryParse (string name, [NotNullWhen (true)] out JniType? type)
+ {
+ if (!JniEnvironment.Types.TryFindClass (name, out var peerReference)) {
+ type = null;
+ return false;
+ }
+ type = new JniType (ref peerReference, JniObjectReferenceOptions.CopyAndDispose);
+ return true;
+ }
+#endif // NET
+
bool registered;
JniObjectReference peerReference;
@@ -236,6 +248,28 @@ public JniMethodInfo GetInstanceMethod (string name, string signature)
return JniEnvironment.InstanceMethods.GetMethodID (PeerReference, name, signature);
}
+#if NET
+ internal bool TryGetInstanceMethod (string name, string signature, [NotNullWhen(true)] out JniMethodInfo? method)
+ {
+ AssertValid ();
+
+ IntPtr thrown;
+ method = null;
+ var id = NativeMethods.java_interop_jnienv_get_method_id (JniEnvironment.EnvironmentPointer, out thrown, PeerReference.Handle, name, signature);
+ if (thrown != IntPtr.Zero) {
+ JniEnvironment.Exceptions.ExceptionClear ();
+ NativeMethods.java_interop_jnienv_delete_local_ref (JniEnvironment.EnvironmentPointer, thrown);
+ return false;
+ }
+ if (id == IntPtr.Zero) {
+ // …huh? Should only happen if `thrown != IntPtr.Zero`, handled above.
+ return false;
+ }
+ method = new JniMethodInfo (name, signature, id, isStatic: false);
+ return true;
+ }
+#endif // NET
+
public JniMethodInfo GetCachedInstanceMethod ([NotNull] ref JniMethodInfo? cachedMethod, string name, string signature)
{
AssertValid ();
@@ -256,6 +290,28 @@ public JniMethodInfo GetStaticMethod (string name, string signature)
return JniEnvironment.StaticMethods.GetStaticMethodID (PeerReference, name, signature);
}
+#if NET
+ internal bool TryGetStaticMethod (string name, string signature, [NotNullWhen(true)] out JniMethodInfo? method)
+ {
+ AssertValid ();
+
+ IntPtr thrown;
+ method = null;
+ var id = NativeMethods.java_interop_jnienv_get_static_method_id (JniEnvironment.EnvironmentPointer, out thrown, PeerReference.Handle, name, signature);
+ if (thrown != IntPtr.Zero) {
+ JniEnvironment.Exceptions.ExceptionClear ();
+ NativeMethods.java_interop_jnienv_delete_local_ref (JniEnvironment.EnvironmentPointer, thrown);
+ return false;
+ }
+ if (id == IntPtr.Zero) {
+ // …huh? Should only happen if `thrown != IntPtr.Zero`, handled above.
+ return false;
+ }
+ method = new JniMethodInfo (name, signature, id, isStatic: true);
+ return true;
+ }
+#endif // NET
+
public JniMethodInfo GetCachedStaticMethod ([NotNull] ref JniMethodInfo? cachedMethod, string name, string signature)
{
AssertValid ();
diff --git a/src/Java.Interop/Java.Interop/JniTypeSignatureAttribute.cs b/src/Java.Interop/Java.Interop/JniTypeSignatureAttribute.cs
index 6ae3fac1f..4b5b6d8d9 100644
--- a/src/Java.Interop/Java.Interop/JniTypeSignatureAttribute.cs
+++ b/src/Java.Interop/Java.Interop/JniTypeSignatureAttribute.cs
@@ -11,14 +11,7 @@ public sealed class JniTypeSignatureAttribute : Attribute {
public JniTypeSignatureAttribute (string simpleReference)
{
- if (simpleReference == null)
- throw new ArgumentNullException (nameof (simpleReference));
- if (simpleReference.IndexOf (".", StringComparison.Ordinal) >= 0)
- throw new ArgumentException ("JNI type names do not contain '.', they use '/'. Are you sure you're using a JNI type name?", nameof (simpleReference));
- if (simpleReference.StartsWith ("[", StringComparison.Ordinal))
- throw new ArgumentException ("Arrays cannot be present in simple type references.", nameof (simpleReference));
- if (simpleReference.StartsWith ("L", StringComparison.Ordinal) && simpleReference.EndsWith (";", StringComparison.Ordinal))
- throw new ArgumentException ("JNI type references are not supported.", nameof (simpleReference));
+ JniRuntime.JniTypeManager.AssertSimpleReference (simpleReference, nameof (simpleReference));
SimpleReference = simpleReference;
}
diff --git a/tests/Java.Interop-Tests/Java.Interop-Tests.csproj b/tests/Java.Interop-Tests/Java.Interop-Tests.csproj
index 9b2f4d6c9..eac512935 100644
--- a/tests/Java.Interop-Tests/Java.Interop-Tests.csproj
+++ b/tests/Java.Interop-Tests/Java.Interop-Tests.csproj
@@ -4,6 +4,7 @@
net472;net6.0
false
true
+ 9.0
@@ -46,6 +47,10 @@
+
+
+
+
diff --git a/tests/Java.Interop-Tests/Java.Interop/JavaVMFixture.cs b/tests/Java.Interop-Tests/Java.Interop/JavaVMFixture.cs
index e1a816c6b..855f52990 100644
--- a/tests/Java.Interop-Tests/Java.Interop/JavaVMFixture.cs
+++ b/tests/Java.Interop-Tests/Java.Interop/JavaVMFixture.cs
@@ -1,3 +1,4 @@
+#nullable enable
using System;
using System.Collections.Generic;
using System.IO;
@@ -10,20 +11,149 @@ namespace Java.InteropTests {
partial class JavaVMFixture {
+ internal static TestJVM? VM;
+ internal static JavaVMFixtureTypeManager? TypeManager;
+
static partial void CreateJavaVM ()
{
- var c = new TestJVM (
- jars: new[]{ "interop-test.jar" },
- typeMappings: new Dictionary () {
+ var o = new TestJVMOptions {
+ JarFilePaths = {
+ "interop-test.jar",
+ },
+ TypeManager = new JavaVMFixtureTypeManager (),
+ };
+ VM = new TestJVM (o);
+ TypeManager = (JavaVMFixtureTypeManager) VM.TypeManager;
+ JniRuntime.SetCurrent (VM);
+ }
+ }
+
+ class JavaVMFixtureTypeManager : JniRuntime.JniTypeManager {
+
+ Dictionary TypeMappings = new() {
#if !NO_MARSHAL_MEMBER_BUILDER_SUPPORT
- { TestType.JniTypeName, typeof (TestType) },
+ [TestType.JniTypeName] = typeof (TestType),
#endif // !NO_MARSHAL_MEMBER_BUILDER_SUPPORT
- { GenericHolder.JniTypeName, typeof (GenericHolder<>) },
+ [GenericHolder.JniTypeName] = typeof (GenericHolder<>),
+ [RenameClassBase.JniTypeName] = typeof (RenameClassBase),
+ [RenameClassDerived.JniTypeName] = typeof (RenameClassDerived),
+ };
+
+ public JavaVMFixtureTypeManager ()
+ {
+ }
+
+ protected override IEnumerable GetTypesForSimpleReference (string jniSimpleReference)
+ {
+ foreach (var t in base.GetTypesForSimpleReference (jniSimpleReference))
+ yield return t;
+ Type target;
+#pragma warning disable CS8600 // huh?
+ if (TypeMappings.TryGetValue (jniSimpleReference, out target))
+ yield return target;
+#pragma warning restore CS8600
+ }
+
+ protected override IEnumerable GetSimpleReferences (Type type)
+ {
+ return base.GetSimpleReferences (type)
+ .Concat (CreateSimpleReferencesEnumerator (type));
+ }
+
+ IEnumerable CreateSimpleReferencesEnumerator (Type type)
+ {
+ foreach (var e in TypeMappings) {
+ if (e.Value == type) {
+#if NET
+ if (ReplacmentTypes.TryGetValue (e.Key, out var alt)) {
+ yield return alt;
+ continue;
}
- );
- JniRuntime.SetCurrent (c);
+#endif // NET
+ yield return e.Key;
+ }
+ }
}
+#if NET
+ public string? RequestedFallbackTypesForSimpleReference;
+ protected override IReadOnlyList? GetStaticMethodFallbackTypesCore (string jniSimpleReference)
+ {
+ RequestedFallbackTypesForSimpleReference = jniSimpleReference;
+ Debug.WriteLine ($"# GetStaticMethodFallbackTypes (jniSimpleReference={jniSimpleReference})");
+
+ var slash = jniSimpleReference.LastIndexOf ('/');
+ var desugarType = slash <= 0
+ ? "Desugar" + jniSimpleReference
+ : jniSimpleReference.Substring (0, slash+1) + "Desugar" + jniSimpleReference.Substring (slash+1);
+
+ // These types likely won't ever exist on Desktop, but providing
+ // "potentially non-existent" types ensures that we don't throw
+ // from places we don't want to internally throw.
+ return new[]{
+ desugarType,
+ $"{jniSimpleReference}$-CC"
+ };
+ }
+
+ Dictionary ReplacmentTypes = new() {
+ ["com/xamarin/interop/RenameClassBase1"] = "com/xamarin/interop/RenameClassBase2",
+ };
+
+ protected override string? GetReplacementTypeCore (string jniSimpleReference) =>
+ ReplacmentTypes.TryGetValue (jniSimpleReference, out var v)
+ ? v
+ : null;
+
+ Dictionary<(string SourceType, string SourceName, string? SourceSignature), (string? TargetType, string? TargetName, string? TargetSignature, int? ParamCount, bool TurnStatic)> ReplacementMethods = new() {
+ [("java/lang/Object", "remappedToToString", "()Ljava/lang/String;")] = (null, "toString", null, null, false),
+ [("java/lang/Object", "remappedToStaticHashCode", null)] = ("com/xamarin/interop/ObjectHelper", "getHashCodeHelper", null, null, true),
+ [("java/lang/Runtime", "remappedToGetRuntime", null)] = (null, "getRuntime", null, null, false),
+
+ // NOTE: key must use *post-renamed* value, not pre-renamed value
+ // NOTE: SourceSignature lacking return type; "closer in spirit" to what `remapping-config.json` allows
+ [("com/xamarin/interop/RenameClassBase2", "hashCode", "()")] = ("com/xamarin/interop/RenameClassBase2", "myNewHashCode", null, null, false),
+ };
+
+ protected override JniRuntime.ReplacementMethodInfo? GetReplacementMethodInfoCore (string jniSourceType, string jniMethodName, string jniMethodSignature)
+ {
+ // Console.Error.WriteLine ($"# jonp: looking for replacement method for (\"{jniSourceType}\", \"{jniMethodName}\", \"{jniMethodSignature}\")");
+ if (!ReplacementMethods.TryGetValue ((jniSourceType, jniMethodName, jniMethodSignature), out var r) &&
+ !ReplacementMethods.TryGetValue ((jniSourceType, jniMethodName, GetAlternateMethodSignature ()), out r) &&
+ !ReplacementMethods.TryGetValue ((jniSourceType, jniMethodName, null), out r)) {
+ return null;
+ }
+ var targetSig = r.TargetSignature;
+ var paramCount = r.ParamCount;
+ if (targetSig == null && r.TurnStatic) {
+ targetSig = $"(L{jniSourceType};" + jniMethodSignature.Substring ("(".Length);
+ paramCount = paramCount ?? JniMemberSignature.GetParameterCountFromMethodSignature (jniMethodSignature);
+ paramCount++;
+ }
+ // Console.Error.WriteLine ($"# jonp: found replacement: ({GetValue (r.TargetType)}, {GetValue (r.TargetName)}, {GetValue (r.TargetSignature)}, {r.ParamCount?.ToString () ?? "null"}, {r.IsStatic})");
+ return new JniRuntime.ReplacementMethodInfo {
+ SourceJniType = jniSourceType,
+ SourceJniMethodName = jniMethodName,
+ SourceJniMethodSignature = jniMethodSignature,
+ TargetJniType = r.TargetType ?? jniSourceType,
+ TargetJniMethodName = r.TargetName ?? jniMethodName,
+ TargetJniMethodSignature = targetSig ?? jniMethodSignature,
+ TargetJniMethodParameterCount = paramCount,
+ TargetJniMethodInstanceToStatic = r.TurnStatic,
+ };
+
+ string GetAlternateMethodSignature ()
+ {
+ int i = jniMethodSignature.IndexOf (')');
+ return jniMethodSignature.Substring (0, i+1);
+ }
+
+ // string GetValue (string? value)
+ // {
+ // return value == null ? "null" : $"\"{value}\"";
+ // }
+ }
+#endif // NET
}
}
diff --git a/tests/Java.Interop-Tests/Java.Interop/JniPeerMembersTests.cs b/tests/Java.Interop-Tests/Java.Interop/JniPeerMembersTests.cs
index 374a52a5b..788f5e61e 100644
--- a/tests/Java.Interop-Tests/Java.Interop/JniPeerMembersTests.cs
+++ b/tests/Java.Interop-Tests/Java.Interop/JniPeerMembersTests.cs
@@ -36,6 +36,79 @@ static Dictionary GetInstanceMethods (JniPeerMembers.JniI
var f = typeof (JniPeerMembers.JniInstanceMethods).GetField ("InstanceMethods", BindingFlags.NonPublic | BindingFlags.Instance);
return (Dictionary) f.GetValue (methods);
}
+
+#if NET
+ [Test]
+ public void MethodLookupForNonexistentStaticMethodWillTryFallbacks ()
+ {
+ try {
+ JavaLangRemappingTestRuntime.doesNotExist ();
+ Assert.Fail ("java.lang.Runtime.doesNotExist() exists?! Not expected to exist.");
+ }
+ catch (Exception e) {
+ Console.WriteLine ($"# jonp: MethodLookupForNonexistentStaticMethodWillTryFallbacks: e={e}");
+ // On Desktop, expect `e` to be:
+ // ```
+ // Java.Interop.JavaException: doesNotExist
+ // at Java.Interop.JniEnvironment.StaticMethods.GetMethodID(JniObjectReference type, String name, String signature)
+ // …
+ // at Java.InteropTests.JavaLangRuntime.doesNotExist()
+ // at Java.InteropTests.JniStaticMethodIDTest.MethodLookupForNonexistentMethodWillTryFallbacks()
+ // --- End of managed Java.Interop.JavaException stack trace ---
+ // java.lang.NoSuchMethodError: doesNotExist
+ // ```
+ // On Android, expect `e` to be:
+ // ```
+ // Java.Lang.NoSuchMethodError: no static method "Ljava/lang/Runtime;.doesNotExist()V"
+ // at Java.Interop.JniEnvironment.StaticMethods.GetStaticMethodID(JniObjectReference type, String name, String signature)
+ // at Java.Interop.JniType.GetStaticMethod(String name, String signature)
+ // at Java.Interop.JniPeerMembers.JniStaticMethods.GetMethodInfo(String method, String signature)
+ // at Java.Interop.JniPeerMembers.JniStaticMethods.GetMethodInfo(String encodedMember)
+ // at Java.Interop.JniPeerMembers.JniStaticMethods.InvokeVoidMethod(String encodedMember, JniArgumentValue* parameters)
+ // at Java.InteropTests.JavaLangRemappingTestRuntime.doesNotExist()
+ // at Java.InteropTests.JniPeerMembersTests.MethodLookupForNonexistentStaticMethodWillTryFallbacks()
+ // --- End of managed Java.Lang.NoSuchMethodError stack trace ---
+ // ```
+ Assert.IsTrue (e.Message.Contains ("doesNotExist", StringComparison.Ordinal));
+#if !ANDROID // Android doesn't allow providing a custom TypeManager
+ Assert.AreEqual ("java/lang/Runtime",
+ JavaVMFixture.TypeManager.RequestedFallbackTypesForSimpleReference);
+#endif // !ANDROID
+ }
+ }
+
+ [Test]
+ public void ReplacementTypeUsedForMethodLookup ()
+ {
+ using var o = new RenameClassDerived ();
+ int r = o.hashCode();
+ Assert.AreEqual (33, r);
+ }
+
+ [Test]
+ public void ReplaceInstanceMethodName ()
+ {
+ using var o = new JavaLangRemappingTestObject ();
+ // Shouldn't throw; should instead invoke Object.toString()
+ var r = o.remappedToToString ();
+ JniObjectReference.Dispose (ref r);
+ }
+
+ [Test]
+ public void ReplaceStaticMethodName ()
+ {
+ var r = JavaLangRemappingTestRuntime.remappedToGetRuntime ();
+ JniObjectReference.Dispose (ref r);
+ }
+
+ [Test]
+ public void ReplaceInstanceMethodWithStaticMethod ()
+ {
+ using var o = new JavaLangRemappingTestObject ();
+ // Shouldn't throw; should instead invoke ObjectHelper.getHashCodeHelper(Object)
+ o.remappedToStaticHashCode ();
+ }
+#endif // NET
}
[JniTypeSignature (JniTypeName)]
@@ -57,5 +130,82 @@ public unsafe MyString (string value)
_members.InstanceMethods.FinishGenericCreateInstance (id, this, value);
}
}
-}
+
+ [JniTypeSignature (JniTypeName)]
+ class JavaLangRemappingTestObject : JavaObject {
+ internal const string JniTypeName = "java/lang/Object";
+ static readonly JniPeerMembers _members = new JniPeerMembers (JniTypeName, typeof (JavaLangRemappingTestObject));
+
+ public JavaLangRemappingTestObject ()
+ {
+ }
+
+ public unsafe void doesNotExist ()
+ {
+ const string id = "doesNotExist.()V";
+ _members.InstanceMethods.InvokeNonvirtualVoidMethod (id, this, null);
+ }
+
+ public unsafe JniObjectReference remappedToToString ()
+ {
+ const string id = "remappedToToString.()Ljava/lang/String;";
+ return _members.InstanceMethods.InvokeNonvirtualObjectMethod (id, this, null);
+ }
+
+ public unsafe int remappedToStaticHashCode ()
+ {
+ const string id = "remappedToStaticHashCode.()I";
+ return _members.InstanceMethods.InvokeVirtualInt32Method (id, this, null);
+ }
+ }
+
+ [JniTypeSignature (JavaLangRemappingTestRuntime.JniTypeName)]
+ internal class JavaLangRemappingTestRuntime : JavaObject {
+ internal const string JniTypeName = "java/lang/Runtime";
+ static readonly JniPeerMembers _members = new JniPeerMembers (JniTypeName, typeof (JavaLangRemappingTestRuntime));
+
+ public static unsafe JniObjectReference remappedToGetRuntime()
+ {
+ const string id = "remappedToGetRuntime.()Ljava/lang/Runtime;";
+ return _members.StaticMethods.InvokeObjectMethod (id, null);
+ }
+
+ public static unsafe void doesNotExist ()
+ {
+ const string id = "doesNotExist.()V";
+ _members.StaticMethods.InvokeVoidMethod (id, null);
+ }
+ }
+
+ [JniTypeSignature (JniTypeName)]
+ class RenameClassBase : JavaObject {
+ internal const string JniTypeName = "com/xamarin/interop/RenameClassBase1";
+ static readonly JniPeerMembers _members = new JniPeerMembers (JniTypeName, typeof (RenameClassBase));
+
+ public override JniPeerMembers JniPeerMembers => _members;
+
+ public RenameClassBase ()
+ {
+ }
+
+ public virtual unsafe int hashCode ()
+ {
+ const string id = "hashCode.()I";
+ return _members.InstanceMethods.InvokeVirtualInt32Method (id, this, null);
+ }
+ }
+
+ [JniTypeSignature (JniTypeName)]
+ class RenameClassDerived : RenameClassBase {
+ internal new const string JniTypeName = "com/xamarin/interop/RenameClassDerived";
+ public RenameClassDerived ()
+ {
+ }
+
+ public override unsafe int hashCode ()
+ {
+ return base.hashCode ();
+ }
+ }
+}
diff --git a/tests/Java.Interop-Tests/java/com/xamarin/interop/ObjectHelper.java b/tests/Java.Interop-Tests/java/com/xamarin/interop/ObjectHelper.java
new file mode 100644
index 000000000..768161461
--- /dev/null
+++ b/tests/Java.Interop-Tests/java/com/xamarin/interop/ObjectHelper.java
@@ -0,0 +1,11 @@
+package com.xamarin.interop;
+
+public class ObjectHelper {
+ private ObjectHelper()
+ {
+ }
+
+ public static int getHashCodeHelper (Object o) {
+ return o.hashCode();
+ }
+}
diff --git a/tests/Java.Interop-Tests/java/com/xamarin/interop/RenameClassBase1.java b/tests/Java.Interop-Tests/java/com/xamarin/interop/RenameClassBase1.java
new file mode 100644
index 000000000..e4e7c906c
--- /dev/null
+++ b/tests/Java.Interop-Tests/java/com/xamarin/interop/RenameClassBase1.java
@@ -0,0 +1,39 @@
+package com.xamarin.interop;
+
+import java.util.ArrayList;
+
+import com.xamarin.java_interop.GCUserPeerable;
+
+public class RenameClassBase1
+ implements GCUserPeerable
+{
+ static final String assemblyQualifiedName = "Java.InteropTests.RenameClassBase, Java.Interop-Tests";
+
+ ArrayList