Skip to content

Commit 09f8da2

Browse files
[JavaCallableWrappers] avoid string.Format() (#1061)
Running PerfView on Windows in a .NET MAUI app, I can see this taking up time inside the `<GenerateJavaStubs/>` MSBuild task: | Name | Inc % | Inc | | --------------------------------------------------------------------------------------------------------------------- | ----: | ----: | | java.interop.tools.javacallablewrappers!Java.Interop.Tools.JavaCallableWrappers.JavaCallableWrapperGenerator..ctor() | 1.4 | 51 | | mscorlib.ni!String.Format | 1.0 | 35 | Around ~26ms appears to be spent inside `JavaCallableWrapperGenerator` calling `string.Format()`. Reviewing the code, there is quite a bit of `WriteLine()` used along with format arguments. I could rework this to use string interpolation, which would be slightly better, as the C# compiler could replace many of these with `string.Concat()`. However, the best case is to just call `Write()` with individual strings, so we don't do extra work creating intermediate string values. Copying `Java.Interop.Tools.JavaCallableWrappers.dll` to: C:\Program Files\dotnet\packs\Microsoft.Android.Sdk.Windows\33.0.4\tools It appears to save about ~17ms in a `dotnet new maui` project: Top 10 most expensive tasks --GenerateJavaStubs = 795 ms ++GenerateJavaStubs = 812 ms This was an incremental build with a `.xaml` change.
1 parent 3a9f770 commit 09f8da2

File tree

1 file changed

+113
-28
lines changed

1 file changed

+113
-28
lines changed

src/Java.Interop.Tools.JavaCallableWrappers/Java.Interop.Tools.JavaCallableWrappers/JavaCallableWrapperGenerator.cs

Lines changed: 113 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -561,7 +561,9 @@ public void Generate (TextWriter writer)
561561
continue;
562562
}
563563
needCtor = true;
564-
writer.WriteLine ("\tstatic final String __md_{0}_methods;", i + 1);
564+
writer.Write ("\tstatic final String __md_");
565+
writer.Write (i + 1);
566+
writer.WriteLine ("_methods;");
565567
}
566568
}
567569

@@ -574,8 +576,7 @@ public void Generate (TextWriter writer)
574576

