internal ReadyToRunCodegenCompilation( DependencyAnalyzerBase <NodeFactory> dependencyGraph, ReadyToRunCodegenNodeFactory nodeFactory, IEnumerable <ICompilationRootProvider> roots, ILProvider ilProvider, Logger logger, DevirtualizationManager devirtualizationManager, JitConfigProvider configProvider, string inputFilePath, IEnumerable <ModuleDesc> modulesBeingInstrumented, bool resilient, bool generateMapFile, int parallelism) : base(dependencyGraph, nodeFactory, roots, ilProvider, devirtualizationManager, modulesBeingInstrumented, logger) { _resilient = resilient; _parallelism = parallelism; _generateMapFile = generateMapFile; NodeFactory = nodeFactory; SymbolNodeFactory = new ReadyToRunSymbolNodeFactory(nodeFactory); _jitConfigProvider = configProvider; _inputFilePath = inputFilePath; _corInfoImpls = new ConditionalWeakTable <Thread, CorInfoImpl>(); CorInfoImpl.RegisterJITModule(configProvider); }
private void CompileSingleMethod(CorInfoImpl corInfo, MethodCodeNode methodCodeNodeNeedingCode) { MethodDesc method = methodCodeNodeNeedingCode.Method; try { corInfo.CompileMethod(methodCodeNodeNeedingCode); } catch (TypeSystemException ex) { // TODO: fail compilation if a switch was passed // Try to compile the method again, but with a throwing method body this time. MethodIL throwingIL = TypeSystemThrowingILEmitter.EmitIL(method, ex); corInfo.CompileMethod(methodCodeNodeNeedingCode, throwingIL); // TODO: Log as a warning. For now, just log to the logger; but this needs to // have an error code, be supressible, the method name/sig needs to be properly formatted, etc. // https://github.com/dotnet/corert/issues/72 Logger.Writer.WriteLine($"Warning: Method `{method}` will always throw because: {ex.Message}"); } finally { if (_compilationCountdown != null) { _compilationCountdown.Signal(); } } }
public override ObjectData GetData(NodeFactory factory, bool relocsOnly = false) { if (relocsOnly) { return(new ObjectData(Array.Empty <byte>(), Array.Empty <Relocation>(), 1, Array.Empty <ISymbolDefinitionNode>())); } PgoValueEmitter pgoEmitter = new PgoValueEmitter(_factory.CompilationModuleGroup, _symbolNodeFactory, true); NativeWriter hashtableWriter = new NativeWriter(); Section hashtableSection = hashtableWriter.NewSection(); VertexHashtable vertexHashtable = new VertexHashtable(); hashtableSection.Place(vertexHashtable); Dictionary <byte[], BlobVertex> uniqueInstrumentationData = new Dictionary <byte[], BlobVertex>(ByteArrayComparer.Instance); foreach (MethodDesc method in _instrumentationDataMethods) { pgoEmitter.Clear(); PgoProcessor.EncodePgoData(CorInfoImpl.ConvertTypeHandleHistogramsToCompactTypeHistogramFormat(_profileDataManager[method].SchemaData, factory.CompilationModuleGroup), pgoEmitter, false); // In composite R2R format, always enforce owning type to let us share generic instantiations among modules EcmaMethod typicalMethod = (EcmaMethod)method.GetTypicalMethodDefinition(); ModuleToken moduleToken = new ModuleToken(typicalMethod.Module, typicalMethod.Handle); ArraySignatureBuilder signatureBuilder = new ArraySignatureBuilder(); signatureBuilder.EmitMethodSignature( new MethodWithToken(method, moduleToken, constrainedType: null, unboxing: false, context: null), enforceDefEncoding: true, enforceOwningType: _factory.CompilationModuleGroup.EnforceOwningType(moduleToken.Module), factory.SignatureContext, isInstantiatingStub: false); byte[] signature = signatureBuilder.ToArray(); BlobVertex signatureBlob = new BlobVertex(signature); byte[] encodedInstrumentationData = pgoEmitter.ToByteArray(); BlobVertex instrumentationDataBlob = null; if (!uniqueInstrumentationData.TryGetValue(encodedInstrumentationData, out instrumentationDataBlob)) { instrumentationDataBlob = new BlobVertex(encodedInstrumentationData); hashtableSection.Place(instrumentationDataBlob); uniqueInstrumentationData.Add(encodedInstrumentationData, instrumentationDataBlob); } PgoInstrumentedDataWithSignatureBlobVertex pgoDataVertex = new PgoInstrumentedDataWithSignatureBlobVertex(signatureBlob, 0, instrumentationDataBlob); hashtableSection.Place(pgoDataVertex); vertexHashtable.Append(unchecked ((uint)ReadyToRunHashCode.MethodHashCode(method)), pgoDataVertex); } MemoryStream hashtableContent = new MemoryStream(); hashtableWriter.Save(hashtableContent); return(new ObjectData( data: hashtableContent.ToArray(), relocs: null, alignment: 8, definedSymbols: new ISymbolDefinitionNode[] { this })); }
protected override void CompileInternal(string outputFile, ObjectDumper dumper) { _corInfo = new CorInfoImpl(this, _jitConfigProvider); var nodes = _dependencyGraph.MarkedNodeList; ObjectWriter.EmitObject(outputFile, nodes, NodeFactory, dumper); }
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); } }
protected override void ComputeDependencyNodeDependencies(List <DependencyNodeCore <NodeFactory> > obj) { foreach (DependencyNodeCore <NodeFactory> dependency in obj) { var methodCodeNodeNeedingCode = dependency as MethodWithGCInfo; if (methodCodeNodeNeedingCode == null) { // To compute dependencies of the shadow method that tracks dictionary // dependencies we need to ensure there is code for the canonical method body. var dependencyMethod = (ShadowConcreteMethodNode)dependency; methodCodeNodeNeedingCode = (MethodWithGCInfo)dependencyMethod.CanonicalMethodNode; } // We might have already compiled this method. if (methodCodeNodeNeedingCode.StaticDependenciesAreComputed) { continue; } MethodDesc method = methodCodeNodeNeedingCode.Method; if (!NodeFactory.CompilationModuleGroup.ContainsMethodBody(method, unboxingStub: false)) { // Don't drill into methods defined outside of this version bubble continue; } if (Logger.IsVerbose) { string methodName = method.ToString(); Logger.Writer.WriteLine("Compiling " + methodName); } try { EcmaModule module = ((EcmaMethod)method.GetTypicalMethodDefinition()).Module; CorInfoImpl perModuleCorInfo; if (!_corInfo.TryGetValue(module, out perModuleCorInfo)) { perModuleCorInfo = new CorInfoImpl(this, module, _jitConfigProvider); _corInfo.Add(module, perModuleCorInfo); } perModuleCorInfo.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"); } } }
private void CompileSingleThreaded(List <MethodCodeNode> methodsToCompile) { CorInfoImpl corInfo = _corinfos.GetValue(Thread.CurrentThread, thread => new CorInfoImpl(this)); foreach (MethodCodeNode methodCodeNodeNeedingCode in methodsToCompile) { if (Logger.IsVerbose) { Logger.Writer.WriteLine($"Compiling {methodCodeNodeNeedingCode.Method}..."); } CompileSingleMethod(corInfo, methodCodeNodeNeedingCode); } }
public override ObjectData GetData(NodeFactory factory, bool relocsOnly = false) { if (relocsOnly) { return(new ObjectData(Array.Empty <byte>(), Array.Empty <Relocation>(), 1, Array.Empty <ISymbolDefinitionNode>())); } PgoValueEmitter pgoEmitter = new PgoValueEmitter(_factory.CompilationModuleGroup, _symbolNodeFactory, true); NativeWriter hashtableWriter = new NativeWriter(); Section hashtableSection = hashtableWriter.NewSection(); VertexHashtable vertexHashtable = new VertexHashtable(); hashtableSection.Place(vertexHashtable); Dictionary <byte[], BlobVertex> uniqueInstrumentationData = new Dictionary <byte[], BlobVertex>(ByteArrayComparer.Instance); foreach (MethodDesc method in _instrumentationDataMethods) { pgoEmitter.Clear(); PgoProcessor.EncodePgoData(CorInfoImpl.ConvertTypeHandleHistogramsToCompactTypeHistogramFormat(_profileDataManager[method].SchemaData, factory.CompilationModuleGroup), pgoEmitter, false); byte[] signature = InstanceEntryPointTableNode.BuildSignatureForMethodDefinedInModule(method, factory); BlobVertex signatureBlob = new BlobVertex(signature); byte[] encodedInstrumentationData = pgoEmitter.ToByteArray(); BlobVertex instrumentationDataBlob = null; if (!uniqueInstrumentationData.TryGetValue(encodedInstrumentationData, out instrumentationDataBlob)) { instrumentationDataBlob = new BlobVertex(encodedInstrumentationData); hashtableSection.Place(instrumentationDataBlob); uniqueInstrumentationData.Add(encodedInstrumentationData, instrumentationDataBlob); } PgoInstrumentedDataWithSignatureBlobVertex pgoDataVertex = new PgoInstrumentedDataWithSignatureBlobVertex(signatureBlob, 0, instrumentationDataBlob); hashtableSection.Place(pgoDataVertex); vertexHashtable.Append(unchecked ((uint)ReadyToRunHashCode.MethodHashCode(method)), pgoDataVertex); } MemoryStream hashtableContent = new MemoryStream(); hashtableWriter.Save(hashtableContent); return(new ObjectData( data: hashtableContent.ToArray(), relocs: null, alignment: 8, definedSymbols: new ISymbolDefinitionNode[] { this })); }
internal ReadyToRunCodegenCompilation( DependencyAnalyzerBase <NodeFactory> dependencyGraph, ReadyToRunCodegenNodeFactory nodeFactory, IEnumerable <ICompilationRootProvider> roots, ILProvider ilProvider, Logger logger, DevirtualizationManager devirtualizationManager, JitConfigProvider configProvider, string inputFilePath, IEnumerable <ModuleDesc> modulesBeingInstrumented) : base(dependencyGraph, nodeFactory, roots, ilProvider, devirtualizationManager, modulesBeingInstrumented, logger) { NodeFactory = nodeFactory; SymbolNodeFactory = new ReadyToRunSymbolNodeFactory(nodeFactory); _jitConfigProvider = configProvider; _inputFilePath = inputFilePath; _corInfo = new CorInfoImpl(this, _jitConfigProvider); }
private void CompileSingleMethod(CorInfoImpl corInfo, MethodCodeNode methodCodeNodeNeedingCode) { try { MethodDesc method = methodCodeNodeNeedingCode.Method; TypeSystemException exception = _methodImportationErrorProvider.GetCompilationError(method); // If we previously failed to import the method, do not try to import it again and go // directly to the error path. if (exception == null) { try { corInfo.CompileMethod(methodCodeNodeNeedingCode); } catch (TypeSystemException ex) { exception = ex; } } if (exception != null) { // TODO: fail compilation if a switch was passed // Try to compile the method again, but with a throwing method body this time. MethodIL throwingIL = TypeSystemThrowingILEmitter.EmitIL(method, exception); corInfo.CompileMethod(methodCodeNodeNeedingCode, throwingIL); if (exception is TypeSystemException.InvalidProgramException && method.OwningType is MetadataType mdOwningType && mdOwningType.HasCustomAttribute("System.Runtime.InteropServices", "ClassInterfaceAttribute")) { Logger.LogWarning("COM interop is not supported with full ahead of time compilation", 3052, method, MessageSubCategory.AotAnalysis); } else { Logger.LogWarning($"Method will always throw because: {exception.Message}", 1005, method, MessageSubCategory.AotAnalysis); } } }
private void CompileSingleMethod(CorInfoImpl corInfo, MethodCodeNode methodCodeNodeNeedingCode) { MethodDesc method = methodCodeNodeNeedingCode.Method; TypeSystemException exception = _methodImportationErrorProvider.GetCompilationError(method); // If we previously failed to import the method, do not try to import it again and go // directly to the error path. if (exception == null) { try { corInfo.CompileMethod(methodCodeNodeNeedingCode); } catch (TypeSystemException ex) { exception = ex; } } if (exception != null) { // Try to compile the method again, but with a throwing method body this time. MethodIL throwingIL = TypeSystemThrowingILEmitter.EmitIL(method, exception); corInfo.CompileMethod(methodCodeNodeNeedingCode, throwingIL); if (exception is TypeSystemException.InvalidProgramException && method.OwningType is MetadataType mdOwningType && mdOwningType.HasCustomAttribute("System.Runtime.InteropServices", "ClassInterfaceAttribute")) { Logger.LogWarning(method, DiagnosticId.COMInteropNotSupportedInFullAOT); } if ((_compilationOptions & RyuJitCompilationOptions.UseResilience) != 0) { Logger.LogMessage($"Method '{method}' will always throw because: {exception.Message}"); } else { Logger.LogError($"Method will always throw because: {exception.Message}", 1005, method, MessageSubCategory.AotAnalysis); } } }
private void RootMethods(TypeDesc type, string reason, IRootingServiceProvider rootProvider) { foreach (MethodDesc method in type.GetAllMethods()) { // Skip methods with no IL if (method.IsAbstract) { continue; } if (method.IsInternalCall) { continue; } MethodDesc methodToRoot = method; if (method.HasInstantiation) { methodToRoot = InstantiateIfPossible(method); if (methodToRoot == null) { continue; } } try { if (!CorInfoImpl.ShouldSkipCompilation(method)) { CheckCanGenerateMethod(methodToRoot); rootProvider.AddCompilationRoot(methodToRoot, reason); } } catch (TypeSystemException) { // Individual methods can fail to load types referenced in their signatures. // Skip them in library mode since they're not going to be callable. continue; } } }
internal ReadyToRunCodegenCompilation( DependencyAnalyzerBase <NodeFactory> dependencyGraph, ReadyToRunCodegenNodeFactory nodeFactory, IEnumerable <ICompilationRootProvider> roots, ILProvider ilProvider, DebugInformationProvider debugInformationProvider, PInvokeILEmitterConfiguration pInvokePolicy, Logger logger, DevirtualizationManager devirtualizationManager, JitConfigProvider configProvider, string inputFilePath) : base(dependencyGraph, nodeFactory, roots, ilProvider, debugInformationProvider, devirtualizationManager, pInvokePolicy, logger) { NodeFactory = nodeFactory; SymbolNodeFactory = new ReadyToRunSymbolNodeFactory(nodeFactory); _jitConfigProvider = configProvider; _inputFilePath = inputFilePath; _corInfo = new CorInfoImpl(this, _jitConfigProvider); }
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 void CompileMultiThreaded(List <MethodCodeNode> methodsToCompile) { if (Logger.IsVerbose) { Logger.Writer.WriteLine($"Compiling {methodsToCompile.Count} methods..."); } WaitCallback compileSingleMethodDelegate = m => { CorInfoImpl corInfo = _corinfos.GetValue(Thread.CurrentThread, thread => new CorInfoImpl(this)); CompileSingleMethod(corInfo, (MethodCodeNode)m); }; using (_compilationCountdown = new CountdownEvent(methodsToCompile.Count)) { foreach (MethodCodeNode methodCodeNodeNeedingCode in methodsToCompile) { ThreadPool.QueueUserWorkItem(compileSingleMethodDelegate, methodCodeNodeNeedingCode); } _compilationCountdown.Wait(); _compilationCountdown = null; } }
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; } }
public void CompileSingleFile() { NodeFactory.NameMangler = NameMangler; _nodeFactory = new NodeFactory(_typeSystemContext, _typeInitManager, _compilationModuleGroup, _options.IsCppCodeGen); // Choose which dependency graph implementation to use based on the amount of logging requested. if (_options.DgmlLog == null) { // No log uses the NoLogStrategy _dependencyGraph = new DependencyAnalyzer <NoLogStrategy <NodeFactory>, NodeFactory>(_nodeFactory, null); } else { if (_options.FullLog) { // Full log uses the full log strategy _dependencyGraph = new DependencyAnalyzer <FullGraphLogStrategy <NodeFactory>, NodeFactory>(_nodeFactory, null); } else { // Otherwise, use the first mark strategy _dependencyGraph = new DependencyAnalyzer <FirstMarkLogStrategy <NodeFactory>, NodeFactory>(_nodeFactory, null); } } _nodeFactory.AttachToDependencyGraph(_dependencyGraph); _compilationModuleGroup.AddWellKnownTypes(); _compilationModuleGroup.AddCompilationRoots(); if (!_options.IsCppCodeGen && !_options.MultiFile) { // TODO: build a general purpose way to hook up pieces that would be part of the core library // if factoring of the core library respected how things are, versus how they would be in // a magic world (future customers of this mechanism will be interop and serialization). var refExec = _typeSystemContext.GetModuleForSimpleName("System.Private.Reflection.Execution"); var exec = refExec.GetKnownType("Internal.Reflection.Execution", "ReflectionExecution"); AddCompilationRoot(exec.GetStaticConstructor(), "Reflection execution"); } if (_options.IsCppCodeGen) { _cppWriter = new CppCodeGen.CppWriter(this); _dependencyGraph.ComputeDependencyRoutine += CppCodeGenComputeDependencyNodeDependencies; var nodes = _dependencyGraph.MarkedNodeList; _cppWriter.OutputCode(nodes, _compilationModuleGroup.StartupCodeMain); } else { _corInfo = new CorInfoImpl(this); _dependencyGraph.ComputeDependencyRoutine += ComputeDependencyNodeDependencies; var nodes = _dependencyGraph.MarkedNodeList; ObjectWriter.EmitObject(_options.OutputFilePath, nodes, _nodeFactory); } if (_options.DgmlLog != null) { using (FileStream dgmlOutput = new FileStream(_options.DgmlLog, FileMode.Create)) { DgmlWriter.WriteDependencyGraphToStream(dgmlOutput, _dependencyGraph); dgmlOutput.Flush(); } } }
public void CompileSingleFile() { NodeFactory.NameMangler = NameMangler; _nodeFactory = new NodeFactory(_typeSystemContext, _options.IsCppCodeGen); // Choose which dependency graph implementation to use based on the amount of logging requested. if (_options.DgmlLog == null) { // No log uses the NoLogStrategy _dependencyGraph = new DependencyAnalyzer <NoLogStrategy <NodeFactory>, NodeFactory>(_nodeFactory, null); } else { if (_options.FullLog) { // Full log uses the full log strategy _dependencyGraph = new DependencyAnalyzer <FullGraphLogStrategy <NodeFactory>, NodeFactory>(_nodeFactory, null); } else { // Otherwise, use the first mark strategy _dependencyGraph = new DependencyAnalyzer <FirstMarkLogStrategy <NodeFactory>, NodeFactory>(_nodeFactory, null); } } _nodeFactory.AttachToDependencyGraph(_dependencyGraph); AddWellKnownTypes(); AddCompilationRoots(); if (_options.IsCppCodeGen) { _cppWriter = new CppCodeGen.CppWriter(this); _dependencyGraph.ComputeDependencyRoutine += CppCodeGenComputeDependencyNodeDependencies; var nodes = _dependencyGraph.MarkedNodeList; _cppWriter.OutputCode(nodes); } else { _corInfo = new CorInfoImpl(this); _dependencyGraph.ComputeDependencyRoutine += ComputeDependencyNodeDependencies; var nodes = _dependencyGraph.MarkedNodeList; ObjectWriter.EmitObject(_options.OutputFilePath, nodes, _nodeFactory); } if (_options.DgmlLog != null) { using (FileStream dgmlOutput = new FileStream(_options.DgmlLog, FileMode.Create)) { DgmlWriter.WriteDependencyGraphToStream(dgmlOutput, _dependencyGraph); dgmlOutput.Flush(); } } }
private void CompileSingleMethod(MethodCodeNode methodCodeNodeNeedingCode) { CorInfoImpl corInfo = _corinfos.GetValue(Thread.CurrentThread, thread => new CorInfoImpl(this)); CompileSingleMethod(corInfo, methodCodeNodeNeedingCode); }
// Shutdown the Jit if it has been loaded. This must only be called once per process public static void ShutdownJit() { CorInfoImpl.ShutdownJit(); }
public void AddCompilationRoots(IRootingServiceProvider rootProvider) { foreach (var method in _profileData) { try { // Validate that this method is fully instantiated if (method.OwningType.IsGenericDefinition || method.OwningType.ContainsSignatureVariables()) { continue; } if (method.IsGenericMethodDefinition) { continue; } bool containsSignatureVariables = false; foreach (TypeDesc t in method.Instantiation) { if (t.IsGenericDefinition) { containsSignatureVariables = true; break; } if (t.ContainsSignatureVariables()) { containsSignatureVariables = true; break; } } if (containsSignatureVariables) { continue; } if (!CorInfoImpl.ShouldSkipCompilation(method)) { CheckCanGenerateMethod(method); rootProvider.AddCompilationRoot(method, "Profile triggered method"); } } catch (TypeSystemException) { // Individual methods can fail to load types referenced in their signatures. // Skip them in library mode since they're not going to be callable. continue; } } if (!_profileDrivenPartialNGen) { foreach (MetadataType type in _module.GetAllTypes()) { MetadataType typeWithMethods = type; if (type.HasInstantiation) { typeWithMethods = InstantiateIfPossible(type); if (typeWithMethods == null) { continue; } } RootMethods(typeWithMethods, "Library module method", rootProvider); } } }
public void CompileSingleFile(MethodDesc mainMethod) { if (_options.IsCppCodeGen) { _cppWriter = new CppCodeGen.CppWriter(this); } else { _corInfo = new CorInfoImpl(this); } _mainMethod = mainMethod; if (!_options.IsCppCodeGen) { _nodeFactory = new NodeFactory(this._typeSystemContext); NodeFactory.NameMangler = NameMangler; // Choose which dependency graph implementation to use based on the amount of logging requested. if (_options.DgmlLog == null) { // No log uses the NoLogStrategy _dependencyGraph = new DependencyAnalyzer <NoLogStrategy <NodeFactory>, NodeFactory>(_nodeFactory, null); } else { if (_options.FullLog) { // Full log uses the full log strategy _dependencyGraph = new DependencyAnalyzer <FullGraphLogStrategy <NodeFactory>, NodeFactory>(_nodeFactory, null); } else { // Otherwise, use the first mark strategy _dependencyGraph = new DependencyAnalyzer <FirstMarkLogStrategy <NodeFactory>, NodeFactory>(_nodeFactory, null); } } _nodeFactory.AttachToDependencyGraph(_dependencyGraph); AddWellKnownTypes(); AddCompilationRoots(); _dependencyGraph.ComputeDependencyRoutine += ComputeDependencyNodeDependencies; var nodes = _dependencyGraph.MarkedNodeList; var mainMethodNode = (_mainMethod != null) ? _nodeFactory.MethodEntrypoint(_mainMethod) : null; ObjectWriter.EmitObject(OutputPath, nodes, mainMethodNode, _nodeFactory); if (_options.DgmlLog != null) { using (FileStream dgmlOutput = new FileStream(_options.DgmlLog, FileMode.Create)) { DgmlWriter.WriteDependencyGraphToStream(dgmlOutput, _dependencyGraph); dgmlOutput.Flush(); } } } else { AddWellKnownTypes(); AddCompilationRoots(); while (_methodsThatNeedsCompilation != null) { CompileMethods(); ExpandVirtualMethods(); } _cppWriter.OutputCode(); } }
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 Compile() { NodeFactory.NameMangler = NameMangler; string systemModuleName = ((IAssemblyDesc)_typeSystemContext.SystemModule).GetName().Name; // TODO: just something to get Runtime.Base compiled if (systemModuleName != "System.Private.CoreLib") { NodeFactory.CompilationUnitPrefix = systemModuleName.Replace(".", "_"); } else { NodeFactory.CompilationUnitPrefix = NameMangler.SanitizeName(Path.GetFileNameWithoutExtension(Options.OutputFilePath)); } if (_options.IsCppCodeGen) { _nodeFactory = new CppCodegenNodeFactory(_typeSystemContext, _compilationModuleGroup); } else { _nodeFactory = new RyuJitNodeFactory(_typeSystemContext, _compilationModuleGroup); } // Choose which dependency graph implementation to use based on the amount of logging requested. if (_options.DgmlLog == null) { // No log uses the NoLogStrategy _dependencyGraph = new DependencyAnalyzer <NoLogStrategy <NodeFactory>, NodeFactory>(_nodeFactory, null); } else { if (_options.FullLog) { // Full log uses the full log strategy _dependencyGraph = new DependencyAnalyzer <FullGraphLogStrategy <NodeFactory>, NodeFactory>(_nodeFactory, null); } else { // Otherwise, use the first mark strategy _dependencyGraph = new DependencyAnalyzer <FirstMarkLogStrategy <NodeFactory>, NodeFactory>(_nodeFactory, null); } } _nodeFactory.AttachToDependencyGraph(_dependencyGraph); if (_options.IsCppCodeGen) { _cppWriter = new CppCodeGen.CppWriter(this); _dependencyGraph.ComputeDependencyRoutine += CppCodeGenComputeDependencyNodeDependencies; var nodes = _dependencyGraph.MarkedNodeList; _cppWriter.OutputCode(nodes, _compilationModuleGroup.StartupCodeMain, _nodeFactory); } else { _corInfo = new CorInfoImpl(this); _dependencyGraph.ComputeDependencyRoutine += ComputeDependencyNodeDependencies; var nodes = _dependencyGraph.MarkedNodeList; ObjectWriter.EmitObject(_options.OutputFilePath, nodes, _nodeFactory); } if (_options.DgmlLog != null) { using (FileStream dgmlOutput = new FileStream(_options.DgmlLog, FileMode.Create)) { DgmlWriter.WriteDependencyGraphToStream(dgmlOutput, _dependencyGraph); dgmlOutput.Flush(); } } }
public override IntPtr OnEntryPoint(MethodEntrypointPtr methodEntrypoint, IntPtr callerArgs) { lock (this) { if (_corInfoImpl == null) { InitJitCodeManager(RuntimeAugments.RhGetOSModuleForMrt()); // TODO: Recycle jit interface object and TypeSystemContext _context = TypeSystemContextFactory.Create(); Compilation compilation = new Compilation(_context); _nodeFactory = compilation.NodeFactory; JitConfigProvider configProvider = new JitConfigProvider(new CorJitFlag[] { CorJitFlag.CORJIT_FLAG_DEBUG_CODE }, Array.Empty <KeyValuePair <string, string> >()); _corInfoImpl = new CorInfoImpl(compilation, configProvider); } MethodDesc methodToCompile = methodEntrypoint.MethodIdentifier.ToMethodDesc(_context); JitMethodCodeNode codeNode = new JitMethodCodeNode(methodToCompile); _corInfoImpl.CompileMethod(codeNode); ObjectNode.ObjectData codeData = codeNode.GetData(null, false); List <ObjectNode> nodesToEmit = new List <ObjectNode>(); Dictionary <DependencyNodeCore <NodeFactory>, object> relocTargets = new Dictionary <DependencyNodeCore <NodeFactory>, object>(); int totalAllocSizeNeeded = 0; int nonObjectRelocTargets = 0; nodesToEmit.Add(codeNode); UpdateBytesUsed(codeNode.GetData(_nodeFactory), ref totalAllocSizeNeeded); int offsetOfEHData = totalAllocSizeNeeded; if (codeNode.EHInfo != null) { Debug.Assert(codeNode.EHInfo.Alignment == 1); // Assert needed as otherwise offsetOfEHData will be wrong UpdateBytesUsed(codeNode.EHInfo, ref totalAllocSizeNeeded); ComputeDependencySizeAndRelocData(codeNode.EHInfo, relocTargets, nodesToEmit, ref totalAllocSizeNeeded, ref nonObjectRelocTargets); } for (int i = 0; i < nodesToEmit.Count; i++) { ObjectNode objNode = nodesToEmit[i]; ComputeDependencySizeAndRelocData(objNode.GetData(_nodeFactory, true), relocTargets, nodesToEmit, ref totalAllocSizeNeeded, ref nonObjectRelocTargets); } if (nonObjectRelocTargets != 0) { totalAllocSizeNeeded = totalAllocSizeNeeded.AlignUp(IntPtr.Size); } int relocTargetOffsetStart = totalAllocSizeNeeded; DependencyNodeCore <NodeFactory>[] relocTargetsArray = new DependencyNodeCore <NodeFactory> [nonObjectRelocTargets]; { int iRelocTarget = 0; foreach (var relocTarget in relocTargets) { if (!(relocTarget.Key is ObjectNode)) { relocTargetsArray[iRelocTarget] = relocTarget.Key; totalAllocSizeNeeded += IntPtr.Size; iRelocTarget++; } } Debug.Assert(iRelocTarget == nonObjectRelocTargets); } GenericDictionaryCell[] genDictCells = new GenericDictionaryCell[relocTargetsArray.Length]; for (int iRelocTarget = 0; iRelocTarget < relocTargetsArray.Length; iRelocTarget++) { DependencyNodeCore <NodeFactory> relocTarget = relocTargetsArray[iRelocTarget]; GenericDictionaryCell newCell = null; if (relocTarget is ExternObjectSymbolNode) { var externObjectSymbolNode = (ExternObjectSymbolNode)relocTarget; var newMethodCell = externObjectSymbolNode.GetDictionaryCell(); newCell = newMethodCell; } if (newCell == null) { Environment.FailFast("Unknown reloc target type"); } genDictCells[iRelocTarget] = newCell; } IntPtr[] relocTargetsAsIntPtr = null; TypeLoaderEnvironment.Instance.RunUnderTypeLoaderLock( () => { TypeBuilderApi.ResolveMultipleCells(genDictCells, out relocTargetsAsIntPtr); }); // Layout of allocated memory... // ObjectNodes (aligned as appropriate) IntPtr pCodeManager; IntPtr jittedCode = AllocJittedCode(checked ((uint)totalAllocSizeNeeded), 8 /* TODO, alignment calculation */, out pCodeManager); int currentOffset = 0; foreach (var node in nodesToEmit) { ObjectNode.ObjectData objectData = node.GetData(_nodeFactory); EmitAndRelocData(objectData, jittedCode, relocTargetOffsetStart, ref currentOffset, relocTargetsArray, relocTargetsAsIntPtr); // EHInfo doesn't get its own node, but it does get emitted into the stream. if ((node == codeNode) && (codeNode.EHInfo != null)) { Debug.Assert(offsetOfEHData == currentOffset); EmitAndRelocData(codeNode.EHInfo, jittedCode, relocTargetOffsetStart, ref currentOffset, relocTargetsArray, relocTargetsAsIntPtr); } } foreach (IntPtr ptr in relocTargetsAsIntPtr) { currentOffset = currentOffset.AlignUp(IntPtr.Size); Marshal.WriteIntPtr(jittedCode, currentOffset, ptr); currentOffset += IntPtr.Size; } SetEHInfoPtr(pCodeManager, jittedCode, jittedCode + offsetOfEHData); IntPtr mainRuntimeFunction = IntPtr.Zero; for (int i = 0; i < codeNode.FrameInfos.Length; i++) { FrameInfo frame = codeNode.FrameInfos[i]; byte[] frameData = frame.BlobData; byte[] gcInfoData = Array.Empty <byte>(); byte[] gcInfoDataDeref = frameData; if (i == 0) { // For main function, add the gc info to the data gcInfoDataDeref = gcInfoData = codeNode.GCInfo; } IntPtr publishedFunction = PublishRuntimeFunction(pCodeManager, jittedCode, mainRuntimeFunction, checked ((uint)frame.StartOffset), checked ((uint)frame.EndOffset), frameData, checked ((uint)frameData.Length), gcInfoDataDeref, checked ((uint)gcInfoData.Length)); if (i == 0) { mainRuntimeFunction = publishedFunction; } } if (mainRuntimeFunction != IntPtr.Zero) { UpdateRuntimeFunctionTable(pCodeManager); } methodEntrypoint.MethodCode = jittedCode; return(jittedCode); } }