public IEnumerable <MethodWithGCInfo> EnumerateCompiledMethods(EcmaModule moduleToEnumerate, CompiledMethodCategory methodCategory) { foreach (IMethodNode methodNode in MetadataManager.GetCompiledMethods(moduleToEnumerate, methodCategory)) { MethodDesc method = methodNode.Method; MethodWithGCInfo methodCodeNode = methodNode as MethodWithGCInfo; #if DEBUG EcmaModule module = ((EcmaMethod)method.GetTypicalMethodDefinition()).Module; ModuleToken moduleToken = Resolver.GetModuleTokenForMethod(method, throwIfNotFound: true); IMethodNode methodNodeDebug = MethodEntrypoint(new MethodWithToken(method, moduleToken, constrainedType: null, unboxing: false, context: null), false, false, false); MethodWithGCInfo methodCodeNodeDebug = methodNodeDebug as MethodWithGCInfo; if (methodCodeNodeDebug == null && methodNodeDebug is DelayLoadMethodImport DelayLoadMethodImport) { methodCodeNodeDebug = DelayLoadMethodImport.MethodCodeNode; } if (methodCodeNodeDebug == null && methodNodeDebug is PrecodeMethodImport precodeMethodImport) { methodCodeNodeDebug = precodeMethodImport.MethodCodeNode; } Debug.Assert(methodCodeNodeDebug == methodCodeNode); #endif if (methodCodeNode != null && !methodCodeNode.IsEmpty) { yield return(methodCodeNode); } } }
public IEnumerable <MethodWithGCInfo> EnumerateCompiledMethods(EcmaModule moduleToEnumerate, CompiledMethodCategory methodCategory) { foreach (IMethodNode methodNode in MetadataManager.GetCompiledMethods(moduleToEnumerate, methodCategory)) { MethodDesc method = methodNode.Method; MethodWithGCInfo methodCodeNode = methodNode as MethodWithGCInfo; #if DEBUG IMethodNode methodNodeDebug = MethodEntrypoint(method); MethodWithGCInfo methodCodeNodeDebug = methodNodeDebug as MethodWithGCInfo; if (methodCodeNodeDebug == null && methodNodeDebug is LocalMethodImport localMethodImport) { methodCodeNodeDebug = localMethodImport.MethodCodeNode; } if (methodCodeNodeDebug == null && methodNodeDebug is PrecodeMethodImport precodeMethodImport) { methodCodeNodeDebug = precodeMethodImport.MethodCodeNode; } Debug.Assert(methodCodeNodeDebug == methodCodeNode); #endif if (methodCodeNode != null && !methodCodeNode.IsEmpty) { yield return(methodCodeNode); } } }
private IMethodNode CreateMethodEntrypoint(TypeAndMethod key) { MethodWithToken method = key.Method; bool isInstantiatingStub = key.IsInstantiatingStub; bool isPrecodeImportRequired = key.IsPrecodeImportRequired; MethodDesc compilableMethod = method.Method.GetCanonMethodTarget(CanonicalFormKind.Specific); MethodWithGCInfo methodWithGCInfo = null; if (CompilationModuleGroup.ContainsMethodBody(compilableMethod, false)) { methodWithGCInfo = CompiledMethodNode(compilableMethod); } if (isPrecodeImportRequired) { Debug.Assert(!key.IsJumpableImportRequired); return(new PrecodeMethodImport( this, ReadyToRunFixupKind.MethodEntry, method, methodWithGCInfo, isInstantiatingStub)); } else { return(new DelayLoadMethodImport( this, ReadyToRunFixupKind.MethodEntry, method, methodWithGCInfo, isInstantiatingStub, isJump: key.IsJumpableImportRequired)); } }
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 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"); } } }); } if (_methodILCache.Count > 1000) { _methodILCache = new ILCache(_methodILCache.ILProvider, NodeFactory.CompilationModuleGroup); } }
private double MethodWithGCInfoToWeight(MethodWithGCInfo method) { var profileData = _profileData[method.Method]; double weight = 0; if (profileData != null) { weight = profileData.ExclusiveWeight; } return(weight); }
public void PrepareForCompilationRetry(MethodWithGCInfo methodToBeRecompiled, IEnumerable <EcmaMethod> methodsThatNeedILBodies) { lock (_methodsToRecompile) { _methodsToRecompile.Add(methodToBeRecompiled); foreach (var method in methodsThatNeedILBodies) { _methodsWhichNeedMutableILBodies.Add(method); } } }
private IMethodNode CreateMethodEntrypointNode(MethodDesc targetMethod, SignatureContext signatureContext, bool isUnboxingStub) { MethodWithGCInfo localMethod = new MethodWithGCInfo(targetMethod, signatureContext); return(new LocalMethodImport( this, ReadyToRunFixupKind.READYTORUN_FIXUP_MethodEntry, localMethod, isUnboxingStub, signatureContext)); }
public ProfileDataNode ProfileDataNode(MethodWithGCInfo method) { ProfileDataNode node; if (!_profileDataCountsNodes.TryGetValue(method, out node)) { node = new ProfileDataNode(method, Target); _profileDataCountsNodes.Add(method, node); } return(node); }
public IEnumerable <MethodWithGCInfo> EnumerateCompiledMethods() { foreach (MethodDesc method in MetadataManager.GetCompiledMethods()) { IMethodNode methodNode = MethodEntrypoint(method); MethodWithGCInfo methodCodeNode = methodNode as MethodWithGCInfo; if (methodCodeNode == null && methodNode is LocalMethodImport localMethodImport) { methodCodeNode = localMethodImport.MethodCodeNode; } if (methodCodeNode != null && !methodCodeNode.IsEmpty) { yield return(methodCodeNode); } } }
private IMethodNode CreateMethodEntrypointNode(MethodWithToken targetMethod, bool isUnboxingStub, bool isInstantiatingStub, SignatureContext signatureContext) { Debug.Assert(CompilationModuleGroup.ContainsMethodBody(targetMethod.Method, false)); MethodDesc localMethod = targetMethod.Method.GetCanonMethodTarget(CanonicalFormKind.Specific); TypeAndMethod localMethodKey = new TypeAndMethod(localMethod.OwningType, localMethod, default(ModuleToken), isUnboxingStub: false, isInstantiatingStub: false); MethodWithGCInfo localMethodNode; if (!_localMethodCache.TryGetValue(localMethodKey, out localMethodNode)) { localMethodNode = new MethodWithGCInfo(localMethod, signatureContext); _localMethodCache.Add(localMethodKey, localMethodNode); } return(localMethodNode); }
protected override void ComputeDependencyNodeDependencies(List <DependencyNodeCore <NodeFactory> > obj) { using (PerfEventSource.StartStopEvents.JitEvents()) { ConditionalWeakTable <Thread, CorInfoImpl> cwt = new ConditionalWeakTable <Thread, CorInfoImpl>(); foreach (DependencyNodeCore <NodeFactory> dependency in obj) { 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 = cwt.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"); } } } }
private IMethodNode CreateMethodEntrypointNode(MethodWithToken targetMethod, bool isUnboxingStub, bool isInstantiatingStub, SignatureContext signatureContext) { MethodDesc localMethod = targetMethod.Method.GetCanonMethodTarget(CanonicalFormKind.Specific); TypeAndMethod localMethodKey = new TypeAndMethod(localMethod.OwningType, localMethod, default(ModuleToken), isUnboxingStub: false, isInstantiatingStub: false); MethodWithGCInfo localMethodNode; if (!_localMethodCache.TryGetValue(localMethodKey, out localMethodNode)) { localMethodNode = new MethodWithGCInfo(localMethod, signatureContext); _localMethodCache.Add(localMethodKey, localMethodNode); } return(new LocalMethodImport( this, ReadyToRunFixupKind.READYTORUN_FIXUP_MethodEntry, targetMethod, localMethodNode, isUnboxingStub, isInstantiatingStub, signatureContext)); }
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"); } } } }
public void AddMethod(MethodWithGCInfo method, ISymbolDefinitionNode symbol) { _methodSymbolMap.Add(symbol, method); }
public ProfileDataNode ProfileData(MethodWithGCInfo method) { return(_profileDataCountsNodes.GetOrAdd(method)); }
private List <MethodWithGCInfo> ApplyMethodSort(List <MethodWithGCInfo> methods) { switch (_methodLayoutAlgorithm) { case ReadyToRunMethodLayoutAlgorithm.DefaultSort: break; case ReadyToRunMethodLayoutAlgorithm.ExclusiveWeight: methods.MergeSortAllowDuplicates(sortMethodWithGCInfoByWeight); int sortMethodWithGCInfoByWeight(MethodWithGCInfo left, MethodWithGCInfo right) { return(-MethodWithGCInfoToWeight(left).CompareTo(MethodWithGCInfoToWeight(right))); } break; case ReadyToRunMethodLayoutAlgorithm.HotCold: methods.MergeSortAllowDuplicates((MethodWithGCInfo left, MethodWithGCInfo right) => ComputeHotColdRegion(left).CompareTo(ComputeHotColdRegion(right))); int ComputeHotColdRegion(MethodWithGCInfo method) { return(MethodWithGCInfoToWeight(method) > 0 ? 0 : 1); } break; case ReadyToRunMethodLayoutAlgorithm.HotWarmCold: methods.MergeSortAllowDuplicates((MethodWithGCInfo left, MethodWithGCInfo right) => ComputeHotWarmColdRegion(left).CompareTo(ComputeHotWarmColdRegion(right))); int ComputeHotWarmColdRegion(MethodWithGCInfo method) { double weight = MethodWithGCInfoToWeight(method); // If weight is greater than 128 its probably signicantly used at runtime if (weight > 128) { return(0); } // If weight is less than 128 but greater than 0, then its probably used at startup // or some at runtime, but is less critical than the hot code if (weight > 0) { return(1); } // Methods without weight are probably relatively rarely used return(2); }; break; case ReadyToRunMethodLayoutAlgorithm.CallFrequency: methods = MethodCallFrequencySort(methods); break; case ReadyToRunMethodLayoutAlgorithm.PettisHansen: methods = PettisHansenSort(methods); break; case ReadyToRunMethodLayoutAlgorithm.Random: Random rand = new Random(0); for (int i = 0; i < methods.Count - 1; i++) { int j = rand.Next(i, methods.Count); MethodWithGCInfo temp = methods[i]; methods[i] = methods[j]; methods[j] = temp; } break; default: throw new NotImplementedException(_methodLayoutAlgorithm.ToString()); } return(methods); }
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; } }