Quiet crossgen2 output (#39340)
authorDavid Wrighton <davidwr@microsoft.com>
Wed, 15 Jul 2020 21:43:31 +0000 (14:43 -0700)
committerGitHub <noreply@github.com>
Wed, 15 Jul 2020 21:43:31 +0000 (14:43 -0700)
Crossgen2 currently prints many unnecessary details to the console using strings that are regarded as temporary

- Update the type system exceptions to use descriptive strings instead of [TEMPORARY ERROR MESSAGE]XXX
- Do not print any error when a method isn't compiled due to lack of IL code
  - This is common, and not a failure of any form
- Tie logging of non-compiled methods to the --verbose switch
  - We may wish to provide variable logging levels, but that can easily be done in the future

src/coreclr/src/tools/Common/JitInterface/CorInfoImpl.cs
src/coreclr/src/tools/Common/TypeSystem/Common/Properties/Resources.resx [new file with mode: 0644]
src/coreclr/src/tools/Common/TypeSystem/Common/TypeSystemException.cs
src/coreclr/src/tools/ILVerification/ILVerification.projitems
src/coreclr/src/tools/aot/ILCompiler.ReadyToRun/Compiler/ReadyToRunCodegenCompilation.cs
src/coreclr/src/tools/aot/ILCompiler.ReadyToRun/JitInterface/CorInfoImpl.ReadyToRun.cs
src/coreclr/src/tools/aot/ILCompiler.TypeSystem.ReadyToRun/ILCompiler.TypeSystem.ReadyToRun.csproj

index 88bc3a5f8b938bda82fc2d136f3fce12640ec24f..dea009b035feaf4358b3697e102bb65b8f9f3756 100644 (file)
@@ -135,21 +135,17 @@ namespace Internal.JitInterface
 
         private CORINFO_MODULE_STRUCT_* _methodScope; // Needed to resolve CORINFO_EH_CLAUSE tokens
 
-        private bool _isFallbackBodyCompilation; // True if we're compiling a fallback method body after compiling the real body failed
-
-        private void CompileMethodInternal(IMethodNode methodCodeNodeNeedingCode, MethodIL methodIL = null)
+        private void CompileMethodInternal(IMethodNode methodCodeNodeNeedingCode, MethodIL methodIL)
         {
-            _isFallbackBodyCompilation = methodIL != null;
-
-            CORINFO_METHOD_INFO methodInfo;
-            methodIL = Get_CORINFO_METHOD_INFO(MethodBeingCompiled, methodIL, &methodInfo);
-
-            // This is e.g. an "extern" method in C# without a DllImport or InternalCall.
+            // methodIL must not be null
             if (methodIL == null)
             {
                 ThrowHelper.ThrowInvalidProgramException(ExceptionStringID.InvalidProgramSpecific, MethodBeingCompiled);
             }
 
+            CORINFO_METHOD_INFO methodInfo;
+            Get_CORINFO_METHOD_INFO(MethodBeingCompiled, methodIL, &methodInfo);
+
             _methodScope = methodInfo.scope;
 
 #if !READYTORUN
@@ -428,16 +424,12 @@ namespace Internal.JitInterface
         private FieldDesc HandleToObject(CORINFO_FIELD_STRUCT_* field) { return (FieldDesc)HandleToObject((IntPtr)field); }
         private CORINFO_FIELD_STRUCT_* ObjectToHandle(FieldDesc field) { return (CORINFO_FIELD_STRUCT_*)ObjectToHandle((Object)field); }
 
-        private MethodIL Get_CORINFO_METHOD_INFO(MethodDesc method, MethodIL methodIL, CORINFO_METHOD_INFO* methodInfo)
+        private bool Get_CORINFO_METHOD_INFO(MethodDesc method, MethodIL methodIL, CORINFO_METHOD_INFO* methodInfo)
         {
-            // MethodIL can be provided externally for the case of a method whose IL was replaced because we couldn't compile it.
-            if (methodIL == null)
-                methodIL = _compilation.GetMethodIL(method);
-
             if (methodIL == null)
             {
                 *methodInfo = default(CORINFO_METHOD_INFO);
-                return null;
+                return false;
             }
 
             methodInfo->ftn = ObjectToHandle(method);
@@ -465,7 +457,7 @@ namespace Internal.JitInterface
             Get_CORINFO_SIG_INFO(method, &methodInfo->args);
             Get_CORINFO_SIG_INFO(methodIL.GetLocals(), &methodInfo->locals);
 
-            return methodIL;
+            return true;
         }
 
         private void Get_CORINFO_SIG_INFO(MethodDesc method, CORINFO_SIG_INFO* sig, bool suppressHiddenArgument = false)
@@ -862,8 +854,9 @@ namespace Internal.JitInterface
 
         private bool getMethodInfo(CORINFO_METHOD_STRUCT_* ftn, CORINFO_METHOD_INFO* info)
         {
-            MethodIL methodIL = Get_CORINFO_METHOD_INFO(HandleToObject(ftn), null, info);
-            return methodIL != null;
+            MethodDesc method = HandleToObject(ftn);
+            MethodIL methodIL = _compilation.GetMethodIL(method);
+            return Get_CORINFO_METHOD_INFO(method, methodIL, info);
         }
 
         private CorInfoInline canInline(CORINFO_METHOD_STRUCT_* callerHnd, CORINFO_METHOD_STRUCT_* calleeHnd, ref uint pRestrictions)
@@ -1722,10 +1715,11 @@ namespace Internal.JitInterface
             MethodDesc md = method == null ? MethodBeingCompiled : HandleToObject(method);
             TypeDesc type = fd != null ? fd.OwningType : typeFromContext(context);
 
-            if (_isFallbackBodyCompilation ||
+            if (
 #if READYTORUN
                 IsClassPreInited(type)
 #else
+                _isFallbackBodyCompilation ||
                 !_compilation.HasLazyStaticConstructor(type)
 #endif
                 )
diff --git a/src/coreclr/src/tools/Common/TypeSystem/Common/Properties/Resources.resx b/src/coreclr/src/tools/Common/TypeSystem/Common/Properties/Resources.resx
new file mode 100644 (file)
index 0000000..3681459
--- /dev/null
@@ -0,0 +1,180 @@
+<?xml version="1.0" encoding="utf-8"?>
+<root>
+  <!-- 
+    Microsoft ResX Schema 
+    
+    Version 2.0
+    
+    The primary goals of this format is to allow a simple XML format 
+    that is mostly human readable. The generation and parsing of the 
+    various data types are done through the TypeConverter classes 
+    associated with the data types.
+    
+    Example:
+    
+    ... ado.net/XML headers & schema ...
+    <resheader name="resmimetype">text/microsoft-resx</resheader>
+    <resheader name="version">2.0</resheader>
+    <resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
+    <resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
+    <data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
+    <data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
+    <data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
+        <value>[base64 mime encoded serialized .NET Framework object]</value>
+    </data>
+    <data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
+        <value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
+        <comment>This is a comment</comment>
+    </data>
+                
+    There are any number of "resheader" rows that contain simple 
+    name/value pairs.
+    
+    Each data row contains a name, and value. The row also contains a 
+    type or mimetype. Type corresponds to a .NET class that support 
+    text/value conversion through the TypeConverter architecture. 
+    Classes that don't support this are serialized and stored with the 
+    mimetype set.
+    
+    The mimetype is used for serialized objects, and tells the 
+    ResXResourceReader how to depersist the object. This is currently not 
+    extensible. For a given mimetype the value must be set accordingly:
+    
+    Note - application/x-microsoft.net.object.binary.base64 is the format 
+    that the ResXResourceWriter will generate, however the reader can 
+    read any of the formats listed below.
+    
+    mimetype: application/x-microsoft.net.object.binary.base64
+    value   : The object must be serialized with 
+            : System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
+            : and then encoded with base64 encoding.
+    
+    mimetype: application/x-microsoft.net.object.soap.base64
+    value   : The object must be serialized with 
+            : System.Runtime.Serialization.Formatters.Soap.SoapFormatter
+            : and then encoded with base64 encoding.
+
+    mimetype: application/x-microsoft.net.object.bytearray.base64
+    value   : The object must be serialized into a byte array 
+            : using a System.ComponentModel.TypeConverter
+            : and then encoded with base64 encoding.
+    -->
+  <xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
+    <xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
+    <xsd:element name="root" msdata:IsDataSet="true">
+      <xsd:complexType>
+        <xsd:choice maxOccurs="unbounded">
+          <xsd:element name="metadata">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" />
+              </xsd:sequence>
+              <xsd:attribute name="name" use="required" type="xsd:string" />
+              <xsd:attribute name="type" type="xsd:string" />
+              <xsd:attribute name="mimetype" type="xsd:string" />
+              <xsd:attribute ref="xml:space" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="assembly">
+            <xsd:complexType>
+              <xsd:attribute name="alias" type="xsd:string" />
+              <xsd:attribute name="name" type="xsd:string" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="data">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+                <xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
+              </xsd:sequence>
+              <xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
+              <xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
+              <xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
+              <xsd:attribute ref="xml:space" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="resheader">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+              </xsd:sequence>
+              <xsd:attribute name="name" type="xsd:string" use="required" />
+            </xsd:complexType>
+          </xsd:element>
+        </xsd:choice>
+      </xsd:complexType>
+    </xsd:element>
+  </xsd:schema>
+  <resheader name="resmimetype">
+    <value>text/microsoft-resx</value>
+  </resheader>
+  <resheader name="version">
+    <value>2.0</value>
+  </resheader>
+  <resheader name="reader">
+    <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+  </resheader>
+  <resheader name="writer">
+    <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+  </resheader>
+  <data name="ClassLoadGeneral" xml:space="preserve">
+    <value>Failed to load type '{0}' from assembly '{1}'</value>
+  </data>
+  <data name="ClassLoadBadFormat" xml:space="preserve">
+    <value>Failed to load type '{0}' from assembly '{1}' because the format is invalid</value>
+  </data>
+  <data name="ClassLoadExplicitGeneric" xml:space="preserve">
+    <value>Failed to load type '{0}' from assembly '{1}' because generic types cannot have explicit layout</value>
+  </data>
+  <data name="ClassLoadExplicitLayout" xml:space="preserve">
+    <value>Failed to load type '{0}' from assembly '{1}' because of field offset '{2}'</value>
+  </data>
+  <data name="ClassLoadValueClassTooLarge" xml:space="preserve">
+    <value>Array of type '{0}' from assembly '{1}' cannot be created because base value type is too large</value>
+  </data>
+  <data name="ClassLoadRankTooLarge" xml:space="preserve">
+    <value>'{0}' from assembly '{1}' has too many dimensions</value>
+  </data>
+  <data name="MissingMethod" xml:space="preserve">
+    <value>Missing method '{0}'</value>
+  </data>
+  <data name="MissingField" xml:space="preserve">
+    <value>Missing field '{0}'</value>
+  </data>
+  <data name="FileLoadErrorGeneric" xml:space="preserve">
+    <value>Failed to load assembly '{0}'</value>
+  </data>
+  <data name="InvalidProgramDefault" xml:space="preserve">
+    <value>Invalid IL or CLR metadata</value>
+  </data>
+  <data name="InvalidProgramSpecific" xml:space="preserve">
+    <value>Invalid IL or CLR metadata in '{0}'</value>
+  </data>
+  <data name="InvalidProgramVararg" xml:space="preserve">
+    <value>Vararg call to '{0}' not supported</value>
+  </data>
+  <data name="InvalidProgramCallVirtFinalize" xml:space="preserve">
+    <value>Callvirt of '{0}' not supported</value>
+  </data>
+  <data name="InvalidProgramUnmanagedCallersOnly" xml:space="preserve">
+    <value>UnmanagedCallersOnly method '{0}' cannot be called from managed code</value>
+  </data>
+  <data name="InvalidProgramCallAbstractMethod" xml:space="preserve">
+    <value>Direct call to abstract method '{0}' not allowed</value>
+  </data>
+  <data name="InvalidProgramCallVirtStatic" xml:space="preserve">
+    <value>Callvirt of static method '{0}' not allowed</value>
+  </data>
+  <data name="InvalidProgramNonStaticMethod" xml:space="preserve">
+    <value>UnmanagedCallersOnly attribute specified on non-static method '{0}'</value>
+  </data>
+  <data name="InvalidProgramGenericMethod" xml:space="preserve">
+    <value>UnmanagedCallersOnly attribute specified on generic method '{0}'</value>
+  </data>
+  <data name="InvalidProgramNonBlittableTypes" xml:space="preserve">
+    <value>UnmanagedCallersOnly attribute specified on method with non-blittable parameters '{0}'</value>
+  </data>
+  <data name="BadImageFormatGeneric" xml:space="preserve">
+    <value>The format of a DLL or executable being loaded is invalid</value>
+  </data>
+</root>
\ No newline at end of file
index 331556a6af13787bfe02d8a8b0c2b281cd5d14b4..c9a71236c4daf067d05c5a3306f4cbf5925b162c 100644 (file)
@@ -43,10 +43,53 @@ namespace Internal.TypeSystem
             _arguments = args;
         }
 
+        private static string GetFormatString(ExceptionStringID id)
+        {
+            switch (id)
+            {
+                case ExceptionStringID.ClassLoadGeneral: return SR.ClassLoadGeneral;
+                case ExceptionStringID.ClassLoadBadFormat: return SR.ClassLoadBadFormat;
+                case ExceptionStringID.ClassLoadExplicitGeneric: return SR.ClassLoadExplicitGeneric;
+                case ExceptionStringID.ClassLoadExplicitLayout: return SR.ClassLoadExplicitLayout;
+                case ExceptionStringID.ClassLoadValueClassTooLarge: return SR.ClassLoadValueClassTooLarge;
+                case ExceptionStringID.ClassLoadRankTooLarge: return SR.ClassLoadRankTooLarge;
+                case ExceptionStringID.MissingMethod: return SR.MissingMethod;
+                case ExceptionStringID.MissingField: return SR.MissingField;
+                case ExceptionStringID.InvalidProgramDefault: return SR.InvalidProgramDefault;
+                case ExceptionStringID.InvalidProgramSpecific: return SR.InvalidProgramSpecific;
+                case ExceptionStringID.InvalidProgramVararg: return SR.InvalidProgramVararg;
+                case ExceptionStringID.InvalidProgramCallVirtFinalize: return SR.InvalidProgramCallVirtFinalize;
+                case ExceptionStringID.InvalidProgramUnmanagedCallersOnly: return SR.InvalidProgramUnmanagedCallersOnly;
+                case ExceptionStringID.InvalidProgramCallAbstractMethod: return SR.InvalidProgramCallAbstractMethod;
+                case ExceptionStringID.InvalidProgramCallVirtStatic: return SR.InvalidProgramCallVirtStatic;
+                case ExceptionStringID.InvalidProgramNonStaticMethod: return SR.InvalidProgramNonStaticMethod;
+                case ExceptionStringID.InvalidProgramGenericMethod: return SR.InvalidProgramGenericMethod;
+                case ExceptionStringID.InvalidProgramNonBlittableTypes: return SR.InvalidProgramNonBlittableTypes;
+                case ExceptionStringID.BadImageFormatGeneric: return SR.BadImageFormatGeneric;
+                case ExceptionStringID.FileLoadErrorGeneric: return SR.FileLoadErrorGeneric;
+            }
+#if !DEBUG
+            throw new Exception($"Unknown Exception string id {id}");
+#else
+            return null;
+#endif
+        }
+
         private static string GetExceptionString(ExceptionStringID id, string[] args)
         {
-            // TODO: Share the strings and lookup logic with System.Private.CoreLib.
-            return "[TEMPORARY EXCEPTION MESSAGE] " + id.ToString() + ": " + String.Join(", ", args);
+            string formatString = GetFormatString(id);
+#if !DEBUG
+            try
+            {
+#endif
+                return String.Format(formatString, (object[])args);
+#if !DEBUG
+            }
+            catch
+            {
+                return "[TEMPORARY EXCEPTION MESSAGE] " + id.ToString() + ": " + String.Join(", ", args);
+            }
+#endif
         }
 
         /// <summary>
index 69ee3651a7519270030a6e3e675ddebbf54e46c4..bc5bda42bc03cf57987d1534b411ecf5e1bfa997 100644 (file)
     <EmbeddedResource Include="$(MSBuildThisFileDirectory)Strings.resx">
       <LogicalName>ILVerification.Strings.resources</LogicalName>
     </EmbeddedResource>
+    <EmbeddedResource Include="..\Common\TypeSystem\Common\Properties\Resources.resx">
+      <GenerateSource>true</GenerateSource>
+      <ClassName>Internal.TypeSystem.SR</ClassName>
+    </EmbeddedResource>
   </ItemGroup>
   <PropertyGroup>
     <ToolsCommonPath>$(MSBuildThisFileDirectory)..\Common\</ToolsCommonPath>
index 7062b678245278a92433d88dcb4ec769368f96d4..fcb362db50a6eff0cf860a1ebb14dc659188a340 100644 (file)
@@ -484,15 +484,18 @@ namespace ILCompiler
                     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}");
+                        if (Logger.IsVerbose)
+                            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");
+                        if (Logger.IsVerbose)
+                            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");
+                        if (Logger.IsVerbose)
+                            Logger.Writer.WriteLine($"Warning: Method `{method}` was not compiled because `{ex.Message}` requires runtime JIT");
                     }
                 });
             }
