Skip to content
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

[Macros] In-process plugin server #73725

Open
wants to merge 1 commit into
base: main
Choose a base branch
from

Conversation

rintaro
Copy link
Member

@rintaro rintaro commented May 17, 2024

Separate swift-syntax libs for the compiler and for the library plugins. Compiler communicates with library plugins using serialized messages just like executable plugins.

  • lib/swift/host/compiler/lib_Compiler*.dylib(source lib/CompilerSwiftSyntax): swift-syntax libraries for compiler. Library evolution is disabled.

  • Compiler (ASTGen and swiftIDEUtilsBridging) only depends on lib/swift/host/compiler libraries.

  • lib/swift/host/libSwiftInProcPluginServer.dylib (source tools/swift-plugin-server/Sources/SwiftInProcPluginServer): In-process plugin server shared library. This has one swift_inproc_plugins_handle_message entry point that receives a message and return the response.

  • In the compiler:

    • Add -in-process-plugin-server-path front-end option, which specifies the SwiftInProcPluginServer shared library path.
    • Remove LoadedLibraryPlugin, because all library plugins are managed by SwiftInProcPluginServer
    • Introduce abstract CompilerPlugin class that has 2 subclasses:
      • LoadedExecutablePlugin existing class that represents an executable plugin
      • InProcessPlugins wraps dlopened SwiftInProcPluginServer and communicate with it via the swift_inproc_plugins_handle_message
    • Unified the code path in TypeCheckMacros.cpp and ASTGen, the difference between executable plugins and library plugins are now abstracted by CompilerPlugin

Comment on lines 28 to 47
# Make unified swift-syntax shared library.
add_pure_swift_host_library(swiftSyntaxUnified SHARED)
set_target_properties(swiftSyntaxUnified PROPERTIES LINKER_LANGUAGE Swift)

macro(target_link_libraries_whole_archive target)
foreach(lib ${ARGN})
target_compile_options(${lib} PRIVATE "SHELL:-module-link-name ${target}")
target_sources(${target} PRIVATE $<TARGET_OBJECTS:${lib}>)
# Workaround for CMake doesn't recognize '.o' files as sources.
target_link_options(${target} PRIVATE $<TARGET_OBJECTS:${lib}>)
set_property(TARGET ${target} APPEND PROPERTY
INTERFACE_INCLUDE_DIRECTORIES "$<TARGET_PROPERTY:${lib},INTERFACE_INCLUDE_DIRECTORIES>"
)
Copy link
Member Author

@rintaro rintaro May 17, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of making an aggregated swift-syntax libraries, can we link those static libraries with ASTGen and make libASTGen.dylib?

edit: no because ASTGen depends on C++ code.

