public MethodIL GetMethodIL(MethodDesc method) { // Flush the cache when it grows too big if (_methodILCache.Count > 1000) { _methodILCache = new ILCache(_methodILCache.ILProvider); } return(_methodILCache.GetOrCreateValue(method).MethodIL); }
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 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"); } }); } if (_methodILCache.Count > 1000) { _methodILCache = new ILCache(_methodILCache.ILProvider, NodeFactory.CompilationModuleGroup); } }
protected Compilation( DependencyAnalyzerBase <NodeFactory> dependencyGraph, NodeFactory nodeFactory, IEnumerable <ICompilationRootProvider> compilationRoots, ILProvider ilProvider, DebugInformationProvider debugInformationProvider, DevirtualizationManager devirtualizationManager, Logger logger) { _dependencyGraph = dependencyGraph; _nodeFactory = nodeFactory; _logger = logger; _debugInformationProvider = debugInformationProvider; _devirtualizationManager = devirtualizationManager; _dependencyGraph.ComputeDependencyRoutine += ComputeDependencyNodeDependencies; NodeFactory.AttachToDependencyGraph(_dependencyGraph); var rootingService = new RootingServiceProvider(dependencyGraph, nodeFactory); foreach (var rootProvider in compilationRoots) { rootProvider.AddCompilationRoots(rootingService); } MetadataType globalModuleGeneratedType = nodeFactory.TypeSystemContext.GeneratedAssembly.GetGlobalModuleType(); _typeGetTypeMethodThunks = new TypeGetTypeMethodThunkCache(globalModuleGeneratedType); _assemblyGetExecutingAssemblyMethodThunks = new AssemblyGetExecutingAssemblyMethodThunkCache(globalModuleGeneratedType); _methodBaseGetCurrentMethodThunks = new MethodBaseGetCurrentMethodThunkCache(); if (!(nodeFactory.InteropStubManager is EmptyInteropStubManager)) { bool?forceLazyPInvokeResolution = null; // TODO: Workaround lazy PInvoke resolution not working with CppCodeGen yet // https://github.com/dotnet/corert/issues/2454 // https://github.com/dotnet/corert/issues/2149 if (nodeFactory.IsCppCodegenTemporaryWorkaround) { forceLazyPInvokeResolution = false; } PInvokeILProvider = new PInvokeILProvider(new PInvokeILEmitterConfiguration(forceLazyPInvokeResolution), nodeFactory.InteropStubManager.InteropStateManager); ilProvider = new CombinedILProvider(ilProvider, PInvokeILProvider); } _methodILCache = new ILCache(ilProvider); }
protected Compilation( DependencyAnalyzerBase <NodeFactory> dependencyGraph, NodeFactory nodeFactory, IEnumerable <ICompilationRootProvider> compilationRoots, ILProvider ilProvider, DebugInformationProvider debugInformationProvider, DevirtualizationManager devirtualizationManager, IInliningPolicy inliningPolicy, Logger logger) { _dependencyGraph = dependencyGraph; _nodeFactory = nodeFactory; _logger = logger; _debugInformationProvider = debugInformationProvider; _devirtualizationManager = devirtualizationManager; _inliningPolicy = inliningPolicy; _dependencyGraph.ComputeDependencyRoutine += ComputeDependencyNodeDependencies; NodeFactory.AttachToDependencyGraph(_dependencyGraph); var rootingService = new RootingServiceProvider(nodeFactory, _dependencyGraph.AddRoot); foreach (var rootProvider in compilationRoots) { rootProvider.AddCompilationRoots(rootingService); } MetadataType globalModuleGeneratedType = nodeFactory.TypeSystemContext.GeneratedAssembly.GetGlobalModuleType(); _typeGetTypeMethodThunks = new TypeGetTypeMethodThunkCache(globalModuleGeneratedType); _assemblyGetExecutingAssemblyMethodThunks = new AssemblyGetExecutingAssemblyMethodThunkCache(globalModuleGeneratedType); _methodBaseGetCurrentMethodThunks = new MethodBaseGetCurrentMethodThunkCache(); PInvokeILProvider = _nodeFactory.InteropStubManager.CreatePInvokeILProvider(); if (PInvokeILProvider != null) { ilProvider = new CombinedILProvider(ilProvider, PInvokeILProvider); } _methodILCache = new ILCache(ilProvider); }
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; } }
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"); } } } }