Skip to content

Commit

Permalink
Migrate to cecil 0.10
Browse files Browse the repository at this point in the history
- fixed handle leaks
- removed duplicate assembly definition resolving (perf++)
- moved debug information to new API
- pretty-much untested yet, but UTs look ok
  • Loading branch information
gluck authored and Alexx999 committed Aug 31, 2018
1 parent a219c50 commit 71e0ea4
Show file tree
Hide file tree
Showing 10 changed files with 79 additions and 41 deletions.
15 changes: 11 additions & 4 deletions ILRepack.IntegrationTests/NuGet/TestHelpers.cs
Original file line number Diff line number Diff line change
Expand Up @@ -38,11 +38,18 @@ public static void DoRepackForCmd(IEnumerable<string> args)

private static void ReloadAndCheckReferences(RepackOptions repackOptions)
{
var outputFile = AssemblyDefinition.ReadAssembly(repackOptions.OutputFile, new ReaderParameters(ReadingMode.Immediate));
var mergedFiles = repackOptions.ResolveFiles().Select(f => AssemblyDefinition.ReadAssembly(f, new ReaderParameters(ReadingMode.Deferred)));
foreach (var a in outputFile.MainModule.AssemblyReferences.Where(x => mergedFiles.Any(y => repackOptions.KeepOtherVersionReferences ? x.FullName == y.FullName : x.Name == y.Name.Name)))
using (var ar = new DefaultAssemblyResolver())
using (var outputFile = AssemblyDefinition.ReadAssembly(repackOptions.OutputFile, new ReaderParameters(ReadingMode.Immediate) { AssemblyResolver = ar }))
{
Assert.Fail($"Merged assembly retains a reference to one (or more) of the merged files: {a.FullName}");
var mergedFiles = repackOptions.ResolveFiles().Select(f => AssemblyDefinition.ReadAssembly(f, new ReaderParameters(ReadingMode.Deferred) { AssemblyResolver = ar })).ToList();
foreach (var a in outputFile.MainModule.AssemblyReferences.Where(x => mergedFiles.Any(y => repackOptions.KeepOtherVersionReferences ? x.FullName == y.FullName : x.Name == y.Name.Name)))
{
Assert.Fail($"Merged assembly retains a reference to one (or more) of the merged files: {a.FullName}");
}
foreach (var a in mergedFiles)
{
a.Dispose();
}
}
}

