예제 #1
0
        public IEnumerable <MethodWithGCInfo> EnumerateCompiledMethods(EcmaModule moduleToEnumerate, CompiledMethodCategory methodCategory)
        {
            foreach (IMethodNode methodNode in MetadataManager.GetCompiledMethods(moduleToEnumerate, methodCategory))
            {
                MethodDesc       method         = methodNode.Method;
                MethodWithGCInfo methodCodeNode = methodNode as MethodWithGCInfo;
#if DEBUG
                EcmaModule  module      = ((EcmaMethod)method.GetTypicalMethodDefinition()).Module;
                ModuleToken moduleToken = Resolver.GetModuleTokenForMethod(method, throwIfNotFound: true);

                IMethodNode      methodNodeDebug     = MethodEntrypoint(new MethodWithToken(method, moduleToken, constrainedType: null, unboxing: false, context: null), false, false, false);
                MethodWithGCInfo methodCodeNodeDebug = methodNodeDebug as MethodWithGCInfo;
                if (methodCodeNodeDebug == null && methodNodeDebug is DelayLoadMethodImport DelayLoadMethodImport)
                {
                    methodCodeNodeDebug = DelayLoadMethodImport.MethodCodeNode;
                }
                if (methodCodeNodeDebug == null && methodNodeDebug is PrecodeMethodImport precodeMethodImport)
                {
                    methodCodeNodeDebug = precodeMethodImport.MethodCodeNode;
                }
                Debug.Assert(methodCodeNodeDebug == methodCodeNode);
#endif

                if (methodCodeNode != null && !methodCodeNode.IsEmpty)
                {
                    yield return(methodCodeNode);
                }
            }
        }
예제 #2
0
        public IEnumerable <MethodWithGCInfo> EnumerateCompiledMethods(EcmaModule moduleToEnumerate, CompiledMethodCategory methodCategory)
        {
            foreach (IMethodNode methodNode in MetadataManager.GetCompiledMethods(moduleToEnumerate, methodCategory))
            {
                MethodDesc       method         = methodNode.Method;
                MethodWithGCInfo methodCodeNode = methodNode as MethodWithGCInfo;
#if DEBUG
                IMethodNode      methodNodeDebug     = MethodEntrypoint(method);
                MethodWithGCInfo methodCodeNodeDebug = methodNodeDebug as MethodWithGCInfo;
                if (methodCodeNodeDebug == null && methodNodeDebug is LocalMethodImport localMethodImport)
                {
                    methodCodeNodeDebug = localMethodImport.MethodCodeNode;
                }
                if (methodCodeNodeDebug == null && methodNodeDebug is PrecodeMethodImport precodeMethodImport)
                {
                    methodCodeNodeDebug = precodeMethodImport.MethodCodeNode;
                }
                Debug.Assert(methodCodeNodeDebug == methodCodeNode);
#endif

                if (methodCodeNode != null && !methodCodeNode.IsEmpty)
                {
                    yield return(methodCodeNode);
                }
            }
        }
예제 #3
0
        private IMethodNode CreateMethodEntrypoint(TypeAndMethod key)
        {
            MethodWithToken  method = key.Method;
            bool             isInstantiatingStub     = key.IsInstantiatingStub;
            bool             isPrecodeImportRequired = key.IsPrecodeImportRequired;
            MethodDesc       compilableMethod        = method.Method.GetCanonMethodTarget(CanonicalFormKind.Specific);
            MethodWithGCInfo methodWithGCInfo        = null;

            if (CompilationModuleGroup.ContainsMethodBody(compilableMethod, false))
            {
                methodWithGCInfo = CompiledMethodNode(compilableMethod);
            }

            if (isPrecodeImportRequired)
            {
                Debug.Assert(!key.IsJumpableImportRequired);
                return(new PrecodeMethodImport(
                           this,
                           ReadyToRunFixupKind.MethodEntry,
                           method,
                           methodWithGCInfo,
                           isInstantiatingStub));
            }
            else
            {
                return(new DelayLoadMethodImport(
                           this,
                           ReadyToRunFixupKind.MethodEntry,
                           method,
                           methodWithGCInfo,
                           isInstantiatingStub,
                           isJump: key.IsJumpableImportRequired));
            }
        }
