Skip to content

Commit 2dd49f5

Browse files
Merge pull request #80474 from cachemeifyoucan/eng/PR-148465899
[Caching][Macro] Make macro plugin options cacheable
2 parents 1445b81 + 3d38d0d commit 2dd49f5

12 files changed

+174
-11
lines changed

include/swift/AST/DiagnosticsSema.def

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1265,6 +1265,10 @@ REMARK(macro_loaded,none,
12651265
"compiler plugin server '%2' with shared library '%3'}1",
12661266
(Identifier, unsigned, StringRef, StringRef))
12671267

1268+
ERROR(resolved_macro_changed,none,
1269+
"resolved macro library '%0' failed verification: %1",
1270+
(StringRef, StringRef))
1271+
12681272
REMARK(transitive_dependency_behavior,none,
12691273
"%1 has %select{a required|an optional|an ignored}2 "
12701274
"transitive dependency on '%0'",

include/swift/AST/PluginLoader.h

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,10 +52,17 @@ class PluginLoader {
5252
/// Get or lazily create and populate 'PluginMap'.
5353
llvm::DenseMap<swift::Identifier, PluginEntry> &getPluginMap();
5454

55+
/// Resolved plugin path remappings.
56+
std::vector<std::string> PathRemap;
57+
5558
public:
5659
PluginLoader(ASTContext &Ctx, DependencyTracker *DepTracker,
60+
std::optional<std::vector<std::string>> Remap = std::nullopt,
5761
bool disableSandbox = false)
58-
: Ctx(Ctx), DepTracker(DepTracker), disableSandbox(disableSandbox) {}
62+
: Ctx(Ctx), DepTracker(DepTracker), disableSandbox(disableSandbox) {
63+
if (Remap)
64+
PathRemap = std::move(*Remap);
65+
}
5966

6067
void setRegistry(PluginRegistry *newValue);
6168
PluginRegistry *getRegistry();

include/swift/AST/SearchPathOptions.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -510,6 +510,9 @@ class SearchPathOptions {
510510
/// Scanner Prefix Mapper.
511511
std::vector<std::string> ScannerPrefixMapper;
512512

513+
/// Verify resolved plugin is not changed.
514+
bool ResolvedPluginVerification = false;
515+
513516
/// When set, don't validate module system dependencies.
514517
///
515518
/// If a system header is modified and this is not set, the compiler will

include/swift/Option/Options.td

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2263,6 +2263,10 @@ def load_resolved_plugin:
22632263
"and exectuable path can be empty if not used">,
22642264
MetaVarName<"<library-path>#<executable-path>#<module-names>">;
22652265

2266+
def resolved_plugin_verification : Flag<["-"], "resolved-plugin-verification">,
2267+
Flags<[FrontendOption, NoDriverOption]>,
2268+
HelpText<"verify resolved plugins">;
2269+
22662270
def in_process_plugin_server_path : Separate<["-"], "in-process-plugin-server-path">,
22672271
Flags<[FrontendOption, ArgumentIsPath]>,
22682272
HelpText<"Path to dynamic library plugin server">;

lib/AST/PluginLoader.cpp

Lines changed: 48 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,12 @@
1313
#include "swift/AST/PluginLoader.h"
1414
#include "swift/AST/ASTContext.h"
1515
#include "swift/AST/DiagnosticEngine.h"
16-
#include "swift/AST/DiagnosticsFrontend.h"
16+
#include "swift/AST/DiagnosticsSema.h"
1717
#include "swift/Basic/Assertions.h"
1818
#include "swift/Basic/SourceManager.h"
1919
#include "swift/Parse/Lexer.h"
2020
#include "llvm/Config/config.h"
21+
#include "llvm/Support/PrefixMapper.h"
2122
#include "llvm/Support/VirtualFileSystem.h"
2223

2324
using namespace swift;
@@ -96,9 +97,45 @@ PluginLoader::getPluginMap() {
9697
map[moduleNameIdentifier] = {libPath, execPath};
9798
};
9899

100+
std::optional<llvm::PrefixMapper> mapper;
101+
if (!PathRemap.empty()) {
102+
SmallVector<llvm::MappedPrefix, 4> prefixes;
103+
llvm::MappedPrefix::transformJoinedIfValid(PathRemap, prefixes);
104+
mapper.emplace();
105+
mapper->addRange(prefixes);
106+
mapper->sort();
107+
}
108+
auto remapPath = [&mapper](StringRef path) {
109+
if (!mapper)
110+
return path.str();
111+
return mapper->mapToString(path);
112+
};
113+
99114
auto fs = getPluginLoadingFS(Ctx);
100115
std::error_code ec;
101116

117+
auto validateLibrary = [&](StringRef path) -> llvm::Expected<std::string> {
118+
auto remappedPath = remapPath(path);
119+
if (!Ctx.SearchPathOpts.ResolvedPluginVerification || path.empty())
120+
return remappedPath;
121+
122+
auto currentStat = fs->status(remappedPath);
123+
if (!currentStat)
124+
return llvm::createFileError(remappedPath, currentStat.getError());
125+
126+
auto goldStat = Ctx.SourceMgr.getFileSystem()->status(path);
127+
if (!goldStat)
128+
return llvm::createStringError(
129+
"cannot open gold reference library to compare");
130+
131+
// Compare the size for difference for now.
132+
if (currentStat->getSize() != goldStat->getSize())
133+
return llvm::createStringError(
134+
"plugin has changed since dependency scanning");
135+
136+
return remappedPath;
137+
};
138+
102139
for (auto &entry : Ctx.SearchPathOpts.PluginSearchOpts) {
103140
switch (entry.getKind()) {
104141

@@ -156,9 +193,17 @@ PluginLoader::getPluginMap() {
156193
// Respect resolved plugin config above other search path, and it can
157194
// overwrite plugins found by other options or previous resolved
158195
// configuration.
159-
for (auto &moduleName : val.ModuleNames)
160-
try_emplace(moduleName, val.LibraryPath, val.ExecutablePath,
196+
for (auto &moduleName : val.ModuleNames) {
197+
auto libPath = validateLibrary(val.LibraryPath);
198+
if (!libPath) {
199+
Ctx.Diags.diagnose(SourceLoc(), diag::resolved_macro_changed,
200+
remapPath(val.LibraryPath),
201+
toString(libPath.takeError()));
202+
continue;
203+
}
204+
try_emplace(moduleName, *libPath, remapPath(val.ExecutablePath),
161205
/*overwrite*/ true);
206+
}
162207
continue;
163208
}
164209
}

lib/DependencyScan/ModuleDependencyScanner.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -201,6 +201,7 @@ ModuleDependencyScanningWorker::ModuleDependencyScanningWorker(
201201
ScanASTContext.SourceMgr, Diagnostics));
202202
auto loader = std::make_unique<PluginLoader>(
203203
*workerASTContext, /*DepTracker=*/nullptr,
204+
workerCompilerInvocation->getFrontendOptions().CacheReplayPrefixMap,
204205
workerCompilerInvocation->getFrontendOptions().DisableSandbox);
205206
workerASTContext->setPluginLoader(std::move(loader));
206207

lib/DependencyScan/ScanDependencies.cpp

Lines changed: 21 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -214,9 +214,23 @@ class ExplicitModuleDependencyResolver {
214214
depInfo.addMacroDependency(macro.first(), macro.second.LibraryPath,
215215
macro.second.ExecutablePath);
216216

217+
bool needPathRemapping = instance.getInvocation()
218+
.getSearchPathOptions()
219+
.ResolvedPluginVerification &&
220+
cache.getScanService().hasPathMapping();
221+
auto mapPath = [&](StringRef path) {
222+
if (!needPathRemapping)
223+
return path.str();
224+
225+
return cache.getScanService().remapPath(path);
226+
};
227+
if (needPathRemapping)
228+
commandline.push_back("-resolved-plugin-verification");
229+
217230
for (auto &macro : depInfo.getMacroDependencies()) {
218-
std::string arg = macro.second.LibraryPath + "#" +
219-
macro.second.ExecutablePath + "#" + macro.first;
231+
std::string arg = mapPath(macro.second.LibraryPath) + "#" +
232+
mapPath(macro.second.ExecutablePath) + "#" +
233+
macro.first;
220234
commandline.push_back("-load-resolved-plugin");
221235
commandline.push_back(arg);
222236
}
@@ -480,9 +494,10 @@ class ExplicitModuleDependencyResolver {
480494
llvm::for_each(
481495
sourceDep->auxiliaryFiles,
482496
[this](const std::string &file) { tracker->trackFile(file); });
483-
llvm::for_each(sourceDep->macroDependencies, [this](const auto &entry) {
484-
tracker->trackFile(entry.second.LibraryPath);
485-
});
497+
llvm::for_each(dependencyInfoCopy.getMacroDependencies(),
498+
[this](const auto &entry) {
499+
tracker->trackFile(entry.second.LibraryPath);
500+
});
486501
auto root = tracker->createTreeFromDependencies();
487502
if (!root)
488503
return root.takeError();
@@ -496,7 +511,7 @@ class ExplicitModuleDependencyResolver {
496511
llvm::for_each(
497512
textualDep->auxiliaryFiles,
498513
[this](const std::string &file) { tracker->trackFile(file); });
499-
llvm::for_each(textualDep->macroDependencies,
514+
llvm::for_each(dependencyInfoCopy.getMacroDependencies(),
500515
[this](const auto &entry) {
501516
tracker->trackFile(entry.second.LibraryPath);
502517
});

lib/Frontend/CachedDiagnostics.cpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,9 @@
1818

1919
#include "swift/AST/DiagnosticBridge.h"
2020
#include "swift/AST/DiagnosticConsumer.h"
21+
#include "swift/AST/DiagnosticsCommon.h"
2122
#include "swift/AST/DiagnosticsFrontend.h"
23+
#include "swift/AST/DiagnosticsSema.h"
2224
#include "swift/Basic/Assertions.h"
2325
#include "swift/Basic/SourceManager.h"
2426
#include "swift/Frontend/Frontend.h"
@@ -755,6 +757,13 @@ class CachingDiagnosticsProcessor::Implementation
755757
auto &Serializer = getSerializer();
756758
assert(SM.getFileSystem() == Serializer.getSourceMgr().getFileSystem() &&
757759
"Caching for a different file system");
760+
761+
// Bypass the caching.
762+
if (BypassDiagIDs.count(Info.ID)) {
763+
for (auto *Diag : OrigConsumers)
764+
Diag->handleDiagnostic(Serializer.getSourceMgr(), Info);
765+
return;
766+
}
758767
Serializer.handleDiagnostic(SM, Info, [&](const DiagnosticInfo &Info) {
759768
for (auto *Diag : OrigConsumers)
760769
Diag->handleDiagnostic(Serializer.getSourceMgr(), Info);
@@ -809,6 +818,8 @@ class CachingDiagnosticsProcessor::Implementation
809818
// Processor/Serializer alive until then.
810819
std::unique_ptr<DiagnosticSerializer> Serializer;
811820

821+
const llvm::SmallDenseSet<DiagID> BypassDiagIDs = {diag::macro_loaded.ID};
822+
812823
SourceManager &InstanceSourceMgr;
813824
const FrontendInputsAndOutputs &InAndOut;
814825
DiagnosticEngine &Diags;

lib/Frontend/CompilerInvocation.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2417,6 +2417,9 @@ static bool ParseSearchPathArgs(SearchPathOptions &Opts, ArgList &Args,
24172417
Opts.ScannerPrefixMapper.push_back(Opt.str());
24182418
}
24192419

2420+
Opts.ResolvedPluginVerification |=
2421+
Args.hasArg(OPT_resolved_plugin_verification);
2422+
24202423
// rdar://132340493 disable scanner-side validation for non-caching builds
24212424
Opts.ScannerModuleValidation |= Args.hasFlag(OPT_scanner_module_validation,
24222425
OPT_no_scanner_module_validation,

lib/Frontend/Frontend.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -878,6 +878,7 @@ bool CompilerInstance::setUpPluginLoader() {
878878
/// FIXME: If Invocation has 'PluginRegistry', we can set it. But should we?
879879
auto loader = std::make_unique<PluginLoader>(
880880
*Context, getDependencyTracker(),
881+
Invocation.getFrontendOptions().CacheReplayPrefixMap,
881882
Invocation.getFrontendOptions().DisableSandbox);
882883
Context->setPluginLoader(std::move(loader));
883884
return false;

0 commit comments

Comments
 (0)