Skip to content

Commit d073929

Browse files
authored
Merge pull request #8887 from huonw/emit-loaded-module-trace
[Frontend] -frontend -emit-loaded-module-trace.
2 parents f1902fd + 268834a commit d073929

21 files changed

+359
-23
lines changed

include/swift/AST/DiagnosticsFrontend.def

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,8 @@ ERROR(error_mode_cannot_emit_dependencies,none,
106106
"this mode does not support emitting dependency files", ())
107107
ERROR(error_mode_cannot_emit_header,none,
108108
"this mode does not support emitting Objective-C headers", ())
109+
ERROR(error_mode_cannot_emit_loaded_module_trace,none,
110+
"this mode does not support emitting the loaded module trace", ())
109111
ERROR(error_mode_cannot_emit_module,none,
110112
"this mode does not support emitting modules", ())
111113
ERROR(error_mode_cannot_emit_module_doc,none,

include/swift/Basic/JSONSerialization.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -445,6 +445,16 @@ class Output {
445445
void indent();
446446
};
447447

448+
template <typename T> struct ArrayTraits<std::vector<T>> {
449+
static size_t size(Output &out, std::vector<T> &seq) { return seq.size(); }
450+
451+
static T &element(Output &out, std::vector<T> &seq, size_t index) {
452+
if (index >= seq.size())
453+
seq.resize(index + 1);
454+
return seq[index];
455+
}
456+
};
457+
448458
template<>
449459
struct ScalarTraits<bool> {
450460
static void output(const bool &, llvm::raw_ostream &);

include/swift/Driver/Compilation.h

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,10 @@ class Compilation {
146146
/// detail than ShowIncrementalBuildDecisions.
147147
bool ShowJobLifecycle = false;
148148

149+
/// When true, some frontend job has requested permission to pass
150+
/// -emit-loaded-module-trace, so no other job needs to do it.
151+
bool PassedEmitLoadedModuleTraceToFrontendJob = false;
152+
149153
static const Job *unwrap(const std::unique_ptr<const Job> &p) {
150154
return p.get();
151155
}
@@ -232,6 +236,22 @@ class Compilation {
232236
/// -2 indicates that one of the Compilation's Jobs crashed during execution
233237
int performJobs();
234238

239+
/// Returns whether the callee is permitted to pass -emit-loaded-module-trace
240+
/// to a frontend job.
241+
///
242+
/// This only returns true once, because only one job should pass that
243+
/// argument.
244+
bool requestPermissionForFrontendToEmitLoadedModuleTrace() {
245+
if (PassedEmitLoadedModuleTraceToFrontendJob)
246+
// Someone else has already done it!
247+
return false;
248+
else {
249+
// We're the first and only (to execute this path).
250+
PassedEmitLoadedModuleTraceToFrontendJob = true;
251+
return true;
252+
}
253+
}
254+
235255
private:
236256
/// \brief Perform all jobs.
237257
///

include/swift/Driver/Types.def

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ TYPE("swift-dependencies", SwiftDeps, "swiftdeps", "")
5959
TYPE("remap", Remapping, "remap", "")
6060
TYPE("imported-modules", ImportedModules, "importedmodules", "")
6161
TYPE("tbd", TBD, "tbd", "")
62+
TYPE("module-trace", ModuleTrace, "trace.json", "")
6263

6364
// Misc types
6465
TYPE("pcm", ClangModuleFile, "pcm", "")

include/swift/Frontend/FrontendOptions.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,9 @@ class FrontendOptions {
116116
/// The path to which we should output fixits as source edits.
117117
std::string FixitsOutputPath;
118118

119+
/// The path to which we should output a loaded module trace file.
120+
std::string LoadedModuleTracePath;
121+
119122
/// Arguments which should be passed in immediate mode.
120123
std::vector<std::string> ImmediateArgv;
121124

include/swift/Option/Options.td

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -199,6 +199,16 @@ def emit_dependencies : Flag<["-"], "emit-dependencies">,
199199
Flags<[FrontendOption, NoInteractiveOption, DoesNotAffectIncrementalBuild]>,
200200
HelpText<"Emit basic Make-compatible dependencies files">;
201201

202+
def emit_loaded_module_trace : Flag<["-"], "emit-loaded-module-trace">,
203+
Flags<[FrontendOption, NoInteractiveOption]>,
204+
HelpText<"Emit a JSON file containing information about what modules were loaded">;
205+
def emit_loaded_module_trace_path : Separate<["-"], "emit-loaded-module-trace-path">,
206+
Flags<[FrontendOption, NoInteractiveOption]>,
207+
HelpText<"Emit the loaded module trace JSON to <path>">,
208+
MetaVarName<"<path>">;
209+
def emit_loaded_module_trace_path_EQ : Joined<["-"], "emit-loaded-module-trace-path=">,
210+
Flags<[FrontendOption, NoInteractiveOption]>, Alias<emit_loaded_module_trace_path>;
211+
202212
def serialize_diagnostics : Flag<["-"], "serialize-diagnostics">,
203213
Flags<[FrontendOption, NoInteractiveOption, DoesNotAffectIncrementalBuild]>,
204214
HelpText<"Serialize diagnostics in a binary format">;

lib/Driver/Driver.cpp

Lines changed: 66 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1421,6 +1421,7 @@ void Driver::buildActions(const ToolChain &TC,
14211421
case types::TY_PCH:
14221422
case types::TY_ImportedModules:
14231423
case types::TY_TBD:
1424+
case types::TY_ModuleTrace:
14241425
// We could in theory handle assembly or LLVM input, but let's not.
14251426
// FIXME: What about LTO?
14261427
Diags.diagnose(SourceLoc(), diag::error_unexpected_input_file,
@@ -1685,6 +1686,36 @@ void Driver::buildJobs(const ActionList &Actions, const OutputInfo &OI,
16851686
}
16861687
}
16871688

1689+
static Optional<StringRef> getOutputFilenameFromPathArgOrAsTopLevel(
1690+
const OutputInfo &OI, const llvm::opt::DerivedArgList &Args,
1691+
llvm::opt::OptSpecifier PathArg, types::ID ExpectedOutputType,
1692+
bool TreatAsTopLevelOutput, StringRef ext, llvm::SmallString<128> &Buffer) {
1693+
if (const Arg *A = Args.getLastArg(PathArg))
1694+
return StringRef(A->getValue());
1695+
1696+
if (TreatAsTopLevelOutput) {
1697+
if (const Arg *A = Args.getLastArg(options::OPT_o)) {
1698+
if (OI.CompilerOutputType == ExpectedOutputType)
1699+
return StringRef(A->getValue());
1700+
1701+
// Otherwise, put the file next to the top-level output.
1702+
Buffer = A->getValue();
1703+
llvm::sys::path::remove_filename(Buffer);
1704+
llvm::sys::path::append(Buffer, OI.ModuleName);
1705+
llvm::sys::path::replace_extension(Buffer, ext);
1706+
return Buffer.str();
1707+
}
1708+
1709+
// A top-level output wasn't specified, so just output to
1710+
// <ModuleName>.<ext>.
1711+
Buffer = OI.ModuleName;
1712+
llvm::sys::path::replace_extension(Buffer, ext);
1713+
return Buffer.str();
1714+
}
1715+
1716+
return None;
1717+
}
1718+
16881719
static StringRef getOutputFilename(Compilation &C,
16891720
const JobAction *JA,
16901721
const OutputInfo &OI,
@@ -1707,29 +1738,14 @@ static StringRef getOutputFilename(Compilation &C,
17071738

17081739
// Process Action-specific output-specifying options next,
17091740
// since we didn't find anything applicable in the OutputMap.
1710-
if (isa<MergeModuleJobAction>(JA)) {
1711-
if (const Arg *A = Args.getLastArg(options::OPT_emit_module_path))
1712-
return A->getValue();
1713-
1714-
if (OI.ShouldTreatModuleAsTopLevelOutput) {
1715-
if (const Arg *A = Args.getLastArg(options::OPT_o)) {
1716-
if (OI.CompilerOutputType == types::TY_SwiftModuleFile)
1717-
return A->getValue();
1718-
1719-
// Otherwise, put the module next to the top-level output.
1720-
Buffer = A->getValue();
1721-
llvm::sys::path::remove_filename(Buffer);
1722-
llvm::sys::path::append(Buffer, OI.ModuleName);
1723-
llvm::sys::path::replace_extension(Buffer, SERIALIZED_MODULE_EXTENSION);
1724-
return Buffer.str();
1725-
}
17261741

1727-
// A top-level output wasn't specified, so just output to
1728-
// <ModuleName>.swiftmodule.
1729-
Buffer = OI.ModuleName;
1730-
llvm::sys::path::replace_extension(Buffer, SERIALIZED_MODULE_EXTENSION);
1731-
return Buffer.str();
1732-
}
1742+
if (isa<MergeModuleJobAction>(JA)) {
1743+
auto optFilename = getOutputFilenameFromPathArgOrAsTopLevel(
1744+
OI, Args, options::OPT_emit_module_path, types::TY_SwiftModuleFile,
1745+
OI.ShouldTreatModuleAsTopLevelOutput, SERIALIZED_MODULE_EXTENSION,
1746+
Buffer);
1747+
if (optFilename)
1748+
return *optFilename;
17331749
}
17341750

17351751
// dSYM actions are never treated as top-level.
@@ -2075,6 +2091,34 @@ Job *Driver::buildJobsForAction(Compilation &C, const JobAction *JA,
20752091
if (C.getIncrementalBuildEnabled()) {
20762092
addAuxiliaryOutput(C, *Output, types::TY_SwiftDeps, OI, OutputMap);
20772093
}
2094+
2095+
// The loaded-module-trace is the same for all compile jobs: all `import`
2096+
// statements are processed, even ones from non-primary files. Thus, only
2097+
// one of those jobs needs to emit the file, and we can get it to write
2098+
// straight to the desired final location.
2099+
auto tracePathEnvVar = getenv("SWIFT_LOADED_MODULE_TRACE_PATH");
2100+
auto shouldEmitTrace =
2101+
tracePathEnvVar ||
2102+
C.getArgs().hasArg(options::OPT_emit_loaded_module_trace,
2103+
options::OPT_emit_loaded_module_trace_path);
2104+
2105+
if (shouldEmitTrace &&
2106+
C.requestPermissionForFrontendToEmitLoadedModuleTrace()) {
2107+
StringRef filename;
2108+
// Prefer the environment variable.
2109+
if (tracePathEnvVar)
2110+
filename = StringRef(tracePathEnvVar);
2111+
else {
2112+
// By treating this as a top-level output, the return value always
2113+
// exists.
2114+
filename = *getOutputFilenameFromPathArgOrAsTopLevel(
2115+
OI, C.getArgs(), options::OPT_emit_loaded_module_trace_path,
2116+
types::TY_ModuleTrace,
2117+
/*TreatAsTopLevelOutput=*/true, "trace.json", Buf);
2118+
}
2119+
2120+
Output->setAdditionalOutputForType(types::TY_ModuleTrace, filename);
2121+
}
20782122
}
20792123

20802124
// Choose the Objective-C header output path.

lib/Driver/ToolChains.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -249,6 +249,7 @@ ToolChain::constructInvocation(const CompileJobAction &job,
249249
case types::TY_ObjCHeader:
250250
case types::TY_Image:
251251
case types::TY_SwiftDeps:
252+
case types::TY_ModuleTrace:
252253
llvm_unreachable("Output type can never be primary output.");
253254
case types::TY_INVALID:
254255
llvm_unreachable("Invalid type ID");
@@ -388,6 +389,13 @@ ToolChain::constructInvocation(const CompileJobAction &job,
388389
Arguments.push_back(ReferenceDependenciesPath.c_str());
389390
}
390391

392+
const std::string &LoadedModuleTracePath =
393+
context.Output.getAdditionalOutputForType(types::TY_ModuleTrace);
394+
if (!LoadedModuleTracePath.empty()) {
395+
Arguments.push_back("-emit-loaded-module-trace-path");
396+
Arguments.push_back(LoadedModuleTracePath.c_str());
397+
}
398+
391399
const std::string &FixitsPath =
392400
context.Output.getAdditionalOutputForType(types::TY_Remapping);
393401
if (!FixitsPath.empty()) {
@@ -518,6 +526,7 @@ ToolChain::constructInvocation(const BackendJobAction &job,
518526
case types::TY_Image:
519527
case types::TY_SwiftDeps:
520528
case types::TY_Remapping:
529+
case types::TY_ModuleTrace:
521530
llvm_unreachable("Output type can never be primary output.");
522531
case types::TY_INVALID:
523532
llvm_unreachable("Invalid type ID");

lib/Driver/Types.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@ bool types::isTextual(ID Id) {
7676
case types::TY_AutolinkFile:
7777
case types::TY_ImportedModules:
7878
case types::TY_TBD:
79+
case types::TY_ModuleTrace:
7980
return true;
8081
case types::TY_Image:
8182
case types::TY_Object:
@@ -127,6 +128,7 @@ bool types::isAfterLLVM(ID Id) {
127128
case types::TY_SwiftDeps:
128129
case types::TY_Nothing:
129130
case types::TY_Remapping:
131+
case types::TY_ModuleTrace:
130132
return false;
131133
case types::TY_INVALID:
132134
llvm_unreachable("Invalid type ID.");
@@ -163,6 +165,7 @@ bool types::isPartOfSwiftCompilation(ID Id) {
163165
case types::TY_SwiftDeps:
164166
case types::TY_Nothing:
165167
case types::TY_Remapping:
168+
case types::TY_ModuleTrace:
166169
return false;
167170
case types::TY_INVALID:
168171
llvm_unreachable("Invalid type ID.");

lib/Frontend/CompilerInvocation.cpp

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -676,6 +676,10 @@ static bool ParseFrontendArgs(FrontendOptions &Opts, ArgList &Args,
676676
OPT_emit_objc_header,
677677
OPT_emit_objc_header_path,
678678
"h", false);
679+
determineOutputFilename(Opts.LoadedModuleTracePath,
680+
OPT_emit_loaded_module_trace,
681+
OPT_emit_loaded_module_trace_path,
682+
"trace.json", false);
679683

680684
if (const Arg *A = Args.getLastArg(OPT_emit_fixits_path)) {
681685
Opts.FixitsOutputPath = A->getValue();
@@ -765,6 +769,39 @@ static bool ParseFrontendArgs(FrontendOptions &Opts, ArgList &Args,
765769
}
766770
}
767771

772+
if (!Opts.LoadedModuleTracePath.empty()) {
773+
switch (Opts.RequestedAction) {
774+
case FrontendOptions::NoneAction:
775+
case FrontendOptions::Parse:
776+
case FrontendOptions::DumpParse:
777+
case FrontendOptions::DumpInterfaceHash:
778+
case FrontendOptions::DumpAST:
779+
case FrontendOptions::PrintAST:
780+
case FrontendOptions::DumpScopeMaps:
781+
case FrontendOptions::DumpTypeRefinementContexts:
782+
case FrontendOptions::Immediate:
783+
case FrontendOptions::REPL:
784+
case FrontendOptions::UpdateCode:
785+
Diags.diagnose(SourceLoc(),
786+
diag::error_mode_cannot_emit_loaded_module_trace);
787+
return true;
788+
case FrontendOptions::Typecheck:
789+
case FrontendOptions::EmitModuleOnly:
790+
case FrontendOptions::EmitPCH:
791+
case FrontendOptions::EmitSILGen:
792+
case FrontendOptions::EmitSIL:
793+
case FrontendOptions::EmitSIBGen:
794+
case FrontendOptions::EmitSIB:
795+
case FrontendOptions::EmitIR:
796+
case FrontendOptions::EmitBC:
797+
case FrontendOptions::EmitAssembly:
798+
case FrontendOptions::EmitObject:
799+
case FrontendOptions::EmitImportedModules:
800+
case FrontendOptions::EmitTBD:
801+
break;
802+
}
803+
}
804+
768805
if (!Opts.ModuleOutputPath.empty() ||
769806
!Opts.ModuleDocOutputPath.empty()) {
770807
switch (Opts.RequestedAction) {

0 commit comments

Comments
 (0)