Skip to content

Commit 93e77f3

Browse files
authored
Merge pull request #64793 from rintaro/5.9-cherry-pick-marcroserver
[5.9] Bundle macro plugin changes
2 parents 5d64c8b + 447637c commit 93e77f3

26 files changed

+497
-215
lines changed

include/swift/AST/ASTContext.h

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1461,12 +1461,21 @@ class ASTContext final {
14611461
/// The declared interface type of Builtin.TheTupleType.
14621462
BuiltinTupleType *getBuiltinTupleType();
14631463

1464-
/// Finds the address of the given symbol. If `libraryHandleHint` is non-null,
1465-
/// search within the library.
1466-
void *getAddressOfSymbol(const char *name, void *libraryHandleHint = nullptr);
1467-
14681464
Type getNamedSwiftType(ModuleDecl *module, StringRef name);
14691465

1466+
/// Lookup a library plugin that can handle \p moduleName and return the path
1467+
/// to it.
1468+
/// The path is valid within the VFS, use `FS.getRealPath()` for the
1469+
/// underlying path.
1470+
Optional<std::string> lookupLibraryPluginByModuleName(Identifier moduleName);
1471+
1472+
/// Load the specified dylib plugin path resolving the path with the
1473+
/// current VFS. If it fails to load the plugin, a diagnostic is emitted, and
1474+
/// returns a nullptr.
1475+
/// NOTE: This method is idempotent. If the plugin is already loaded, the same
1476+
/// instance is simply returned.
1477+
void *loadLibraryPlugin(StringRef path);
1478+
14701479
/// Lookup an executable plugin that is declared to handle \p moduleName
14711480
/// module by '-load-plugin-executable'.
14721481
/// The path is valid within the VFS, use `FS.getRealPath()` for the
@@ -1494,6 +1503,8 @@ class ASTContext final {
14941503
/// This should be called before any plugin is loaded.
14951504
void setPluginRegistry(PluginRegistry *newValue);
14961505

1506+
const llvm::StringSet<> &getLoadedPluginLibraryPaths() const;
1507+
14971508
private:
14981509
friend Decl;
14991510

@@ -1506,7 +1517,7 @@ class ASTContext final {
15061517
Optional<StringRef> getBriefComment(const Decl *D);
15071518
void setBriefComment(const Decl *D, StringRef Comment);
15081519

1509-
void loadCompilerPlugins();
1520+
void createModuleToExecutablePluginMap();
15101521

15111522
friend TypeBase;
15121523
friend ArchetypeType;

include/swift/AST/CASTBridging.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -317,6 +317,9 @@ void Plugin_lock(PluginHandle handle);
317317
/// Unlock the plugin.
318318
void Plugin_unlock(PluginHandle handle);
319319

320+
/// Launch the plugin if it's not running.
321+
_Bool Plugin_spawnIfNeeded(PluginHandle handle);
322+
320323
/// Sends the message to the plugin, returns true if there was an error.
321324
/// Clients should receive the response by \c Plugin_waitForNextMessage .
322325
_Bool Plugin_sendMessage(PluginHandle handle, const BridgedData data);

include/swift/AST/DiagnosticsFrontend.def

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,9 @@ ERROR(error_invalid_source_location_str,none,
128128
ERROR(error_no_source_location_scope_map,none,
129129
"-dump-scope-maps argument must be 'expanded' or a list of "
130130
"source locations", ())
131+
ERROR(error_load_plugin_executable,none,
132+
"invalid value '%0' in '-load-plugin-executable'; "
133+
"make sure to use format '<plugin path>#<module names>'", (StringRef))
131134

132135
NOTE(note_valid_swift_versions, none,
133136
"valid arguments to '-swift-version' are %0", (StringRef))

include/swift/AST/PluginRegistry.h

Lines changed: 81 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -22,36 +22,82 @@
2222

2323
namespace swift {
2424

25+
/// Represent a "resolved" exectuable plugin.
26+
///
27+
/// Plugin clients usually deal with this object to communicate with the actual
28+
/// plugin implementation.
29+
/// This object has a file path of the plugin executable, and is responsible to
30+
/// launch it and manages the process. When the plugin process crashes, this
31+
/// should automatically relaunch the process so the clients can keep using this
32+
/// object as the interface.
2533
class LoadedExecutablePlugin {
26-
const llvm::sys::procid_t pid;
34+
35+
/// Represents the current process of the executable plugin.
36+
struct PluginProcess {
37+
const llvm::sys::procid_t pid;
38+
const int inputFileDescriptor;
39+
const int outputFileDescriptor;
40+
bool isStale = false;
41+
42+
PluginProcess(llvm::sys::procid_t pid, int inputFileDescriptor,
43+
int outputFileDescriptor);
44+
45+
~PluginProcess();
46+
47+
ssize_t write(const void *buf, size_t nbyte) const;
48+
ssize_t read(void *buf, size_t nbyte) const;
49+
};
50+
51+
/// Launched current process.
52+
std::unique_ptr<PluginProcess> Process;
53+
54+
/// Path to the plugin executable.
55+
const std::string ExecutablePath;
56+
57+
/// Last modification time of the `ExecutablePath` when this is initialized.
2758
const llvm::sys::TimePoint<> LastModificationTime;
28-
const int inputFileDescriptor;
29-
const int outputFileDescriptor;
3059

3160
/// Opaque value of the protocol capability of the pluugin. This is a
3261
/// value from ASTGen.
3362
const void *capability = nullptr;
3463

64+
/// Callbacks to be called when the connection is restored.
65+
llvm::SmallVector<std::function<void(void)> *, 0> onReconnect;
66+
67+
/// Flag to dump plugin messagings.
68+
bool dumpMessaging = false;
69+
3570
/// Cleanup function to call ASTGen.
3671
std::function<void(void)> cleanup;
3772

3873
std::mutex mtx;
3974

40-
ssize_t write(const void *buf, size_t nbyte) const;
41-
ssize_t read(void *buf, size_t nbyte) const;
42-
4375
public:
44-
LoadedExecutablePlugin(llvm::sys::procid_t pid,
45-
llvm::sys::TimePoint<> LastModificationTime,
46-
int inputFileDescriptor, int outputFileDescriptor);
76+
LoadedExecutablePlugin(llvm::StringRef ExecutablePath,
77+
llvm::sys::TimePoint<> LastModificationTime)
78+
: ExecutablePath(ExecutablePath),
79+
LastModificationTime(LastModificationTime){};
4780
~LoadedExecutablePlugin();
81+
82+
/// The last modification time of 'ExecutablePath' when this object is
83+
/// created.
4884
llvm::sys::TimePoint<> getLastModificationTime() const {
4985
return LastModificationTime;
5086
}
5187

88+
/// Indicates that the current process is usable.
89+
bool isAlive() const { return Process != nullptr && !Process->isStale; }
90+
91+
/// Mark the current process "stale".
92+
void setStale() const { Process->isStale = true; }
93+
5294
void lock() { mtx.lock(); }
5395
void unlock() { mtx.unlock(); }
5496

97+
// Launch the plugin if it's not already running, or it's stale. Return an
98+
// error if it's fails to execute it.
99+
llvm::Error spawnIfNeeded();
100+
55101
/// Send a message to the plugin.
56102
llvm::Error sendMessage(llvm::StringRef message) const;
57103

@@ -63,10 +109,23 @@ class LoadedExecutablePlugin {
63109
this->cleanup = cleanup;
64110
}
65111

66-
llvm::sys::procid_t getPid() { return pid; }
112+
/// Add "on reconnect" callback.
113+
/// These callbacks are called when `spawnIfNeeded()` relaunched the plugin.
114+
void addOnReconnect(std::function<void(void)> *fn) {
115+
onReconnect.push_back(fn);
116+
}
117+
118+
/// Remove "on reconnect" callback.
119+
void removeOnReconnect(std::function<void(void)> *fn) {
120+
llvm::erase_value(onReconnect, fn);
121+
}
122+
123+
llvm::sys::procid_t getPid() { return Process->pid; }
67124

68125
const void *getCapability() { return capability; };
69126
void setCapability(const void *newValue) { capability = newValue; };
127+
128+
void setDumpMessaging(bool flag) { dumpMessaging = flag; }
70129
};
71130

72131
class PluginRegistry {
@@ -77,14 +136,22 @@ class PluginRegistry {
77136
llvm::StringMap<std::unique_ptr<LoadedExecutablePlugin>>
78137
LoadedPluginExecutables;
79138

139+
/// Flag to dump plugin messagings.
140+
bool dumpMessaging = false;
141+
142+
std::mutex mtx;
143+
80144
public:
145+
PluginRegistry();
146+
147+
/// Load a dynamic link library specified by \p path.
148+
/// If \p path plugin is already loaded, this returns the cached object.
81149
llvm::Expected<void *> loadLibraryPlugin(llvm::StringRef path);
150+
151+
/// Load an executable plugin specified by \p path .
152+
/// If \p path plugin is already loaded, this returns the cached object.
82153
llvm::Expected<LoadedExecutablePlugin *>
83154
loadExecutablePlugin(llvm::StringRef path);
84-
85-
const llvm::StringMap<void *> &getLoadedLibraryPlugins() const {
86-
return LoadedPluginLibraries;
87-
}
88155
};
89156

90157
} // namespace swift

include/swift/AST/SearchPathOptions.h

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -174,6 +174,12 @@ class ModuleSearchPathLookup {
174174
llvm::vfs::FileSystem *FS, bool IsOSDarwin);
175175
};
176176

177+
/// Pair of a plugin path and the module name that the plugin provides.
178+
struct PluginExecutablePathAndModuleNames {
179+
std::string ExecutablePath;
180+
std::vector<std::string> ModuleNames;
181+
};
182+
177183
/// Pair of a plugin search path and the corresponding plugin server executable
178184
/// path.
179185
struct ExternalPluginSearchPathAndServerPath {
@@ -242,8 +248,7 @@ class SearchPathOptions {
242248
std::vector<std::string> CompilerPluginLibraryPaths;
243249

244250
/// Compiler plugin executable paths and providing module names.
245-
/// Format: '<path>#<module names>'
246-
std::vector<std::string> CompilerPluginExecutablePaths;
251+
std::vector<PluginExecutablePathAndModuleNames> CompilerPluginExecutablePaths;
247252

248253
/// Add a single import search path. Must only be called from
249254
/// \c ASTContext::addSearchPath.
@@ -361,12 +366,13 @@ class SearchPathOptions {
361366
}
362367

363368
void setCompilerPluginExecutablePaths(
364-
std::vector<std::string> NewCompilerPluginExecutablePaths) {
365-
CompilerPluginExecutablePaths = NewCompilerPluginExecutablePaths;
369+
std::vector<PluginExecutablePathAndModuleNames> &&newValue) {
370+
CompilerPluginExecutablePaths = std::move(newValue);
366371
Lookup.searchPathsDidChange();
367372
}
368373

369-
ArrayRef<std::string> getCompilerPluginExecutablePaths() const {
374+
ArrayRef<PluginExecutablePathAndModuleNames>
375+
getCompilerPluginExecutablePaths() const {
370376
return CompilerPluginExecutablePaths;
371377
}
372378

include/swift/IDETool/CompileInstance.h

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,13 +25,15 @@ namespace swift {
2525

2626
class CompilerInstance;
2727
class DiagnosticConsumer;
28+
class PluginRegistry;
2829

2930
namespace ide {
3031

3132
/// Manages \c CompilerInstance for completion like operations.
3233
class CompileInstance {
3334
const std::string &RuntimeResourcePath;
3435
const std::string &DiagnosticDocumentationPath;
36+
const std::shared_ptr<swift::PluginRegistry> Plugins;
3537

3638
struct Options {
3739
unsigned MaxASTReuseCount = 100;
@@ -66,10 +68,11 @@ class CompileInstance {
6668

6769
public:
6870
CompileInstance(const std::string &RuntimeResourcePath,
69-
const std::string &DiagnosticDocumentationPath)
71+
const std::string &DiagnosticDocumentationPath,
72+
std::shared_ptr<swift::PluginRegistry> Plugins = nullptr)
7073
: RuntimeResourcePath(RuntimeResourcePath),
7174
DiagnosticDocumentationPath(DiagnosticDocumentationPath),
72-
CachedCIInvalidated(false), CachedReuseCount(0) {}
75+
Plugins(Plugins), CachedCIInvalidated(false), CachedReuseCount(0) {}
7376

7477
/// NOTE: \p Args is only used for checking the equaity of the invocation.
7578
/// Since this function assumes that it is already normalized, exact the same

include/swift/IDETool/IDEInspectionInstance.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ namespace swift {
3535
class CompilerInstance;
3636
class CompilerInvocation;
3737
class DiagnosticConsumer;
38+
class PluginRegistry;
3839

3940
namespace ide {
4041

@@ -96,6 +97,8 @@ class IDEInspectionInstance {
9697

9798
std::mutex mtx;
9899

100+
std::shared_ptr<PluginRegistry> Plugins;
101+
99102
std::shared_ptr<CompilerInstance> CachedCI;
100103
llvm::hash_code CachedArgHash;
101104
llvm::sys::TimePoint<> DependencyCheckedTimestamp;
@@ -167,7 +170,8 @@ class IDEInspectionInstance {
167170
Callback);
168171

169172
public:
170-
IDEInspectionInstance() : CachedCIShouldBeInvalidated(false) {}
173+
IDEInspectionInstance(std::shared_ptr<PluginRegistry> Plugins = nullptr)
174+
: Plugins(Plugins), CachedCIShouldBeInvalidated(false) {}
171175

172176
// Mark the cached compiler instance "should be invalidated". In the next
173177
// completion, new compiler instance will be used. (Thread safe.)

0 commit comments

Comments
 (0)