@@ -319,7 +319,7 @@ class PluginDiagnosticsEngine {
messageSuffix: String? = nil
) {
for diagnostic in diagnostics {
self.emit(diagnostic)
self.emit(diagnostic, messageSuffix: messageSuffix)
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We had a bug in executable plugins where (from macro '\(macroName)') suffix wasn't added in the diagnostics from executable plugins 😞

llvm::StringMap<void *> resolvedSymbols;
std::mutex mtx;

/// Opaque value of the protocol capability of the pluugin. This is a
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
/// Opaque value of the protocol capability of the pluugin. This is a
/// Opaque value of the protocol capability of the plugin. This is a

// Already loaded.
return storage.get();
CompilerPlugin::~CompilerPlugin() {
// Let ASTGen to cleanup things.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// Let ASTGen to cleanup things.
// Let ASTGen do cleanup things.

Comment on lines 106 to 107
auto message = receivedResponse;
receivedResponse = "";
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could get rid of the string copy here, but probably doesn't matter that much

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

SWIFT_DEFER { receivedResponse = ""; };
return std::move(receivedResponse);

Comment on lines 53 to 54
llvm::Expected<InProcessPlugins *>
InProcessPlugins::create(const char *serverPath) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Any reason not to have this return a unique_ptr?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No. Changed to return unique_ptr 👍

var basename: String {
guard
let lastSlash = lastIndex(where: {
#if os(iOS) || os(macOS) || os(tvOS) || os(watchOS) || os(Android) || os(Linux)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

visionOS?

@@ -46,20 +46,20 @@ endif()

if(SWIFT_BUILD_SWIFT_SYNTAX)
if(SWIFT_HOST_VARIANT_SDK IN_LIST SWIFT_DARWIN_PLATFORMS)
# Ensure that we can find the host shared libraries.
# Ensure that we can find the shaered swiftsyntax libraries.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
# Ensure that we can find the shaered swiftsyntax libraries.
# Ensure that we can find the shared swiftsyntax libraries.

@rintaro rintaro force-pushed the macros-inproc-plugin branch 2 times, most recently from 1d223b1 to 8e7b75e Compare May 24, 2024 04:16
Swift_MODULE_NAME ${name}
Swift_MODULE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
set(module_file "${CMAKE_CURRENT_BINARY_DIR}/${name}.swiftmodule")
set(module_dir "${CMAKE_CURRENT_BINARY_DIR}/modules")
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fragile modules are now created in ${CMAKE_CURRENT_BINARY_DIR}/modules. This is to avoid PR testing failures in incremental bots. This PR changes _CompilerRegexParser to fragile, if we create ${CMAKE_CURRENT_BINARY_DIR}/_CompilerRegexParser.swiftmodule , subsequent PR testings will be confused because -I ${CMAKE_CURRENT_BINARY_DIR} is added by CMake. Pre-patch #73799 can avoid that, but just in case.

@@ -629,8 +629,8 @@ struct HasNestedType {
#if TEST_DIAGNOSTICS
@freestanding(expression)
macro missingMacro() = #externalMacro(module: "MacroDefinition", type: "BluhBlah")
// expected-warning@-1 {{external macro implementation type 'MacroDefinition.BluhBlah' could not be found for macro 'missingMacro()'; 'MacroDefinition.BluhBlah' could not be found in library plugin '}}
// FIXME: xpected-warning@-1 {{external macro implementation type 'MacroDefinition.BluhBlah' could not be found for macro 'missingMacro()'; 'MacroDefinition.BluhBlah' could not be found in library plugin '}}
Copy link
Member Author

@rintaro rintaro May 24, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is because the plugin message facilities (i.e. executable plugins) doesn't support "resolve macro type" at this point. Expansions would just fail and be diagnosed if the type is not found or not a macro type.

Maybe we can introduce case resolveMacroType(module: String, type: String) plugin message to recover this.

@rintaro
Copy link
Member Author

rintaro commented May 24, 2024

2 similar comments
@rintaro
Copy link
Member Author

rintaro commented May 24, 2024

@rintaro
Copy link
Member Author

rintaro commented May 24, 2024

@rintaro
Copy link
Member Author

rintaro commented May 25, 2024

@rintaro
Copy link
Member Author

rintaro commented May 25, 2024

1 similar comment
@rintaro
Copy link
Member Author

rintaro commented May 25, 2024

@rintaro
Copy link
Member Author

rintaro commented May 25, 2024

apple/swift-syntax#2659
apple/swift-driver#1616
@swift-ci Please smoke test Windows

@rintaro
Copy link
Member Author

rintaro commented May 25, 2024

apple/swift-syntax#2659
apple/swift-driver#1616
@swift-ci Please smoke test Windows

@kabiroberai
Copy link
Contributor

kabiroberai commented May 29, 2024

👋 does this PR remove support for the loadPluginLibrary approach entirely? Worth noting that we're relying on this mechanism in #73031 in order to enable support for WebAssembly-based plugins. We could move these in-process but I think it would be preferable to keep third-party Wasm plugins out-of-process for defence-in-depth/isolation reasons (especially if we eventually want to execute them with JIT), so IMO it's worth keeping the library plugin mechanism for that. Also, IIUC one of the ways we could improve macro performance is to reuse a single plugin library/executable across swiftc invocations. Would this PR preclude that change for library-based plugins?

I should mention that I don't fully understand the implications of this PR so please do correct me if I'm mistaken. In general, in-process execution for first-party plugins during one-off swiftc invocation does seem like a nice improvement!

@rintaro
Copy link
Member Author

rintaro commented May 30, 2024

does this PR remove support for the loadPluginLibrary approach entirely?

I'm not 100% sure what "loadPluginLibrary approach" you mean, but either it's about -load-plugin-library compiler option or loadPluginLibrary plugin message, this PR doesn't remove them.

Since we need to keep supporting "in-process" plugins (i.e. -load-plugin-library and -plugin-path compiler options) for various reasons, we've been suffered by some limitations from that. The main intent of this PR is that separating swift-syntax libraries for the compiler and swift-syntax libraries for those "in-process" plugins. By that

  • We can unify the code path between in-process and out-of-process plugins
  • We can use different swift-syntax between the compiler and the in-process plugins. That let us compiling swift-syntax for the compiler without library-evolution, for the compiler performance

This PR doesn't have any intent of removing or deprecating out-of-process plugin mechanism.

IIUC one of the ways we could improve macro performance is to reuse a single plugin library/executable across swiftc invocations. Would this PR preclude that change for library-based plugins?

Yes, reusing plugin processes across multiple swift-frontend invocations is probably what we need to tackle on next. This PR does not preclude that approach.

I'm not sure I entirely understand your concerns. Let me know if you still have any questions!

@rintaro
Copy link
Member Author

rintaro commented May 30, 2024

1 similar comment
@rintaro
Copy link
Member Author

rintaro commented May 30, 2024

@kabiroberai
Copy link
Contributor

kabiroberai commented May 31, 2024

Ah I was under the impression that this removed support for external plugin servers in favour of in-process plugins, but looks like I was confused. Thanks for the clarification!

@rintaro
Copy link
Member Author

rintaro commented May 31, 2024

@rintaro
Copy link
Member Author

rintaro commented May 31, 2024

apple/swift-syntax#2659
apple/swift-driver#1616
@swift-ci Please smoke test Linux

@rintaro
Copy link
Member Author

rintaro commented Jun 4, 2024

apple/swift-syntax#2659
apple/swift-driver#1616
@swift-ci Please smoke test Linux

@rintaro
Copy link
Member Author

rintaro commented Jun 4, 2024

1 similar comment
@rintaro
Copy link
Member Author

rintaro commented Jun 4, 2024

@rintaro
Copy link
Member Author

rintaro commented Jun 5, 2024

@rintaro
Copy link
Member Author

rintaro commented Jun 5, 2024

Separate swift-syntax libs for the compiler and for the library plugins.
Compiler communicates with library plugins using serialized messages
just like executable plugins.

* `lib/swift/host/compiler/lib_Compiler*.dylib`(`lib/CompilerSwiftSyntax`):
  swift-syntax libraries for compiler. Library evolution is disabled.
* Compiler (`ASTGen` and `swiftIDEUtilsBridging`) only depends on
  `lib/swift/host/compiler` libraries.
* `SwiftInProcPluginServer`: In-process plugin server shared library.
  This has one `swift_inproc_plugins_handle_message` entry point that
  receives a message and return the response.
* In the compiler
  * Add `-in-process-plugin-server-path` front-end option, which specifies
    the `SwiftInProcPluginServer` shared library path.
  * Remove `LoadedLibraryPlugin`, because all library plugins are managed
    by `SwiftInProcPluginServer`
  * Introduce abstract `CompilerPlugin` class that has 2 subclasses:
    * `LoadedExecutablePlugin` existing class that represents an
      executable plugin
    * `InProcessPlugins` wraps `dlopen`ed `SwiftInProcPluginServer`
  * Unified the code path in `TypeCheckMacros.cpp` and `ASTGen`, the
    difference between executable plugins and library plugins are now
    abstracted by `CompilerPlugin`
@rintaro
Copy link
Member Author

rintaro commented Jun 6, 2024

@rintaro
Copy link
Member Author

rintaro commented Jun 6, 2024

@rintaro
Copy link
Member Author

rintaro commented Jun 6, 2024

apple/llvm-project#8855
apple/swift-syntax#2659
apple/swift-driver#1616
@swift-ci Please Test Source Compatibility

@rintaro
Copy link
Member Author

rintaro commented Jun 6, 2024

apple/llvm-project#8855
apple/swift-syntax#2659
apple/swift-driver#1616
apple/swift-installer-scripts#304
@swift-ci Please build toolchain Windows

@rintaro rintaro marked this pull request as ready for review June 6, 2024 22:53
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants