Example #1
0
        internal ReadyToRunCodegenCompilation(
            DependencyAnalyzerBase <NodeFactory> dependencyGraph,
            ReadyToRunCodegenNodeFactory nodeFactory,
            IEnumerable <ICompilationRootProvider> roots,
            ILProvider ilProvider,
            Logger logger,
            DevirtualizationManager devirtualizationManager,
            JitConfigProvider configProvider,
            string inputFilePath,
            IEnumerable <ModuleDesc> modulesBeingInstrumented,
            bool resilient,
            bool generateMapFile,
            int parallelism)
            : base(dependencyGraph, nodeFactory, roots, ilProvider, devirtualizationManager, modulesBeingInstrumented, logger)
        {
            _resilient         = resilient;
            _parallelism       = parallelism;
            _generateMapFile   = generateMapFile;
            NodeFactory        = nodeFactory;
            SymbolNodeFactory  = new ReadyToRunSymbolNodeFactory(nodeFactory);
            _jitConfigProvider = configProvider;

            _inputFilePath = inputFilePath;

            _corInfoImpls = new ConditionalWeakTable <Thread, CorInfoImpl>();
            CorInfoImpl.RegisterJITModule(configProvider);
        }
Example #2
0
        private void CompileSingleMethod(CorInfoImpl corInfo, MethodCodeNode methodCodeNodeNeedingCode)
        {
            MethodDesc method = methodCodeNodeNeedingCode.Method;

            try
            {
                corInfo.CompileMethod(methodCodeNodeNeedingCode);
            }
            catch (TypeSystemException ex)
            {
                // TODO: fail compilation if a switch was passed

                // Try to compile the method again, but with a throwing method body this time.
                MethodIL throwingIL = TypeSystemThrowingILEmitter.EmitIL(method, ex);
                corInfo.CompileMethod(methodCodeNodeNeedingCode, throwingIL);

                // TODO: Log as a warning. For now, just log to the logger; but this needs to
                // have an error code, be supressible, the method name/sig needs to be properly formatted, etc.
                // https://github.com/dotnet/corert/issues/72
                Logger.Writer.WriteLine($"Warning: Method `{method}` will always throw because: {ex.Message}");
            }
            finally
            {
                if (_compilationCountdown != null)
                {
                    _compilationCountdown.Signal();
                }
            }
        }
        public override ObjectData GetData(NodeFactory factory, bool relocsOnly = false)
        {
            if (relocsOnly)
            {
                return(new ObjectData(Array.Empty <byte>(), Array.Empty <Relocation>(), 1, Array.Empty <ISymbolDefinitionNode>()));
            }

            PgoValueEmitter pgoEmitter      = new PgoValueEmitter(_factory.CompilationModuleGroup, _symbolNodeFactory, true);
            NativeWriter    hashtableWriter = new NativeWriter();

            Section         hashtableSection = hashtableWriter.NewSection();
            VertexHashtable vertexHashtable  = new VertexHashtable();

            hashtableSection.Place(vertexHashtable);

            Dictionary <byte[], BlobVertex> uniqueInstrumentationData = new Dictionary <byte[], BlobVertex>(ByteArrayComparer.Instance);

            foreach (MethodDesc method in _instrumentationDataMethods)
            {
                pgoEmitter.Clear();
                PgoProcessor.EncodePgoData(CorInfoImpl.ConvertTypeHandleHistogramsToCompactTypeHistogramFormat(_profileDataManager[method].SchemaData, factory.CompilationModuleGroup), pgoEmitter, false);

                // In composite R2R format, always enforce owning type to let us share generic instantiations among modules
                EcmaMethod  typicalMethod = (EcmaMethod)method.GetTypicalMethodDefinition();
                ModuleToken moduleToken   = new ModuleToken(typicalMethod.Module, typicalMethod.Handle);

                ArraySignatureBuilder signatureBuilder = new ArraySignatureBuilder();
                signatureBuilder.EmitMethodSignature(
                    new MethodWithToken(method, moduleToken, constrainedType: null, unboxing: false, context: null),
                    enforceDefEncoding: true,
                    enforceOwningType: _factory.CompilationModuleGroup.EnforceOwningType(moduleToken.Module),
                    factory.SignatureContext,
                    isInstantiatingStub: false);
                byte[]     signature     = signatureBuilder.ToArray();
                BlobVertex signatureBlob = new BlobVertex(signature);

                byte[]     encodedInstrumentationData = pgoEmitter.ToByteArray();
                BlobVertex instrumentationDataBlob    = null;
                if (!uniqueInstrumentationData.TryGetValue(encodedInstrumentationData, out instrumentationDataBlob))
                {
                    instrumentationDataBlob = new BlobVertex(encodedInstrumentationData);
                    hashtableSection.Place(instrumentationDataBlob);
                    uniqueInstrumentationData.Add(encodedInstrumentationData, instrumentationDataBlob);
                }

                PgoInstrumentedDataWithSignatureBlobVertex pgoDataVertex = new PgoInstrumentedDataWithSignatureBlobVertex(signatureBlob, 0, instrumentationDataBlob);
                hashtableSection.Place(pgoDataVertex);
                vertexHashtable.Append(unchecked ((uint)ReadyToRunHashCode.MethodHashCode(method)), pgoDataVertex);
            }

            MemoryStream hashtableContent = new MemoryStream();

            hashtableWriter.Save(hashtableContent);
            return(new ObjectData(
                       data: hashtableContent.ToArray(),
                       relocs: null,
                       alignment: 8,
                       definedSymbols: new ISymbolDefinitionNode[] { this }));
        }
Example #4
0
        protected override void CompileInternal(string outputFile, ObjectDumper dumper)
        {
            _corInfo = new CorInfoImpl(this, _jitConfigProvider);

            var nodes = _dependencyGraph.MarkedNodeList;

            ObjectWriter.EmitObject(outputFile, nodes, NodeFactory, dumper);
        }