예제 #4
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);
            }
        }
예제 #5
0
        private double MethodWithGCInfoToWeight(MethodWithGCInfo method)
        {
            var    profileData = _profileData[method.Method];
            double weight      = 0;

            if (profileData != null)
            {
                weight = profileData.ExclusiveWeight;
            }
            return(weight);
        }
예제 #6
0
 public void PrepareForCompilationRetry(MethodWithGCInfo methodToBeRecompiled, IEnumerable <EcmaMethod> methodsThatNeedILBodies)
 {
     lock (_methodsToRecompile)
     {
         _methodsToRecompile.Add(methodToBeRecompiled);
         foreach (var method in methodsThatNeedILBodies)
         {
             _methodsWhichNeedMutableILBodies.Add(method);
         }
     }
 }
예제 #7
0
        private IMethodNode CreateMethodEntrypointNode(MethodDesc targetMethod, SignatureContext signatureContext, bool isUnboxingStub)
        {
            MethodWithGCInfo localMethod = new MethodWithGCInfo(targetMethod, signatureContext);

            return(new LocalMethodImport(
                       this,
                       ReadyToRunFixupKind.READYTORUN_FIXUP_MethodEntry,
                       localMethod,
                       isUnboxingStub,
                       signatureContext));
        }
예제 #8
0
        public ProfileDataNode ProfileDataNode(MethodWithGCInfo method)
        {
            ProfileDataNode node;

            if (!_profileDataCountsNodes.TryGetValue(method, out node))
            {
                node = new ProfileDataNode(method, Target);
                _profileDataCountsNodes.Add(method, node);
            }
            return(node);
        }
예제 #9
0
        public IEnumerable <MethodWithGCInfo> EnumerateCompiledMethods()
        {
            foreach (MethodDesc method in MetadataManager.GetCompiledMethods())
            {
                IMethodNode      methodNode     = MethodEntrypoint(method);
                MethodWithGCInfo methodCodeNode = methodNode as MethodWithGCInfo;
                if (methodCodeNode == null && methodNode is LocalMethodImport localMethodImport)
                {
                    methodCodeNode = localMethodImport.MethodCodeNode;
                }

                if (methodCodeNode != null && !methodCodeNode.IsEmpty)
                {
                    yield return(methodCodeNode);
                }
            }
        }
예제 #10
0
        private IMethodNode CreateMethodEntrypointNode(MethodWithToken targetMethod, bool isUnboxingStub, bool isInstantiatingStub, SignatureContext signatureContext)
        {
            Debug.Assert(CompilationModuleGroup.ContainsMethodBody(targetMethod.Method, false));

            MethodDesc localMethod = targetMethod.Method.GetCanonMethodTarget(CanonicalFormKind.Specific);

            TypeAndMethod    localMethodKey = new TypeAndMethod(localMethod.OwningType, localMethod, default(ModuleToken), isUnboxingStub: false, isInstantiatingStub: false);
            MethodWithGCInfo localMethodNode;

            if (!_localMethodCache.TryGetValue(localMethodKey, out localMethodNode))
            {
                localMethodNode = new MethodWithGCInfo(localMethod, signatureContext);
                _localMethodCache.Add(localMethodKey, localMethodNode);
            }

            return(localMethodNode);
        }
예제 #11
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");
                    }
                }
            }
        }
