public static Assembly PruneAssembly(HostEnvironment host, ISlice <MethodReferenceAdaptor, FieldReferenceAdaptor, TypeReferenceAdaptor, IAssemblyReference> slice) { Contract.Requires(host != null); Contract.Requires(slice != null); var newAssemblyName = slice.Name; var originalAssembly = slice.ContainingAssembly.ResolvedAssembly; Contract.Assume(!(originalAssembly is Dummy)); var methodDefsToKeep = new HashSet <uint>(); foreach (var m in slice.Methods) { methodDefsToKeep.Add(m.reference.InternedKey); } var copier = new MetadataDeepCopier(host); var thingsToKeep = new HashSet <object>(); var methodHashAttributes = new Dictionary <IMethodDefinition, MethodHashAttribute>(); var me = new Prune(host, copier, thingsToKeep, methodDefsToKeep, methodHashAttributes); // 1. everything that is specified in the slice should definitely be kept. foreach (var c in slice.Chains) { me.VisitChain(c); } // 2. everything reachable from the initial set of things to keep should be kept Dictionary <IMethodDefinition, uint> contractOffsets; FindReachable.Reachable(host, slice, thingsToKeep, methodDefsToKeep, out contractOffsets); me.contractOffsets = contractOffsets; // 3. copy the original assembly --- entirely! var a_prime = copier.Copy(originalAssembly); var nameTable = host.NameTable; a_prime.ModuleName = nameTable.GetNameFor(newAssemblyName + ".dll"); a_prime.Name = nameTable.GetNameFor(newAssemblyName); var mutableRoot = (RootUnitNamespace)(a_prime.UnitNamespaceRoot); var methodHashAttributeType = DefineMethodHashAttributeType(host, mutableRoot); me.methodHashAttributeCtor = new Microsoft.Cci.MethodReference( host, methodHashAttributeType, CallingConvention.HasThis, host.PlatformType.SystemVoid, host.NameTable.Ctor, 0, me.systemString, me.systemInt); // 4. delete all unwanted things from the mutable copy me.RewriteChildren(a_prime); var remainingTypes = new List <INamedTypeDefinition>(a_prime.AllTypes.Count); // will only shrink remainingTypes.Add(a_prime.AllTypes[0]); // <Module> class is always kept for (int i = 1, n = a_prime.AllTypes.Count; i < n; i++) { var t = a_prime.AllTypes[i]; Contract.Assume(t != null); Contract.Assume(copier.OriginalFor.ContainsKey(t)); var orig = copier.OriginalFor[t]; if (thingsToKeep.Contains(orig)) { remainingTypes.Add(t); } } a_prime.AllTypes = remainingTypes; // do this afterwards so it doesn't get visited. mutableRoot.Members.Add(methodHashAttributeType); a_prime.AllTypes.Add(methodHashAttributeType); return(a_prime); }
public bool WriteSliceToFile(ISlice <MethodReferenceAdaptor, FieldReferenceAdaptor, TypeReferenceAdaptor, IAssemblyReference> slice, string directory, out string dll) { #if TRACE_PERFORMANCE var stopWatch = new Stopwatch(); stopWatch.Start(); #endif var newAssembly = Prune.PruneAssembly(host, slice); #if TRACE_PERFORMANCE Console.WriteLine("Time to prune the assembly: {0}", stopWatch.Elapsed); #endif var errors = ValidateAssembly(host, newAssembly); if (/*errors != null && */ 0 < errors.Count) { #if !DEBUG_SLICE dll = null; return(false); #endif } //Get a PDB reader if there is a PDB file. PdbReader /*?*/ pdbReader = null; string pdbFile = slice.ContainingAssembly.ResolvedAssembly.DebugInformationLocation; if (string.IsNullOrEmpty(pdbFile) || !File.Exists(pdbFile)) { pdbFile = Path.ChangeExtension(slice.ContainingAssembly.ResolvedAssembly.Location, "pdb"); } if (File.Exists(pdbFile)) { using (var pdbStream = File.OpenRead(pdbFile)) { pdbReader = new PdbReader(pdbStream, host); } } using (pdbReader) { ISourceLocationProvider sourceLocationProvider = pdbReader; ILocalScopeProvider localScopeProvider = pdbReader; Contract.Assume(sourceLocationProvider != null, "why??"); if (!MakeSureSliceHasAtLeastMethodSourceLocation(slice, sourceLocationProvider)) { dll = null; return(false); } dll = Path.Combine(directory, slice.Name + ".dll"); #if TRACE_PERFORMANCE stopWatch.Reset(); #endif using (var peStream = File.Create(dll)) { if (pdbReader == null) { PeWriter.WritePeToStream(newAssembly, host, peStream); } else { using (var pdbWriter = new PdbWriter(dll.Replace(".dll", ".pdb"), pdbReader, emitTokenSourceInfo: true)) { PeWriter.WritePeToStream(newAssembly, host, peStream, sourceLocationProvider, localScopeProvider, pdbWriter); } } } #if TRACE_PERFORMANCE Console.WriteLine("Time spent to write on the disk: {0}", stopWatch.Elapsed); #endif } #if !DEBUG_SLICE if (errors != null && 0 < errors.Count) { using (var tw = new StreamWriter(File.Create(Path.Combine(directory, slice.Name + ".errors.txt")))) { // something is performed asynchronously and may not be terminated here, that is wrong! lock (errors) { foreach (var err in errors) { tw.WriteLine(err.Location); foreach (var e in err.Errors) { tw.WriteLine("{0} {1} {2}", e.IsWarning ? "WARNING" : "ERROR ", e.Code, e.Message); } tw.WriteLine(); } } } return(false); } #endif // Can this be checked before writing it out? if (newAssembly.AssemblyReferences.Any(ar => ar.AssemblyIdentity.Equals(slice.ContainingAssembly.AssemblyIdentity))) { } return(true); }
public static Assembly PruneAssembly(HostEnvironment host, ISlice<MethodReferenceAdaptor, FieldReferenceAdaptor, TypeReferenceAdaptor, IAssemblyReference> slice) { Contract.Requires(host != null); Contract.Requires(slice != null); var newAssemblyName = slice.Name; var originalAssembly = slice.ContainingAssembly.ResolvedAssembly; Contract.Assume(!(originalAssembly is Dummy)); var methodDefsToKeep = new HashSet<uint>(); foreach (var m in slice.Methods) { methodDefsToKeep.Add(m.reference.InternedKey); } var copier = new MetadataDeepCopier(host); var thingsToKeep = new HashSet<object>(); var methodHashAttributes = new Dictionary<IMethodDefinition, MethodHashAttribute>(); var me = new Prune(host, copier, thingsToKeep, methodDefsToKeep, methodHashAttributes); // 1. everything that is specified in the slice should definitely be kept. foreach (var c in slice.Chains) { me.VisitChain(c); } // 2. everything reachable from the initial set of things to keep should be kept Dictionary<IMethodDefinition, uint> contractOffsets; FindReachable.Reachable(host, slice, thingsToKeep, methodDefsToKeep, out contractOffsets); me.contractOffsets = contractOffsets; // 3. copy the original assembly --- entirely! var a_prime = copier.Copy(originalAssembly); var nameTable = host.NameTable; a_prime.ModuleName = nameTable.GetNameFor(newAssemblyName + ".dll"); a_prime.Name = nameTable.GetNameFor(newAssemblyName); var mutableRoot = (RootUnitNamespace)(a_prime.UnitNamespaceRoot); var methodHashAttributeType = DefineMethodHashAttributeType(host, mutableRoot); me.methodHashAttributeCtor = new Microsoft.Cci.MethodReference( host, methodHashAttributeType, CallingConvention.HasThis, host.PlatformType.SystemVoid, host.NameTable.Ctor, 0, me.systemString, me.systemInt); // 4. delete all unwanted things from the mutable copy me.RewriteChildren(a_prime); var remainingTypes = new List<INamedTypeDefinition>(a_prime.AllTypes.Count); // will only shrink remainingTypes.Add(a_prime.AllTypes[0]); // <Module> class is always kept for (int i = 1, n = a_prime.AllTypes.Count; i < n; i++) { var t = a_prime.AllTypes[i]; Contract.Assume(t!= null); Contract.Assume(copier.OriginalFor.ContainsKey(t)); var orig = copier.OriginalFor[t]; if (thingsToKeep.Contains(orig)) remainingTypes.Add(t); } a_prime.AllTypes = remainingTypes; // do this afterwards so it doesn't get visited. mutableRoot.Members.Add(methodHashAttributeType); a_prime.AllTypes.Add(methodHashAttributeType); return a_prime; }