public ImplementationModel(ThinModel thinModel) { _thinModel = thinModel; _depot = new ClosureDepot(); _rootAssemblies = new Dictionary<IAssembly, ThinAssembly>(); _rootTypes = new Dictionary<INamedTypeDefinition, ThinType>(); _rootTypeForwarders = new Dictionary<IAliasForType, ThinTypeForwarder>(); _rootMembers = new Dictionary<ITypeDefinitionMember, ThinMember>(); _missingMembers = new List<ThinMember>(); }
// Special case: If closureStatus == ApiRoot this will automatically // convert it to ImplRoot for internal types // TODO: Visitor should set status instead of this. public ThinModel ExportModel(IncludeStatus closureStatus) { _closureStatus = closureStatus; int nApiTypes = 0; int nApiTypeForwarders = 0; int nApiMembers = 0; ThinModel thinModel = new ThinModel(_thinModel.Options); Dictionary<String, ThinAssembly> assemblies = new Dictionary<String, ThinAssembly>(_depot.AssembliesClosure.Count); Dictionary<INamedTypeDefinition, ThinType> types = new Dictionary<INamedTypeDefinition, ThinType>(_depot.TypesClosure.Count); foreach (IAssembly assembly in _depot.AssembliesClosure.Values) { ThinAssembly thinAsm = new ThinAssembly(_thinModel, assembly.Name.Value, GetIncludeStatus(assembly), assembly); thinModel.Assemblies.Add(thinAsm.Name, thinAsm); assemblies.Add(assembly.Name.Value, thinAsm); } foreach (INamedTypeDefinition type in _depot.TypesClosure.Values) { IAssembly asm = TypeHelper.GetDefiningUnit(type) as IAssembly; if (asm != null && assemblies.ContainsKey(asm.Name.Value)) { VisibilityOverride vis = VisibilityOverride.None; if (ShouldHideType(type)) vis = VisibilityOverride.Internal; if (closureStatus != IncludeStatus.ApiRoot) { if (TypeIsVisibleInApi(type)) { INamedTypeDefinition curType = type; while (curType != null && curType != Dummy.Type && // TODO: Remove dummy check? CanInclude(curType)) { if (WeHidThisType(curType)) throw new Exception("API closure error! Base type " + curType + " was hidden, but " + type + " is in the public API"); ITypeReference curTypeRef = TypeHelper.BaseClass(curType); curType = curTypeRef != null ? Util.CanonicalizeType(curTypeRef) : null; } } } ThinAssembly declaringAssembly = assemblies[asm.Name.Value]; ThinType thinType = new ThinType(declaringAssembly, Util.FullyQualifiedTypeNameFromType(type), GetIncludeStatus(type), type, vis); declaringAssembly.Types.Add(thinType.Name, thinType); types.Add(type, thinType); if (thinType.IncludeStatus == IncludeStatus.ApiClosure || thinType.IncludeStatus == IncludeStatus.ApiRoot || thinType.IncludeStatus == IncludeStatus.ApiFxInternal) { nApiTypes++; } } else { Console.Error.WriteLine("BclRewriter : warning BR5004 : couldn't find declaring module of type {0} in closure", type); } } foreach (IAliasForType typeForwarder in _depot.TypeForwardersClosure.Values) { // TODO: Why is this getting an immutable copy of the assembly? IAssembly asm = Util.GetDefiningAssembly(typeForwarder); if (asm != null && assemblies.ContainsKey(asm.Name.Value)) { ThinAssembly declaringAssembly = assemblies[asm.Name.Value]; ITypeReference aliasedType = typeForwarder.AliasedType; ThinTypeForwarder thinTypeForwarder = new ThinTypeForwarder(declaringAssembly, Util.GetDefiningAssembly(aliasedType).Name.Value, Util.GetTypeName(aliasedType), GetIncludeStatus(typeForwarder), typeForwarder); declaringAssembly.TypeForwarders.Add(thinTypeForwarder.Key, thinTypeForwarder); if (thinTypeForwarder.IncludeStatus == IncludeStatus.ApiClosure || thinTypeForwarder.IncludeStatus == IncludeStatus.ApiRoot || thinTypeForwarder.IncludeStatus == IncludeStatus.ApiFxInternal) { nApiTypeForwarders++; } } else { Console.Error.WriteLine("BclRewriter : warning BR5001 : couldn't find declaring module of type forwarder {0} in closure", typeForwarder); } } foreach (ITypeDefinitionMember member in _depot.MembersClosure.Keys) { INamedTypeDefinition type = Util.ContainingTypeDefinition(member); if (types.ContainsKey(type)) { ThinType declaringType = types[type]; IncludeStatus status = GetIncludeStatus(member); VisibilityOverride vis = VisibilityOverride.None; if (ShouldHideMember(member)) vis = VisibilityOverride.Internal; if ((type.IsInterface) && TypeIsVisibleInApi(type) && vis == VisibilityOverride.Internal) { throw new Exception(string.Format("Implementation required non-public member on public interface: {0} on {1}. This usually means you added a property to model.xml without adding the corresponding getter or setter.", member.Name, Util.FullyQualifiedTypeNameFromType(member.ContainingType))); } ThinMember thinMember = new ThinMember(declaringType, member, status, vis); declaringType.Members.Add(thinMember.Key, thinMember); if (thinMember.IncludeStatus == IncludeStatus.ApiClosure || thinMember.IncludeStatus == IncludeStatus.ApiRoot || thinMember.IncludeStatus == IncludeStatus.ApiFxInternal) { nApiMembers++; } } else { Console.Error.WriteLine("BclRewriter : warning BR5002 : couldn't find declaring type of member {0} in closure", member); } } foreach (IMethodDefinition method in _depot.MethodsClosure.Values) { INamedTypeDefinition type = Util.ContainingTypeDefinition(method); if (types.ContainsKey(type)) { ThinType declaringType = types[type]; IncludeStatus status = GetIncludeStatus(method); VisibilityOverride vis = VisibilityOverride.None; if (ShouldHideMember(method)) vis = VisibilityOverride.Internal; if ((type.IsInterface) && TypeIsVisibleInApi(type) && vis == VisibilityOverride.Internal) { //throw new Exception(string.Format("WARNING: implementation required non-public member on public interface: {0} on {1}. This usually means you added a property to model.xml without adding the corresponding getter or setter.", // method.Name, // Util.FullyQualifiedTypeNameFromType(method.ContainingType))); } ThinMember thinMember = new ThinMember(declaringType, method, status, vis); if (declaringType.Members.ContainsKey(thinMember.Key)) { throw new Exception(String.Format("Found two members with the same signature: {0}", thinMember.Key)); } declaringType.Members.Add(thinMember.Key, thinMember); if (thinMember.IncludeStatus == IncludeStatus.ApiClosure || thinMember.IncludeStatus == IncludeStatus.ApiRoot || thinMember.IncludeStatus == IncludeStatus.ApiFxInternal) { nApiMembers++; } } else { Console.Error.WriteLine("BclRewriter : warning BR5003 : couldn't find declaring type of method {0} in closure", method); } } foreach (ThinMember thinMember in _missingMembers) { ThinType typeToExtend = types[thinMember.DeclaringType.Metadata]; ThinMember newThinMember = new ThinMember(typeToExtend, thinMember); if (!typeToExtend.Members.ContainsKey(newThinMember.Key)) typeToExtend.Members.Add(newThinMember.Key, newThinMember); } return thinModel; }
private void CombineIncludeStatusWithModel(IncludeStatus targetStatusToAdd, ThinModel otherModel) { // TODO: which one should we keep, the one in this model or the other model? foreach (ThinAssembly assembly in Assemblies.Values) { AssemblyElement newAssembly; if (!otherModel.Assemblies.TryGetValue(assembly.Name, out newAssembly) && (assembly.IncludeStatus == targetStatusToAdd)) { newAssembly = new ThinAssembly(otherModel, assembly); otherModel.Assemblies.Add(newAssembly.Key, newAssembly); } foreach (ThinTypeForwarder typeForwarder in assembly.TypeForwarders.Values) { TypeForwarderElement newTypeForwarder; if (!newAssembly.TypeForwarders.TryGetValue(typeForwarder.Key, out newTypeForwarder) && (typeForwarder.IncludeStatus == targetStatusToAdd)) { newTypeForwarder = new ThinTypeForwarder((ThinAssembly)newAssembly, typeForwarder); newAssembly.TypeForwarders.Add(newTypeForwarder.Key, newTypeForwarder); } } foreach (ThinType type in assembly.Types.Values) { TypeElement newType; if (!newAssembly.Types.TryGetValue(type.Name, out newType) && (type.IncludeStatus == targetStatusToAdd)) { newType = new ThinType((ThinAssembly)newAssembly, type); newAssembly.Types.Add(newType.Key, newType); } foreach (ThinMember member in type.Members.Values) { MemberElement newMember; if (!newType.Members.TryGetValue(member.Key, out newMember) && (member.IncludeStatus == targetStatusToAdd)) { newMember = new ThinMember((ThinType)newType, member); newType.Members.Add(newMember.Key, newMember); } } } } }
public ThinReader(ThinModel thinModel, ModelReaderOptions options) { _thinModel = thinModel; _options = options; }
public ThinAssembly(ThinModel declaringModel, ThinAssembly assyToCopy) { _types = new Dictionary<string, TypeElement>(); _typeForwaders = new Dictionary<string, TypeForwarderElement>(); _assemblyNode = assyToCopy._assemblyNode; _assemblyName = assyToCopy._assemblyName; _includeStatus = assyToCopy._includeStatus; _thinModel = declaringModel; }
public ThinAssembly(ThinModel thinModel, string assemblyName, IncludeStatus includeStatus, IAssembly assemblyNode) { _types = new Dictionary<string, TypeElement>(); _typeForwaders = new Dictionary<string, TypeForwarderElement>(); _assemblyNode = assemblyNode; _assemblyName = assemblyName; _includeStatus = includeStatus; _thinModel = thinModel; }
public static void RunBclRewriter(string[] args) { #region Parse the command-line arguments. if (!Parser.ParseArgumentsWithUsage(args, typeof(Program))) throw new UsageException(); #endregion #region Figure out paths s_assemblyName = Path.GetFullPath(s_assemblyName); // this has to be specified string outputBaseName = null; if (!String.IsNullOrEmpty(s_output)) { s_output = Path.GetFullPath(s_output); outputBaseName = Path.GetFileNameWithoutExtension(s_output); } else { s_output = Path.Combine(Directory.GetCurrentDirectory(), Path.GetFileNameWithoutExtension(s_assemblyName) + ".small" + Path.GetExtension(s_assemblyName)); outputBaseName = s_assemblyName; } string pdbSourceFile = Path.ChangeExtension(s_assemblyName, "pdb"); string outputPdb = Path.ChangeExtension(s_output, "pdb"); string outputFolder = Path.GetDirectoryName(s_output); // if the user wants to do an in-place rewrite, we copy the file to a temp file if (s_output == s_assemblyName) { String tempPath = s_assemblyName + TempExtension; String tempPdbPath = pdbSourceFile + TempExtension; File.Copy(s_assemblyName, tempPath, true); s_assemblyName = tempPath; if (File.Exists(pdbSourceFile)) { File.Copy(pdbSourceFile, tempPdbPath, true); pdbSourceFile = tempPdbPath; } } if (!Directory.Exists(outputFolder)) Directory.CreateDirectory(outputFolder); #endregion #region Load input files HostEnvironment host = new HostEnvironment(new NameTable(), s_assemblyDependencyPaths, s_referencedAssemblies); IAssembly/*?*/ assembly = host.LoadUnitFrom(s_assemblyName) as IAssembly; // TODO: Handle multimodule assemblies if (assembly == null || assembly == Dummy.Assembly) { throw new UsageException(args[0] + " is not a PE file containing a CLR assembly, or an error occurred when loading it."); } if (!File.Exists(s_includeListFile)) { throw new UsageException(String.Format("ERROR: Can't find code model file '{0}'", s_includeListFile)); } ThinModel model = new ThinModel(new ThinnerOptions(host, new AssemblyIdentity[] { assembly.AssemblyIdentity })); model.LoadModel(s_includeListFile, new ModelReaderOptions(s_platform, s_architecture, s_flavor, s_treatFxInternalAsPublic, s_defines)); #endregion #region Calculate api closure. ConsoleTimer.StartTimer("Calculating api closure"); model.LoadMetadataFrom(assembly); ThinModel apiClosure = model.CalculateApiClosure(); if (s_keepTempFiles) apiClosure.SaveModel(Path.ChangeExtension(s_output, ".apiClosure.xml")); ConsoleTimer.EndTimer("Calculating api closure"); #endregion #region Calculate impl closure. ConsoleTimer.StartTimer("Calculating implementation closure"); apiClosure.LoadMetadataFrom(assembly); ThinModel implClosure = apiClosure.CalculateImplementationClosure(true, FieldOptions.KeepAll); if (s_keepTempFiles) implClosure.SaveModel(Path.ChangeExtension(s_output, ".implClosure.xml")); ConsoleTimer.EndTimer("Calculating implementation closure"); #endregion #region Trim. ConsoleTimer.StartTimer("Trimming assembly"); IncludeSet includeSet = new IncludeSet(); includeSet.LoadFrom(implClosure); var copier = new MetadataDeepCopier(host); Assembly copiedAssembly = copier.Copy(assembly); Trimmer trimmer = new Trimmer(includeSet, true, false, true, host, s_removeSerializable); trimmer.RewriteChildren(copiedAssembly); Assembly mutableAssembly = copiedAssembly; assembly = mutableAssembly; ConsoleTimer.EndTimer("Trimming assembly"); #endregion #region Update assembly name. ConsoleTimer.StartTimer("Updating assembly name"); // If the output assembly name is different, update the internal assembly name to match. AssemblyIdentity originalAssemblyIdentity = mutableAssembly.AssemblyIdentity; if (!outputBaseName.Equals(originalAssemblyIdentity.Name.ToString(), StringComparison.OrdinalIgnoreCase)) { mutableAssembly.Name = host.NameTable.GetNameFor(outputBaseName); mutableAssembly.ModuleName = mutableAssembly.Name; } // If we changed the assembly identity, update references to it. if (!mutableAssembly.AssemblyIdentity.Equals(originalAssemblyIdentity)) { trimmer.UpdateAssemblyReferences(originalAssemblyIdentity, mutableAssembly.AssemblyIdentity); } ConsoleTimer.EndTimer("Updating assembly name"); #endregion #region Write out the assembly ConsoleTimer.StartTimer("Writing assembly"); PdbReader pdbReader = null; PdbWriter pdbWriter = null; if (File.Exists(pdbSourceFile)) { Stream pdbStream = File.OpenRead(pdbSourceFile); pdbReader = new PdbReader(pdbStream, host); pdbWriter = new PdbWriter(outputPdb, pdbReader); Console.WriteLine("Writing pdb: {0}", outputPdb); } Console.WriteLine("Writing assembly: {0}", s_output); FileStream file = File.Create(s_output); try { PeWriter.WritePeToStream(assembly, host, file, pdbReader, pdbReader, pdbWriter); } finally { if (file != null) { file.Dispose(); } if (pdbWriter != null) { pdbWriter.Dispose(); } } ConsoleTimer.EndTimer("Writing assembly"); #endregion }