575577
if (children != null) {
576578
for (int i = 0; i < children.Count; ++i) {
577-
string methods = string.Format ("__md_{0}_methods", i + 1);
578-
GenerateRegisterType (writer, children [i], methods);
579+
GenerateRegisterType (writer, children [i], $"__md_{i + 1}_methods");
579580
}
580581
}
581582
writer.WriteLine ("\t}");
@@ -613,7 +614,9 @@ static void WriteAnnotations (string indent, TextWriter sw, IEnumerable<CustomAt
613614
var catype = ca.AttributeType.Resolve ();
614615
var tca = catype.CustomAttributes.FirstOrDefault (a => a.AttributeType.FullName == "Android.Runtime.AnnotationAttribute");
615616
if (tca != null) {
616-
sw.Write ("{0}@{1}", indent, tca.ConstructorArguments [0].Value);
617+
sw.Write (indent);
618+
sw.Write ('@');
619+
sw.Write (tca.ConstructorArguments [0].Value);
617620
if (ca.Properties.Count > 0) {
618621
sw.WriteLine ("(");
619622
bool wrote = false;
@@ -622,7 +625,9 @@ static void WriteAnnotations (string indent, TextWriter sw, IEnumerable<CustomAt
622625
sw.WriteLine (',');
623626
var pd = catype.Properties.FirstOrDefault (pp => pp.Name == p.Name);
624627
var reg = pd != null ? pd.CustomAttributes.FirstOrDefault (pdca => pdca.AttributeType.FullName == "Android.Runtime.RegisterAttribute") : null;
625-
sw.Write ("{0} = {1}", reg != null ? reg.ConstructorArguments [0].Value : p.Name, ManagedValueToJavaSource (p.Argument.Value));
628+
sw.Write (reg != null ? reg.ConstructorArguments [0].Value : p.Name);
629+
sw.Write (" = ");
630+
sw.Write (ManagedValueToJavaSource (p.Argument.Value));
626631
wrote = true;
627632
}
628633
sw.Write (")");
@@ -674,7 +679,8 @@ void GenerateHeader (TextWriter sw)
674679
if (ifaces.Any ()) {
675680
foreach (TypeDefinition iface in ifaces) {
676681
sw.WriteLine (",");
677-
sw.Write ("\t\t{0}", GetJavaTypeName (iface, cache));
682+
sw.Write ("\t\t");
683+
sw.Write (GetJavaTypeName (iface, cache));
678684
}
679685
}
680686
sw.WriteLine ();
@@ -699,12 +705,20 @@ void GenerateBody (TextWriter sw)
699705

700706
if (GenerateOnCreateOverrides && JavaNativeTypeManager.IsApplication (type, cache) && !methods.Any (m => m.Name == "onCreate"))
701707
WriteApplicationOnCreate (sw, w => {
702-
w.WriteLine ("\t\tmono.android.Runtime.register (\"{0}\", {1}.class, __md_methods);", type.GetPartialAssemblyQualifiedName (cache), name);
708+
w.Write ("\t\tmono.android.Runtime.register (\"");
709+
w.Write (type.GetPartialAssemblyQualifiedName (cache));
710+
w.Write ("\", ");
711+
w.Write (name);
712+
w.WriteLine (".class, __md_methods);");
703713
w.WriteLine ("\t\tsuper.onCreate ();");
704714
});
705715
if (GenerateOnCreateOverrides && JavaNativeTypeManager.IsInstrumentation (type, cache) && !methods.Any (m => m.Name == "onCreate"))
706716
WriteInstrumentationOnCreate (sw, w => {
707-
w.WriteLine ("\t\tmono.android.Runtime.register (\"{0}\", {1}.class, __md_methods);", type.GetPartialAssemblyQualifiedName (cache), name);
717+
w.Write ("\t\tmono.android.Runtime.register (\"");
718+
w.Write (type.GetPartialAssemblyQualifiedName (cache));
719+
w.Write ("\", ");
720+
w.Write (name);
721+
w.WriteLine (".class, __md_methods);");
708722
w.WriteLine ("\t\tsuper.onCreate (arguments);");
709723
});
710724

@@ -737,29 +751,43 @@ void GenerateRegisterType (TextWriter sw, JavaCallableWrapperGenerator self, str
737751
return;
738752
}
739753

740-
sw.WriteLine ("\t\t{0} = ", field);
754+
sw.Write ("\t\t");
755+
sw.Write (field);
756+
sw.WriteLine (" = ");
741757
string managedTypeName = self.type.GetPartialAssemblyQualifiedName (cache);
742758
string javaTypeName = $"{package}.{name}";
743759

744760
foreach (Signature method in self.methods) {
745761
if (method.IsDynamicallyRegistered) {
746-
sw.WriteLine ("\t\t\t\"{0}\\n\" +", method.Method);
762+
sw.Write ("\t\t\t\"", method.Method);
763+
sw.Write (method.Method);
764+
sw.WriteLine ("\\n\" +");
747765
}
748766
}
749767
sw.WriteLine ("\t\t\t\"\";");
750768
if (CannotRegisterInStaticConstructor (self.type))
751769
return;
752-
string? format = null;
770+
sw.Write ("\t\t");
753771
switch (CodeGenerationTarget) {
754772
case JavaPeerStyle.JavaInterop1:
755-
format = "com.xamarin.java_interop.ManagedPeer.registerNativeMembers ({1}.class, \"{0}\", {2});";
773+
sw.Write ("com.xamarin.java_interop.ManagedPeer.registerNativeMembers (");
774+
sw.Write (self.name);
775+
sw.Write (".class, \"");
776+
sw.Write (managedTypeName);
777+
sw.Write ("\", ");
778+
sw.Write (field);
779+
sw.WriteLine (");");
756780
break;
757781
default:
758-
format = "mono.android.Runtime.register (\"{0}\", {1}.class, {2});";
782+
sw.Write ("mono.android.Runtime.register (\"");
783+
sw.Write (managedTypeName);
784+
sw.Write ("\", ");
785+
sw.Write (self.name);
786+
sw.Write (".class, ");
787+
sw.Write (field);
788+
sw.WriteLine (");");
759789
break;
760790
}
761-
sw.Write ("\t\t");
762-
sw.WriteLine (format, managedTypeName, self.name, field);
763791
}
764792

765793
void GenerateFooter (TextWriter sw)
@@ -922,25 +950,44 @@ void GenerateConstructor (Signature ctor, TextWriter sw)
922950
sw.WriteLine ();
923951
if (ctor.Annotations != null)
924952
sw.WriteLine (ctor.Annotations);
925-
sw.WriteLine ("\tpublic {0} ({1}){2}", name, ctor.Params, ctor.ThrowsDeclaration);
953+
sw.Write ("\tpublic ");
954+
sw.Write (name);
955+
sw.Write (" (");
956+
sw.Write (ctor.Params);
957+
sw.Write (')');
958+
sw.WriteLine (ctor.ThrowsDeclaration);
926959
sw.WriteLine ("\t{");
927-
sw.WriteLine ("\t\tsuper ({0});", ctor.SuperCall);
960+
sw.Write ("\t\tsuper (");
961+
sw.Write (ctor.SuperCall);
962+
sw.WriteLine (");");
928963
#if MONODROID_TIMING
929964
sw.WriteLine ("\t\tandroid.util.Log.i(\"MonoDroid-Timing\", \"{0}..ctor({1}): time: \"+java.lang.System.currentTimeMillis());", name, ctor.Params);
930965
#endif
931966
if (!CannotRegisterInStaticConstructor (type)) {
932-
string? format = null;
967+
sw.Write ("\t\tif (getClass () == ");
968+
sw.Write (name);
969+
sw.WriteLine (".class) {");
970+
sw.Write ("\t\t\t");
933971
switch (CodeGenerationTarget) {
934972
case JavaPeerStyle.JavaInterop1:
935-
format = "com.xamarin.java_interop.ManagedPeer.construct (this, \"{0}\", \"{1}\", new java.lang.Object[] {{ {2} }});";
973+
sw.Write ("com.xamarin.java_interop.ManagedPeer.construct (this, \"");
974+
sw.Write (type.GetPartialAssemblyQualifiedName (cache));
975+
sw.Write ("\", \"");
976+
sw.Write (ctor.ManagedParameters);
977+
sw.Write ("\", new java.lang.Object[] { ");
978+
sw.Write (ctor.ActivateCall);
979+
sw.WriteLine (" });");
936980
break;
937981
default:
938-
format = "mono.android.TypeManager.Activate (\"{0}\", \"{1}\", this, new java.lang.Object[] {{ {2} }});";
982+
sw.Write ("mono.android.TypeManager.Activate (\"");
983+
sw.Write (type.GetPartialAssemblyQualifiedName (cache));
984+
sw.Write ("\", \"");
985+
sw.Write (ctor.ManagedParameters);
986+
sw.Write ("\", this, new java.lang.Object[] { ");
987+
sw.Write (ctor.ActivateCall);
988+
sw.WriteLine (" });");
939989
break;
940990
}
941-
sw.WriteLine ("\t\tif (getClass () == {0}.class) {{", name);
942-
sw.Write ("\t\t\t");
943-
sw.WriteLine (format, type.GetPartialAssemblyQualifiedName (cache), ctor.ManagedParameters, ctor.ActivateCall);
944991
sw.WriteLine ("\t\t}");
945992
}
946993
sw.WriteLine ("\t}");
@@ -953,7 +1000,9 @@ void GenerateApplicationConstructor (TextWriter sw)
9531000
}
9541001

9551002
sw.WriteLine ();
956-
sw.WriteLine ("\tpublic {0} ()", name);
1003+
sw.Write ("\tpublic ");
1004+
sw.Write (name);
1005+
sw.WriteLine (" ()");
9571006
sw.WriteLine ("\t{");
9581007
sw.WriteLine ("\t\tmono.MonoPackageManager.setContext (this);");
9591008
sw.WriteLine ("\t}");
@@ -964,24 +1013,60 @@ void GenerateExportedField (JavaFieldInfo field, TextWriter sw)
9641013
sw.WriteLine ();
9651014
if (field.Annotations != null)
9661015
sw.WriteLine (field.Annotations);
967-
sw.WriteLine ("\t{0} {1}{2} {3} = {4} ();", field.GetJavaAccess (), field.IsStatic ? "static " : null, field.TypeName, field.FieldName, field.InitializerName);
1016+
sw.Write ("\t");
1017+
sw.Write (field.GetJavaAccess ());
1018+
sw.Write (' ');
1019+
if (field.IsStatic)
1020+
sw.Write ("static ");
1021+
sw.Write (field.TypeName);
1022+
sw.Write (' ');
1023+
sw.Write (field.FieldName);
1024+
sw.Write (" = ");
1025+
sw.Write (field.InitializerName);
1026+
sw.WriteLine (" ();");
9681027
}
9691028

