internal static TResult CompileWithRetry <TResult>( ImmutableArray <MetadataBlock> metadataBlocks, DiagnosticFormatter formatter, CreateContextDelegate createContext, CompileDelegate <TResult> compile, DkmUtilities.GetMetadataBytesPtrFunction getMetaDataBytesPtr, out string errorMessage) { errorMessage = null; TResult compileResult; bool tryAgain; do { var context = createContext(metadataBlocks, useReferencedModulesOnly: false); var diagnostics = DiagnosticBag.GetInstance(); compileResult = compile(context, diagnostics); tryAgain = false; if (diagnostics.HasAnyErrors()) { bool useReferencedModulesOnly; ImmutableArray <AssemblyIdentity> missingAssemblyIdentities; errorMessage = context.GetErrorMessageAndMissingAssemblyIdentities( diagnostics, formatter, preferredUICulture: null, useReferencedModulesOnly: out useReferencedModulesOnly, missingAssemblyIdentities: out missingAssemblyIdentities); if (useReferencedModulesOnly) { Debug.Assert(missingAssemblyIdentities.IsEmpty); var otherContext = createContext(metadataBlocks, useReferencedModulesOnly: true); var otherDiagnostics = DiagnosticBag.GetInstance(); var otherResult = compile(otherContext, otherDiagnostics); if (!otherDiagnostics.HasAnyErrors()) { errorMessage = null; compileResult = otherResult; } otherDiagnostics.Free(); } else { tryAgain = ShouldTryAgainWithMoreMetadataBlocks(getMetaDataBytesPtr, missingAssemblyIdentities, ref metadataBlocks); } } diagnostics.Free(); } while (tryAgain); return(compileResult); }
private TResult CompileWithRetry <TResult>( DkmClrModuleInstance moduleInstance, ImmutableArray <MetadataBlock> metadataBlocks, CreateContextDelegate createContext, CompileDelegate <TResult> compile, out string errorMessage) { return(CompileWithRetry( metadataBlocks, this.DiagnosticFormatter, createContext, compile, (AssemblyIdentity assemblyIdentity, out uint size) => moduleInstance.AppDomain.GetMetaDataBytesPtr(assemblyIdentity.GetDisplayName(), out size), out errorMessage)); }
private TResult CompileWithRetry <TResult>( DkmClrAppDomain appDomain, DkmClrRuntimeInstance runtimeInstance, CreateContextDelegate createContext, CompileDelegate <TResult> compile, out string errorMessage) { var metadataBlocks = GetMetadataBlocks(appDomain, runtimeInstance); return(CompileWithRetry( metadataBlocks, this.DiagnosticFormatter, createContext, compile, (AssemblyIdentity assemblyIdentity, out uint size) => appDomain.GetMetaDataBytesPtr(assemblyIdentity.GetDisplayName(), out size), out errorMessage)); }
internal static TResult CompileWithRetry <TResult>( ImmutableArray <MetadataBlock> metadataBlocks, DiagnosticFormatter formatter, CreateContextDelegate createContext, CompileDelegate <TResult> compile, DkmUtilities.GetMetadataBytesPtrFunction getMetaDataBytesPtr, out string errorMessage) { TResult compileResult; PooledHashSet <AssemblyIdentity> assembliesLoadedInRetryLoop = null; bool tryAgain; do { errorMessage = null; var context = createContext(metadataBlocks, useReferencedModulesOnly: false); var diagnostics = DiagnosticBag.GetInstance(); compileResult = compile(context, diagnostics); tryAgain = false; if (diagnostics.HasAnyErrors()) { bool useReferencedModulesOnly; ImmutableArray <AssemblyIdentity> missingAssemblyIdentities; errorMessage = context.GetErrorMessageAndMissingAssemblyIdentities( diagnostics, formatter, preferredUICulture: null, useReferencedModulesOnly: out useReferencedModulesOnly, missingAssemblyIdentities: out missingAssemblyIdentities); if (useReferencedModulesOnly) { Debug.Assert(missingAssemblyIdentities.IsEmpty); var otherContext = createContext(metadataBlocks, useReferencedModulesOnly: true); var otherDiagnostics = DiagnosticBag.GetInstance(); var otherResult = compile(otherContext, otherDiagnostics); if (!otherDiagnostics.HasAnyErrors()) { errorMessage = null; compileResult = otherResult; } otherDiagnostics.Free(); } else { if (!missingAssemblyIdentities.IsEmpty) { if (assembliesLoadedInRetryLoop == null) { assembliesLoadedInRetryLoop = PooledHashSet <AssemblyIdentity> .GetInstance(); } // If any identities failed to add (they were already in the list), then don't retry. if (assembliesLoadedInRetryLoop.AddAll(missingAssemblyIdentities)) { tryAgain = ShouldTryAgainWithMoreMetadataBlocks(getMetaDataBytesPtr, missingAssemblyIdentities, ref metadataBlocks); } } } } diagnostics.Free(); } while (tryAgain); assembliesLoadedInRetryLoop?.Free(); return(compileResult); }
/// <summary> /// Initializes a new instance of the <see cref="ToolChain" /> class. For now tool chains are single tools, but this /// could be easily extended to support multiple steps. /// </summary> /// <param name="graphicsBackend">The graphics backend.</param> /// <param name="backendType">Type of the backend.</param> /// <param name="createBackend">The function to create the backend.</param> /// <param name="compileFunction">The compile function.</param> /// <param name="createHeadless">The function to create a headless graphics device.</param> /// <param name="createWindowed">The create windowed.</param> /// <exception cref="ArgumentOutOfRangeException">backendType</exception> private ToolChain(GraphicsBackend graphicsBackend, Type backendType, Func <Compilation, LanguageBackend> createBackend, CompileDelegate compileFunction, Func <GraphicsDevice> createHeadless, Func <GraphicsDevice> createWindowed) { if (!backendType.IsSubclassOf(typeof(LanguageBackend))) { throw new ArgumentOutOfRangeException(nameof(backendType), $"{backendType.Name} is not a descendent of {nameof(LanguageBackend)}."); } BackendType = backendType; // Calculate name (strip 'Backend' if present). Name = backendType.Name; if (Name.EndsWith("Backend", StringComparison.InvariantCultureIgnoreCase)) { Name = Name.Substring(0, Name.Length - 7); } GraphicsBackend = graphicsBackend; ToolFeatures features = ToolFeatures.None; if (createBackend != null) { _createBackend = createBackend; features |= ToolFeatures.Transpilation; } if (compileFunction != null) { _compileFunction = compileFunction; features |= ToolFeatures.Compilation; } // Don't allow creation of graphics devices on CI Servers. bool onCiServer = Environment.GetEnvironmentVariable("CI")?.ToLowerInvariant() == "true"; if (!onCiServer && createHeadless != null && GraphicsDevice.IsBackendSupported(graphicsBackend)) { try { // Try to create a headless graphics device using (createHeadless()) { } _createHeadless = createHeadless; features |= ToolFeatures.HeadlessGraphicsDevice; } catch { } } // TODO For future expansion, will need to review signature of function. if (!onCiServer && createWindowed != null && GraphicsDevice.IsBackendSupported(graphicsBackend)) { try { // Try to create a headless graphics device using (createWindowed()) { } _createWindowed = createWindowed; features |= ToolFeatures.WindowedGraphicsDevice; } catch { } } Features = features; // Add to lookup dictionaries. _toolChainsByGraphicsBackend.Add(graphicsBackend, this); _toolChainsByBackendType.Add(backendType, this); }
internal static TResult CompileWithRetry <TResult>( ImmutableArray <MetadataBlock> metadataBlocks, DiagnosticFormatter formatter, CreateContextDelegate createContext, CompileDelegate <TResult> compile, DkmUtilities.GetMetadataBytesPtrFunction getMetaDataBytesPtr, out string errorMessage) { TResult compileResult; PooledHashSet <AssemblyIdentity> assembliesLoadedInRetryLoop = null; bool tryAgain; var linqLibrary = EvaluationContextBase.SystemLinqIdentity; do { errorMessage = null; var context = createContext(metadataBlocks, useReferencedModulesOnly: false); var diagnostics = DiagnosticBag.GetInstance(); compileResult = compile(context, diagnostics); tryAgain = false; if (diagnostics.HasAnyErrors()) { bool useReferencedModulesOnly; ImmutableArray <AssemblyIdentity> missingAssemblyIdentities; errorMessage = context.GetErrorMessageAndMissingAssemblyIdentities( diagnostics, formatter, preferredUICulture: null, linqLibrary: linqLibrary, useReferencedModulesOnly: out useReferencedModulesOnly, missingAssemblyIdentities: out missingAssemblyIdentities); // If there were LINQ-related errors, we'll initially add System.Linq (set above). // If that doesn't work, we'll fall back to System.Core for subsequent retries. linqLibrary = EvaluationContextBase.SystemCoreIdentity; // Can we remove the `useReferencedModulesOnly` attempt if we're only using // modules reachable from the current module? In short, can we avoid retrying? if (useReferencedModulesOnly) { Debug.Assert(missingAssemblyIdentities.IsEmpty); var otherContext = createContext(metadataBlocks, useReferencedModulesOnly: true); var otherDiagnostics = DiagnosticBag.GetInstance(); var otherResult = compile(otherContext, otherDiagnostics); if (!otherDiagnostics.HasAnyErrors()) { errorMessage = null; compileResult = otherResult; } otherDiagnostics.Free(); } else { if (!missingAssemblyIdentities.IsEmpty) { if (assembliesLoadedInRetryLoop == null) { assembliesLoadedInRetryLoop = PooledHashSet <AssemblyIdentity> .GetInstance(); } // If any identities failed to add (they were already in the list), then don't retry. if (assembliesLoadedInRetryLoop.AddAll(missingAssemblyIdentities)) { tryAgain = ShouldTryAgainWithMoreMetadataBlocks(getMetaDataBytesPtr, missingAssemblyIdentities, ref metadataBlocks); } } } } diagnostics.Free(); } while (tryAgain); assembliesLoadedInRetryLoop?.Free(); return(compileResult); }