Skip to content

Commit b8a073c

Browse files
committed
[Macros] Create plugin search lookup table.
Iterating all options and potential file system access is not great for every plugin lookup request. Instead, lazily create a single lookup table keyed by module name.
1 parent 13a29a0 commit b8a073c

File tree

3 files changed

+106
-61
lines changed

3 files changed

+106
-61
lines changed

include/swift/AST/PluginLoader.h

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,13 @@ class ASTContext;
2828
/// * Load plugins resolving VFS paths
2929
/// * Track plugin dependencies
3030
class PluginLoader {
31+
public:
32+
struct PluginEntry {
33+
StringRef libraryPath;
34+
StringRef executablePath;
35+
};
36+
37+
private:
3138
/// Plugin registry. Lazily populated by get/setRegistry().
3239
/// NOTE: Do not reference this directly. Use getRegistry().
3340
PluginRegistry *Registry = nullptr;
@@ -38,16 +45,15 @@ class PluginLoader {
3845
ASTContext &Ctx;
3946
DependencyTracker *DepTracker;
4047

41-
/// Map a module name to an executable plugin path that provides the module.
42-
llvm::DenseMap<swift::Identifier, llvm::StringRef> ExecutablePluginPaths;
48+
/// Map a module name to an plugin entry that provides the module.
49+
llvm::Optional<llvm::DenseMap<swift::Identifier, PluginEntry>> PluginMap;
4350

44-
void createModuleToExecutablePluginMap();
51+
/// Get or lazily create and populate 'PluginMap'.
52+
llvm::DenseMap<swift::Identifier, PluginEntry> &getPluginMap();
4553

4654
public:
4755
PluginLoader(ASTContext &Ctx, DependencyTracker *DepTracker)
48-
: Ctx(Ctx), DepTracker(DepTracker) {
49-
createModuleToExecutablePluginMap();
50-
}
56+
: Ctx(Ctx), DepTracker(DepTracker) {}
5157

5258
void setRegistry(PluginRegistry *newValue);
5359
PluginRegistry *getRegistry();
@@ -63,8 +69,7 @@ class PluginLoader {
6369
/// 'loadExecutablePlugin()'.
6470
/// * (libPath: some, execPath: some) - load the executable path by
6571
/// 'loadExecutablePlugin()' and let the plugin load the libPath via IPC.
66-
std::pair<std::string, std::string>
67-
lookupPluginByModuleName(Identifier moduleName);
72+
const PluginEntry &lookupPluginByModuleName(Identifier moduleName);
6873

6974
/// Load the specified dylib plugin path resolving the path with the
7075
/// current VFS. If it fails to load the plugin, a diagnostic is emitted, and

lib/AST/PluginLoader.cpp

Lines changed: 86 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -15,23 +15,11 @@
1515
#include "swift/AST/DiagnosticEngine.h"
1616
#include "swift/AST/DiagnosticsFrontend.h"
1717
#include "swift/Basic/SourceManager.h"
18+
#include "swift/Parse/Lexer.h"
1819
#include "llvm/Config/config.h"
1920

2021
using namespace swift;
2122

22-
void PluginLoader::createModuleToExecutablePluginMap() {
23-
for (auto &elem : Ctx.SearchPathOpts.PluginSearchOpts) {
24-
if (auto *arg = elem.dyn_cast<PluginSearchOption::LoadPluginExecutable>()) {
25-
// Create a moduleName -> pluginPath mapping.
26-
assert(!arg->ExecutablePath.empty() && "empty plugin path");
27-
StringRef pathStr = Ctx.AllocateCopy(arg->ExecutablePath);
28-
for (auto moduleName : arg->ModuleNames) {
29-
ExecutablePluginPaths[Ctx.getIdentifier(moduleName)] = pathStr;
30-
}
31-
}
32-
}
33-
}
34-
3523
void PluginLoader::setRegistry(PluginRegistry *newValue) {
3624
assert(Registry == nullptr && "Too late to set a new plugin registry");
3725
Registry = newValue;
@@ -48,65 +36,121 @@ PluginRegistry *PluginLoader::getRegistry() {
4836
return Registry;
4937
}
5038

51-
std::pair<std::string, std::string>
52-
PluginLoader::lookupPluginByModuleName(Identifier moduleName) {
53-
auto fs = Ctx.SourceMgr.getFileSystem();
54-
55-
// Look for 'lib${module name}(.dylib|.so)'.
39+
/// Get plugin module name from \p path if the path looks like a shared library
40+
/// path. Otherwise, returns an empty string.
41+
static StringRef pluginModuleNameStringFromPath(StringRef path) {
42+
// Plugin library must be named 'lib${module name}(.dylib|.so|.dll)'.
5643
// FIXME: Shared library prefix might be different between platforms.
57-
SmallString<64> pluginLibBasename;
58-
pluginLibBasename.append("lib");
59-
pluginLibBasename.append(moduleName.str());
60-
pluginLibBasename.append(LTDL_SHLIB_EXT);
44+
constexpr StringRef libPrefix = "lib";
45+
constexpr StringRef libSuffix = LTDL_SHLIB_EXT;
46+
47+
StringRef filename = llvm::sys::path::filename(path);
48+
if (filename.starts_with(libPrefix) && filename.ends_with(libSuffix)) {
49+
// We don't check if the result it a valid identifier. Even if we put
50+
// invalid name in the lookup table, clients wound not be able to lookup
51+
// that name, thus harmless.
52+
return filename.drop_front(libPrefix.size()).drop_back(libSuffix.size());
53+
}
54+
return "";
55+
}
56+
57+
llvm::DenseMap<Identifier, PluginLoader::PluginEntry> &
58+
PluginLoader::getPluginMap() {
59+
if (PluginMap.has_value()) {
60+
return PluginMap.value();
61+
}
62+
63+
// Create and populate the map.
64+
PluginMap.emplace();
65+
auto &map = PluginMap.value();
66+
67+
// Helper function to try inserting an entry if there's no existing entry
68+
// associated with the module name.
69+
auto try_emplace = [&](StringRef moduleName, StringRef libPath,
70+
StringRef execPath) {
71+
auto moduleNameIdentifier = Ctx.getIdentifier(moduleName);
72+
if (map.find(moduleNameIdentifier) != map.end()) {
73+
// Specified module name is already in the map.
74+
return;
75+
}
76+
77+
libPath = libPath.empty() ? "" : Ctx.AllocateCopy(libPath);
78+
execPath = execPath.empty() ? "" : Ctx.AllocateCopy(execPath);
79+
auto result = map.insert({moduleNameIdentifier, {libPath, execPath}});
80+
assert(result.second);
81+
(void)result;
82+
};
83+
84+
auto fs = Ctx.SourceMgr.getFileSystem();
85+
std::error_code ec;
6186

62-
// FIXME: Should we create a lookup table keyed by module name?
6387
for (auto &entry : Ctx.SearchPathOpts.PluginSearchOpts) {
6488
switch (entry.getKind()) {
65-
// Try '-load-plugin-library'.
89+
90+
// '-load-plugin-library <library path>'.
6691
case PluginSearchOption::Kind::LoadPluginLibrary: {
6792
auto &val = entry.get<PluginSearchOption::LoadPluginLibrary>();
68-
if (llvm::sys::path::filename(val.LibraryPath) == pluginLibBasename) {
69-
return {val.LibraryPath, ""};
93+
auto moduleName = pluginModuleNameStringFromPath(val.LibraryPath);
94+
if (!moduleName.empty()) {
95+
try_emplace(moduleName, val.LibraryPath, /*executablePath=*/"");
7096
}
7197
continue;
7298
}
7399

74-
// Try '-load-plugin-executable'.
100+
// '-load-plugin-executable <executable path>#<module name>, ...'.
75101
case PluginSearchOption::Kind::LoadPluginExecutable: {
76102
auto &val = entry.get<PluginSearchOption::LoadPluginExecutable>();
77-
auto found = ExecutablePluginPaths.find(moduleName);
78-
if (found != ExecutablePluginPaths.end() &&
79-
found->second == val.ExecutablePath) {
80-
return {"", val.ExecutablePath};
103+
assert(!val.ExecutablePath.empty() && "empty plugin path");
104+
for (auto &moduleName : val.ModuleNames) {
105+
try_emplace(moduleName, /*libraryPath=*/"", val.ExecutablePath);
81106
}
82107
continue;
83108
}
84109

85-
// Try '-plugin-path'.
110+
// '-plugin-path <library search path>'.
86111
case PluginSearchOption::Kind::PluginPath: {
87112
auto &val = entry.get<PluginSearchOption::PluginPath>();
88-
SmallString<128> fullPath(val.SearchPath);
89-
llvm::sys::path::append(fullPath, pluginLibBasename);
90-
if (fs->exists(fullPath)) {
91-
return {std::string(fullPath), ""};
113+
for (auto i = fs->dir_begin(val.SearchPath, ec);
114+
i != llvm::vfs::directory_iterator(); i = i.increment(ec)) {
115+
auto libPath = i->path();
116+
auto moduleName = pluginModuleNameStringFromPath(libPath);
117+
if (!moduleName.empty()) {
118+
try_emplace(moduleName, libPath, /*executablePath=*/"");
119+
}
92120
}
93121
continue;
94122
}
95123

96-
// Try '-external-plugin-path'.
124+
// '-external-plugin-path <library search path>#<server path>'.
97125
case PluginSearchOption::Kind::ExternalPluginPath: {
98126
auto &val = entry.get<PluginSearchOption::ExternalPluginPath>();
99-
SmallString<128> fullPath(val.SearchPath);
100-
llvm::sys::path::append(fullPath, pluginLibBasename);
101-
if (fs->exists(fullPath)) {
102-
return {std::string(fullPath), val.ServerPath};
127+
for (auto i = fs->dir_begin(val.SearchPath, ec);
128+
i != llvm::vfs::directory_iterator(); i = i.increment(ec)) {
129+
auto libPath = i->path();
130+
auto moduleName = pluginModuleNameStringFromPath(libPath);
131+
if (!moduleName.empty()) {
132+
try_emplace(moduleName, libPath, val.ServerPath);
133+
}
103134
}
104135
continue;
105136
}
106137
}
138+
llvm_unreachable("unhandled PluginSearchOption::Kind");
107139
}
108140

109-
return {};
141+
return map;
142+
}
143+
144+
const PluginLoader::PluginEntry &
145+
PluginLoader::lookupPluginByModuleName(Identifier moduleName) {
146+
auto &map = getPluginMap();
147+
auto found = map.find(moduleName);
148+
if (found != map.end()) {
149+
return found->second;
150+
} else {
151+
static PluginEntry notFound{"", ""};
152+
return notFound;
153+
}
110154
}
111155

112156
LoadedLibraryPlugin *PluginLoader::loadLibraryPlugin(StringRef path) {

lib/Sema/TypeCheckMacros.cpp

Lines changed: 7 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -342,21 +342,17 @@ LoadedCompilerPlugin
342342
CompilerPluginLoadRequest::evaluate(Evaluator &evaluator, ASTContext *ctx,
343343
Identifier moduleName) const {
344344
PluginLoader &loader = ctx->getPluginLoader();
345+
const auto &entry = loader.lookupPluginByModuleName(moduleName);
345346

346-
std::string libraryPath;
347-
std::string executablePath;
348-
std::tie(libraryPath, executablePath) =
349-
loader.lookupPluginByModuleName(moduleName);
350-
351-
if (!executablePath.empty()) {
347+
if (!entry.executablePath.empty()) {
352348
if (LoadedExecutablePlugin *executablePlugin =
353-
loader.loadExecutablePlugin(executablePath)) {
354-
return initializeExecutablePlugin(*ctx, executablePlugin, libraryPath,
355-
moduleName);
349+
loader.loadExecutablePlugin(entry.executablePath)) {
350+
return initializeExecutablePlugin(*ctx, executablePlugin,
351+
entry.libraryPath, moduleName);
356352
}
357-
} else if (!libraryPath.empty()) {
353+
} else if (!entry.libraryPath.empty()) {
358354
if (LoadedLibraryPlugin *libraryPlugin =
359-
loader.loadLibraryPlugin(libraryPath)) {
355+
loader.loadLibraryPlugin(entry.libraryPath)) {
360356
return libraryPlugin;
361357
}
362358
}

0 commit comments

Comments
 (0)