index 3c42b86ccb5776726ba687b9cfee30aa73fe53a9..7388a1d0ef6e076dba2c31f451ea1cae2779af42 100644 (file)
@@ -226,8 +226,12 @@ namespace Internal.JitInterface
             {
                 if (!ShouldSkipCompilation(MethodBeingCompiled))
                 {
-                    CompileMethodInternal(methodCodeNodeNeedingCode);
-                    codeGotPublished = true;
+                    MethodIL methodIL = _compilation.GetMethodIL(MethodBeingCompiled);
+                    if (methodIL != null)
+                    {
+                        CompileMethodInternal(methodCodeNodeNeedingCode, methodIL);
+                        codeGotPublished = true;
+                    }
                 }
             }
             finally
index c6266c64df3b0b13f9868d591bf6ec233448cac0..733bd833c140a70b636d5d8f436638990947971d 100644 (file)
     <GenerateDependencyFile>false</GenerateDependencyFile>
     <Configurations>Debug;Release;Checked</Configurations>
   </PropertyGroup>
+
+  <ItemGroup Label="Embedded Resources">
+    <EmbeddedResource Include="..\..\Common\TypeSystem\Common\Properties\Resources.resx">
+      <GenerateSource>true</GenerateSource>
+      <ClassName>Internal.TypeSystem.SR</ClassName>
+    </EmbeddedResource>
+  </ItemGroup>
+
   <ItemGroup>
     <PackageReference Include="System.IO.MemoryMappedFiles">
       <Version>4.3.0</Version>