Skip to content
This repository was archived by the owner on May 1, 2024. It is now read-only.

Commit af6f333

Browse files
[XamlC] Cache Resolve and ImportReference (#1875)
ImportReference with System.Reflection based argument is notoriously slow on .NET. So we cache the results for those. We do not cache the results for TypeReference, MethodReference or FieldReference calls, as those are already fast (passthrough if the reference was already imported), and they aren't valid as dictionary keys (no concept of equatability). While we're at it, we shave another few ms from Resolve(TypeReference) calls as well. As, on good days, it shaves up to 40% of XamlC time, we can say that it - fixes #1848
1 parent b96f65b commit af6f333

27 files changed

+251
-209
lines changed

Xamarin.Forms.Build.Tasks/BindablePropertyReferenceExtensions.cs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ public static TypeReference GetBindablePropertyType(this FieldReference bpRef, I
2626
md.IsStatic &&
2727
md.IsPublic &&
2828
md.Parameters.Count == 1 &&
29-
md.Parameters[0].ParameterType.InheritsFromOrImplements(module.ImportReference(typeof(BindableObject))), module).SingleOrDefault()?.Item1;
29+
md.Parameters[0].ParameterType.InheritsFromOrImplements(module.ImportReferenceCached(typeof(BindableObject))), module).SingleOrDefault()?.Item1;
3030
if (getter == null)
3131
throw new XamlParseException($"Missing a public static Get{bpName} or a public instance property getter for the attached property \"{bpRef.DeclaringType}.{bpRef.Name}\"", iXmlLineInfo);
3232
return getter.ResolveGenericReturnType(declaringTypeRef, module);
@@ -43,17 +43,17 @@ public static TypeReference GetBindablePropertyTypeConverter(this FieldReference
4343
md.IsStatic &&
4444
md.IsPublic &&
4545
md.Parameters.Count == 1 &&
46-
md.Parameters[0].ParameterType.InheritsFromOrImplements(module.ImportReference(typeof(BindableObject))), module).SingleOrDefault()?.Item1;
46+
md.Parameters[0].ParameterType.InheritsFromOrImplements(module.ImportReferenceCached(typeof(BindableObject))), module).SingleOrDefault()?.Item1;
4747

4848
var attributes = new List<CustomAttribute>();
4949
if (property != null && property.HasCustomAttributes)
5050
attributes.AddRange(property.CustomAttributes);
51-
if (propertyType != null && propertyType.Resolve().HasCustomAttributes)
52-
attributes.AddRange(propertyType.Resolve().CustomAttributes);
51+
if (propertyType != null && propertyType.ResolveCached().HasCustomAttributes)
52+
attributes.AddRange(propertyType.ResolveCached().CustomAttributes);
5353
if (staticGetter != null && staticGetter.HasCustomAttributes)
5454
attributes.AddRange(staticGetter.CustomAttributes);
55-
if (staticGetter != null && staticGetter.ReturnType.Resolve().HasCustomAttributes)
56-
attributes.AddRange(staticGetter.ReturnType.Resolve().CustomAttributes);
55+
if (staticGetter != null && staticGetter.ReturnType.ResolveCached().HasCustomAttributes)
56+
attributes.AddRange(staticGetter.ReturnType.ResolveCached().CustomAttributes);
5757

5858
return attributes.FirstOrDefault(cad => TypeConverterAttribute.TypeConvertersType.Contains(cad.AttributeType.FullName))?.ConstructorArguments [0].Value as TypeReference;
5959
}