Example #5
0
        protected override void ComputeDependencyNodeDependencies(List <DependencyNodeCore <NodeFactory> > obj)
        {
            using (PerfEventSource.StartStopEvents.JitEvents())
            {
                ParallelOptions options = new ParallelOptions
                {
                    MaxDegreeOfParallelism = _parallelism
                };
                Parallel.ForEach(obj, options, dependency =>
                {
                    MethodWithGCInfo methodCodeNodeNeedingCode = dependency as MethodWithGCInfo;
                    MethodDesc method = methodCodeNodeNeedingCode.Method;

                    if (Logger.IsVerbose)
                    {
                        string methodName = method.ToString();
                        Logger.Writer.WriteLine("Compiling " + methodName);
                    }

                    try
                    {
                        using (PerfEventSource.StartStopEvents.JitMethodEvents())
                        {
                            CorInfoImpl corInfoImpl = _corInfoImpls.GetValue(Thread.CurrentThread, thread => new CorInfoImpl(this));
                            corInfoImpl.CompileMethod(methodCodeNodeNeedingCode);
                        }
                    }
                    catch (TypeSystemException ex)
                    {
                        // If compilation fails, don't emit code for this method. It will be Jitted at runtime
                        if (Logger.IsVerbose)
                        {
                            Logger.Writer.WriteLine($"Warning: Method `{method}` was not compiled because: {ex.Message}");
                        }
                    }
                    catch (RequiresRuntimeJitException ex)
                    {
                        if (Logger.IsVerbose)
                        {
                            Logger.Writer.WriteLine($"Info: Method `{method}` was not compiled because `{ex.Message}` requires runtime JIT");
                        }
                    }
                    catch (CodeGenerationFailedException ex) when(_resilient)
                    {
                        if (Logger.IsVerbose)
                        {
                            Logger.Writer.WriteLine($"Warning: Method `{method}` was not compiled because `{ex.Message}` requires runtime JIT");
                        }
                    }
                });
            }

            if (_methodILCache.Count > 1000)
            {
                _methodILCache = new ILCache(_methodILCache.ILProvider, NodeFactory.CompilationModuleGroup);
            }
        }
Example #6
0
        protected override void ComputeDependencyNodeDependencies(List <DependencyNodeCore <NodeFactory> > obj)
        {
            foreach (DependencyNodeCore <NodeFactory> dependency in obj)
            {
                var methodCodeNodeNeedingCode = dependency as MethodWithGCInfo;
                if (methodCodeNodeNeedingCode == null)
                {
                    // To compute dependencies of the shadow method that tracks dictionary
                    // dependencies we need to ensure there is code for the canonical method body.
                    var dependencyMethod = (ShadowConcreteMethodNode)dependency;
                    methodCodeNodeNeedingCode = (MethodWithGCInfo)dependencyMethod.CanonicalMethodNode;
                }

                // We might have already compiled this method.
                if (methodCodeNodeNeedingCode.StaticDependenciesAreComputed)
                {
                    continue;
                }

                MethodDesc method = methodCodeNodeNeedingCode.Method;
                if (!NodeFactory.CompilationModuleGroup.ContainsMethodBody(method, unboxingStub: false))
                {
                    // Don't drill into methods defined outside of this version bubble
                    continue;
                }

                if (Logger.IsVerbose)
                {
                    string methodName = method.ToString();
                    Logger.Writer.WriteLine("Compiling " + methodName);
                }

                try
                {
                    EcmaModule module = ((EcmaMethod)method.GetTypicalMethodDefinition()).Module;

                    CorInfoImpl perModuleCorInfo;
                    if (!_corInfo.TryGetValue(module, out perModuleCorInfo))
                    {
                        perModuleCorInfo = new CorInfoImpl(this, module, _jitConfigProvider);
                        _corInfo.Add(module, perModuleCorInfo);
                    }

                    perModuleCorInfo.CompileMethod(methodCodeNodeNeedingCode);
                }
                catch (TypeSystemException ex)
                {
                    // If compilation fails, don't emit code for this method. It will be Jitted at runtime
                    Logger.Writer.WriteLine($"Warning: Method `{method}` was not compiled because: {ex.Message}");
                }
                catch (RequiresRuntimeJitException ex)
                {
                    Logger.Writer.WriteLine($"Info: Method `{method}` was not compiled because `{ex.Message}` requires runtime JIT");
                }
            }
        }
Example #7
0
        private void CompileSingleThreaded(List <MethodCodeNode> methodsToCompile)
        {
            CorInfoImpl corInfo = _corinfos.GetValue(Thread.CurrentThread, thread => new CorInfoImpl(this));

            foreach (MethodCodeNode methodCodeNodeNeedingCode in methodsToCompile)
            {
                if (Logger.IsVerbose)
                {
                    Logger.Writer.WriteLine($"Compiling {methodCodeNodeNeedingCode.Method}...");
                }

                CompileSingleMethod(corInfo, methodCodeNodeNeedingCode);
            }
        }
        public override ObjectData GetData(NodeFactory factory, bool relocsOnly = false)
        {
            if (relocsOnly)
            {
                return(new ObjectData(Array.Empty <byte>(), Array.Empty <Relocation>(), 1, Array.Empty <ISymbolDefinitionNode>()));
            }

            PgoValueEmitter pgoEmitter      = new PgoValueEmitter(_factory.CompilationModuleGroup, _symbolNodeFactory, true);
            NativeWriter    hashtableWriter = new NativeWriter();

            Section         hashtableSection = hashtableWriter.NewSection();
            VertexHashtable vertexHashtable  = new VertexHashtable();

            hashtableSection.Place(vertexHashtable);

            Dictionary <byte[], BlobVertex> uniqueInstrumentationData = new Dictionary <byte[], BlobVertex>(ByteArrayComparer.Instance);

            foreach (MethodDesc method in _instrumentationDataMethods)
            {
                pgoEmitter.Clear();
                PgoProcessor.EncodePgoData(CorInfoImpl.ConvertTypeHandleHistogramsToCompactTypeHistogramFormat(_profileDataManager[method].SchemaData, factory.CompilationModuleGroup), pgoEmitter, false);

                byte[]     signature     = InstanceEntryPointTableNode.BuildSignatureForMethodDefinedInModule(method, factory);
                BlobVertex signatureBlob = new BlobVertex(signature);

                byte[]     encodedInstrumentationData = pgoEmitter.ToByteArray();
                BlobVertex instrumentationDataBlob    = null;
                if (!uniqueInstrumentationData.TryGetValue(encodedInstrumentationData, out instrumentationDataBlob))
                {
                    instrumentationDataBlob = new BlobVertex(encodedInstrumentationData);
                    hashtableSection.Place(instrumentationDataBlob);
                    uniqueInstrumentationData.Add(encodedInstrumentationData, instrumentationDataBlob);
                }

                PgoInstrumentedDataWithSignatureBlobVertex pgoDataVertex = new PgoInstrumentedDataWithSignatureBlobVertex(signatureBlob, 0, instrumentationDataBlob);
                hashtableSection.Place(pgoDataVertex);
                vertexHashtable.Append(unchecked ((uint)ReadyToRunHashCode.MethodHashCode(method)), pgoDataVertex);
            }

            MemoryStream hashtableContent = new MemoryStream();

            hashtableWriter.Save(hashtableContent);
            return(new ObjectData(
                       data: hashtableContent.ToArray(),
                       relocs: null,
                       alignment: 8,
                       definedSymbols: new ISymbolDefinitionNode[] { this }));
        }
        internal ReadyToRunCodegenCompilation(
            DependencyAnalyzerBase <NodeFactory> dependencyGraph,
            ReadyToRunCodegenNodeFactory nodeFactory,
            IEnumerable <ICompilationRootProvider> roots,
            ILProvider ilProvider,
            Logger logger,
            DevirtualizationManager devirtualizationManager,
            JitConfigProvider configProvider,
            string inputFilePath,
            IEnumerable <ModuleDesc> modulesBeingInstrumented)
            : base(dependencyGraph, nodeFactory, roots, ilProvider, devirtualizationManager, modulesBeingInstrumented, logger)
        {
            NodeFactory        = nodeFactory;
            SymbolNodeFactory  = new ReadyToRunSymbolNodeFactory(nodeFactory);
            _jitConfigProvider = configProvider;

            _inputFilePath = inputFilePath;
            _corInfo       = new CorInfoImpl(this, _jitConfigProvider);
        }
