Tweak crossgen2 so that SuperPMI should work (#42555)
authorDavid Wrighton <davidwr@microsoft.com>
Tue, 22 Sep 2020 17:55:10 +0000 (10:55 -0700)
committerGitHub <noreply@github.com>
Tue, 22 Sep 2020 17:55:10 +0000 (10:55 -0700)
- Remove unneeded getBuiltinClass for CLASSID_ARGUMENT_HANDLE from SuperPMI
- Tweak crossgen2 single threaded compilation to reliably only use exactly 1 for compilation
  - This allows superpmi to rely on the detail that handles are unique.
  - This assumes that superpmi collection is done with the compilation options `--parallelism 1`

src/coreclr/src/ToolBox/superpmi/superpmi-shim-collector/icorjitcompiler.cpp
src/coreclr/src/tools/Common/JitInterface/CorInfoImpl.cs
src/coreclr/src/tools/aot/ILCompiler.ReadyToRun/Compiler/ReadyToRunCodegenCompilation.cs

index e55e709..10bcb3c 100644 (file)
@@ -41,7 +41,6 @@ CorJitResult __stdcall interceptor_ICJC::compileMethod(ICorJitInfo*
     our_ICorJitInfo.getBuiltinClass(CLASSID_FIELD_HANDLE);
     our_ICorJitInfo.getBuiltinClass(CLASSID_METHOD_HANDLE);
     our_ICorJitInfo.getBuiltinClass(CLASSID_STRING);
-    our_ICorJitInfo.getBuiltinClass(CLASSID_ARGUMENT_HANDLE);
     our_ICorJitInfo.getBuiltinClass(CLASSID_RUNTIME_TYPE);
 
 #ifdef fatMC
index 098b49a..ace2a86 100644 (file)
@@ -403,6 +403,8 @@ namespace Internal.JitInterface
 
         private IntPtr ObjectToHandle(Object obj)
         {
+            // SuperPMI relies on the handle returned from this function being stable for the lifetime of the crossgen2 process
+            // If handle deletion is implemented, please update SuperPMI
             IntPtr handle;
             if (!_objectToHandle.TryGetValue(obj, out handle))
             {
index d37c45b..628b356 100644 (file)
@@ -467,11 +467,7 @@ namespace ILCompiler
         {
             using (PerfEventSource.StartStopEvents.JitEvents())
             {
-                ParallelOptions options = new ParallelOptions
-                {
-                    MaxDegreeOfParallelism = _parallelism
-                };
-                Parallel.ForEach(obj, options, dependency =>
+                Action<DependencyNodeCore<NodeFactory>> compileOneMethod = (DependencyNodeCore<NodeFactory> dependency) =>
                 {
                     MethodWithGCInfo methodCodeNodeNeedingCode = dependency as MethodWithGCInfo;
                     MethodDesc method = methodCodeNodeNeedingCode.Method;
@@ -486,6 +482,8 @@ namespace ILCompiler
                     {
                         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);
                         }
@@ -506,7 +504,23 @@ namespace ILCompiler
                         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 (_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)