Repository: dotnet/runtime
File: src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/ReadyToRunCodegenCompilation.cs (C#)

Code before:
            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 (!CorInfoImpl.ShouldCodeNotBeCompiledIntoFinalImage(InstructionSetSupport, method)
                            && method.IsAsyncCall())
                        {
                            AddNecessaryAsyncReferences(method);
                        }

                        if (!_nodeFactory.CompilationModuleGroup.VersionsWithMethodBody(method))
                            EnsureInstantiationReferencesArePresentForExternalMethod(method);
                    }
                }

                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");


Review comment (suggestion):
The condition calls CorInfoImpl.ShouldCodeNotBeCompiledIntoFinalImage(...) for every method in the loop due to left-to-right evaluation, even though the work is only needed for async-call methods. Consider checking method.IsAsyncCall() first (and only then calling ShouldCodeNotBeCompiledIntoFinalImage) to avoid unnecessary metadata work and reduce the chance of hitting ShouldCodeNotBeCompiledIntoFinalImage assumptions on non-ECMA methods.
```suggestion
                        if (method.IsAsyncCall()
                            && !CorInfoImpl.ShouldCodeNotBeCompiledIntoFinalImage(InstructionSetSupport, method))
```

Code after:
            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 (method.IsAsyncCall()
                            && !CorInfoImpl.ShouldCodeNotBeCompiledIntoFinalImage(InstructionSetSupport, method))
                        {
                            AddNecessaryAsyncReferences(method);
                        }

                        if (!_nodeFactory.CompilationModuleGroup.VersionsWithMethodBody(method))
                            EnsureInstantiationReferencesArePresentForExternalMethod(method);
                    }
                }

                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");