Do not generate PerfMap entries for methods we didn't compile (#85958)
authorMichal Strehovský <MichalStrehovsky@users.noreply.github.com>
Tue, 9 May 2023 11:17:28 +0000 (20:17 +0900)
committerGitHub <noreply@github.com>
Tue, 9 May 2023 11:17:28 +0000 (20:17 +0900)
* Do not generate PerfMap entries for methods we didn't compile

dotnet/installer#16318 is currently blocked due to crossgen2 crash. While Jan (https://github.com/dotnet/installer/pull/16318#issuecomment-1537160058) is totally right that the command line to crossgen2 is garbage, we should try not to crash. Based on the stack we already emitted the PE and PDB. The crash seems to be caused by attempting to include methods that didn't successfully compile in the perfmap (`EnumerateCompilerMethods` has an `IsEmpty` check whereas walking all nodes looking for `MethodWithGCInfo` doesn't check that).

```
Internal.TypeSystem.TypeSystemException+TypeLoadException: Failed to load type 'System.Security.Policy.EvidenceBase' from assembly 'System.Security.AccessControl, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a' [/__w/1/s/src/redist/redist.csproj]
    at Internal.TypeSystem.ThrowHelper.ThrowTypeLoadException(ExceptionStringID, String, String) + 0x39 [/__w/1/s/src/redist/redist.csproj]
    at Internal.TypeSystem.ResolutionFailure.Throw() + 0x99 [/__w/1/s/src/redist/redist.csproj]
    at Internal.TypeSystem.Ecma.EcmaModule.GetObject(EntityHandle, NotFoundBehavior) + 0x8f [/__w/1/s/src/redist/redist.csproj]
    at Internal.TypeSystem.Ecma.EcmaModule.GetType(EntityHandle) + 0x2c [/__w/1/s/src/redist/redist.csproj]
    at Internal.TypeSystem.Ecma.EcmaType.InitializeBaseType() + 0x81 [/__w/1/s/src/redist/redist.csproj]
    at Internal.TypeSystem.Ecma.EcmaType.ComputeTypeFlags(TypeFlags) + 0x48 [/__w/1/s/src/redist/redist.csproj]
    at Internal.TypeSystem.TypeDesc.InitializeTypeFlags(TypeFlags) + 0x1e [/__w/1/s/src/redist/redist.csproj]
    at Internal.TypeSystem.TypeNameFormatter.AppendName(StringBuilder, TypeDesc) + 0x2d [/__w/1/s/src/redist/redist.csproj]
    at ILCompiler.PEWriter.TypeString.AppendName(StringBuilder, ArrayType) + 0x1b [/__w/1/s/src/redist/redist.csproj]
    at Internal.TypeSystem.TypeNameFormatter.FormatName(TypeDesc) + 0x54 [/__w/1/s/src/redist/redist.csproj]
    at ILCompiler.PEWriter.OutputInfoBuilder.FormatMethodName(MethodDesc, TypeNameFormatter) + 0x174 [/__w/1/s/src/redist/redist.csproj]
    at ILCompiler.PEWriter.OutputInfoBuilder.<EnumerateMethods>d__16.MoveNext() + 0x15f [/__w/1/s/src/redist/redist.csproj]
    at ILCompiler.Diagnostics.PerfMapWriter.Write(String, Int32, IEnumerable`1, IEnumerable`1, TargetDetails) + 0x13b [/__w/1/s/src/redist/redist.csproj]
    at ILCompiler.PEWriter.SymbolFileBuilder.SavePerfMap(String, Int32, String) + 0x1ba [/__w/1/s/src/redist/redist.csproj]
    at ILCompiler.DependencyAnalysis.ReadyToRunObjectWriter.EmitPortableExecutable() + 0xa59 [/__w/1/s/src/redist/redist.csproj]
```

This is all based on the stack trace. I didn't validate this fixes the issue (or that it compiles at all) but the fix seems legit to me.

My local workflows are affected by the installer repo break because the runtime repo had a breaking change in CoreLib that is not compatible with existing installer builds. Nobody seems to be doing anything with the failing integration PR, so this is my attempt...

src/coreclr/tools/aot/ILCompiler.ReadyToRun/CodeGen/ReadyToRunObjectWriter.cs

index 623098a..9c57990 100644 (file)
@@ -295,11 +295,12 @@ namespace ILCompiler.DependencyAnalysis
 
                     EmitObjectData(r2rPeBuilder, nodeContents, nodeIndex, name, node.GetSection(_nodeFactory));
                     lastWrittenObjectNode = node;
-
-                    if (_outputInfoBuilder != null && node is MethodWithGCInfo methodNode)
-                    {
-                        _outputInfoBuilder.AddMethod(methodNode, nodeContents.DefinedSymbols[0]);
-                    }
+                }
+                
+                if (_outputInfoBuilder != null)
+                {
+                    foreach (MethodWithGCInfo methodNode in _nodeFactory.EnumerateCompiledMethods())
+                        _outputInfoBuilder.AddMethod(methodNode, methodNode);
                 }
 
                 // Emit cold method nodes to end of execution section.