Skip to content

[NFC] Add Compilation::Result #35034

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Dec 10, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 27 additions & 5 deletions include/swift/Driver/Compilation.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
#include "swift/Basic/OutputFileMap.h"
#include "swift/Basic/Statistic.h"
#include "swift/Driver/Driver.h"
#include "swift/Driver/FineGrainedDependencyDriverGraph.h"
#include "swift/Driver/Job.h"
#include "swift/Driver/Util.h"
#include "llvm/ADT/StringRef.h"
Expand Down Expand Up @@ -78,6 +79,29 @@ using CommandSet = llvm::SmallPtrSet<const Job *, 16>;

class Compilation {
public:
struct Result {
/// Set to true if any job exits abnormally (i.e. crashes).
bool hadAbnormalExit;
/// The exit code of this driver process.
int exitCode;
/// The dependency graph built up during the compilation of this module.
///
/// This data is used for cross-module module dependencies.
fine_grained_dependencies::ModuleDepGraph depGraph;

Result(const Result &) = delete;
Result &operator=(const Result &) = delete;

Result(Result &&) = default;
Result &operator=(Result &&) = default;

/// Construct a \c Compilation::Result from just an exit code.
static Result code(int code) {
return Compilation::Result{false, code,
fine_grained_dependencies::ModuleDepGraph()};
}
};

class IncrementalSchemeComparator {
const bool EnableIncrementalBuildWhenConstructed;
const bool &EnableIncrementalBuild;
Expand Down Expand Up @@ -490,7 +514,7 @@ class Compilation {
///
/// \returns result code for the Compilation's Jobs; 0 indicates success and
/// -2 indicates that one of the Compilation's Jobs crashed during execution
int performJobs(std::unique_ptr<sys::TaskQueue> &&TQ);
Compilation::Result performJobs(std::unique_ptr<sys::TaskQueue> &&TQ);

/// Returns whether the callee is permitted to pass -emit-loaded-module-trace
/// to a frontend job.
Expand Down Expand Up @@ -534,13 +558,11 @@ class Compilation {
private:
/// Perform all jobs.
///
/// \param[out] abnormalExit Set to true if any job exits abnormally (i.e.
/// crashes).
/// \param TQ The task queue on which jobs will be scheduled.
///
/// \returns exit code of the first failed Job, or 0 on success. If a Job
/// crashes during execution, a negative value will be returned.
int performJobsImpl(bool &abnormalExit, std::unique_ptr<sys::TaskQueue> &&TQ);
Compilation::Result performJobsImpl(std::unique_ptr<sys::TaskQueue> &&TQ);

/// Performs a single Job by executing in place, if possible.
///
Expand All @@ -550,7 +572,7 @@ class Compilation {
/// will no longer exist, or it will call exit() if the program was
/// successfully executed. In the event of an error, this function will return
/// a negative value indicating a failure to execute.
int performSingleCommand(const Job *Cmd);
Compilation::Result performSingleCommand(const Job *Cmd);
};

} // end namespace driver
Expand Down
6 changes: 3 additions & 3 deletions include/swift/Driver/FineGrainedDependencyDriverGraph.h
Original file line number Diff line number Diff line change
Expand Up @@ -188,8 +188,8 @@ class ModuleDepGraph {
std::unordered_map<std::string, unsigned> dotFileSequenceNumber;

public:
const bool verifyFineGrainedDependencyGraphAfterEveryImport;
const bool emitFineGrainedDependencyDotFileAfterEveryImport;
bool verifyFineGrainedDependencyGraphAfterEveryImport;
bool emitFineGrainedDependencyDotFileAfterEveryImport;

private:
/// If tracing dependencies, holds a vector used to hold the current path
Expand All @@ -203,7 +203,7 @@ class ModuleDepGraph {
dependencyPathsToJobs;

/// For helping with performance tuning, may be null:
UnifiedStatsReporter *const stats;
UnifiedStatsReporter *stats;

//==============================================================================
// MARK: ModuleDepGraph - mutating dependencies
Expand Down
73 changes: 43 additions & 30 deletions lib/Driver/Compilation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -244,7 +244,7 @@ namespace driver {
std::unique_ptr<TaskQueue> TQ;

/// Cumulative result of PerformJobs(), accumulated from subprocesses.
int Result = EXIT_SUCCESS;
int ResultCode = EXIT_SUCCESS;

/// True if any Job crashed.
bool AnyAbnormalExit = false;
Expand Down Expand Up @@ -719,8 +719,8 @@ namespace driver {
// Store this task's ReturnCode as our Result if we haven't stored
// anything yet.

if (Result == EXIT_SUCCESS)
Result = ReturnCode;
if (ResultCode == EXIT_SUCCESS)
ResultCode = ReturnCode;

if (!isa<CompileJobAction>(FinishedCmd->getSource()) ||
ReturnCode != EXIT_FAILURE) {
Expand Down Expand Up @@ -825,7 +825,7 @@ namespace driver {
}

// Since the task signalled, unconditionally set result to -2.
Result = -2;
ResultCode = -2;
AnyAbnormalExit = true;

return TaskFinishedResponse::StopExecution;
Expand Down Expand Up @@ -1536,7 +1536,7 @@ namespace driver {
_3, _4, _5, _6),
std::bind(&PerformJobsState::taskSignalled, this, _1,
_2, _3, _4, _5, _6, _7))) {
if (Result == EXIT_SUCCESS) {
if (ResultCode == EXIT_SUCCESS) {
// FIXME: Error from task queue while Result == EXIT_SUCCESS most
// likely means some fork/exec or posix_spawn failed; TaskQueue saw
// "an error" at some stage before even calling us with a process
Expand All @@ -1546,21 +1546,21 @@ namespace driver {
Comp.getDiags().diagnose(SourceLoc(),
diag::error_unable_to_execute_command,
"<unknown>");
Result = -2;
ResultCode = -2;
AnyAbnormalExit = true;
return;
}
}

// Returning without error from TaskQueue::execute should mean either an
// empty TaskQueue or a failed subprocess.
assert(!(Result == 0 && TQ->hasRemainingTasks()));
assert(!(ResultCode == 0 && TQ->hasRemainingTasks()));

// Task-exit callbacks from TaskQueue::execute may have unblocked jobs,
// which means there might be PendingExecution jobs to enqueue here. If
// there are, we need to continue trying to make progress on the
// TaskQueue before we start marking deferred jobs as skipped, below.
if (!PendingExecution.empty() && Result == 0) {
if (!PendingExecution.empty() && ResultCode == 0) {
formBatchJobsAndAddPendingJobsToTaskQueue();
continue;
}
Expand All @@ -1585,11 +1585,11 @@ namespace driver {

// If we added jobs to the TaskQueue, and we are not in an error state,
// we want to give the TaskQueue another run.
} while (Result == 0 && TQ->hasRemainingTasks());
} while (ResultCode == 0 && TQ->hasRemainingTasks());
}

void checkUnfinishedJobs() {
if (Result == 0) {
if (ResultCode == 0) {
assert(BlockingCommands.empty() &&
"some blocking commands never finished properly");
} else {
Expand Down Expand Up @@ -1693,10 +1693,14 @@ namespace driver {
});
}

int getResult() {
if (Result == 0)
Result = Comp.getDiags().hadAnyError();
return Result;
Compilation::Result takeResult() && {
if (ResultCode == 0)
ResultCode = Comp.getDiags().hadAnyError();
const bool forRanges = Comp.getEnableSourceRangeDependencies();
const bool hadAbnormalExit = hadAnyAbnormalExit();
const auto resultCode = ResultCode;
auto &&graph = std::move(*this).takeFineGrainedDepGraph(forRanges);
return Compilation::Result{hadAbnormalExit, resultCode, std::move(graph)};
}

bool hadAnyAbnormalExit() {
Expand Down Expand Up @@ -1756,6 +1760,12 @@ namespace driver {
getFineGrainedDepGraph(const bool forRanges) const {
return forRanges ? FineGrainedDepGraphForRanges : FineGrainedDepGraph;
}

fine_grained_dependencies::ModuleDepGraph &&
takeFineGrainedDepGraph(const bool forRanges) && {
return forRanges ? std::move(FineGrainedDepGraphForRanges)
: std::move(FineGrainedDepGraph);
}
};
} // namespace driver
} // namespace swift
Expand Down Expand Up @@ -1936,8 +1946,8 @@ static bool writeFilelistIfNecessary(const Job *job, const ArgList &args,
return ok;
}

int Compilation::performJobsImpl(bool &abnormalExit,
std::unique_ptr<TaskQueue> &&TQ) {
Compilation::Result
Compilation::performJobsImpl(std::unique_ptr<TaskQueue> &&TQ) {
PerformJobsState State(*this, std::move(TQ));

State.runJobs();
Expand All @@ -1946,36 +1956,39 @@ int Compilation::performJobsImpl(bool &abnormalExit,
InputInfoMap InputInfo;
State.populateInputInfoMap(InputInfo);
checkForOutOfDateInputs(Diags, InputInfo);

auto result = std::move(State).takeResult();
writeCompilationRecord(CompilationRecordPath, ArgsHash, BuildStartTime,
InputInfo);
return result;
} else {
return std::move(State).takeResult();
}
abnormalExit = State.hadAnyAbnormalExit();
return State.getResult();
}

int Compilation::performSingleCommand(const Job *Cmd) {
Compilation::Result Compilation::performSingleCommand(const Job *Cmd) {
assert(Cmd->getInputs().empty() &&
"This can only be used to run a single command with no inputs");

switch (Cmd->getCondition()) {
case Job::Condition::CheckDependencies:
return 0;
return Compilation::Result::code(0);
case Job::Condition::RunWithoutCascading:
case Job::Condition::Always:
case Job::Condition::NewlyAdded:
break;
}

if (!writeFilelistIfNecessary(Cmd, *TranslatedArgs.get(), Diags))
return 1;
return Compilation::Result::code(1);

switch (Level) {
case OutputLevel::Normal:
case OutputLevel::Parseable:
break;
case OutputLevel::PrintJobs:
Cmd->printCommandLineAndEnvironment(llvm::outs());
return 0;
return Compilation::Result::code(0);
case OutputLevel::Verbose:
Cmd->printCommandLine(llvm::errs());
break;
Expand All @@ -1999,11 +2012,12 @@ int Compilation::performSingleCommand(const Job *Cmd) {
"expected environment variable to be set successfully");
// Bail out early in release builds.
if (envResult != 0) {
return envResult;
return Compilation::Result::code(envResult);
}
}

return ExecuteInPlace(ExecPath, argv);
const auto returnCode = ExecuteInPlace(ExecPath, argv);
return Compilation::Result::code(returnCode);
}

static bool writeAllSourcesFile(DiagnosticEngine &diags, StringRef path,
Expand All @@ -2026,10 +2040,10 @@ static bool writeAllSourcesFile(DiagnosticEngine &diags, StringRef path,
return true;
}

int Compilation::performJobs(std::unique_ptr<TaskQueue> &&TQ) {
Compilation::Result Compilation::performJobs(std::unique_ptr<TaskQueue> &&TQ) {
if (AllSourceFilesPath)
if (!writeAllSourcesFile(Diags, AllSourceFilesPath, getInputFiles()))
return EXIT_FAILURE;
return Compilation::Result::code(EXIT_FAILURE);

// If we don't have to do any cleanup work, just exec the subprocess.
if (Level < OutputLevel::Parseable &&
Expand All @@ -2044,20 +2058,19 @@ int Compilation::performJobs(std::unique_ptr<TaskQueue> &&TQ) {
Diags.diagnose(SourceLoc(), diag::warning_parallel_execution_not_supported);
}

bool abnormalExit;
int result = performJobsImpl(abnormalExit, std::move(TQ));
auto result = performJobsImpl(std::move(TQ));

if (IncrementalComparator)
IncrementalComparator->outputComparison();

if (!SaveTemps) {
for (const auto &pathPair : TempFilePaths) {
if (!abnormalExit || pathPair.getValue() == PreserveOnSignal::No)
if (!result.hadAbnormalExit || pathPair.getValue() == PreserveOnSignal::No)
(void)llvm::sys::fs::remove(pathPair.getKey());
}
}
if (Stats)
Stats->noteCurrentProcessExitStatus(result);
Stats->noteCurrentProcessExitStatus(result.exitCode);
return result;
}

Expand Down
2 changes: 1 addition & 1 deletion tools/driver/driver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -248,7 +248,7 @@ static int run_driver(StringRef ExecName,
std::unique_ptr<sys::TaskQueue> TQ = TheDriver.buildTaskQueue(*C);
if (!TQ)
return 1;
return C->performJobs(std::move(TQ));
return C->performJobs(std::move(TQ)).exitCode;
}

return 0;
Expand Down