Expand Down
30 changes: 13 additions & 17 deletions ILRepack/IKVMLineIndexer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ internal class IKVMLineIndexer
{
private readonly IRepackContext repack;
private bool enabled;
private LineNumberWriter lineNumberWriter;
private string fileName;
private TypeReference sourceFileAttributeTypeReference;
private TypeReference lineNumberTableAttributeTypeReference;
Expand All @@ -41,29 +40,29 @@ public IKVMLineIndexer(IRepackContext ilRepack, bool doLineIndexing)

public void Reset()
{
lineNumberWriter = null;
fileName = null;
}

public void PreMethodBodyRepack(MethodBody body, MethodDefinition parent)
{
if (!enabled)
if (!enabled || !parent.DebugInformation.HasSequencePoints)
return;

Reset();
if (!parent.CustomAttributes.Any(x => x.Constructor.DeclaringType.Name == "LineNumberTableAttribute"))
{
lineNumberWriter = new LineNumberWriter(body.Instructions.Count / 4);
var lineNumberWriter = new LineNumberWriter(body.Instructions.Count / 4);
foreach (var sp in parent.DebugInformation.SequencePoints)
{
AddSeqPoint(sp, lineNumberWriter);
}
PostMethodBodyRepack(parent, lineNumberWriter);
}
}

public void ProcessMethodBodyInstruction(Instruction instr)
private void AddSeqPoint(SequencePoint currentSeqPoint, LineNumberWriter lineNumberWriter)
{
if (!enabled)
return;

var currentSeqPoint = instr.SequencePoint;
if (lineNumberWriter != null && currentSeqPoint != null)
if (currentSeqPoint != null)
{
if (fileName == null && currentSeqPoint.Document != null)
{
Expand All @@ -84,25 +83,22 @@ public void ProcessMethodBodyInstruction(Instruction instr)
{
if (lineNumberWriter.LineNo > 0)
{
lineNumberWriter.AddMapping(instr.Offset, -1);
lineNumberWriter.AddMapping(currentSeqPoint.Offset, -1);
}
}
else
{
if (lineNumberWriter.LineNo != currentSeqPoint.StartLine)
{
lineNumberWriter.AddMapping(instr.Offset, currentSeqPoint.StartLine);
lineNumberWriter.AddMapping(currentSeqPoint.Offset, currentSeqPoint.StartLine);
}
}
}
}

public void PostMethodBodyRepack(MethodDefinition parent)
private void PostMethodBodyRepack(MethodDefinition parent, LineNumberWriter lineNumberWriter)
{
if (!enabled)
return;

if (lineNumberWriter != null && lineNumberWriter.Count > 0)
if (lineNumberWriter.Count > 0)
{
CustomAttribute ca;
if (lineNumberWriter.Count == 1)
Expand Down
15 changes: 11 additions & 4 deletions ILRepack/ILRepack.cs
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,7 @@ private AssemblyDefinitionContainer ReadInputAssembly(string assembly, bool isPr

if (!Options.AllowZeroPeKind && (mergeAsm.MainModule.Attributes & ModuleAttributes.ILOnly) == 0)
throw new ArgumentException("Failed to load assembly with Zero PeKind: " + assembly);
GlobalAssemblyResolver.RegisterAssembly(mergeAsm);

return new AssemblyDefinitionContainer
{
Expand Down Expand Up @@ -264,7 +265,6 @@ public void Repack()

// Read input assemblies only after all properties are set.
ReadInputAssemblies();
GlobalAssemblyResolver.RegisterAssemblies(MergedAssemblies);

_platformFixer = new PlatformFixer(this, PrimaryAssemblyMainModule.Runtime);
_mappingHandler = new MappingHandler();
Expand Down Expand Up @@ -337,10 +337,16 @@ public void Repack()
step.Perform();
}

for (int i = 1; i < MergedAssemblies.Count; ++i)
{
MergedAssemblies[i].Dispose();
}

var parameters = new WriterParameters
{
StrongNameKeyPair = signingStep.KeyPair,
WriteSymbols = Options.DebugInfo
WriteSymbols = Options.DebugInfo && PrimaryAssemblyMainModule.SymbolReader != null,
SymbolWriterProvider = PrimaryAssemblyMainModule.SymbolReader?.GetWriterProvider(),
};
// create output directory if it does not exist
var outputDir = Path.GetDirectoryName(Options.OutputFile);
Expand All @@ -350,11 +356,12 @@ public void Repack()
Directory.CreateDirectory(outputDir);
}

TargetAssemblyDefinition.Write(Options.OutputFile, parameters);

sourceServerDataStep.Write();

Logger.Info("Writing output assembly to disk");
TargetAssemblyDefinition.Write(Options.OutputFile, parameters);
TargetAssemblyDefinition.Dispose();
GlobalAssemblyResolver.Dispose();
// If this is an executable and we are on linux/osx we should copy file permissions from
// the primary assembly
if (isUnixEnvironment)
Expand Down
1 change: 1 addition & 0 deletions ILRepack/ILRepack.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@
<Compile Include="ILRepack.cs" />
<Compile Include="MethodMatcher.cs" />
<Compile Include="Mixins\AssemblyNameReferenceCollectionMixins.cs" />
<Compile Include="Mixins\CollectionMixins.cs" />
<Compile Include="PermissionsetHelper.cs" />
<Compile Include="PlatformFixer.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
Expand Down
16 changes: 16 additions & 0 deletions ILRepack/Mixins/CollectionMixins.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
using Mono.Collections.Generic;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ILRepacking.Mixins
{
static class CollectionMixins
{
public static void AddRange<T>(this Collection<T> dest, IEnumerable<T> source)
{
foreach (var obj in source) dest.Add(obj);
}
}
}
8 changes: 6 additions & 2 deletions ILRepack/ReferenceFixator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,11 @@ internal void FixReferences(TypeDefinition type)
type.BaseType = Fix(type.BaseType);

// interfaces before methods, because methods will have to go through them
FixReferences(type.Interfaces);
foreach (InterfaceImplementation nested in type.Interfaces)
{
nested.InterfaceType = Fix(nested.InterfaceType);
FixReferences(nested.CustomAttributes);
}

// nested types first
foreach (TypeDefinition nested in type.NestedTypes)
Expand Down Expand Up @@ -332,7 +336,7 @@ private bool IsAnnotation(TypeDefinition typeAttribute)
{
if (typeAttribute == null)
return false;
if (typeAttribute.Interfaces.Any(@interface => @interface.FullName == "java.lang.annotation.Annotation"))
if (typeAttribute.Interfaces.Any(@interface => @interface.InterfaceType.FullName == "java.lang.annotation.Annotation"))
return true;
return typeAttribute.BaseType != null && IsAnnotation(typeAttribute.BaseType.Resolve());
}
Expand Down
7 changes: 2 additions & 5 deletions ILRepack/RepackAssemblyResolver.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,9 @@ namespace ILRepacking
{
public class RepackAssemblyResolver : DefaultAssemblyResolver
{
public void RegisterAssemblies(IList<AssemblyDefinition> mergedAssemblies)
public new void RegisterAssembly(AssemblyDefinition assembly)
{
foreach (var assemblyDefinition in mergedAssemblies)
{
RegisterAssembly(assemblyDefinition);
}
base.RegisterAssembly(assembly);
}
}
}
24 changes: 17 additions & 7 deletions ILRepack/RepackImporter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
using ILRepacking.Mixins;

namespace ILRepacking
{
Expand Down Expand Up @@ -373,6 +374,10 @@ private void CloneTo(MethodDefinition meth, TypeDefinition type, bool typeJustCr
// use void placeholder as we'll do the return type import later on (after generic parameters)
MethodDefinition nm = new MethodDefinition(meth.Name, meth.Attributes, _repackContext.TargetAssemblyMainModule.TypeSystem.Void);
nm.ImplAttributes = meth.ImplAttributes;
if (meth.DebugInformation.HasCustomDebugInformations)
nm.DebugInformation.CustomDebugInformations.AddRange(meth.DebugInformation.CustomDebugInformations);
if (meth.DebugInformation.HasSequencePoints)
nm.DebugInformation.SequencePoints.AddRange(meth.DebugInformation.SequencePoints);

type.Methods.Add(nm);

Expand Down Expand Up @@ -430,15 +435,13 @@ private void CloneTo(MethodBody body, MethodDefinition parent)
nb.LocalVarToken = body.LocalVarToken;

foreach (VariableDefinition var in body.Variables)
nb.Variables.Add(new VariableDefinition(var.Name,
nb.Variables.Add(new VariableDefinition(
Import(var.VariableType, parent)));

nb.Instructions.SetCapacity(body.Instructions.Count);
_repackContext.LineIndexer.PreMethodBodyRepack(body, parent);
foreach (Instruction instr in body.Instructions)
{
_repackContext.LineIndexer.ProcessMethodBodyInstruction(instr);

Instruction ni;

if (instr.OpCode.Code == Code.Calli)
Expand Down Expand Up @@ -527,11 +530,8 @@ private void CloneTo(MethodBody body, MethodDefinition parent)
default:
throw new InvalidOperationException();
}
ni.SequencePoint = instr.SequencePoint;
nb.Instructions.Add(ni);
}
_repackContext.LineIndexer.PostMethodBodyRepack(parent);

for (int i = 0; i < body.Instructions.Count; i++)
{
Instruction instr = nb.Instructions[i];
Expand Down Expand Up @@ -592,11 +592,21 @@ private TypeDefinition CreateType(TypeDefinition type, Collection<TypeDefinition
// don't copy these twice if UnionMerge==true
// TODO: we can move this down if we chek for duplicates when adding
CopySecurityDeclarations(type.SecurityDeclarations, nt.SecurityDeclarations, nt);
CopyTypeReferences(type.Interfaces, nt.Interfaces, nt);
CopyInterfaces(type.Interfaces, nt.Interfaces, nt);
CopyCustomAttributes(type.CustomAttributes, nt.CustomAttributes, nt);
return nt;
}

private void CopyInterfaces(Collection<InterfaceImplementation> interfaces1, Collection<InterfaceImplementation> interfaces2, TypeDefinition nt)
{
foreach (var iface in interfaces1)
{
var newIface = new InterfaceImplementation(Import(iface.InterfaceType, nt));
CopyCustomAttributes(iface.CustomAttributes, newIface.CustomAttributes, nt);
interfaces2.Add(newIface);
}
}

private MethodDefinition FindMethodInNewType(TypeDefinition nt, MethodDefinition methodDefinition)
{
var ret = _repackContext.ReflectionHelper.FindMethodDefinitionInType(nt, methodDefinition);
Expand Down
2 changes: 1 addition & 1 deletion ILRepack/Steps/XamlResourcePathPatcherStep.cs
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ private void PatchWpfToolkitVersionResourceDictionary(TypeDefinition type)

private void PatchIComponentConnector(TypeDefinition type)
{
if (!type.Interfaces.Any(t => t.FullName == "System.Windows.Markup.IComponentConnector"))
if (!type.Interfaces.Any(t => t.InterfaceType.FullName == "System.Windows.Markup.IComponentConnector"))
return;

var initializeMethod = type.Methods.FirstOrDefault(m =>
Expand Down
2 changes: 1 addition & 1 deletion cecil
Submodule cecil updated 131 files

0 comments on commit 71e0ea4

Please sign in to comment.