Example #10
0
        private void CompileSingleMethod(CorInfoImpl corInfo, MethodCodeNode methodCodeNodeNeedingCode)
        {
            try
            {
                MethodDesc method = methodCodeNodeNeedingCode.Method;

                TypeSystemException exception = _methodImportationErrorProvider.GetCompilationError(method);

                // If we previously failed to import the method, do not try to import it again and go
                // directly to the error path.
                if (exception == null)
                {
                    try
                    {
                        corInfo.CompileMethod(methodCodeNodeNeedingCode);
                    }
                    catch (TypeSystemException ex)
                    {
                        exception = ex;
                    }
                }

                if (exception != null)
                {
                    // TODO: fail compilation if a switch was passed

                    // Try to compile the method again, but with a throwing method body this time.
                    MethodIL throwingIL = TypeSystemThrowingILEmitter.EmitIL(method, exception);
                    corInfo.CompileMethod(methodCodeNodeNeedingCode, throwingIL);

                    if (exception is TypeSystemException.InvalidProgramException &&
                        method.OwningType is MetadataType mdOwningType &&
                        mdOwningType.HasCustomAttribute("System.Runtime.InteropServices", "ClassInterfaceAttribute"))
                    {
                        Logger.LogWarning("COM interop is not supported with full ahead of time compilation", 3052, method, MessageSubCategory.AotAnalysis);
                    }
                    else
                    {
                        Logger.LogWarning($"Method will always throw because: {exception.Message}", 1005, method, MessageSubCategory.AotAnalysis);
                    }
                }
            }
Example #11
0
        private void CompileSingleMethod(CorInfoImpl corInfo, MethodCodeNode methodCodeNodeNeedingCode)
        {
            MethodDesc method = methodCodeNodeNeedingCode.Method;

            TypeSystemException exception = _methodImportationErrorProvider.GetCompilationError(method);

            // If we previously failed to import the method, do not try to import it again and go
            // directly to the error path.
            if (exception == null)
            {
                try
                {
                    corInfo.CompileMethod(methodCodeNodeNeedingCode);
                }
                catch (TypeSystemException ex)
                {
                    exception = ex;
                }
            }

            if (exception != null)
            {
                // Try to compile the method again, but with a throwing method body this time.
                MethodIL throwingIL = TypeSystemThrowingILEmitter.EmitIL(method, exception);
                corInfo.CompileMethod(methodCodeNodeNeedingCode, throwingIL);

                if (exception is TypeSystemException.InvalidProgramException &&
                    method.OwningType is MetadataType mdOwningType &&
                    mdOwningType.HasCustomAttribute("System.Runtime.InteropServices", "ClassInterfaceAttribute"))
                {
                    Logger.LogWarning(method, DiagnosticId.COMInteropNotSupportedInFullAOT);
                }
                if ((_compilationOptions & RyuJitCompilationOptions.UseResilience) != 0)
                {
                    Logger.LogMessage($"Method '{method}' will always throw because: {exception.Message}");
                }
                else
                {
                    Logger.LogError($"Method will always throw because: {exception.Message}", 1005, method, MessageSubCategory.AotAnalysis);
                }
            }
        }
Example #12
0
        private void RootMethods(TypeDesc type, string reason, IRootingServiceProvider rootProvider)
        {
            foreach (MethodDesc method in type.GetAllMethods())
            {
                // Skip methods with no IL
                if (method.IsAbstract)
                {
                    continue;
                }

                if (method.IsInternalCall)
                {
                    continue;
                }

                MethodDesc methodToRoot = method;
                if (method.HasInstantiation)
                {
                    methodToRoot = InstantiateIfPossible(method);

                    if (methodToRoot == null)
                    {
                        continue;
                    }
                }

                try
                {
                    if (!CorInfoImpl.ShouldSkipCompilation(method))
                    {
                        CheckCanGenerateMethod(methodToRoot);
                        rootProvider.AddCompilationRoot(methodToRoot, reason);
                    }
                }
                catch (TypeSystemException)
                {
                    // Individual methods can fail to load types referenced in their signatures.
                    // Skip them in library mode since they're not going to be callable.
                    continue;
                }
            }
        }
Example #13
0
        internal ReadyToRunCodegenCompilation(
            DependencyAnalyzerBase <NodeFactory> dependencyGraph,
            ReadyToRunCodegenNodeFactory nodeFactory,
            IEnumerable <ICompilationRootProvider> roots,
            ILProvider ilProvider,
            DebugInformationProvider debugInformationProvider,
            PInvokeILEmitterConfiguration pInvokePolicy,
            Logger logger,
            DevirtualizationManager devirtualizationManager,
            JitConfigProvider configProvider,
            string inputFilePath)
            : base(dependencyGraph, nodeFactory, roots, ilProvider, debugInformationProvider, devirtualizationManager, pInvokePolicy, logger)
        {
            NodeFactory        = nodeFactory;
            SymbolNodeFactory  = new ReadyToRunSymbolNodeFactory(nodeFactory);
            _jitConfigProvider = configProvider;

            _inputFilePath = inputFilePath;
            _corInfo       = new CorInfoImpl(this, _jitConfigProvider);
        }
Example #14
0
        protected override void ComputeDependencyNodeDependencies(List <DependencyNodeCore <NodeFactory> > obj)
        {
            using (PerfEventSource.StartStopEvents.JitEvents())
            {
                ConditionalWeakTable <Thread, CorInfoImpl> cwt = new ConditionalWeakTable <Thread, CorInfoImpl>();
                foreach (DependencyNodeCore <NodeFactory> dependency in obj)
                {
                    MethodWithGCInfo methodCodeNodeNeedingCode = dependency as MethodWithGCInfo;
                    MethodDesc       method = methodCodeNodeNeedingCode.Method;

                    if (Logger.IsVerbose)
                    {
                        string methodName = method.ToString();
                        Logger.Writer.WriteLine("Compiling " + methodName);
                    }

                    try
                    {
                        using (PerfEventSource.StartStopEvents.JitMethodEvents())
                        {
                            CorInfoImpl corInfoImpl = cwt.GetValue(Thread.CurrentThread, thread => new CorInfoImpl(this));
                            corInfoImpl.CompileMethod(methodCodeNodeNeedingCode);
                        }
                    }
                    catch (TypeSystemException ex)
                    {
                        // If compilation fails, don't emit code for this method. It will be Jitted at runtime
                        Logger.Writer.WriteLine($"Warning: Method `{method}` was not compiled because: {ex.Message}");
                    }
                    catch (RequiresRuntimeJitException ex)
                    {
                        Logger.Writer.WriteLine($"Info: Method `{method}` was not compiled because `{ex.Message}` requires runtime JIT");
                    }
                    catch (CodeGenerationFailedException ex) when(_resilient)
                    {
                        Logger.Writer.WriteLine($"Warning: Method `{method}` was not compiled because `{ex.Message}` requires runtime JIT");
                    }
                }
            }
        }
Example #15
0
        private void CompileMultiThreaded(List <MethodCodeNode> methodsToCompile)
        {
            if (Logger.IsVerbose)
            {
                Logger.Writer.WriteLine($"Compiling {methodsToCompile.Count} methods...");
            }

            WaitCallback compileSingleMethodDelegate = m =>
            {
                CorInfoImpl corInfo = _corinfos.GetValue(Thread.CurrentThread, thread => new CorInfoImpl(this));
                CompileSingleMethod(corInfo, (MethodCodeNode)m);
            };

            using (_compilationCountdown = new CountdownEvent(methodsToCompile.Count))
            {
                foreach (MethodCodeNode methodCodeNodeNeedingCode in methodsToCompile)
                {
                    ThreadPool.QueueUserWorkItem(compileSingleMethodDelegate, methodCodeNodeNeedingCode);
                }

                _compilationCountdown.Wait();
                _compilationCountdown = null;
            }
        }
        protected override void ComputeDependencyNodeDependencies(List <DependencyNodeCore <NodeFactory> > obj)
        {
            using (PerfEventSource.StartStopEvents.JitEvents())
            {
                Action <DependencyNodeCore <NodeFactory> > compileOneMethod = (DependencyNodeCore <NodeFactory> dependency) =>
                {
                    MethodWithGCInfo methodCodeNodeNeedingCode = dependency as MethodWithGCInfo;
                    if (methodCodeNodeNeedingCode == null)
                    {
                        if (dependency is DeferredTillPhaseNode deferredPhaseNode)
                        {
                            if (Logger.IsVerbose)
                            {
                                _logger.Writer.WriteLine($"Moved to phase {_nodeFactory.CompilationCurrentPhase}");
                            }
                            deferredPhaseNode.NotifyCurrentPhase(_nodeFactory.CompilationCurrentPhase);
                            return;
                        }
                    }

                    Debug.Assert((_nodeFactory.CompilationCurrentPhase == 0) || ((_nodeFactory.CompilationCurrentPhase == 2) && !_finishedFirstCompilationRunInPhase2));

                    MethodDesc method = methodCodeNodeNeedingCode.Method;

                    if (Logger.IsVerbose)
                    {
                        string methodName = method.ToString();
                        Logger.Writer.WriteLine("Compiling " + methodName);
                    }

                    if (_printReproInstructions != null)
                    {
                        Logger.Writer.WriteLine($"Single method repro args:{_printReproInstructions(method)}");
                    }

                    try
                    {
                        using (PerfEventSource.StartStopEvents.JitMethodEvents())
                        {
                            // Create only 1 CorInfoImpl per thread.
                            // This allows SuperPMI to rely on non-reuse of handles in ObjectToHandle
                            CorInfoImpl corInfoImpl = _corInfoImpls.GetValue(Thread.CurrentThread, thread => new CorInfoImpl(this));
                            corInfoImpl.CompileMethod(methodCodeNodeNeedingCode, Logger);
                        }
                    }
                    catch (TypeSystemException ex)
                    {
                        // If compilation fails, don't emit code for this method. It will be Jitted at runtime
                        if (Logger.IsVerbose)
                        {
                            Logger.Writer.WriteLine($"Warning: Method `{method}` was not compiled because: {ex.Message}");
                        }
                    }
                    catch (RequiresRuntimeJitException ex)
                    {
                        if (Logger.IsVerbose)
                        {
                            Logger.Writer.WriteLine($"Info: Method `{method}` was not compiled because `{ex.Message}` requires runtime JIT");
                        }
                    }
                    catch (CodeGenerationFailedException ex) when(_resilient)
                    {
                        if (Logger.IsVerbose)
                        {
                            Logger.Writer.WriteLine($"Warning: Method `{method}` was not compiled because `{ex.Message}` requires runtime JIT");
                        }
                    }
                };

                // Use only main thread to compile if parallelism is 1. This allows SuperPMI to rely on non-reuse of handles in ObjectToHandle
                if (Logger.IsVerbose)
                {
                    Logger.Writer.WriteLine($"Processing {obj.Count} dependencies");
                }
                if (_parallelism == 1)
                {
                    foreach (var dependency in obj)
                    {
                        compileOneMethod(dependency);
                    }
                }
                else
                {
                    ParallelOptions options = new ParallelOptions
                    {
                        MaxDegreeOfParallelism = _parallelism
                    };

                    Parallel.ForEach(obj, options, compileOneMethod);
                }
            }

            if (_methodILCache.Count > 1000)
            {
                _methodILCache = new ILCache(_methodILCache.ILProvider, NodeFactory.CompilationModuleGroup);
            }

            if (_nodeFactory.CompilationCurrentPhase == 2)
            {
                _finishedFirstCompilationRunInPhase2 = true;
            }
        }
Example #17
0
        public void CompileSingleFile()
        {
            NodeFactory.NameMangler = NameMangler;

            _nodeFactory = new NodeFactory(_typeSystemContext, _typeInitManager, _compilationModuleGroup, _options.IsCppCodeGen);

            // Choose which dependency graph implementation to use based on the amount of logging requested.
            if (_options.DgmlLog == null)
            {
                // No log uses the NoLogStrategy
                _dependencyGraph = new DependencyAnalyzer <NoLogStrategy <NodeFactory>, NodeFactory>(_nodeFactory, null);
            }
            else
            {
                if (_options.FullLog)
                {
                    // Full log uses the full log strategy
                    _dependencyGraph = new DependencyAnalyzer <FullGraphLogStrategy <NodeFactory>, NodeFactory>(_nodeFactory, null);
                }
                else
                {
                    // Otherwise, use the first mark strategy
                    _dependencyGraph = new DependencyAnalyzer <FirstMarkLogStrategy <NodeFactory>, NodeFactory>(_nodeFactory, null);
                }
            }

            _nodeFactory.AttachToDependencyGraph(_dependencyGraph);

            _compilationModuleGroup.AddWellKnownTypes();
            _compilationModuleGroup.AddCompilationRoots();

            if (!_options.IsCppCodeGen && !_options.MultiFile)
            {
                // TODO: build a general purpose way to hook up pieces that would be part of the core library
                //       if factoring of the core library respected how things are, versus how they would be in
                //       a magic world (future customers of this mechanism will be interop and serialization).
                var refExec = _typeSystemContext.GetModuleForSimpleName("System.Private.Reflection.Execution");
                var exec    = refExec.GetKnownType("Internal.Reflection.Execution", "ReflectionExecution");
                AddCompilationRoot(exec.GetStaticConstructor(), "Reflection execution");
            }

            if (_options.IsCppCodeGen)
            {
                _cppWriter = new CppCodeGen.CppWriter(this);

                _dependencyGraph.ComputeDependencyRoutine += CppCodeGenComputeDependencyNodeDependencies;

                var nodes = _dependencyGraph.MarkedNodeList;

                _cppWriter.OutputCode(nodes, _compilationModuleGroup.StartupCodeMain);
            }
            else
            {
                _corInfo = new CorInfoImpl(this);

                _dependencyGraph.ComputeDependencyRoutine += ComputeDependencyNodeDependencies;

                var nodes = _dependencyGraph.MarkedNodeList;

                ObjectWriter.EmitObject(_options.OutputFilePath, nodes, _nodeFactory);
            }

            if (_options.DgmlLog != null)
            {
                using (FileStream dgmlOutput = new FileStream(_options.DgmlLog, FileMode.Create))
                {
                    DgmlWriter.WriteDependencyGraphToStream(dgmlOutput, _dependencyGraph);
                    dgmlOutput.Flush();
                }
            }
        }
Example #18
0
        public void CompileSingleFile()
        {
            NodeFactory.NameMangler = NameMangler;

            _nodeFactory = new NodeFactory(_typeSystemContext, _options.IsCppCodeGen);

            // Choose which dependency graph implementation to use based on the amount of logging requested.
            if (_options.DgmlLog == null)
            {
                // No log uses the NoLogStrategy
                _dependencyGraph = new DependencyAnalyzer <NoLogStrategy <NodeFactory>, NodeFactory>(_nodeFactory, null);
            }
            else
            {
                if (_options.FullLog)
                {
                    // Full log uses the full log strategy
                    _dependencyGraph = new DependencyAnalyzer <FullGraphLogStrategy <NodeFactory>, NodeFactory>(_nodeFactory, null);
                }
                else
                {
                    // Otherwise, use the first mark strategy
                    _dependencyGraph = new DependencyAnalyzer <FirstMarkLogStrategy <NodeFactory>, NodeFactory>(_nodeFactory, null);
                }
            }

            _nodeFactory.AttachToDependencyGraph(_dependencyGraph);

            AddWellKnownTypes();
            AddCompilationRoots();

            if (_options.IsCppCodeGen)
            {
                _cppWriter = new CppCodeGen.CppWriter(this);

                _dependencyGraph.ComputeDependencyRoutine += CppCodeGenComputeDependencyNodeDependencies;

                var nodes = _dependencyGraph.MarkedNodeList;

                _cppWriter.OutputCode(nodes);
            }
            else
            {
                _corInfo = new CorInfoImpl(this);

                _dependencyGraph.ComputeDependencyRoutine += ComputeDependencyNodeDependencies;

                var nodes = _dependencyGraph.MarkedNodeList;

                ObjectWriter.EmitObject(_options.OutputFilePath, nodes, _nodeFactory);
            }

            if (_options.DgmlLog != null)
            {
                using (FileStream dgmlOutput = new FileStream(_options.DgmlLog, FileMode.Create))
                {
                    DgmlWriter.WriteDependencyGraphToStream(dgmlOutput, _dependencyGraph);
                    dgmlOutput.Flush();
                }
            }
        }
Example #19
0
        private void CompileSingleMethod(MethodCodeNode methodCodeNodeNeedingCode)
        {
            CorInfoImpl corInfo = _corinfos.GetValue(Thread.CurrentThread, thread => new CorInfoImpl(this));

            CompileSingleMethod(corInfo, methodCodeNodeNeedingCode);
        }
 // Shutdown the Jit if it has been loaded. This must only be called once per process
 public static void ShutdownJit()
 {
     CorInfoImpl.ShutdownJit();
 }
Example #21
0
        public void AddCompilationRoots(IRootingServiceProvider rootProvider)
        {
            foreach (var method in _profileData)
            {
                try
                {
                    // Validate that this method is fully instantiated
                    if (method.OwningType.IsGenericDefinition || method.OwningType.ContainsSignatureVariables())
                    {
                        continue;
                    }

                    if (method.IsGenericMethodDefinition)
                    {
                        continue;
                    }

                    bool containsSignatureVariables = false;
                    foreach (TypeDesc t in method.Instantiation)
                    {
                        if (t.IsGenericDefinition)
                        {
                            containsSignatureVariables = true;
                            break;
                        }

                        if (t.ContainsSignatureVariables())
                        {
                            containsSignatureVariables = true;
                            break;
                        }
                    }
                    if (containsSignatureVariables)
                    {
                        continue;
                    }

                    if (!CorInfoImpl.ShouldSkipCompilation(method))
                    {
                        CheckCanGenerateMethod(method);
                        rootProvider.AddCompilationRoot(method, "Profile triggered method");
                    }
                }
                catch (TypeSystemException)
                {
                    // Individual methods can fail to load types referenced in their signatures.
                    // Skip them in library mode since they're not going to be callable.
                    continue;
                }
            }

            if (!_profileDrivenPartialNGen)
            {
                foreach (MetadataType type in _module.GetAllTypes())
                {
                    MetadataType typeWithMethods = type;
                    if (type.HasInstantiation)
                    {
                        typeWithMethods = InstantiateIfPossible(type);
                        if (typeWithMethods == null)
                        {
                            continue;
                        }
                    }

                    RootMethods(typeWithMethods, "Library module method", rootProvider);
                }
            }
        }
Example #22
0
        public void CompileSingleFile(MethodDesc mainMethod)
        {
            if (_options.IsCppCodeGen)
            {
                _cppWriter = new CppCodeGen.CppWriter(this);
            }
            else
            {
                _corInfo = new CorInfoImpl(this);
            }

            _mainMethod = mainMethod;

            if (!_options.IsCppCodeGen)
            {
                _nodeFactory            = new NodeFactory(this._typeSystemContext);
                NodeFactory.NameMangler = NameMangler;

                // Choose which dependency graph implementation to use based on the amount of logging requested.
                if (_options.DgmlLog == null)
                {
                    // No log uses the NoLogStrategy
                    _dependencyGraph = new DependencyAnalyzer <NoLogStrategy <NodeFactory>, NodeFactory>(_nodeFactory, null);
                }
                else
                {
                    if (_options.FullLog)
                    {
                        // Full log uses the full log strategy
                        _dependencyGraph = new DependencyAnalyzer <FullGraphLogStrategy <NodeFactory>, NodeFactory>(_nodeFactory, null);
                    }
                    else
                    {
                        // Otherwise, use the first mark strategy
                        _dependencyGraph = new DependencyAnalyzer <FirstMarkLogStrategy <NodeFactory>, NodeFactory>(_nodeFactory, null);
                    }
                }

                _nodeFactory.AttachToDependencyGraph(_dependencyGraph);

                AddWellKnownTypes();
                AddCompilationRoots();

                _dependencyGraph.ComputeDependencyRoutine += ComputeDependencyNodeDependencies;
                var nodes = _dependencyGraph.MarkedNodeList;

                var mainMethodNode = (_mainMethod != null) ? _nodeFactory.MethodEntrypoint(_mainMethod) : null;
                ObjectWriter.EmitObject(OutputPath, nodes, mainMethodNode, _nodeFactory);

                if (_options.DgmlLog != null)
                {
                    using (FileStream dgmlOutput = new FileStream(_options.DgmlLog, FileMode.Create))
                    {
                        DgmlWriter.WriteDependencyGraphToStream(dgmlOutput, _dependencyGraph);
                        dgmlOutput.Flush();
                    }
                }
            }
            else
            {
                AddWellKnownTypes();
                AddCompilationRoots();

                while (_methodsThatNeedsCompilation != null)
                {
                    CompileMethods();

                    ExpandVirtualMethods();
                }

                _cppWriter.OutputCode();
            }
        }
Example #23
0
        protected override void ComputeDependencyNodeDependencies(List <DependencyNodeCore <NodeFactory> > obj)
        {
            using (PerfEventSource.StartStopEvents.JitEvents())
            {
                // Use only main thread to compile if parallelism is 1. This allows SuperPMI to rely on non-reuse of handles in ObjectToHandle
                if (Logger.IsVerbose)
                {
                    Logger.Writer.WriteLine($"Processing {obj.Count} dependencies");
                }

                // Ensure all methods being compiled have assigned tokens. This matters for code from modules from outside of the version bubble
                // as those tokens are dynamically assigned, and for instantiation which depend on tokens outside of the module
                var ilProvider = (ReadyToRunILProvider)_methodILCache.ILProvider;
                obj.MergeSortAllowDuplicates(new SortableDependencyNode.ObjectNodeComparer(CompilerComparer.Instance));
                foreach (var dependency in obj)
                {
                    if (dependency is MethodWithGCInfo methodCodeNodeNeedingCode)
                    {
                        var method = methodCodeNodeNeedingCode.Method;
                        if (method.GetTypicalMethodDefinition() is EcmaMethod ecmaMethod)
                        {
                            if (ilProvider.NeedsCrossModuleInlineableTokens(ecmaMethod) &&
                                !_methodsWhichNeedMutableILBodies.Contains(ecmaMethod) &&
                                CorInfoImpl.IsMethodCompilable(this, methodCodeNodeNeedingCode.Method))
                            {
                                _methodsWhichNeedMutableILBodies.Add(ecmaMethod);
                            }
                        }
                        if (!_nodeFactory.CompilationModuleGroup.VersionsWithMethodBody(method))
                        {
                            // Validate that the typedef tokens for all of the instantiation parameters of the method
                            // have tokens.
                            foreach (var type in method.Instantiation)
                            {
                                EnsureTypeDefTokensAreReady(type);
                            }
                            foreach (var type in method.OwningType.Instantiation)
                            {
                                EnsureTypeDefTokensAreReady(type);
                            }

                            void EnsureTypeDefTokensAreReady(TypeDesc type)
                            {
                                // Type represented by simple element type
                                if (type.IsPrimitive || type.IsVoid || type.IsObject || type.IsString || type.IsTypedReference)
                                {
                                    return;
                                }

                                if (type is EcmaType ecmaType)
                                {
                                    if (!_nodeFactory.Resolver.GetModuleTokenForType(ecmaType, allowDynamicallyCreatedReference: false, throwIfNotFound: false).IsNull)
                                    {
                                        return;
                                    }
                                    try
                                    {
                                        Debug.Assert(_nodeFactory.CompilationModuleGroup.CrossModuleInlineableModule(ecmaType.Module));
                                        _nodeFactory.ManifestMetadataTable._mutableModule.ModuleThatIsCurrentlyTheSourceOfNewReferences
                                            = ecmaType.Module;
                                        if (!_nodeFactory.ManifestMetadataTable._mutableModule.TryGetEntityHandle(ecmaType).HasValue)
                                        {
                                            throw new InternalCompilerErrorException($"Unable to create token to {ecmaType}");
                                        }
                                    }
                                    finally
                                    {
                                        _nodeFactory.ManifestMetadataTable._mutableModule.ModuleThatIsCurrentlyTheSourceOfNewReferences
                                            = null;
                                    }
                                    return;
                                }

                                if (type.HasInstantiation)
                                {
                                    EnsureTypeDefTokensAreReady(type.GetTypeDefinition());

                                    foreach (TypeDesc instParam in type.Instantiation)
                                    {
                                        EnsureTypeDefTokensAreReady(instParam);
                                    }
                                }
                                else if (type.IsParameterizedType)
                                {
                                    EnsureTypeDefTokensAreReady(type.GetParameterType());
                                }
                            }
                        }
                    }
                }

                ProcessMutableMethodBodiesList();
                ResetILCache();
                CompileMethodList(obj);

                while (_methodsToRecompile.Count > 0)
                {
                    ProcessMutableMethodBodiesList();
                    ResetILCache();
                    MethodWithGCInfo[] methodsToRecompile = new MethodWithGCInfo[_methodsToRecompile.Count];
                    _methodsToRecompile.CopyTo(methodsToRecompile);
                    _methodsToRecompile.Clear();
                    Array.Sort(methodsToRecompile, new SortableDependencyNode.ObjectNodeComparer(CompilerComparer.Instance));

                    if (Logger.IsVerbose)
                    {
                        Logger.Writer.WriteLine($"Processing {methodsToRecompile.Length} recompiles");
                    }

                    CompileMethodList(methodsToRecompile);
                }
            }

            ResetILCache();

            if (_nodeFactory.CompilationCurrentPhase == 2)
            {
                _finishedFirstCompilationRunInPhase2 = true;
            }

            void ProcessMutableMethodBodiesList()
            {
                EcmaMethod[] mutableMethodBodyNeedList = new EcmaMethod[_methodsWhichNeedMutableILBodies.Count];
                _methodsWhichNeedMutableILBodies.CopyTo(mutableMethodBodyNeedList);
                _methodsWhichNeedMutableILBodies.Clear();
                TypeSystemComparer      comparer   = TypeSystemComparer.Instance;
                Comparison <EcmaMethod> comparison = (EcmaMethod a, EcmaMethod b) => comparer.Compare(a, b);

                Array.Sort(mutableMethodBodyNeedList, comparison);
                var ilProvider = (ReadyToRunILProvider)_methodILCache.ILProvider;

                foreach (var method in mutableMethodBodyNeedList)
                {
                    ilProvider.CreateCrossModuleInlineableTokensForILBody(method);
                }
            }

            void ResetILCache()
            {
                if (_methodILCache.Count > 1000 || _methodILCache.ILProvider.Version != _methodILCache.ExpectedILProviderVersion)
                {
                    _methodILCache = new ILCache(_methodILCache.ILProvider, NodeFactory.CompilationModuleGroup);
                }
            }

            void CompileMethodList(IEnumerable <DependencyNodeCore <NodeFactory> > methodList)
            {
                // Disable generation of new tokens across the multi-threaded compile
                NodeFactory.ManifestMetadataTable._mutableModule.DisableNewTokens = true;

                if (_parallelism == 1)
                {
                    foreach (var dependency in methodList)
                    {
                        CompileOneMethod(dependency);
                    }
                }
                else
                {
                    ParallelOptions options = new ParallelOptions
                    {
                        MaxDegreeOfParallelism = _parallelism
                    };

                    Parallel.ForEach(methodList, options, CompileOneMethod);
                }

                // Re-enable generation of new tokens after the multi-threaded compile
                NodeFactory.ManifestMetadataTable._mutableModule.DisableNewTokens = false;
            }

            void CompileOneMethod(DependencyNodeCore <NodeFactory> dependency)
            {
                MethodWithGCInfo methodCodeNodeNeedingCode = dependency as MethodWithGCInfo;

                if (methodCodeNodeNeedingCode == null)
                {
                    if (dependency is DeferredTillPhaseNode deferredPhaseNode)
                    {
                        if (Logger.IsVerbose)
                        {
                            _logger.Writer.WriteLine($"Moved to phase {_nodeFactory.CompilationCurrentPhase}");
                        }
                        deferredPhaseNode.NotifyCurrentPhase(_nodeFactory.CompilationCurrentPhase);
                        return;
                    }
                }

                Debug.Assert((_nodeFactory.CompilationCurrentPhase == 0) || ((_nodeFactory.CompilationCurrentPhase == 2) && !_finishedFirstCompilationRunInPhase2));

                MethodDesc method = methodCodeNodeNeedingCode.Method;

                if (Logger.IsVerbose)
                {
                    string methodName = method.ToString();
                    Logger.Writer.WriteLine("Compiling " + methodName);
                }

                if (_printReproInstructions != null)
                {
                    Logger.Writer.WriteLine($"Single method repro args:{_printReproInstructions(method)}");
                }

                try
                {
                    using (PerfEventSource.StartStopEvents.JitMethodEvents())
                    {
                        // Create only 1 CorInfoImpl per thread.
                        // This allows SuperPMI to rely on non-reuse of handles in ObjectToHandle
                        CorInfoImpl corInfoImpl = _corInfoImpls.GetValue(Thread.CurrentThread, thread => new CorInfoImpl(this));
                        corInfoImpl.CompileMethod(methodCodeNodeNeedingCode, Logger);
                    }
                }
                catch (TypeSystemException ex)
                {
                    // If compilation fails, don't emit code for this method. It will be Jitted at runtime
                    if (Logger.IsVerbose)
                    {
                        Logger.Writer.WriteLine($"Warning: Method `{method}` was not compiled because: {ex.Message}");
                    }
                }
                catch (RequiresRuntimeJitException ex)
                {
                    if (Logger.IsVerbose)
                    {
                        Logger.Writer.WriteLine($"Info: Method `{method}` was not compiled because `{ex.Message}` requires runtime JIT");
                    }
                }
                catch (CodeGenerationFailedException ex) when(_resilient)
                {
                    if (Logger.IsVerbose)
                    {
                        Logger.Writer.WriteLine($"Warning: Method `{method}` was not compiled because `{ex.Message}` requires runtime JIT");
                    }
                }
            }
        }
Example #24
0
        public void Compile()
        {
            NodeFactory.NameMangler = NameMangler;

            string systemModuleName = ((IAssemblyDesc)_typeSystemContext.SystemModule).GetName().Name;

            // TODO: just something to get Runtime.Base compiled
            if (systemModuleName != "System.Private.CoreLib")
            {
                NodeFactory.CompilationUnitPrefix = systemModuleName.Replace(".", "_");
            }
            else
            {
                NodeFactory.CompilationUnitPrefix = NameMangler.SanitizeName(Path.GetFileNameWithoutExtension(Options.OutputFilePath));
            }

            if (_options.IsCppCodeGen)
            {
                _nodeFactory = new CppCodegenNodeFactory(_typeSystemContext, _compilationModuleGroup);
            }
            else
            {
                _nodeFactory = new RyuJitNodeFactory(_typeSystemContext, _compilationModuleGroup);
            }

            // Choose which dependency graph implementation to use based on the amount of logging requested.
            if (_options.DgmlLog == null)
            {
                // No log uses the NoLogStrategy
                _dependencyGraph = new DependencyAnalyzer <NoLogStrategy <NodeFactory>, NodeFactory>(_nodeFactory, null);
            }
            else
            {
                if (_options.FullLog)
                {
                    // Full log uses the full log strategy
                    _dependencyGraph = new DependencyAnalyzer <FullGraphLogStrategy <NodeFactory>, NodeFactory>(_nodeFactory, null);
                }
                else
                {
                    // Otherwise, use the first mark strategy
                    _dependencyGraph = new DependencyAnalyzer <FirstMarkLogStrategy <NodeFactory>, NodeFactory>(_nodeFactory, null);
                }
            }

            _nodeFactory.AttachToDependencyGraph(_dependencyGraph);

            if (_options.IsCppCodeGen)
            {
                _cppWriter = new CppCodeGen.CppWriter(this);

                _dependencyGraph.ComputeDependencyRoutine += CppCodeGenComputeDependencyNodeDependencies;

                var nodes = _dependencyGraph.MarkedNodeList;

                _cppWriter.OutputCode(nodes, _compilationModuleGroup.StartupCodeMain, _nodeFactory);
            }
            else
            {
                _corInfo = new CorInfoImpl(this);

                _dependencyGraph.ComputeDependencyRoutine += ComputeDependencyNodeDependencies;

                var nodes = _dependencyGraph.MarkedNodeList;

                ObjectWriter.EmitObject(_options.OutputFilePath, nodes, _nodeFactory);
            }

            if (_options.DgmlLog != null)
            {
                using (FileStream dgmlOutput = new FileStream(_options.DgmlLog, FileMode.Create))
                {
                    DgmlWriter.WriteDependencyGraphToStream(dgmlOutput, _dependencyGraph);
                    dgmlOutput.Flush();
                }
            }
        }
        public override IntPtr OnEntryPoint(MethodEntrypointPtr methodEntrypoint, IntPtr callerArgs)
        {
            lock (this)
            {
                if (_corInfoImpl == null)
                {
                    InitJitCodeManager(RuntimeAugments.RhGetOSModuleForMrt());

                    // TODO: Recycle jit interface object and TypeSystemContext
                    _context = TypeSystemContextFactory.Create();

                    Compilation compilation = new Compilation(_context);
                    _nodeFactory = compilation.NodeFactory;

                    JitConfigProvider configProvider = new JitConfigProvider(new CorJitFlag[] { CorJitFlag.CORJIT_FLAG_DEBUG_CODE }, Array.Empty <KeyValuePair <string, string> >());

                    _corInfoImpl = new CorInfoImpl(compilation, configProvider);
                }

                MethodDesc methodToCompile = methodEntrypoint.MethodIdentifier.ToMethodDesc(_context);

                JitMethodCodeNode codeNode = new JitMethodCodeNode(methodToCompile);
                _corInfoImpl.CompileMethod(codeNode);

                ObjectNode.ObjectData codeData = codeNode.GetData(null, false);

                List <ObjectNode> nodesToEmit = new List <ObjectNode>();
                Dictionary <DependencyNodeCore <NodeFactory>, object> relocTargets = new Dictionary <DependencyNodeCore <NodeFactory>, object>();
                int totalAllocSizeNeeded  = 0;
                int nonObjectRelocTargets = 0;

                nodesToEmit.Add(codeNode);
                UpdateBytesUsed(codeNode.GetData(_nodeFactory), ref totalAllocSizeNeeded);

                int offsetOfEHData = totalAllocSizeNeeded;

                if (codeNode.EHInfo != null)
                {
                    Debug.Assert(codeNode.EHInfo.Alignment == 1); // Assert needed as otherwise offsetOfEHData will be wrong

                    UpdateBytesUsed(codeNode.EHInfo, ref totalAllocSizeNeeded);
                    ComputeDependencySizeAndRelocData(codeNode.EHInfo, relocTargets, nodesToEmit, ref totalAllocSizeNeeded, ref nonObjectRelocTargets);
                }

                for (int i = 0; i < nodesToEmit.Count; i++)
                {
                    ObjectNode objNode = nodesToEmit[i];
                    ComputeDependencySizeAndRelocData(objNode.GetData(_nodeFactory, true), relocTargets, nodesToEmit, ref totalAllocSizeNeeded, ref nonObjectRelocTargets);
                }

                if (nonObjectRelocTargets != 0)
                {
                    totalAllocSizeNeeded = totalAllocSizeNeeded.AlignUp(IntPtr.Size);
                }

                int relocTargetOffsetStart = totalAllocSizeNeeded;

                DependencyNodeCore <NodeFactory>[] relocTargetsArray = new DependencyNodeCore <NodeFactory> [nonObjectRelocTargets];
                {
                    int iRelocTarget = 0;
                    foreach (var relocTarget in relocTargets)
                    {
                        if (!(relocTarget.Key is ObjectNode))
                        {
                            relocTargetsArray[iRelocTarget] = relocTarget.Key;
                            totalAllocSizeNeeded           += IntPtr.Size;
                            iRelocTarget++;
                        }
                    }
                    Debug.Assert(iRelocTarget == nonObjectRelocTargets);
                }

                GenericDictionaryCell[] genDictCells = new GenericDictionaryCell[relocTargetsArray.Length];
                for (int iRelocTarget = 0; iRelocTarget < relocTargetsArray.Length; iRelocTarget++)
                {
                    DependencyNodeCore <NodeFactory> relocTarget = relocTargetsArray[iRelocTarget];
                    GenericDictionaryCell            newCell     = null;

                    if (relocTarget is ExternObjectSymbolNode)
                    {
                        var externObjectSymbolNode = (ExternObjectSymbolNode)relocTarget;
                        var newMethodCell          = externObjectSymbolNode.GetDictionaryCell();
                        newCell = newMethodCell;
                    }

                    if (newCell == null)
                    {
                        Environment.FailFast("Unknown reloc target type");
                    }
                    genDictCells[iRelocTarget] = newCell;
                }

                IntPtr[] relocTargetsAsIntPtr = null;

                TypeLoaderEnvironment.Instance.RunUnderTypeLoaderLock(
                    () =>
                {
                    TypeBuilderApi.ResolveMultipleCells(genDictCells, out relocTargetsAsIntPtr);
                });

                // Layout of allocated memory...
                // ObjectNodes (aligned as appropriate)
                IntPtr pCodeManager;
                IntPtr jittedCode    = AllocJittedCode(checked ((uint)totalAllocSizeNeeded), 8 /* TODO, alignment calculation */, out pCodeManager);
                int    currentOffset = 0;

                foreach (var node in nodesToEmit)
                {
                    ObjectNode.ObjectData objectData = node.GetData(_nodeFactory);
                    EmitAndRelocData(objectData, jittedCode, relocTargetOffsetStart, ref currentOffset, relocTargetsArray, relocTargetsAsIntPtr);

                    // EHInfo doesn't get its own node, but it does get emitted into the stream.
                    if ((node == codeNode) && (codeNode.EHInfo != null))
                    {
                        Debug.Assert(offsetOfEHData == currentOffset);
                        EmitAndRelocData(codeNode.EHInfo, jittedCode, relocTargetOffsetStart, ref currentOffset, relocTargetsArray, relocTargetsAsIntPtr);
                    }
                }

                foreach (IntPtr ptr in relocTargetsAsIntPtr)
                {
                    currentOffset = currentOffset.AlignUp(IntPtr.Size);
                    Marshal.WriteIntPtr(jittedCode, currentOffset, ptr);
                    currentOffset += IntPtr.Size;
                }

                SetEHInfoPtr(pCodeManager, jittedCode, jittedCode + offsetOfEHData);

                IntPtr mainRuntimeFunction = IntPtr.Zero;

                for (int i = 0; i < codeNode.FrameInfos.Length; i++)
                {
                    FrameInfo frame           = codeNode.FrameInfos[i];
                    byte[]    frameData       = frame.BlobData;
                    byte[]    gcInfoData      = Array.Empty <byte>();
                    byte[]    gcInfoDataDeref = frameData;

                    if (i == 0)
                    {
                        // For main function, add the gc info to the data
                        gcInfoDataDeref = gcInfoData = codeNode.GCInfo;
                    }

                    IntPtr publishedFunction = PublishRuntimeFunction(pCodeManager,
                                                                      jittedCode,
                                                                      mainRuntimeFunction,
                                                                      checked ((uint)frame.StartOffset),
                                                                      checked ((uint)frame.EndOffset),
                                                                      frameData,
                                                                      checked ((uint)frameData.Length),
                                                                      gcInfoDataDeref,
                                                                      checked ((uint)gcInfoData.Length));

                    if (i == 0)
                    {
                        mainRuntimeFunction = publishedFunction;
                    }
                }

                if (mainRuntimeFunction != IntPtr.Zero)
                {
                    UpdateRuntimeFunctionTable(pCodeManager);
                }

                methodEntrypoint.MethodCode = jittedCode;

                return(jittedCode);
            }
        }