Skip to content

[Macros] Add support for wasm macros #73031

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

Open
wants to merge 132 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 37 commits
Commits
Show all changes
132 commits
Select commit Hold shift + click to select a range
e5c191d
wip
kabiroberai Apr 15, 2024
e5342e7
wip
kabiroberai Apr 15, 2024
d5d1cb7
wip
kabiroberai Apr 15, 2024
f776c28
revert swift-plugin-server
kabiroberai Apr 15, 2024
43fc233
use jsc in-proc
kabiroberai Apr 15, 2024
961fd54
Allow wasm in sandbox, don’t disable it
kabiroberai Apr 15, 2024
a771631
fix warning, prune version check
kabiroberai Apr 15, 2024
3f8ef81
Factor out JSCWasmPlugin
kabiroberai Apr 15, 2024
23426e0
the continuation just... works now?
kabiroberai Apr 15, 2024
9fe505f
more tweaks to JSCWasmPlugin
kabiroberai Apr 15, 2024
89158e2
Create SwiftPluginServerSupport
kabiroberai Apr 15, 2024
f084e25
JSCWasmPlugin: memoize, improve errors
kabiroberai Apr 15, 2024
5ef86da
steps towards x-plat
kabiroberai Apr 15, 2024
02f4324
more modularity
kabiroberai Apr 15, 2024
bddde66
Add wasm-plugin-server-path frontend opt
kabiroberai Apr 16, 2024
ca22e2d
Start adding WasmKit support
kabiroberai Apr 16, 2024
6a9bbe7
Update WasmKitPlugin
kabiroberai Apr 16, 2024
e598064
safety, tweaks
kabiroberai Apr 16, 2024
7d1510e
tweaks to JSC
kabiroberai Apr 16, 2024
37b8a61
Merge remote-tracking branch 'upstream/main' into kabir/wasm-plugins
kabiroberai Apr 17, 2024
da74f38
Proper WasmKit integration
kabiroberai Apr 22, 2024
7a18da2
tweaks
kabiroberai Apr 22, 2024
1076b16
Check ABI version
kabiroberai Apr 22, 2024
805c659
Merge remote-tracking branch 'upstream/main' into kabir/wasm-plugins
kabiroberai Apr 22, 2024
4527842
move ABI check into WasmEnginePlugin
kabiroberai Apr 22, 2024
f9dbbb1
build fixes
kabiroberai Apr 22, 2024
6511672
Elide copies of wasm blob
kabiroberai Apr 22, 2024
dd481fe
fix duplicate libraries warning
kabiroberai Apr 23, 2024
4ce4749
Merge remote-tracking branch 'upstream/main' into kabir/wasm-plugins
kabiroberai Apr 23, 2024
482871c
add SWIFT_WASM_USE_JSC
kabiroberai Apr 23, 2024
771acb0
Merge remote-tracking branch 'upstream/main' into kabir/wasm-plugins
kabiroberai Apr 23, 2024
2460e98
Skip wasmkit CLI for now
kabiroberai Apr 24, 2024
150f3d2
Or actually build wasmkit-cli
kabiroberai Apr 24, 2024
34ed5b0
use stdio for ipc
kabiroberai Apr 24, 2024
94d525e
No need for memory witness
kabiroberai Apr 24, 2024
a99f6b3
Byte-swap length if needed
kabiroberai Apr 24, 2024
c5dc6bd
Improve error handling
kabiroberai Apr 24, 2024
6375faf
Merge branch 'main' into kabir/wasm-plugins
kabiroberai Apr 30, 2024
826a80f
Fix linkage
kabiroberai Apr 30, 2024
f053859
No C dep needed for wasm
kabiroberai Apr 30, 2024
6c0b40c
Drop foundation (mostly); lower min os
kabiroberai Apr 30, 2024
d72e165
More foundation pruning
kabiroberai Apr 30, 2024
564f844
interop mode cxx -> c
kabiroberai Apr 30, 2024
a670f32
Target
kabiroberai Apr 30, 2024
aaaaae3
tweaks
kabiroberai Apr 30, 2024
7b16cbd
We don’t need WasmKitPluginError
kabiroberai Apr 30, 2024
7d9d015
Change wasm versioning approach
kabiroberai May 5, 2024
ea81405
Merge branch 'main' into kabir/wasm-plugins
kabiroberai May 5, 2024
b472f4f
Merge branch 'main' into kabir/wasm-plugins
kabiroberai May 11, 2024
3baf627
Merge branch 'main' into kabir/wasm-plugins
kabiroberai May 25, 2024
eee48e0
swift-wasm-plugin-server => swift-plugin-server
kabiroberai May 25, 2024
4fca102
swift-plugin-server doesn’t need a product
kabiroberai May 25, 2024
d465d36
We don’t need Dispatch here
kabiroberai May 25, 2024
c4efcee
Improve diagnostics
kabiroberai May 25, 2024
b3f53c2
Remove JSC for now
kabiroberai May 25, 2024
b629484
Explicitly depend on System
kabiroberai May 26, 2024
af2b87e
Nevermind SwiftPM didn’t like that
kabiroberai May 26, 2024
bbb916c
Lower swift-tools-version
kabiroberai May 26, 2024
77c273f
Fix WASI dep
kabiroberai May 26, 2024
b56e28a
Add missing header
kabiroberai May 26, 2024
94f0ad7
Merge branch 'main' into kabir/wasm-plugins
kabiroberai May 26, 2024
14b5b79
Include position in diagnostics if possible
kabiroberai May 26, 2024
af68825
Merge branch 'main' into kabir/wasm-plugins
kabiroberai May 26, 2024
92aef4e
this comment is now stale
kabiroberai May 26, 2024
9b1e4ee
No wasm_plugin_server_path
kabiroberai May 26, 2024
f93df4d
Remove debug code
kabiroberai May 26, 2024
95f254c
error_load_plugin diagnostic
kabiroberai May 26, 2024
ca27b45
Merge branch 'main' into kabir/wasm-plugins
kabiroberai May 26, 2024
caa1a8c
Elide copy
kabiroberai May 26, 2024
2ee417f
Merge branch 'main' into kabir/wasm-plugins
kabiroberai Jun 12, 2024
fa52ecd
Feedback
kabiroberai Jun 12, 2024
f2f2ea2
nit
kabiroberai Jun 12, 2024
c0a75e1
record ServerPath
kabiroberai Jun 12, 2024
011a0a5
Basic test
kabiroberai Jun 12, 2024
d2d3b94
Parameterize
kabiroberai Jun 12, 2024
e2a455a
Merge branch 'main' into kabir/wasm-plugins
kabiroberai Jun 29, 2024
b307eb4
Fix deprecation warning
kabiroberai Jun 29, 2024
782956a
working test
kabiroberai Jun 30, 2024
8a88dc5
simplify
kabiroberai Jun 30, 2024
fcb838d
remove wasm_sdk_root
kabiroberai Jun 30, 2024
469d84a
error tests
kabiroberai Jun 30, 2024
cc41cf1
Update WasmKit to 0.0.5
kateinoigakukun Jul 1, 2024
7499295
Merge branch 'main' into kabir/wasm-plugins
kabiroberai Jul 14, 2024
e89fd6a
post-merge fixup
kabiroberai Jul 14, 2024
2b47724
no opaque types
kabiroberai Jul 14, 2024
4285cf1
tentative fix for lldb build
kabiroberai Jul 14, 2024
56b6cae
don’t depend on ArgumentParser
kabiroberai Jul 14, 2024
96363e1
temporarily update wasmkit checkout
kabiroberai Jul 14, 2024
913041b
Revert "temporarily update wasmkit checkout"
kateinoigakukun Jul 15, 2024
6cd389e
Update WasmKit to 0.0.6
kateinoigakukun Jul 15, 2024
c3f4276
[test] Annotate macro tests that require the WebAssembly code generator
kateinoigakukun Jul 15, 2024
4341058
Update WasmKit to 0.0.7
kateinoigakukun Jul 21, 2024
393933a
Add temporary workaround for Windows pipe support of swift-system
kateinoigakukun Jul 22, 2024
9c5e7fc
[test] Remove usage of unused lit variables for building wasm plugins
kateinoigakukun Jul 22, 2024
5890c3e
Change the first `-load-plugin` path separator from `:` to `#`
kateinoigakukun Jul 23, 2024
0f39ec8
[test] Fix path segment separator of plugin path for Windows
kateinoigakukun Jul 23, 2024
48dd97f
Merge branch 'main' into kabir/wasm-plugins
MaxDesiatov Aug 20, 2024
c3f41c7
Merge branch 'main' into kabir/wasm-plugins
MaxDesiatov Aug 21, 2024
ee82b85
Merge branch 'main' of github.com:apple/swift into kabir/wasm-plugins
MaxDesiatov Aug 23, 2024
1dcdd7b
Merge branch 'main' of github.com:apple/swift into kabir/wasm-plugins
MaxDesiatov Aug 27, 2024
6e56934
Attempt to use `main` branch of WasmKit
MaxDesiatov Aug 27, 2024
dd13597
Merge branch 'main' into kabir/wasm-plugins
kabiroberai Sep 21, 2024
5770553
Revert wasmkit bump
kabiroberai Sep 21, 2024
94f870c
Merge branch 'main' into kabir/wasm-plugins
MaxDesiatov Oct 10, 2024
ed54400
Bump WasmKit to 0.1.0 in `update-checkout-config.json`
MaxDesiatov Oct 10, 2024
d568d67
Update for WasmKit 0.1.0 API
MaxDesiatov Oct 10, 2024
75bd7ca
Fix missing imports in `WasmKitEngine.swift`
MaxDesiatov Oct 11, 2024
c1e928d
Bump wasmkit to 0.1.1 to enable WMO
kateinoigakukun Oct 13, 2024
0d2c140
Merge remote-tracking branch 'origin/main' into kabir/wasm-plugins
kateinoigakukun Oct 13, 2024
7683e83
Bump WasmKit to 0.1.2 in `update-checkout-config.json`
MaxDesiatov Oct 21, 2024
e0427b2
Bump stack size in `WasmKitEngine.swift` to avoid OOB
MaxDesiatov Oct 21, 2024
be04533
Merge branch 'main' of github.com:apple/swift into kabir/wasm-plugins
MaxDesiatov Dec 4, 2024
1852df9
Remove outdated use of `PluginSearchOption::LoadPlugin`
MaxDesiatov Dec 4, 2024
e49c980
Bump WasmKit to 0.1.3 in `update-checkout-config.json`
MaxDesiatov Dec 4, 2024
052058a
Remove outdated `case OPT_load_plugin` in `CompilerInvocation.cpp`
MaxDesiatov Dec 4, 2024
f860528
Remove outdated use of `LoadPlugin` from `swift-ide-test.cpp`
MaxDesiatov Dec 4, 2024
28a9efa
Update lit tests to use `-load-resolved-plugin`
MaxDesiatov Dec 6, 2024
19eef9a
Merge branch 'main' of github.com:apple/swift into kabir/wasm-plugins
MaxDesiatov Dec 6, 2024
db325e8
Merge branch 'main' of github.com:apple/swift into kabir/wasm-plugins
MaxDesiatov Dec 12, 2024
54eb483
Adopt new `shutDown` API introduced in `swift-syntax`
MaxDesiatov Dec 12, 2024
224ac09
Add a trivial echo macro test to the package
MaxDesiatov Dec 13, 2024
dc8cd3c
Test `WasmEnginePlugin` APIs in `WasmEngineTests`
MaxDesiatov Dec 16, 2024
6817517
Merge branch 'main' of github.com:apple/swift into kabir/wasm-plugins
MaxDesiatov Dec 16, 2024
f56ec6a
Make formatting consistent in `swift-plugin-server`
MaxDesiatov Dec 16, 2024
1626ad8
Create stdin/stdout pipes for plugins with `mkfifo`
MaxDesiatov Dec 16, 2024
4204eef
Clean up temp Wasm fixture file in `WasmEngineTests`
MaxDesiatov Dec 16, 2024
1cf1e20
Make `init` parameter names more explicit in `WasmEngine`
MaxDesiatov Dec 16, 2024
6277098
Merge branch 'main' into kabir/wasm-plugins
MaxDesiatov Dec 17, 2024
0da4f22
Remove use of named pipes as engine-specific
MaxDesiatov Dec 17, 2024
3991b60
Fix renaming in `tools/swift-plugin-server/CMakeLists.txt`
MaxDesiatov Dec 17, 2024
636fa0e
Fix Windows compatibility
MaxDesiatov Dec 17, 2024
f915c05
Merge branch 'main' of github.com:apple/swift into kabir/wasm-plugins
MaxDesiatov Jan 3, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions include/swift/AST/SearchPathOptions.h
Original file line number Diff line number Diff line change
Expand Up @@ -468,6 +468,9 @@ class SearchPathOptions {
/// Plugin search path options.
std::vector<PluginSearchOption> PluginSearchOpts;

/// Path to swift-wasm-plugin-server executable.
std::string PluginWasmServerPath;

/// Don't look in for compiler-provided modules.
bool SkipRuntimeLibraryImportPaths = false;

Expand Down
5 changes: 5 additions & 0 deletions include/swift/Option/FrontendOptions.td
Original file line number Diff line number Diff line change
Expand Up @@ -277,6 +277,11 @@ def Raccess_note_EQ : Joined<["-"], "Raccess-note=">,
def block_list_file
: Separate<["-"], "blocklist-file">, MetaVarName<"<path>">,
HelpText<"The path to a blocklist configuration file">;

def wasm_plugin_server_path : Separate<["-"], "wasm-plugin-server-path">,
Copy link
Member

Choose a reason for hiding this comment

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

Can we merge wasm plugin server into the main plugin server? Having different frontend options for each mode complicates build systems, so it would be nice to unify the plugin servers into single one and switch underlying plugin mechanisms based on plugin extension or file magic.

Copy link
Member

Choose a reason for hiding this comment

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

Yeah, I like @kateinoigakukun's suggestion here. Let's bring wasm support into the main plugin server, so other tools around this (driver, build systems, etc.) that reason about macros don't need to change.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I have a few concerns about bringing wasm into the main plugin server, curious to hear what you folks think:

  1. Security: merging the servers will mean that enabling JIT for Wasm would allow library-based plugins to themselves use JIT. This increases risk exposure a bit, though it might be mitigated by AMFI library validation if that's indeed applied to the plugin server.
  2. Wasm plugins are currently invoked via -load-plugin-executable Lib.wasm#Module, with the server being an impl detail. Meanwhile bona fide server plugins are invoked with -external-plugin-path Lib#Exec, and notably A) this doesn't allow supplying an external module name, B) the client would have to locate the executable themselves, as afaik the Driver only does the locating for a pre-existing set of modules. Perhaps the solution to this would be to A) add a -load-external-plugin-with-module Lib#Exec#Module to the driver and B) Let the driver convert -load-plugin-executable Lib.wasm#Module to -load-external-plugin-with-module Lib.wasm#<swift-plugin-server>#Module? Would be nice to have the -load-external-plugin-with-module god-option anyway.

Copy link
Member

Choose a reason for hiding this comment

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

  1. Security

Yes, once we will conclude that we cannot satisfy performance expectations without JIT, we need a separate process to minimize such risks, but let's start in a simpler way

  1. God option

-load-plugin <library path>:<server path>#<module name>,... in the current tree seems good to me

Flags<[DoesNotAffectIncrementalBuild, ArgumentIsPath]>,
HelpText<"Path to the swift-wasm-plugin-server executable">,
MetaVarName<"<path>">;
} // end let Flags = [FrontendOption, NoDriverOption]