Xamarin.Forms.Build.Tasks/CompiledConverters/BindingTypeConverter.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ public IEnumerable<Instruction> ConvertFromString(string value, ILContext contex
2020
if (IsNullOrEmpty(value))
2121
throw new XamlParseException($"Cannot convert \"{value}\" into {typeof(Binding)}", node);
2222

23-
var bindingCtor = module.ImportReference(typeof(Binding)).Resolve().Methods.FirstOrDefault(md => md.IsConstructor && md.Parameters.Count == 6);
23+
var bindingCtor = module.ImportReferenceCached(typeof(Binding)).ResolveCached().Methods.FirstOrDefault(md => md.IsConstructor && md.Parameters.Count == 6);
2424
var bindingCtorRef = module.ImportReference(bindingCtor);
2525

2626
yield return Instruction.Create(OpCodes.Ldstr, value);

Xamarin.Forms.Build.Tasks/CompiledConverters/BoundsTypeConverter.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ IEnumerable<Instruction> GenerateIL(double x, double y, double w, double h, Modu
6868
yield return Instruction.Create(OpCodes.Ldc_R8, w);
6969
yield return Instruction.Create(OpCodes.Ldc_R8, h);
7070

71-
var rectangleCtor = module.ImportReference(typeof(Rectangle)).Resolve().Methods.FirstOrDefault(md => md.IsConstructor && md.Parameters.Count == 4);
71+
var rectangleCtor = module.ImportReferenceCached(typeof(Rectangle)).ResolveCached().Methods.FirstOrDefault(md => md.IsConstructor && md.Parameters.Count == 4);
7272
var rectangleCtorRef = module.ImportReference(rectangleCtor);
7373
yield return Instruction.Create(OpCodes.Newobj, rectangleCtorRef);
7474
}

Xamarin.Forms.Build.Tasks/CompiledConverters/ColorTypeConverter.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ public IEnumerable<Instruction> ConvertFromString(string value, ILContext contex
2828
yield return Instruction.Create(OpCodes.Ldc_R8, color.G);
2929
yield return Instruction.Create(OpCodes.Ldc_R8, color.B);
3030
yield return Instruction.Create(OpCodes.Ldc_R8, color.A);
31-
var colorCtor = module.ImportReference(typeof(Color)).Resolve().Methods.FirstOrDefault(
31+
var colorCtor = module.ImportReferenceCached(typeof(Color)).ResolveCached().Methods.FirstOrDefault(
3232
md => md.IsConstructor && md.Parameters.Count == 4 &&
3333
md.Parameters.All(p => p.ParameterType.FullName == "System.Double"));
3434
var colorCtorRef = module.ImportReference(colorCtor);
@@ -39,12 +39,12 @@ public IEnumerable<Instruction> ConvertFromString(string value, ILContext contex
3939
if (parts.Length == 1 || (parts.Length == 2 && parts [0] == "Color")) {
4040
var color = parts [parts.Length - 1];
4141

42-
var field = module.ImportReference(typeof(Color)).Resolve().Fields.SingleOrDefault(fd => fd.Name == color && fd.IsStatic);
42+
var field = module.ImportReferenceCached(typeof(Color)).ResolveCached().Fields.SingleOrDefault(fd => fd.Name == color && fd.IsStatic);
4343
if (field != null) {
4444
yield return Instruction.Create(OpCodes.Ldsfld, module.ImportReference(field));
4545
yield break;
4646
}
47-
var propertyGetter = module.ImportReference(typeof(Color)).Resolve().Properties.SingleOrDefault(pd => pd.Name == color && pd.GetMethod.IsStatic)?.GetMethod;
47+
var propertyGetter = module.ImportReferenceCached(typeof(Color)).ResolveCached().Properties.SingleOrDefault(pd => pd.Name == color && pd.GetMethod.IsStatic)?.GetMethod;
4848
if (propertyGetter != null) {
4949
yield return Instruction.Create(OpCodes.Call, module.ImportReference(propertyGetter));
5050
yield break;

Xamarin.Forms.Build.Tasks/CompiledConverters/ConstraintTypeConverter.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ public IEnumerable<Instruction> ConvertFromString(string value, ILContext contex
2323

2424
yield return Instruction.Create(OpCodes.Ldc_R8, size);
2525

26-
var constantDef = module.ImportReference(typeof(Constraint)).Resolve().Methods.FirstOrDefault(md => md.IsStatic && md.Name == "Constant");
26+
var constantDef = module.ImportReferenceCached(typeof(Constraint)).ResolveCached().Methods.FirstOrDefault(md => md.IsStatic && md.Name == "Constant");
2727
var constantRef = module.ImportReference(constantDef);
2828
yield return Instruction.Create(OpCodes.Call, constantRef);
2929
}

Xamarin.Forms.Build.Tasks/CompiledConverters/LayoutOptionsConverter.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ public IEnumerable<Instruction> ConvertFromString(string value, ILContext contex
2626
if (parts.Length == 1 || (parts.Length == 2 && parts [0] == "LayoutOptions")) {
2727
var options = parts [parts.Length - 1];
2828

29-
var field = module.ImportReference(typeof(LayoutOptions)).Resolve().Fields.SingleOrDefault(fd => fd.Name == options && fd.IsStatic);
29+
var field = module.ImportReferenceCached(typeof(LayoutOptions)).ResolveCached().Fields.SingleOrDefault(fd => fd.Name == options && fd.IsStatic);
3030
if (field != null) {
3131
yield return Instruction.Create(OpCodes.Ldsfld, module.ImportReference(field));
3232
yield break;

Xamarin.Forms.Build.Tasks/CompiledConverters/ListStringTypeConverter.cs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,13 +22,13 @@ public IEnumerable<Instruction> ConvertFromString(string value, ILContext contex
2222
}
2323
var parts = value.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries).Select(s => s.Trim()).ToList();
2424

25-
var listCtor = module.ImportReference(typeof(List<>)).Resolve().Methods.FirstOrDefault(md => md.IsConstructor && md.Parameters.Count == 1 && md.Parameters[0].ParameterType.FullName == "System.Int32");
25+
var listCtor = module.ImportReferenceCached(typeof(List<>)).ResolveCached().Methods.FirstOrDefault(md => md.IsConstructor && md.Parameters.Count == 1 && md.Parameters[0].ParameterType.FullName == "System.Int32");
2626
var listCtorRef = module.ImportReference(listCtor);
27-
listCtorRef = module.ImportReference(listCtorRef.ResolveGenericParameters(module.ImportReference(typeof(List<string>)), module));
27+
listCtorRef = module.ImportReference(listCtorRef.ResolveGenericParameters(module.ImportReferenceCached(typeof(List<string>)), module));
2828

29-
var adder = module.ImportReference(typeof(ICollection<>)).Resolve().Methods.FirstOrDefault(md => md.Name == "Add" && md.Parameters.Count == 1);
29+
var adder = module.ImportReferenceCached(typeof(ICollection<>)).ResolveCached().Methods.FirstOrDefault(md => md.Name == "Add" && md.Parameters.Count == 1);
3030
var adderRef = module.ImportReference(adder);
31-
adderRef = module.ImportReference(adderRef.ResolveGenericParameters(module.ImportReference(typeof(ICollection<string>)), module));
31+
adderRef = module.ImportReference(adderRef.ResolveGenericParameters(module.ImportReferenceCached(typeof(ICollection<string>)), module));
3232

3333
yield return Instruction.Create(OpCodes.Ldc_I4, parts.Count);
3434
yield return Instruction.Create(OpCodes.Newobj, listCtorRef);

Xamarin.Forms.Build.Tasks/CompiledConverters/RDSourceTypeConverter.cs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -44,15 +44,15 @@ public IEnumerable<Instruction> ConvertFromString(string value, ILContext contex
4444

4545
//keep the Uri for later
4646
yield return Create(Dup);
47-
var uriVarDef = new VariableDefinition(module.ImportReference(typeof(Uri)));
47+
var uriVarDef = new VariableDefinition(module.ImportReferenceCached(typeof(Uri)));
4848
body.Variables.Add(uriVarDef);
4949
yield return Create(Stloc, uriVarDef);
5050

5151
yield return Create(Ldstr, resourcePath); //resourcePath
5252

53-
var getTypeFromHandle = module.ImportReference(typeof(Type).GetMethod("GetTypeFromHandle", new[] { typeof(RuntimeTypeHandle) }));
54-
var getTypeInfo = module.ImportReference(typeof(System.Reflection.IntrospectionExtensions).GetMethod("GetTypeInfo", new Type[] { typeof(Type) }));
55-
var getAssembly = module.ImportReference(typeof(System.Reflection.TypeInfo).GetProperty("Assembly").GetMethod);
53+
var getTypeFromHandle = module.ImportReferenceCached(typeof(Type).GetMethod("GetTypeFromHandle", new[] { typeof(RuntimeTypeHandle) }));
54+
var getTypeInfo = module.ImportReferenceCached(typeof(System.Reflection.IntrospectionExtensions).GetMethod("GetTypeInfo", new Type[] { typeof(Type) }));
55+
var getAssembly = module.ImportReferenceCached(typeof(System.Reflection.TypeInfo).GetProperty("Assembly").GetMethod);
5656
yield return Create(Ldtoken, module.ImportReference(((ILRootNode)rootNode).TypeReference));
5757
yield return Create(Call, module.ImportReference(getTypeFromHandle));
5858
yield return Create(Call, module.ImportReference(getTypeInfo));
@@ -61,7 +61,7 @@ public IEnumerable<Instruction> ConvertFromString(string value, ILContext contex
6161
foreach (var instruction in node.PushXmlLineInfo(context))
6262
yield return instruction; //lineinfo
6363

64-
var setAndLoadSource = module.ImportReference(typeof(ResourceDictionary).GetMethod("SetAndLoadSource"));
64+
var setAndLoadSource = module.ImportReferenceCached(typeof(ResourceDictionary).GetMethod("SetAndLoadSource"));
6565
yield return Create(Callvirt, module.ImportReference(setAndLoadSource));
6666

6767
//ldloc the stored uri as return value
@@ -71,7 +71,7 @@ public IEnumerable<Instruction> ConvertFromString(string value, ILContext contex
7171
internal static string GetPathForType(ModuleDefinition module, TypeReference type)
7272
{
7373
foreach (var ca in type.Module.GetCustomAttributes()) {
74-
if (!TypeRefComparer.Default.Equals(ca.AttributeType, module.ImportReference(typeof(XamlResourceIdAttribute))))
74+
if (!TypeRefComparer.Default.Equals(ca.AttributeType, module.ImportReferenceCached(typeof(XamlResourceIdAttribute))))
7575
continue;
7676
if (!TypeRefComparer.Default.Equals(ca.ConstructorArguments[2].Value as TypeReference, type))
7777
continue;

Xamarin.Forms.Build.Tasks/CompiledConverters/RectangleTypeConverter.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ IEnumerable<Instruction> GenerateIL(double x, double y, double w, double h, Modu
4343
yield return Instruction.Create(OpCodes.Ldc_R8, w);
4444
yield return Instruction.Create(OpCodes.Ldc_R8, h);
4545

46-
var rectangleCtor = module.ImportReference(typeof(Rectangle)).Resolve().Methods.FirstOrDefault(md => md.IsConstructor && md.Parameters.Count == 4);
46+
var rectangleCtor = module.ImportReferenceCached(typeof(Rectangle)).ResolveCached().Methods.FirstOrDefault(md => md.IsConstructor && md.Parameters.Count == 4);
4747
var rectangleCtorRef = module.ImportReference(rectangleCtor);
4848
yield return Instruction.Create(OpCodes.Newobj, rectangleCtorRef);
4949
}

Xamarin.Forms.Build.Tasks/CompiledConverters/ThicknessTypeConverter.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ IEnumerable<Instruction> GenerateIL(ModuleDefinition module, params double[] arg
4545
{
4646
foreach (var d in args)
4747
yield return Instruction.Create(OpCodes.Ldc_R8, d);
48-
var thicknessCtor = module.ImportReference(typeof(Thickness)).Resolve().Methods.FirstOrDefault(md => md.IsConstructor && md.Parameters.Count == args.Length);
48+
var thicknessCtor = module.ImportReferenceCached(typeof(Thickness)).ResolveCached().Methods.FirstOrDefault(md => md.IsConstructor && md.Parameters.Count == args.Length);
4949
var thicknessCtorRef = module.ImportReference(thicknessCtor);
5050
yield return Instruction.Create(OpCodes.Newobj, thicknessCtorRef);
5151
}

0 commit comments

Comments
 (0)