Ejemplo n.º 1
0
        public async Task <object?> ProcessAsync(IWorkSession session, IList <Diagnostic> diagnostics, CancellationToken cancellationToken)
        {
            PerformanceLog.Checkpoint("SlowUpdate.ProcessAsync.Start");
            var targetName = GetAndEnsureTargetName(session);

            _topLevelProgramSupport.UpdateOutputKind(session, diagnostics);

            if (targetName is TargetNames.Ast or TargetNames.Explain)
            {
                var astTarget = _astTargets[session.LanguageName];
                var ast       = await astTarget.GetAstAsync(session, cancellationToken).ConfigureAwait(false);

                if (targetName == TargetNames.Explain)
                {
                    return(await _explainer.ExplainAsync(ast, session, cancellationToken).ConfigureAwait(false));
                }
                return(ast);
            }

            if (diagnostics.Any(d => d.Severity == DiagnosticSeverity.Error))
            {
                return(null);
            }

            if (targetName == LanguageNames.VisualBasic)
            {
                return(VisualBasicNotAvailable);
            }

            if (targetName is not(TargetNames.Run or TargetNames.Verify) && !_decompilers.ContainsKey(targetName))
            {
                throw new NotSupportedException($"Target '{targetName}' is not (yet?) supported by this branch.");
            }

            MemoryStream?assemblyStream = null;
            MemoryStream?symbolStream   = null;

            try {
                assemblyStream = _memoryStreamManager.GetStream();
                if (targetName is TargetNames.Run or TargetNames.IL)
                {
                    symbolStream = _memoryStreamManager.GetStream();
                }

                var compilationStopwatch = session.ShouldReportPerformance() ? Stopwatch.StartNew() : null;
                var compiled             = await _compiler.TryCompileToStreamAsync(assemblyStream, symbolStream, session, diagnostics, cancellationToken).ConfigureAwait(false);

                compilationStopwatch?.Stop();
                if (!compiled.assembly)
                {
                    assemblyStream.Dispose();
                    symbolStream?.Dispose();
                    return(null);
                }

                if (targetName == TargetNames.Verify)
                {
                    assemblyStream.Dispose();
                    symbolStream?.Dispose();
                    return("✔️ Compilation completed.");
                }

                assemblyStream.Seek(0, SeekOrigin.Begin);
                symbolStream?.Seek(0, SeekOrigin.Begin);
                AssemblyLog.Log("1.Compiled", assemblyStream, compiled.symbols ? symbolStream : null);

                var streams = new CompilationStreamPair(assemblyStream, compiled.symbols ? symbolStream : null);
                if (targetName == TargetNames.Run)
                {
                    if (!session.HasContainerExperimentFailed())
                    {
                        try {
                            var output = await _containerExecutor.ExecuteAsync(streams, session, cancellationToken);

                            if (compilationStopwatch != null)
                            {
                                // TODO: Prettify
                                output += $"\n  COMPILATION: {compilationStopwatch.ElapsedMilliseconds,15}ms";
                            }
                            streams.Dispose();
                            _monitor.Metric(ContainerExperimentMetrics.ContainerRunCount, 1);
                            return(output);
                        }
                        catch (Exception ex) {
                            _monitor.Metric(ContainerExperimentMetrics.ContainerFailureCount, 1);
                            _monitor.Exception(ex, session);
                            session.SetContainerExperimentException(ex);
                            assemblyStream.Seek(0, SeekOrigin.Begin);
                            symbolStream?.Seek(0, SeekOrigin.Begin);
                        }
                    }

                    _monitor.Metric(ContainerExperimentMetrics.LegacyRunCount, 1);
                    return(_executor.Execute(streams, session));
                }

                // it's fine not to Dispose() here -- MirrorSharp will dispose it after calling WriteResult()
                return(streams);
            }
            catch {
                assemblyStream?.Dispose();
                symbolStream?.Dispose();
                throw;
            }
        }