def debug_crash_Group : OptionGroup<"<automatic crashing options>">;
Expand Down
14 changes: 12 additions & 2 deletions lib/AST/PluginLoader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -116,8 +116,18 @@ PluginLoader::getPluginMap() {
case PluginSearchOption::Kind::LoadPluginExecutable: {
auto &val = entry.get<PluginSearchOption::LoadPluginExecutable>();
assert(!val.ExecutablePath.empty() && "empty plugin path");
for (auto &moduleName : val.ModuleNames) {
try_emplace(moduleName, /*libraryPath=*/"", val.ExecutablePath);
if (llvm::sys::path::filename(val.ExecutablePath).ends_with(".wasm")) {
Copy link
Member

Choose a reason for hiding this comment

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

I recommend using llvm::sys::path::extension() == ".wasm" here

Copy link
Member

Choose a reason for hiding this comment

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

Actually, when taking @kateinoigakukun 's advice, we won't need this code because the plugin server will handle it.

// we treat wasm plugins like library plugins that can be loaded by an external
// "wasm server" that in turn invokes the wasm runtime.
const auto &wasmServerPath = Ctx.SearchPathOpts.PluginWasmServerPath;
assert(!wasmServerPath.empty() && "wasm load requested but got empty wasm server path");
for (auto &moduleName : val.ModuleNames) {
try_emplace(moduleName, val.ExecutablePath, wasmServerPath);
}
} else {
for (auto &moduleName : val.ModuleNames) {
try_emplace(moduleName, /*libraryPath=*/"", val.ExecutablePath);
}
}
continue;
}
Expand Down
4 changes: 2 additions & 2 deletions lib/Basic/Sandbox.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,8 @@ static StringRef sandboxProfile(llvm::BumpPtrAllocator &Alloc) {
// Allow reading file metadata of any files.
contents += "(allow file-read-metadata)\n";

// Allow reading dylibs.
contents += "(allow file-read* (regex #\"\\.dylib$\"))\n";
// Allow reading dylibs and WebAssembly macros.
contents += "(allow file-read* (regex #\"\\.(dylib|wasm)$\"))\n";

// This is required to launch any processes (execve(2)).
contents += "(allow process-exec*)\n";
Expand Down
4 changes: 4 additions & 0 deletions lib/Frontend/CompilerInvocation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1991,6 +1991,10 @@ static bool ParseSearchPathArgs(SearchPathOptions &Opts, ArgList &Args,
}
}

if (const Arg *A = Args.getLastArg(OPT_wasm_plugin_server_path)) {
Opts.PluginWasmServerPath = A->getValue();
}

for (const Arg *A : Args.filtered(OPT_L)) {
Opts.LibrarySearchPaths.push_back(resolveSearchPath(A->getValue()));
}
Expand Down
1 change: 1 addition & 0 deletions tools/swift-plugin-server/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Package.resolved
65 changes: 65 additions & 0 deletions tools/swift-plugin-server/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,17 @@
if (SWIFT_BUILD_SWIFT_SYNTAX)
# hack: override macOS deployment target to 10.15.4
# since that's the minimum required by WasmKit
set(SWIFT_DARWIN_DEPLOYMENT_VERSION_OSX "10.15.4")
include(DarwinSDKs)
Copy link
Member

Choose a reason for hiding this comment

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

We'll want to find a cleaner way to do this... add if #available in the appropriate places, for example

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Also included this in swiftwasm/WasmKit#91

swift_get_host_triple(SWIFT_HOST_TRIPLE)

# override the remote SwiftSystem and ArgParser dependencies in WasmKit
FetchContent_Declare(SwiftSystem SOURCE_DIR "${PROJECT_SOURCE_DIR}/../swift-system")
FetchContent_Declare(ArgumentParser SOURCE_DIR "${PROJECT_SOURCE_DIR}/../swift-argument-parser")
Copy link
Member

Choose a reason for hiding this comment

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

We might end up having to do something more bespoke here to get things building on all of the platforms, but let's try this to start!


FetchContent_Declare(WasmKit SOURCE_DIR "${PROJECT_SOURCE_DIR}/../wasmkit")
FetchContent_MakeAvailable(WasmKit)

# _swiftCSwiftPluginServer is just a C support library for swift-plugin-server
# Don't bother to create '.a' for that.
add_swift_host_library(_swiftCSwiftPluginServer OBJECT
Expand All @@ -11,6 +24,16 @@ if (SWIFT_BUILD_SWIFT_SYNTAX)
Sources/CSwiftPluginServer/include
)

add_pure_swift_host_library(SwiftPluginServerSupport EMIT_MODULE
Sources/SwiftPluginServerSupport/SwiftPluginServerSupport.swift
DEPENDENCIES
$<TARGET_OBJECTS:_swiftCSwiftPluginServer>
SwiftCompilerPluginMessageHandling
)
target_include_directories(SwiftPluginServerSupport PRIVATE
Sources/CSwiftPluginServer/include
)

add_pure_swift_host_tool(swift-plugin-server
Sources/swift-plugin-server/swift-plugin-server.swift
DEPENDENCIES
Expand All @@ -23,8 +46,50 @@ if (SWIFT_BUILD_SWIFT_SYNTAX)
SwiftSyntaxMacroExpansion
SwiftCompilerPluginMessageHandling
swiftLLVMJSON
SwiftPluginServerSupport
)
target_include_directories(swift-plugin-server PRIVATE
Sources/CSwiftPluginServer/include
)

set(SWIFT_WASM_ALLOW_JSC ON CACHE BOOL "Use JavaScriptCore Wasm runtime if possible" FORCE)
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Wanted to leave this in for the initial review to show what the JSC runtime would look like, but I can remove this before we do a final pass since Doug mentioned that it's better to stick to a uniform implementation to begin with, for simplicity. I think it's definitely worth revisiting this in a follow-up because the JSC runtime is a lot faster than WasmKit when it can be used (500ms vs 1100ms in some cases I've tested.)

Copy link
Member

Choose a reason for hiding this comment

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

Yeah, that's a pretty big time difference. (I still prefer "make it work across platforms, then add in more optimizations afterward")

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Split out the JSC stuff into a separate branch, happy to make a followup PR when we're ready for JSC: kabiroberai/swift@kabir/wasm-plugins...kabir/jsc-wasm


if(SWIFT_HOST_VARIANT_SDK IN_LIST SWIFT_DARWIN_PLATFORMS)
set(swift_wasm_use_jsc ${SWIFT_WASM_ALLOW_JSC})
else()
set(swift_wasm_use_jsc OFF)
endif()

if (swift_wasm_use_jsc)
set(wasi_dep WASI)
set(jsc_defines SWIFT_WASM_USE_JSC)
else()
set(wasi_dep WasmKitWASI)
set(jsc_defines)
endif()

add_pure_swift_host_tool(swift-wasm-plugin-server
Sources/swift-wasm-plugin-server/swift-wasm-plugin-server.swift
Sources/swift-wasm-plugin-server/JSCWasmEngine.swift
Sources/swift-wasm-plugin-server/WasmEngine.swift
Sources/swift-wasm-plugin-server/WasmKitEngine.swift
DEPENDENCIES
$<TARGET_OBJECTS:_swiftCSwiftPluginServer>
SWIFT_COMPONENT
compiler
SWIFT_DEPENDENCIES
SwiftCompilerPluginMessageHandling
swiftLLVMJSON
SwiftPluginServerSupport
${wasi_dep}
)
target_compile_definitions(swift-wasm-plugin-server PRIVATE ${jsc_defines})
target_include_directories(swift-wasm-plugin-server PRIVATE
Sources/CSwiftPluginServer/include
)
if (swift_wasm_use_jsc)
add_custom_command(TARGET swift-wasm-plugin-server POST_BUILD COMMAND
codesign -fs - $<TARGET_FILE:swift-wasm-plugin-server> --entitlements ${CMAKE_CURRENT_SOURCE_DIR}/allow-jit.plist
Copy link
Contributor Author

@kabiroberai kabiroberai Apr 16, 2024

Choose a reason for hiding this comment

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

not sure if this is sufficient (works in dev but I haven't tested a packaged toolchain.) do we need a corresponding codesign invocation in build_script as well?

Copy link
Member

Choose a reason for hiding this comment

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

We would need to code sign in build-script, but I don't know if there are other steps. This is another reason I'd like to start with the simpler WasmKit integration.

)
endif()
endif()
50 changes: 40 additions & 10 deletions tools/swift-plugin-server/Package.swift
Original file line number Diff line number Diff line change
@@ -1,38 +1,68 @@
// swift-tools-version: 5.6
// swift-tools-version: 5.9

import PackageDescription

let allowJSC = true

let package = Package(
name: "swift-plugin-server",
platforms: [
.macOS(.v10_15)
.macOS(.v11),
],
products: [
.library(name: "swift-plugin-server", targets: ["swift-plugin-server"]),
.library(name: "swift-wasm-plugin-server", targets: ["swift-wasm-plugin-server"]),
],
dependencies: [
.package(path: "../../../swift-syntax"),
.package(path: "../../lib/ASTGen"),
.package(path: "../../../wasmkit"),
],
targets: [
.target(
name: "CSwiftPluginServer",
cxxSettings: [
.unsafeFlags([
"-I", "../../include",
"-I", "../../stdlib/public/SwiftShims",
"-I", "../../../build/Default/swift/include",
"-I", "../../../build/Default/llvm/include",
"-I", "../../../llvm-project/llvm/include",
])
]
),
.executableTarget(
name: "swift-plugin-server",
.target(
name: "SwiftPluginServerSupport",
dependencies: [
.product(name: "swiftLLVMJSON", package: "ASTGen"),
.product(name: "SwiftCompilerPluginMessageHandling", package: "swift-syntax"),
.product(name: "SwiftDiagnostics", package: "swift-syntax"),
.product(name: "SwiftSyntax", package: "swift-syntax"),
.product(name: "SwiftOperators", package: "swift-syntax"),
.product(name: "SwiftParser", package: "swift-syntax"),
"CSwiftPluginServer",
],
swiftSettings: [.interoperabilityMode(.Cxx)]
),
.target(
name: "swift-plugin-server",
dependencies: [
.product(name: "SwiftCompilerPluginMessageHandling", package: "swift-syntax"),
.product(name: "SwiftSyntaxMacros", package: "swift-syntax"),
"CSwiftPluginServer"
]
"CSwiftPluginServer",
"SwiftPluginServerSupport",
],
swiftSettings: [.interoperabilityMode(.Cxx)]
Copy link
Member

Choose a reason for hiding this comment

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

Using C++ interoperability here is driven by JSC, right?

Copy link
Contributor Author

@kabiroberai kabiroberai Apr 30, 2024

Choose a reason for hiding this comment

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

iirc this was required for swiftLLVMJSON but I was able to change the interop mode back to C now that we're using SwiftSyntax's JSON parser

),
.target(
name: "swift-wasm-plugin-server",
dependencies: [
.product(name: "swiftLLVMJSON", package: "ASTGen"),
.product(name: "SwiftCompilerPluginMessageHandling", package: "swift-syntax"),
"CSwiftPluginServer",
"SwiftPluginServerSupport",
.product(name: "WASI", package: "WasmKit"),
.product(name: "WasmKitWASI", package: "WasmKit", condition: .when(platforms: [.linux, .windows])),
],
swiftSettings: [.interoperabilityMode(.Cxx)] + (
allowJSC ? [.define("SWIFT_WASM_USE_JSC", .when(platforms: [.macOS]))] : []
)
),
],
cxxLanguageStandard: .cxx17
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
//===----------------------------------------------------------------------===//
//
// This source file is part of the Swift open source project
//
// Copyright (c) 2024 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See http://swift.org/LICENSE.txt for license information
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//

@_spi(PluginMessage) import SwiftCompilerPluginMessageHandling
import swiftLLVMJSON
import CSwiftPluginServer

@_spi(PluginMessage) public final class PluginHostConnection: MessageConnection {
let handle: UnsafeRawPointer
public init() throws {
var errorMessage: UnsafePointer<CChar>? = nil
guard let handle = PluginServer_createConnection(&errorMessage) else {
throw PluginServerError(message: String(cString: errorMessage!))
}
self.handle = handle
}

deinit {
PluginServer_destroyConnection(self.handle)
}

public func sendMessage<TX: Encodable>(_ message: TX) throws {
try LLVMJSON.encoding(message) { buffer in
try self.sendMessageData(buffer)
}
}

public func waitForNextMessage<RX: Decodable>(_ type: RX.Type) throws -> RX? {
return try self.withReadingMessageData { jsonData in
try LLVMJSON.decode(RX.self, from: jsonData)
}
}

/// Send a serialized message to the message channel.
private func sendMessageData(_ data: UnsafeBufferPointer<Int8>) throws {
// Write the header (a 64-bit length field in little endian byte order).
var header: UInt64 = UInt64(data.count).littleEndian
let writtenSize = try Swift.withUnsafeBytes(of: &header) { buffer in
try self.write(buffer: UnsafeRawBufferPointer(buffer))
}
guard writtenSize == MemoryLayout.size(ofValue: header) else {
throw PluginServerError(message: "failed to write message header")
}

// Write the body.
guard try self.write(buffer: UnsafeRawBufferPointer(data)) == data.count else {
throw PluginServerError(message: "failed to write message body")
}
}

/// Read a serialized message from the message channel and call the 'body'
/// with the data.
private func withReadingMessageData<R>(_ body: (UnsafeBufferPointer<Int8>) throws -> R) throws -> R? {
// Read the header (a 64-bit length field in little endian byte order).
var header: UInt64 = 0
let readSize = try Swift.withUnsafeMutableBytes(of: &header) { buffer in
try self.read(into: UnsafeMutableRawBufferPointer(buffer))
}
guard readSize == MemoryLayout.size(ofValue: header) else {
if readSize == 0 {
// The host closed the pipe.
return nil
}
// Otherwise, some error happened.
throw PluginServerError(message: "failed to read message header")
}

// Read the body.
let count = Int(UInt64(littleEndian: header))
let data = UnsafeMutableBufferPointer<Int8>.allocate(capacity: count)
defer { data.deallocate() }
guard try self.read(into: UnsafeMutableRawBufferPointer(data)) == count else {
throw PluginServerError(message: "failed to read message body")
}

// Invoke the handler.
return try body(UnsafeBufferPointer(data))
}

/// Write the 'buffer' to the message channel.
/// Returns the number of bytes succeeded to write.
private func write(buffer: UnsafeRawBufferPointer) throws -> Int {
var bytesToWrite = buffer.count
guard bytesToWrite > 0 else {
return 0
}
var ptr = buffer.baseAddress!

while (bytesToWrite > 0) {
let writtenSize = PluginServer_write(handle, ptr, bytesToWrite)
if (writtenSize <= 0) {
// error e.g. broken pipe.
break
}
ptr = ptr.advanced(by: writtenSize)
bytesToWrite -= Int(writtenSize)
}
return buffer.count - bytesToWrite
}

/// Read data from the message channel into the 'buffer' up to 'buffer.count' bytes.
/// Returns the number of bytes succeeded to read.
private func read(into buffer: UnsafeMutableRawBufferPointer) throws -> Int {
var bytesToRead = buffer.count
guard bytesToRead > 0 else {
return 0
}
var ptr = buffer.baseAddress!

while bytesToRead > 0 {
let readSize = PluginServer_read(handle, ptr, bytesToRead)
if (readSize <= 0) {
// 0: EOF (the host closed), -1: Broken pipe (the host crashed?)
break;
}
ptr = ptr.advanced(by: readSize)
bytesToRead -= readSize
}
return buffer.count - bytesToRead
}
}

public struct PluginServerError: Error, CustomStringConvertible {
public var description: String
public init(message: String) {
self.description = message
}
}
Loading