Skip to content

Commit 3b5ef93

Browse files
grendellopjcollins
authored andcommitted
[Java.Interop] JniTypeManager optimizations (#582)
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)
1 parent 54ea1e8 commit 3b5ef93

File tree

8 files changed

+289
-103
lines changed

8 files changed

+289
-103
lines changed

src/Java.Interop/.editorconfig

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,6 @@ dotnet_diagnostic.CA1408.severity = error
9898
dotnet_diagnostic.CA1412.severity = error
9999
dotnet_diagnostic.CA1410.severity = error
100100
dotnet_diagnostic.CA1411.severity = error
101-
dotnet_diagnostic.CA1502.severity = error
102101
dotnet_diagnostic.CA1501.severity = error
103102
dotnet_diagnostic.CA1011.severity = error
104103
dotnet_diagnostic.CA1504.severity = error
@@ -154,5 +153,6 @@ dotnet_diagnostic.CA1062.severity = none # Validate arguments of public methods
154153
dotnet_diagnostic.CA1063.severity = none # Implement IDisposable correctly
155154
dotnet_diagnostic.CA1303.severity = none # Do not pass literals as localized parameters
156155
dotnet_diagnostic.CA1305.severity = none # Specify IFormatProvider
156+
dotnet_diagnostic.CA1502.severity = none # 'Method' has a cyclomatic complexity of 'XX'. Rewrite or refactor the code to decrease its complexity below 'YY'.
157157
dotnet_diagnostic.CA1810.severity = none # Initialize reference type static fields inline
158158
dotnet_diagnostic.CA1816.severity = none # Call GC.SuppressFinalize correctly

src/Java.Interop/Java.Interop/JavaPrimitiveArrays.cs

