Beispiel #1
0
        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>();
        }
Beispiel #2
0
        // 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;
        }
Beispiel #3
0
        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);
                        }
                    }
                }
            }
        }
Beispiel #4
0
 public ThinReader(ThinModel thinModel, ModelReaderOptions options)
 {
     _thinModel = thinModel;
     _options = options;
 }
Beispiel #5
0
        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;
        }
Beispiel #6
0
        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;
        }
Beispiel #7
0
        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
        }