9701029
void GenerateMethod (Signature method, TextWriter sw)
9711030
{
9721031
sw.WriteLine ();
9731032
if (method.Annotations != null)
9741033
sw.WriteLine (method.Annotations);
975-
sw.WriteLine ("\t{0} {1}{2} {3} ({4}){5}", method.IsExport ? method.JavaAccess : "public", method.IsStatic ? "static " : null, method.Retval, method.JavaName, method.Params, method.ThrowsDeclaration);
1034+
sw.Write ("\t");
1035+
sw.Write (method.IsExport ? method.JavaAccess : "public");
1036+
sw.Write (' ');
1037+
if (method.IsStatic)
1038+
sw.Write ("static ");
1039+
sw.Write (method.Retval);
1040+
sw.Write (' ');
1041+
sw.Write (method.JavaName);
1042+
sw.Write (" (");
1043+
sw.Write (method.Params);
1044+
sw.Write (')');
1045+
sw.WriteLine (method.ThrowsDeclaration);
9761046
sw.WriteLine ("\t{");
9771047
#if MONODROID_TIMING
9781048
sw.WriteLine ("\t\tandroid.util.Log.i(\"MonoDroid-Timing\", \"{0}.{1}: time: \"+java.lang.System.currentTimeMillis());", name, method.Name);
9791049
#endif
980-
sw.WriteLine ("\t\t{0}n_{1} ({2});", method.Retval == "void" ? String.Empty : "return ", method.Name, method.ActivateCall);
1050+
sw.Write ("\t\t");
1051+
sw.Write (method.Retval == "void" ? String.Empty : "return ");
1052+
sw.Write ("n_");
1053+
sw.Write (method.Name);
1054+
sw.Write (" (");
1055+
sw.Write (method.ActivateCall);
1056+
sw.WriteLine (");");
9811057

9821058
sw.WriteLine ("\t}");
9831059
sw.WriteLine ();
984-
sw.WriteLine ("\tprivate {0}native {1} n_{2} ({3});", method.IsStatic ? "static " : null, method.Retval, method.Name, method.Params);
1060+
sw.Write ("\tprivate ");
1061+
if (method.IsStatic)
1062+
sw.Write ("static ");
1063+
sw.Write ("native ");
1064+
sw.Write (method.Retval);
1065+
sw.Write (" n_");
1066+
sw.Write (method.Name);
1067+
sw.Write (" (");
1068+
sw.Write (method.Params);
1069+
sw.WriteLine (");");
9851070
}
9861071

9871072
void WriteApplicationOnCreate (TextWriter sw, Action<TextWriter> extra)

0 commit comments

Comments
 (0)