From d1a9951ea437d50f649913ae92ae32002ad429bd Mon Sep 17 00:00:00 2001 From: Jonathan Pryor Date: Fri, 29 Mar 2024 13:49:58 -0400 Subject: [PATCH 1/6] [Java.Interop] Add JniMemberInfoLookup MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Context: c6c487b62dab4ffec45e61b09dd43afc89898caf Context: 312fbf439ed874bb5f4f25ee6d2c9a2b3c2f5a8b Context: 2197579478152fbc815eb15195977f808cd6bde4 Context: https://github.com/xamarin/xamarin-android/issues/7276 There is a desire to remove the "marshal-ilgen" component from .NET Android, which is responsible for all non-blittable type marshaling within P/Invoke (and related) invocations. The largest source of such non-blittable parameter marshaling was with string marshaling: `JNIEnv::GetFieldID()` was "wrapped" by `java_interop_jnienv_get_field_id`: JI_API jfieldID java_interop_jnienv_get_field_id (JNIEnv *env, jthrowable *_thrown, jclass type, const char* name, const char* signature); which was P/Invoked within `JniEnvironment.g.cs`: partial class NativeMethods { internal static extern unsafe IntPtr java_interop_jnienv_get_field_id (IntPtr jnienv, out IntPtr thrown, jobject type, string name, string signature); } and `string` parameter marshaling is *not* blittable. Turns out™ that this particular usage of non-blittable parameter marshaling was fixed and rendered moot by: * 312fbf43: C#9 function pointer backend for `JNIEnv` invocations * c6c487b6: "Standalone" build config to use C#9 function pointers * 21975794: Standalone build config is now the default That said, this code path felt slightly less than ideal: the "top-level abstraction" for member lookups is an "encoded member", a string containing the name of the member, a `.`, and the JNI signature of the member, e.g.: _members.InstanceFields.GetBooleanValue("propogateFinallyBlockExecuted.Z", this) The "encoded member" would need to be split on `.`, and with c6c487b6 the name and signature would be separately passed to `Marshal.StringToCoTaskMemUTF8()`, which performs a memory allocation and converts the UTF-16 string to UTF-8. Meanwhile, [C# 11 introduced UTF-8 string literals][0], which allows the compiler to deal with UTF-8 conversion and memory allocation. Enter `JniMemberInfoLookup``: public ref struct JniMemberInfoLookup { public string EncodedMember {get;} public ReadOnlySpan MemberName {get;} public ReadOnlySpan MemberSignature {get;} public JniMemberInfoLookup (string encodedMember, ReadOnlySpan memberName, ReadOnlySpan memberSignature); } `JniMemberInfoLookup` removes the need to call `Marshal.StringToCoTaskMemUTF8()` entirely, at the cost of a more complicated member invocation: // Old and busted: bool value = _members.InstanceFields.GetBooleanValue("propogateFinallyBlockExecuted.Z", this); // Eventual new hawtness: var lookup = new JniMemberInfoLookup ( "propogateFinallyBlockExecuted.Z", "propogateFinallyBlockExecuted"u8, "Z"u8); bool value = _members.InstanceFields.GetBooleanValue(lookup, this); Is It Worth It™? *Maybe*; see the new `JniFieldLookupTiming.FieldLookupTiming()` test, which allocates a new `JniPeerMembers` instance and invoke `members.InstanceFields.GetFieldInfo(string)` and `members.InstanceFields.GetFieldInfo(JniMemberInfoLookup)`. (A new `JniPeerMembers` instance is required because `GetFieldInfo()` caches the field lookup.) Using `JniMemberInfoLookup` is about 4% faster. # FieldLookupTiming Timing: looking up JavaTiming.instanceIntField 10000 times # .InstanceMethods.GetFieldInfo(string): 00:00:02.2780667 # .InstanceMethods.GetFieldInfo(JniMemberInfoLookup): 00:00:02.2016146 I'm not sure if this is *actually* worth it, especially as this will imply an increase in code size. TODO: * Update `JniPeerMembers.*.cs` to use `JniMemberInfoLookup`, so that e.g. the above `_members.InstanceFields.GetBooleanValue()` overload exists. * `generator` changes to use `JniMemberInfoLookup` [0]: https://learn.microsoft.com/dotnet/csharp/whats-new/csharp-11#utf-8-string-literals --- src/Java.Interop/GlobalSuppressions.cs | 4 + src/Java.Interop/Java.Interop.csproj | 2 +- .../JniEnvironment.InstanceFields.cs | 37 ++++++++ .../JniEnvironment.InstanceMethods.cs | 37 ++++++++ .../JniEnvironment.StaticFields.cs | 38 ++++++++ .../JniEnvironment.StaticMethods.cs | 82 +++++++++++++++++ .../Java.Interop/JniMemberInfoLookup.cs | 16 ++++ .../JniPeerMembers.JniInstanceFields.cs | 11 +++ .../JniPeerMembers.JniInstanceMethods.cs | 42 +++++++++ .../JniPeerMembers.JniStaticFields.cs | 11 +++ .../JniPeerMembers.JniStaticMethods.cs | 65 ++++++++++++++ .../Java.Interop/JniRuntime.JniTypeManager.cs | 16 ++++ src/Java.Interop/Java.Interop/JniType.cs | 88 +++++++++++++++++++ .../Java.Interop/TimingTests.cs | 31 +++++++ .../interop/performance/JavaTiming.java | 2 + .../Java.Interop/JniTypeTest.cs | 16 ++-- 16 files changed, 489 insertions(+), 9 deletions(-) create mode 100644 src/Java.Interop/Java.Interop/JniEnvironment.InstanceFields.cs create mode 100644 src/Java.Interop/Java.Interop/JniEnvironment.InstanceMethods.cs create mode 100644 src/Java.Interop/Java.Interop/JniEnvironment.StaticFields.cs create mode 100644 src/Java.Interop/Java.Interop/JniEnvironment.StaticMethods.cs create mode 100644 src/Java.Interop/Java.Interop/JniMemberInfoLookup.cs diff --git a/src/Java.Interop/GlobalSuppressions.cs b/src/Java.Interop/GlobalSuppressions.cs index e5cc3b533..e1efbc7da 100644 --- a/src/Java.Interop/GlobalSuppressions.cs +++ b/src/Java.Interop/GlobalSuppressions.cs @@ -19,6 +19,10 @@ // See: 045b8af7, 6a42bb89, f60906cf, e10f7cb0, etc. [assembly: SuppressMessage ("Design", "CA1034:Nested types should not be visible", Justification = "Deliberate choice to 'hide' these types from code completion for `Java.Interop.`.", Scope = "type", Target = "~T:Java.Interop.JniEnvironment.Exceptions")] +[assembly: SuppressMessage ("Design", "CA1034:Nested types should not be visible", Justification = "Deliberate choice to 'hide' these types from code completion for `Java.Interop.`.", Scope = "type", Target = "~T:Java.Interop.JniEnvironment.InstanceFields")] +[assembly: SuppressMessage ("Design", "CA1034:Nested types should not be visible", Justification = "Deliberate choice to 'hide' these types from code completion for `Java.Interop.`.", Scope = "type", Target = "~T:Java.Interop.JniEnvironment.InstanceMethods")] +[assembly: SuppressMessage ("Design", "CA1034:Nested types should not be visible", Justification = "Deliberate choice to 'hide' these types from code completion for `Java.Interop.`.", Scope = "type", Target = "~T:Java.Interop.JniEnvironment.StaticFields")] +[assembly: SuppressMessage ("Design", "CA1034:Nested types should not be visible", Justification = "Deliberate choice to 'hide' these types from code completion for `Java.Interop.`.", Scope = "type", Target = "~T:Java.Interop.JniEnvironment.StaticMethods")] [assembly: SuppressMessage ("Design", "CA1034:Nested types should not be visible", Justification = "Deliberate choice to 'hide' these types from code completion for `Java.Interop.`.", Scope = "type", Target = "~T:Java.Interop.JniPeerMembers.JniStaticMethods")] [assembly: SuppressMessage ("Design", "CA1034:Nested types should not be visible", Justification = "Deliberate choice to 'hide' these types from code completion for `Java.Interop.`.", Scope = "type", Target = "~T:Java.Interop.JniRuntime.JniMarshalMemberBuilder")] [assembly: SuppressMessage ("Design", "CA1034:Nested types should not be visible", Justification = "Deliberate choice to 'hide' these types from code completion for `Java.Interop.`.", Scope = "type", Target = "~T:Java.Interop.JniPeerMembers.JniStaticFields")] diff --git a/src/Java.Interop/Java.Interop.csproj b/src/Java.Interop/Java.Interop.csproj index 1c4f0c681..0b90eb370 100644 --- a/src/Java.Interop/Java.Interop.csproj +++ b/src/Java.Interop/Java.Interop.csproj @@ -29,7 +29,7 @@ $(ToolOutputFullPath) $(ToolOutputFullPath)Java.Interop.xml $(BuildToolOutputFullPath) - 9.0 + 12.0 8.0 $(JICoreLibVersion) true diff --git a/src/Java.Interop/Java.Interop/JniEnvironment.InstanceFields.cs b/src/Java.Interop/Java.Interop/JniEnvironment.InstanceFields.cs new file mode 100644 index 000000000..2245069c3 --- /dev/null +++ b/src/Java.Interop/Java.Interop/JniEnvironment.InstanceFields.cs @@ -0,0 +1,37 @@ +using System; +using System.Runtime.ExceptionServices; +using System.Runtime.InteropServices; + +namespace Java.Interop; + +partial class JniEnvironment { + partial class InstanceFields { + public static unsafe JniFieldInfo GetFieldID (JniObjectReference type, ReadOnlySpan name, ReadOnlySpan signature) + { + if (!type.IsValid) + throw new ArgumentException ("Handle must be valid.", "type"); + + IntPtr env = JniEnvironment.EnvironmentPointer; + IntPtr field; + IntPtr thrown; + fixed (void* name_ptr = &MemoryMarshal.GetReference (name)) + fixed (void* signature_ptr = &MemoryMarshal.GetReference (signature)) { + field = JniNativeMethods.GetFieldID (env, type.Handle, (IntPtr) name_ptr, (IntPtr) signature_ptr); + thrown = JniNativeMethods.ExceptionOccurred (env); + } + + Exception? __e = JniEnvironment.GetExceptionForLastThrowable (thrown); + if (__e != null) + ExceptionDispatchInfo.Capture (__e).Throw (); + + if (field == IntPtr.Zero) + throw new InvalidOperationException ("Should not be reached; `GetFieldID` should have thrown!"); + +#if DEBUG + return new JniFieldInfo (name.ToString (), signature.ToString (), field, isStatic: false); +#else // DEBUG + return new JniFieldInfo (null!, null!, field, isStatic: false); +#endif // DEBUG + } + } +} diff --git a/src/Java.Interop/Java.Interop/JniEnvironment.InstanceMethods.cs b/src/Java.Interop/Java.Interop/JniEnvironment.InstanceMethods.cs new file mode 100644 index 000000000..e84ce5837 --- /dev/null +++ b/src/Java.Interop/Java.Interop/JniEnvironment.InstanceMethods.cs @@ -0,0 +1,37 @@ +using System; +using System.Runtime.ExceptionServices; +using System.Runtime.InteropServices; + +namespace Java.Interop; + +partial class JniEnvironment { + partial class InstanceMethods { + public static unsafe JniMethodInfo GetMethodID (JniObjectReference type, ReadOnlySpan name, ReadOnlySpan signature) + { + if (!type.IsValid) + throw new ArgumentException ("Handle must be valid.", "type"); + + IntPtr env = JniEnvironment.EnvironmentPointer; + IntPtr method; + IntPtr thrown; + fixed (void* name_ptr = &MemoryMarshal.GetReference (name)) + fixed (void* signature_ptr = &MemoryMarshal.GetReference (signature)) { + method = JniNativeMethods.GetMethodID (env, type.Handle, (IntPtr) name_ptr, (IntPtr) signature_ptr); + thrown = JniNativeMethods.ExceptionOccurred (env); + } + + Exception? __e = JniEnvironment.GetExceptionForLastThrowable (thrown); + if (__e != null) + ExceptionDispatchInfo.Capture (__e).Throw (); + + if (method == IntPtr.Zero) + throw new InvalidOperationException ("Should not be reached; `GetMethodID` should have thrown!"); + +#if DEBUG + return new JniMethodInfo (name.ToString (), signature.ToString (), method, isStatic: false); +#else // DEBUG + return new JniMethodInfo (null!, null!, method, isStatic: false); +#endif // DEBUG + } + } +} diff --git a/src/Java.Interop/Java.Interop/JniEnvironment.StaticFields.cs b/src/Java.Interop/Java.Interop/JniEnvironment.StaticFields.cs new file mode 100644 index 000000000..0433dec28 --- /dev/null +++ b/src/Java.Interop/Java.Interop/JniEnvironment.StaticFields.cs @@ -0,0 +1,38 @@ +using System; +using System.Runtime.ExceptionServices; +using System.Runtime.InteropServices; + +namespace Java.Interop; + +partial class JniEnvironment { + partial class StaticFields { + + public static unsafe JniFieldInfo GetStaticFieldID (JniObjectReference type, ReadOnlySpan name, ReadOnlySpan signature) + { + if (!type.IsValid) + throw new ArgumentException ("Handle must be valid.", "type"); + + IntPtr env = JniEnvironment.EnvironmentPointer; + IntPtr field; + IntPtr thrown; + fixed (void* name_ptr = &MemoryMarshal.GetReference (name)) + fixed (void* signature_ptr = &MemoryMarshal.GetReference (signature)) { + field = JniNativeMethods.GetStaticFieldID (env, type.Handle, (IntPtr) name_ptr, (IntPtr) signature_ptr); + thrown = JniNativeMethods.ExceptionOccurred (env); + } + + Exception? __e = JniEnvironment.GetExceptionForLastThrowable (thrown); + if (__e != null) + ExceptionDispatchInfo.Capture (__e).Throw (); + + if (field == IntPtr.Zero) + throw new InvalidOperationException ("Should not be reached; `GetFieldID` should have thrown!"); + +#if DEBUG + return new JniFieldInfo (name.ToString (), signature.ToString (), field, isStatic: false); +#else // DEBUG + return new JniFieldInfo (null!, null!, field, isStatic: false); +#endif // DEBUG + } + } +} diff --git a/src/Java.Interop/Java.Interop/JniEnvironment.StaticMethods.cs b/src/Java.Interop/Java.Interop/JniEnvironment.StaticMethods.cs new file mode 100644 index 000000000..a4e62d48b --- /dev/null +++ b/src/Java.Interop/Java.Interop/JniEnvironment.StaticMethods.cs @@ -0,0 +1,82 @@ +using System; +using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; +using System.Runtime.ExceptionServices; +using System.Runtime.InteropServices; + +namespace Java.Interop; + +partial class JniEnvironment { + partial class StaticMethods { + + public static unsafe JniMethodInfo GetStaticMethodID (JniObjectReference type, ReadOnlySpan name, ReadOnlySpan signature) + { + if (!type.IsValid) + throw new ArgumentException ("Handle must be valid.", "type"); + + IntPtr env = JniEnvironment.EnvironmentPointer; + IntPtr method; + IntPtr thrown; + fixed (void* name_ptr = &MemoryMarshal.GetReference (name)) + fixed (void* signature_ptr = &MemoryMarshal.GetReference (signature)) { + method = JniNativeMethods.GetStaticMethodID (env, type.Handle, (IntPtr) name_ptr, (IntPtr) signature_ptr); + thrown = JniNativeMethods.ExceptionOccurred (env); + } + + Exception? __e = JniEnvironment.GetExceptionForLastThrowable (thrown); + if (__e != null) + ExceptionDispatchInfo.Capture (__e).Throw (); + + if (method == IntPtr.Zero) + throw new InvalidOperationException ("Should not be reached; `GetStaticMethodID` should have thrown!"); + +#if DEBUG + return new JniMethodInfo (name.ToString (), signature.ToString (), method, isStatic: true); +#else // DEBUG + return new JniMethodInfo (null!, null!, method, isStatic: true); +#endif // DEBUG + } + + internal static unsafe bool TryGetStaticMethod ( + JniObjectReference type, + ReadOnlySpan name, + ReadOnlySpan signature, + [NotNullWhen(true)] + out JniMethodInfo? method) + { + method = null; + + if (!type.IsValid) + throw new ArgumentException ("Handle must be valid.", "type"); + + IntPtr env = JniEnvironment.EnvironmentPointer; + IntPtr id; + IntPtr thrown; + fixed (void* name_ptr = &MemoryMarshal.GetReference (name)) + fixed (void* signature_ptr = &MemoryMarshal.GetReference (signature)) { + id = JniNativeMethods.GetStaticMethodID (env, type.Handle, (IntPtr) name_ptr, (IntPtr) signature_ptr); + thrown = JniNativeMethods.ExceptionOccurred (env); + } + + if (thrown != IntPtr.Zero) { + JniNativeMethods.ExceptionClear (env); + JniEnvironment.References.RawDeleteLocalRef (env, thrown); + thrown = IntPtr.Zero; + return false; + } + + Debug.Assert (id != IntPtr.Zero); + if (id == IntPtr.Zero) { + return false; + } + +#if DEBUG + method = new JniMethodInfo (name.ToString (), signature.ToString (), id, isStatic: true); +#else // DEBUG + method = new JniMethodInfo (null!, null!, id, isStatic: true); +#endif // DEBUG + + return true; + } + } +} diff --git a/src/Java.Interop/Java.Interop/JniMemberInfoLookup.cs b/src/Java.Interop/Java.Interop/JniMemberInfoLookup.cs new file mode 100644 index 000000000..c2e019141 --- /dev/null +++ b/src/Java.Interop/Java.Interop/JniMemberInfoLookup.cs @@ -0,0 +1,16 @@ +using System; + +namespace Java.Interop; + +public ref struct JniMemberInfoLookup { + public string EncodedMember {get; private set;} + public ReadOnlySpan MemberName {get; private set;} + public ReadOnlySpan MemberSignature {get; private set;} + + public JniMemberInfoLookup (string encodedMember, ReadOnlySpan memberName, ReadOnlySpan memberSignature) + { + EncodedMember = encodedMember; + MemberName = memberName; + MemberSignature = memberSignature; + } +} diff --git a/src/Java.Interop/Java.Interop/JniPeerMembers.JniInstanceFields.cs b/src/Java.Interop/Java.Interop/JniPeerMembers.JniInstanceFields.cs index e0a5ae40d..48f6f9e16 100644 --- a/src/Java.Interop/Java.Interop/JniPeerMembers.JniInstanceFields.cs +++ b/src/Java.Interop/Java.Interop/JniPeerMembers.JniInstanceFields.cs @@ -34,6 +34,17 @@ public JniFieldInfo GetFieldInfo (string encodedMember) return f; } } + + public JniFieldInfo GetFieldInfo (JniMemberInfoLookup member) + { + lock (InstanceFields) { + if (!InstanceFields.TryGetValue (member.EncodedMember, out var f)) { + f = Members.JniPeerType.GetInstanceField (member.MemberName, member.MemberSignature); + InstanceFields.Add (member.EncodedMember, f); + } + return f; + } + } }} } diff --git a/src/Java.Interop/Java.Interop/JniPeerMembers.JniInstanceMethods.cs b/src/Java.Interop/Java.Interop/JniPeerMembers.JniInstanceMethods.cs index 04d96870e..dbf55b000 100644 --- a/src/Java.Interop/Java.Interop/JniPeerMembers.JniInstanceMethods.cs +++ b/src/Java.Interop/Java.Interop/JniPeerMembers.JniInstanceMethods.cs @@ -157,6 +157,48 @@ JniMethodInfo GetMethodInfo (string method, string signature) return JniPeerType.GetInstanceMethod (method, signature); } + + public JniMethodInfo GetMethodInfo (JniMemberInfoLookup member) + { + lock (InstanceMethods) { + if (InstanceMethods.TryGetValue (member.EncodedMember, out var m)) { + return m; + } + } + var info = GetMethodInfo (member.MemberName, member.MemberSignature); + lock (InstanceMethods) { + if (InstanceMethods.TryGetValue (member.EncodedMember, out var m)) { + return m; + } + InstanceMethods.Add (member.EncodedMember, info); + } + return info; + } + + JniMethodInfo GetMethodInfo (ReadOnlySpan method, ReadOnlySpan signature) + { + 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.ToString (); + var methodSig = newMethod.Value.TargetJniMethodSignature ?? signature.ToString (); + + 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.ToString ()}.{signature.ToString ()}`, could not find requested method `{typeName}.{methodName}.{methodSig}`!"); + } + return JniPeerType.GetInstanceMethod (method, signature); + } + public unsafe JniObjectReference StartCreateInstance (string constructorSignature, Type declaringType, JniArgumentValue* parameters) { if (constructorSignature == null) diff --git a/src/Java.Interop/Java.Interop/JniPeerMembers.JniStaticFields.cs b/src/Java.Interop/Java.Interop/JniPeerMembers.JniStaticFields.cs index 7fe131b62..5a2626cb4 100644 --- a/src/Java.Interop/Java.Interop/JniPeerMembers.JniStaticFields.cs +++ b/src/Java.Interop/Java.Interop/JniPeerMembers.JniStaticFields.cs @@ -30,6 +30,17 @@ public JniFieldInfo GetFieldInfo (string encodedMember) } } + public JniFieldInfo GetFieldInfo (JniMemberInfoLookup member) + { + lock (StaticFields) { + if (!StaticFields.TryGetValue (member.EncodedMember, out var f)) { + f = Members.JniPeerType.GetInstanceField (member.MemberName, member.MemberSignature); + StaticFields.Add (member.EncodedMember, f); + } + return f; + } + } + internal void Dispose () { StaticFields.Clear (); diff --git a/src/Java.Interop/Java.Interop/JniPeerMembers.JniStaticMethods.cs b/src/Java.Interop/Java.Interop/JniPeerMembers.JniStaticMethods.cs index 9ce77fbe3..84123874f 100644 --- a/src/Java.Interop/Java.Interop/JniPeerMembers.JniStaticMethods.cs +++ b/src/Java.Interop/Java.Interop/JniPeerMembers.JniStaticMethods.cs @@ -66,6 +66,46 @@ JniMethodInfo GetMethodInfo (string method, string signature) return Members.JniPeerType.GetStaticMethod (method, signature); } + public JniMethodInfo GetMethodInfo (JniMemberInfoLookup member) + { + lock (StaticMethods) { + if (StaticMethods.TryGetValue (member.EncodedMember, out var m)) { + return m; + } + } + var info = GetMethodInfo (member.MemberName, member.MemberSignature); + lock (StaticMethods) { + if (StaticMethods.TryGetValue (member.EncodedMember, out var m)) { + return m; + } + StaticMethods.Add (member.EncodedMember, info); + } + return info; + } + + JniMethodInfo GetMethodInfo (ReadOnlySpan method, ReadOnlySpan signature) + { + 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.ToString (), + newMethod.Value.TargetJniMethodSignature ?? signature.ToString (), + out m)) { + return m; + } + } + if (Members.JniPeerType.TryGetStaticMethod (method, signature, out m)) { + return m; + } + m = FindInFallbackTypes (method, signature); + if (m != null) { + return m; + } + return Members.JniPeerType.GetStaticMethod (method, signature); + } + #pragma warning disable CA1801 JniType GetMethodDeclaringType (JniMethodInfo method) { @@ -105,6 +145,31 @@ JniType GetMethodDeclaringType (JniMethodInfo method) } #endif // NET + JniMethodInfo? FindInFallbackTypes (ReadOnlySpan method, ReadOnlySpan 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)) { + m.StaticRedirect = t; + t = null; + return m; + } + } + finally { + t?.Dispose (); + } + } + return null; + } + public unsafe void InvokeVoidMethod (string encodedMember, JniArgumentValue* parameters) { var m = GetMethodInfo (encodedMember); diff --git a/src/Java.Interop/Java.Interop/JniRuntime.JniTypeManager.cs b/src/Java.Interop/Java.Interop/JniRuntime.JniTypeManager.cs index cc778dba7..45078568d 100644 --- a/src/Java.Interop/Java.Interop/JniRuntime.JniTypeManager.cs +++ b/src/Java.Interop/Java.Interop/JniRuntime.JniTypeManager.cs @@ -423,6 +423,22 @@ IEnumerable CreateGetTypesForSimpleReferenceEnumerator (string jniSimpleRe protected virtual ReplacementMethodInfo? GetReplacementMethodInfoCore (string jniSimpleReference, string jniMethodName, string jniMethodSignature) => null; + public ReplacementMethodInfo? GetReplacementMethodInfo (string jniSimpleReference, ReadOnlySpan jniMethodName, ReadOnlySpan jniMethodSignature) + { + AssertValid (); + AssertSimpleReference (jniSimpleReference, nameof (jniSimpleReference)); + if (jniMethodName.IsEmpty) { + throw new ArgumentNullException (nameof (jniMethodName)); + } + if (jniMethodSignature.IsEmpty) { + throw new ArgumentNullException (nameof (jniMethodSignature)); + } + + return GetReplacementMethodInfoCore (jniSimpleReference, jniMethodName, jniMethodSignature); + } + + protected virtual ReplacementMethodInfo? GetReplacementMethodInfoCore (string jniSimpleReference, ReadOnlySpan jniMethodName, ReadOnlySpan jniMethodSignature) => null; + public virtual void RegisterNativeMembers ( JniType nativeClass, [DynamicallyAccessedMembers (MethodsAndPrivateNested)] diff --git a/src/Java.Interop/Java.Interop/JniType.cs b/src/Java.Interop/Java.Interop/JniType.cs index 396f5067b..f02d32936 100644 --- a/src/Java.Interop/Java.Interop/JniType.cs +++ b/src/Java.Interop/Java.Interop/JniType.cs @@ -210,6 +210,13 @@ public JniFieldInfo GetInstanceField (string name, string signature) return JniEnvironment.InstanceFields.GetFieldID (PeerReference, name, signature); } + public JniFieldInfo GetInstanceField (ReadOnlySpan name, ReadOnlySpan signature) + { + AssertValid (); + + return JniEnvironment.InstanceFields.GetFieldID (PeerReference, name, signature); + } + public JniFieldInfo GetCachedInstanceField ([NotNull] ref JniFieldInfo? cachedField, string name, string signature) { AssertValid (); @@ -223,6 +230,19 @@ public JniFieldInfo GetCachedInstanceField ([NotNull] ref JniFieldInfo? cachedFi return cachedField; } + public JniFieldInfo GetCachedInstanceField ([NotNull] ref JniFieldInfo? cachedField, ReadOnlySpan name, ReadOnlySpan signature) + { + AssertValid (); + + if (cachedField != null && cachedField.IsValid) + return cachedField; + var m = GetInstanceField (name, signature); + if (Interlocked.CompareExchange (ref cachedField, m, null) != null) { + // No cleanup required; let the GC collect the unused instance + } + return cachedField; + } + public JniFieldInfo GetStaticField (string name, string signature) { AssertValid (); @@ -230,6 +250,14 @@ public JniFieldInfo GetStaticField (string name, string signature) return JniEnvironment.StaticFields.GetStaticFieldID (PeerReference, name, signature); } + + public JniFieldInfo GetStaticField (ReadOnlySpan name, ReadOnlySpan signature) + { + AssertValid (); + + return JniEnvironment.StaticFields.GetStaticFieldID (PeerReference, name, signature); + } + public JniFieldInfo GetCachedStaticField ([NotNull] ref JniFieldInfo? cachedField, string name, string signature) { AssertValid (); @@ -243,6 +271,19 @@ public JniFieldInfo GetCachedStaticField ([NotNull] ref JniFieldInfo? cachedFiel return cachedField; } + public JniFieldInfo GetCachedStaticField ([NotNull] ref JniFieldInfo? cachedField, ReadOnlySpan name, ReadOnlySpan signature) + { + AssertValid (); + + if (cachedField != null && cachedField.IsValid) + return cachedField; + var m = GetStaticField (name, signature); + if (Interlocked.CompareExchange (ref cachedField, m, null) != null) { + // No cleanup required; let the GC collect the unused instance + } + return cachedField; + } + public JniMethodInfo GetInstanceMethod (string name, string signature) { AssertValid (); @@ -250,6 +291,13 @@ public JniMethodInfo GetInstanceMethod (string name, string signature) return JniEnvironment.InstanceMethods.GetMethodID (PeerReference, name, signature); } + public JniMethodInfo GetInstanceMethod (ReadOnlySpan name, ReadOnlySpan signature) + { + AssertValid (); + + return JniEnvironment.InstanceMethods.GetMethodID (PeerReference, name, signature); + } + #if NET internal bool TryGetInstanceMethod (string name, string signature, [NotNullWhen(true)] out JniMethodInfo? method) { @@ -308,6 +356,19 @@ public JniMethodInfo GetCachedInstanceMethod ([NotNull] ref JniMethodInfo? cache return cachedMethod; } + public JniMethodInfo GetCachedInstanceMethod ([NotNull] ref JniMethodInfo? cachedMethod, ReadOnlySpan name, ReadOnlySpan signature) + { + AssertValid (); + + if (cachedMethod != null && cachedMethod.IsValid) + return cachedMethod; + var m = GetInstanceMethod (name, signature); + if (Interlocked.CompareExchange (ref cachedMethod, m, null) != null) { + // No cleanup required; let the GC collect the unused instance + } + return cachedMethod; + } + public JniMethodInfo GetStaticMethod (string name, string signature) { AssertValid (); @@ -315,6 +376,13 @@ public JniMethodInfo GetStaticMethod (string name, string signature) return JniEnvironment.StaticMethods.GetStaticMethodID (PeerReference, name, signature); } + + public JniMethodInfo GetStaticMethod (ReadOnlySpan name, ReadOnlySpan signature) + { + AssertValid (); + + return JniEnvironment.StaticMethods.GetStaticMethodID (PeerReference, name, signature); + } #if NET internal bool TryGetStaticMethod (string name, string signature, [NotNullWhen(true)] out JniMethodInfo? method) { @@ -360,6 +428,13 @@ IntPtr RawGetStaticMethodID (IntPtr env, string name, string signature, out IntP } #endif // NET + internal bool TryGetStaticMethod (ReadOnlySpan name, ReadOnlySpan signature, [NotNullWhen(true)] out JniMethodInfo? method) + { + AssertValid (); + + return JniEnvironment.StaticMethods.TryGetStaticMethod (PeerReference, name, signature, out method); + } + public JniMethodInfo GetCachedStaticMethod ([NotNull] ref JniMethodInfo? cachedMethod, string name, string signature) { AssertValid (); @@ -372,5 +447,18 @@ public JniMethodInfo GetCachedStaticMethod ([NotNull] ref JniMethodInfo? cachedM } return cachedMethod; } + + public JniMethodInfo GetCachedStaticMethod ([NotNull] ref JniMethodInfo? cachedMethod, ReadOnlySpan name, ReadOnlySpan signature) + { + AssertValid (); + + if (cachedMethod != null && cachedMethod.IsValid) + return cachedMethod; + var m = GetStaticMethod (name, signature); + if (Interlocked.CompareExchange (ref cachedMethod, m, null) != null) { + // No cleanup required; let the GC collect the unused instance + } + return cachedMethod; + } } } diff --git a/tests/Java.Interop-PerformanceTests/Java.Interop/TimingTests.cs b/tests/Java.Interop-PerformanceTests/Java.Interop/TimingTests.cs index 67e4c1255..e7f275580 100644 --- a/tests/Java.Interop-PerformanceTests/Java.Interop/TimingTests.cs +++ b/tests/Java.Interop-PerformanceTests/Java.Interop/TimingTests.cs @@ -402,6 +402,37 @@ public void MethodLookupTiming () } } + [TestFixture] + class JniFieldLookupTiming : Java.InteropTests.JavaVMFixture { + + [Test] + public void FieldLookupTiming () + { + const string JniType = "com/xamarin/interop/performance/JavaTiming"; + const string EncodedMember = "instanceIntField.I"; + const int count = 10000; + + var strLookupTime = Stopwatch.StartNew (); + for (int i = 0; i < count; ++i) { + var p = new JniPeerMembers (JniType, typeof (JavaTiming)); + var f = p.InstanceFields.GetFieldInfo (EncodedMember); + } + strLookupTime.Stop (); + + var encLookupTime = Stopwatch.StartNew (); + for (int i = 0; i < count; ++i) { + var p = new JniPeerMembers (JniType, typeof (JavaTiming)); + var lookup = new JniMemberInfoLookup (EncodedMember, "instanceIntField"u8, "I"u8); + var f = p.InstanceFields.GetFieldInfo (lookup); + } + encLookupTime.Stop (); + + Console.WriteLine ($"# {nameof (FieldLookupTiming)} Timing: looking up JavaTiming.instanceIntField {count} times"); + Console.WriteLine ($"# .InstanceMethods.GetFieldInfo(string): {strLookupTime.Elapsed}"); + Console.WriteLine ($"# .InstanceMethods.GetFieldInfo(JniMemberInfoLookup): {encLookupTime.Elapsed}"); + } + } + [TestFixture] class JavaArrayTiming : Java.InteropTests.JavaVMFixture { diff --git a/tests/Java.Interop-PerformanceTests/java/com/xamarin/interop/performance/JavaTiming.java b/tests/Java.Interop-PerformanceTests/java/com/xamarin/interop/performance/JavaTiming.java index ca45b787d..099e16de8 100644 --- a/tests/Java.Interop-PerformanceTests/java/com/xamarin/interop/performance/JavaTiming.java +++ b/tests/Java.Interop-PerformanceTests/java/com/xamarin/interop/performance/JavaTiming.java @@ -2,6 +2,8 @@ public class JavaTiming { + public int instanceIntField; + public static void StaticVoidMethod () { } diff --git a/tests/Java.Interop-Tests/Java.Interop/JniTypeTest.cs b/tests/Java.Interop-Tests/Java.Interop/JniTypeTest.cs index f56002836..2ccb60474 100644 --- a/tests/Java.Interop-Tests/Java.Interop/JniTypeTest.cs +++ b/tests/Java.Interop-Tests/Java.Interop/JniTypeTest.cs @@ -48,10 +48,10 @@ public unsafe void Dispose_Exceptions () Assert.Throws (() => t.AllocObject ()); Assert.Throws (() => t.NewObject (null, null)); Assert.Throws (() => t.GetConstructor (null)); - Assert.Throws (() => t.GetInstanceField (null, null)); - Assert.Throws (() => t.GetInstanceMethod (null, null)); - Assert.Throws (() => t.GetStaticField (null, null)); - Assert.Throws (() => t.GetStaticMethod (null, null)); + Assert.Throws (() => t.GetInstanceField (null, (string) null)); + Assert.Throws (() => t.GetInstanceMethod (null, (string) null)); + Assert.Throws (() => t.GetStaticField (null, (string) null)); + Assert.Throws (() => t.GetStaticMethod (null, (string) null)); Assert.Throws (() => t.GetSuperclass ()); Assert.Throws (() => t.IsAssignableFrom (null)); Assert.Throws (() => t.IsInstanceOfType (new JniObjectReference ())); @@ -60,14 +60,14 @@ public unsafe void Dispose_Exceptions () Assert.Throws (() => t.UnregisterNativeMethods ()); JniFieldInfo jif = null; - Assert.Throws (() => t.GetCachedInstanceField (ref jif, null, null)); + Assert.Throws (() => t.GetCachedInstanceField (ref jif, (string) null, (string) null)); JniMethodInfo jim = null; Assert.Throws (() => t.GetCachedConstructor (ref jim, null)); - Assert.Throws (() => t.GetCachedInstanceMethod (ref jim, null, null)); + Assert.Throws (() => t.GetCachedInstanceMethod (ref jim, (string) null, (string) null)); JniFieldInfo jsf = null; - Assert.Throws (() => t.GetCachedStaticField (ref jsf, null, null)); + Assert.Throws (() => t.GetCachedStaticField (ref jsf, (string) null, (string) null)); JniMethodInfo jsm = null; - Assert.Throws (() => t.GetCachedStaticMethod (ref jsm, null, null)); + Assert.Throws (() => t.GetCachedStaticMethod (ref jsm, (string) null, (string) null)); } [Test] From 41254f23ffee57f94f53686a3a1b3f1a1d6802f7 Mon Sep 17 00:00:00 2001 From: "Jonathan Pryor (HE/HIM)" Date: Fri, 29 Mar 2024 18:58:54 -0400 Subject: [PATCH 2/6] Fix PublicAPI.Unshipped.txt errors. --- .../Java.Interop/JniMemberInfoLookup.cs | 6 +++++ src/Java.Interop/PublicAPI.Unshipped.txt | 24 +++++++++++++++++++ 2 files changed, 30 insertions(+) diff --git a/src/Java.Interop/Java.Interop/JniMemberInfoLookup.cs b/src/Java.Interop/Java.Interop/JniMemberInfoLookup.cs index c2e019141..d0582c2a1 100644 --- a/src/Java.Interop/Java.Interop/JniMemberInfoLookup.cs +++ b/src/Java.Interop/Java.Interop/JniMemberInfoLookup.cs @@ -7,6 +7,12 @@ public ref struct JniMemberInfoLookup { public ReadOnlySpan MemberName {get; private set;} public ReadOnlySpan MemberSignature {get; private set;} + [Obsolete ("Use the JniMemberInfoLookup(string, ReadOnlySpan, ReadOnlySpan) constructor.", error: true)] + public JniMemberInfoLookup () + { + throw new NotSupportedException (); + } + public JniMemberInfoLookup (string encodedMember, ReadOnlySpan memberName, ReadOnlySpan memberSignature) { EncodedMember = encodedMember; diff --git a/src/Java.Interop/PublicAPI.Unshipped.txt b/src/Java.Interop/PublicAPI.Unshipped.txt index 7dc5c5811..ef0e5e10a 100644 --- a/src/Java.Interop/PublicAPI.Unshipped.txt +++ b/src/Java.Interop/PublicAPI.Unshipped.txt @@ -1 +1,25 @@ #nullable enable +Java.Interop.JniMemberInfoLookup +Java.Interop.JniMemberInfoLookup.EncodedMember.get -> string! +Java.Interop.JniMemberInfoLookup.JniMemberInfoLookup() -> void +Java.Interop.JniMemberInfoLookup.JniMemberInfoLookup(string! encodedMember, System.ReadOnlySpan memberName, System.ReadOnlySpan memberSignature) -> void +Java.Interop.JniMemberInfoLookup.MemberName.get -> System.ReadOnlySpan +Java.Interop.JniMemberInfoLookup.MemberSignature.get -> System.ReadOnlySpan +Java.Interop.JniPeerMembers.JniInstanceFields.GetFieldInfo(Java.Interop.JniMemberInfoLookup member) -> Java.Interop.JniFieldInfo! +Java.Interop.JniPeerMembers.JniInstanceMethods.GetMethodInfo(Java.Interop.JniMemberInfoLookup member) -> Java.Interop.JniMethodInfo! +Java.Interop.JniPeerMembers.JniStaticFields.GetFieldInfo(Java.Interop.JniMemberInfoLookup member) -> Java.Interop.JniFieldInfo! +Java.Interop.JniPeerMembers.JniStaticMethods.GetMethodInfo(Java.Interop.JniMemberInfoLookup member) -> Java.Interop.JniMethodInfo! +Java.Interop.JniRuntime.JniTypeManager.GetReplacementMethodInfo(string! jniSimpleReference, System.ReadOnlySpan jniMethodName, System.ReadOnlySpan jniMethodSignature) -> Java.Interop.JniRuntime.ReplacementMethodInfo? +Java.Interop.JniType.GetCachedInstanceField(ref Java.Interop.JniFieldInfo? cachedField, System.ReadOnlySpan name, System.ReadOnlySpan signature) -> Java.Interop.JniFieldInfo! +Java.Interop.JniType.GetCachedInstanceMethod(ref Java.Interop.JniMethodInfo? cachedMethod, System.ReadOnlySpan name, System.ReadOnlySpan signature) -> Java.Interop.JniMethodInfo! +Java.Interop.JniType.GetCachedStaticField(ref Java.Interop.JniFieldInfo? cachedField, System.ReadOnlySpan name, System.ReadOnlySpan signature) -> Java.Interop.JniFieldInfo! +Java.Interop.JniType.GetCachedStaticMethod(ref Java.Interop.JniMethodInfo? cachedMethod, System.ReadOnlySpan name, System.ReadOnlySpan signature) -> Java.Interop.JniMethodInfo! +Java.Interop.JniType.GetInstanceField(System.ReadOnlySpan name, System.ReadOnlySpan signature) -> Java.Interop.JniFieldInfo! +Java.Interop.JniType.GetInstanceMethod(System.ReadOnlySpan name, System.ReadOnlySpan signature) -> Java.Interop.JniMethodInfo! +Java.Interop.JniType.GetStaticField(System.ReadOnlySpan name, System.ReadOnlySpan signature) -> Java.Interop.JniFieldInfo! +Java.Interop.JniType.GetStaticMethod(System.ReadOnlySpan name, System.ReadOnlySpan signature) -> Java.Interop.JniMethodInfo! +static Java.Interop.JniEnvironment.InstanceFields.GetFieldID(Java.Interop.JniObjectReference type, System.ReadOnlySpan name, System.ReadOnlySpan signature) -> Java.Interop.JniFieldInfo! +static Java.Interop.JniEnvironment.InstanceMethods.GetMethodID(Java.Interop.JniObjectReference type, System.ReadOnlySpan name, System.ReadOnlySpan signature) -> Java.Interop.JniMethodInfo! +static Java.Interop.JniEnvironment.StaticFields.GetStaticFieldID(Java.Interop.JniObjectReference type, System.ReadOnlySpan name, System.ReadOnlySpan signature) -> Java.Interop.JniFieldInfo! +static Java.Interop.JniEnvironment.StaticMethods.GetStaticMethodID(Java.Interop.JniObjectReference type, System.ReadOnlySpan name, System.ReadOnlySpan signature) -> Java.Interop.JniMethodInfo! +virtual Java.Interop.JniRuntime.JniTypeManager.GetReplacementMethodInfoCore(string! jniSimpleReference, System.ReadOnlySpan jniMethodName, System.ReadOnlySpan jniMethodSignature) -> Java.Interop.JniRuntime.ReplacementMethodInfo? From 86e15a3cbb5c117e28a8493e1685de9eab418ff5 Mon Sep 17 00:00:00 2001 From: Jonathan Pryor Date: Fri, 5 Jul 2024 15:07:50 -0400 Subject: [PATCH 3/6] Fix indentation --- .../JniEnvironment.StaticMethods.cs | 30 +++++++++---------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/src/Java.Interop/Java.Interop/JniEnvironment.StaticMethods.cs b/src/Java.Interop/Java.Interop/JniEnvironment.StaticMethods.cs index a4e62d48b..81ae95628 100644 --- a/src/Java.Interop/Java.Interop/JniEnvironment.StaticMethods.cs +++ b/src/Java.Interop/Java.Interop/JniEnvironment.StaticMethods.cs @@ -38,13 +38,13 @@ public static unsafe JniMethodInfo GetStaticMethodID (JniObjectReference type, R } internal static unsafe bool TryGetStaticMethod ( - JniObjectReference type, - ReadOnlySpan name, - ReadOnlySpan signature, - [NotNullWhen(true)] - out JniMethodInfo? method) + JniObjectReference type, + ReadOnlySpan name, + ReadOnlySpan signature, + [NotNullWhen(true)] + out JniMethodInfo? method) { - method = null; + method = null; if (!type.IsValid) throw new ArgumentException ("Handle must be valid.", "type"); @@ -58,17 +58,17 @@ internal static unsafe bool TryGetStaticMethod ( thrown = JniNativeMethods.ExceptionOccurred (env); } - if (thrown != IntPtr.Zero) { - JniNativeMethods.ExceptionClear (env); + if (thrown != IntPtr.Zero) { + JniNativeMethods.ExceptionClear (env); JniEnvironment.References.RawDeleteLocalRef (env, thrown); - thrown = IntPtr.Zero; - return false; - } + thrown = IntPtr.Zero; + return false; + } Debug.Assert (id != IntPtr.Zero); - if (id == IntPtr.Zero) { - return false; - } + if (id == IntPtr.Zero) { + return false; + } #if DEBUG method = new JniMethodInfo (name.ToString (), signature.ToString (), id, isStatic: true); @@ -76,7 +76,7 @@ internal static unsafe bool TryGetStaticMethod ( method = new JniMethodInfo (null!, null!, id, isStatic: true); #endif // DEBUG - return true; + return true; } } } From 6dd933cf9ea515616b9a7cd7418b5c5eeaf1e717 Mon Sep 17 00:00:00 2001 From: Jonathan Pryor Date: Fri, 5 Jul 2024 15:39:37 -0400 Subject: [PATCH 4/6] =?UTF-8?q?Flesh=20things=20out=E2=80=A6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Java.Interop/JniPeerMembers.JniFields.cs | 299 +++++++++++++++++- .../Java.Interop/JniPeerMembers.JniFields.tt | 33 ++ 2 files changed, 331 insertions(+), 1 deletion(-) diff --git a/src/Java.Interop/Java.Interop/JniPeerMembers.JniFields.cs b/src/Java.Interop/Java.Interop/JniPeerMembers.JniFields.cs index ea9d0cb51..2eea2cc04 100644 --- a/src/Java.Interop/Java.Interop/JniPeerMembers.JniFields.cs +++ b/src/Java.Interop/Java.Interop/JniPeerMembers.JniFields.cs @@ -1,4 +1,4 @@ -#nullable enable +#nullable enable using System; @@ -28,6 +28,27 @@ public void SetValue (string encodedMember, IJavaPeerable self, bool value) GC.KeepAlive (self); } + public bool GetBooleanValue ( + JniMemberInfoLookup member, + IJavaPeerable self) + { + JniPeerMembers.AssertSelf (self); + + var f = GetFieldInfo (member); + var r = JniEnvironment.InstanceFields.GetBooleanField (self.PeerReference, f); + GC.KeepAlive (self); + return r; + } + + public void SetValue (JniMemberInfoLookup member, IJavaPeerable self, bool value) + { + JniPeerMembers.AssertSelf (self); + + var f = GetFieldInfo (member); + JniEnvironment.InstanceFields.SetBooleanField (self.PeerReference, f, value); + GC.KeepAlive (self); + } + public sbyte GetSByteValue ( string encodedMember, IJavaPeerable self) @@ -49,6 +70,27 @@ public void SetValue (string encodedMember, IJavaPeerable self, sbyte value) GC.KeepAlive (self); } + public sbyte GetSByteValue ( + JniMemberInfoLookup member, + IJavaPeerable self) + { + JniPeerMembers.AssertSelf (self); + + var f = GetFieldInfo (member); + var r = JniEnvironment.InstanceFields.GetByteField (self.PeerReference, f); + GC.KeepAlive (self); + return r; + } + + public void SetValue (JniMemberInfoLookup member, IJavaPeerable self, sbyte value) + { + JniPeerMembers.AssertSelf (self); + + var f = GetFieldInfo (member); + JniEnvironment.InstanceFields.SetByteField (self.PeerReference, f, value); + GC.KeepAlive (self); + } + public char GetCharValue ( string encodedMember, IJavaPeerable self) @@ -70,6 +112,27 @@ public void SetValue (string encodedMember, IJavaPeerable self, char value) GC.KeepAlive (self); } + public char GetCharValue ( + JniMemberInfoLookup member, + IJavaPeerable self) + { + JniPeerMembers.AssertSelf (self); + + var f = GetFieldInfo (member); + var r = JniEnvironment.InstanceFields.GetCharField (self.PeerReference, f); + GC.KeepAlive (self); + return r; + } + + public void SetValue (JniMemberInfoLookup member, IJavaPeerable self, char value) + { + JniPeerMembers.AssertSelf (self); + + var f = GetFieldInfo (member); + JniEnvironment.InstanceFields.SetCharField (self.PeerReference, f, value); + GC.KeepAlive (self); + } + public short GetInt16Value ( string encodedMember, IJavaPeerable self) @@ -91,6 +154,27 @@ public void SetValue (string encodedMember, IJavaPeerable self, short value) GC.KeepAlive (self); } + public short GetInt16Value ( + JniMemberInfoLookup member, + IJavaPeerable self) + { + JniPeerMembers.AssertSelf (self); + + var f = GetFieldInfo (member); + var r = JniEnvironment.InstanceFields.GetShortField (self.PeerReference, f); + GC.KeepAlive (self); + return r; + } + + public void SetValue (JniMemberInfoLookup member, IJavaPeerable self, short value) + { + JniPeerMembers.AssertSelf (self); + + var f = GetFieldInfo (member); + JniEnvironment.InstanceFields.SetShortField (self.PeerReference, f, value); + GC.KeepAlive (self); + } + public int GetInt32Value ( string encodedMember, IJavaPeerable self) @@ -112,6 +196,27 @@ public void SetValue (string encodedMember, IJavaPeerable self, int value) GC.KeepAlive (self); } + public int GetInt32Value ( + JniMemberInfoLookup member, + IJavaPeerable self) + { + JniPeerMembers.AssertSelf (self); + + var f = GetFieldInfo (member); + var r = JniEnvironment.InstanceFields.GetIntField (self.PeerReference, f); + GC.KeepAlive (self); + return r; + } + + public void SetValue (JniMemberInfoLookup member, IJavaPeerable self, int value) + { + JniPeerMembers.AssertSelf (self); + + var f = GetFieldInfo (member); + JniEnvironment.InstanceFields.SetIntField (self.PeerReference, f, value); + GC.KeepAlive (self); + } + public long GetInt64Value ( string encodedMember, IJavaPeerable self) @@ -133,6 +238,27 @@ public void SetValue (string encodedMember, IJavaPeerable self, long value) GC.KeepAlive (self); } + public long GetInt64Value ( + JniMemberInfoLookup member, + IJavaPeerable self) + { + JniPeerMembers.AssertSelf (self); + + var f = GetFieldInfo (member); + var r = JniEnvironment.InstanceFields.GetLongField (self.PeerReference, f); + GC.KeepAlive (self); + return r; + } + + public void SetValue (JniMemberInfoLookup member, IJavaPeerable self, long value) + { + JniPeerMembers.AssertSelf (self); + + var f = GetFieldInfo (member); + JniEnvironment.InstanceFields.SetLongField (self.PeerReference, f, value); + GC.KeepAlive (self); + } + public float GetSingleValue ( string encodedMember, IJavaPeerable self) @@ -154,6 +280,27 @@ public void SetValue (string encodedMember, IJavaPeerable self, float value) GC.KeepAlive (self); } + public float GetSingleValue ( + JniMemberInfoLookup member, + IJavaPeerable self) + { + JniPeerMembers.AssertSelf (self); + + var f = GetFieldInfo (member); + var r = JniEnvironment.InstanceFields.GetFloatField (self.PeerReference, f); + GC.KeepAlive (self); + return r; + } + + public void SetValue (JniMemberInfoLookup member, IJavaPeerable self, float value) + { + JniPeerMembers.AssertSelf (self); + + var f = GetFieldInfo (member); + JniEnvironment.InstanceFields.SetFloatField (self.PeerReference, f, value); + GC.KeepAlive (self); + } + public double GetDoubleValue ( string encodedMember, IJavaPeerable self) @@ -175,6 +322,27 @@ public void SetValue (string encodedMember, IJavaPeerable self, double value) GC.KeepAlive (self); } + public double GetDoubleValue ( + JniMemberInfoLookup member, + IJavaPeerable self) + { + JniPeerMembers.AssertSelf (self); + + var f = GetFieldInfo (member); + var r = JniEnvironment.InstanceFields.GetDoubleField (self.PeerReference, f); + GC.KeepAlive (self); + return r; + } + + public void SetValue (JniMemberInfoLookup member, IJavaPeerable self, double value) + { + JniPeerMembers.AssertSelf (self); + + var f = GetFieldInfo (member); + JniEnvironment.InstanceFields.SetDoubleField (self.PeerReference, f, value); + GC.KeepAlive (self); + } + public JniObjectReference GetObjectValue ( string encodedMember, IJavaPeerable self) @@ -195,6 +363,27 @@ public void SetValue (string encodedMember, IJavaPeerable self, JniObjectReferen JniEnvironment.InstanceFields.SetObjectField (self.PeerReference, f, value); GC.KeepAlive (self); } + + public JniObjectReference GetObjectValue ( + JniMemberInfoLookup member, + IJavaPeerable self) + { + JniPeerMembers.AssertSelf (self); + + var f = GetFieldInfo (member); + var r = JniEnvironment.InstanceFields.GetObjectField (self.PeerReference, f); + GC.KeepAlive (self); + return r; + } + + public void SetValue (JniMemberInfoLookup member, IJavaPeerable self, JniObjectReference value) + { + JniPeerMembers.AssertSelf (self); + + var f = GetFieldInfo (member); + JniEnvironment.InstanceFields.SetObjectField (self.PeerReference, f, value); + GC.KeepAlive (self); + } } partial class JniStaticFields { @@ -211,6 +400,18 @@ public void SetValue (string encodedMember, bool value) JniEnvironment.StaticFields.SetStaticBooleanField (Members.JniPeerType.PeerReference, f, value); } + public bool GetBooleanValue (JniMemberInfoLookup member) + { + var f = GetFieldInfo (member); + return JniEnvironment.StaticFields.GetStaticBooleanField (Members.JniPeerType.PeerReference, f); + } + + public void SetValue (JniMemberInfoLookup member, bool value) + { + var f = GetFieldInfo (member); + JniEnvironment.StaticFields.SetStaticBooleanField (Members.JniPeerType.PeerReference, f, value); + } + public sbyte GetSByteValue (string encodedMember) { var f = GetFieldInfo (encodedMember); @@ -223,6 +424,18 @@ public void SetValue (string encodedMember, sbyte value) JniEnvironment.StaticFields.SetStaticByteField (Members.JniPeerType.PeerReference, f, value); } + public sbyte GetSByteValue (JniMemberInfoLookup member) + { + var f = GetFieldInfo (member); + return JniEnvironment.StaticFields.GetStaticByteField (Members.JniPeerType.PeerReference, f); + } + + public void SetValue (JniMemberInfoLookup member, sbyte value) + { + var f = GetFieldInfo (member); + JniEnvironment.StaticFields.SetStaticByteField (Members.JniPeerType.PeerReference, f, value); + } + public char GetCharValue (string encodedMember) { var f = GetFieldInfo (encodedMember); @@ -235,6 +448,18 @@ public void SetValue (string encodedMember, char value) JniEnvironment.StaticFields.SetStaticCharField (Members.JniPeerType.PeerReference, f, value); } + public char GetCharValue (JniMemberInfoLookup member) + { + var f = GetFieldInfo (member); + return JniEnvironment.StaticFields.GetStaticCharField (Members.JniPeerType.PeerReference, f); + } + + public void SetValue (JniMemberInfoLookup member, char value) + { + var f = GetFieldInfo (member); + JniEnvironment.StaticFields.SetStaticCharField (Members.JniPeerType.PeerReference, f, value); + } + public short GetInt16Value (string encodedMember) { var f = GetFieldInfo (encodedMember); @@ -247,6 +472,18 @@ public void SetValue (string encodedMember, short value) JniEnvironment.StaticFields.SetStaticShortField (Members.JniPeerType.PeerReference, f, value); } + public short GetInt16Value (JniMemberInfoLookup member) + { + var f = GetFieldInfo (member); + return JniEnvironment.StaticFields.GetStaticShortField (Members.JniPeerType.PeerReference, f); + } + + public void SetValue (JniMemberInfoLookup member, short value) + { + var f = GetFieldInfo (member); + JniEnvironment.StaticFields.SetStaticShortField (Members.JniPeerType.PeerReference, f, value); + } + public int GetInt32Value (string encodedMember) { var f = GetFieldInfo (encodedMember); @@ -259,6 +496,18 @@ public void SetValue (string encodedMember, int value) JniEnvironment.StaticFields.SetStaticIntField (Members.JniPeerType.PeerReference, f, value); } + public int GetInt32Value (JniMemberInfoLookup member) + { + var f = GetFieldInfo (member); + return JniEnvironment.StaticFields.GetStaticIntField (Members.JniPeerType.PeerReference, f); + } + + public void SetValue (JniMemberInfoLookup member, int value) + { + var f = GetFieldInfo (member); + JniEnvironment.StaticFields.SetStaticIntField (Members.JniPeerType.PeerReference, f, value); + } + public long GetInt64Value (string encodedMember) { var f = GetFieldInfo (encodedMember); @@ -271,6 +520,18 @@ public void SetValue (string encodedMember, long value) JniEnvironment.StaticFields.SetStaticLongField (Members.JniPeerType.PeerReference, f, value); } + public long GetInt64Value (JniMemberInfoLookup member) + { + var f = GetFieldInfo (member); + return JniEnvironment.StaticFields.GetStaticLongField (Members.JniPeerType.PeerReference, f); + } + + public void SetValue (JniMemberInfoLookup member, long value) + { + var f = GetFieldInfo (member); + JniEnvironment.StaticFields.SetStaticLongField (Members.JniPeerType.PeerReference, f, value); + } + public float GetSingleValue (string encodedMember) { var f = GetFieldInfo (encodedMember); @@ -283,6 +544,18 @@ public void SetValue (string encodedMember, float value) JniEnvironment.StaticFields.SetStaticFloatField (Members.JniPeerType.PeerReference, f, value); } + public float GetSingleValue (JniMemberInfoLookup member) + { + var f = GetFieldInfo (member); + return JniEnvironment.StaticFields.GetStaticFloatField (Members.JniPeerType.PeerReference, f); + } + + public void SetValue (JniMemberInfoLookup member, float value) + { + var f = GetFieldInfo (member); + JniEnvironment.StaticFields.SetStaticFloatField (Members.JniPeerType.PeerReference, f, value); + } + public double GetDoubleValue (string encodedMember) { var f = GetFieldInfo (encodedMember); @@ -295,6 +568,18 @@ public void SetValue (string encodedMember, double value) JniEnvironment.StaticFields.SetStaticDoubleField (Members.JniPeerType.PeerReference, f, value); } + public double GetDoubleValue (JniMemberInfoLookup member) + { + var f = GetFieldInfo (member); + return JniEnvironment.StaticFields.GetStaticDoubleField (Members.JniPeerType.PeerReference, f); + } + + public void SetValue (JniMemberInfoLookup member, double value) + { + var f = GetFieldInfo (member); + JniEnvironment.StaticFields.SetStaticDoubleField (Members.JniPeerType.PeerReference, f, value); + } + public JniObjectReference GetObjectValue (string encodedMember) { var f = GetFieldInfo (encodedMember); @@ -306,5 +591,17 @@ public void SetValue (string encodedMember, JniObjectReference value) var f = GetFieldInfo (encodedMember); JniEnvironment.StaticFields.SetStaticObjectField (Members.JniPeerType.PeerReference, f, value); } + + public JniObjectReference GetObjectValue (JniMemberInfoLookup member) + { + var f = GetFieldInfo (member); + return JniEnvironment.StaticFields.GetStaticObjectField (Members.JniPeerType.PeerReference, f); + } + + public void SetValue (JniMemberInfoLookup member, JniObjectReference value) + { + var f = GetFieldInfo (member); + JniEnvironment.StaticFields.SetStaticObjectField (Members.JniPeerType.PeerReference, f, value); + } }} } diff --git a/src/Java.Interop/Java.Interop/JniPeerMembers.JniFields.tt b/src/Java.Interop/Java.Interop/JniPeerMembers.JniFields.tt index f569b372b..3602a74e6 100644 --- a/src/Java.Interop/Java.Interop/JniPeerMembers.JniFields.tt +++ b/src/Java.Interop/Java.Interop/JniPeerMembers.JniFields.tt @@ -49,6 +49,27 @@ namespace Java.Interop { JniEnvironment.InstanceFields.Set<#= info.JniCallType #>Field (self.PeerReference, f, value); GC.KeepAlive (self); } + + public <#= info.ReturnType #> Get<#= info.ManagedType #>Value ( + JniMemberInfoLookup member, + IJavaPeerable self) + { + JniPeerMembers.AssertSelf (self); + + var f = GetFieldInfo (member); + var r = JniEnvironment.InstanceFields.Get<#= info.JniCallType #>Field (self.PeerReference, f); + GC.KeepAlive (self); + return r; + } + + public void SetValue (JniMemberInfoLookup member, IJavaPeerable self, <#= info.ParameterType #> value) + { + JniPeerMembers.AssertSelf (self); + + var f = GetFieldInfo (member); + JniEnvironment.InstanceFields.Set<#= info.JniCallType #>Field (self.PeerReference, f, value); + GC.KeepAlive (self); + } <# } #> @@ -70,6 +91,18 @@ namespace Java.Interop { var f = GetFieldInfo (encodedMember); JniEnvironment.StaticFields.SetStatic<#= info.JniCallType #>Field (Members.JniPeerType.PeerReference, f, value); } + + public <#= info.ReturnType #> Get<#= info.ManagedType #>Value (JniMemberInfoLookup member) + { + var f = GetFieldInfo (member); + return JniEnvironment.StaticFields.GetStatic<#= info.JniCallType #>Field (Members.JniPeerType.PeerReference, f); + } + + public void SetValue (JniMemberInfoLookup member, <#= info.ParameterType #> value) + { + var f = GetFieldInfo (member); + JniEnvironment.StaticFields.SetStatic<#= info.JniCallType #>Field (Members.JniPeerType.PeerReference, f, value); + } <# } #> From cdf490286a6085b72159dc424e16351b6c5896d1 Mon Sep 17 00:00:00 2001 From: Jonathan Pryor Date: Mon, 8 Jul 2024 19:44:42 -0400 Subject: [PATCH 5/6] Flesh out method lookup --- ...niPeerMembers.JniInstanceMethods_Invoke.cs | 693 +++++++++++++++++- ...niPeerMembers.JniInstanceMethods_Invoke.tt | 70 ++ .../JniPeerMembers.JniStaticMethods.cs | 81 ++ src/Java.Interop/PublicAPI.Unshipped.txt | 76 ++ 4 files changed, 919 insertions(+), 1 deletion(-) diff --git a/src/Java.Interop/Java.Interop/JniPeerMembers.JniInstanceMethods_Invoke.cs b/src/Java.Interop/Java.Interop/JniPeerMembers.JniInstanceMethods_Invoke.cs index 0e96fa29c..f8a834251 100644 --- a/src/Java.Interop/Java.Interop/JniPeerMembers.JniInstanceMethods_Invoke.cs +++ b/src/Java.Interop/Java.Interop/JniPeerMembers.JniInstanceMethods_Invoke.cs @@ -1,7 +1,8 @@ -#nullable enable +#nullable enable using System; using System.Diagnostics; +using System.Runtime.InteropServices; namespace Java.Interop { @@ -52,6 +53,25 @@ public unsafe void InvokeAbstractVoidMethod (string encodedMember, IJavaPeerable } } + public unsafe void InvokeAbstractVoidMethod (JniMemberInfoLookup member, IJavaPeerable self, ReadOnlySpan parameters) + { + JniPeerMembers.AssertSelf (self); + + try { + var m = GetMethodInfo (member); + fixed (JniArgumentValue* params_ptr = &MemoryMarshal.GetReference (parameters)) { + if (TryInvokeVoidStaticRedirect (m, self, params_ptr)) { + return; + } + JniEnvironment.InstanceMethods.CallVoidMethod (self.PeerReference, m, params_ptr); + return; + } + } + finally { + GC.KeepAlive (self); + } + } + public unsafe void InvokeVirtualVoidMethod (string encodedMember, IJavaPeerable self, JniArgumentValue* parameters) { JniPeerMembers.AssertSelf (self); @@ -81,6 +101,37 @@ public unsafe void InvokeVirtualVoidMethod (string encodedMember, IJavaPeerable } } + public unsafe void InvokeVirtualVoidMethod (JniMemberInfoLookup member, IJavaPeerable self, ReadOnlySpan parameters) + { + JniPeerMembers.AssertSelf (self); + + try { + var declaringType = DeclaringType; + fixed (JniArgumentValue* params_ptr = &MemoryMarshal.GetReference (parameters)) { + if (Members.UsesVirtualDispatch (self, declaringType)) { + var m = GetMethodInfo (member); + if (TryInvokeVoidStaticRedirect (m, self, params_ptr)) { + return; + } + JniEnvironment.InstanceMethods.CallVoidMethod (self.PeerReference, m, params_ptr); + return; + } + var j = Members.GetPeerMembers (self); + var n = j.InstanceMethods.GetMethodInfo (member); + do { + if (TryInvokeVoidStaticRedirect (n, self, params_ptr)) { + return; + } + JniEnvironment.InstanceMethods.CallNonvirtualVoidMethod (self.PeerReference, j.JniPeerType.PeerReference, n, params_ptr); + return; + } while (false); + } + } + finally { + GC.KeepAlive (self); + } + } + public unsafe void InvokeNonvirtualVoidMethod (string encodedMember, IJavaPeerable self, JniArgumentValue* parameters) { JniPeerMembers.AssertSelf (self); @@ -98,6 +149,25 @@ public unsafe void InvokeNonvirtualVoidMethod (string encodedMember, IJavaPeerab } } + public unsafe void InvokeNonvirtualVoidMethod (JniMemberInfoLookup member, IJavaPeerable self, ReadOnlySpan parameters) + { + JniPeerMembers.AssertSelf (self); + + var m = GetMethodInfo (member); + try { + fixed (JniArgumentValue* params_ptr = &MemoryMarshal.GetReference (parameters)) { + if (TryInvokeVoidStaticRedirect (m, self, params_ptr)) { + return; + } + JniEnvironment.InstanceMethods.CallNonvirtualVoidMethod (self.PeerReference, JniPeerType.PeerReference, m, params_ptr); + return; + } + } + finally { + GC.KeepAlive (self); + } + } + #pragma warning disable CA1801 static unsafe bool TryInvokeBooleanStaticRedirect (JniMethodInfo method, IJavaPeerable self, JniArgumentValue* parameters, out bool r) { @@ -141,6 +211,25 @@ public unsafe bool InvokeAbstractBooleanMethod (string encodedMember, IJavaPeera } } + public unsafe bool InvokeAbstractBooleanMethod (JniMemberInfoLookup member, IJavaPeerable self, ReadOnlySpan parameters) + { + JniPeerMembers.AssertSelf (self); + + try { + var m = GetMethodInfo (member); + fixed (JniArgumentValue* params_ptr = &MemoryMarshal.GetReference (parameters)) { + if (TryInvokeBooleanStaticRedirect (m, self, params_ptr, out bool r)) { + return r; + } + r = JniEnvironment.InstanceMethods.CallBooleanMethod (self.PeerReference, m, params_ptr); + return r; + } + } + finally { + GC.KeepAlive (self); + } + } + public unsafe bool InvokeVirtualBooleanMethod (string encodedMember, IJavaPeerable self, JniArgumentValue* parameters) { JniPeerMembers.AssertSelf (self); @@ -170,6 +259,37 @@ public unsafe bool InvokeVirtualBooleanMethod (string encodedMember, IJavaPeerab } } + public unsafe bool InvokeVirtualBooleanMethod (JniMemberInfoLookup member, IJavaPeerable self, ReadOnlySpan parameters) + { + JniPeerMembers.AssertSelf (self); + + try { + var declaringType = DeclaringType; + fixed (JniArgumentValue* params_ptr = &MemoryMarshal.GetReference (parameters)) { + if (Members.UsesVirtualDispatch (self, declaringType)) { + var m = GetMethodInfo (member); + if (TryInvokeBooleanStaticRedirect (m, self, params_ptr, out bool r)) { + return r; + } + r = JniEnvironment.InstanceMethods.CallBooleanMethod (self.PeerReference, m, params_ptr); + return r; + } + var j = Members.GetPeerMembers (self); + var n = j.InstanceMethods.GetMethodInfo (member); + do { + if (TryInvokeBooleanStaticRedirect (n, self, params_ptr, out bool r)) { + return r; + } + r = JniEnvironment.InstanceMethods.CallNonvirtualBooleanMethod (self.PeerReference, j.JniPeerType.PeerReference, n, params_ptr); + return r; + } while (false); + } + } + finally { + GC.KeepAlive (self); + } + } + public unsafe bool InvokeNonvirtualBooleanMethod (string encodedMember, IJavaPeerable self, JniArgumentValue* parameters) { JniPeerMembers.AssertSelf (self); @@ -187,6 +307,25 @@ public unsafe bool InvokeNonvirtualBooleanMethod (string encodedMember, IJavaPee } } + public unsafe bool InvokeNonvirtualBooleanMethod (JniMemberInfoLookup member, IJavaPeerable self, ReadOnlySpan parameters) + { + JniPeerMembers.AssertSelf (self); + + var m = GetMethodInfo (member); + try { + fixed (JniArgumentValue* params_ptr = &MemoryMarshal.GetReference (parameters)) { + if (TryInvokeBooleanStaticRedirect (m, self, params_ptr, out bool r)) { + return r; + } + r = JniEnvironment.InstanceMethods.CallNonvirtualBooleanMethod (self.PeerReference, JniPeerType.PeerReference, m, params_ptr); + return r; + } + } + finally { + GC.KeepAlive (self); + } + } + #pragma warning disable CA1801 static unsafe bool TryInvokeSByteStaticRedirect (JniMethodInfo method, IJavaPeerable self, JniArgumentValue* parameters, out sbyte r) { @@ -230,6 +369,25 @@ public unsafe sbyte InvokeAbstractSByteMethod (string encodedMember, IJavaPeerab } } + public unsafe sbyte InvokeAbstractSByteMethod (JniMemberInfoLookup member, IJavaPeerable self, ReadOnlySpan parameters) + { + JniPeerMembers.AssertSelf (self); + + try { + var m = GetMethodInfo (member); + fixed (JniArgumentValue* params_ptr = &MemoryMarshal.GetReference (parameters)) { + if (TryInvokeSByteStaticRedirect (m, self, params_ptr, out sbyte r)) { + return r; + } + r = JniEnvironment.InstanceMethods.CallByteMethod (self.PeerReference, m, params_ptr); + return r; + } + } + finally { + GC.KeepAlive (self); + } + } + public unsafe sbyte InvokeVirtualSByteMethod (string encodedMember, IJavaPeerable self, JniArgumentValue* parameters) { JniPeerMembers.AssertSelf (self); @@ -259,6 +417,37 @@ public unsafe sbyte InvokeVirtualSByteMethod (string encodedMember, IJavaPeerabl } } + public unsafe sbyte InvokeVirtualSByteMethod (JniMemberInfoLookup member, IJavaPeerable self, ReadOnlySpan parameters) + { + JniPeerMembers.AssertSelf (self); + + try { + var declaringType = DeclaringType; + fixed (JniArgumentValue* params_ptr = &MemoryMarshal.GetReference (parameters)) { + if (Members.UsesVirtualDispatch (self, declaringType)) { + var m = GetMethodInfo (member); + if (TryInvokeSByteStaticRedirect (m, self, params_ptr, out sbyte r)) { + return r; + } + r = JniEnvironment.InstanceMethods.CallByteMethod (self.PeerReference, m, params_ptr); + return r; + } + var j = Members.GetPeerMembers (self); + var n = j.InstanceMethods.GetMethodInfo (member); + do { + if (TryInvokeSByteStaticRedirect (n, self, params_ptr, out sbyte r)) { + return r; + } + r = JniEnvironment.InstanceMethods.CallNonvirtualByteMethod (self.PeerReference, j.JniPeerType.PeerReference, n, params_ptr); + return r; + } while (false); + } + } + finally { + GC.KeepAlive (self); + } + } + public unsafe sbyte InvokeNonvirtualSByteMethod (string encodedMember, IJavaPeerable self, JniArgumentValue* parameters) { JniPeerMembers.AssertSelf (self); @@ -276,6 +465,25 @@ public unsafe sbyte InvokeNonvirtualSByteMethod (string encodedMember, IJavaPeer } } + public unsafe sbyte InvokeNonvirtualSByteMethod (JniMemberInfoLookup member, IJavaPeerable self, ReadOnlySpan parameters) + { + JniPeerMembers.AssertSelf (self); + + var m = GetMethodInfo (member); + try { + fixed (JniArgumentValue* params_ptr = &MemoryMarshal.GetReference (parameters)) { + if (TryInvokeSByteStaticRedirect (m, self, params_ptr, out sbyte r)) { + return r; + } + r = JniEnvironment.InstanceMethods.CallNonvirtualByteMethod (self.PeerReference, JniPeerType.PeerReference, m, params_ptr); + return r; + } + } + finally { + GC.KeepAlive (self); + } + } + #pragma warning disable CA1801 static unsafe bool TryInvokeCharStaticRedirect (JniMethodInfo method, IJavaPeerable self, JniArgumentValue* parameters, out char r) { @@ -319,6 +527,25 @@ public unsafe char InvokeAbstractCharMethod (string encodedMember, IJavaPeerable } } + public unsafe char InvokeAbstractCharMethod (JniMemberInfoLookup member, IJavaPeerable self, ReadOnlySpan parameters) + { + JniPeerMembers.AssertSelf (self); + + try { + var m = GetMethodInfo (member); + fixed (JniArgumentValue* params_ptr = &MemoryMarshal.GetReference (parameters)) { + if (TryInvokeCharStaticRedirect (m, self, params_ptr, out char r)) { + return r; + } + r = JniEnvironment.InstanceMethods.CallCharMethod (self.PeerReference, m, params_ptr); + return r; + } + } + finally { + GC.KeepAlive (self); + } + } + public unsafe char InvokeVirtualCharMethod (string encodedMember, IJavaPeerable self, JniArgumentValue* parameters) { JniPeerMembers.AssertSelf (self); @@ -348,6 +575,37 @@ public unsafe char InvokeVirtualCharMethod (string encodedMember, IJavaPeerable } } + public unsafe char InvokeVirtualCharMethod (JniMemberInfoLookup member, IJavaPeerable self, ReadOnlySpan parameters) + { + JniPeerMembers.AssertSelf (self); + + try { + var declaringType = DeclaringType; + fixed (JniArgumentValue* params_ptr = &MemoryMarshal.GetReference (parameters)) { + if (Members.UsesVirtualDispatch (self, declaringType)) { + var m = GetMethodInfo (member); + if (TryInvokeCharStaticRedirect (m, self, params_ptr, out char r)) { + return r; + } + r = JniEnvironment.InstanceMethods.CallCharMethod (self.PeerReference, m, params_ptr); + return r; + } + var j = Members.GetPeerMembers (self); + var n = j.InstanceMethods.GetMethodInfo (member); + do { + if (TryInvokeCharStaticRedirect (n, self, params_ptr, out char r)) { + return r; + } + r = JniEnvironment.InstanceMethods.CallNonvirtualCharMethod (self.PeerReference, j.JniPeerType.PeerReference, n, params_ptr); + return r; + } while (false); + } + } + finally { + GC.KeepAlive (self); + } + } + public unsafe char InvokeNonvirtualCharMethod (string encodedMember, IJavaPeerable self, JniArgumentValue* parameters) { JniPeerMembers.AssertSelf (self); @@ -365,6 +623,25 @@ public unsafe char InvokeNonvirtualCharMethod (string encodedMember, IJavaPeerab } } + public unsafe char InvokeNonvirtualCharMethod (JniMemberInfoLookup member, IJavaPeerable self, ReadOnlySpan parameters) + { + JniPeerMembers.AssertSelf (self); + + var m = GetMethodInfo (member); + try { + fixed (JniArgumentValue* params_ptr = &MemoryMarshal.GetReference (parameters)) { + if (TryInvokeCharStaticRedirect (m, self, params_ptr, out char r)) { + return r; + } + r = JniEnvironment.InstanceMethods.CallNonvirtualCharMethod (self.PeerReference, JniPeerType.PeerReference, m, params_ptr); + return r; + } + } + finally { + GC.KeepAlive (self); + } + } + #pragma warning disable CA1801 static unsafe bool TryInvokeInt16StaticRedirect (JniMethodInfo method, IJavaPeerable self, JniArgumentValue* parameters, out short r) { @@ -408,6 +685,25 @@ public unsafe short InvokeAbstractInt16Method (string encodedMember, IJavaPeerab } } + public unsafe short InvokeAbstractInt16Method (JniMemberInfoLookup member, IJavaPeerable self, ReadOnlySpan parameters) + { + JniPeerMembers.AssertSelf (self); + + try { + var m = GetMethodInfo (member); + fixed (JniArgumentValue* params_ptr = &MemoryMarshal.GetReference (parameters)) { + if (TryInvokeInt16StaticRedirect (m, self, params_ptr, out short r)) { + return r; + } + r = JniEnvironment.InstanceMethods.CallShortMethod (self.PeerReference, m, params_ptr); + return r; + } + } + finally { + GC.KeepAlive (self); + } + } + public unsafe short InvokeVirtualInt16Method (string encodedMember, IJavaPeerable self, JniArgumentValue* parameters) { JniPeerMembers.AssertSelf (self); @@ -437,6 +733,37 @@ public unsafe short InvokeVirtualInt16Method (string encodedMember, IJavaPeerabl } } + public unsafe short InvokeVirtualInt16Method (JniMemberInfoLookup member, IJavaPeerable self, ReadOnlySpan parameters) + { + JniPeerMembers.AssertSelf (self); + + try { + var declaringType = DeclaringType; + fixed (JniArgumentValue* params_ptr = &MemoryMarshal.GetReference (parameters)) { + if (Members.UsesVirtualDispatch (self, declaringType)) { + var m = GetMethodInfo (member); + if (TryInvokeInt16StaticRedirect (m, self, params_ptr, out short r)) { + return r; + } + r = JniEnvironment.InstanceMethods.CallShortMethod (self.PeerReference, m, params_ptr); + return r; + } + var j = Members.GetPeerMembers (self); + var n = j.InstanceMethods.GetMethodInfo (member); + do { + if (TryInvokeInt16StaticRedirect (n, self, params_ptr, out short r)) { + return r; + } + r = JniEnvironment.InstanceMethods.CallNonvirtualShortMethod (self.PeerReference, j.JniPeerType.PeerReference, n, params_ptr); + return r; + } while (false); + } + } + finally { + GC.KeepAlive (self); + } + } + public unsafe short InvokeNonvirtualInt16Method (string encodedMember, IJavaPeerable self, JniArgumentValue* parameters) { JniPeerMembers.AssertSelf (self); @@ -454,6 +781,25 @@ public unsafe short InvokeNonvirtualInt16Method (string encodedMember, IJavaPeer } } + public unsafe short InvokeNonvirtualInt16Method (JniMemberInfoLookup member, IJavaPeerable self, ReadOnlySpan parameters) + { + JniPeerMembers.AssertSelf (self); + + var m = GetMethodInfo (member); + try { + fixed (JniArgumentValue* params_ptr = &MemoryMarshal.GetReference (parameters)) { + if (TryInvokeInt16StaticRedirect (m, self, params_ptr, out short r)) { + return r; + } + r = JniEnvironment.InstanceMethods.CallNonvirtualShortMethod (self.PeerReference, JniPeerType.PeerReference, m, params_ptr); + return r; + } + } + finally { + GC.KeepAlive (self); + } + } + #pragma warning disable CA1801 static unsafe bool TryInvokeInt32StaticRedirect (JniMethodInfo method, IJavaPeerable self, JniArgumentValue* parameters, out int r) { @@ -497,6 +843,25 @@ public unsafe int InvokeAbstractInt32Method (string encodedMember, IJavaPeerable } } + public unsafe int InvokeAbstractInt32Method (JniMemberInfoLookup member, IJavaPeerable self, ReadOnlySpan parameters) + { + JniPeerMembers.AssertSelf (self); + + try { + var m = GetMethodInfo (member); + fixed (JniArgumentValue* params_ptr = &MemoryMarshal.GetReference (parameters)) { + if (TryInvokeInt32StaticRedirect (m, self, params_ptr, out int r)) { + return r; + } + r = JniEnvironment.InstanceMethods.CallIntMethod (self.PeerReference, m, params_ptr); + return r; + } + } + finally { + GC.KeepAlive (self); + } + } + public unsafe int InvokeVirtualInt32Method (string encodedMember, IJavaPeerable self, JniArgumentValue* parameters) { JniPeerMembers.AssertSelf (self); @@ -526,6 +891,37 @@ public unsafe int InvokeVirtualInt32Method (string encodedMember, IJavaPeerable } } + public unsafe int InvokeVirtualInt32Method (JniMemberInfoLookup member, IJavaPeerable self, ReadOnlySpan parameters) + { + JniPeerMembers.AssertSelf (self); + + try { + var declaringType = DeclaringType; + fixed (JniArgumentValue* params_ptr = &MemoryMarshal.GetReference (parameters)) { + if (Members.UsesVirtualDispatch (self, declaringType)) { + var m = GetMethodInfo (member); + if (TryInvokeInt32StaticRedirect (m, self, params_ptr, out int r)) { + return r; + } + r = JniEnvironment.InstanceMethods.CallIntMethod (self.PeerReference, m, params_ptr); + return r; + } + var j = Members.GetPeerMembers (self); + var n = j.InstanceMethods.GetMethodInfo (member); + do { + if (TryInvokeInt32StaticRedirect (n, self, params_ptr, out int r)) { + return r; + } + r = JniEnvironment.InstanceMethods.CallNonvirtualIntMethod (self.PeerReference, j.JniPeerType.PeerReference, n, params_ptr); + return r; + } while (false); + } + } + finally { + GC.KeepAlive (self); + } + } + public unsafe int InvokeNonvirtualInt32Method (string encodedMember, IJavaPeerable self, JniArgumentValue* parameters) { JniPeerMembers.AssertSelf (self); @@ -543,6 +939,25 @@ public unsafe int InvokeNonvirtualInt32Method (string encodedMember, IJavaPeerab } } + public unsafe int InvokeNonvirtualInt32Method (JniMemberInfoLookup member, IJavaPeerable self, ReadOnlySpan parameters) + { + JniPeerMembers.AssertSelf (self); + + var m = GetMethodInfo (member); + try { + fixed (JniArgumentValue* params_ptr = &MemoryMarshal.GetReference (parameters)) { + if (TryInvokeInt32StaticRedirect (m, self, params_ptr, out int r)) { + return r; + } + r = JniEnvironment.InstanceMethods.CallNonvirtualIntMethod (self.PeerReference, JniPeerType.PeerReference, m, params_ptr); + return r; + } + } + finally { + GC.KeepAlive (self); + } + } + #pragma warning disable CA1801 static unsafe bool TryInvokeInt64StaticRedirect (JniMethodInfo method, IJavaPeerable self, JniArgumentValue* parameters, out long r) { @@ -586,6 +1001,25 @@ public unsafe long InvokeAbstractInt64Method (string encodedMember, IJavaPeerabl } } + public unsafe long InvokeAbstractInt64Method (JniMemberInfoLookup member, IJavaPeerable self, ReadOnlySpan parameters) + { + JniPeerMembers.AssertSelf (self); + + try { + var m = GetMethodInfo (member); + fixed (JniArgumentValue* params_ptr = &MemoryMarshal.GetReference (parameters)) { + if (TryInvokeInt64StaticRedirect (m, self, params_ptr, out long r)) { + return r; + } + r = JniEnvironment.InstanceMethods.CallLongMethod (self.PeerReference, m, params_ptr); + return r; + } + } + finally { + GC.KeepAlive (self); + } + } + public unsafe long InvokeVirtualInt64Method (string encodedMember, IJavaPeerable self, JniArgumentValue* parameters) { JniPeerMembers.AssertSelf (self); @@ -615,6 +1049,37 @@ public unsafe long InvokeVirtualInt64Method (string encodedMember, IJavaPeerable } } + public unsafe long InvokeVirtualInt64Method (JniMemberInfoLookup member, IJavaPeerable self, ReadOnlySpan parameters) + { + JniPeerMembers.AssertSelf (self); + + try { + var declaringType = DeclaringType; + fixed (JniArgumentValue* params_ptr = &MemoryMarshal.GetReference (parameters)) { + if (Members.UsesVirtualDispatch (self, declaringType)) { + var m = GetMethodInfo (member); + if (TryInvokeInt64StaticRedirect (m, self, params_ptr, out long r)) { + return r; + } + r = JniEnvironment.InstanceMethods.CallLongMethod (self.PeerReference, m, params_ptr); + return r; + } + var j = Members.GetPeerMembers (self); + var n = j.InstanceMethods.GetMethodInfo (member); + do { + if (TryInvokeInt64StaticRedirect (n, self, params_ptr, out long r)) { + return r; + } + r = JniEnvironment.InstanceMethods.CallNonvirtualLongMethod (self.PeerReference, j.JniPeerType.PeerReference, n, params_ptr); + return r; + } while (false); + } + } + finally { + GC.KeepAlive (self); + } + } + public unsafe long InvokeNonvirtualInt64Method (string encodedMember, IJavaPeerable self, JniArgumentValue* parameters) { JniPeerMembers.AssertSelf (self); @@ -632,6 +1097,25 @@ public unsafe long InvokeNonvirtualInt64Method (string encodedMember, IJavaPeera } } + public unsafe long InvokeNonvirtualInt64Method (JniMemberInfoLookup member, IJavaPeerable self, ReadOnlySpan parameters) + { + JniPeerMembers.AssertSelf (self); + + var m = GetMethodInfo (member); + try { + fixed (JniArgumentValue* params_ptr = &MemoryMarshal.GetReference (parameters)) { + if (TryInvokeInt64StaticRedirect (m, self, params_ptr, out long r)) { + return r; + } + r = JniEnvironment.InstanceMethods.CallNonvirtualLongMethod (self.PeerReference, JniPeerType.PeerReference, m, params_ptr); + return r; + } + } + finally { + GC.KeepAlive (self); + } + } + #pragma warning disable CA1801 static unsafe bool TryInvokeSingleStaticRedirect (JniMethodInfo method, IJavaPeerable self, JniArgumentValue* parameters, out float r) { @@ -675,6 +1159,25 @@ public unsafe float InvokeAbstractSingleMethod (string encodedMember, IJavaPeera } } + public unsafe float InvokeAbstractSingleMethod (JniMemberInfoLookup member, IJavaPeerable self, ReadOnlySpan parameters) + { + JniPeerMembers.AssertSelf (self); + + try { + var m = GetMethodInfo (member); + fixed (JniArgumentValue* params_ptr = &MemoryMarshal.GetReference (parameters)) { + if (TryInvokeSingleStaticRedirect (m, self, params_ptr, out float r)) { + return r; + } + r = JniEnvironment.InstanceMethods.CallFloatMethod (self.PeerReference, m, params_ptr); + return r; + } + } + finally { + GC.KeepAlive (self); + } + } + public unsafe float InvokeVirtualSingleMethod (string encodedMember, IJavaPeerable self, JniArgumentValue* parameters) { JniPeerMembers.AssertSelf (self); @@ -704,6 +1207,37 @@ public unsafe float InvokeVirtualSingleMethod (string encodedMember, IJavaPeerab } } + public unsafe float InvokeVirtualSingleMethod (JniMemberInfoLookup member, IJavaPeerable self, ReadOnlySpan parameters) + { + JniPeerMembers.AssertSelf (self); + + try { + var declaringType = DeclaringType; + fixed (JniArgumentValue* params_ptr = &MemoryMarshal.GetReference (parameters)) { + if (Members.UsesVirtualDispatch (self, declaringType)) { + var m = GetMethodInfo (member); + if (TryInvokeSingleStaticRedirect (m, self, params_ptr, out float r)) { + return r; + } + r = JniEnvironment.InstanceMethods.CallFloatMethod (self.PeerReference, m, params_ptr); + return r; + } + var j = Members.GetPeerMembers (self); + var n = j.InstanceMethods.GetMethodInfo (member); + do { + if (TryInvokeSingleStaticRedirect (n, self, params_ptr, out float r)) { + return r; + } + r = JniEnvironment.InstanceMethods.CallNonvirtualFloatMethod (self.PeerReference, j.JniPeerType.PeerReference, n, params_ptr); + return r; + } while (false); + } + } + finally { + GC.KeepAlive (self); + } + } + public unsafe float InvokeNonvirtualSingleMethod (string encodedMember, IJavaPeerable self, JniArgumentValue* parameters) { JniPeerMembers.AssertSelf (self); @@ -721,6 +1255,25 @@ public unsafe float InvokeNonvirtualSingleMethod (string encodedMember, IJavaPee } } + public unsafe float InvokeNonvirtualSingleMethod (JniMemberInfoLookup member, IJavaPeerable self, ReadOnlySpan parameters) + { + JniPeerMembers.AssertSelf (self); + + var m = GetMethodInfo (member); + try { + fixed (JniArgumentValue* params_ptr = &MemoryMarshal.GetReference (parameters)) { + if (TryInvokeSingleStaticRedirect (m, self, params_ptr, out float r)) { + return r; + } + r = JniEnvironment.InstanceMethods.CallNonvirtualFloatMethod (self.PeerReference, JniPeerType.PeerReference, m, params_ptr); + return r; + } + } + finally { + GC.KeepAlive (self); + } + } + #pragma warning disable CA1801 static unsafe bool TryInvokeDoubleStaticRedirect (JniMethodInfo method, IJavaPeerable self, JniArgumentValue* parameters, out double r) { @@ -764,6 +1317,25 @@ public unsafe double InvokeAbstractDoubleMethod (string encodedMember, IJavaPeer } } + public unsafe double InvokeAbstractDoubleMethod (JniMemberInfoLookup member, IJavaPeerable self, ReadOnlySpan parameters) + { + JniPeerMembers.AssertSelf (self); + + try { + var m = GetMethodInfo (member); + fixed (JniArgumentValue* params_ptr = &MemoryMarshal.GetReference (parameters)) { + if (TryInvokeDoubleStaticRedirect (m, self, params_ptr, out double r)) { + return r; + } + r = JniEnvironment.InstanceMethods.CallDoubleMethod (self.PeerReference, m, params_ptr); + return r; + } + } + finally { + GC.KeepAlive (self); + } + } + public unsafe double InvokeVirtualDoubleMethod (string encodedMember, IJavaPeerable self, JniArgumentValue* parameters) { JniPeerMembers.AssertSelf (self); @@ -793,6 +1365,37 @@ public unsafe double InvokeVirtualDoubleMethod (string encodedMember, IJavaPeera } } + public unsafe double InvokeVirtualDoubleMethod (JniMemberInfoLookup member, IJavaPeerable self, ReadOnlySpan parameters) + { + JniPeerMembers.AssertSelf (self); + + try { + var declaringType = DeclaringType; + fixed (JniArgumentValue* params_ptr = &MemoryMarshal.GetReference (parameters)) { + if (Members.UsesVirtualDispatch (self, declaringType)) { + var m = GetMethodInfo (member); + if (TryInvokeDoubleStaticRedirect (m, self, params_ptr, out double r)) { + return r; + } + r = JniEnvironment.InstanceMethods.CallDoubleMethod (self.PeerReference, m, params_ptr); + return r; + } + var j = Members.GetPeerMembers (self); + var n = j.InstanceMethods.GetMethodInfo (member); + do { + if (TryInvokeDoubleStaticRedirect (n, self, params_ptr, out double r)) { + return r; + } + r = JniEnvironment.InstanceMethods.CallNonvirtualDoubleMethod (self.PeerReference, j.JniPeerType.PeerReference, n, params_ptr); + return r; + } while (false); + } + } + finally { + GC.KeepAlive (self); + } + } + public unsafe double InvokeNonvirtualDoubleMethod (string encodedMember, IJavaPeerable self, JniArgumentValue* parameters) { JniPeerMembers.AssertSelf (self); @@ -810,6 +1413,25 @@ public unsafe double InvokeNonvirtualDoubleMethod (string encodedMember, IJavaPe } } + public unsafe double InvokeNonvirtualDoubleMethod (JniMemberInfoLookup member, IJavaPeerable self, ReadOnlySpan parameters) + { + JniPeerMembers.AssertSelf (self); + + var m = GetMethodInfo (member); + try { + fixed (JniArgumentValue* params_ptr = &MemoryMarshal.GetReference (parameters)) { + if (TryInvokeDoubleStaticRedirect (m, self, params_ptr, out double r)) { + return r; + } + r = JniEnvironment.InstanceMethods.CallNonvirtualDoubleMethod (self.PeerReference, JniPeerType.PeerReference, m, params_ptr); + return r; + } + } + finally { + GC.KeepAlive (self); + } + } + #pragma warning disable CA1801 static unsafe bool TryInvokeObjectStaticRedirect (JniMethodInfo method, IJavaPeerable self, JniArgumentValue* parameters, out JniObjectReference r) { @@ -853,6 +1475,25 @@ public unsafe JniObjectReference InvokeAbstractObjectMethod (string encodedMembe } } + public unsafe JniObjectReference InvokeAbstractObjectMethod (JniMemberInfoLookup member, IJavaPeerable self, ReadOnlySpan parameters) + { + JniPeerMembers.AssertSelf (self); + + try { + var m = GetMethodInfo (member); + fixed (JniArgumentValue* params_ptr = &MemoryMarshal.GetReference (parameters)) { + if (TryInvokeObjectStaticRedirect (m, self, params_ptr, out JniObjectReference r)) { + return r; + } + r = JniEnvironment.InstanceMethods.CallObjectMethod (self.PeerReference, m, params_ptr); + return r; + } + } + finally { + GC.KeepAlive (self); + } + } + public unsafe JniObjectReference InvokeVirtualObjectMethod (string encodedMember, IJavaPeerable self, JniArgumentValue* parameters) { JniPeerMembers.AssertSelf (self); @@ -882,6 +1523,37 @@ public unsafe JniObjectReference InvokeVirtualObjectMethod (string encodedMember } } + public unsafe JniObjectReference InvokeVirtualObjectMethod (JniMemberInfoLookup member, IJavaPeerable self, ReadOnlySpan parameters) + { + JniPeerMembers.AssertSelf (self); + + try { + var declaringType = DeclaringType; + fixed (JniArgumentValue* params_ptr = &MemoryMarshal.GetReference (parameters)) { + if (Members.UsesVirtualDispatch (self, declaringType)) { + var m = GetMethodInfo (member); + if (TryInvokeObjectStaticRedirect (m, self, params_ptr, out JniObjectReference r)) { + return r; + } + r = JniEnvironment.InstanceMethods.CallObjectMethod (self.PeerReference, m, params_ptr); + return r; + } + var j = Members.GetPeerMembers (self); + var n = j.InstanceMethods.GetMethodInfo (member); + do { + if (TryInvokeObjectStaticRedirect (n, self, params_ptr, out JniObjectReference r)) { + return r; + } + r = JniEnvironment.InstanceMethods.CallNonvirtualObjectMethod (self.PeerReference, j.JniPeerType.PeerReference, n, params_ptr); + return r; + } while (false); + } + } + finally { + GC.KeepAlive (self); + } + } + public unsafe JniObjectReference InvokeNonvirtualObjectMethod (string encodedMember, IJavaPeerable self, JniArgumentValue* parameters) { JniPeerMembers.AssertSelf (self); @@ -898,6 +1570,25 @@ public unsafe JniObjectReference InvokeNonvirtualObjectMethod (string encodedMem GC.KeepAlive (self); } } + + public unsafe JniObjectReference InvokeNonvirtualObjectMethod (JniMemberInfoLookup member, IJavaPeerable self, ReadOnlySpan parameters) + { + JniPeerMembers.AssertSelf (self); + + var m = GetMethodInfo (member); + try { + fixed (JniArgumentValue* params_ptr = &MemoryMarshal.GetReference (parameters)) { + if (TryInvokeObjectStaticRedirect (m, self, params_ptr, out JniObjectReference r)) { + return r; + } + r = JniEnvironment.InstanceMethods.CallNonvirtualObjectMethod (self.PeerReference, JniPeerType.PeerReference, m, params_ptr); + 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 a326b6b1f..eb25f1b15 100644 --- a/src/Java.Interop/Java.Interop/JniPeerMembers.JniInstanceMethods_Invoke.tt +++ b/src/Java.Interop/Java.Interop/JniPeerMembers.JniInstanceMethods_Invoke.tt @@ -22,6 +22,7 @@ using System; using System.Diagnostics; +using System.Runtime.InteropServices; namespace Java.Interop { @@ -80,6 +81,25 @@ namespace Java.Interop { } } + public unsafe <#= returnType.ReturnType #> InvokeAbstract<#= returnType.ManagedType #>Method (JniMemberInfoLookup member, IJavaPeerable self, ReadOnlySpan parameters) + { + JniPeerMembers.AssertSelf (self); + + try { + var m = GetMethodInfo (member); + fixed (JniArgumentValue* params_ptr = &MemoryMarshal.GetReference (parameters)) { + if (TryInvoke<#= returnType.ManagedType #>StaticRedirect (m, self, params_ptr<#= byRefParamDecl #>)) { + <#= returnByRefParam #>; + } + <#= setByRefParam #>JniEnvironment.InstanceMethods.Call<#= returnType.JniCallType #>Method (self.PeerReference, m, params_ptr); + <#= returnByRefParam #>; + } + } + finally { + GC.KeepAlive (self); + } + } + public unsafe <#= returnType.ReturnType #> InvokeVirtual<#= returnType.ManagedType #>Method (string encodedMember, IJavaPeerable self, JniArgumentValue* parameters) { JniPeerMembers.AssertSelf (self); @@ -109,6 +129,37 @@ namespace Java.Interop { } } + public unsafe <#= returnType.ReturnType #> InvokeVirtual<#= returnType.ManagedType #>Method (JniMemberInfoLookup member, IJavaPeerable self, ReadOnlySpan parameters) + { + JniPeerMembers.AssertSelf (self); + + try { + var declaringType = DeclaringType; + fixed (JniArgumentValue* params_ptr = &MemoryMarshal.GetReference (parameters)) { + if (Members.UsesVirtualDispatch (self, declaringType)) { + var m = GetMethodInfo (member); + if (TryInvoke<#= returnType.ManagedType #>StaticRedirect (m, self, params_ptr<#= byRefParamDecl #>)) { + <#= returnByRefParam #>; + } + <#= setByRefParam #>JniEnvironment.InstanceMethods.Call<#= returnType.JniCallType #>Method (self.PeerReference, m, params_ptr); + <#= returnByRefParam #>; + } + var j = Members.GetPeerMembers (self); + var n = j.InstanceMethods.GetMethodInfo (member); + do { + if (TryInvoke<#= returnType.ManagedType #>StaticRedirect (n, self, params_ptr<#= byRefParamDecl #>)) { + <#= returnByRefParam #>; + } + <#= setByRefParam #>JniEnvironment.InstanceMethods.CallNonvirtual<#= returnType.JniCallType #>Method (self.PeerReference, j.JniPeerType.PeerReference, n, params_ptr); + <#= returnByRefParam #>; + } while (false); + } + } + finally { + GC.KeepAlive (self); + } + } + public unsafe <#= returnType.ReturnType #> InvokeNonvirtual<#= returnType.ManagedType #>Method (string encodedMember, IJavaPeerable self, JniArgumentValue* parameters) { JniPeerMembers.AssertSelf (self); @@ -125,6 +176,25 @@ namespace Java.Interop { GC.KeepAlive (self); } } + + public unsafe <#= returnType.ReturnType #> InvokeNonvirtual<#= returnType.ManagedType #>Method (JniMemberInfoLookup member, IJavaPeerable self, ReadOnlySpan parameters) + { + JniPeerMembers.AssertSelf (self); + + var m = GetMethodInfo (member); + try { + fixed (JniArgumentValue* params_ptr = &MemoryMarshal.GetReference (parameters)) { + if (TryInvoke<#= returnType.ManagedType #>StaticRedirect (m, self, params_ptr<#= byRefParamDecl #>)) { + <#= returnByRefParam #>; + } + <#= setByRefParam #>JniEnvironment.InstanceMethods.CallNonvirtual<#= returnType.JniCallType #>Method (self.PeerReference, JniPeerType.PeerReference, m, params_ptr); + <#= 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 84123874f..55373862a 100644 --- a/src/Java.Interop/Java.Interop/JniPeerMembers.JniStaticMethods.cs +++ b/src/Java.Interop/Java.Interop/JniPeerMembers.JniStaticMethods.cs @@ -2,6 +2,7 @@ using System; using System.Collections.Generic; +using System.Runtime.InteropServices; namespace Java.Interop { @@ -176,59 +177,139 @@ public unsafe void InvokeVoidMethod (string encodedMember, JniArgumentValue* par JniEnvironment.StaticMethods.CallStaticVoidMethod (GetMethodDeclaringType (m).PeerReference, m, parameters); } + public unsafe void InvokeVoidMethod (JniMemberInfoLookup member, ReadOnlySpan parameters) + { + var m = GetMethodInfo (member); + fixed (JniArgumentValue* params_ptr = &MemoryMarshal.GetReference (parameters)) { + JniEnvironment.StaticMethods.CallStaticVoidMethod (GetMethodDeclaringType (m).PeerReference, m, params_ptr); + } + } + public unsafe bool InvokeBooleanMethod (string encodedMember, JniArgumentValue* parameters) { var m = GetMethodInfo (encodedMember); return JniEnvironment.StaticMethods.CallStaticBooleanMethod (GetMethodDeclaringType (m).PeerReference, m, parameters); } + public unsafe bool InvokeBooleanMethod (JniMemberInfoLookup member, ReadOnlySpan parameters) + { + var m = GetMethodInfo (member); + fixed (JniArgumentValue* params_ptr = &MemoryMarshal.GetReference (parameters)) { + return JniEnvironment.StaticMethods.CallStaticBooleanMethod (GetMethodDeclaringType (m).PeerReference, m, params_ptr); + } + } + public unsafe sbyte InvokeSByteMethod (string encodedMember, JniArgumentValue* parameters) { var m = GetMethodInfo (encodedMember); return JniEnvironment.StaticMethods.CallStaticByteMethod (GetMethodDeclaringType (m).PeerReference, m, parameters); } + public unsafe sbyte InvokeSByteMethod (JniMemberInfoLookup member, ReadOnlySpan parameters) + { + var m = GetMethodInfo (member); + fixed (JniArgumentValue* params_ptr = &MemoryMarshal.GetReference (parameters)) { + return JniEnvironment.StaticMethods.CallStaticByteMethod (GetMethodDeclaringType (m).PeerReference, m, params_ptr); + } + } + public unsafe char InvokeCharMethod (string encodedMember, JniArgumentValue* parameters) { var m = GetMethodInfo (encodedMember); return JniEnvironment.StaticMethods.CallStaticCharMethod (GetMethodDeclaringType (m).PeerReference, m, parameters); } + public unsafe char InvokeCharMethod (JniMemberInfoLookup member, ReadOnlySpan parameters) + { + var m = GetMethodInfo (member); + fixed (JniArgumentValue* params_ptr = &MemoryMarshal.GetReference (parameters)) { + return JniEnvironment.StaticMethods.CallStaticCharMethod (GetMethodDeclaringType (m).PeerReference, m, params_ptr); + } + } + public unsafe short InvokeInt16Method (string encodedMember, JniArgumentValue* parameters) { var m = GetMethodInfo (encodedMember); return JniEnvironment.StaticMethods.CallStaticShortMethod (GetMethodDeclaringType (m).PeerReference, m, parameters); } + public unsafe short InvokeInt16Method (JniMemberInfoLookup member, ReadOnlySpan parameters) + { + var m = GetMethodInfo (member); + fixed (JniArgumentValue* params_ptr = &MemoryMarshal.GetReference (parameters)) { + return JniEnvironment.StaticMethods.CallStaticShortMethod (GetMethodDeclaringType (m).PeerReference, m, params_ptr); + } + } + public unsafe int InvokeInt32Method (string encodedMember, JniArgumentValue* parameters) { var m = GetMethodInfo (encodedMember); return JniEnvironment.StaticMethods.CallStaticIntMethod (GetMethodDeclaringType (m).PeerReference, m, parameters); } + public unsafe int InvokeInt32Method (JniMemberInfoLookup member, ReadOnlySpan parameters) + { + var m = GetMethodInfo (member); + fixed (JniArgumentValue* params_ptr = &MemoryMarshal.GetReference (parameters)) { + return JniEnvironment.StaticMethods.CallStaticIntMethod (GetMethodDeclaringType (m).PeerReference, m, params_ptr); + } + } + public unsafe long InvokeInt64Method (string encodedMember, JniArgumentValue* parameters) { var m = GetMethodInfo (encodedMember); return JniEnvironment.StaticMethods.CallStaticLongMethod (GetMethodDeclaringType (m).PeerReference, m, parameters); } + public unsafe long InvokeInt64Method (JniMemberInfoLookup member, ReadOnlySpan parameters) + { + var m = GetMethodInfo (member); + fixed (JniArgumentValue* params_ptr = &MemoryMarshal.GetReference (parameters)) { + return JniEnvironment.StaticMethods.CallStaticLongMethod (GetMethodDeclaringType (m).PeerReference, m, params_ptr); + } + } + public unsafe float InvokeSingleMethod (string encodedMember, JniArgumentValue* parameters) { var m = GetMethodInfo (encodedMember); return JniEnvironment.StaticMethods.CallStaticFloatMethod (GetMethodDeclaringType (m).PeerReference, m, parameters); } + public unsafe float InvokeSingleMethod (JniMemberInfoLookup member, ReadOnlySpan parameters) + { + var m = GetMethodInfo (member); + fixed (JniArgumentValue* params_ptr = &MemoryMarshal.GetReference (parameters)) { + return JniEnvironment.StaticMethods.CallStaticFloatMethod (GetMethodDeclaringType (m).PeerReference, m, params_ptr); + } + } + public unsafe double InvokeDoubleMethod (string encodedMember, JniArgumentValue* parameters) { var m = GetMethodInfo (encodedMember); return JniEnvironment.StaticMethods.CallStaticDoubleMethod (GetMethodDeclaringType (m).PeerReference, m, parameters); } + public unsafe double InvokeDoubleMethod (JniMemberInfoLookup member, ReadOnlySpan parameters) + { + var m = GetMethodInfo (member); + fixed (JniArgumentValue* params_ptr = &MemoryMarshal.GetReference (parameters)) { + return JniEnvironment.StaticMethods.CallStaticDoubleMethod (GetMethodDeclaringType (m).PeerReference, m, params_ptr); + } + } + public unsafe JniObjectReference InvokeObjectMethod (string encodedMember, JniArgumentValue* parameters) { var m = GetMethodInfo (encodedMember); return JniEnvironment.StaticMethods.CallStaticObjectMethod (GetMethodDeclaringType (m).PeerReference, m, parameters); } + + public unsafe JniObjectReference InvokeObjectMethod (JniMemberInfoLookup member, ReadOnlySpan parameters) + { + var m = GetMethodInfo (member); + fixed (JniArgumentValue* params_ptr = &MemoryMarshal.GetReference (parameters)) { + return JniEnvironment.StaticMethods.CallStaticObjectMethod (GetMethodDeclaringType (m).PeerReference, m, params_ptr); + } + } }} } diff --git a/src/Java.Interop/PublicAPI.Unshipped.txt b/src/Java.Interop/PublicAPI.Unshipped.txt index ef0e5e10a..ef04d6076 100644 --- a/src/Java.Interop/PublicAPI.Unshipped.txt +++ b/src/Java.Interop/PublicAPI.Unshipped.txt @@ -5,9 +5,75 @@ Java.Interop.JniMemberInfoLookup.JniMemberInfoLookup() -> void Java.Interop.JniMemberInfoLookup.JniMemberInfoLookup(string! encodedMember, System.ReadOnlySpan memberName, System.ReadOnlySpan memberSignature) -> void Java.Interop.JniMemberInfoLookup.MemberName.get -> System.ReadOnlySpan Java.Interop.JniMemberInfoLookup.MemberSignature.get -> System.ReadOnlySpan +Java.Interop.JniPeerMembers.JniInstanceFields.GetBooleanValue(Java.Interop.JniMemberInfoLookup member, Java.Interop.IJavaPeerable! self) -> bool +Java.Interop.JniPeerMembers.JniInstanceFields.GetCharValue(Java.Interop.JniMemberInfoLookup member, Java.Interop.IJavaPeerable! self) -> char +Java.Interop.JniPeerMembers.JniInstanceFields.GetDoubleValue(Java.Interop.JniMemberInfoLookup member, Java.Interop.IJavaPeerable! self) -> double Java.Interop.JniPeerMembers.JniInstanceFields.GetFieldInfo(Java.Interop.JniMemberInfoLookup member) -> Java.Interop.JniFieldInfo! +Java.Interop.JniPeerMembers.JniInstanceFields.GetInt16Value(Java.Interop.JniMemberInfoLookup member, Java.Interop.IJavaPeerable! self) -> short +Java.Interop.JniPeerMembers.JniInstanceFields.GetInt32Value(Java.Interop.JniMemberInfoLookup member, Java.Interop.IJavaPeerable! self) -> int +Java.Interop.JniPeerMembers.JniInstanceFields.GetInt64Value(Java.Interop.JniMemberInfoLookup member, Java.Interop.IJavaPeerable! self) -> long +Java.Interop.JniPeerMembers.JniInstanceFields.GetObjectValue(Java.Interop.JniMemberInfoLookup member, Java.Interop.IJavaPeerable! self) -> Java.Interop.JniObjectReference +Java.Interop.JniPeerMembers.JniInstanceFields.GetSByteValue(Java.Interop.JniMemberInfoLookup member, Java.Interop.IJavaPeerable! self) -> sbyte +Java.Interop.JniPeerMembers.JniInstanceFields.GetSingleValue(Java.Interop.JniMemberInfoLookup member, Java.Interop.IJavaPeerable! self) -> float +Java.Interop.JniPeerMembers.JniInstanceFields.SetValue(Java.Interop.JniMemberInfoLookup member, Java.Interop.IJavaPeerable! self, bool value) -> void +Java.Interop.JniPeerMembers.JniInstanceFields.SetValue(Java.Interop.JniMemberInfoLookup member, Java.Interop.IJavaPeerable! self, char value) -> void +Java.Interop.JniPeerMembers.JniInstanceFields.SetValue(Java.Interop.JniMemberInfoLookup member, Java.Interop.IJavaPeerable! self, double value) -> void +Java.Interop.JniPeerMembers.JniInstanceFields.SetValue(Java.Interop.JniMemberInfoLookup member, Java.Interop.IJavaPeerable! self, float value) -> void +Java.Interop.JniPeerMembers.JniInstanceFields.SetValue(Java.Interop.JniMemberInfoLookup member, Java.Interop.IJavaPeerable! self, int value) -> void +Java.Interop.JniPeerMembers.JniInstanceFields.SetValue(Java.Interop.JniMemberInfoLookup member, Java.Interop.IJavaPeerable! self, Java.Interop.JniObjectReference value) -> void +Java.Interop.JniPeerMembers.JniInstanceFields.SetValue(Java.Interop.JniMemberInfoLookup member, Java.Interop.IJavaPeerable! self, long value) -> void +Java.Interop.JniPeerMembers.JniInstanceFields.SetValue(Java.Interop.JniMemberInfoLookup member, Java.Interop.IJavaPeerable! self, sbyte value) -> void +Java.Interop.JniPeerMembers.JniInstanceFields.SetValue(Java.Interop.JniMemberInfoLookup member, Java.Interop.IJavaPeerable! self, short value) -> void Java.Interop.JniPeerMembers.JniInstanceMethods.GetMethodInfo(Java.Interop.JniMemberInfoLookup member) -> Java.Interop.JniMethodInfo! +Java.Interop.JniPeerMembers.JniInstanceMethods.InvokeAbstractBooleanMethod(Java.Interop.JniMemberInfoLookup member, Java.Interop.IJavaPeerable! self, System.ReadOnlySpan parameters) -> bool +Java.Interop.JniPeerMembers.JniInstanceMethods.InvokeAbstractCharMethod(Java.Interop.JniMemberInfoLookup member, Java.Interop.IJavaPeerable! self, System.ReadOnlySpan parameters) -> char +Java.Interop.JniPeerMembers.JniInstanceMethods.InvokeAbstractDoubleMethod(Java.Interop.JniMemberInfoLookup member, Java.Interop.IJavaPeerable! self, System.ReadOnlySpan parameters) -> double +Java.Interop.JniPeerMembers.JniInstanceMethods.InvokeAbstractInt16Method(Java.Interop.JniMemberInfoLookup member, Java.Interop.IJavaPeerable! self, System.ReadOnlySpan parameters) -> short +Java.Interop.JniPeerMembers.JniInstanceMethods.InvokeAbstractInt32Method(Java.Interop.JniMemberInfoLookup member, Java.Interop.IJavaPeerable! self, System.ReadOnlySpan parameters) -> int +Java.Interop.JniPeerMembers.JniInstanceMethods.InvokeAbstractInt64Method(Java.Interop.JniMemberInfoLookup member, Java.Interop.IJavaPeerable! self, System.ReadOnlySpan parameters) -> long +Java.Interop.JniPeerMembers.JniInstanceMethods.InvokeAbstractObjectMethod(Java.Interop.JniMemberInfoLookup member, Java.Interop.IJavaPeerable! self, System.ReadOnlySpan parameters) -> Java.Interop.JniObjectReference +Java.Interop.JniPeerMembers.JniInstanceMethods.InvokeAbstractSByteMethod(Java.Interop.JniMemberInfoLookup member, Java.Interop.IJavaPeerable! self, System.ReadOnlySpan parameters) -> sbyte +Java.Interop.JniPeerMembers.JniInstanceMethods.InvokeAbstractSingleMethod(Java.Interop.JniMemberInfoLookup member, Java.Interop.IJavaPeerable! self, System.ReadOnlySpan parameters) -> float +Java.Interop.JniPeerMembers.JniInstanceMethods.InvokeAbstractVoidMethod(Java.Interop.JniMemberInfoLookup member, Java.Interop.IJavaPeerable! self, System.ReadOnlySpan parameters) -> void +Java.Interop.JniPeerMembers.JniInstanceMethods.InvokeNonvirtualBooleanMethod(Java.Interop.JniMemberInfoLookup member, Java.Interop.IJavaPeerable! self, System.ReadOnlySpan parameters) -> bool +Java.Interop.JniPeerMembers.JniInstanceMethods.InvokeNonvirtualCharMethod(Java.Interop.JniMemberInfoLookup member, Java.Interop.IJavaPeerable! self, System.ReadOnlySpan parameters) -> char +Java.Interop.JniPeerMembers.JniInstanceMethods.InvokeNonvirtualDoubleMethod(Java.Interop.JniMemberInfoLookup member, Java.Interop.IJavaPeerable! self, System.ReadOnlySpan parameters) -> double +Java.Interop.JniPeerMembers.JniInstanceMethods.InvokeNonvirtualInt16Method(Java.Interop.JniMemberInfoLookup member, Java.Interop.IJavaPeerable! self, System.ReadOnlySpan parameters) -> short +Java.Interop.JniPeerMembers.JniInstanceMethods.InvokeNonvirtualInt32Method(Java.Interop.JniMemberInfoLookup member, Java.Interop.IJavaPeerable! self, System.ReadOnlySpan parameters) -> int +Java.Interop.JniPeerMembers.JniInstanceMethods.InvokeNonvirtualInt64Method(Java.Interop.JniMemberInfoLookup member, Java.Interop.IJavaPeerable! self, System.ReadOnlySpan parameters) -> long +Java.Interop.JniPeerMembers.JniInstanceMethods.InvokeNonvirtualObjectMethod(Java.Interop.JniMemberInfoLookup member, Java.Interop.IJavaPeerable! self, System.ReadOnlySpan parameters) -> Java.Interop.JniObjectReference +Java.Interop.JniPeerMembers.JniInstanceMethods.InvokeNonvirtualSByteMethod(Java.Interop.JniMemberInfoLookup member, Java.Interop.IJavaPeerable! self, System.ReadOnlySpan parameters) -> sbyte +Java.Interop.JniPeerMembers.JniInstanceMethods.InvokeNonvirtualSingleMethod(Java.Interop.JniMemberInfoLookup member, Java.Interop.IJavaPeerable! self, System.ReadOnlySpan parameters) -> float +Java.Interop.JniPeerMembers.JniInstanceMethods.InvokeNonvirtualVoidMethod(Java.Interop.JniMemberInfoLookup member, Java.Interop.IJavaPeerable! self, System.ReadOnlySpan parameters) -> void +Java.Interop.JniPeerMembers.JniInstanceMethods.InvokeVirtualBooleanMethod(Java.Interop.JniMemberInfoLookup member, Java.Interop.IJavaPeerable! self, System.ReadOnlySpan parameters) -> bool +Java.Interop.JniPeerMembers.JniInstanceMethods.InvokeVirtualCharMethod(Java.Interop.JniMemberInfoLookup member, Java.Interop.IJavaPeerable! self, System.ReadOnlySpan parameters) -> char +Java.Interop.JniPeerMembers.JniInstanceMethods.InvokeVirtualDoubleMethod(Java.Interop.JniMemberInfoLookup member, Java.Interop.IJavaPeerable! self, System.ReadOnlySpan parameters) -> double +Java.Interop.JniPeerMembers.JniInstanceMethods.InvokeVirtualInt16Method(Java.Interop.JniMemberInfoLookup member, Java.Interop.IJavaPeerable! self, System.ReadOnlySpan parameters) -> short +Java.Interop.JniPeerMembers.JniInstanceMethods.InvokeVirtualInt32Method(Java.Interop.JniMemberInfoLookup member, Java.Interop.IJavaPeerable! self, System.ReadOnlySpan parameters) -> int +Java.Interop.JniPeerMembers.JniInstanceMethods.InvokeVirtualInt64Method(Java.Interop.JniMemberInfoLookup member, Java.Interop.IJavaPeerable! self, System.ReadOnlySpan parameters) -> long +Java.Interop.JniPeerMembers.JniInstanceMethods.InvokeVirtualObjectMethod(Java.Interop.JniMemberInfoLookup member, Java.Interop.IJavaPeerable! self, System.ReadOnlySpan parameters) -> Java.Interop.JniObjectReference +Java.Interop.JniPeerMembers.JniInstanceMethods.InvokeVirtualSByteMethod(Java.Interop.JniMemberInfoLookup member, Java.Interop.IJavaPeerable! self, System.ReadOnlySpan parameters) -> sbyte +Java.Interop.JniPeerMembers.JniInstanceMethods.InvokeVirtualSingleMethod(Java.Interop.JniMemberInfoLookup member, Java.Interop.IJavaPeerable! self, System.ReadOnlySpan parameters) -> float +Java.Interop.JniPeerMembers.JniInstanceMethods.InvokeVirtualVoidMethod(Java.Interop.JniMemberInfoLookup member, Java.Interop.IJavaPeerable! self, System.ReadOnlySpan parameters) -> void +Java.Interop.JniPeerMembers.JniStaticFields.GetBooleanValue(Java.Interop.JniMemberInfoLookup member) -> bool +Java.Interop.JniPeerMembers.JniStaticFields.GetCharValue(Java.Interop.JniMemberInfoLookup member) -> char +Java.Interop.JniPeerMembers.JniStaticFields.GetDoubleValue(Java.Interop.JniMemberInfoLookup member) -> double Java.Interop.JniPeerMembers.JniStaticFields.GetFieldInfo(Java.Interop.JniMemberInfoLookup member) -> Java.Interop.JniFieldInfo! +Java.Interop.JniPeerMembers.JniStaticFields.GetInt16Value(Java.Interop.JniMemberInfoLookup member) -> short +Java.Interop.JniPeerMembers.JniStaticFields.GetInt32Value(Java.Interop.JniMemberInfoLookup member) -> int +Java.Interop.JniPeerMembers.JniStaticFields.GetInt64Value(Java.Interop.JniMemberInfoLookup member) -> long +Java.Interop.JniPeerMembers.JniStaticFields.GetObjectValue(Java.Interop.JniMemberInfoLookup member) -> Java.Interop.JniObjectReference +Java.Interop.JniPeerMembers.JniStaticFields.GetSByteValue(Java.Interop.JniMemberInfoLookup member) -> sbyte +Java.Interop.JniPeerMembers.JniStaticFields.GetSingleValue(Java.Interop.JniMemberInfoLookup member) -> float +Java.Interop.JniPeerMembers.JniStaticFields.SetValue(Java.Interop.JniMemberInfoLookup member, bool value) -> void +Java.Interop.JniPeerMembers.JniStaticFields.SetValue(Java.Interop.JniMemberInfoLookup member, char value) -> void +Java.Interop.JniPeerMembers.JniStaticFields.SetValue(Java.Interop.JniMemberInfoLookup member, double value) -> void +Java.Interop.JniPeerMembers.JniStaticFields.SetValue(Java.Interop.JniMemberInfoLookup member, float value) -> void +Java.Interop.JniPeerMembers.JniStaticFields.SetValue(Java.Interop.JniMemberInfoLookup member, int value) -> void +Java.Interop.JniPeerMembers.JniStaticFields.SetValue(Java.Interop.JniMemberInfoLookup member, Java.Interop.JniObjectReference value) -> void +Java.Interop.JniPeerMembers.JniStaticFields.SetValue(Java.Interop.JniMemberInfoLookup member, long value) -> void +Java.Interop.JniPeerMembers.JniStaticFields.SetValue(Java.Interop.JniMemberInfoLookup member, sbyte value) -> void +Java.Interop.JniPeerMembers.JniStaticFields.SetValue(Java.Interop.JniMemberInfoLookup member, short value) -> void Java.Interop.JniPeerMembers.JniStaticMethods.GetMethodInfo(Java.Interop.JniMemberInfoLookup member) -> Java.Interop.JniMethodInfo! Java.Interop.JniRuntime.JniTypeManager.GetReplacementMethodInfo(string! jniSimpleReference, System.ReadOnlySpan jniMethodName, System.ReadOnlySpan jniMethodSignature) -> Java.Interop.JniRuntime.ReplacementMethodInfo? Java.Interop.JniType.GetCachedInstanceField(ref Java.Interop.JniFieldInfo? cachedField, System.ReadOnlySpan name, System.ReadOnlySpan signature) -> Java.Interop.JniFieldInfo! @@ -22,4 +88,14 @@ static Java.Interop.JniEnvironment.InstanceFields.GetFieldID(Java.Interop.JniObj static Java.Interop.JniEnvironment.InstanceMethods.GetMethodID(Java.Interop.JniObjectReference type, System.ReadOnlySpan name, System.ReadOnlySpan signature) -> Java.Interop.JniMethodInfo! static Java.Interop.JniEnvironment.StaticFields.GetStaticFieldID(Java.Interop.JniObjectReference type, System.ReadOnlySpan name, System.ReadOnlySpan signature) -> Java.Interop.JniFieldInfo! static Java.Interop.JniEnvironment.StaticMethods.GetStaticMethodID(Java.Interop.JniObjectReference type, System.ReadOnlySpan name, System.ReadOnlySpan signature) -> Java.Interop.JniMethodInfo! +Java.Interop.JniPeerMembers.JniStaticMethods.InvokeBooleanMethod(Java.Interop.JniMemberInfoLookup member, System.ReadOnlySpan parameters) -> bool +Java.Interop.JniPeerMembers.JniStaticMethods.InvokeCharMethod(Java.Interop.JniMemberInfoLookup member, System.ReadOnlySpan parameters) -> char +Java.Interop.JniPeerMembers.JniStaticMethods.InvokeDoubleMethod(Java.Interop.JniMemberInfoLookup member, System.ReadOnlySpan parameters) -> double +Java.Interop.JniPeerMembers.JniStaticMethods.InvokeInt16Method(Java.Interop.JniMemberInfoLookup member, System.ReadOnlySpan parameters) -> short +Java.Interop.JniPeerMembers.JniStaticMethods.InvokeInt32Method(Java.Interop.JniMemberInfoLookup member, System.ReadOnlySpan parameters) -> int +Java.Interop.JniPeerMembers.JniStaticMethods.InvokeInt64Method(Java.Interop.JniMemberInfoLookup member, System.ReadOnlySpan parameters) -> long +Java.Interop.JniPeerMembers.JniStaticMethods.InvokeObjectMethod(Java.Interop.JniMemberInfoLookup member, System.ReadOnlySpan parameters) -> Java.Interop.JniObjectReference +Java.Interop.JniPeerMembers.JniStaticMethods.InvokeSByteMethod(Java.Interop.JniMemberInfoLookup member, System.ReadOnlySpan parameters) -> sbyte +Java.Interop.JniPeerMembers.JniStaticMethods.InvokeSingleMethod(Java.Interop.JniMemberInfoLookup member, System.ReadOnlySpan parameters) -> float +Java.Interop.JniPeerMembers.JniStaticMethods.InvokeVoidMethod(Java.Interop.JniMemberInfoLookup member, System.ReadOnlySpan parameters) -> void virtual Java.Interop.JniRuntime.JniTypeManager.GetReplacementMethodInfoCore(string! jniSimpleReference, System.ReadOnlySpan jniMethodName, System.ReadOnlySpan jniMethodSignature) -> Java.Interop.JniRuntime.ReplacementMethodInfo? From 840f04a4f4d7375a44f3a935901429c24f92c8ae Mon Sep 17 00:00:00 2001 From: Jonathan Pryor Date: Tue, 9 Jul 2024 07:02:57 -0400 Subject: [PATCH 6/6] JniMemberInfoLookup timing Commit d1a9951e showed that *for just field lookup*, the idea of a `ref struct JniMemberInfoLookup` *might* be a good idea. Now that we've expanded `JniMemberInfoLookup` plumbing to include *method* lookup, we can throw it into `TimingTests.cs` and see how it compares! The answer is that `ref struct`s and `Span` are *not* magical performance sauce with magical JIT support, and this is with CoreCLR! Method Lookup + Invoke Timing: Traditional: 00:00:00.0175778 No caching: 00:00:00.0202369 Dict w/ lock: 00:00:00.0181357 ConcurrentDict: 00:00:00.0220411 JniPeerMembers: 00:00:00.0209174 JPM+Lookup: 00:00:00.0186421 (I)I virtual+traditional: 00:00:00.0000600 (I)I virtual+JniPeerMembers: 00:00:00.0000588 (I)I virtual+JPM+Lookup: 00:00:00.0007137 The new timings are `JPM+Lookup` and `virtual+JPM+Lookup`. // JniPeerMembers return _members.InstanceMethods.InvokeVirtualObjectMethod("toString.()Ljava/lang/String;", this, null); // JPM+Lookup var member = new JniMemberInfoLookup("toString.()Ljava/lang/String;", "toString"u8, "()Ljava/lang/String;"u8); ReadOnlySpan args = null; return _members.InstanceMethods.InvokeVirtualObjectMethod (member, this, args); We see that JPM+Lookup is 11% *faster* when no arguments are involved. Nice! Throw an argument into the mix: // (I)I virtual+JniPeerMembers var args = stackalloc JniArgumentValue [1]; args [0] = new JniArgumentValue (value); return _members.InstanceMethods.InvokeVirtualInt32Method ("VirtualIntMethod1Args.(I)I", this, args); // (I)I virtual+JPM+Lookup var member = new JniMemberInfoLookup ( "VirtualIntMethod1Args.(I)I", "VirtualIntMethod1Args"u8, "(I)I"u8 ); var args = stackalloc JniArgumentValue [1]; args [0] = new JniArgumentValue (value); return _members.InstanceMethods.InvokeVirtualInt32Method (member, this, new ReadOnlySpan (args, 1)); and we're now a *whole order of magnitude worse*, taking 12.1x longer. Which quickly makes this idea as-is unworkable. Maybe it's the ReadOnlySpan usage, and if I went back to straight `JniArgumentValue*` values it would be better? --- .../Java.Interop-PerformanceTests.targets | 2 +- .../Java.Interop/JavaTiming.cs | 24 +++++++++++++++++++ .../Java.Interop/TimingTests.cs | 14 +++++++++++ 3 files changed, 39 insertions(+), 1 deletion(-) diff --git a/tests/Java.Interop-PerformanceTests/Java.Interop-PerformanceTests.targets b/tests/Java.Interop-PerformanceTests/Java.Interop-PerformanceTests.targets index f3866e5d6..1f4b9340d 100644 --- a/tests/Java.Interop-PerformanceTests/Java.Interop-PerformanceTests.targets +++ b/tests/Java.Interop-PerformanceTests/Java.Interop-PerformanceTests.targets @@ -4,7 +4,7 @@ BeforeTargets="BeforeBuild" Inputs="@(JavaPerformanceTestJar)" Outputs="$(OutputPath)performance-test.jar"> - + diff --git a/tests/Java.Interop-PerformanceTests/Java.Interop/JavaTiming.cs b/tests/Java.Interop-PerformanceTests/Java.Interop/JavaTiming.cs index a4104ac70..28f903c09 100644 --- a/tests/Java.Interop-PerformanceTests/Java.Interop/JavaTiming.cs +++ b/tests/Java.Interop-PerformanceTests/Java.Interop/JavaTiming.cs @@ -128,6 +128,19 @@ public virtual unsafe int Timing_VirtualIntMethod_Marshal1Args (int value) return _members.InstanceMethods.InvokeVirtualInt32Method ("VirtualIntMethod1Args.(I)I", this, args); } + public virtual unsafe int Timing_Lookup_VirtualIntMethod_Marshal1Args (int value) + { + var member = new JniMemberInfoLookup ( + "VirtualIntMethod1Args.(I)I", + "VirtualIntMethod1Args"u8, + "(I)I"u8 + ); + var args = stackalloc JniArgumentValue [1]; + args [0] = new JniArgumentValue (value); + + return _members.InstanceMethods.InvokeVirtualInt32Method (member, this, new ReadOnlySpan (args, 1)); + } + public virtual int Timing_VirtualIntMethod_GenericMarshal1Args (int value) { return _members.InstanceMethods.InvokeGenericVirtualInt32Method ("VirtualIntMethod1Args.(I)I", this, value); @@ -277,6 +290,17 @@ public unsafe JniObjectReference Timing_ToString_JniPeerMembers () return _members.InstanceMethods.InvokeVirtualObjectMethod (id, this, null); } + public JniObjectReference Timing_ToString_JniPeerMembers_Lookup () + { + var member = new JniMemberInfoLookup ( + toString_name + "." + toString_sig, + "toString"u8, + "()Ljava/lang/String;"u8 + ); + ReadOnlySpan args = null; + return _members.InstanceMethods.InvokeVirtualObjectMethod (member, this, args); + } + public static unsafe JniObjectReference CreateRunnable () { return _members.StaticMethods.InvokeObjectMethod ("CreateRunnable.()Ljava/lang/Runnable;", null); diff --git a/tests/Java.Interop-PerformanceTests/Java.Interop/TimingTests.cs b/tests/Java.Interop-PerformanceTests/Java.Interop/TimingTests.cs index e7f275580..36496d2a6 100644 --- a/tests/Java.Interop-PerformanceTests/Java.Interop/TimingTests.cs +++ b/tests/Java.Interop-PerformanceTests/Java.Interop/TimingTests.cs @@ -357,6 +357,12 @@ public void MethodLookupTiming () } tp.Stop (); + var tl = Stopwatch.StartNew (); + for (int i = 0; i < count; ++i) { + var s = o.Timing_ToString_JniPeerMembers_Lookup (); + JniObjectReference.Dispose (ref s); + } + tl.Stop (); var vtt = Stopwatch.StartNew (); for (int i = 0; i < count; ++i) { @@ -370,6 +376,12 @@ public void MethodLookupTiming () } vti.Stop (); + var vtl = Stopwatch.StartNew (); + for (int i = 0; i < count; ++i) { + o.Timing_Lookup_VirtualIntMethod_Marshal1Args (i); + } + vtl.Stop (); + Console.WriteLine ("Method Lookup + Invoke Timing:"); Console.WriteLine ("\t Traditional: {0}", tt.Elapsed); @@ -377,9 +389,11 @@ public void MethodLookupTiming () Console.WriteLine ("\t Dict w/ lock: {0}", td.Elapsed); Console.WriteLine ("\tConcurrentDict: {0}", tc.Elapsed); Console.WriteLine ("\tJniPeerMembers: {0}", tp.Elapsed); + Console.WriteLine ("\t JPM+Lookup: {0}", tl.Elapsed); Console.WriteLine (); Console.WriteLine ("\t (I)I virtual+traditional: {0}", vtt.Elapsed); Console.WriteLine ("\t (I)I virtual+JniPeerMembers: {0}", vti.Elapsed); + Console.WriteLine ("\t (I)I virtual+JPM+Lookup: {0}", vtl.Elapsed); } using (var o = new DerivedJavaTiming ()) { var ntt = Stopwatch.StartNew ();