2016-04-21 15:57:02 +03:00
|
|
|
// Copyright 2016 Xamarin Inc. All right reserved.
|
|
|
|
|
|
|
|
using System;
|
|
|
|
using Mono.Cecil;
|
|
|
|
using Mono.Linker;
|
|
|
|
using Mono.Tuner;
|
|
|
|
|
|
|
|
namespace Xamarin.Linker.Steps {
|
|
|
|
|
|
|
|
// The value of some metadata is very low, some is useful only when debugging
|
|
|
|
// and other can be replaced with different information
|
2017-01-16 19:42:41 +03:00
|
|
|
public class MetadataReducerSubStep : ExceptionalSubStep {
|
|
|
|
|
|
|
|
protected override string Name { get; } = "Metadata Reducer";
|
|
|
|
protected override int ErrorCode { get; } = 2070;
|
2016-04-21 15:57:02 +03:00
|
|
|
|
|
|
|
public override SubStepTargets Targets {
|
|
|
|
get {
|
|
|
|
return SubStepTargets.Type | SubStepTargets.Method;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool ReflectedParameterNames { get; set; }
|
|
|
|
|
|
|
|
public override void Initialize (LinkContext context)
|
|
|
|
{
|
|
|
|
base.Initialize (context);
|
|
|
|
// is some user code depending (or not) on reflection to get method's parameters names ?
|
|
|
|
// note: member references will still exists (even if not marked) until the assembly is saved
|
|
|
|
// so we need this to be pre-computed at the marking stage
|
|
|
|
ReflectedParameterNames = Annotations.GetCustomAnnotations ("ParameterInfo").Count > 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
public override bool IsActiveFor (AssemblyDefinition assembly)
|
|
|
|
{
|
|
|
|
return Annotations.GetAction (assembly) == AssemblyAction.Link;
|
|
|
|
}
|
|
|
|
|
2017-01-16 19:42:41 +03:00
|
|
|
protected override void Process (MethodDefinition method)
|
2016-04-21 15:57:02 +03:00
|
|
|
{
|
|
|
|
if (method.IsPInvokeImpl) {
|
|
|
|
// note: ObjCRuntime.Messaging - but also 3rd parties bindings (normally ApiDefinitions.Messaging)
|
|
|
|
// to avoid possible out-of-assembly usage (eg. classic) we only apply the optimization on non-public methods
|
|
|
|
var dt = method.DeclaringType;
|
|
|
|
if (!method.IsPublic || !dt.IsPublic) {
|
|
|
|
// Avoid hundreds of different strings for msgSend[Super] overloads
|
2017-01-16 19:42:41 +03:00
|
|
|
// C# requires different names (for methods with different return values)
|
2016-04-21 15:57:02 +03:00
|
|
|
// but it's not an issue in IL
|
|
|
|
if ((dt.Name == "Messaging") && (method.PInvokeInfo.Module.Name == "/usr/lib/libobjc.dylib"))
|
|
|
|
method.Name = method.PInvokeInfo.EntryPoint;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Parameter names are rather safe to remove, i.e. unlikely to be used in reflection
|
|
|
|
// but their removal (from the string table) can save a lot of space in the .app
|
|
|
|
// https://trello.com/c/zYFcYmuM/34-linker-support-for-removing-parameter-names
|
|
|
|
|
|
|
|
// Still unlikely != impossible, e.g. some user code can reflect them
|
|
|
|
// https://bugzilla.xamarin.com/show_bug.cgi?id=40458
|
|
|
|
if (ReflectedParameterNames)
|
|
|
|
return;
|
|
|
|
|
|
|
|
// The limit of this optimization is that parameter validation (e.g. null checks)
|
|
|
|
// often use the parameter name anyway (no saving in those cases). However this
|
|
|
|
// is something that can be solved elsewhere...
|
|
|
|
if (!method.HasParameters)
|
|
|
|
return;
|
|
|
|
|
|
|
|
foreach (var p in method.Parameters)
|
|
|
|
p.Name = null;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|