Skip to content

Commit

Permalink
[Java.Interop] JniTypeManager optimizations (#582)
Browse files Browse the repository at this point in the history
Replace the `JniRuntime.JniBuiltinArrayMappings` field and its
associated `Lazy<T>` initializer with new methods
`JniRuntime.GetBuiltInTypeArraySignature()` and
`JniRuntime.GetBuiltInTypeSignature()`, which removes an array
initialization from the `JniRuntime` static constructor and an array
iteration from `JniRuntime.JniTypeManager.GetTypeSignature()`.
Additionally, use `Type.GetTypeCode(Type)` to more quickly map
builtin types such as `string` to `java/lang/String`.

Additionally, add a new
`JniRuntime.CreationOptions.JniAddNativeMethodRegistrationAttributePresent`
property which controls whether or not
`JniRuntime.JniTypeManager.TryRegisterNativeMembers()` attempts to
look for the `[JniAddNativeMethodRegistration]` custom attribute on
methods.  This is a seldom used attribute, and if no types in the app
use the attribute, this can save precious startup time by removing
the `method.GetCustomAttribute()` calls.

These changes together improve Xamarin.Android startup time, saving
~262ms:

  * Before:

        Total(ms) Self(ms)      Calls Method name
              344        9        199 Java.Interop.JniRuntime/JniTypeManager:GetTypeSignature (System.Type)

  * After:

        Total(ms) Self(ms)      Calls Method name
               82        9        199 Java.Interop.JniRuntime/JniTypeManager:GetTypeSignature (System.Type)
  • Loading branch information
grendello authored Mar 3, 2020
1 parent 28b1fc9 commit b33d183
Show file tree
Hide file tree
Showing 8 changed files with 289 additions and 103 deletions.
2 changes: 1 addition & 1 deletion src/Java.Interop/.editorconfig
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,6 @@ dotnet_diagnostic.CA1408.severity = error
dotnet_diagnostic.CA1412.severity = error
dotnet_diagnostic.CA1410.severity = error
dotnet_diagnostic.CA1411.severity = error
dotnet_diagnostic.CA1502.severity = error
dotnet_diagnostic.CA1501.severity = error
dotnet_diagnostic.CA1011.severity = error
dotnet_diagnostic.CA1504.severity = error
Expand Down Expand Up @@ -154,5 +153,6 @@ dotnet_diagnostic.CA1062.severity = none # Validate arguments of public methods
dotnet_diagnostic.CA1063.severity = none # Implement IDisposable correctly
dotnet_diagnostic.CA1303.severity = none # Do not pass literals as localized parameters
dotnet_diagnostic.CA1305.severity = none # Specify IFormatProvider
dotnet_diagnostic.CA1502.severity = none # 'Method' has a cyclomatic complexity of 'XX'. Rewrite or refactor the code to decrease its complexity below 'YY'.
dotnet_diagnostic.CA1810.severity = none # Initialize reference type static fields inline
dotnet_diagnostic.CA1816.severity = none # Call GC.SuppressFinalize correctly
66 changes: 44 additions & 22 deletions src/Java.Interop/Java.Interop/JavaPrimitiveArrays.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,28 +11,50 @@
namespace Java.Interop {

partial class JniRuntime {
static readonly Lazy<KeyValuePair<Type, JniTypeSignature>[]> JniBuiltinArrayMappings = new Lazy<KeyValuePair<Type, JniTypeSignature>[]> (InitJniBuiltinArrayMappings);

static KeyValuePair<Type, JniTypeSignature>[] InitJniBuiltinArrayMappings ()
{
return new[] {
new KeyValuePair<Type, JniTypeSignature>(typeof (JavaPrimitiveArray<Boolean>), new JniTypeSignature ("Z", arrayRank: 1, keyword: true)),
new KeyValuePair<Type, JniTypeSignature>(typeof (JavaArray<Boolean>), new JniTypeSignature ("Z", arrayRank: 1, keyword: true)),
new KeyValuePair<Type, JniTypeSignature>(typeof (JavaPrimitiveArray<SByte>), new JniTypeSignature ("B", arrayRank: 1, keyword: true)),
new KeyValuePair<Type, JniTypeSignature>(typeof (JavaArray<SByte>), new JniTypeSignature ("B", arrayRank: 1, keyword: true)),
new KeyValuePair<Type, JniTypeSignature>(typeof (JavaPrimitiveArray<Char>), new JniTypeSignature ("C", arrayRank: 1, keyword: true)),
new KeyValuePair<Type, JniTypeSignature>(typeof (JavaArray<Char>), new JniTypeSignature ("C", arrayRank: 1, keyword: true)),
new KeyValuePair<Type, JniTypeSignature>(typeof (JavaPrimitiveArray<Int16>), new JniTypeSignature ("S", arrayRank: 1, keyword: true)),
new KeyValuePair<Type, JniTypeSignature>(typeof (JavaArray<Int16>), new JniTypeSignature ("S", arrayRank: 1, keyword: true)),
new KeyValuePair<Type, JniTypeSignature>(typeof (JavaPrimitiveArray<Int32>), new JniTypeSignature ("I", arrayRank: 1, keyword: true)),
new KeyValuePair<Type, JniTypeSignature>(typeof (JavaArray<Int32>), new JniTypeSignature ("I", arrayRank: 1, keyword: true)),
new KeyValuePair<Type, JniTypeSignature>(typeof (JavaPrimitiveArray<Int64>), new JniTypeSignature ("J", arrayRank: 1, keyword: true)),
new KeyValuePair<Type, JniTypeSignature>(typeof (JavaArray<Int64>), new JniTypeSignature ("J", arrayRank: 1, keyword: true)),
new KeyValuePair<Type, JniTypeSignature>(typeof (JavaPrimitiveArray<Single>), new JniTypeSignature ("F", arrayRank: 1, keyword: true)),
new KeyValuePair<Type, JniTypeSignature>(typeof (JavaArray<Single>), new JniTypeSignature ("F", arrayRank: 1, keyword: true)),
new KeyValuePair<Type, JniTypeSignature>(typeof (JavaPrimitiveArray<Double>), new JniTypeSignature ("D", arrayRank: 1, keyword: true)),
new KeyValuePair<Type, JniTypeSignature>(typeof (JavaArray<Double>), new JniTypeSignature ("D", arrayRank: 1, keyword: true)),
};
static JniTypeSignature __BooleanTypeArraySignature;
static JniTypeSignature __SByteTypeArraySignature;
static JniTypeSignature __CharTypeArraySignature;
static JniTypeSignature __Int16TypeArraySignature;
static JniTypeSignature __Int32TypeArraySignature;
static JniTypeSignature __Int64TypeArraySignature;
static JniTypeSignature __SingleTypeArraySignature;
static JniTypeSignature __DoubleTypeArraySignature;

static bool GetBuiltInTypeArraySignature (Type type, ref JniTypeSignature signature)
{
if (type == typeof (JavaArray<Boolean>) || type == typeof (JavaPrimitiveArray<Boolean>)) {
signature = GetCachedTypeSignature (ref __BooleanTypeArraySignature, "Z", arrayRank: 1, keyword: true);
return true;
}
if (type == typeof (JavaArray<SByte>) || type == typeof (JavaPrimitiveArray<SByte>)) {
signature = GetCachedTypeSignature (ref __SByteTypeArraySignature, "B", arrayRank: 1, keyword: true);
return true;
}
if (type == typeof (JavaArray<Char>) || type == typeof (JavaPrimitiveArray<Char>)) {
signature = GetCachedTypeSignature (ref __CharTypeArraySignature, "C", arrayRank: 1, keyword: true);
return true;
}
if (type == typeof (JavaArray<Int16>) || type == typeof (JavaPrimitiveArray<Int16>)) {
signature = GetCachedTypeSignature (ref __Int16TypeArraySignature, "S", arrayRank: 1, keyword: true);
return true;
}
if (type == typeof (JavaArray<Int32>) || type == typeof (JavaPrimitiveArray<Int32>)) {
signature = GetCachedTypeSignature (ref __Int32TypeArraySignature, "I", arrayRank: 1, keyword: true);
return true;
}
if (type == typeof (JavaArray<Int64>) || type == typeof (JavaPrimitiveArray<Int64>)) {
signature = GetCachedTypeSignature (ref __Int64TypeArraySignature, "J", arrayRank: 1, keyword: true);
return true;
}
if (type == typeof (JavaArray<Single>) || type == typeof (JavaPrimitiveArray<Single>)) {
signature = GetCachedTypeSignature (ref __SingleTypeArraySignature, "F", arrayRank: 1, keyword: true);
return true;
}
if (type == typeof (JavaArray<Double>) || type == typeof (JavaPrimitiveArray<Double>)) {
signature = GetCachedTypeSignature (ref __DoubleTypeArraySignature, "D", arrayRank: 1, keyword: true);
return true;
}
return false;
}

static readonly Lazy<KeyValuePair<Type, JniValueMarshaler>[]> JniPrimitiveArrayMarshalers = new Lazy<KeyValuePair<Type, JniValueMarshaler>[]> (InitJniPrimitiveArrayMarshalers);
Expand Down
19 changes: 13 additions & 6 deletions src/Java.Interop/Java.Interop/JavaPrimitiveArrays.tt
Original file line number Diff line number Diff line change
Expand Up @@ -28,20 +28,27 @@ namespace Java.Interop {
};
#>
partial class JniRuntime {
static readonly Lazy<KeyValuePair<Type, JniTypeSignature>[]> JniBuiltinArrayMappings = new Lazy<KeyValuePair<Type, JniTypeSignature>[]> (InitJniBuiltinArrayMappings);
<#
foreach (var type in arrayTypeInfo) {
#>
static JniTypeSignature __<#= type.ManagedType #>TypeArraySignature;
<#
}
#>

static KeyValuePair<Type, JniTypeSignature>[] InitJniBuiltinArrayMappings ()
static bool GetBuiltInTypeArraySignature (Type type, ref JniTypeSignature signature)
{
return new[] {
<#
foreach (var info in arrayTypeInfo) {
#>
new KeyValuePair<Type, JniTypeSignature>(typeof (JavaPrimitiveArray<<#= info.ManagedType #>>), new JniTypeSignature ("<#= info.JniType #>", arrayRank: 1, keyword: true)),
new KeyValuePair<Type, JniTypeSignature>(typeof (JavaArray<<#= info.ManagedType #>>), new JniTypeSignature ("<#= info.JniType #>", arrayRank: 1, keyword: true)),
if (type == typeof (JavaArray<<#= info.ManagedType #>>) || type == typeof (JavaPrimitiveArray<<#= info.ManagedType #>>)) {
signature = GetCachedTypeSignature (ref __<#= info.ManagedType #>TypeArraySignature, "<#= info.JniType #>", arrayRank: 1, keyword: true);
return true;
}
<#
}
#>
};
return false;
}

static readonly Lazy<KeyValuePair<Type, JniValueMarshaler>[]> JniPrimitiveArrayMarshalers = new Lazy<KeyValuePair<Type, JniValueMarshaler>[]> (InitJniPrimitiveArrayMarshalers);
Expand Down
160 changes: 134 additions & 26 deletions src/Java.Interop/Java.Interop/JniBuiltinMarshalers.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

using System;
using System.Collections.Generic;
using System.Runtime.CompilerServices;
using System.Diagnostics;
using System.Linq.Expressions;
using System.Reflection;
Expand All @@ -11,34 +12,141 @@
namespace Java.Interop {

partial class JniRuntime {
static JniTypeSignature __StringTypeSignature;
static JniTypeSignature __VoidTypeSignature;
static JniTypeSignature __BooleanTypeSignature;
static JniTypeSignature __BooleanNullableTypeSignature;
static JniTypeSignature __SByteTypeSignature;
static JniTypeSignature __SByteNullableTypeSignature;
static JniTypeSignature __CharTypeSignature;
static JniTypeSignature __CharNullableTypeSignature;
static JniTypeSignature __Int16TypeSignature;
static JniTypeSignature __Int16NullableTypeSignature;
static JniTypeSignature __Int32TypeSignature;
static JniTypeSignature __Int32NullableTypeSignature;
static JniTypeSignature __Int64TypeSignature;
static JniTypeSignature __Int64NullableTypeSignature;
static JniTypeSignature __SingleTypeSignature;
static JniTypeSignature __SingleNullableTypeSignature;
static JniTypeSignature __DoubleTypeSignature;
static JniTypeSignature __DoubleNullableTypeSignature;

[MethodImpl (MethodImplOptions.AggressiveInlining)]
static JniTypeSignature GetCachedTypeSignature (ref JniTypeSignature field, string signature, int arrayRank = 0, bool keyword = false)
{
if (!field.IsValid)
field = new JniTypeSignature (signature, arrayRank, keyword);
return field;
}

static bool GetBuiltInTypeSignature (Type type, ref JniTypeSignature signature)
{
switch (Type.GetTypeCode (type)) {
case TypeCode.String:
signature = GetCachedTypeSignature (ref __StringTypeSignature, "java/lang/String");
return true;
case TypeCode.Boolean:
signature = GetCachedTypeSignature (ref __BooleanTypeSignature, "Z", arrayRank: 0, keyword: true);
return true;
case TypeCode.SByte:
signature = GetCachedTypeSignature (ref __SByteTypeSignature, "B", arrayRank: 0, keyword: true);
return true;
case TypeCode.Char:
signature = GetCachedTypeSignature (ref __CharTypeSignature, "C", arrayRank: 0, keyword: true);
return true;
case TypeCode.Int16:
signature = GetCachedTypeSignature (ref __Int16TypeSignature, "S", arrayRank: 0, keyword: true);
return true;
case TypeCode.Int32:
signature = GetCachedTypeSignature (ref __Int32TypeSignature, "I", arrayRank: 0, keyword: true);
return true;
case TypeCode.Int64:
signature = GetCachedTypeSignature (ref __Int64TypeSignature, "J", arrayRank: 0, keyword: true);
return true;
case TypeCode.Single:
signature = GetCachedTypeSignature (ref __SingleTypeSignature, "F", arrayRank: 0, keyword: true);
return true;
case TypeCode.Double:
signature = GetCachedTypeSignature (ref __DoubleTypeSignature, "D", arrayRank: 0, keyword: true);
return true;
case TypeCode.DateTime:
case TypeCode.DBNull:
case TypeCode.Decimal:
case TypeCode.Empty:
case TypeCode.UInt16:
case TypeCode.UInt32:
case TypeCode.UInt64:
return false;
}

static readonly Lazy<KeyValuePair<Type, JniTypeSignature>[]> JniBuiltinTypeNameMappings = new Lazy<KeyValuePair<Type, JniTypeSignature>[]> (InitJniBuiltinTypeNameMappings);
if (type == typeof (void)) {
signature = GetCachedTypeSignature (ref __VoidTypeSignature, "V", arrayRank: 0, keyword: true);
return true;
}

static KeyValuePair<Type, JniTypeSignature>[] InitJniBuiltinTypeNameMappings ()
{
return new []{
new KeyValuePair<Type, JniTypeSignature>(typeof (string), new JniTypeSignature ("java/lang/String")),

new KeyValuePair<Type, JniTypeSignature>(typeof (void), new JniTypeSignature ("V", arrayRank: 0, keyword: true)),
new KeyValuePair<Type, JniTypeSignature>(typeof (void), new JniTypeSignature ("java/lang/Void")),

new KeyValuePair<Type, JniTypeSignature>(typeof (Boolean), new JniTypeSignature ("Z", 0, keyword: true)),
new KeyValuePair<Type, JniTypeSignature>(typeof (Boolean?), new JniTypeSignature ("java/lang/Boolean")),
new KeyValuePair<Type, JniTypeSignature>(typeof (SByte), new JniTypeSignature ("B", 0, keyword: true)),
new KeyValuePair<Type, JniTypeSignature>(typeof (SByte?), new JniTypeSignature ("java/lang/Byte")),
new KeyValuePair<Type, JniTypeSignature>(typeof (Char), new JniTypeSignature ("C", 0, keyword: true)),
new KeyValuePair<Type, JniTypeSignature>(typeof (Char?), new JniTypeSignature ("java/lang/Character")),
new KeyValuePair<Type, JniTypeSignature>(typeof (Int16), new JniTypeSignature ("S", 0, keyword: true)),
new KeyValuePair<Type, JniTypeSignature>(typeof (Int16?), new JniTypeSignature ("java/lang/Short")),
new KeyValuePair<Type, JniTypeSignature>(typeof (Int32), new JniTypeSignature ("I", 0, keyword: true)),
new KeyValuePair<Type, JniTypeSignature>(typeof (Int32?), new JniTypeSignature ("java/lang/Integer")),
new KeyValuePair<Type, JniTypeSignature>(typeof (Int64), new JniTypeSignature ("J", 0, keyword: true)),
new KeyValuePair<Type, JniTypeSignature>(typeof (Int64?), new JniTypeSignature ("java/lang/Long")),
new KeyValuePair<Type, JniTypeSignature>(typeof (Single), new JniTypeSignature ("F", 0, keyword: true)),
new KeyValuePair<Type, JniTypeSignature>(typeof (Single?), new JniTypeSignature ("java/lang/Float")),
new KeyValuePair<Type, JniTypeSignature>(typeof (Double), new JniTypeSignature ("D", 0, keyword: true)),
new KeyValuePair<Type, JniTypeSignature>(typeof (Double?), new JniTypeSignature ("java/lang/Double")),
};
if (!type.IsValueType)
return false;

if (type == typeof (Boolean?)) {
signature = GetCachedTypeSignature (ref __BooleanNullableTypeSignature, "java/lang/Boolean");
return true;
}
if (type == typeof (SByte?)) {
signature = GetCachedTypeSignature (ref __SByteNullableTypeSignature, "java/lang/Byte");
return true;
}
if (type == typeof (Char?)) {
signature = GetCachedTypeSignature (ref __CharNullableTypeSignature, "java/lang/Character");
return true;
}
if (type == typeof (Int16?)) {
signature = GetCachedTypeSignature (ref __Int16NullableTypeSignature, "java/lang/Short");
return true;
}
if (type == typeof (Int32?)) {
signature = GetCachedTypeSignature (ref __Int32NullableTypeSignature, "java/lang/Integer");
return true;
}
if (type == typeof (Int64?)) {
signature = GetCachedTypeSignature (ref __Int64NullableTypeSignature, "java/lang/Long");
return true;
}
if (type == typeof (Single?)) {
signature = GetCachedTypeSignature (ref __SingleNullableTypeSignature, "java/lang/Float");
return true;
}
if (type == typeof (Double?)) {
signature = GetCachedTypeSignature (ref __DoubleNullableTypeSignature, "java/lang/Double");
return true;
}

return false;
}

static readonly Lazy<Dictionary<string, Type>> JniBuiltinSimpleReferenceToType = new Lazy<Dictionary<string, Type>> (InitJniBuiltinSimpleReferenceToType);

static Dictionary<string, Type> InitJniBuiltinSimpleReferenceToType ()
{
return new Dictionary<string, Type> (StringComparer.Ordinal) {
{"java/lang/String", typeof (string)},
{"V", typeof (void)},
{"Z", typeof (Boolean)},
{"java/lang/Boolean", typeof (Boolean?)},
{"B", typeof (SByte)},
{"java/lang/Byte", typeof (SByte?)},
{"C", typeof (Char)},
{"java/lang/Character", typeof (Char?)},
{"S", typeof (Int16)},
{"java/lang/Short", typeof (Int16?)},
{"I", typeof (Int32)},
{"java/lang/Integer", typeof (Int32?)},
{"J", typeof (Int64)},
{"java/lang/Long", typeof (Int64?)},
{"F", typeof (Single)},
{"java/lang/Float", typeof (Single?)},
{"D", typeof (Double)},
{"java/lang/Double", typeof (Double?)},
};
}

static readonly Lazy<KeyValuePair<Type, JniValueMarshaler>[]> JniBuiltinMarshalers = new Lazy<KeyValuePair<Type, JniValueMarshaler>[]> (InitJniBuiltinMarshalers);
Expand Down
Loading

0 comments on commit b33d183

Please sign in to comment.