예제 #12
0
        private IMethodNode CreateMethodEntrypointNode(MethodWithToken targetMethod, bool isUnboxingStub, bool isInstantiatingStub, SignatureContext signatureContext)
        {
            MethodDesc localMethod = targetMethod.Method.GetCanonMethodTarget(CanonicalFormKind.Specific);

            TypeAndMethod    localMethodKey = new TypeAndMethod(localMethod.OwningType, localMethod, default(ModuleToken), isUnboxingStub: false, isInstantiatingStub: false);
            MethodWithGCInfo localMethodNode;

            if (!_localMethodCache.TryGetValue(localMethodKey, out localMethodNode))
            {
                localMethodNode = new MethodWithGCInfo(localMethod, signatureContext);
                _localMethodCache.Add(localMethodKey, localMethodNode);
            }

            return(new LocalMethodImport(
                       this,
                       ReadyToRunFixupKind.READYTORUN_FIXUP_MethodEntry,
                       targetMethod,
                       localMethodNode,
                       isUnboxingStub,
                       isInstantiatingStub,
                       signatureContext));
        }
예제 #13
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");
                    }
                }
            }
        }
예제 #14
0
 public void AddMethod(MethodWithGCInfo method, ISymbolDefinitionNode symbol)
 {
     _methodSymbolMap.Add(symbol, method);
 }
예제 #15
0
 public ProfileDataNode ProfileData(MethodWithGCInfo method)
 {
     return(_profileDataCountsNodes.GetOrAdd(method));
 }
예제 #16
0
        private List <MethodWithGCInfo> ApplyMethodSort(List <MethodWithGCInfo> methods)
        {
            switch (_methodLayoutAlgorithm)
            {
            case ReadyToRunMethodLayoutAlgorithm.DefaultSort:
                break;

            case ReadyToRunMethodLayoutAlgorithm.ExclusiveWeight:
                methods.MergeSortAllowDuplicates(sortMethodWithGCInfoByWeight);

                int sortMethodWithGCInfoByWeight(MethodWithGCInfo left, MethodWithGCInfo right)
                {
                    return(-MethodWithGCInfoToWeight(left).CompareTo(MethodWithGCInfoToWeight(right)));
                }

                break;

            case ReadyToRunMethodLayoutAlgorithm.HotCold:
                methods.MergeSortAllowDuplicates((MethodWithGCInfo left, MethodWithGCInfo right) => ComputeHotColdRegion(left).CompareTo(ComputeHotColdRegion(right)));

                int ComputeHotColdRegion(MethodWithGCInfo method)
                {
                    return(MethodWithGCInfoToWeight(method) > 0 ? 0 : 1);
                }

                break;

            case ReadyToRunMethodLayoutAlgorithm.HotWarmCold:
                methods.MergeSortAllowDuplicates((MethodWithGCInfo left, MethodWithGCInfo right) => ComputeHotWarmColdRegion(left).CompareTo(ComputeHotWarmColdRegion(right)));

                int ComputeHotWarmColdRegion(MethodWithGCInfo method)
                {
                    double weight = MethodWithGCInfoToWeight(method);

                    // If weight is greater than 128 its probably signicantly used at runtime
                    if (weight > 128)
                    {
                        return(0);
                    }

                    // If weight is less than 128 but greater than 0, then its probably used at startup
                    // or some at runtime, but is less critical than the hot code
                    if (weight > 0)
                    {
                        return(1);
                    }

                    // Methods without weight are probably relatively rarely used
                    return(2);
                };
                break;

            case ReadyToRunMethodLayoutAlgorithm.CallFrequency:
                methods = MethodCallFrequencySort(methods);
                break;

            case ReadyToRunMethodLayoutAlgorithm.PettisHansen:
                methods = PettisHansenSort(methods);
                break;

            case ReadyToRunMethodLayoutAlgorithm.Random:
                Random rand = new Random(0);
                for (int i = 0; i < methods.Count - 1; i++)
                {
                    int j = rand.Next(i, methods.Count);
                    MethodWithGCInfo temp = methods[i];
                    methods[i] = methods[j];
                    methods[j] = temp;
                }
                break;

            default:
                throw new NotImplementedException(_methodLayoutAlgorithm.ToString());
            }

            return(methods);
        }
        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;
            }
        }