[linker] add linker dependencies dumping
authorRadek Doulik <rodo@xamarin.com>
Wed, 16 Sep 2015 21:03:43 +0000 (23:03 +0200)
committerRadek Doulik <rodo@xamarin.com>
Fri, 18 Sep 2015 10:45:54 +0000 (12:45 +0200)
mcs/tools/linker/Mono.Linker.Steps/MarkStep.cs
mcs/tools/linker/Mono.Linker.Steps/OutputStep.cs
mcs/tools/linker/Mono.Linker.Steps/ResolveFromAssemblyStep.cs
mcs/tools/linker/Mono.Linker/Annotations.cs
mcs/tools/linker/Mono.Linker/Pipeline.cs
mcs/tools/tuner/Mono.Tuner/Dispatcher.cs

index c9b66af44ab1d6d16bed8dae33b598a1c3be3da0..04dabf45625ad29be82f46385bb1d1be27548bec 100644 (file)
@@ -123,7 +123,9 @@ namespace Mono.Linker.Steps {
                {
                        while (!QueueIsEmpty ()) {
                                MethodDefinition method = (MethodDefinition) _methods.Dequeue ();
+                               Annotations.Push (method);
                                ProcessMethod (method);
+                               Annotations.Pop ();
                        }
                }
 
@@ -483,6 +485,8 @@ namespace Mono.Linker.Steps {
                        if (CheckProcessed (type))
                                return null;
 
+                       Annotations.Push (type);
+
                        MarkScope (type.Scope);
                        MarkType (type.BaseType);
                        MarkType (type.DeclaringType);
@@ -516,6 +520,8 @@ namespace Mono.Linker.Steps {
 
                        DoAdditionalTypeProcessing (type);
 
+                       Annotations.Pop ();
+
                        Annotations.Mark (type);
 
                        ApplyPreserveInfo (type);
@@ -878,6 +884,7 @@ namespace Mono.Linker.Steps {
                        if (reference.DeclaringType is ArrayType)
                                return null;
 
+                       Annotations.Push (reference);
                        if (reference.DeclaringType is GenericInstanceType)
                                MarkType (reference.DeclaringType);
 
@@ -886,13 +893,18 @@ namespace Mono.Linker.Steps {
 
                        MethodDefinition method = ResolveMethodDefinition (reference);
 
-                       if (method == null)
+                       if (method == null) {
+                               Annotations.Pop ();
                                throw new ResolutionException (reference);
+                       }
 
                        if (Annotations.GetAction (method) == MethodAction.Nothing)
                                Annotations.SetAction (method, MethodAction.Parse);
 
                        EnqueueMethod (method);
+
+                       Annotations.Pop ();
+
                        return method;
                }
 
index 5dfa488d6251b22d5c556edcc0a2ea3bea074909..0260c892e99b74494f18250b4979bf3c20fbff4c 100644 (file)
@@ -39,6 +39,7 @@ namespace Mono.Linker.Steps {
                protected override void Process ()
                {
                        CheckOutputDirectory ();
+                       Annotations.SaveDependencies ();
                }
 
                void CheckOutputDirectory ()
@@ -63,9 +64,11 @@ namespace Mono.Linker.Steps {
                        switch (Annotations.GetAction (assembly)) {
                        case AssemblyAction.Save:
                        case AssemblyAction.Link:
+                               Context.Annotations.AddDependency (assembly);
                                assembly.Write (GetAssemblyFileName (assembly, directory), SaveSymbols (assembly));
                                break;
                        case AssemblyAction.Copy:
+                               Context.Annotations.AddDependency (assembly);
                                CloseSymbols (assembly);
                                CopyAssembly (GetOriginalAssemblyFileInfo (assembly), directory, Context.LinkSymbols);
                                break;
index e3ad96b410bf8cf324874466307965919e3ba050..6219bc92ffc27d21e83361e511e2dce69db5508e 100644 (file)
@@ -56,10 +56,10 @@ namespace Mono.Linker.Steps {
                        switch (assembly.MainModule.Kind) {
                        case ModuleKind.Dll:
                                ProcessLibrary (Context, assembly);
-                               return;
+                               break;
                        default:
                                ProcessExecutable (assembly);
-                               return;
+                               break;
                        }
                }
 
@@ -79,14 +79,20 @@ namespace Mono.Linker.Steps {
                {
                        SetAction (context, assembly, AssemblyAction.Copy);
 
+                       context.Annotations.Push (assembly);
+
                        foreach (TypeDefinition type in assembly.MainModule.Types)
                                MarkType (context, type);
+
+                       context.Annotations.Pop ();
                }
 
                static void MarkType (LinkContext context, TypeDefinition type)
                {
                        context.Annotations.Mark (type);
 
+                       context.Annotations.Push (type);
+
                        if (type.HasFields)
                                MarkFields (context, type.Fields);
                        if (type.HasMethods)
@@ -94,14 +100,20 @@ namespace Mono.Linker.Steps {
                        if (type.HasNestedTypes)
                                foreach (var nested in type.NestedTypes)
                                        MarkType (context, nested);
+
+                       context.Annotations.Pop ();
                }
 
                void ProcessExecutable (AssemblyDefinition assembly)
                {
                        SetAction (Context, assembly, AssemblyAction.Link);
 
+                       Annotations.Push (assembly);
+
                        Annotations.Mark (assembly.EntryPoint.DeclaringType);
                        MarkMethod (Context, assembly.EntryPoint, MethodAction.Parse);
+
+                       Annotations.Pop ();
                }
 
                static void MarkFields (LinkContext context, ICollection fields)
index 41fb042c7e549b05db221f8bc9001be70249c1dd..c0386936d570a8ea74aafb22d2473c62a7c2b586 100644 (file)
@@ -29,6 +29,8 @@
 using System;
 using System.Collections;
 using System.Collections.Generic;
+using System.IO;
+using System.IO.Compression;
 
 using Mono.Cecil;
 using Mono.Cecil.Cil;
@@ -50,6 +52,26 @@ namespace Mono.Linker {
 
                readonly Dictionary<object, Dictionary<IMetadataTokenProvider, object>> custom_annotations = new Dictionary<object, Dictionary<IMetadataTokenProvider, object>> ();
 
+               readonly Stack<object> dependency_stack = new Stack<object> ();
+               System.Xml.XmlWriter writer;
+               GZipStream zipStream;
+
+               public void PrepareDependenciesDump ()
+               {
+                       System.Xml.XmlWriterSettings settings = new System.Xml.XmlWriterSettings();
+                       settings.Indent = true;
+                       settings.IndentChars = "\t";
+                       var depsFile = File.OpenWrite ("linker-dependencies.xml.gz");
+                       zipStream = new GZipStream (depsFile, CompressionMode.Compress);
+
+                       writer = System.Xml.XmlWriter.Create (zipStream, settings);
+                       writer.WriteStartDocument ();
+                       writer.WriteStartElement ("dependencies");
+                       writer.WriteStartAttribute ("version");
+                       writer.WriteString ("1.0");
+                       writer.WriteEndAttribute ();
+               }
+
                public AssemblyAction GetAction (AssemblyDefinition assembly)
                {
                        AssemblyAction action;
@@ -86,6 +108,7 @@ namespace Mono.Linker {
                public void Mark (IMetadataTokenProvider provider)
                {
                        marked.Add (provider);
+                       AddDependency (provider);
                }
 
                public bool IsMarked (IMetadataTokenProvider provider)
@@ -237,5 +260,63 @@ namespace Mono.Linker {
                        custom_annotations.Add (key, slots);
                        return slots;
                }
+
+               public void AddDependency (object o)
+               {
+                       if (writer == null)
+                               return;
+
+                       KeyValuePair<object, object> pair = new KeyValuePair<object, object> (dependency_stack.Count > 0 ? dependency_stack.Peek () : null, o);
+                       writer.WriteStartElement ("edge");
+                       writer.WriteAttributeString ("b", TokenString (pair.Key));
+                       writer.WriteAttributeString ("e", TokenString (pair.Value));
+                       writer.WriteEndElement ();
+               }
+
+               public void Push (object o)
+               {
+                       if (writer == null)
+                               return;
+
+                       if (dependency_stack.Count > 0)
+                               AddDependency (o);
+                       dependency_stack.Push (o);
+               }
+
+               public void Pop ()
+               {
+                       if (writer == null)
+                               return;
+
+                       dependency_stack.Pop ();
+               }
+
+               string TokenString (object o)
+               {
+                       if (o == null)
+                               return "N:null";
+
+                       if (o is IMetadataTokenProvider)
+                               return (o as IMetadataTokenProvider).MetadataToken.TokenType + ":" + o;
+
+                       return "Other:" + o;
+               }
+
+               public void SaveDependencies ()
+               {
+                       if (writer == null)
+                               return;
+
+                       writer.WriteEndElement ();
+                       writer.WriteEndDocument ();
+                       writer.Flush ();
+                       writer.Close ();
+                       zipStream.Close ();
+
+                       writer.Dispose ();
+                       zipStream.Dispose ();
+                       writer = null;
+                       zipStream = null;
+               }
        }
 }
index 437a938fa2e11c8e0418eac127c86b560e8f34c9..7ae07d24f1e4a2bd9d0d6c07e3972b2dd500d58c 100644 (file)
@@ -114,7 +114,9 @@ namespace Mono.Linker {
                {
                        while (_steps.Count > 0) {
                                IStep step = (IStep) _steps [0];
+                               context.Annotations.Push (step);
                                step.Process (context);
+                               context.Annotations.Pop ();
                                _steps.Remove (step);
                        }
                }
index 439afd50e35f2afc5f9fe50dd3d8865494954fd1..9dcf5ee05afc4e9bc4a51658a00738dff404443d 100644 (file)
@@ -181,14 +181,26 @@ namespace Mono.Tuner {
 
                void DispatchAssembly (AssemblyDefinition assembly)
                {
-                       foreach (var substep in on_assemblies)
+                       foreach (var substep in on_assemblies) {
+                               var bs = substep as BaseSubStep;
+                               if (bs != null)
+                                       bs.Annotations.Push (substep);
                                substep.ProcessAssembly (assembly);
+                               if (bs != null)
+                                       bs.Annotations.Pop ();
+                       }
                }
 
                void DispatchType (TypeDefinition type)
                {
-                       foreach (var substep in on_types)
+                       foreach (var substep in on_types) {
+                               var bs = substep as BaseSubStep;
+                               if (bs != null)
+                                       bs.Annotations.Push (substep);
                                substep.ProcessType (type);
+                               if (bs != null)
+                                       bs.Annotations.Pop ();
+                       }
                }
 
                void DispatchField (FieldDefinition field)