Ejemplo n.º 1
0
            public ModuleGraphNode GetNode(ModuleDesc module)
            {
                if (_nodes.TryGetValue(module, out ModuleGraphNode result))
                {
                    return(result);
                }

                if (module is EcmaModule ecmaModule)
                {
                    ArrayBuilder <ModuleDesc> referencedAssemblies = new ArrayBuilder <ModuleDesc>();
                    var reader = ecmaModule.MetadataReader;
                    foreach (var assemblyReferenceHandle in reader.AssemblyReferences)
                    {
                        var    assemblyReference = reader.GetAssemblyReference(assemblyReferenceHandle);
                        string assemblyName      = reader.GetString(assemblyReference.Name);

                        try
                        {
                            var reference = module.Context.ResolveAssembly(new System.Reflection.AssemblyName(assemblyName));
                            referencedAssemblies.Add(reference);
                        }
                        catch (TypeSystemException) { }
                    }
                    result = new ModuleGraphNode(this, module, referencedAssemblies.ToArray());
                }
                else
                {
                    result = new ModuleGraphNode(this, module, Array.Empty <ModuleDesc>());
                }

                _nodes.Add(module, result);
                return(result);
            }
Ejemplo n.º 2
0
        public override ObjectData GetData(NodeFactory factory, bool relocsOnly = false)
        {
            // This is a summary node that doesn't introduce dependencies.
            if (relocsOnly)
            {
                return(new ObjectData(Array.Empty <byte>(), Array.Empty <Relocation>(), 1, new ISymbolDefinitionNode[] { this }));
            }

            var modulesWithCctor = new List <ModuleDesc>();

            foreach (var methodNode in factory.MetadataManager.GetCompiledMethodBodies())
            {
                MethodDesc method = methodNode.Method;
                if (method.OwningType is MetadataType mdType &&
                    mdType.IsModuleType && method.IsStaticConstructor)
                {
                    modulesWithCctor.Add(mdType.Module);
                }
            }

            // We have a list of modules with a class constructor.
            // Do a topological sort based on the assembly references of each module.
            // This is an approximation that tries to deal with module initializers that might have
            // dependencies on each other. The spec doesn't guarantee any ordering so this is best effort.
            List <ModuleDesc> sortedModules = new List <ModuleDesc>();

            var graphFactory = new ModuleGraphFactory();

            // This is a list because we want to keep a stable sort order.
            var allModules = new List <ModuleGraphNode>();

            // Seed the graph with the list of modules we're interested in
            foreach (ModuleDesc module in modulesWithCctor)
            {
                allModules.Add(graphFactory.GetNode(module));
            }

            // Expand the graph to include all the nodes in between the interesting ones
            var modulesToExpand = new Queue <ModuleGraphNode>(allModules);

            while (modulesToExpand.Count > 0)
            {
                ModuleGraphNode node = modulesToExpand.Dequeue();
                foreach (var reference in node.Edges)
                {
                    if (!allModules.Contains(reference))
                    {
                        allModules.Add(reference);
                        modulesToExpand.Enqueue(reference);
                    }
                }
            }

            // Now sort the nodes
            //
            // We start with the modules that don't reference any other modules.
            // Then we add modules that reference the modules we already sorted.
            // Etc. until we figured out the order of all modules with a cctor.
            //
            // This might appear counter intuitive (the cctor of the entrypoint module
            // will likely run last), but if the entrypoint module cctor calls into another
            // module that has a cctor, CoreCLR will run that cctor first.
            //
            // If a module doesn't call into other modules with a cctor, it doesn't matter
            // when we sort it. If it does call into one, it should run before.
            var markedModules = new HashSet <ModuleGraphNode>();

            while (sortedModules.Count != modulesWithCctor.Count)
            {
                bool madeProgress = false;

                // Add nodes that have all their dependencies already satisfied.
                foreach (var module in allModules)
                {
                    if (!markedModules.Contains(module) && module.Satisfies(markedModules))
                    {
                        madeProgress = true;
                        markedModules.Add(module);
                        if (modulesWithCctor.Contains(module.Module))
                        {
                            sortedModules.Add(module.Module);
                        }
                    }
                }

                // If we haven't made progress, there's a cycle. Pick the first unmarked node as victim.
                if (!madeProgress)
                {
                    foreach (var module in allModules)
                    {
                        if (!markedModules.Contains(module))
                        {
                            markedModules.Add(module);
                            if (modulesWithCctor.Contains(module.Module))
                            {
                                sortedModules.Add(module.Module);
                            }
                            break;
                        }
                    }
                }
            }

            // The data structure is a flat list of module constructors to call.
            // This is insufficient for the purposes of ordering in the multi-object-module mode.
            // If this mode ever becomes more interesting, we'll need to do the sorting at
            // the time of startup. (Linker likely can't do it, unfortunately.)

            ObjectDataBuilder builder = new ObjectDataBuilder(factory, relocsOnly);

            builder.AddSymbol(this);
            builder.AddSymbol(_endSymbol);

            foreach (var module in sortedModules)
            {
                builder.EmitPointerReloc(factory.MethodEntrypoint(module.GetGlobalModuleType().GetStaticConstructor()));
            }

            var result = builder.ToObjectData();

            _endSymbol.SetSymbolOffset(result.Data.Length);

            return(result);
        }