Lines changed: 44 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -11,28 +11,50 @@
1111
namespace Java.Interop {
1212

1313
partial class JniRuntime {
14-
static readonly Lazy<KeyValuePair<Type, JniTypeSignature>[]> JniBuiltinArrayMappings = new Lazy<KeyValuePair<Type, JniTypeSignature>[]> (InitJniBuiltinArrayMappings);
15-
16-
static KeyValuePair<Type, JniTypeSignature>[] InitJniBuiltinArrayMappings ()
17-
{
18-
return new[] {
19-
new KeyValuePair<Type, JniTypeSignature>(typeof (JavaPrimitiveArray<Boolean>), new JniTypeSignature ("Z", arrayRank: 1, keyword: true)),
20-
new KeyValuePair<Type, JniTypeSignature>(typeof (JavaArray<Boolean>), new JniTypeSignature ("Z", arrayRank: 1, keyword: true)),
21-
new KeyValuePair<Type, JniTypeSignature>(typeof (JavaPrimitiveArray<SByte>), new JniTypeSignature ("B", arrayRank: 1, keyword: true)),
22-
new KeyValuePair<Type, JniTypeSignature>(typeof (JavaArray<SByte>), new JniTypeSignature ("B", arrayRank: 1, keyword: true)),
23-
new KeyValuePair<Type, JniTypeSignature>(typeof (JavaPrimitiveArray<Char>), new JniTypeSignature ("C", arrayRank: 1, keyword: true)),
24-
new KeyValuePair<Type, JniTypeSignature>(typeof (JavaArray<Char>), new JniTypeSignature ("C", arrayRank: 1, keyword: true)),
25-
new KeyValuePair<Type, JniTypeSignature>(typeof (JavaPrimitiveArray<Int16>), new JniTypeSignature ("S", arrayRank: 1, keyword: true)),
26-
new KeyValuePair<Type, JniTypeSignature>(typeof (JavaArray<Int16>), new JniTypeSignature ("S", arrayRank: 1, keyword: true)),
27-
new KeyValuePair<Type, JniTypeSignature>(typeof (JavaPrimitiveArray<Int32>), new JniTypeSignature ("I", arrayRank: 1, keyword: true)),
28-
new KeyValuePair<Type, JniTypeSignature>(typeof (JavaArray<Int32>), new JniTypeSignature ("I", arrayRank: 1, keyword: true)),
29-
new KeyValuePair<Type, JniTypeSignature>(typeof (JavaPrimitiveArray<Int64>), new JniTypeSignature ("J", arrayRank: 1, keyword: true)),
30-
new KeyValuePair<Type, JniTypeSignature>(typeof (JavaArray<Int64>), new JniTypeSignature ("J", arrayRank: 1, keyword: true)),
31-
new KeyValuePair<Type, JniTypeSignature>(typeof (JavaPrimitiveArray<Single>), new JniTypeSignature ("F", arrayRank: 1, keyword: true)),
32-
new KeyValuePair<Type, JniTypeSignature>(typeof (JavaArray<Single>), new JniTypeSignature ("F", arrayRank: 1, keyword: true)),
33-
new KeyValuePair<Type, JniTypeSignature>(typeof (JavaPrimitiveArray<Double>), new JniTypeSignature ("D", arrayRank: 1, keyword: true)),
34-
new KeyValuePair<Type, JniTypeSignature>(typeof (JavaArray<Double>), new JniTypeSignature ("D", arrayRank: 1, keyword: true)),
35-
};
14+
static JniTypeSignature __BooleanTypeArraySignature;
15+
static JniTypeSignature __SByteTypeArraySignature;
16+
static JniTypeSignature __CharTypeArraySignature;
17+
static JniTypeSignature __Int16TypeArraySignature;
18+
static JniTypeSignature __Int32TypeArraySignature;
19+
static JniTypeSignature __Int64TypeArraySignature;
20+
static JniTypeSignature __SingleTypeArraySignature;
21+
static JniTypeSignature __DoubleTypeArraySignature;
22+
23+
static bool GetBuiltInTypeArraySignature (Type type, ref JniTypeSignature signature)
24+
{
25+
if (type == typeof (JavaArray<Boolean>) || type == typeof (JavaPrimitiveArray<Boolean>)) {
26+
signature = GetCachedTypeSignature (ref __BooleanTypeArraySignature, "Z", arrayRank: 1, keyword: true);
27+
return true;
28+
}
29+
if (type == typeof (JavaArray<SByte>) || type == typeof (JavaPrimitiveArray<SByte>)) {
30+
signature = GetCachedTypeSignature (ref __SByteTypeArraySignature, "B", arrayRank: 1, keyword: true);
31+
return true;
32+
}
33+
if (type == typeof (JavaArray<Char>) || type == typeof (JavaPrimitiveArray<Char>)) {
34+
signature = GetCachedTypeSignature (ref __CharTypeArraySignature, "C", arrayRank: 1, keyword: true);
35+
return true;
36+
}
37+
if (type == typeof (JavaArray<Int16>) || type == typeof (JavaPrimitiveArray<Int16>)) {
38+
signature = GetCachedTypeSignature (ref __Int16TypeArraySignature, "S", arrayRank: 1, keyword: true);
39+
return true;
40+
}
41+
if (type == typeof (JavaArray<Int32>) || type == typeof (JavaPrimitiveArray<Int32>)) {
42+
signature = GetCachedTypeSignature (ref __Int32TypeArraySignature, "I", arrayRank: 1, keyword: true);
43+
return true;
44+
}
45+
if (type == typeof (JavaArray<Int64>) || type == typeof (JavaPrimitiveArray<Int64>)) {
46+
signature = GetCachedTypeSignature (ref __Int64TypeArraySignature, "J", arrayRank: 1, keyword: true);
47+
return true;
48+
}
49+
if (type == typeof (JavaArray<Single>) || type == typeof (JavaPrimitiveArray<Single>)) {
50+
signature = GetCachedTypeSignature (ref __SingleTypeArraySignature, "F", arrayRank: 1, keyword: true);
51+
return true;
52+
}
53+
if (type == typeof (JavaArray<Double>) || type == typeof (JavaPrimitiveArray<Double>)) {
54+
signature = GetCachedTypeSignature (ref __DoubleTypeArraySignature, "D", arrayRank: 1, keyword: true);
55+
return true;
56+
}
57+
return false;
3658
}
3759

3860
static readonly Lazy<KeyValuePair<Type, JniValueMarshaler>[]> JniPrimitiveArrayMarshalers = new Lazy<KeyValuePair<Type, JniValueMarshaler>[]> (InitJniPrimitiveArrayMarshalers);

src/Java.Interop/Java.Interop/JavaPrimitiveArrays.tt

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -28,20 +28,27 @@ namespace Java.Interop {
2828
};
2929
#>
3030
partial class JniRuntime {
31-
static readonly Lazy<KeyValuePair<Type, JniTypeSignature>[]> JniBuiltinArrayMappings = new Lazy<KeyValuePair<Type, JniTypeSignature>[]> (InitJniBuiltinArrayMappings);
31+
<#
32+
foreach (var type in arrayTypeInfo) {
33+
#>
34+
static JniTypeSignature __<#= type.ManagedType #>TypeArraySignature;
35+
<#
36+
}
37+
#>
3238

33-
static KeyValuePair<Type, JniTypeSignature>[] InitJniBuiltinArrayMappings ()
39+
static bool GetBuiltInTypeArraySignature (Type type, ref JniTypeSignature signature)
3440
{
35-
return new[] {
3641
<#
3742
foreach (var info in arrayTypeInfo) {
3843
#>
39-
new KeyValuePair<Type, JniTypeSignature>(typeof (JavaPrimitiveArray<<#= info.ManagedType #>>), new JniTypeSignature ("<#= info.JniType #>", arrayRank: 1, keyword: true)),
40-
new KeyValuePair<Type, JniTypeSignature>(typeof (JavaArray<<#= info.ManagedType #>>), new JniTypeSignature ("<#= info.JniType #>", arrayRank: 1, keyword: true)),
44+
if (type == typeof (JavaArray<<#= info.ManagedType #>>) || type == typeof (JavaPrimitiveArray<<#= info.ManagedType #>>)) {
45+
signature = GetCachedTypeSignature (ref __<#= info.ManagedType #>TypeArraySignature, "<#= info.JniType #>", arrayRank: 1, keyword: true);
46+
return true;
47+
}
4148
<#
4249
}
4350
#>
44-
};
51+
return false;
4552
}
4653

4754
static readonly Lazy<KeyValuePair<Type, JniValueMarshaler>[]> JniPrimitiveArrayMarshalers = new Lazy<KeyValuePair<Type, JniValueMarshaler>[]> (InitJniPrimitiveArrayMarshalers);

src/Java.Interop/Java.Interop/JniBuiltinMarshalers.cs

Lines changed: 134 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
using System;
44
using System.Collections.Generic;
5+
using System.Runtime.CompilerServices;
56
using System.Diagnostics;
67
using System.Linq.Expressions;
78
using System.Reflection;
@@ -11,34 +12,141 @@
1112
namespace Java.Interop {
1213

1314
partial class JniRuntime {
15+
static JniTypeSignature __StringTypeSignature;
16+
static JniTypeSignature __VoidTypeSignature;
17+
static JniTypeSignature __BooleanTypeSignature;
18+
static JniTypeSignature __BooleanNullableTypeSignature;
19+
static JniTypeSignature __SByteTypeSignature;
20+
static JniTypeSignature __SByteNullableTypeSignature;
21+
static JniTypeSignature __CharTypeSignature;
22+
static JniTypeSignature __CharNullableTypeSignature;
23+
static JniTypeSignature __Int16TypeSignature;
24+
static JniTypeSignature __Int16NullableTypeSignature;
25+
static JniTypeSignature __Int32TypeSignature;
26+
static JniTypeSignature __Int32NullableTypeSignature;
27+
static JniTypeSignature __Int64TypeSignature;
28+
static JniTypeSignature __Int64NullableTypeSignature;
29+
static JniTypeSignature __SingleTypeSignature;
30+
static JniTypeSignature __SingleNullableTypeSignature;
31+
static JniTypeSignature __DoubleTypeSignature;
32+
static JniTypeSignature __DoubleNullableTypeSignature;
33+
34+
[MethodImpl (MethodImplOptions.AggressiveInlining)]
35+
static JniTypeSignature GetCachedTypeSignature (ref JniTypeSignature field, string signature, int arrayRank = 0, bool keyword = false)
36+
{
37+
if (!field.IsValid)
38+
field = new JniTypeSignature (signature, arrayRank, keyword);
39+
return field;
40+
}
41+
42+
static bool GetBuiltInTypeSignature (Type type, ref JniTypeSignature signature)
43+
{
44+
switch (Type.GetTypeCode (type)) {
45+
case TypeCode.String:
46+
signature = GetCachedTypeSignature (ref __StringTypeSignature, "java/lang/String");
47+
return true;
48+
case TypeCode.Boolean:
49+
signature = GetCachedTypeSignature (ref __BooleanTypeSignature, "Z", arrayRank: 0, keyword: true);
50+
return true;
51+
case TypeCode.SByte:
52+
signature = GetCachedTypeSignature (ref __SByteTypeSignature, "B", arrayRank: 0, keyword: true);
53+
return true;
54+
case TypeCode.Char:
55+
signature = GetCachedTypeSignature (ref __CharTypeSignature, "C", arrayRank: 0, keyword: true);
56+
return true;
57+
case TypeCode.Int16:
58+
signature = GetCachedTypeSignature (ref __Int16TypeSignature, "S", arrayRank: 0, keyword: true);
59+
return true;
60+
case TypeCode.Int32:
61+
signature = GetCachedTypeSignature (ref __Int32TypeSignature, "I", arrayRank: 0, keyword: true);
62+
return true;
63+
case TypeCode.Int64:
64+
signature = GetCachedTypeSignature (ref __Int64TypeSignature, "J", arrayRank: 0, keyword: true);
65+
return true;
66+
case TypeCode.Single:
67+
signature = GetCachedTypeSignature (ref __SingleTypeSignature, "F", arrayRank: 0, keyword: true);
68+
return true;
69+
case TypeCode.Double:
70+
signature = GetCachedTypeSignature (ref __DoubleTypeSignature, "D", arrayRank: 0, keyword: true);
71+
return true;
72+
case TypeCode.DateTime:
73+
case TypeCode.DBNull:
74+
case TypeCode.Decimal:
75+
case TypeCode.Empty:
76+
case TypeCode.UInt16:
77+
case TypeCode.UInt32:
78+
case TypeCode.UInt64:
79+
return false;
80+
}
1481

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

17-
static KeyValuePair<Type, JniTypeSignature>[] InitJniBuiltinTypeNameMappings ()
18-
{
19-
return new []{
20-
new KeyValuePair<Type, JniTypeSignature>(typeof (string), new JniTypeSignature ("java/lang/String")),
21-
22-
new KeyValuePair<Type, JniTypeSignature>(typeof (void), new JniTypeSignature ("V", arrayRank: 0, keyword: true)),
23-
new KeyValuePair<Type, JniTypeSignature>(typeof (void), new JniTypeSignature ("java/lang/Void")),
24-
25-
new KeyValuePair<Type, JniTypeSignature>(typeof (Boolean), new JniTypeSignature ("Z", 0, keyword: true)),
26-
new KeyValuePair<Type, JniTypeSignature>(typeof (Boolean?), new JniTypeSignature ("java/lang/Boolean")),
27-
new KeyValuePair<Type, JniTypeSignature>(typeof (SByte), new JniTypeSignature ("B", 0, keyword: true)),
28-
new KeyValuePair<Type, JniTypeSignature>(typeof (SByte?), new JniTypeSignature ("java/lang/Byte")),
29-
new KeyValuePair<Type, JniTypeSignature>(typeof (Char), new JniTypeSignature ("C", 0, keyword: true)),
30-
new KeyValuePair<Type, JniTypeSignature>(typeof (Char?), new JniTypeSignature ("java/lang/Character")),
31-
new KeyValuePair<Type, JniTypeSignature>(typeof (Int16), new JniTypeSignature ("S", 0, keyword: true)),
32-
new KeyValuePair<Type, JniTypeSignature>(typeof (Int16?), new JniTypeSignature ("java/lang/Short")),
33-
new KeyValuePair<Type, JniTypeSignature>(typeof (Int32), new JniTypeSignature ("I", 0, keyword: true)),
34-
new KeyValuePair<Type, JniTypeSignature>(typeof (Int32?), new JniTypeSignature ("java/lang/Integer")),
35-
new KeyValuePair<Type, JniTypeSignature>(typeof (Int64), new JniTypeSignature ("J", 0, keyword: true)),
36-
new KeyValuePair<Type, JniTypeSignature>(typeof (Int64?), new JniTypeSignature ("java/lang/Long")),
37-
new KeyValuePair<Type, JniTypeSignature>(typeof (Single), new JniTypeSignature ("F", 0, keyword: true)),
38-
new KeyValuePair<Type, JniTypeSignature>(typeof (Single?), new JniTypeSignature ("java/lang/Float")),
39-
new KeyValuePair<Type, JniTypeSignature>(typeof (Double), new JniTypeSignature ("D", 0, keyword: true)),
40-
new KeyValuePair<Type, JniTypeSignature>(typeof (Double?), new JniTypeSignature ("java/lang/Double")),
41-
};
87+
if (!type.IsValueType)
88+
return false;
89+
90+
if (type == typeof (Boolean?)) {
91+
signature = GetCachedTypeSignature (ref __BooleanNullableTypeSignature, "java/lang/Boolean");
92+
return true;
93+
}
94+
if (type == typeof (SByte?)) {
95+
signature = GetCachedTypeSignature (ref __SByteNullableTypeSignature, "java/lang/Byte");
96+
return true;
97+
}
98+
if (type == typeof (Char?)) {
99+
signature = GetCachedTypeSignature (ref __CharNullableTypeSignature, "java/lang/Character");
100+
return true;
101+
}
102+
if (type == typeof (Int16?)) {
103+
signature = GetCachedTypeSignature (ref __Int16NullableTypeSignature, "java/lang/Short");
104+
return true;
105+
}
106+
if (type == typeof (Int32?)) {
107+
signature = GetCachedTypeSignature (ref __Int32NullableTypeSignature, "java/lang/Integer");
108+
return true;
109+
}
110+
if (type == typeof (Int64?)) {
111+
signature = GetCachedTypeSignature (ref __Int64NullableTypeSignature, "java/lang/Long");
112+
return true;
113+
}
114+
if (type == typeof (Single?)) {
115+
signature = GetCachedTypeSignature (ref __SingleNullableTypeSignature, "java/lang/Float");
116+
return true;
117+
}
118+
if (type == typeof (Double?)) {
119+
signature = GetCachedTypeSignature (ref __DoubleNullableTypeSignature, "java/lang/Double");
120+
return true;
121+
}
122+
123+
return false;
124+
}
125+
126+
static readonly Lazy<Dictionary<string, Type>> JniBuiltinSimpleReferenceToType = new Lazy<Dictionary<string, Type>> (InitJniBuiltinSimpleReferenceToType);
127+
128+
static Dictionary<string, Type> InitJniBuiltinSimpleReferenceToType ()
129+
{
130+
return new Dictionary<string, Type> (StringComparer.Ordinal) {
131+
{"java/lang/String", typeof (string)},
132+
{"V", typeof (void)},
133+
{"Z", typeof (Boolean)},
134+
{"java/lang/Boolean", typeof (Boolean?)},
135+
{"B", typeof (SByte)},
136+
{"java/lang/Byte", typeof (SByte?)},
137+
{"C", typeof (Char)},
138+
{"java/lang/Character", typeof (Char?)},
139+
{"S", typeof (Int16)},
140+
{"java/lang/Short", typeof (Int16?)},
141+
{"I", typeof (Int32)},
142+
{"java/lang/Integer", typeof (Int32?)},
143+
{"J", typeof (Int64)},
144+
{"java/lang/Long", typeof (Int64?)},
145+
{"F", typeof (Single)},
146+
{"java/lang/Float", typeof (Single?)},
147+
{"D", typeof (Double)},
148+
{"java/lang/Double", typeof (Double?)},
149+
};
42150
}
43151

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

0 commit comments

Comments
 (0)