diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml new file mode 100644 index 0000000000000..80eb85fecf0e6 --- /dev/null +++ b/.github/workflows/main.yml @@ -0,0 +1,141 @@ +name: CI + +on: + push: + branches: + - swiftwasm + pull_request: + branches: + - swiftwasm + +jobs: + linux_build: + timeout-minutes: 0 + runs-on: ubuntu-18.04 + + steps: + - uses: actions/checkout@v1 + with: + path: swift + - name: Build Linux installable archive + run: ./utils/webassembly/ci-linux.sh + - name: Upload Linux installable archive + uses: actions/upload-artifact@v1 + with: + name: linux-installable + path: ../swiftwasm-linux.tar.gz + - name: Pack test results + run: tar cJf swift-test-results.tar.gz ../build/*/swift-linux-x86_64/swift-test-results + - name: Upload test results + uses: actions/upload-artifact@v1 + with: + name: linux-test-results + path: ./swift-test-results.tar.gz + + macos_build: + timeout-minutes: 0 + runs-on: macos-latest + + steps: + - uses: actions/checkout@v1 + with: + path: swift + - name: Build macOS installable archive + run: ./utils/webassembly/ci-mac.sh + - name: Upload macOS installable archive + uses: actions/upload-artifact@v1 + with: + name: macos-installable + path: ../swiftwasm-macos.tar.gz + - name: Upload packaging scripts + uses: actions/upload-artifact@v1 + with: + name: packaging-scripts + path: utils/webassembly + - name: Pack test results + run: tar cJf swift-test-results.tar.gz ../build/*/swift-macosx-x86_64/swift-test-results + - name: Upload test results + uses: actions/upload-artifact@v1 + with: + name: macos-test-results + path: ./swift-test-results.tar.gz + package: + name: Build SwiftWasm packages + needs: + - linux_build + - macos_build + runs-on: ubuntu-18.04 + steps: + - name: Download installable Linux archive + uses: actions/download-artifact@v1 + with: + name: linux-installable + - name: Download installable macOS archive + uses: actions/download-artifact@v1 + with: + name: macos-installable + - name: Download packaging scripts + uses: actions/download-artifact@v1 + with: + name: packaging-scripts + - name: Build the packages + shell: bash + run: | + cd packaging-scripts + find . -name '*.sh' -exec chmod +x {} \; + chmod +x sdkroot/swiftwasm + ./download-prebuilts.sh + + cp ../linux-installable/swiftwasm-linux.tar.gz \ + ../macos-installable/swiftwasm-macos.tar.gz \ + prebuilt + ./build-packages.sh + + cd output + tar xf swiftwasm-sdk-linux.tar.xz && echo "Successfully unpacked Linux SDK" + + cd swiftwasm-sdk + ./swiftwasm example/hello.swift hello.wasm && echo "Successfully linked hello.wasm" + + - name: Upload macOS package + uses: actions/upload-artifact@v1 + with: + name: macos-package + path: packaging-scripts/output/swiftwasm-sdk-macos.tar.xz + + - name: Upload Linux package + uses: actions/upload-artifact@v1 + with: + name: linux-package + path: packaging-scripts/output/swiftwasm-sdk-linux.tar.xz + + - name: Upload hello.wasm compiled with Linux package + uses: actions/upload-artifact@v1 + with: + name: linux-hello.wasm + path: packaging-scripts/output/swiftwasm-sdk/hello.wasm + + macos_smoke_test: + name: Compile hello.swift on macOS + runs-on: macos-latest + needs: package + steps: + - name: Download SwiftWasm macOS package + uses: actions/download-artifact@v1 + with: + name: macos-package + + - name: Build hello.wasm + shell: bash + run: | + cd macos-package + tar xf swiftwasm-sdk-macos.tar.xz && echo "Successfully unpacked macOS SDK" + + cd swiftwasm-sdk + ./swiftwasm example/hello.swift hello.wasm && echo "Successfully linked hello.wasm" + + - name: Upload hello.wasm compiled with macOS package + uses: actions/upload-artifact@v1 + with: + name: macos-hello.wasm + path: macos-package/swiftwasm-sdk/hello.wasm diff --git a/CMakeLists.txt b/CMakeLists.txt index 852ef3cf48a48..0f0b9d9f7598c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -260,11 +260,11 @@ set(SWIFT_ANDROID_DEPLOY_DEVICE_PATH "" CACHE STRING "Path on an Android device where build products will be pushed. These are used when running the test suite against the device") # -# User-configurable ICU specific options for Android, FreeBSD, Linux and Haiku. +# User-configurable ICU specific options for Android, FreeBSD, Linux, Haiku, and WebAssembly. # -foreach(sdk ANDROID;FREEBSD;LINUX;WINDOWS;HAIKU) - foreach(arch aarch64;armv6;armv7;i686;powerpc64;powerpc64le;s390x;x86_64) +foreach(sdk ANDROID;FREEBSD;LINUX;WINDOWS;HAIKU;WASI) + foreach(arch aarch64;armv6;armv7;i686;powerpc64;powerpc64le;s390x;wasm32;x86_64) set(SWIFT_${sdk}_${arch}_ICU_UC "" CACHE STRING "Path to a directory containing the icuuc library for ${sdk}") set(SWIFT_${sdk}_${arch}_ICU_UC_INCLUDE "" CACHE STRING @@ -595,6 +595,8 @@ else() set(SWIFT_HOST_VARIANT_ARCH_default "powerpc64le") elseif("${CMAKE_SYSTEM_PROCESSOR}" STREQUAL "s390x") set(SWIFT_HOST_VARIANT_ARCH_default "s390x") + elseif("${CMAKE_SYSTEM_PROCESSOR}" STREQUAL "wasm32") + set(SWIFT_HOST_VARIANT_ARCH_default "wasm32") # FIXME: Only matches v6l/v7l - by far the most common variants elseif("${CMAKE_SYSTEM_PROCESSOR}" STREQUAL "armv6l") set(SWIFT_HOST_VARIANT_ARCH_default "armv6") @@ -779,6 +781,18 @@ if(swift_build_windows AND NOT "${CMAKE_SYSTEM_NAME}" STREQUAL "Windows") configure_sdk_windows("Windows" "msvc" "${SWIFT_SDK_WINDOWS_ARCHITECTURES}") endif() +# Should we cross-compile the standard library for WebAssembly (WASI)? +is_sdk_requested(WASI swift_build_wasm) +if(swift_build_wasm AND NOT "${SWIFT_HOST_VARIANT_SDK}" STREQUAL "WASI") + if(SWIFT_BUILD_DYNAMIC_SDK_OVERLAY OR SWIFT_BUILD_DYNAMIC_STDLIB) + message(FATAL_ERROR "Unable to build dynamic overlay/stdlib for WASI. WASM does not support dynamic linking.") + endif() + if("${SWIFT_SDK_WASI_ARCHITECTURES}" STREQUAL "") + set(SWIFT_SDK_WASI_ARCHITECTURES wasm32) + endif() + configure_sdk_unix("WASI" "${SWIFT_SDK_WASI_ARCHITECTURES}") +endif() + if("${SWIFT_SDKS}" STREQUAL "") set(SWIFT_SDKS "${SWIFT_CONFIGURED_SDKS}") endif() diff --git a/cmake/modules/AddSwift.cmake b/cmake/modules/AddSwift.cmake index dc59e57379d02..567616670f283 100644 --- a/cmake/modules/AddSwift.cmake +++ b/cmake/modules/AddSwift.cmake @@ -366,6 +366,8 @@ function(_add_variant_c_compile_flags) list(APPEND result -isystem;${path}) endforeach() list(APPEND result "-D__ANDROID_API__=${SWIFT_ANDROID_API_LEVEL}") + elseif("${CFLAGS_SDK}" STREQUAL "WASI") + list(APPEND result "-D_WASI_EMULATED_MMAN") elseif(CFLAGS_SDK STREQUAL WINDOWS) swift_windows_include_for_arch(${CFLAGS_ARCH} ${CFLAGS_ARCH}_INCLUDE) foreach(path ${${CFLAGS_ARCH}_INCLUDE}) @@ -439,6 +441,8 @@ function(_add_variant_swift_compile_flags foreach(path IN LISTS ${arch}_swift_include) list(APPEND result "\"${CMAKE_INCLUDE_FLAG_C}${path}\"") endforeach() + elseif("${sdk}" STREQUAL "WASI") + list(APPEND result "-Xcc" "-D_WASI_EMULATED_MMAN") endif() if(NOT BUILD_STANDALONE) @@ -551,6 +555,8 @@ function(_add_variant_link_flags) foreach(path IN LISTS ${LFLAGS_ARCH}_LIB) list(APPEND library_search_directories ${path}) endforeach() + elseif("${LFLAGS_SDK}" STREQUAL "WASI") + list(APPEND result "-Wl,wasi-emulated-mman") else() # If lto is enabled, we need to add the object path flag so that the LTO code # generator leaves the intermediate object file in a place where it will not @@ -1072,7 +1078,8 @@ function(_add_swift_library_single target name) ${INCORPORATED_OBJECT_LIBRARIES_EXPRESSIONS} ${SWIFTLIB_SINGLE_XCODE_WORKAROUND_SOURCES}) if(("${SWIFT_SDK_${SWIFTLIB_SINGLE_SDK}_OBJECT_FORMAT}" STREQUAL "ELF" OR - "${SWIFT_SDK_${SWIFTLIB_SINGLE_SDK}_OBJECT_FORMAT}" STREQUAL "COFF") AND + "${SWIFT_SDK_${SWIFTLIB_SINGLE_SDK}_OBJECT_FORMAT}" STREQUAL "COFF" OR + "${SWIFT_SDK_${SWIFTLIB_SINGLE_SDK}_OBJECT_FORMAT}" STREQUAL "WASM") AND SWIFTLIB_SINGLE_TARGET_LIBRARY) if("${libkind}" STREQUAL "SHARED" AND NOT SWIFTLIB_SINGLE_NOSWIFTRT) # TODO(compnerd) switch to the generator expression when cmake is upgraded @@ -1399,6 +1406,12 @@ function(_add_swift_library_single target name) list(APPEND c_compile_flags -D_WINDLL) endif() endif() + # Double-check that we're not trying to build a dynamic library for WASM. + if(SWIFTLIB_SINGLE_SDK MATCHES WASM) + if(libkind STREQUAL SHARED) + message(FATAL_ERROR "WASM does not support shared libraries.") + endif() + endif() _add_variant_link_flags( SDK "${SWIFTLIB_SINGLE_SDK}" ARCH "${SWIFTLIB_SINGLE_ARCHITECTURE}" @@ -1710,6 +1723,9 @@ endfunction() # SWIFT_MODULE_DEPENDS_HAIKU # Swift modules this library depends on when built for Haiku. # +# SWIFT_MODULE_DEPENDS_WASI +# Swift modules this library depends on when built for WASI. +# # FRAMEWORK_DEPENDS # System frameworks this library depends on. # @@ -1826,6 +1842,7 @@ function(add_swift_target_library name) SWIFT_MODULE_DEPENDS_OSX SWIFT_MODULE_DEPENDS_TVOS SWIFT_MODULE_DEPENDS_WATCHOS + SWIFT_MODULE_DEPENDS_WASI SWIFT_MODULE_DEPENDS_WINDOWS SWIFT_MODULE_DEPENDS_FROM_SDK TARGET_SDKS @@ -1987,6 +2004,9 @@ function(add_swift_target_library name) elseif(${sdk} STREQUAL HAIKU) list(APPEND swiftlib_module_depends_flattened ${SWIFTLIB_SWIFT_MODULE_DEPENDS_HAIKU}) + elseif(${sdk} STREQUAL WASI) + list(APPEND swiftlib_module_depends_flattened + ${SWIFTLIB_SWIFT_MODULE_DEPENDS_WASI}) elseif(${sdk} STREQUAL WINDOWS) list(APPEND swiftlib_module_depends_flattened ${SWIFTLIB_SWIFT_MODULE_DEPENDS_WINDOWS}) diff --git a/cmake/modules/SwiftConfigureSDK.cmake b/cmake/modules/SwiftConfigureSDK.cmake index 52a3a4f3aeb0c..5862add80e424 100644 --- a/cmake/modules/SwiftConfigureSDK.cmake +++ b/cmake/modules/SwiftConfigureSDK.cmake @@ -217,6 +217,8 @@ macro(configure_sdk_unix name architectures) set(SWIFT_SDK_${prefix}_ARCHITECTURES "${architectures}") if("${prefix}" STREQUAL "CYGWIN") set(SWIFT_SDK_${prefix}_OBJECT_FORMAT "COFF") + elseif("${prefix}" STREQUAL "WASI") + set(SWIFT_SDK_${prefix}_OBJECT_FORMAT "WASM") else() set(SWIFT_SDK_${prefix}_OBJECT_FORMAT "ELF") endif() @@ -333,6 +335,14 @@ macro(configure_sdk_unix name architectures) message(FATAL_ERROR "unsupported arch for Haiku: ${arch}") endif() set(SWIFT_SDK_HAIKU_ARCH_x86_64_TRIPLE "x86_64-unknown-haiku") + elseif("${prefix}" STREQUAL "WASI") + if(NOT arch STREQUAL wasm32) + message(FATAL_ERROR "unsupported arch for WebAssembly: ${arch}") + endif() + set(SWIFT_SDK_WASI_ARCH_wasm32_PATH "${SWIFT_WASI_SDK_PATH}/share/wasi-sysroot") + set(SWIFT_SDK_WASI_ARCH_wasm32_TRIPLE "wasm32-unknown-wasi") + set(SWIFT_SDK_WASI_ARCH_wasm32_LIBC_INCLUDE_DIRECTORY "${SWIFT_WASI_SDK_PATH}/share/wasi-sysroot/include") + set(SWIFT_SDK_WASI_ARCH_wasm32_LIBC_ARCHITECTURE_INCLUDE_DIRECTORY "${SWIFT_WASI_SDK_PATH}/share/wasi-sysroot/include") else() message(FATAL_ERROR "unknown Unix OS: ${prefix}") endif() diff --git a/cmake/modules/SwiftSetIfArchBitness.cmake b/cmake/modules/SwiftSetIfArchBitness.cmake index 5212cf3ccb854..d38a9689150ba 100644 --- a/cmake/modules/SwiftSetIfArchBitness.cmake +++ b/cmake/modules/SwiftSetIfArchBitness.cmake @@ -12,7 +12,8 @@ function(set_if_arch_bitness var_name) "${SIA_ARCH}" STREQUAL "armv6" OR "${SIA_ARCH}" STREQUAL "armv7" OR "${SIA_ARCH}" STREQUAL "armv7k" OR - "${SIA_ARCH}" STREQUAL "armv7s") + "${SIA_ARCH}" STREQUAL "armv7s" OR + "${SIA_ARCH}" STREQUAL "wasm32") set("${var_name}" "${SIA_CASE_32_BIT}" PARENT_SCOPE) elseif("${SIA_ARCH}" STREQUAL "x86_64" OR "${SIA_ARCH}" STREQUAL "arm64" OR diff --git a/include/swift/Basic/Lazy.h b/include/swift/Basic/Lazy.h index 594e2ed8b9fcd..647e5aff41c59 100644 --- a/include/swift/Basic/Lazy.h +++ b/include/swift/Basic/Lazy.h @@ -16,12 +16,18 @@ #include #ifdef __APPLE__ #include +#elif defined(__wasi__) +// No pthread on wasi #else #include #endif #include "swift/Basic/Malloc.h" #include "swift/Basic/type_traits.h" +#ifdef __wasi__ +void wasi_polyfill_call_once(int *flag, void *context, void (*func)(void *)); +#endif + namespace swift { #ifdef __APPLE__ @@ -36,6 +42,10 @@ namespace swift { using OnceToken_t = unsigned long; # define SWIFT_ONCE_F(TOKEN, FUNC, CONTEXT) \ _swift_once_f(&TOKEN, CONTEXT, FUNC) +#elif defined(__wasi__) + using OnceToken_t = int; +# define SWIFT_ONCE_F(TOKEN, FUNC, CONTEXT) \ + ::wasi_polyfill_call_once(&TOKEN, CONTEXT, FUNC) #else using OnceToken_t = std::once_flag; # define SWIFT_ONCE_F(TOKEN, FUNC, CONTEXT) \ diff --git a/include/swift/Basic/RelativePointer.h b/include/swift/Basic/RelativePointer.h index f5cffd1c33c25..31cfd2971ece2 100644 --- a/include/swift/Basic/RelativePointer.h +++ b/include/swift/Basic/RelativePointer.h @@ -146,6 +146,11 @@ static inline uintptr_t applyRelativeOffset(BasePtrTy *basePtr, Offset offset) { std::is_signed::value, "offset type should be signed integer"); +#ifdef __wasm__ + // WebAssembly: hack: disable relative pointers + return (uintptr_t)(intptr_t)offset; +#endif + auto base = reinterpret_cast(basePtr); // We want to do wrapping arithmetic, but with a sign-extended // offset. To do this in C, we need to do signed promotion to get @@ -164,6 +169,13 @@ static inline Offset measureRelativeOffset(A *referent, B *base) { static_assert(std::is_integral::value && std::is_signed::value, "offset type should be signed integer"); +#ifdef __wasm__ + // WebAssembly: hack: disable relative pointers + auto offset = (Offset)(uintptr_t)referent; + assert((intptr_t)offset == (intptr_t)(uintptr_t)referent + && "pointer too large to fit in offset type"); + return offset; +#endif auto distance = (uintptr_t)referent - (uintptr_t)base; // Truncate as unsigned, then wrap around to signed. diff --git a/include/swift/IRGen/Linking.h b/include/swift/IRGen/Linking.h index 56b76c07be474..eeaabd8bbcbd9 100644 --- a/include/swift/IRGen/Linking.h +++ b/include/swift/IRGen/Linking.h @@ -1157,6 +1157,11 @@ class ApplyIRLinkage { // TODO: BFD and gold do not handle COMDATs properly if (Triple.isOSBinFormatELF()) return; + // WebAssembly: hack: comdat + custom section = explosion + // the comdat code assumes section name would be unique for each comdat + // this doesn't happen for metadata. + if (Triple.isOSBinFormatWasm()) + return; if (IRL.Linkage == llvm::GlobalValue::LinkOnceODRLinkage || IRL.Linkage == llvm::GlobalValue::WeakODRLinkage) diff --git a/include/swift/Runtime/Mutex.h b/include/swift/Runtime/Mutex.h index 1b320e9d22a6e..a24c555ccca03 100644 --- a/include/swift/Runtime/Mutex.h +++ b/include/swift/Runtime/Mutex.h @@ -24,6 +24,8 @@ #include "swift/Runtime/MutexPThread.h" #elif defined(_WIN32) #include "swift/Runtime/MutexWin32.h" +#elif defined(__wasi__) +#include "swift/Runtime/MutexWASI.h" #else #error "Implement equivalent of MutexPThread.h/cpp for your platform." #endif diff --git a/include/swift/Runtime/MutexPThread.h b/include/swift/Runtime/MutexPThread.h index 1b06a2977bd06..50eef549cc0be 100644 --- a/include/swift/Runtime/MutexPThread.h +++ b/include/swift/Runtime/MutexPThread.h @@ -26,7 +26,7 @@ typedef pthread_cond_t ConditionHandle; typedef pthread_mutex_t MutexHandle; typedef pthread_rwlock_t ReadWriteLockHandle; -#if defined(__CYGWIN__) || defined(__ANDROID__) || defined(__HAIKU__) +#if defined(__CYGWIN__) || defined(__ANDROID__) || defined(__HAIKU__) || defined(__wasi__) // At the moment CYGWIN pthreads implementation doesn't support the use of // constexpr for static allocation versions. The way they define things // results in a reinterpret_cast which violates constexpr. Similarly, Android's diff --git a/include/swift/Runtime/MutexWASI.h b/include/swift/Runtime/MutexWASI.h new file mode 100644 index 0000000000000..28f212d6f48e9 --- /dev/null +++ b/include/swift/Runtime/MutexWASI.h @@ -0,0 +1,66 @@ +//===--- MutexWin32.h - -----------------------------------------*- C++ -*-===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors +// Licensed under Apache License v2.0 with Runtime Library Exception +// +// See https://swift.org/LICENSE.txt for license information +// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +// +//===----------------------------------------------------------------------===// +// +// Mutex, ConditionVariable, Read/Write lock, and Scoped lock implementations +// using Windows Slim Reader/Writer Locks and Conditional Variables. +// +//===----------------------------------------------------------------------===// + +#ifndef SWIFT_RUNTIME_MUTEX_WASI_H +#define SWIFT_RUNTIME_MUTEX_WASI_H + +namespace swift { + +typedef void* ConditionHandle; +typedef void* MutexHandle; +typedef void* ReadWriteLockHandle; + +#define SWIFT_CONDITION_SUPPORTS_CONSTEXPR 1 +#define SWIFT_MUTEX_SUPPORTS_CONSTEXPR 1 +#define SWIFT_READWRITELOCK_SUPPORTS_CONSTEXPR 1 + +struct ConditionPlatformHelper { + static constexpr ConditionHandle staticInit() { + return nullptr; + }; + static void init(ConditionHandle &condition) {} + static void destroy(ConditionHandle &condition) {} + static void notifyOne(ConditionHandle &condition) {} + static void notifyAll(ConditionHandle &condition) {} + static void wait(ConditionHandle &condition, MutexHandle &mutex); +}; + +struct MutexPlatformHelper { + static constexpr MutexHandle staticInit() { return nullptr; } + static void init(MutexHandle &mutex, bool checked = false) {} + static void destroy(MutexHandle &mutex) {} + static void lock(MutexHandle &mutex) {} + static void unlock(MutexHandle &mutex) {} + static bool try_lock(MutexHandle &mutex) { return true; } + static void unsafeLock(MutexHandle &mutex) {} + static void unsafeUnlock(MutexHandle &mutex) {} +}; + +struct ReadWriteLockPlatformHelper { + static constexpr ReadWriteLockHandle staticInit() { return nullptr; } + static void init(ReadWriteLockHandle &rwlock) {} + static void destroy(ReadWriteLockHandle &rwlock) {} + static void readLock(ReadWriteLockHandle &rwlock) {} + static bool try_readLock(ReadWriteLockHandle &rwlock) { return true; } + static void readUnlock(ReadWriteLockHandle &rwlock) {} + static void writeLock(ReadWriteLockHandle &rwlock) {} + static bool try_writeLock(ReadWriteLockHandle &rwlock) { return true; } + static void writeUnlock(ReadWriteLockHandle &rwlock) {} +}; +} + +#endif diff --git a/include/swift/Runtime/Once.h b/include/swift/Runtime/Once.h index 8a78cddc23c56..95265cfcda794 100644 --- a/include/swift/Runtime/Once.h +++ b/include/swift/Runtime/Once.h @@ -44,6 +44,10 @@ typedef std::once_flag swift_once_t; /// extent of type swift_once_t. SWIFT_RUNTIME_EXPORT void swift_once(swift_once_t *predicate, void (*fn)(void *), void *context); +#ifdef __wasm__ +// WebAssembly: hack +void swift_once_real(swift_once_t *predicate, void (*fn)(void *), void *context); +#endif } diff --git a/include/swift/SwiftRemoteMirror/Platform.h b/include/swift/SwiftRemoteMirror/Platform.h index cefdea2c4de6f..1ec61dde9cad9 100644 --- a/include/swift/SwiftRemoteMirror/Platform.h +++ b/include/swift/SwiftRemoteMirror/Platform.h @@ -18,7 +18,7 @@ extern "C" { #endif #if defined(swiftRemoteMirror_EXPORTS) -# if defined(__ELF__) +# if defined(__ELF__) || defined(__wasm__) # define SWIFT_REMOTE_MIRROR_LINKAGE __attribute__((__visibility__("protected"))) # elif defined(__MACH__) # define SWIFT_REMOTE_MIRROR_LINKAGE __attribute__((__visibility__("default"))) @@ -30,7 +30,7 @@ extern "C" { # endif # endif #else -# if defined(__ELF__) +# if defined(__ELF__) || defined(__wasm__) # define SWIFT_REMOTE_MIRROR_LINKAGE __attribute__((__visibility__("default"))) # elif defined(__MACH__) # define SWIFT_REMOTE_MIRROR_LINKAGE __attribute__((__visibility__("default"))) diff --git a/lib/ClangImporter/ClangImporter.cpp b/lib/ClangImporter/ClangImporter.cpp index 3bc3c4b5d1e3d..f879e383d7bf1 100644 --- a/lib/ClangImporter/ClangImporter.cpp +++ b/lib/ClangImporter/ClangImporter.cpp @@ -598,6 +598,10 @@ getNormalInvocationArguments(std::vector &invocationArgStrs, }); } + if (triple.isOSWASI()) { + invocationArgStrs.insert(invocationArgStrs.end(), {"-D_WASI_EMULATED_MMAN"}); + } + if (triple.isOSWindows()) { switch (triple.getArch()) { default: llvm_unreachable("unsupported Windows architecture"); diff --git a/lib/Driver/CMakeLists.txt b/lib/Driver/CMakeLists.txt index 448f5044b7064..d1c4893e30152 100644 --- a/lib/Driver/CMakeLists.txt +++ b/lib/Driver/CMakeLists.txt @@ -33,8 +33,8 @@ target_link_libraries(swiftDriver PRIVATE if(SWIFT_BUILD_STATIC_STDLIB) set(static_stdlib_lnk_file_list) foreach(sdk ${SWIFT_CONFIGURED_SDKS}) + string(TOLOWER "${sdk}" lowercase_sdk) if("${SWIFT_SDK_${sdk}_OBJECT_FORMAT}" STREQUAL "ELF") - string(TOLOWER "${sdk}" lowercase_sdk) if(SWIFT_${SWIFT_HOST_VARIANT_SDK}_${SWIFT_HOST_VARIANT_ARCH}_ICU_STATICLIB) set(ICU_STATICLIB "TRUE") else() @@ -61,6 +61,44 @@ if(SWIFT_BUILD_STATIC_STDLIB) swift_install_in_component(FILES "${SWIFTSTATICLIB_DIR}/${linkfile}" DESTINATION "lib/swift_static/${lowercase_sdk}" COMPONENT stdlib) + elseif("${sdk}" STREQUAL "WASI") + set(linkfile_src "${SWIFT_SOURCE_DIR}/utils/webassembly/static-stdlib-args.lnk") + set(linkfile "${lowercase_sdk}/static-stdlib-args.lnk") + add_custom_command_target(swift_static_stdlib_${sdk}_args + COMMAND + "${CMAKE_COMMAND}" -E copy + "${linkfile_src}" + "${SWIFTSTATICLIB_DIR}/${linkfile}" + OUTPUT + "${SWIFTSTATICLIB_DIR}/${linkfile}" + DEPENDS + "${linkfile_src}") + + list(APPEND static_stdlib_lnk_file_list ${swift_static_stdlib_${sdk}_args}) + swift_install_in_component(FILES "${SWIFTSTATICLIB_DIR}/${linkfile}" + DESTINATION "lib/swift_static/${lowercase_sdk}" + COMPONENT stdlib) + set(swift_icu_libs_wasi_list) + set(icu_modules UC I18N DATA) + foreach(module IN LISTS icu_modules) + set(module_lib "${SWIFT_WASI_wasm32_ICU_${module}}") + get_filename_component(module_lib_name ${module_lib} NAME) + add_custom_command_target(swift_icu_${module}_${sdk} + COMMAND + "${CMAKE_COMMAND}" -E copy + "${module_lib}" + "${SWIFTSTATICLIB_DIR}/${lowercase_sdk}/${module_lib_name}" + OUTPUT + "${SWIFTSTATICLIB_DIR}/${lowercase_sdk}/${module_lib_name}" + DEPENDS + "${module_lib}") + list(APPEND swift_icu_libs_wasi_list ${swift_icu_${module}_${sdk}}) + swift_install_in_component(FILES "${SWIFTSTATICLIB_DIR}/${lowercase_sdk}/${module_lib_name}" + DESTINATION "lib/swift_static/${lowercase_sdk}" + COMPONENT stdlib) + endforeach() + add_custom_target(swift_icu_libs_wasi ALL DEPENDS ${swift_icu_libs_wasi_list}) + add_dependencies(stdlib swift_icu_libs_wasi) endif() endforeach() add_custom_target(swift_static_lnk_args ALL DEPENDS ${static_stdlib_lnk_file_list}) diff --git a/lib/Driver/UnixToolChains.cpp b/lib/Driver/UnixToolChains.cpp index 07a19d9e548ac..7607c31b86ff2 100644 --- a/lib/Driver/UnixToolChains.cpp +++ b/lib/Driver/UnixToolChains.cpp @@ -346,7 +346,12 @@ toolchains::GenericUnix::constructInvocation(const StaticLinkJobAction &job, ArgStringList Arguments; // Configure the toolchain. - const char *AR = "ar"; + const char *AR; + if (getTriple().isOSBinFormatWasm()) { + AR = "llvm-ar"; + } else { + AR = "ar"; + } Arguments.push_back("crs"); Arguments.push_back( diff --git a/lib/IRGen/ConstantBuilder.h b/lib/IRGen/ConstantBuilder.h index 3bb9e7d1fb338..8c85f8d3c2a33 100644 --- a/lib/IRGen/ConstantBuilder.h +++ b/lib/IRGen/ConstantBuilder.h @@ -82,6 +82,11 @@ class ConstantAggregateBuilderBase void addRelativeAddress(llvm::Constant *target) { assert(!isa(target)); + if (IGM().TargetInfo.OutputObjectFormat == llvm::Triple::Wasm) { + // WebAssembly: hack: doesn't support PCrel data relocations + add(llvm::ConstantExpr::getPtrToInt(target, IGM().RelativeAddressTy, false)); + return; + } addRelativeOffset(IGM().RelativeAddressTy, target); } @@ -90,6 +95,21 @@ class ConstantAggregateBuilderBase /// a "GOT-equivalent", i.e. a pointer to an external object; if so, /// set the low bit of the offset to indicate that this is true. void addRelativeAddress(ConstantReference reference) { + if (IGM().TargetInfo.OutputObjectFormat == llvm::Triple::Wasm) { + // WebAssembly: hack: doesn't support PCrel data relocations + // also, we should set the lowest bit, but I don't know how to do that + // there's no GOT on WebAssembly anyways though + + + llvm::Constant *offset = llvm::ConstantExpr::getPtrToInt(reference.getValue(), IGM().RelativeAddressTy, false); + // borrowed from addTaggedRelativeOffset + unsigned tag = unsigned(reference.isIndirect()); + if (tag) { + offset = llvm::ConstantExpr::getAdd(offset, llvm::ConstantInt::get(IGM().RelativeAddressTy, tag)); + } + add(offset); + return; + } addTaggedRelativeOffset(IGM().RelativeAddressTy, reference.getValue(), unsigned(reference.isIndirect())); @@ -99,6 +119,11 @@ class ConstantAggregateBuilderBase /// The target must be a "GOT-equivalent", i.e. a pointer to an /// external object. void addIndirectRelativeAddress(ConstantReference reference) { + if (IGM().TargetInfo.OutputObjectFormat == llvm::Triple::Wasm) { + // WebAssembly: hack: doesn't support PCrel data relocations + add(llvm::ConstantExpr::getPtrToInt(reference.getValue(), IGM().RelativeAddressTy, false)); + return; + } assert(reference.isIndirect()); addRelativeOffset(IGM().RelativeAddressTy, reference.getValue()); diff --git a/lib/IRGen/GenDecl.cpp b/lib/IRGen/GenDecl.cpp index 440963c22d129..6cffbd53e5d2b 100644 --- a/lib/IRGen/GenDecl.cpp +++ b/lib/IRGen/GenDecl.cpp @@ -3071,6 +3071,11 @@ IRGenModule::emitDirectRelativeReference(llvm::Constant *target, // Convert the target to an integer. auto targetAddr = llvm::ConstantExpr::getPtrToInt(target, SizeTy); + // WebAssembly hack: WebAssembly doesn't support PC-relative references + if (TargetInfo.OutputObjectFormat == llvm::Triple::Wasm) { + return targetAddr; + } + SmallVector indices; indices.push_back(llvm::ConstantInt::get(Int32Ty, 0)); for (unsigned baseIndex : baseIndices) { diff --git a/lib/IRGen/GenMeta.cpp b/lib/IRGen/GenMeta.cpp index 392b6c4159f10..14c0b768f0cf1 100644 --- a/lib/IRGen/GenMeta.cpp +++ b/lib/IRGen/GenMeta.cpp @@ -4516,6 +4516,17 @@ GenericRequirementsMetadata irgen::addGenericRequirements( unsigned tag = unsigned(descriptorRef.isIndirect()); if (protocol->isObjC()) tag |= 0x02; + // WebAssembly: hack: Wasm doesn't support PC-relative offsets. + // also doesn't handle tag yet + if (IGM.TargetInfo.OutputObjectFormat == llvm::Triple::Wasm) { + llvm::Constant *offset = llvm::ConstantExpr::getPtrToInt(descriptorRef.getValue(), IGM.RelativeAddressTy, false); + // borrowed from addTaggedRelativeOffset + if (tag) { + offset = llvm::ConstantExpr::getAdd(offset, llvm::ConstantInt::get(IGM.RelativeAddressTy, tag)); + } + B.add(offset); + return; + } B.addTaggedRelativeOffset(IGM.RelativeAddressTy, descriptorRef.getValue(), diff --git a/lib/IRGen/IRGen.cpp b/lib/IRGen/IRGen.cpp index a39ff7e63e4cd..3aede529fa774 100644 --- a/lib/IRGen/IRGen.cpp +++ b/lib/IRGen/IRGen.cpp @@ -166,6 +166,13 @@ swift::getIRTargetOptions(const IRGenOptions &Opts, ASTContext &Ctx) { auto *Clang = static_cast(Ctx.getClangModuleLoader()); clang::TargetOptions &ClangOpts = Clang->getTargetInfo().getTargetOpts(); + + // WebAssembly doesn't support atomics or DWARF5 yet. + if (Clang->getTargetInfo().getTriple().isOSBinFormatWasm()) { + TargetOpts.DebuggerTuning = llvm::DebuggerKind::Default; + TargetOpts.ThreadModel = llvm::ThreadModel::Single; + } + return std::make_tuple(TargetOpts, ClangOpts.CPU, ClangOpts.Features, ClangOpts.Triple); } diff --git a/lib/IRGen/IRGenSIL.cpp b/lib/IRGen/IRGenSIL.cpp index 7292f9e0160ca..d3394346328bd 100644 --- a/lib/IRGen/IRGenSIL.cpp +++ b/lib/IRGen/IRGenSIL.cpp @@ -4343,7 +4343,8 @@ void IRGenSILFunction::visitBeginUnpairedAccessInst( // in which case we should use the caller, which is generally ok because // materializeForSet can't usually be thunked. llvm::Value *pc; - if (hasBeenInlined(access)) { + // hack: wasm doesn't have returnaddress + if (true || hasBeenInlined(access)) { pc = llvm::ConstantPointerNull::get(IGM.Int8PtrTy); } else { auto retAddrFn = diff --git a/lib/IRGen/MetadataRequest.cpp b/lib/IRGen/MetadataRequest.cpp index 3d8385d7db6e6..bf919157c8036 100644 --- a/lib/IRGen/MetadataRequest.cpp +++ b/lib/IRGen/MetadataRequest.cpp @@ -2414,14 +2414,19 @@ emitMetadataAccessByMangledName(IRGenFunction &IGF, CanType type, IGM.Int32Ty); stringAddrOffset = subIGF.Builder.CreateSExtOrBitCast(stringAddrOffset, IGM.SizeTy); - auto stringAddrBase = subIGF.Builder.CreatePtrToInt(cache, IGM.SizeTy); - if (IGM.getModule()->getDataLayout().isBigEndian()) { - stringAddrBase = subIGF.Builder.CreateAdd(stringAddrBase, - llvm::ConstantInt::get(IGM.SizeTy, 4)); + llvm::Value *stringAddr; + if (IGM.TargetInfo.OutputObjectFormat == llvm::Triple::Wasm) { + stringAddr = subIGF.Builder.CreateIntToPtr(stringAddrOffset, IGM.Int8PtrTy); + } else { + auto stringAddrBase = subIGF.Builder.CreatePtrToInt(cache, IGM.SizeTy); + if (IGM.getModule()->getDataLayout().isBigEndian()) { + stringAddrBase = subIGF.Builder.CreateAdd(stringAddrBase, + llvm::ConstantInt::get(IGM.SizeTy, 4)); + } + stringAddr = subIGF.Builder.CreateAdd(stringAddrBase, + stringAddrOffset); + stringAddr = subIGF.Builder.CreateIntToPtr(stringAddr, IGM.Int8PtrTy); } - auto stringAddr = subIGF.Builder.CreateAdd(stringAddrBase, - stringAddrOffset); - stringAddr = subIGF.Builder.CreateIntToPtr(stringAddr, IGM.Int8PtrTy); llvm::CallInst *call; if (request.isStaticallyAbstract()) { diff --git a/lib/SIL/TypeLowering.cpp b/lib/SIL/TypeLowering.cpp index 5566950fb6acd..1ce304e85296e 100644 --- a/lib/SIL/TypeLowering.cpp +++ b/lib/SIL/TypeLowering.cpp @@ -2633,10 +2633,23 @@ TypeConverter::checkFunctionForABIDifferences(SILModule &M, return ABIDifference::NeedsThunk; } + // There is no ABI compatibility between non-throws and throws on WebAssembly, + // so need thunk. + if (M.getASTContext().LangOpts.Target.isOSBinFormatWasm()) { + if (!fnTy1->hasErrorResult() && fnTy2->hasErrorResult()) { + return ABIDifference::NeedsThunk; + } + } + auto rep1 = fnTy1->getRepresentation(), rep2 = fnTy2->getRepresentation(); if (rep1 != rep2) { if (rep1 == SILFunctionTypeRepresentation::Thin && rep2 == SILFunctionTypeRepresentation::Thick) { + // There is no ABI compatibility between thin and thick on WebAssembly, + // so need thunk. + if (M.getASTContext().LangOpts.Target.isOSBinFormatWasm()) { + return ABIDifference::NeedsThunk; + } if (DifferentFunctionTypesHaveDifferentRepresentation) { // FIXME: check whether the representations are compatible modulo // context @@ -2645,7 +2658,6 @@ TypeConverter::checkFunctionForABIDifferences(SILModule &M, return ABIDifference::CompatibleRepresentation_ThinToThick; } } - return ABIDifference::NeedsThunk; } diff --git a/stdlib/private/CMakeLists.txt b/stdlib/private/CMakeLists.txt index 45cf31363574b..9e900d1178773 100644 --- a/stdlib/private/CMakeLists.txt +++ b/stdlib/private/CMakeLists.txt @@ -18,7 +18,8 @@ if(SWIFT_BUILD_SDK_OVERLAY) add_subdirectory(OSLog) - if(CMAKE_SYSTEM_NAME STREQUAL "Darwin") + list_intersect("${SWIFT_APPLE_PLATFORMS}" "${SWIFT_SDKS}" building_darwin_sdks) + if(building_darwin_sdks) add_subdirectory(StdlibUnittestFoundationExtras) if (SWIFT_INCLUDE_TESTS) add_subdirectory(SwiftReflectionTest) diff --git a/stdlib/private/StdlibUnittest/CMakeLists.txt b/stdlib/private/StdlibUnittest/CMakeLists.txt index 710ccede83171..9614bfbdcbc04 100644 --- a/stdlib/private/StdlibUnittest/CMakeLists.txt +++ b/stdlib/private/StdlibUnittest/CMakeLists.txt @@ -40,6 +40,7 @@ add_swift_target_library(swiftStdlibUnittest ${SWIFT_STDLIB_LIBRARY_BUILD_TYPES} SWIFT_MODULE_DEPENDS_FREEBSD Glibc SWIFT_MODULE_DEPENDS_CYGWIN Glibc SWIFT_MODULE_DEPENDS_HAIKU Glibc + SWIFT_MODULE_DEPENDS_WASI Glibc SWIFT_MODULE_DEPENDS_WINDOWS MSVCRT WinSDK SWIFT_COMPILE_FLAGS ${swift_stdlib_unittest_compile_flags} ${SWIFT_STANDARD_LIBRARY_SWIFT_FLAGS} INSTALL_IN_COMPONENT stdlib-experimental diff --git a/stdlib/private/StdlibUnittest/InterceptTraps.cpp b/stdlib/private/StdlibUnittest/InterceptTraps.cpp index 377397bebb9bf..2e76ac6e84aea 100644 --- a/stdlib/private/StdlibUnittest/InterceptTraps.cpp +++ b/stdlib/private/StdlibUnittest/InterceptTraps.cpp @@ -26,6 +26,9 @@ #include "swift/Runtime/Config.h" +// WebAssembly: no signals on WASI yet +#ifndef __wasi__ + static void CrashCatcher(int Sig) { const char *Msg; switch (Sig) { @@ -65,11 +68,16 @@ VectoredCrashHandler(PEXCEPTION_POINTERS ExceptionInfo) { } #endif +#endif // __wasi__ + SWIFT_CC(swift) SWIFT_RUNTIME_LIBRARY_VISIBILITY extern "C" void installTrapInterceptor() { // Disable buffering on stdout so that everything is printed before crashing. setbuf(stdout, 0); +// WebAssembly: no signals on WASI +#ifndef __wasi__ + #if defined(_WIN32) _set_abort_behavior(0, _WRITE_ABORT_MSG); #endif @@ -85,5 +93,6 @@ void installTrapInterceptor() { signal(SIGBUS, CrashCatcher); signal(SIGSYS, CrashCatcher); #endif -} +#endif // __wasi__ +} diff --git a/stdlib/private/StdlibUnittest/RaceTest.swift b/stdlib/private/StdlibUnittest/RaceTest.swift index 3bdee4f03d32f..d793930527e71 100644 --- a/stdlib/private/StdlibUnittest/RaceTest.swift +++ b/stdlib/private/StdlibUnittest/RaceTest.swift @@ -41,7 +41,7 @@ import SwiftPrivateLibcExtras import SwiftPrivateThreadExtras #if os(macOS) || os(iOS) import Darwin -#elseif os(Linux) || os(FreeBSD) || os(PS4) || os(Android) || os(Cygwin) || os(Haiku) +#elseif os(Linux) || os(FreeBSD) || os(PS4) || os(Android) || os(Cygwin) || os(Haiku) || os(WASI) import Glibc #elseif os(Windows) import MSVCRT @@ -562,7 +562,12 @@ class _InterruptibleSleep { return } +#if os(WASI) +// WebAssembly/WASI on wasm32 is the only 32-bit platform with Int64 time_t + var timeout = timeval(tv_sec: time_t(duration), tv_usec: 0) +#else var timeout = timeval(tv_sec: duration, tv_usec: 0) +#endif var readFDs = _stdlib_fd_set() var writeFDs = _stdlib_fd_set() diff --git a/stdlib/private/StdlibUnittest/StdlibCoreExtras.swift b/stdlib/private/StdlibUnittest/StdlibCoreExtras.swift index 20bb2b2c9376f..bc8bd4fe980e0 100644 --- a/stdlib/private/StdlibUnittest/StdlibCoreExtras.swift +++ b/stdlib/private/StdlibUnittest/StdlibCoreExtras.swift @@ -14,7 +14,7 @@ import SwiftPrivate import SwiftPrivateLibcExtras #if os(macOS) || os(iOS) import Darwin -#elseif os(Linux) || os(FreeBSD) || os(PS4) || os(Android) || os(Cygwin) || os(Haiku) +#elseif os(Linux) || os(FreeBSD) || os(PS4) || os(Android) || os(Cygwin) || os(Haiku) || os(WASI) import Glibc #elseif os(Windows) import MSVCRT diff --git a/stdlib/private/StdlibUnittest/StdlibUnittest.swift b/stdlib/private/StdlibUnittest/StdlibUnittest.swift index c67f1778d8a3b..019de920c4201 100644 --- a/stdlib/private/StdlibUnittest/StdlibUnittest.swift +++ b/stdlib/private/StdlibUnittest/StdlibUnittest.swift @@ -18,7 +18,7 @@ import SwiftPrivateLibcExtras #if os(macOS) || os(iOS) || os(watchOS) || os(tvOS) import Foundation import Darwin -#elseif os(Linux) || os(FreeBSD) || os(PS4) || os(Android) || os(Cygwin) || os(Haiku) +#elseif os(Linux) || os(FreeBSD) || os(PS4) || os(Android) || os(Cygwin) || os(Haiku) || os(WASI) import Glibc #elseif os(Windows) import MSVCRT @@ -748,6 +748,8 @@ extension ProcessTerminationStatus { case .signal(let signal): #if os(Windows) return CInt(signal) == SIGILL +#elseif os(WASI) + return false #else return CInt(signal) == SIGILL || CInt(signal) == SIGTRAP #endif @@ -1447,7 +1449,12 @@ public func runAllTests() { if _isChildProcess { _childProcess() } else { + #if os(WASI) + // WASI doesn't support child process + var runTestsInProcess: Bool = true + #else var runTestsInProcess: Bool = false + #endif var filter: String? var args = [String]() var i = 0 @@ -1746,6 +1753,7 @@ public enum OSVersion : CustomStringConvertible { case windowsCygnus case windows case haiku + case wasi public var description: String { switch self { @@ -1777,6 +1785,8 @@ public enum OSVersion : CustomStringConvertible { return "Windows" case .haiku: return "Haiku" + case .wasi: + return "WASI" } } } @@ -1821,6 +1831,8 @@ func _getOSVersion() -> OSVersion { return .windows #elseif os(Haiku) return .haiku +#elseif os(WASI) + return .wasi #else let productVersion = _getSystemVersionPlistProperty("ProductVersion")! let (major, minor, bugFix) = _parseDottedVersionTriple(productVersion) diff --git a/stdlib/private/StdlibUnittest/SymbolLookup.swift b/stdlib/private/StdlibUnittest/SymbolLookup.swift index 2e9c627487a4f..f827f6e2fe956 100644 --- a/stdlib/private/StdlibUnittest/SymbolLookup.swift +++ b/stdlib/private/StdlibUnittest/SymbolLookup.swift @@ -12,7 +12,7 @@ #if os(macOS) || os(iOS) || os(tvOS) || os(watchOS) import Darwin -#elseif os(Linux) || os(FreeBSD) || os(PS4) || os(Android) || os(Cygwin) || os(Haiku) +#elseif os(Linux) || os(FreeBSD) || os(PS4) || os(Android) || os(Cygwin) || os(Haiku) || os(WASI) import Glibc #elseif os(Windows) import MSVCRT @@ -23,7 +23,7 @@ #if os(macOS) || os(iOS) || os(watchOS) || os(tvOS) let RTLD_DEFAULT = UnsafeMutableRawPointer(bitPattern: -2) -#elseif os(Linux) +#elseif os(Linux) || os(WASI) let RTLD_DEFAULT = UnsafeMutableRawPointer(bitPattern: 0) #elseif os(Android) #if arch(arm) || arch(i386) @@ -43,6 +43,8 @@ public func pointerToSwiftCoreSymbol(name: String) -> UnsafeMutableRawPointer? { #if os(Windows) return unsafeBitCast(GetProcAddress(hStdlibCore, name), to: UnsafeMutableRawPointer?.self) +#elseif os(WASI) + fatalError("\(#function) is not supported on WebAssembly") #else return dlsym(RTLD_DEFAULT, name) #endif diff --git a/stdlib/private/SwiftPrivateLibcExtras/CMakeLists.txt b/stdlib/private/SwiftPrivateLibcExtras/CMakeLists.txt index 22979ebc7ce8b..a4545a05728ae 100644 --- a/stdlib/private/SwiftPrivateLibcExtras/CMakeLists.txt +++ b/stdlib/private/SwiftPrivateLibcExtras/CMakeLists.txt @@ -17,6 +17,7 @@ add_swift_target_library(swiftSwiftPrivateLibcExtras ${SWIFT_STDLIB_LIBRARY_BUIL SWIFT_MODULE_DEPENDS_FREEBSD Glibc SWIFT_MODULE_DEPENDS_CYGWIN Glibc SWIFT_MODULE_DEPENDS_HAIKU Glibc + SWIFT_MODULE_DEPENDS_WASI Glibc SWIFT_MODULE_DEPENDS_WINDOWS MSVCRT WinSDK INSTALL_IN_COMPONENT stdlib-experimental DARWIN_INSTALL_NAME_DIR "${SWIFT_DARWIN_STDLIB_PRIVATE_INSTALL_NAME_DIR}") diff --git a/stdlib/private/SwiftPrivateLibcExtras/Subprocess.c b/stdlib/private/SwiftPrivateLibcExtras/Subprocess.c index 4ef6fdbff8537..26d2402db4626 100644 --- a/stdlib/private/SwiftPrivateLibcExtras/Subprocess.c +++ b/stdlib/private/SwiftPrivateLibcExtras/Subprocess.c @@ -11,7 +11,7 @@ //===----------------------------------------------------------------------===// // posix_spawn is not available on Android or Windows (MSVC). -#if !defined(__ANDROID__) && !defined(__HAIKU__) && (!defined(_WIN32) || defined(__CYGWIN__)) +#if !defined(__ANDROID__) && !defined(__HAIKU__) && (!defined(_WIN32) || defined(__CYGWIN__)) && !defined(__wasi__) #include "swift/Runtime/Config.h" diff --git a/stdlib/private/SwiftPrivateLibcExtras/Subprocess.swift b/stdlib/private/SwiftPrivateLibcExtras/Subprocess.swift index e95e07e142c3c..84ab3b44398b2 100644 --- a/stdlib/private/SwiftPrivateLibcExtras/Subprocess.swift +++ b/stdlib/private/SwiftPrivateLibcExtras/Subprocess.swift @@ -13,7 +13,7 @@ import SwiftPrivate #if os(macOS) || os(iOS) || os(watchOS) || os(tvOS) import Darwin -#elseif os(Linux) || os(FreeBSD) || os(PS4) || os(Android) || os(Cygwin) || os(Haiku) +#elseif os(Linux) || os(FreeBSD) || os(PS4) || os(Android) || os(Cygwin) || os(Haiku) || os(WASI) import Glibc #elseif os(Windows) import MSVCRT @@ -21,6 +21,9 @@ import WinSDK #endif internal func _signalToString(_ signal: Int) -> String { +#if os(WASI) + return "unsupported" +#else switch CInt(signal) { case SIGILL: return "SIGILL" case SIGABRT: return "SIGABRT" @@ -33,6 +36,7 @@ internal func _signalToString(_ signal: Int) -> String { #endif default: return "SIG???? (\(signal))" } +#endif // os(WASI) } public enum ProcessTerminationStatus : CustomStringConvertible { @@ -141,6 +145,15 @@ public func waitProcess(_ process: HANDLE) -> ProcessTerminationStatus { } return .exit(Int(status)) } +#elseif os(WASI) +// Oops, we can't launch tests in subprocesses yet! +public func spawnChild(_ args: [String]) + -> (pid: pid_t, stdinFD: CInt, stdoutFD: CInt, stderrFD: CInt) { + fatalError("Not supported on WebAssembly!") +} +public func posixWaitpid(_ pid: pid_t) -> ProcessTerminationStatus { + fatalError("Not supported on WebAssembly!") +} #else // posix_spawn is not available on Android. // posix_spawn is not available on Haiku. diff --git a/stdlib/private/SwiftPrivateLibcExtras/SwiftPrivateLibcExtras.swift b/stdlib/private/SwiftPrivateLibcExtras/SwiftPrivateLibcExtras.swift index 6fa2c06b6f6ee..68e955f7d648a 100644 --- a/stdlib/private/SwiftPrivateLibcExtras/SwiftPrivateLibcExtras.swift +++ b/stdlib/private/SwiftPrivateLibcExtras/SwiftPrivateLibcExtras.swift @@ -13,14 +13,14 @@ import SwiftPrivate #if os(macOS) || os(iOS) || os(watchOS) || os(tvOS) import Darwin -#elseif os(Linux) || os(FreeBSD) || os(PS4) || os(Android) || os(Cygwin) || os(Haiku) +#elseif os(Linux) || os(FreeBSD) || os(PS4) || os(Android) || os(Cygwin) || os(Haiku) || os(WASI) import Glibc #elseif os(Windows) import MSVCRT #endif public func _stdlib_mkstemps(_ template: inout String, _ suffixlen: CInt) -> CInt { -#if os(Android) || os(Haiku) || os(Windows) +#if os(Android) || os(Haiku) || os(Windows) || os(WASI) preconditionFailure("mkstemps doesn't work on your platform") #else var utf8CStr = template.utf8CString @@ -125,6 +125,8 @@ public func _stdlib_pipe() -> (readEnd: CInt, writeEnd: CInt, error: CInt) { let ret = fds.withUnsafeMutableBufferPointer { unsafeFds -> CInt in #if os(Windows) return _pipe(unsafeFds.baseAddress, 0, 0) +#elseif os(WASI) + fatalError("no pipes on WebAssembly") #else return pipe(unsafeFds.baseAddress) #endif diff --git a/stdlib/private/SwiftPrivateThreadExtras/CMakeLists.txt b/stdlib/private/SwiftPrivateThreadExtras/CMakeLists.txt index 97e2cc0d2af5b..82a68f1962560 100644 --- a/stdlib/private/SwiftPrivateThreadExtras/CMakeLists.txt +++ b/stdlib/private/SwiftPrivateThreadExtras/CMakeLists.txt @@ -14,6 +14,7 @@ add_swift_target_library(swiftSwiftPrivateThreadExtras ${SWIFT_STDLIB_LIBRARY_BU SWIFT_MODULE_DEPENDS_FREEBSD Glibc SWIFT_MODULE_DEPENDS_CYGWIN Glibc SWIFT_MODULE_DEPENDS_HAIKU Glibc + SWIFT_MODULE_DEPENDS_WASI Glibc SWIFT_MODULE_DEPENDS_WINDOWS MSVCRT WinSDK SWIFT_COMPILE_FLAGS ${SWIFT_STANDARD_LIBRARY_SWIFT_FLAGS} INSTALL_IN_COMPONENT stdlib-experimental diff --git a/stdlib/private/SwiftPrivateThreadExtras/SwiftPrivateThreadExtras.swift b/stdlib/private/SwiftPrivateThreadExtras/SwiftPrivateThreadExtras.swift index 002aef8e74145..c9d34e35017c2 100644 --- a/stdlib/private/SwiftPrivateThreadExtras/SwiftPrivateThreadExtras.swift +++ b/stdlib/private/SwiftPrivateThreadExtras/SwiftPrivateThreadExtras.swift @@ -17,7 +17,7 @@ #if os(macOS) || os(iOS) || os(watchOS) || os(tvOS) import Darwin -#elseif os(Linux) || os(FreeBSD) || os(PS4) || os(Android) || os(Cygwin) || os(Haiku) +#elseif os(Linux) || os(FreeBSD) || os(PS4) || os(Android) || os(Cygwin) || os(Haiku) || os(WASI) import Glibc #elseif os(Windows) import MSVCRT @@ -98,6 +98,9 @@ public func _stdlib_thread_create_block( } else { return (0, ThreadHandle(bitPattern: threadID)) } +#elseif os(WASI) + // WASI environment has a only single thread + return (0, nil) #else var threadID = _make_pthread_t() let result = pthread_create(&threadID, nil, @@ -128,6 +131,9 @@ public func _stdlib_thread_join( } else { return (CInt(result), nil) } +#elseif os(WASI) + // WASI environment has a only single thread + return (0, nil) #else var threadResultRawPtr: UnsafeMutableRawPointer? let result = pthread_join(thread, &threadResultRawPtr) diff --git a/stdlib/private/SwiftPrivateThreadExtras/ThreadBarriers.swift b/stdlib/private/SwiftPrivateThreadExtras/ThreadBarriers.swift index 9f5e183447021..8bef3340ec82a 100644 --- a/stdlib/private/SwiftPrivateThreadExtras/ThreadBarriers.swift +++ b/stdlib/private/SwiftPrivateThreadExtras/ThreadBarriers.swift @@ -12,7 +12,7 @@ #if os(macOS) || os(iOS) || os(watchOS) || os(tvOS) import Darwin -#elseif os(Linux) || os(FreeBSD) || os(PS4) || os(Android) || os(Cygwin) || os(Haiku) +#elseif os(Linux) || os(FreeBSD) || os(PS4) || os(Android) || os(Cygwin) || os(Haiku) || os(WASI) import Glibc #elseif os(Windows) import MSVCRT @@ -36,6 +36,8 @@ public struct _stdlib_thread_barrier_t { #elseif os(Cygwin) || os(FreeBSD) var mutex: UnsafeMutablePointer? var cond: UnsafeMutablePointer? +#elseif os(WASI) + // No pthread for WASI #else var mutex: UnsafeMutablePointer? var cond: UnsafeMutablePointer? @@ -67,6 +69,8 @@ public func _stdlib_thread_barrier_init( barrier.pointee.cond = UnsafeMutablePointer.allocate(capacity: 1) InitializeConditionVariable(barrier.pointee.cond!) +#elseif os(WASI) + // WASI environment has a only single thread #else barrier.pointee.mutex = UnsafeMutablePointer.allocate(capacity: 1) if pthread_mutex_init(barrier.pointee.mutex!, nil) != 0 { @@ -89,6 +93,8 @@ public func _stdlib_thread_barrier_destroy( #if os(Windows) // Condition Variables do not need to be explicitly destroyed // Mutexes do not need to be explicitly destroyed +#elseif os(WASI) + // WASI environment has a only single thread #else if pthread_cond_destroy(barrier.pointee.cond!) != 0 { // FIXME: leaking memory, leaking a mutex. @@ -99,11 +105,14 @@ public func _stdlib_thread_barrier_destroy( return -1 } #endif + +#if !os(WASI) barrier.pointee.cond!.deinitialize(count: 1) barrier.pointee.cond!.deallocate() barrier.pointee.mutex!.deinitialize(count: 1) barrier.pointee.mutex!.deallocate() +#endif return 0 } @@ -113,6 +122,8 @@ public func _stdlib_thread_barrier_wait( ) -> CInt { #if os(Windows) AcquireSRWLockExclusive(barrier.pointee.mutex!) +#elseif os(WASI) + // WASI environment has a only single thread #else if pthread_mutex_lock(barrier.pointee.mutex!) != 0 { return -1 @@ -127,6 +138,8 @@ public func _stdlib_thread_barrier_wait( return -1 } ReleaseSRWLockExclusive(barrier.pointee.mutex!) +#elseif os(WASI) + // WASI environment has a only single thread #else if pthread_cond_wait(barrier.pointee.cond!, barrier.pointee.mutex!) != 0 { return -1 @@ -144,6 +157,8 @@ public func _stdlib_thread_barrier_wait( #if os(Windows) WakeAllConditionVariable(barrier.pointee.cond!) ReleaseSRWLockExclusive(barrier.pointee.mutex!) +#elseif os(WASI) + // WASI environment has a only single thread #else if pthread_cond_broadcast(barrier.pointee.cond!) != 0 { return -1 diff --git a/stdlib/public/CMakeLists.txt b/stdlib/public/CMakeLists.txt index e8d5da6490b76..5768d2168c373 100644 --- a/stdlib/public/CMakeLists.txt +++ b/stdlib/public/CMakeLists.txt @@ -62,6 +62,10 @@ if(SWIFT_BUILD_STDLIB) add_subdirectory(core) add_subdirectory(SwiftOnoneSupport) + if(WASI IN_LIST SWIFT_SDKS) + add_subdirectory(WASI) + endif() + if(SWIFT_ENABLE_EXPERIMENTAL_DIFFERENTIABLE_PROGRAMMING) add_subdirectory(Differentiation) endif() diff --git a/stdlib/public/Platform/CMakeLists.txt b/stdlib/public/Platform/CMakeLists.txt index 841dc6c602d2d..6a6a2e05ed29c 100644 --- a/stdlib/public/Platform/CMakeLists.txt +++ b/stdlib/public/Platform/CMakeLists.txt @@ -44,7 +44,7 @@ add_swift_target_library(swiftGlibc ${SWIFT_STDLIB_LIBRARY_BUILD_TYPES} IS_SDK_O ${SWIFT_RUNTIME_SWIFT_COMPILE_FLAGS} ${SWIFT_STANDARD_LIBRARY_SWIFT_FLAGS} LINK_FLAGS "${SWIFT_RUNTIME_SWIFT_LINK_FLAGS}" - TARGET_SDKS ANDROID CYGWIN FREEBSD LINUX HAIKU + TARGET_SDKS ANDROID CYGWIN FREEBSD LINUX HAIKU WASI INSTALL_IN_COMPONENT sdk-overlay DEPENDS glibc_modulemap) @@ -70,7 +70,8 @@ foreach(sdk ${SWIFT_SDKS}) NOT "${sdk}" STREQUAL "FREEBSD" AND NOT "${sdk}" STREQUAL "ANDROID" AND NOT "${sdk}" STREQUAL "CYGWIN" AND - NOT "${sdk}" STREQUAL "HAIKU") + NOT "${sdk}" STREQUAL "HAIKU" AND + NOT "${sdk}" STREQUAL "WASI") continue() endif() diff --git a/stdlib/public/Platform/Glibc.swift.gyb b/stdlib/public/Platform/Glibc.swift.gyb index 2de990adfffaf..dc5ca8b711484 100644 --- a/stdlib/public/Platform/Glibc.swift.gyb +++ b/stdlib/public/Platform/Glibc.swift.gyb @@ -69,3 +69,9 @@ public let ${prefix}_TRUE_MIN = ${type}.leastNonzeroMagnitude #endif % end %end + +#if os(WASI) +// WebAssembly's error.h uses a macro that Swift can't import. +public let EINTR:Int32 = 27 +public let EINVAL:Int32 = 28 +#endif diff --git a/stdlib/public/Platform/Platform.swift b/stdlib/public/Platform/Platform.swift index f5e54c7da1283..fce8fb75eadf3 100644 --- a/stdlib/public/Platform/Platform.swift +++ b/stdlib/public/Platform/Platform.swift @@ -366,6 +366,8 @@ public var SIG_IGN: _crt_signal_t { public var SIG_ERR: _crt_signal_t { return unsafeBitCast(-1, to: _crt_signal_t.self) } +#elseif os(WASI) +// WebAssembly/WASI doesn't have signals. #else internal var _ignore = _UnsupportedPlatformError() #endif @@ -380,7 +382,7 @@ public var SEM_FAILED: UnsafeMutablePointer? { #if os(macOS) || os(iOS) || os(watchOS) || os(tvOS) // The value is ABI. Value verified to be correct for OS X, iOS, watchOS, tvOS. return UnsafeMutablePointer(bitPattern: -1) -#elseif os(Linux) || os(FreeBSD) || os(PS4) || os(Android) || os(Cygwin) || os(Haiku) +#elseif os(Linux) || os(FreeBSD) || os(PS4) || os(Android) || os(Cygwin) || os(Haiku) || os(WASI) // The value is ABI. Value verified to be correct on Glibc. return UnsafeMutablePointer(bitPattern: 0) #else diff --git a/stdlib/public/Platform/glibc.modulemap.gyb b/stdlib/public/Platform/glibc.modulemap.gyb index 12de1073b6317..b6171c8c321a0 100644 --- a/stdlib/public/Platform/glibc.modulemap.gyb +++ b/stdlib/public/Platform/glibc.modulemap.gyb @@ -126,10 +126,12 @@ module SwiftGlibc [system] { header "${GLIBC_INCLUDE_PATH}/math.h" export * } +% if CMAKE_SDK != "WASI": module setjmp { header "${GLIBC_INCLUDE_PATH}/setjmp.h" export * } +% end module signal { header "${GLIBC_INCLUDE_PATH}/signal.h" export * @@ -319,6 +321,7 @@ module SwiftGlibc [system] { header "${GLIBC_INCLUDE_PATH}/dirent.h" export * } +% if CMAKE_SDK != "WASI": module dl { header "${GLIBC_INCLUDE_PATH}/link.h" export * @@ -327,6 +330,7 @@ module SwiftGlibc [system] { header "${GLIBC_INCLUDE_PATH}/dlfcn.h" export * } +% end module fcntl { header "${GLIBC_INCLUDE_PATH}/fcntl.h" export * @@ -335,10 +339,12 @@ module SwiftGlibc [system] { header "${GLIBC_INCLUDE_PATH}/fnmatch.h" export * } +% if CMAKE_SDK != "WASI": module grp { header "${GLIBC_INCLUDE_PATH}/grp.h" export * } +% end module ioctl { header "${GLIBC_ARCH_INCLUDE_PATH}/sys/ioctl.h" export * @@ -347,12 +353,14 @@ module SwiftGlibc [system] { header "${GLIBC_INCLUDE_PATH}/libgen.h" export * } +% if CMAKE_SDK != "WASI": module net { module if { header "${GLIBC_INCLUDE_PATH}/net/if.h" export * } } +% end module netinet { module in { header "${GLIBC_INCLUDE_PATH}/netinet/in.h" @@ -369,6 +377,7 @@ module SwiftGlibc [system] { header "${GLIBC_INCLUDE_PATH}/poll.h" export * } +% if CMAKE_SDK != "WASI": module pthread { header "${GLIBC_INCLUDE_PATH}/pthread.h" export * @@ -377,6 +386,7 @@ module SwiftGlibc [system] { header "${GLIBC_INCLUDE_PATH}/pwd.h" export * } +% end module regex { header "${GLIBC_INCLUDE_PATH}/regex.h" export * @@ -422,18 +432,22 @@ module SwiftGlibc [system] { } % end +% if CMAKE_SDK != "WASI": module ipc { header "${GLIBC_ARCH_INCLUDE_PATH}/sys/ipc.h" export * } +% end module mman { header "${GLIBC_ARCH_INCLUDE_PATH}/sys/mman.h" export * } +% if CMAKE_SDK != "WASI": module msg { header "${GLIBC_ARCH_INCLUDE_PATH}/sys/msg.h" export * } +% end module resource { header "${GLIBC_ARCH_INCLUDE_PATH}/sys/resource.h" export * @@ -442,7 +456,7 @@ module SwiftGlibc [system] { header "${GLIBC_ARCH_INCLUDE_PATH}/sys/select.h" export * } -% if CMAKE_SDK != "FREEBSD" and CMAKE_SDK != "HAIKU": +% if CMAKE_SDK != "FREEBSD" and CMAKE_SDK != "HAIKU" and CMAKE_SDK != "WASI": module sendfile { header "${GLIBC_ARCH_INCLUDE_PATH}/sys/sendfile.h" export * @@ -492,10 +506,12 @@ module SwiftGlibc [system] { header "${GLIBC_ARCH_INCLUDE_PATH}/sys/utsname.h" export * } +% if CMAKE_SDK != "WASI": module wait { header "${GLIBC_ARCH_INCLUDE_PATH}/sys/wait.h" export * } +% end } % if CMAKE_SDK in ["LINUX", "FREEBSD"]: module sysexits { @@ -503,23 +519,29 @@ module SwiftGlibc [system] { export * } % end +% if CMAKE_SDK != "WASI": module termios { header "${GLIBC_INCLUDE_PATH}/termios.h" export * } +% end module unistd { header "${GLIBC_INCLUDE_PATH}/unistd.h" export * } +% if CMAKE_SDK != "WASI": module utime { header "${GLIBC_INCLUDE_PATH}/utime.h" export * } +% end } } +% if CMAKE_SDK != "WASI": module CUUID [system] { header "${GLIBC_INCLUDE_PATH}/uuid/uuid.h" link "uuid" export * } +% end diff --git a/stdlib/public/SwiftShims/LibcShims.h b/stdlib/public/SwiftShims/LibcShims.h index 5725f294885f9..1c60a7561c5b8 100644 --- a/stdlib/public/SwiftShims/LibcShims.h +++ b/stdlib/public/SwiftShims/LibcShims.h @@ -43,6 +43,8 @@ typedef __swift_uint32_t __swift_mode_t; typedef __swift_uint16_t __swift_mode_t; #elif defined(_WIN32) typedef __swift_int32_t __swift_mode_t; +#elif defined(__wasi__) +typedef __swift_uint32_t __swift_mode_t; #else // just guessing typedef __swift_uint16_t __swift_mode_t; #endif @@ -105,7 +107,7 @@ static inline __swift_size_t _swift_stdlib_malloc_size(const void *ptr) { return malloc_size(ptr); } #elif defined(__linux__) || defined(__CYGWIN__) || defined(__ANDROID__) \ - || defined(__HAIKU__) || defined(__FreeBSD__) + || defined(__HAIKU__) || defined(__FreeBSD__) || defined(__wasi__) static inline __swift_size_t _swift_stdlib_malloc_size(const void *ptr) { #if defined(__ANDROID__) #if !defined(__ANDROID_API__) || __ANDROID_API__ >= 17 diff --git a/stdlib/public/SwiftShims/Visibility.h b/stdlib/public/SwiftShims/Visibility.h index 8577fad1653b9..8245a3b9be7e7 100644 --- a/stdlib/public/SwiftShims/Visibility.h +++ b/stdlib/public/SwiftShims/Visibility.h @@ -76,7 +76,7 @@ // SWIFT_RUNTIME_EXPORT on the library it's exported from. /// Attribute used to export symbols from the runtime. -#if defined(__MACH__) +#if defined(__MACH__) || defined(__wasm__) # define SWIFT_EXPORT_ATTRIBUTE __attribute__((__visibility__("default"))) diff --git a/stdlib/public/WASI/CMakeLists.txt b/stdlib/public/WASI/CMakeLists.txt new file mode 100644 index 0000000000000..0d088443ad7be --- /dev/null +++ b/stdlib/public/WASI/CMakeLists.txt @@ -0,0 +1,4 @@ +add_swift_target_library(swiftWasiPthread STATIC IS_STDLIB + Pthread.cpp + TARGET_SDKS WASI + INSTALL_IN_COMPONENT stdlib) diff --git a/stdlib/public/WASI/Pthread.cpp b/stdlib/public/WASI/Pthread.cpp new file mode 100644 index 0000000000000..5a64d9bdb4c39 --- /dev/null +++ b/stdlib/public/WASI/Pthread.cpp @@ -0,0 +1,153 @@ +// SPDX-License-Identifier: 0BSD +// prototypes taken from opengroup +#include +#include +#include +#include + +#define STUB() do {fprintf(stderr, "FakePthread: unsupported %s\n", __func__);abort();}while(0) + +// mutexes: just no-ops + +int pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *attr) { + return 0; +} + +int pthread_mutex_destroy(pthread_mutex_t *mutex) { + return 0; +} + +int pthread_mutexattr_init(pthread_mutexattr_t *attr) { + return 0; +} + +int pthread_mutexattr_destroy(pthread_mutexattr_t *attr) { + return 0; +} + +int pthread_mutexattr_gettype(const pthread_mutexattr_t *attr, int *type) { + return 0; +} + +int pthread_mutexattr_settype(pthread_mutexattr_t *attr, int type) { + return 0; +} + +int pthread_mutex_lock(pthread_mutex_t *mutex) { + return 0; +} + +int pthread_mutex_trylock(pthread_mutex_t *mutex) { + return 0; +} + +int pthread_mutex_unlock(pthread_mutex_t *mutex) { + return 0; +} + +// pthread_cond: STUB + +int pthread_cond_init(pthread_cond_t *cond, const pthread_condattr_t *attr) { + return 0; +} + +int pthread_cond_destroy(pthread_cond_t *cond) { + return 0; +} + +int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex) { + STUB(); +} + +int pthread_cond_timedwait(pthread_cond_t *cond, + pthread_mutex_t *mutex, const struct timespec *abstime) { + STUB(); +} + +int pthread_cond_broadcast(pthread_cond_t *cond) { + return 0; +} + +int pthread_cond_signal(pthread_cond_t *cond) { + return 0; +} + +// tls + +int pthread_key_create(pthread_key_t *key, void (*destructor)(void*)) { + STUB(); +} + +void *pthread_getspecific(pthread_key_t key) { + STUB(); +} + +int pthread_setspecific(pthread_key_t key, const void *value) { + STUB(); +} + +// threads + +pthread_t pthread_self() { + return (pthread_t)1234; +} + +#undef pthread_equal + +int pthread_equal(pthread_t t1, pthread_t t2) { + return t1 == t2; +} + +int pthread_join(pthread_t thread, void **value_ptr) { + STUB(); +} + +int pthread_detach(pthread_t thread) { + STUB(); +} + +int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine)(void *), void *arg) { + return 0; +} + +// once + +int pthread_once(pthread_once_t *once_control, void (*init_routine)(void)) { + STUB(); +} + +// rwlock + +int pthread_rwlock_init(pthread_rwlock_t *rwlock, const pthread_rwlockattr_t *attr) { + return 0; +} + +int pthread_rwlock_destroy(pthread_rwlock_t *rwlock) { + return 0; +} + +int pthread_rwlock_rdlock(pthread_rwlock_t *rwlock) { + return 0; +} + +int pthread_rwlock_tryrdlock(pthread_rwlock_t *rwlock) { + return 0; +} + +int pthread_rwlock_wrlock(pthread_rwlock_t *rwlock) { + return 0; +} + +int pthread_rwlock_trywrlock(pthread_rwlock_t *rwlock) { + return 0; +} + +int pthread_rwlock_unlock(pthread_rwlock_t *rwlock) { + return 0; +} + +// named semaphores + +sem_t *sem_open(const char *name, int oflag, ...) { + STUB(); +} diff --git a/stdlib/public/core/AtomicInt.swift.gyb b/stdlib/public/core/AtomicInt.swift.gyb index 62217f282ccc5..80514f42c147c 100644 --- a/stdlib/public/core/AtomicInt.swift.gyb +++ b/stdlib/public/core/AtomicInt.swift.gyb @@ -65,7 +65,7 @@ internal func _swift_stdlib_atomicCompareExchangeStrongInt( object target: UnsafeMutablePointer, expected: UnsafeMutablePointer, desired: Int) -> Bool { -#if arch(i386) || arch(arm) +#if arch(i386) || arch(arm) || arch(wasm32) let (oldValue, won) = Builtin.cmpxchg_seqcst_seqcst_Int32( target._rawValue, expected.pointee._value, desired._value) #elseif arch(x86_64) || arch(arm64) || arch(powerpc64) || arch(powerpc64le) || arch(s390x) @@ -82,7 +82,7 @@ internal func _swift_stdlib_atomicCompareExchangeStrongInt( public // Existing uses outside stdlib func _swift_stdlib_atomicLoadInt( object target: UnsafeMutablePointer) -> Int { -#if arch(i386) || arch(arm) +#if arch(i386) || arch(arm) || arch(wasm32) let value = Builtin.atomicload_seqcst_Int32(target._rawValue) return Int(value) #elseif arch(x86_64) || arch(arm64) || arch(powerpc64) || arch(powerpc64le) || arch(s390x) @@ -95,7 +95,7 @@ func _swift_stdlib_atomicLoadInt( internal func _swift_stdlib_atomicStoreInt( object target: UnsafeMutablePointer, desired: Int) { -#if arch(i386) || arch(arm) +#if arch(i386) || arch(arm) || arch(wasm32) Builtin.atomicstore_seqcst_Int32(target._rawValue, desired._value) #elseif arch(x86_64) || arch(arm64) || arch(powerpc64) || arch(powerpc64le) || arch(s390x) Builtin.atomicstore_seqcst_Int64(target._rawValue, desired._value) @@ -111,7 +111,7 @@ func _swift_stdlib_atomicFetch${operation}Int( object target: UnsafeMutablePointer, operand: Int) -> Int { let rawTarget = UnsafeMutableRawPointer(target) -#if arch(i386) || arch(arm) +#if arch(i386) || arch(arm) || arch(wasm32) let value = _swift_stdlib_atomicFetch${operation}Int32( object: rawTarget.assumingMemoryBound(to: Int32.self), operand: Int32(operand)) diff --git a/stdlib/public/core/BridgeStorage.swift b/stdlib/public/core/BridgeStorage.swift index 4b100f28f7cfe..fcc971f8b6f76 100644 --- a/stdlib/public/core/BridgeStorage.swift +++ b/stdlib/public/core/BridgeStorage.swift @@ -61,7 +61,7 @@ internal struct _BridgeStorage { rawValue = Builtin.reinterpretCast(native) } -#if !(arch(i386) || arch(arm)) +#if !(arch(i386) || arch(arm) || arch(wasm32)) @inlinable @inline(__always) internal init(taggedPayload: UInt) { diff --git a/stdlib/public/core/Builtin.swift b/stdlib/public/core/Builtin.swift index 07c9ce14af6a7..b29bcc0d6aa59 100644 --- a/stdlib/public/core/Builtin.swift +++ b/stdlib/public/core/Builtin.swift @@ -379,7 +379,7 @@ internal var _objectPointerLowSpareBitShift: UInt { } #if arch(i386) || arch(arm) || arch(powerpc64) || arch(powerpc64le) || arch( - s390x) + s390x) || arch(wasm32) @inlinable internal var _objectPointerIsObjCBit: UInt { @inline(__always) get { return 0x0000_0002 } diff --git a/stdlib/public/core/DictionaryVariant.swift b/stdlib/public/core/DictionaryVariant.swift index 988ef9f7d0679..5ffaacc45ef32 100644 --- a/stdlib/public/core/DictionaryVariant.swift +++ b/stdlib/public/core/DictionaryVariant.swift @@ -46,7 +46,7 @@ extension Dictionary { @inlinable @inline(__always) init(dummy: Void) { -#if arch(i386) || arch(arm) +#if arch(i386) || arch(arm) || arch(wasm32) self.init(native: _NativeDictionary()) #else self.object = _BridgeStorage(taggedPayload: 0) diff --git a/stdlib/public/core/Hasher.swift b/stdlib/public/core/Hasher.swift index f7098db934aa3..202c2830610ab 100644 --- a/stdlib/public/core/Hasher.swift +++ b/stdlib/public/core/Hasher.swift @@ -160,7 +160,7 @@ extension Hasher { @inline(__always) internal mutating func combine(_ value: UInt) { -#if arch(i386) || arch(arm) +#if arch(i386) || arch(arm) || arch(wasm32) combine(UInt32(truncatingIfNeeded: value)) #else combine(UInt64(truncatingIfNeeded: value)) @@ -423,7 +423,7 @@ public struct Hasher { @usableFromInline internal static func _hash(seed: Int, _ value: UInt) -> Int { var state = _State(seed: seed) -#if arch(i386) || arch(arm) +#if arch(i386) || arch(arm) || arch(wasm32) _internalInvariant(UInt.bitWidth < UInt64.bitWidth) let tbc = _TailBuffer( tail: UInt64(truncatingIfNeeded: value), diff --git a/stdlib/public/core/SetVariant.swift b/stdlib/public/core/SetVariant.swift index 0092fc74ca45e..ae3149002c7c4 100644 --- a/stdlib/public/core/SetVariant.swift +++ b/stdlib/public/core/SetVariant.swift @@ -36,7 +36,7 @@ extension Set { @inlinable @inline(__always) init(dummy: ()) { -#if arch(i386) || arch(arm) +#if arch(i386) || arch(arm) || arch(wasm32) self.init(native: _NativeSet()) #else self.object = _BridgeStorage(taggedPayload: 0) diff --git a/stdlib/public/core/SmallString.swift b/stdlib/public/core/SmallString.swift index 1f53f8e7ff4fb..9792ed1cf485f 100644 --- a/stdlib/public/core/SmallString.swift +++ b/stdlib/public/core/SmallString.swift @@ -76,7 +76,7 @@ internal struct _SmallString { extension _SmallString { @inlinable @inline(__always) internal static var capacity: Int { -#if arch(i386) || arch(arm) +#if arch(i386) || arch(arm) || arch(wasm32) return 10 #else return 15 diff --git a/stdlib/public/core/StringBridge.swift b/stdlib/public/core/StringBridge.swift index 1896d974204b6..2b892c2d52867 100644 --- a/stdlib/public/core/StringBridge.swift +++ b/stdlib/public/core/StringBridge.swift @@ -285,7 +285,7 @@ internal enum _KnownCocoaString { case storage case shared case cocoa -#if !(arch(i386) || arch(arm)) +#if !(arch(i386) || arch(arm) || arch(wasm32)) case tagged #endif diff --git a/stdlib/public/core/StringGuts.swift b/stdlib/public/core/StringGuts.swift index 2b7765cd4093e..cc6ed08226e67 100644 --- a/stdlib/public/core/StringGuts.swift +++ b/stdlib/public/core/StringGuts.swift @@ -178,7 +178,7 @@ extension _StringGuts { #else @usableFromInline @inline(never) @_effects(releasenone) internal func _invariantCheck() { - #if arch(i386) || arch(arm) + #if arch(i386) || arch(arm) || arch(wasm32) _internalInvariant(MemoryLayout.size == 12, """ the runtime is depending on this, update Reflection.mm and \ this if you change it diff --git a/stdlib/public/core/StringObject.swift b/stdlib/public/core/StringObject.swift index 501d81b66ff53..72cf15c5200c7 100644 --- a/stdlib/public/core/StringObject.swift +++ b/stdlib/public/core/StringObject.swift @@ -77,7 +77,7 @@ internal struct _StringObject { internal init(zero: ()) { self._storage = 0 } } -#if arch(i386) || arch(arm) +#if arch(i386) || arch(arm) || arch(wasm32) @usableFromInline @frozen internal enum Variant { case immortal(UInt) @@ -169,7 +169,7 @@ extension _StringObject { @usableFromInline internal typealias RawBitPattern = (UInt64, UInt64) -#if arch(i386) || arch(arm) +#if arch(i386) || arch(arm) || arch(wasm32) // On 32-bit platforms, raw bit conversion is one-way only and uses the same // layout as on 64-bit platforms. @usableFromInline @@ -245,7 +245,7 @@ extension _StringObject { @inlinable @_transparent internal var discriminatedObjectRawBits: UInt64 { -#if arch(i386) || arch(arm) +#if arch(i386) || arch(arm) || arch(wasm32) let low32: UInt switch _variant { case .immortal(let bitPattern): @@ -387,7 +387,7 @@ extension _StringObject.Nibbles { extension _StringObject { @inlinable @inline(__always) internal static var nativeBias: UInt { -#if arch(i386) || arch(arm) +#if arch(i386) || arch(arm) || arch(wasm32) return 20 #else return 32 @@ -512,7 +512,7 @@ extension _StringObject { // spare bits (the most significant nibble) in a pointer. let word1 = small.rawBits.0.littleEndian let word2 = small.rawBits.1.littleEndian -#if arch(i386) || arch(arm) +#if arch(i386) || arch(arm) || arch(wasm32) // On 32-bit, we need to unpack the small string. let smallStringDiscriminatorAndCount: UInt64 = 0xFF00_0000_0000_0000 @@ -556,7 +556,7 @@ extension _StringObject { @inlinable @inline(__always) internal init(empty:()) { // Canonical empty pattern: small zero-length string -#if arch(i386) || arch(arm) +#if arch(i386) || arch(arm) || arch(wasm32) self.init( count: 0, variant: .immortal(0), @@ -819,7 +819,7 @@ extension _StringObject { @inline(__always) internal var nativeStorage: __StringStorage { -#if arch(i386) || arch(arm) +#if arch(i386) || arch(arm) || arch(wasm32) guard case .native(let storage) = _variant else { _internalInvariantFailure() } @@ -832,7 +832,7 @@ extension _StringObject { @inline(__always) internal var sharedStorage: __SharedStringStorage { -#if arch(i386) || arch(arm) +#if arch(i386) || arch(arm) || arch(wasm32) guard case .native(let storage) = _variant else { _internalInvariantFailure() } @@ -846,7 +846,7 @@ extension _StringObject { @inline(__always) internal var cocoaObject: AnyObject { -#if arch(i386) || arch(arm) +#if arch(i386) || arch(arm) || arch(wasm32) guard case .bridged(let object) = _variant else { _internalInvariantFailure() } @@ -935,7 +935,7 @@ extension _StringObject { internal init(immortal bufPtr: UnsafeBufferPointer, isASCII: Bool) { let countAndFlags = CountAndFlags( immortalCount: bufPtr.count, isASCII: isASCII) -#if arch(i386) || arch(arm) +#if arch(i386) || arch(arm) || arch(wasm32) self.init( variant: .immortal(start: bufPtr.baseAddress._unsafelyUnwrappedUnchecked), discriminator: Nibbles.largeImmortal(), @@ -955,7 +955,7 @@ extension _StringObject { @inline(__always) internal init(_ storage: __StringStorage) { -#if arch(i386) || arch(arm) +#if arch(i386) || arch(arm) || arch(wasm32) self.init( variant: .native(storage), discriminator: Nibbles.largeMortal(), @@ -969,7 +969,7 @@ extension _StringObject { } internal init(_ storage: __SharedStringStorage) { -#if arch(i386) || arch(arm) +#if arch(i386) || arch(arm) || arch(wasm32) self.init( variant: .native(storage), discriminator: Nibbles.largeMortal(), @@ -987,7 +987,7 @@ extension _StringObject { ) { let countAndFlags = CountAndFlags(sharedCount: length, isASCII: isASCII) let discriminator = Nibbles.largeCocoa(providesFastUTF8: providesFastUTF8) -#if arch(i386) || arch(arm) +#if arch(i386) || arch(arm) || arch(wasm32) self.init( variant: .bridged(cocoa), discriminator: discriminator, @@ -1009,7 +1009,7 @@ extension _StringObject { #else @usableFromInline @inline(never) @_effects(releasenone) internal func _invariantCheck() { - #if arch(i386) || arch(arm) + #if arch(i386) || arch(arm) || arch(wasm32) _internalInvariant(MemoryLayout<_StringObject>.size == 12) _internalInvariant(MemoryLayout<_StringObject>.stride == 12) _internalInvariant(MemoryLayout<_StringObject>.alignment == 4) @@ -1079,7 +1079,7 @@ extension _StringObject { } } - #if arch(i386) || arch(arm) + #if arch(i386) || arch(arm) || arch(wasm32) switch _variant { case .immortal: _internalInvariant(isImmortal) @@ -1099,7 +1099,7 @@ extension _StringObject { let raw = self.rawBits let word0 = ("0000000000000000" + String(raw.0, radix: 16)).suffix(16) let word1 = ("0000000000000000" + String(raw.1, radix: 16)).suffix(16) -#if arch(i386) || arch(arm) +#if arch(i386) || arch(arm) || arch(wasm32) print(""" StringObject(\ <\(word0) \(word1)> \ diff --git a/stdlib/public/core/StringStorage.swift b/stdlib/public/core/StringStorage.swift index 8e8a3d29d2133..3e47a43cc3f30 100644 --- a/stdlib/public/core/StringStorage.swift +++ b/stdlib/public/core/StringStorage.swift @@ -46,7 +46,7 @@ private typealias CountAndFlags = _StringObject.CountAndFlags // renamed. The old name must not be used in the new runtime. final internal class __StringStorage : __SwiftNativeNSString, _AbstractStringStorage { -#if arch(i386) || arch(arm) +#if arch(i386) || arch(arm) || arch(wasm32) // The total allocated storage capacity. Note that this includes the required // nul-terminator. internal var _realCapacity: Int @@ -106,7 +106,7 @@ final internal class __StringStorage // for Strings ~1KB or larger, though at this point we're well into our growth // curve. private func determineCodeUnitCapacity(_ desiredCapacity: Int) -> Int { -#if arch(i386) || arch(arm) +#if arch(i386) || arch(arm) || arch(wasm32) // FIXME: Adapt to actual 32-bit allocator. For now, let's arrange things so // that the instance size will be a multiple of 4. let bias = Int(bitPattern: _StringObject.nativeBias) @@ -139,7 +139,7 @@ extension __StringStorage { __StringStorage.self, realCodeUnitCapacity._builtinWordValue, UInt8.self, 1._builtinWordValue, Optional<_StringBreadcrumbs>.self) -#if arch(i386) || arch(arm) +#if arch(i386) || arch(arm) || arch(wasm32) storage._realCapacity = realCodeUnitCapacity storage._count = countAndFlags.count storage._flags = countAndFlags.flags @@ -186,7 +186,7 @@ extension __StringStorage { let count = try initializer(buffer) let countAndFlags = CountAndFlags(mortalCount: count, isASCII: false) - #if arch(i386) || arch(arm) + #if arch(i386) || arch(arm) || arch(wasm32) storage._count = countAndFlags.count storage._flags = countAndFlags.flags #else @@ -319,7 +319,7 @@ extension __StringStorage { internal func _updateCountAndFlags(newCount: Int, newIsASCII: Bool) { let countAndFlags = CountAndFlags( mortalCount: newCount, isASCII: newIsASCII) -#if arch(i386) || arch(arm) +#if arch(i386) || arch(arm) || arch(wasm32) self._count = countAndFlags.count self._flags = countAndFlags.flags #else @@ -463,7 +463,7 @@ final internal class __SharedStringStorage internal var _owner: AnyObject? internal var start: UnsafePointer -#if arch(i386) || arch(arm) +#if arch(i386) || arch(arm) || arch(wasm32) internal var _count: Int internal var _flags: UInt16 @@ -485,7 +485,7 @@ final internal class __SharedStringStorage ) { self._owner = nil self.start = ptr -#if arch(i386) || arch(arm) +#if arch(i386) || arch(arm) || arch(wasm32) self._count = countAndFlags.count self._flags = countAndFlags.flags #else diff --git a/stdlib/public/runtime/CMakeLists.txt b/stdlib/public/runtime/CMakeLists.txt index 7b0c16cc9245e..1463033798a3b 100644 --- a/stdlib/public/runtime/CMakeLists.txt +++ b/stdlib/public/runtime/CMakeLists.txt @@ -56,6 +56,7 @@ set(swift_runtime_sources MetadataLookup.cpp MutexPThread.cpp MutexWin32.cpp + MutexWASI.cpp Numeric.cpp Once.cpp Portability.cpp @@ -80,6 +81,7 @@ endif(LLVM_ENABLE_ASSERTIONS) set(LLVM_OPTIONAL_SOURCES SwiftRT-COFF.cpp SwiftRT-ELF.cpp + SwiftRT-WASM.cpp ${swift_runtime_sources} ${swift_runtime_objc_sources} ${swift_runtime_leaks_sources}) @@ -88,79 +90,121 @@ set(swift_runtime_library_compile_flags ${swift_runtime_compile_flags}) list(APPEND swift_runtime_library_compile_flags -DswiftCore_EXPORTS) list(APPEND swift_runtime_library_compile_flags -I${SWIFT_SOURCE_DIR}/include) -set(sdk "${SWIFT_HOST_VARIANT_SDK}") -if(SWIFT_BUILD_STATIC_STDLIB AND "${sdk}" STREQUAL "LINUX") - list(REMOVE_ITEM swift_runtime_sources ImageInspectionELF.cpp) - set(static_binary_lnk_file_list) +set(static_binary_lnk_file_list) +set(static_binary_dependencies_list) +macro(add_image_inspection_shared sdk primary_arch inspection_file linkfile_src) + if(${inspection_file} IN_LIST swift_runtime_sources) + list(REMOVE_ITEM swift_runtime_sources ${inspection_file}) + endif() string(TOLOWER "${sdk}" lowercase_sdk) # These two libraries are only used with the static swiftcore add_swift_target_library(swiftImageInspectionShared STATIC - ImageInspectionELF.cpp + ${inspection_file} C_COMPILE_FLAGS ${swift_runtime_library_compile_flags} LINK_FLAGS ${swift_runtime_linker_flags} SWIFT_COMPILE_FLAGS ${SWIFT_STANDARD_LIBRARY_SWIFT_FLAGS} + TARGET_SDKS ${sdk} INSTALL_IN_COMPONENT stdlib) foreach(arch IN LISTS SWIFT_SDK_${sdk}_ARCHITECTURES) set(FragileSupportLibrary swiftImageInspectionShared-${SWIFT_SDK_${sdk}_LIB_SUBDIR}-${arch}) set(LibraryLocation ${SWIFTSTATICLIB_DIR}/${lowercase_sdk}/${arch}) - add_custom_command_target(swift_image_inspection_${arch}_static + + add_custom_command_target(swift_image_inspection_${lowercase_sdk}_${arch}_static COMMAND "${CMAKE_COMMAND}" -E copy $ ${LibraryLocation} OUTPUT "${LibraryLocation}/${CMAKE_STATIC_LIBRARY_PREFIX}swiftImageInspectionShared${CMAKE_STATIC_LIBRARY_SUFFIX}" DEPENDS ${FragileSupportLibrary}) + + list(APPEND static_binary_dependencies_list ${swift_image_inspection_${lowercase_sdk}_${arch}_static}) add_dependencies(stdlib ${FragileSupportLibrary}) swift_install_in_component(FILES $ DESTINATION "lib/swift_static/${lowercase_sdk}/${arch}" COMPONENT stdlib) endforeach() - set(FragileSupportLibraryPrimary swiftImageInspectionShared-${SWIFT_SDK_${sdk}_LIB_SUBDIR}-${SWIFT_PRIMARY_VARIANT_ARCH}) - set(LibraryLocationPrimary ${SWIFTSTATICLIB_DIR}/${lowercase_sdk}) - add_custom_command_target(swift_image_inspection_static_primary_arch - COMMAND - "${CMAKE_COMMAND}" -E copy $ ${LibraryLocationPrimary} - OUTPUT - "${LibraryLocationPrimary}/${CMAKE_STATIC_LIBRARY_PREFIX}swiftImageInspectionShared${CMAKE_STATIC_LIBRARY_SUFFIX}" - DEPENDS - ${FragileSupportLibraryPrimary}) + if(NOT "${primary_arch}" STREQUAL "") + set(FragileSupportLibraryPrimary swiftImageInspectionShared-${SWIFT_SDK_${sdk}_LIB_SUBDIR}-${primary_arch}) + set(LibraryLocationPrimary ${SWIFTSTATICLIB_DIR}/${lowercase_sdk}) + add_custom_command_target(swift_image_inspection_static_${lowercase_sdk}_primary_arch + COMMAND + "${CMAKE_COMMAND}" -E copy $ ${LibraryLocationPrimary} + OUTPUT + "${LibraryLocationPrimary}/${CMAKE_STATIC_LIBRARY_PREFIX}swiftImageInspectionShared${CMAKE_STATIC_LIBRARY_SUFFIX}" + DEPENDS + ${FragileSupportLibraryPrimary}) + list(APPEND static_binary_dependencies_list ${swift_image_inspection_static_${lowercase_sdk}_primary_arch}) add_dependencies(stdlib ${FragileSupportLibraryPrimary}) swift_install_in_component(FILES $ DESTINATION "lib/swift_static/${lowercase_sdk}" COMPONENT stdlib) + endif() - # Generate the static-executable-args.lnk file used for ELF systems (eg linux) set(linkfile "${lowercase_sdk}/static-executable-args.lnk") add_custom_command_target(swift_static_binary_${sdk}_args COMMAND "${CMAKE_COMMAND}" -E copy - "${SWIFT_SOURCE_DIR}/utils/static-executable-args.lnk" + "${linkfile_src}" "${SWIFTSTATICLIB_DIR}/${linkfile}" OUTPUT "${SWIFTSTATICLIB_DIR}/${linkfile}" DEPENDS - "${SWIFT_SOURCE_DIR}/utils/static-executable-args.lnk") + "${linkfile_src}") list(APPEND static_binary_lnk_file_list ${swift_static_binary_${sdk}_args}) swift_install_in_component(FILES "${SWIFTSTATICLIB_DIR}/${linkfile}" DESTINATION "lib/swift_static/${lowercase_sdk}" COMPONENT stdlib) - add_custom_target(static_binary_magic ALL DEPENDS ${static_binary_lnk_file_list}) - foreach(arch IN LISTS SWIFT_SDK_LINUX_ARCHITECTURES) - add_dependencies(static_binary_magic ${swift_image_inspection_${arch}_static}) - endforeach() - add_dependencies(static_binary_magic ${swift_image_inspection_static_primary_arch}) - add_dependencies(stdlib static_binary_magic) add_swift_target_library(swiftImageInspectionSharedObject OBJECT_LIBRARY - ImageInspectionELF.cpp + ${inspection_file} C_COMPILE_FLAGS ${swift_runtime_library_compile_flags} LINK_FLAGS ${swift_runtime_linker_flags} SWIFT_COMPILE_FLAGS ${SWIFT_STANDARD_LIBRARY_SWIFT_FLAGS} + TARGET_SDKS ${sdk} INSTALL_IN_COMPONENT never_install) +endmacro() + +set(is_image_inspection_required) +foreach(sdk IN LISTS SWIFT_SDKS) + set(image_inspection_shared_sdk) + set(primary_arch) + set(image_inspection_shared_file) + set(linkfile_src) + + if("${SWIFT_SDK_${sdk}_OBJECT_FORMAT}" STREQUAL "ELF") + list(APPEND ELFISH_SDKS ${sdk}) + set(linkfile_src "${SWIFT_SOURCE_DIR}/utils/static-executable-args.lnk") + elseif("${SWIFT_SDK_${sdk}_OBJECT_FORMAT}" STREQUAL "WASM") + set(linkfile_src "${SWIFT_SOURCE_DIR}/utils/webassembly/static-executable-args.lnk") + endif() + + if(SWIFT_BUILD_STATIC_STDLIB AND "${sdk}" STREQUAL "LINUX") + set(image_inspection_shared_sdk "${sdk}") + set(image_inspection_shared_file ImageInspectionELF.cpp) + elseif(SWIFT_BUILD_STATIC_STDLIB AND "${sdk}" STREQUAL "WASI") + set(image_inspection_shared_sdk "${sdk}") + set(image_inspection_shared_file ImageInspectionELF.cpp) + # Set default arch + set(primary_arch "wasm32") + endif() + + if("${sdk}" STREQUAL "${SWIFT_PRIMARY_VARIANT_SDK}") + set(primary_arch ${SWIFT_PRIMARY_VARIANT_ARCH}) + endif() + + if(NOT "${image_inspection_shared_sdk}" STREQUAL "" AND NOT "${primary_arch}" STREQUAL "") + set(is_image_inspection_required TRUE) + add_image_inspection_shared(${image_inspection_shared_sdk} ${primary_arch} ${image_inspection_shared_file} ${linkfile_src}) + endif() +endforeach() + +if(is_image_inspection_required) + add_custom_target(static_binary_magic ALL DEPENDS ${static_binary_lnk_file_list} ${static_binary_dependencies_list}) + add_dependencies(stdlib static_binary_magic) endif() if(SWIFT_STDLIB_USE_NONATOMIC_RC) @@ -179,11 +223,14 @@ add_swift_target_library(swiftRuntime OBJECT_LIBRARY set(ELFISH_SDKS) set(COFF_SDKS) +set(WASM_SDKS) foreach(sdk ${SWIFT_CONFIGURED_SDKS}) if("${SWIFT_SDK_${sdk}_OBJECT_FORMAT}" STREQUAL "ELF") list(APPEND ELFISH_SDKS ${sdk}) elseif("${SWIFT_SDK_${sdk}_OBJECT_FORMAT}" STREQUAL "COFF") list(APPEND COFF_SDKS ${sdk}) + elseif("${SWIFT_SDK_${sdk}_OBJECT_FORMAT}" STREQUAL "WASM") + list(APPEND WASM_SDKS ${sdk}) endif() endforeach() @@ -196,6 +243,16 @@ add_swift_target_library(swiftImageRegistrationObjectELF TARGET_SDKS ${ELFISH_SDKS} SWIFT_COMPILE_FLAGS ${SWIFT_STANDARD_LIBRARY_SWIFT_FLAGS} INSTALL_IN_COMPONENT none) + +add_swift_target_library(swiftImageRegistrationObjectWASM + OBJECT_LIBRARY IS_STDLIB IS_STDLIB_CORE + SwiftRT-WASM.cpp + C_COMPILE_FLAGS ${SWIFT_RUNTIME_CORE_CXX_FLAGS} + LINK_FLAGS ${SWIFT_RUNTIME_CORE_LINK_FLAGS} + TARGET_SDKS ${WASM_SDKS} + SWIFT_COMPILE_FLAGS ${SWIFT_STANDARD_LIBRARY_SWIFT_FLAGS} + INSTALL_IN_COMPONENT none) + # FIXME(compnerd) this should be compiled twice, once for static and once for # shared. The static version should be used for building the standard library. add_swift_target_library(swiftImageRegistrationObjectCOFF @@ -213,7 +270,8 @@ foreach(sdk ${SWIFT_CONFIGURED_SDKS}) set(arch_suffix "${SWIFT_SDK_${sdk}_LIB_SUBDIR}-${arch}") if("${SWIFT_SDK_${sdk}_OBJECT_FORMAT}" STREQUAL "ELF" OR - "${SWIFT_SDK_${sdk}_OBJECT_FORMAT}" STREQUAL "COFF") + "${SWIFT_SDK_${sdk}_OBJECT_FORMAT}" STREQUAL "COFF" OR + "${SWIFT_SDK_${sdk}_OBJECT_FORMAT}" STREQUAL "WASM") # TODO(compnerd) switch to the generator expression when cmake is upgraded # to a version which supports it. # set(swiftrtObject "$") diff --git a/stdlib/public/runtime/Casting.cpp b/stdlib/public/runtime/Casting.cpp index 2c516a9952fb4..0456b400611ee 100644 --- a/stdlib/public/runtime/Casting.cpp +++ b/stdlib/public/runtime/Casting.cpp @@ -30,7 +30,12 @@ #include "swift/Runtime/ExistentialContainer.h" #include "swift/Runtime/HeapObject.h" #include "swift/Runtime/Metadata.h" -#include "swift/Runtime/Mutex.h" +#ifdef __wasi__ +# define SWIFT_CASTING_SUPPORTS_MUTEX 0 +#else +# define SWIFT_CASTING_SUPPORTS_MUTEX 1 +# include "swift/Runtime/Mutex.h" +#endif #include "swift/Runtime/Unreachable.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/PointerIntPair.h" @@ -125,7 +130,9 @@ TypeNamePair swift::swift_getTypeName(const Metadata *type, bool qualified) { using Key = llvm::PointerIntPair; + #if SWIFT_CASTING_SUPPORTS_MUTEX static StaticReadWriteLock TypeNameCacheLock; + #endif static Lazy>> TypeNameCache; @@ -134,7 +141,9 @@ swift::swift_getTypeName(const Metadata *type, bool qualified) { // Attempt read-only lookup of cache entry. { + #if SWIFT_CASTING_SUPPORTS_MUTEX StaticScopedReadLock guard(TypeNameCacheLock); + #endif auto found = cache.find(key); if (found != cache.end()) { @@ -145,7 +154,9 @@ swift::swift_getTypeName(const Metadata *type, bool qualified) { // Read-only lookup failed to find item, we may need to create it. { + #if SWIFT_CASTING_SUPPORTS_MUTEX StaticScopedWriteLock guard(TypeNameCacheLock); + #endif // Do lookup again just to make sure it wasn't created by another // thread before we acquired the write lock. diff --git a/stdlib/public/runtime/CompatibilityOverride.cpp b/stdlib/public/runtime/CompatibilityOverride.cpp index 3eebb8581ff24..7723eaad3a439 100644 --- a/stdlib/public/runtime/CompatibilityOverride.cpp +++ b/stdlib/public/runtime/CompatibilityOverride.cpp @@ -49,7 +49,12 @@ static_assert(std::is_pod::value, static OverrideSection *getOverrideSectionPtr() { static OverrideSection *OverrideSectionPtr; static swift_once_t Predicate; + // WebAssembly: hack +#ifdef __wasm__ + swift_once_real(&Predicate, [](void *) { +#else swift_once(&Predicate, [](void *) { +#endif size_t Size; OverrideSectionPtr = static_cast( lookupSection("__DATA", "__swift52_hooks", &Size)); diff --git a/stdlib/public/runtime/CompatibilityOverride.h b/stdlib/public/runtime/CompatibilityOverride.h index abc2eea227424..ad79a27273d51 100644 --- a/stdlib/public/runtime/CompatibilityOverride.h +++ b/stdlib/public/runtime/CompatibilityOverride.h @@ -39,7 +39,7 @@ namespace swift { Override_ ## name getOverride_ ## name(); #include "CompatibilityOverride.def" - +#ifndef __wasm__ /// Used to define an override point. The override point #defines the appropriate /// OVERRIDE macro from CompatibilityOverride.def to this macro, then includes /// the file to generate the override points. The original implementation of the @@ -55,6 +55,20 @@ namespace swift { return Override(COMPATIBILITY_UNPAREN namedArgs, swift_ ## name ## Impl); \ return swift_ ## name ## Impl namedArgs; \ } +#else +// WebAssembly: hack: change to swift_once_real +#define COMPATIBILITY_OVERRIDE(name, ret, attrs, ccAttrs, namespace, typedArgs, namedArgs) \ + attrs ccAttrs ret namespace swift_ ## name typedArgs { \ + static Override_ ## name Override; \ + static swift_once_t Predicate; \ + swift_once_real(&Predicate, [](void *) { \ + Override = getOverride_ ## name(); \ + }, nullptr); \ + if (Override != nullptr) \ + return Override(COMPATIBILITY_UNPAREN namedArgs, swift_ ## name ## Impl); \ + return swift_ ## name ## Impl namedArgs; \ + } +#endif } /* end namespace swift */ diff --git a/stdlib/public/runtime/Errors.cpp b/stdlib/public/runtime/Errors.cpp index 6e202434750f0..48201d54d6a2a 100644 --- a/stdlib/public/runtime/Errors.cpp +++ b/stdlib/public/runtime/Errors.cpp @@ -14,7 +14,7 @@ // //===----------------------------------------------------------------------===// -#if defined(__CYGWIN__) || defined(__HAIKU__) +#if defined(__CYGWIN__) || defined(__HAIKU__) || defined(__wasi__) #define SWIFT_SUPPORTS_BACKTRACE_REPORTING 0 #else #define SWIFT_SUPPORTS_BACKTRACE_REPORTING 1 diff --git a/stdlib/public/runtime/Exclusivity.cpp b/stdlib/public/runtime/Exclusivity.cpp index dfff68f105f0f..59acc280dfadf 100644 --- a/stdlib/public/runtime/Exclusivity.cpp +++ b/stdlib/public/runtime/Exclusivity.cpp @@ -24,7 +24,9 @@ #include // Pick a return-address strategy -#if __GNUC__ +#if defined(__wasm__) +#define get_return_address() ((void*) 0) +#elif __GNUC__ #define get_return_address() __builtin_return_address(0) #elif _MSC_VER #include @@ -36,7 +38,11 @@ using namespace swift; +#ifdef __wasm__ +bool swift::_swift_disableExclusivityChecking = true; +#else bool swift::_swift_disableExclusivityChecking = false; +#endif static const char *getAccessName(ExclusivityFlags flags) { switch (flags) { diff --git a/stdlib/public/runtime/Heap.cpp b/stdlib/public/runtime/Heap.cpp index 46e133a7b1d17..a241d153299e3 100644 --- a/stdlib/public/runtime/Heap.cpp +++ b/stdlib/public/runtime/Heap.cpp @@ -42,6 +42,11 @@ using namespace swift; #elif defined(_WIN32) # define MALLOC_ALIGN_MASK 7 +#elif defined(__wasi__) +// Musl malloc is 4*sizeof(size_t), so 16 bytes on 32-bit? +// For some reason the unknown alignment code fails because std::max isn't constexpr? +# define MALLOC_ALIGN_MASK 15 + #else // Unknown alignment, but the standard requires alignment suitable for the largest // standard types. diff --git a/stdlib/public/runtime/HeapObject.cpp b/stdlib/public/runtime/HeapObject.cpp index aa306722f3209..25a171bc7b96b 100644 --- a/stdlib/public/runtime/HeapObject.cpp +++ b/stdlib/public/runtime/HeapObject.cpp @@ -152,7 +152,13 @@ swift::swift_initStaticObject(HeapMetadata const *metadata, // refcount to 1 while another thread already incremented it - and would // decrement it to 0 afterwards. InitStaticObjectContext Ctx = { object, metadata }; +#ifdef __wasm__ + // WebAssembly: hack: swift_once has been modified to take a function pointer without a parameter. + // so use the _real version that does have a parameter + swift_once_real(token, initStaticObjectWithContext, &Ctx); +#else swift_once(token, initStaticObjectWithContext, &Ctx); +#endif return object; } diff --git a/stdlib/public/runtime/ImageInspectionCOFF.cpp b/stdlib/public/runtime/ImageInspectionCOFF.cpp index a6f6d906f98e6..09f0251f12bb6 100644 --- a/stdlib/public/runtime/ImageInspectionCOFF.cpp +++ b/stdlib/public/runtime/ImageInspectionCOFF.cpp @@ -10,7 +10,7 @@ // //===----------------------------------------------------------------------===// -#if !defined(__ELF__) && !defined(__MACH__) +#if !defined(__ELF__) && !defined(__MACH__) && !defined(__wasm__) #include "ImageInspection.h" #include "ImageInspectionCOFF.h" diff --git a/stdlib/public/runtime/ImageInspectionCOFF.h b/stdlib/public/runtime/ImageInspectionCOFF.h index c76a33e25d0c4..b5e54c46687db 100644 --- a/stdlib/public/runtime/ImageInspectionCOFF.h +++ b/stdlib/public/runtime/ImageInspectionCOFF.h @@ -19,7 +19,7 @@ #ifndef SWIFT_RUNTIME_IMAGEINSPECTIONCOFF_H #define SWIFT_RUNTIME_IMAGEINSPECTIONCOFF_H -#if !defined(__ELF__) && !defined(__MACH__) +#if !defined(__ELF__) && !defined(__MACH__) && !defined(__wasm__) #include "../SwiftShims/Visibility.h" #include diff --git a/stdlib/public/runtime/ImageInspectionELF.cpp b/stdlib/public/runtime/ImageInspectionELF.cpp index 331ee3614f54f..9c0fe4d949dcf 100644 --- a/stdlib/public/runtime/ImageInspectionELF.cpp +++ b/stdlib/public/runtime/ImageInspectionELF.cpp @@ -18,11 +18,13 @@ /// //===----------------------------------------------------------------------===// -#if defined(__ELF__) +#if defined(__ELF__) || defined(__wasm__) #include "ImageInspection.h" #include "ImageInspectionELF.h" +#ifndef __wasm__ #include +#endif using namespace swift; @@ -132,6 +134,7 @@ void swift_addNewDSOImage(const void *addr) { } int swift::lookupSymbol(const void *address, SymbolInfo *info) { +#ifndef __wasm__ Dl_info dlinfo; if (dladdr(address, &dlinfo) == 0) { return 0; @@ -142,6 +145,9 @@ int swift::lookupSymbol(const void *address, SymbolInfo *info) { info->symbolName.reset(dlinfo.dli_sname); info->symbolAddress = dlinfo.dli_saddr; return 1; +#else + return 0; +#endif } // This is only used for backward deployment hooks, which we currently only support for diff --git a/stdlib/public/runtime/ImageInspectionELF.h b/stdlib/public/runtime/ImageInspectionELF.h index afa2ee7150603..6b120897fc926 100644 --- a/stdlib/public/runtime/ImageInspectionELF.h +++ b/stdlib/public/runtime/ImageInspectionELF.h @@ -21,7 +21,7 @@ #define SWIFT_REFLECTION_METADATA_ELF_NOTE_MAGIC_STRING "swift_reflection_metadata_magic_string" -#if defined(__ELF__) +#if defined(__ELF__) || defined(__wasm__) #include "../SwiftShims/Visibility.h" #include diff --git a/stdlib/public/runtime/Metadata.cpp b/stdlib/public/runtime/Metadata.cpp index 2546d90dec5cd..23b4ecce1e370 100644 --- a/stdlib/public/runtime/Metadata.cpp +++ b/stdlib/public/runtime/Metadata.cpp @@ -44,7 +44,10 @@ #else #include #include +// WASI doesn't have dynamic linking yet +#ifndef __wasi__ #include +#endif //__wasi #endif #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/Hashing.h" diff --git a/stdlib/public/runtime/MutexPThread.cpp b/stdlib/public/runtime/MutexPThread.cpp index 62e718c16abaa..92db58226cd09 100644 --- a/stdlib/public/runtime/MutexPThread.cpp +++ b/stdlib/public/runtime/MutexPThread.cpp @@ -15,7 +15,7 @@ // //===----------------------------------------------------------------------===// -#if !defined(_WIN32) +#if !defined(_WIN32) && !defined(__wasi__) #include "swift/Runtime/Mutex.h" #include "swift/Runtime/Debug.h" diff --git a/stdlib/public/runtime/MutexWASI.cpp b/stdlib/public/runtime/MutexWASI.cpp new file mode 100644 index 0000000000000..6288ecce03449 --- /dev/null +++ b/stdlib/public/runtime/MutexWASI.cpp @@ -0,0 +1,25 @@ +//===--- MutexWin32.cpp - -------------------------------------------------===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors +// Licensed under Apache License v2.0 with Runtime Library Exception +// +// See https://swift.org/LICENSE.txt for license information +// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +// +//===----------------------------------------------------------------------===// +// +// Mutex, ConditionVariable, Read/Write lock, and Scoped lock implementations +// using Windows Slim Reader/Writer Locks and Conditional Variables. +// +//===----------------------------------------------------------------------===// + +#if defined(__wasi__) +#include "swift/Runtime/Mutex.h" + +using namespace swift; + +void ConditionPlatformHelper::wait(void* &condition, + void* &mutex) {} +#endif diff --git a/stdlib/public/runtime/Once.cpp b/stdlib/public/runtime/Once.cpp index 57282590cbd06..7554d5d4ae751 100644 --- a/stdlib/public/runtime/Once.cpp +++ b/stdlib/public/runtime/Once.cpp @@ -52,7 +52,28 @@ void swift::swift_once(swift_once_t *predicate, void (*fn)(void *), dispatch_once_f(predicate, context, fn); #elif defined(__CYGWIN__) _swift_once_f(predicate, context, fn); +#elif defined(__wasm__) + // WebAssembly: hack: Swift compiler passes in a fn that doesn't take a parameter, + // which is invalid in WebAssembly. So swift_once casts the function. + // The correct way to fix this is to change + // SILGenModule::emitLazyGlobalInitializer + // but this is OK as a proof of concept. + // Keep a copy of the unmodified swift_once function below. + std::call_once(*predicate, [fn, context]() { ((void (*)())fn)(); }); #else std::call_once(*predicate, [fn, context]() { fn(context); }); #endif } + +#ifdef __wasm__ +void swift::swift_once_real(swift_once_t *predicate, void (*fn)(void *), + void *context) { +#if defined(__APPLE__) + dispatch_once_f(predicate, context, fn); +#elif defined(__CYGWIN__) + _swift_once_f(predicate, context, fn); +#else + std::call_once(*predicate, [fn, context]() { fn(context); }); +#endif +} +#endif diff --git a/stdlib/public/runtime/SwiftRT-WASM.cpp b/stdlib/public/runtime/SwiftRT-WASM.cpp new file mode 100644 index 0000000000000..24dc7130def4d --- /dev/null +++ b/stdlib/public/runtime/SwiftRT-WASM.cpp @@ -0,0 +1,82 @@ +//===--- SwiftRT-WASM.cpp --------------------------------------------------===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors +// Licensed under Apache License v2.0 with Runtime Library Exception +// +// See https://swift.org/LICENSE.txt for license information +// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +// +//===----------------------------------------------------------------------===// + +#include "ImageInspectionELF.h" + +#include + +// Link start/stop symbols weakly to link them if they aren't synthesized by the linker. +#define DECLARE_SWIFT_SECTION(name) \ + __attribute__((__visibility__("hidden"),__aligned__(1),weak)) extern const char __start_##name; \ + __attribute__((__visibility__("hidden"),__aligned__(1),weak)) extern const char __stop_##name; + +extern "C" { +DECLARE_SWIFT_SECTION(swift5_protocols) +DECLARE_SWIFT_SECTION(swift5_protocol_conformances) +DECLARE_SWIFT_SECTION(swift5_type_metadata) + +DECLARE_SWIFT_SECTION(swift5_typeref) +DECLARE_SWIFT_SECTION(swift5_reflstr) +DECLARE_SWIFT_SECTION(swift5_fieldmd) +DECLARE_SWIFT_SECTION(swift5_assocty) +DECLARE_SWIFT_SECTION(swift5_replace) +DECLARE_SWIFT_SECTION(swift5_replac2) +DECLARE_SWIFT_SECTION(swift5_builtin) +DECLARE_SWIFT_SECTION(swift5_capture) +} + +#undef DECLARE_SWIFT_SECTION + +namespace { +static swift::MetadataSections sections{}; +} + +__attribute__((__constructor__)) +static void swift_image_constructor() { +#define SWIFT_SECTION_RANGE(name) \ + { reinterpret_cast(&__start_##name), \ + static_cast(&__stop_##name - &__start_##name) } + + sections = { + swift::CurrentSectionMetadataVersion, + 0, + + nullptr, + nullptr, + + SWIFT_SECTION_RANGE(swift5_protocols), + SWIFT_SECTION_RANGE(swift5_protocol_conformances), + SWIFT_SECTION_RANGE(swift5_type_metadata), + + SWIFT_SECTION_RANGE(swift5_typeref), + SWIFT_SECTION_RANGE(swift5_reflstr), + SWIFT_SECTION_RANGE(swift5_fieldmd), + SWIFT_SECTION_RANGE(swift5_assocty), + SWIFT_SECTION_RANGE(swift5_replace), + SWIFT_SECTION_RANGE(swift5_replac2), + SWIFT_SECTION_RANGE(swift5_builtin), + SWIFT_SECTION_RANGE(swift5_capture), + }; + +#undef SWIFT_SECTION_RANGE + + swift_addNewDSOImage(§ions); +} + +static __attribute__((__used__)) +__attribute__((__section__(".note.swift_reflection_metadata"))) +__attribute__((__aligned__(1))) +struct { + const char MagicString[sizeof(SWIFT_REFLECTION_METADATA_ELF_NOTE_MAGIC_STRING)]; + const swift::MetadataSections *Sections; +} __attribute__((__packed__)) +Note = {SWIFT_REFLECTION_METADATA_ELF_NOTE_MAGIC_STRING, §ions}; diff --git a/stdlib/public/runtime/ThreadLocalStorage.h b/stdlib/public/runtime/ThreadLocalStorage.h index 82e2457b24f8a..4e62b76b1d74e 100644 --- a/stdlib/public/runtime/ThreadLocalStorage.h +++ b/stdlib/public/runtime/ThreadLocalStorage.h @@ -81,6 +81,8 @@ typedef int __swift_thread_key_t; typedef unsigned long __swift_thread_key_t; # elif defined(__HAIKU__) typedef int __swift_thread_key_t; +# elif defined(__wasi__) +typedef unsigned int __swift_thread_key_t; # else typedef unsigned long __swift_thread_key_t; # endif @@ -96,7 +98,13 @@ static_assert(std::is_same<__swift_thread_key_t, DWORD>::value, # define SWIFT_THREAD_KEY_CREATE _stdlib_thread_key_create # define SWIFT_THREAD_GETSPECIFIC FlsGetValue # define SWIFT_THREAD_SETSPECIFIC(key, value) (FlsSetValue(key, value) == FALSE) - +# elif defined(__wasi__) +int wasi_polyfill_pthread_key_create(__swift_thread_key_t *key, void (*destructor)(void*)); +void *wasi_polyfill_pthread_getspecific(__swift_thread_key_t key); +int wasi_polyfill_pthread_setspecific(__swift_thread_key_t key, const void *value); +# define SWIFT_THREAD_KEY_CREATE wasi_polyfill_pthread_key_create +# define SWIFT_THREAD_GETSPECIFIC wasi_polyfill_pthread_getspecific +# define SWIFT_THREAD_SETSPECIFIC wasi_polyfill_pthread_setspecific # else // Otherwise use the pthread API. # include diff --git a/stdlib/public/stubs/CommandLine.cpp b/stdlib/public/stubs/CommandLine.cpp index 0b4506391beeb..cf371e5ababe4 100644 --- a/stdlib/public/stubs/CommandLine.cpp +++ b/stdlib/public/stubs/CommandLine.cpp @@ -206,6 +206,42 @@ char ** _swift_stdlib_getUnsafeArgvArgc(int *outArgLen) { return outBuf; } +#elif defined(__wasi__) +#include +#include +#include + +SWIFT_RUNTIME_STDLIB_API +char ** _swift_stdlib_getUnsafeArgvArgc(int *outArgLen) { + assert(outArgLen != nullptr); + + if (_swift_stdlib_ProcessOverrideUnsafeArgv) { + *outArgLen = _swift_stdlib_ProcessOverrideUnsafeArgc; + return _swift_stdlib_ProcessOverrideUnsafeArgv; + } + + __wasi_errno_t err; + + size_t argv_buf_size; + size_t argc; + err = __wasi_args_sizes_get(&argc, &argv_buf_size); + if (err != __WASI_ERRNO_SUCCESS) return nullptr; + + size_t num_ptrs = argc + 1; + char *argv_buf = (char *)malloc(argv_buf_size); + char **argv = (char **)calloc(num_ptrs, sizeof(char *)); + + err = __wasi_args_get((uint8_t **)argv, (uint8_t *)argv_buf); + if (err != __WASI_ERRNO_SUCCESS) { + free(argv_buf); + free(argv); + return nullptr; + } + + *outArgLen = static_cast(argc); + + return argv; +} #else // Add your favorite OS's command line arg grabber here. SWIFT_RUNTIME_STDLIB_API char ** _swift_stdlib_getUnsafeArgvArgc(int *outArgLen) { diff --git a/stdlib/public/stubs/LibcShims.cpp b/stdlib/public/stubs/LibcShims.cpp index 083deaa4747a1..b54ede8c61f66 100644 --- a/stdlib/public/stubs/LibcShims.cpp +++ b/stdlib/public/stubs/LibcShims.cpp @@ -23,7 +23,7 @@ #include #include -#if defined(__unix__) || (defined(__APPLE__) && defined(__MACH__)) +#if defined(__unix__) || (defined(__APPLE__) && defined(__MACH__)) || defined(__wasi__) #include #endif diff --git a/stdlib/public/stubs/Random.cpp b/stdlib/public/stubs/Random.cpp index bb69f7e7793d1..e099d9c5e43ee 100644 --- a/stdlib/public/stubs/Random.cpp +++ b/stdlib/public/stubs/Random.cpp @@ -42,6 +42,10 @@ #include "swift/Runtime/Mutex.h" #include "../SwiftShims/Random.h" +#ifdef __wasi__ +#include // std::min +#endif + #if defined(__APPLE__) SWIFT_RUNTIME_STDLIB_API @@ -88,7 +92,7 @@ void swift::swift_stdlib_random(void *buf, __swift_size_t nbytes) { if (getrandom_available) { actual_nbytes = WHILE_EINTR(syscall(__NR_getrandom, buf, nbytes, 0)); } -#elif __has_include() && (defined(__CYGWIN__) || defined(__Fuchsia__)) +#elif __has_include() && (defined(__CYGWIN__) || defined(__Fuchsia__) || defined(__wasi__)) __swift_size_t getentropy_nbytes = std::min(nbytes, __swift_size_t{256}); if (0 == getentropy(buf, getentropy_nbytes)) { diff --git a/stdlib/public/stubs/Stubs.cpp b/stdlib/public/stubs/Stubs.cpp index 55bada6a1db92..d8416c62f1733 100644 --- a/stdlib/public/stubs/Stubs.cpp +++ b/stdlib/public/stubs/Stubs.cpp @@ -26,7 +26,7 @@ #define NOMINMAX #include #else -#if !defined(__HAIKU__) +#if !defined(__HAIKU__) && !defined(__wasi__) #include #else #include @@ -67,7 +67,7 @@ static float swift_strtof_l(const char *nptr, char **endptr, locale_t loc) { #define strtod_l swift_strtod_l #define strtof_l swift_strtof_l #endif -#elif defined(__linux__) +#elif defined(__linux__) || defined(__wasi__) #include #else #include @@ -503,6 +503,8 @@ const char *swift::_swift_stdlib_strtof_clocale( void swift::_swift_stdlib_flockfile_stdout() { #if defined(_WIN32) _lock_file(stdout); +#elif defined(__wasi__) + // WebAssembly/WASI doesn't support file locking yet #else flockfile(stdout); #endif @@ -511,6 +513,8 @@ void swift::_swift_stdlib_flockfile_stdout() { void swift::_swift_stdlib_funlockfile_stdout() { #if defined(_WIN32) _unlock_file(stdout); +#elif defined(__wasi__) + // WebAssembly/WASI doesn't support file locking yet #else funlockfile(stdout); #endif diff --git a/stdlib/public/stubs/ThreadLocalStorage.cpp b/stdlib/public/stubs/ThreadLocalStorage.cpp index 50168f955bc6c..4e855cb593b72 100644 --- a/stdlib/public/stubs/ThreadLocalStorage.cpp +++ b/stdlib/public/stubs/ThreadLocalStorage.cpp @@ -25,6 +25,26 @@ void *_stdlib_createTLS(void); #if !SWIFT_TLS_HAS_RESERVED_PTHREAD_SPECIFIC || (defined(_WIN32) && !defined(__CYGWIN__)) +#if defined(__wasi__) +#define STUB() do { /* fprintf(stderr, "%s is unsupported on WASI environment\n", __func__);*/ abort(); } while(0) +void wasi_polyfill_call_once(int *flag, void *context, void (*func)(void *)) + { + switch (*flag) { + case 0: + func(context); + *flag = 1; + return; + case 1: + return; + default: + STUB(); + } + } +int wasi_polyfill_pthread_key_create(__swift_thread_key_t *key, void (*destructor)(void*)) { STUB(); } +void *wasi_polyfill_pthread_getspecific(__swift_thread_key_t key) { STUB(); } +int wasi_polyfill_pthread_setspecific(__swift_thread_key_t key, const void *value) { STUB(); } +#endif + static void #if defined(_M_IX86) __stdcall diff --git a/stdlib/tools/swift-reflection-test/swift-reflection-test.c b/stdlib/tools/swift-reflection-test/swift-reflection-test.c index dfcfe544c1078..e454e0dcd493b 100644 --- a/stdlib/tools/swift-reflection-test/swift-reflection-test.c +++ b/stdlib/tools/swift-reflection-test/swift-reflection-test.c @@ -27,7 +27,7 @@ #include #include #include -#if defined(__unix__) || (defined(__APPLE__) && defined(__MACH__)) +#if defined(__unix__) || (defined(__APPLE__) && defined(__MACH__)) || defined(__wasi__) #include #elif defined(_WIN32) #include diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 796b9bf1da4cb..e457525edbe19 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -75,7 +75,8 @@ function(get_test_dependencies SDK result_var_name) ("${SDK}" STREQUAL "FREEBSD") OR ("${SDK}" STREQUAL "ANDROID") OR ("${SDK}" STREQUAL "WINDOWS") OR - ("${SDK}" STREQUAL "HAIKU")) + ("${SDK}" STREQUAL "HAIKU") OR + ("${SDK}" STREQUAL "WASI")) # No extra dependencies. else() message(FATAL_ERROR "Unknown SDK: ${SDK}") @@ -224,28 +225,30 @@ foreach(SDK ${SWIFT_SDKS}) # NOTE create a stub BlocksRuntime library that can be used for the # reflection tests - file(WRITE ${test_bin_dir}/Inputs/BlocksRuntime.c + if(NOT CMAKE_SYSTEM_NAME STREQUAL Darwin AND (SWIFT_BUILD_SYNTAXPARSERLIB OR SWIFT_BUILD_SOURCEKIT)) + file(WRITE ${test_bin_dir}/Inputs/BlocksRuntime.c "void #if defined(_WIN32) __declspec(dllexport) #endif _Block_release(void) { }\n") - _add_swift_library_single( - BlocksRuntimeStub${VARIANT_SUFFIX} - BlocksRuntimeStub - SHARED - DONT_EMBED_BITCODE - NOSWIFTRT - ARCHITECTURE ${ARCH} - SDK ${SDK} - INSTALL_IN_COMPONENT dev - ${test_bin_dir}/Inputs/BlocksRuntime.c) - set_target_properties(BlocksRuntimeStub${VARIANT_SUFFIX} PROPERTIES - ARCHIVE_OUTPUT_DIRECTORY ${test_bin_dir} - LIBRARY_OUTPUT_DIRECTORY ${test_bin_dir} - RUNTIME_OUTPUT_DIRECTORY ${test_bin_dir} - OUTPUT_NAME BlocksRuntime) - list(APPEND test_dependencies BlocksRuntimeStub${VARIANT_SUFFIX}) + _add_swift_library_single( + BlocksRuntimeStub${VARIANT_SUFFIX} + BlocksRuntimeStub + SHARED + DONT_EMBED_BITCODE + NOSWIFTRT + ARCHITECTURE ${ARCH} + SDK ${SDK} + INSTALL_IN_COMPONENT dev + ${test_bin_dir}/Inputs/BlocksRuntime.c) + set_target_properties(BlocksRuntimeStub${VARIANT_SUFFIX} PROPERTIES + ARCHIVE_OUTPUT_DIRECTORY ${test_bin_dir} + LIBRARY_OUTPUT_DIRECTORY ${test_bin_dir} + RUNTIME_OUTPUT_DIRECTORY ${test_bin_dir} + OUTPUT_NAME BlocksRuntime) + list(APPEND test_dependencies BlocksRuntimeStub${VARIANT_SUFFIX}) + endif() if(SWIFT_BUILD_STDLIB AND SWIFT_INCLUDE_TESTS) list(APPEND test_dependencies @@ -257,7 +260,11 @@ _Block_release(void) { }\n") # doesn't need to be build for macCatalyst. list(APPEND test_dependencies "swift-reflection-test${DEFAULT_OSX_VARIANT_SUFFIX}") - else() + + endif() + + if(NOT "${SDK}" STREQUAL "WASI") + # wasm: Avoid to build swift-reflection-test because it uses unsupported linker flags for wasm-ld list(APPEND test_dependencies "swift-reflection-test${VARIANT_SUFFIX}_signed") endif() diff --git a/test/ClangImporter/availability_returns_twice.swift b/test/ClangImporter/availability_returns_twice.swift index ef9ff6ffad251..c91e922fb0e89 100644 --- a/test/ClangImporter/availability_returns_twice.swift +++ b/test/ClangImporter/availability_returns_twice.swift @@ -1,5 +1,6 @@ // RUN: %target-typecheck-verify-swift // UNSUPPORTED: OS=windows-msvc +// UNSUPPORTED: OS=wasi // In Android jmp_buf is int[16], which doesn't convert to &Int (SR-9136) // XFAIL: OS=linux-androideabi // XFAIL: OS=linux-android diff --git a/test/lit.cfg b/test/lit.cfg index b77e33f282e97..d25b688e8aeb8 100644 --- a/test/lit.cfg +++ b/test/lit.cfg @@ -1300,6 +1300,89 @@ elif run_os == 'linux-androideabi' or run_os == 'linux-android': '-L%s' % make_path(test_resource_dir, config.target_sdk_name)]) # The Swift interpreter is not available when targeting Android. config.available_features.discard('swift_interpreter') +elif run_os == 'wasi': + tools_directory = pipes.quote(make_path(config.wasi_sdk_path, "bin")) + + if run_cpu == 'wasm32': + lit_config.note("Testing WebAssembly/WASI " + config.variant_triple) + else: + lit_config.fatal("Unknown environment %s %s" % (run_os, run_cpu)) + + config.target_object_format = "wasm" + config.target_shared_library_prefix = 'lib' + config.target_shared_library_suffix = ".a" + config.target_sdk_name = "wasi" + config.target_runtime = "native" + + # Exclude test cases that use objc-interop because clang doesn't support it + # with WebAssembly binary file yet. + testfiles = glob.glob(os.path.join(config.test_source_root, "**", "*.swift")) + + def use_objc_interop(path): + with open(path) as f: + return '-enable-objc-interop' in f.read() + + import fnmatch + def objc_interop_enabled_filenames(path, filename_pat): + matches = [] + for root, dirnames, filenames in os.walk(path): + for filename in fnmatch.filter(filenames, filename_pat): + filepath = os.path.join(root, filename) + if not use_objc_interop(filepath): continue + matches.append(filename) + return matches + + config.excludes += objc_interop_enabled_filenames(config.test_source_root, "*.swift") + + config.target_swift_autolink_extract = inferSwiftBinary("swift-autolink-extract") + + config.target_build_swift = ' '.join([ + '%s', '-target %s', '-static', '-static-executable', + '-Xcc --sysroot=%s', '-Xclang-linker --sysroot=%s', + '-tools-directory %s', + '-toolchain-stdlib-rpath %s', '%s %s %s %s' + ]) % (config.swiftc, config.variant_triple, + config.variant_sdk, config.variant_sdk, + tools_directory, resource_dir_opt, + mcp_opt, config.swift_test_options, + config.swift_driver_test_options, swift_execution_tests_extra_flags) + config.target_codesign = "echo" + config.target_build_swift_dylib = ( + "%s -parse-as-library -emit-library -o '\\1'" + % (config.target_build_swift)) + config.target_add_rpath = '' + config.target_swift_frontend = ( + '%s -frontend -target %s %s %s %s %s ' + % (config.swift, config.variant_triple, resource_dir_opt, mcp_opt, + config.swift_test_options, config.swift_frontend_test_options)) + subst_target_swift_frontend_mock_sdk = config.target_swift_frontend + subst_target_swift_frontend_mock_sdk_after = "" + config.target_run = 'wasmtime' + if 'interpret' in lit_config.params: + use_interpreter_for_simple_runs() + config.target_sil_opt = ( + '%s -target %s %s %s %s' % + (config.sil_opt, config.variant_triple, resource_dir_opt, mcp_opt, config.sil_test_options)) + config.target_swift_ide_test = ( + '%s -target %s %s %s %s' % + (config.swift_ide_test, config.variant_triple, resource_dir_opt, + mcp_opt, ccp_opt)) + subst_target_swift_ide_test_mock_sdk = config.target_swift_ide_test + subst_target_swift_ide_test_mock_sdk_after = "" + config.target_swiftc_driver = ( + "%s -target %s -toolchain-stdlib-rpath %s %s" % + (config.swiftc, config.variant_triple, resource_dir_opt, mcp_opt)) + config.target_swift_modulewrap = ( + '%s -modulewrap -target %s' % + (config.swiftc, config.variant_triple)) + config.target_swift_emit_pcm = ( + '%s -emit-pcm -target %s' % + (config.swiftc, config.variant_triple)) + config.target_clang = ( + "clang++ -target %s %s -fobjc-runtime=ios-5.0" % + (config.variant_triple, clang_mcp_opt)) + config.target_ld = "ld -L%r" % (make_path(test_resource_dir, config.target_sdk_name)) + else: lit_config.fatal("Don't know how to define target_run and " diff --git a/test/lit.site.cfg.in b/test/lit.site.cfg.in index 69107930747b0..9f86de7721dcc 100644 --- a/test/lit.site.cfg.in +++ b/test/lit.site.cfg.in @@ -41,6 +41,9 @@ config.darwin_xcrun_toolchain = "@SWIFT_DARWIN_XCRUN_TOOLCHAIN@" config.android_ndk_path = "@SWIFT_ANDROID_NDK_PATH@" config.android_ndk_gcc_version = "@SWIFT_ANDROID_NDK_GCC_VERSION@" +# --- WebAssembly --- +config.wasi_sdk_path = "@SWIFT_WASI_SDK_PATH@" + # --- Windows --- msvc_runtime_flags = { 'MultiThreaded': 'MT', diff --git a/test/stdlib/mmap.swift b/test/stdlib/mmap.swift index 6879941e9f7dd..7008923d4c660 100644 --- a/test/stdlib/mmap.swift +++ b/test/stdlib/mmap.swift @@ -1,6 +1,7 @@ // RUN: %target-run-simple-swift %t // REQUIRES: executable_test // UNSUPPORTED: OS=windows-msvc +// UNSUPPORTED: OS=wasi import StdlibUnittest #if os(macOS) || os(iOS) || os(tvOS) || os(watchOS) diff --git a/test/stdlib/simd_diagnostics.swift b/test/stdlib/simd_diagnostics.swift index 2aa1be085bc37..d2230cc2a0970 100644 --- a/test/stdlib/simd_diagnostics.swift +++ b/test/stdlib/simd_diagnostics.swift @@ -1,7 +1,7 @@ // RUN: %target-typecheck-verify-swift // FIXME: No simd module on linux rdar://problem/20795411 -// XFAIL: linux, windows +// XFAIL: linux, windows, wasm import simd diff --git a/tools/driver/autolink_extract_main.cpp b/tools/driver/autolink_extract_main.cpp index f805714c30eb2..dfc70b9941f5d 100644 --- a/tools/driver/autolink_extract_main.cpp +++ b/tools/driver/autolink_extract_main.cpp @@ -32,6 +32,8 @@ #include "llvm/Object/Archive.h" #include "llvm/Object/ObjectFile.h" #include "llvm/Object/ELFObjectFile.h" +#include "llvm/Object/Wasm.h" +#include "llvm/BinaryFormat/Wasm.h" using namespace swift; using namespace llvm::opt; @@ -140,6 +142,31 @@ extractLinkerFlagsFromObjectFile(const llvm::object::ObjectFile *ObjectFile, return false; } +/// Look inside the object file 'WasmObjectFile' and append any linker flags found in +/// its ".swift1_autolink_entries" section to 'LinkerFlags'. +/// Return 'true' if there was an error, and 'false' otherwise. +static bool +extractLinkerFlagsFromObjectFile(const llvm::object::WasmObjectFile *ObjectFile, + std::vector &LinkerFlags, + CompilerInstance &Instance) { + + // Search for the data segment we hold autolink entries in + for (const llvm::object::WasmSegment &Segment : ObjectFile->dataSegments()) { + if (Segment.Data.Name == ".swift1_autolink_entries") { + + StringRef SegmentData = llvm::toStringRef(Segment.Data.Content); + // entries are null-terminated, so extract them and push them into + // the set. + llvm::SmallVector SplitFlags; + SegmentData.split(SplitFlags, llvm::StringRef("\0", 1), -1, + /*KeepEmpty=*/false); + for (const auto &Flag : SplitFlags) + LinkerFlags.push_back(Flag); + } + } + return false; +} + /// Look inside the binary 'Bin' and append any linker flags found in its /// ".swift1_autolink_entries" section to 'LinkerFlags'. If 'Bin' is an archive, /// recursively look inside all children within the archive. Return 'true' if @@ -150,6 +177,8 @@ static bool extractLinkerFlags(const llvm::object::Binary *Bin, std::vector &LinkerFlags) { if (auto *ObjectFile = llvm::dyn_cast(Bin)) { return extractLinkerFlagsFromObjectFile(ObjectFile, LinkerFlags, Instance); + } else if (auto *ObjectFile = llvm::dyn_cast(Bin)) { + return extractLinkerFlagsFromObjectFile(ObjectFile, LinkerFlags, Instance); } else if (auto *Archive = llvm::dyn_cast(Bin)) { llvm::Error Error = llvm::Error::success(); for (const auto &Child : Archive->children(Error)) { diff --git a/tools/sil-func-extractor/SILFunctionExtractor.cpp b/tools/sil-func-extractor/SILFunctionExtractor.cpp index 33d0082c8b352..3b9cd3d1c121f 100644 --- a/tools/sil-func-extractor/SILFunctionExtractor.cpp +++ b/tools/sil-func-extractor/SILFunctionExtractor.cpp @@ -249,6 +249,8 @@ int main(int argc, char **argv) { Invocation.getLangOptions().DisableAvailabilityChecking = true; Invocation.getLangOptions().EnableAccessControl = false; Invocation.getLangOptions().EnableObjCAttrRequiresFoundation = false; + if (Invocation.getLangOptions().Target.isOSBinFormatWasm()) + Invocation.getLangOptions().EnableObjCInterop = false; serialization::ExtendedValidationInfo extendedInfo; llvm::ErrorOr> FileBufOrErr = diff --git a/utils/build-script b/utils/build-script index 120f75a5cd928..7271993e9d665 100755 --- a/utils/build-script +++ b/utils/build-script @@ -122,6 +122,20 @@ class BuildScriptInvocation(object): "--android-icu-i18n-include, and --android-icu-data " "must be specified") + if args.wasm: + if args.wasi_sdk is None or \ + args.wasi_icu_uc is None or \ + args.wasi_icu_uc_include is None or \ + args.wasi_icu_i18n is None or \ + args.wasi_icu_i18n_include is None or \ + args.wasi_icu_data is None: + diagnostics.fatal( + "when building for WebAssembly, --wasi-sdk, " + "--wasi-icu-uc, " + "--wasi-icu-uc-include, --wasi-icu-i18n, " + "--wasi-icu-i18n-include, and --wasi-icu-data " + "must be specified") + targets_needing_toolchain = [ 'build_indexstoredb', 'build_sourcekitlsp', @@ -216,6 +230,9 @@ class BuildScriptInvocation(object): elif args.android_arch == "aarch64": args.stdlib_deployment_targets.append( StdlibDeploymentTarget.Android.aarch64.name) + if args.wasm: + args.stdlib_deployment_targets.append( + StdlibDeploymentTarget.WASI.wasm32.name) # Infer platform flags from manually-specified configure targets. # This doesn't apply to Darwin platforms, as they are @@ -501,6 +518,8 @@ class BuildScriptInvocation(object): impl_args += ["--skip-build-watchos-simulator"] if not args.build_android: impl_args += ["--skip-build-android"] + if not args.build_wasm: + impl_args += ["--skip-build-wasm"] if not args.build_clang_tools_extra: impl_args += ["--skip-build-clang-tools-extra"] @@ -541,6 +560,10 @@ class BuildScriptInvocation(object): impl_args += ["--skip-test-android"] if not args.test_android_host: impl_args += ["--skip-test-android-host"] + if not args.test_wasm: + impl_args += ["--skip-test-wasm"] + if not args.test_wasm_host: + impl_args += ["--skip-test-wasm-host"] if args.build_runtime_with_host_compiler: impl_args += ["--build-runtime-with-host-compiler"] if args.validation_test: @@ -581,6 +604,16 @@ class BuildScriptInvocation(object): args.android_deploy_device_path, ] + if args.wasm: + impl_args += [ + "--wasi-sdk", args.wasi_sdk, + "--wasi-icu-uc", args.wasi_icu_uc, + "--wasi-icu-uc-include", args.wasi_icu_uc_include, + "--wasi-icu-i18n", args.wasi_icu_i18n, + "--wasi-icu-i18n-include", args.wasi_icu_i18n_include, + "--wasi-icu-data", args.wasi_icu_data, + ] + if platform.system() == 'Darwin': impl_args += [ "--toolchain-prefix", diff --git a/utils/build-script-impl b/utils/build-script-impl index 49239434d12e0..6fe416c60b9ab 100755 --- a/utils/build-script-impl +++ b/utils/build-script-impl @@ -114,6 +114,14 @@ KNOWN_SETTINGS=( darwin-toolchain-version "" "Version for xctoolchain info plist and installer pkg" darwin-xcrun-toolchain "default" "the name of the toolchain to use on Darwin" + ## WebAssembly/WASI Options + wasi-sdk "" "An absolute path to the WASI SDK that will be used as a libc implementation for Wasm builds" + wasi-icu-uc "" "Path to libicuuc.so" + wasi-icu-uc-include "" "Path to a directory containing headers for libicuuc" + wasi-icu-i18n "" "Path to libicui18n.so" + wasi-icu-i18n-include "" "Path to a directory containing headers libicui18n" + wasi-icu-data "" "Path to libicudata.so" + ## Build Types for Components swift-stdlib-build-type "Debug" "the CMake build variant for Swift" @@ -133,6 +141,7 @@ KNOWN_SETTINGS=( skip-build-osx "" "set to skip building Swift stdlibs for OS X" skip-build-tvos-device "" "set to skip building Swift stdlibs for tvOS devices (i.e. build simulators only)" skip-build-tvos-simulator "" "set to skip building Swift stdlibs for tvOS simulators (i.e. build devices only)" + skip-build-wasm "" "set to skip building Swift stdlibs for WebAssembly" skip-build-watchos-device "" "set to skip building Swift stdlibs for Apple watchOS devices (i.e. build simulators only)" skip-build-watchos-simulator "" "set to skip building Swift stdlibs for Apple watchOS simulators (i.e. build devices only)" @@ -150,6 +159,8 @@ KNOWN_SETTINGS=( skip-test-osx "" "set to skip testing Swift stdlibs for OS X" skip-test-tvos-host "" "set to skip testing the host parts of the tvOS toolchain" skip-test-tvos-simulator "" "set to skip testing Swift stdlibs for tvOS simulators (i.e. test devices only)" + skip-test-wasm "" "set to skip testing Swift stdlibs for WebAssembly" + skip-test-wasm-host "" "set to skip testing the host parts of the WebAssembly toolchain" skip-test-watchos-host "" "set to skip testing the host parts of the watchOS toolchain" skip-test-watchos-simulator "" "set to skip testing Swift stdlibs for Apple watchOS simulators (i.e. test devices only)" skip-test-benchmarks "" "set to skip running Swift Benchmark Suite" @@ -423,7 +434,8 @@ function verify_host_is_supported() { | watchsimulator-i386 \ | watchos-armv7k \ | android-armv7 \ - | android-aarch64) + | android-aarch64 \ + | wasi-wasm32) ;; *) echo "Unknown host tools target: ${host}" @@ -1188,6 +1200,9 @@ function common_cross_c_flags() { watchos-*) echo -n " -arch ${arch} -mwatchos-version-min=${DARWIN_DEPLOYMENT_VERSION_WATCHOS}" ;; + wasi-wasm32) + echo -n " -arch wasm32" + ;; esac local build_type=$2 @@ -1571,6 +1586,18 @@ for host in "${ALL_HOSTS[@]}"; do ) fi + if [[ ! "${SKIP_BUILD_WASM}" ]]; then + cmake_options=( + "${cmake_options[@]}" + -DSWIFT_WASI_SDK_PATH:STRING="${WASI_SDK}" + -DSWIFT_WASI_wasm32_ICU_UC:STRING="${WASI_ICU_UC}" + -DSWIFT_WASI_wasm32_ICU_UC_INCLUDE:STRING="${WASI_ICU_UC_INCLUDE}" + -DSWIFT_WASI_wasm32_ICU_I18N:STRING="${WASI_ICU_I18N}" + -DSWIFT_WASI_wasm32_ICU_I18N_INCLUDE:STRING="${WASI_ICU_I18N_INCLUDE}" + -DSWIFT_WASI_wasm32_ICU_DATA:STRING="${WASI_ICU_DATA}" + ) + fi + if [[ "${DARWIN_OVERLAY_TARGET}" != "" ]]; then # Split LOCAL_HOST into a pair ``arch-sdk`` # Example LOCAL_HOST: macosx-x86_64 diff --git a/utils/build_swift/build_swift/driver_arguments.py b/utils/build_swift/build_swift/driver_arguments.py index 108ea4793315a..47dcf1f8f5eed 100644 --- a/utils/build_swift/build_swift/driver_arguments.py +++ b/utils/build_swift/build_swift/driver_arguments.py @@ -141,6 +141,7 @@ def _apply_default_arguments(args): args.build_tvos = False args.build_watchos = False args.build_android = False + args.build_wasm = False args.build_benchmarks = False args.build_external_benchmarks = False args.build_lldb = False @@ -170,6 +171,9 @@ def _apply_default_arguments(args): if not args.android or not args.build_android: args.build_android = False + if not args.wasm or not args.build_wasm: + args.build_wasm = False + # --test-paths implies --test and/or --validation-test # depending on what directories/files have been specified. if args.test_paths: @@ -206,6 +210,7 @@ def _apply_default_arguments(args): args.test_tvos = False args.test_watchos = False args.test_android = False + args.test_wasm = False args.test_swiftpm = False args.test_swiftsyntax = False args.test_indexstoredb = False @@ -252,11 +257,19 @@ def _apply_default_arguments(args): if not args.test_android: args.test_android_host = False + if not args.build_wasm: + args.test_wasm = False + args.test_wasm_host = False + + if not args.test_android: + args.test_android_host = False + if not args.host_test: args.test_ios_host = False args.test_tvos_host = False args.test_watchos_host = False args.test_android_host = False + args.test_wasm_host = False def create_argument_parser(): @@ -345,6 +358,9 @@ def create_argument_parser(): option('--android', toggle_true, help='also build for Android') + option('--wasm', toggle_true, + help='also build for WebAssembly') + option('--swift-analyze-code-coverage', store, choices=['false', 'not-merged', 'merged'], # so CMake can see the inert mode as a false value @@ -933,6 +949,9 @@ def create_argument_parser(): option('--skip-build-android', toggle_false('build_android'), help='skip building Swift stdlibs for Android') + option('--skip-build-wasm', toggle_false('build_wasm'), + help='skip building Swift stdlibs for WebAssembly') + option('--skip-build-benchmarks', toggle_false('build_benchmarks'), help='skip building Swift Benchmark Suite') @@ -989,6 +1008,14 @@ def create_argument_parser(): help='skip testing Android device targets on the host machine (the ' 'phone itself)') + option('--skip-test-wasm', + toggle_false('test_wasm'), + help='skip testing all WebAssembly targets.') + option('--skip-test-wasm-host', + toggle_false('test_wasm_host'), + help='skip testing WebAssembly device targets on the host machine (the ' + 'WebAssembly runtime)') + option('--skip-test-swiftpm', toggle_false('test_swiftpm'), help='skip testing swiftpm') option('--skip-test-swiftsyntax', toggle_false('test_swiftsyntax'), @@ -1057,6 +1084,23 @@ def create_argument_parser(): 'Currently only armv7 and aarch64 are supported. ' '%(default)s is the default.') + in_group('Build settings for Android') + + option('--wasi-sdk', store_path, + help='An absolute path to WASI SDK that will be used as a libc ' + 'implementation for Wasm builds') + + option('--wasi-icu-uc', store_path, + help='Path to libicuuc.so') + option('--wasi-icu-uc-include', store_path, + help='Path to a directory containing headers for libicuuc') + option('--wasi-icu-i18n', store_path, + help='Path to libicui18n.so') + option('--wasi-icu-i18n-include', store_path, + help='Path to a directory containing headers libicui18n') + option('--wasi-icu-data', store_path, + help='Path to libicudata.so') + # ------------------------------------------------------------------------- in_group('Experimental language features') diff --git a/utils/swift_build_support/swift_build_support/host_specific_configuration.py b/utils/swift_build_support/swift_build_support/host_specific_configuration.py index ecdb437113321..085957cda2828 100644 --- a/utils/swift_build_support/swift_build_support/host_specific_configuration.py +++ b/utils/swift_build_support/swift_build_support/host_specific_configuration.py @@ -201,6 +201,8 @@ def __platforms_to_skip_build(self, args): StdlibDeploymentTarget.AppleWatchSimulator) if not args.build_android: platforms_to_skip_build.add(StdlibDeploymentTarget.Android) + if not args.build_wasm: + platforms_to_skip_build.add(StdlibDeploymentTarget.WASI) return platforms_to_skip_build def __platforms_to_skip_test(self, args): @@ -240,6 +242,8 @@ def __platforms_to_skip_test(self, args): StdlibDeploymentTarget.AppleWatchSimulator) if not args.test_android: platforms_to_skip_test.add(StdlibDeploymentTarget.Android) + if not args.test_wasm: + platforms_to_skip_test.add(StdlibDeploymentTarget.WASI) return platforms_to_skip_test @@ -260,4 +264,6 @@ def __platforms_to_skip_test_host(self, args): platforms_to_skip_test_host.add(StdlibDeploymentTarget.AppleTV) if not args.test_watchos_host: platforms_to_skip_test_host.add(StdlibDeploymentTarget.AppleWatch) + if not args.test_wasm_host: + platforms_to_skip_test_host.add(StdlibDeploymentTarget.WASI) return platforms_to_skip_test_host diff --git a/utils/swift_build_support/swift_build_support/targets.py b/utils/swift_build_support/swift_build_support/targets.py index 45bb45ca9916a..6a2f8f55c5013 100644 --- a/utils/swift_build_support/swift_build_support/targets.py +++ b/utils/swift_build_support/swift_build_support/targets.py @@ -158,6 +158,8 @@ class StdlibDeploymentTarget(object): Haiku = Platform("haiku", archs=["x86_64"]) + WASI = Platform("wasi", archs=["wasm32"]) + # The list of known platforms. known_platforms = [ OSX, @@ -169,7 +171,8 @@ class StdlibDeploymentTarget(object): Cygwin, Android, Windows, - Haiku] + Haiku, + WASI] # Cache of targets by name. _targets_by_name = dict((target.name, target) @@ -233,6 +236,10 @@ def host_target(): if machine == 'x86_64': return StdlibDeploymentTarget.Haiku.x86_64 + elif system == 'WASI': + if machine == 'wasm32': + return StdlibDeploymentTarget.WASI.wasm32 + raise NotImplementedError('System "%s" with architecture "%s" is not ' 'supported' % (system, machine)) diff --git a/utils/update_checkout/update-checkout-config.json b/utils/update_checkout/update-checkout-config.json index 969612f899647..9c10c92c79b34 100644 --- a/utils/update_checkout/update-checkout-config.json +++ b/utils/update_checkout/update-checkout-config.json @@ -3,7 +3,7 @@ "https-clone-pattern": "https://github.com/%s.git", "repos" : { "swift": { - "remote": { "id": "apple/swift" } }, + "remote": { "id": "swiftwasm/swift" } }, "cmark": { "remote": { "id": "apple/swift-cmark" } }, "llbuild": { @@ -29,8 +29,7 @@ "ninja": { "remote": { "id": "ninja-build/ninja" } }, "icu": { - "remote": { "id": "unicode-org/icu" }, - "platforms": [ "Linux" ] + "remote": { "id": "unicode-org/icu" } }, "cmake": { "remote": { "id": "KitWare/CMake" }, @@ -43,11 +42,34 @@ "swift-format": { "remote": { "id": "apple/swift-format" } }, "llvm-project": { - "remote": { "id": "apple/llvm-project" } } + "remote": { "id": "swiftwasm/llvm-project" } } }, - "default-branch-scheme": "master", + "default-branch-scheme": "wasm", "branch-schemes": { - "master": { + "wasm": { + "aliases": ["wasm"], + "repos": { + "llvm-project": "swiftwasm", + "swift": "swiftwasm", + "cmark": "master", + "llbuild": "master", + "swiftpm": "master", + "swift-syntax": "master", + "swift-stress-tester": "master", + "swift-corelibs-xctest": "master", + "swift-corelibs-foundation": "master", + "swift-corelibs-libdispatch": "master", + "swift-integration-tests": "master", + "swift-xcode-playground-support": "master", + "ninja": "release", + "icu": "release-61-1", + "cmake": "v3.15.1", + "indexstore-db": "master", + "sourcekit-lsp": "master", + "swift-format": "master" + } + }, + "master": { "aliases": ["master", "swift/master"], "repos": { "llvm-project": "swift/master", diff --git a/utils/webassembly/.gitignore b/utils/webassembly/.gitignore new file mode 100644 index 0000000000000..411f44532e7bc --- /dev/null +++ b/utils/webassembly/.gitignore @@ -0,0 +1,5 @@ +compiler +swiftwasm-sdk +prebuilt +output +tmpdir diff --git a/utils/webassembly/README.md b/utils/webassembly/README.md new file mode 100644 index 0000000000000..106f4fc35d84d --- /dev/null +++ b/utils/webassembly/README.md @@ -0,0 +1,23 @@ +Creates packages containing everything needed to build WebAssembly programs with Swift. + +# Building + +``` +./download-prebuilts.sh +./download-installable-prebuilts.sh +./build-packages.sh +``` + +# Contents of package + +- Swift toolchain from [swiftwasm-sdk](https://github.com/swiftwasm/swiftwasm-sdk) +- WASI modified sysroot from [wasi-sdk](https://github.com/swiftwasm/wasi-sdk) +- libicu from [icu4c-wasi](https://github.com/swiftwasm/icu4c-wasi) +- linking helpers from [swiftwasm-wasi-stubs](https://github.com/swiftwasm/swiftwasm-wasi-stubs) +- wasi-ld, either from wasi-sdk (on Linux) or upstream LLVM 9.0 (on Mac) +- build script for compiling a Swift file to a .wasm +- a Getting Started guide + +# Notes + +This shares a lot with the [swiftwasm-compile-service](https://github.com/swiftwasm/swiftwasm-compile-service). diff --git a/utils/webassembly/build-linux-package.sh b/utils/webassembly/build-linux-package.sh new file mode 100755 index 0000000000000..685d5c247a18e --- /dev/null +++ b/utils/webassembly/build-linux-package.sh @@ -0,0 +1,9 @@ +#!/bin/bash + +echo "Unpacking Linux prebuilts" +mkdir -p output +cd linux +./unpack-prebuilts.sh +echo "Compressing" +tar cJf ../output/swiftwasm-sdk-linux.tar.xz swiftwasm-sdk +cd .. diff --git a/utils/webassembly/build-linux.sh b/utils/webassembly/build-linux.sh new file mode 100755 index 0000000000000..7aa8b90e26cfe --- /dev/null +++ b/utils/webassembly/build-linux.sh @@ -0,0 +1,35 @@ +#/bin/bash + +SOURCE_PATH="$( cd "$(dirname $0)/../../.." && pwd )" +SWIFT_PATH=$SOURCE_PATH/swift + +$SWIFT_PATH/utils/build-script --wasm \ + --skip-build-benchmarks \ + --extra-cmake-options=" \ + -DSWIFT_PRIMARY_VARIANT_SDK:STRING=WASI \ + -DSWIFT_PRIMARY_VARIANT_ARCH:STRING=wasm32 \ + -DSWIFT_SDKS='WASI;LINUX' \ + -DSWIFT_BUILD_SOURCEKIT=FALSE \ + -DSWIFT_ENABLE_SOURCEKIT_TESTS=FALSE \ + -DSWIFT_BUILD_SYNTAXPARSERLIB=FALSE \ + -DCMAKE_AR='$SOURCE_PATH/wasi-sdk/bin/llvm-ar' \ + -DCMAKE_RANLIB='$SOURCE_PATH/wasi-sdk/bin/llvm-ranlib' \ + " \ + --build-stdlib-deployment-targets "wasi-wasm32" \ + --build-swift-dynamic-sdk-overlay false \ + --build-swift-dynamic-stdlib false \ + --build-swift-static-sdk-overlay \ + --build-swift-static-stdlib \ + --install-destdir="$SOURCE_PATH/install" \ + --install-prefix="/opt/swiftwasm-sdk" \ + --install-swift \ + --installable-package="$SOURCE_PATH/swiftwasm-linux.tar.gz" \ + --llvm-targets-to-build "X86;WebAssembly" \ + --stdlib-deployment-targets "wasi-wasm32" \ + --wasi-icu-data "$SOURCE_PATH/icu_out/lib/libicudata.a" \ + --wasi-icu-i18n "$SOURCE_PATH/icu_out/lib/libicui18n.a" \ + --wasi-icu-i18n-include "$SOURCE_PATH/icu_out/include" \ + --wasi-icu-uc "$SOURCE_PATH/icu_out/lib/libicuuc.a" \ + --wasi-icu-uc-include "$SOURCE_PATH/icu_out/include" \ + --wasi-sdk "$SOURCE_PATH/wasi-sdk" \ + "$@" diff --git a/utils/webassembly/build-mac-package.sh b/utils/webassembly/build-mac-package.sh new file mode 100755 index 0000000000000..cd3c2602e8b5d --- /dev/null +++ b/utils/webassembly/build-mac-package.sh @@ -0,0 +1,9 @@ +#!/bin/bash + +echo "Unpacking macOS prebuilts" +mkdir -p output +cd macos +./unpack-prebuilts.sh +echo "Compressing macOS package" +tar cJf ../output/swiftwasm-sdk-macos.tar.xz swiftwasm-sdk +cd .. diff --git a/utils/webassembly/build-mac.sh b/utils/webassembly/build-mac.sh new file mode 100755 index 0000000000000..1fef9d76ac8d6 --- /dev/null +++ b/utils/webassembly/build-mac.sh @@ -0,0 +1,35 @@ +#/bin/bash + +SOURCE_PATH="$( cd "$(dirname $0)/../../.." && pwd )" +SWIFT_PATH=$SOURCE_PATH/swift + +$SWIFT_PATH/utils/build-script --wasm \ + --skip-build-benchmarks \ + --extra-cmake-options=" \ + -DSWIFT_PRIMARY_VARIANT_SDK:STRING=WASI \ + -DSWIFT_PRIMARY_VARIANT_ARCH:STRING=wasm32 \ + -DSWIFT_OSX_x86_64_ICU_STATICLIB=TRUE \ + -DSWIFT_BUILD_SOURCEKIT=FALSE \ + -DSWIFT_ENABLE_SOURCEKIT_TESTS=FALSE \ + -DSWIFT_BUILD_SYNTAXPARSERLIB=FALSE \ + -DCMAKE_AR='/usr/local/opt/llvm/bin/llvm-ar' \ + -DCMAKE_RANLIB='/usr/local/opt/llvm/bin/llvm-ranlib' \ + " \ + --build-stdlib-deployment-targets "wasi-wasm32" \ + --build-swift-dynamic-sdk-overlay false \ + --build-swift-dynamic-stdlib false \ + --build-swift-static-sdk-overlay \ + --build-swift-static-stdlib \ + --llvm-targets-to-build "X86;WebAssembly" \ + --stdlib-deployment-targets "wasi-wasm32" \ + --wasi-icu-data "$SOURCE_PATH/icu_out/lib/libicudata.a" \ + --wasi-icu-i18n "$SOURCE_PATH/icu_out/lib/libicui18n.a" \ + --wasi-icu-i18n-include "$SOURCE_PATH/icu_out/include" \ + --wasi-icu-uc "$SOURCE_PATH/icu_out/lib/libicuuc.a" \ + --wasi-icu-uc-include "$SOURCE_PATH/icu_out/include" \ + --wasi-sdk "$SOURCE_PATH/wasi-sdk" \ + --install-swift \ + --install-prefix="/opt/swiftwasm-sdk" \ + --install-destdir="$SOURCE_PATH/install" \ + --installable-package="$SOURCE_PATH/swiftwasm-macos.tar.gz" \ + "$@" diff --git a/utils/webassembly/build-packages.sh b/utils/webassembly/build-packages.sh new file mode 100755 index 0000000000000..e83fc38beb5d6 --- /dev/null +++ b/utils/webassembly/build-packages.sh @@ -0,0 +1,5 @@ +#!/bin/bash +set -e +rm -rf output || true +./build-linux-package.sh +./build-mac-package.sh diff --git a/utils/webassembly/ci-linux.sh b/utils/webassembly/ci-linux.sh new file mode 100755 index 0000000000000..9a00e5d4cc821 --- /dev/null +++ b/utils/webassembly/ci-linux.sh @@ -0,0 +1,53 @@ +#/bin/bash + +set -ex + +sudo apt update +sudo apt install \ + git ninja-build clang python python-six \ + uuid-dev libicu-dev icu-devtools libbsd-dev \ + libedit-dev libxml2-dev libsqlite3-dev swig \ + libpython-dev libncurses5-dev pkg-config \ + libblocksruntime-dev libcurl4-openssl-dev \ + systemtap-sdt-dev tzdata rsync wget llvm + +SOURCE_PATH="$( cd "$(dirname $0)/../../.." && pwd )" +SWIFT_PATH=$SOURCE_PATH/swift +BUILD_SCRIPT=$SWIFT_PATH/utils/webassembly/build-linux.sh +cd $SWIFT_PATH + +./utils/update-checkout --clone --scheme wasm --skip-repository swift + +# Install wasmtime + +sudo mkdir /opt/wasmtime && cd /opt/wasmtime +wget -O - "https://github.com/bytecodealliance/wasmtime/releases/download/v0.8.0/wasmtime-v0.8.0-x86_64-linux.tar.xz" | \ + sudo tar Jx --strip-components 1 +sudo ln -sf /opt/wasmtime/* /usr/local/bin + +cd $SOURCE_PATH + +wget -O install_cmake.sh "https://github.com/Kitware/CMake/releases/download/v3.15.3/cmake-3.15.3-Linux-x86_64.sh" +chmod +x install_cmake.sh +sudo mkdir -p /opt/cmake +sudo ./install_cmake.sh --skip-license --prefix=/opt/cmake +sudo ln -sf /opt/cmake/bin/* /usr/local/bin +cmake --version + +wget -O dist-wasi-sdk.tgz https://github.com/swiftwasm/wasi-sdk/suites/370986556/artifacts/809002 +unzip dist-wasi-sdk.tgz -d . +WASI_SDK_TAR_PATH=$(find . -type f -name "wasi-sdk-*") +WASI_SDK_FULL_NAME=$(basename $WASI_SDK_TAR_PATH -linux.tar.gz) +tar xfz $WASI_SDK_TAR_PATH +mv $WASI_SDK_FULL_NAME ./wasi-sdk + +# Link wasm32-wasi-unknown to wasm32-wasi because clang finds crt1.o from sysroot +# with os and environment name `getMultiarchTriple`. +ln -s wasm32-wasi wasi-sdk/share/wasi-sysroot/lib/wasm32-wasi-unknown + +wget -O icu.tar.xz "https://github.com/swiftwasm/icu4c-wasi/releases/download/20190421.3/icu4c-wasi.tar.xz" +tar xf icu.tar.xz + +$BUILD_SCRIPT --release --debug-swift-stdlib --verbose +# Run test but ignore failure temporarily +$BUILD_SCRIPT --release --debug-swift-stdlib --verbose -t || true diff --git a/utils/webassembly/ci-mac.sh b/utils/webassembly/ci-mac.sh new file mode 100755 index 0000000000000..e2c6e3bb49589 --- /dev/null +++ b/utils/webassembly/ci-mac.sh @@ -0,0 +1,46 @@ +#/bin/bash + +set -ex + +brew install cmake ninja llvm python@2 + +# Install six for python3 migration +pip2 install six + +SOURCE_PATH="$( cd "$(dirname $0)/../../.." && pwd )" +SWIFT_PATH=$SOURCE_PATH/swift +BUILD_SCRIPT=$SWIFT_PATH/utils/webassembly/build-mac.sh +cd $SWIFT_PATH + +./utils/update-checkout --clone --scheme wasm --skip-repository swift + +# Install wasmtime + +sudo mkdir /opt/wasmtime && cd /opt/wasmtime +wget -O - "https://github.com/bytecodealliance/wasmtime/releases/download/v0.8.0/wasmtime-v0.8.0-x86_64-macos.tar.xz" | \ + sudo tar Jx --strip-components 1 +sudo ln -sf /opt/wasmtime/* /usr/local/bin + +cd $SOURCE_PATH + +wget -O dist-wasi-sdk.tgz https://github.com/swiftwasm/wasi-sdk/suites/370986556/artifacts/809001 +unzip dist-wasi-sdk.tgz -d . +WASI_SDK_TAR_PATH=$(find . -type f -name "wasi-sdk-*") +WASI_SDK_FULL_NAME=$(basename $WASI_SDK_TAR_PATH -macos.tar.gz) +tar xfz $WASI_SDK_TAR_PATH +mv $WASI_SDK_FULL_NAME ./wasi-sdk + +# Link sysroot/usr/include to sysroot/include because Darwin sysroot doesn't +# find header files in sysroot/include but sysroot/usr/include +mkdir wasi-sdk/share/wasi-sysroot/usr/ +ln -s ../include wasi-sdk/share/wasi-sysroot/usr/include +# Link wasm32-wasi-unknown to wasm32-wasi because clang finds crt1.o from sysroot +# with os and environment name `getMultiarchTriple`. +ln -s wasm32-wasi wasi-sdk/share/wasi-sysroot/lib/wasm32-wasi-unknown + +wget -O icu.tar.xz "https://github.com/swiftwasm/icu4c-wasi/releases/download/20190421.3/icu4c-wasi.tar.xz" +tar xf icu.tar.xz + +$BUILD_SCRIPT --release --debug-swift-stdlib --verbose +# Run test but ignore failure temporarily +$BUILD_SCRIPT --release --debug-swift-stdlib --verbose -t || true diff --git a/utils/webassembly/copy-shared-files.sh b/utils/webassembly/copy-shared-files.sh new file mode 100755 index 0000000000000..daaf0c5d30f82 --- /dev/null +++ b/utils/webassembly/copy-shared-files.sh @@ -0,0 +1,4 @@ +#!/bin/bash +set -e +cp -r ../sdkroot/* compiler/ +cp ../linux/compiler/opt/swiftwasm-sdk/lib/swift/wasi/wasm32/glibc.modulemap compiler/extra_utils diff --git a/utils/webassembly/download-installable-prebuilts.sh b/utils/webassembly/download-installable-prebuilts.sh new file mode 100755 index 0000000000000..c407580547fc4 --- /dev/null +++ b/utils/webassembly/download-installable-prebuilts.sh @@ -0,0 +1,7 @@ +#!/bin/bash +set -e +mkdir -p prebuilt +cd prebuilt +wget -O swiftwasm-linux.tar.gz https://github.com/swiftwasm/swiftwasm-sdk/releases/download/20191112.1.linux/swiftwasm.tar.gz +# Mac specific +wget -O swiftwasm-macos.tar.gz https://github.com/swiftwasm/swiftwasm-sdk/releases/download/20191112.1.mac/swiftwasm-mac.tar.gz diff --git a/utils/webassembly/download-prebuilts.sh b/utils/webassembly/download-prebuilts.sh new file mode 100755 index 0000000000000..5ee1c8b3bf756 --- /dev/null +++ b/utils/webassembly/download-prebuilts.sh @@ -0,0 +1,8 @@ +#!/bin/bash +set -e +mkdir -p prebuilt +cd prebuilt +wget https://github.com/swiftwasm/wasi-sdk/releases/download/20191022.1/wasi-sdk-4.39g3025a5f47c04-linux.tar.gz +wget https://github.com/swiftwasm/icu4c-wasi/releases/download/20190421.3/icu4c-wasi.tar.xz +# Mac specific +wget http://releases.llvm.org/9.0.0/clang+llvm-9.0.0-x86_64-darwin-apple.tar.xz diff --git a/utils/webassembly/linux/unpack-prebuilts.sh b/utils/webassembly/linux/unpack-prebuilts.sh new file mode 100755 index 0000000000000..a5d5f669aa39f --- /dev/null +++ b/utils/webassembly/linux/unpack-prebuilts.sh @@ -0,0 +1,20 @@ +#!/bin/bash +set -e +rm -rf swiftwasm-sdk compiler +mkdir swiftwasm-sdk +ln -s swiftwasm-sdk compiler +cd compiler +untar="../../prebuilt/wasi-sdk-"*"-linux.tar.gz +../../prebuilt/swiftwasm-linux.tar.gz +../../prebuilt/icu4c-wasi.tar.xz" +for i in $untar +do + echo $i + tar xf $i +done +cd .. +mv "compiler/wasi-sdk-"* "compiler/wasi-sdk" +mv compiler/wasi-sdk/share/wasi-sysroot compiler/wasi-sdk/share/sysroot +../remove-swift-extra-files.sh || true +../remove-wasi-extra-files.sh || true +../copy-shared-files.sh || true diff --git a/utils/webassembly/macos/unpack-prebuilts.sh b/utils/webassembly/macos/unpack-prebuilts.sh new file mode 100755 index 0000000000000..199552346db2e --- /dev/null +++ b/utils/webassembly/macos/unpack-prebuilts.sh @@ -0,0 +1,30 @@ +#!/bin/bash +set -e +rm -rf swiftwasm-sdk compiler tmpdir +mkdir swiftwasm-sdk tmpdir +ln -s swiftwasm-sdk compiler +cd compiler +untar="../../prebuilt/wasi-sdk-"*"-linux.tar.gz +../../prebuilt/swiftwasm-macos.tar.gz +../../prebuilt/icu4c-wasi.tar.xz" +for i in $untar +do + echo $i + tar xf $i +done +# Mac: unpack the Linux one and copy stdlibs +cd .. +cd tmpdir +tar xf ../../prebuilt/clang+llvm-*-x86_64-darwin-apple.tar.xz +tar xf ../../prebuilt/swiftwasm-linux.tar.gz +cd .. +mv "compiler/wasi-sdk-"* "compiler/wasi-sdk" +mv compiler/wasi-sdk/share/wasi-sysroot compiler/wasi-sdk/share/sysroot +../remove-swift-extra-files.sh || true +rm -r compiler/wasi-sdk/bin +mkdir compiler/wasi-sdk/bin +cp tmpdir/clang+llvm-*-x86_64-darwin-apple/bin/wasm-ld compiler/wasi-sdk/bin +cp -a tmpdir/opt/swiftwasm-sdk/lib/swift/wasi compiler/opt/swiftwasm-sdk/lib/swift/wasi +cp -a tmpdir/opt/swiftwasm-sdk/lib/swift_static compiler/opt/swiftwasm-sdk/lib/swift_static +# ok, finally copy over the shared files +../copy-shared-files.sh || true diff --git a/utils/webassembly/remove-swift-extra-files.sh b/utils/webassembly/remove-swift-extra-files.sh new file mode 100755 index 0000000000000..2e4e2d541a45f --- /dev/null +++ b/utils/webassembly/remove-swift-extra-files.sh @@ -0,0 +1,26 @@ +#!/bin/bash +basepath="compiler/opt/swiftwasm-sdk" +filestoremove="bin/sil-* +bin/lldb* +bin/sourcekitd-* +bin/swift-api-digester +bin/swift-autolink-extract +bin/swift-demangle +bin/swift-demangle-yamldump +bin/swift-format +bin/swift-llvm-opt +bin/swift-refactor +bin/swift-reflection-dump +bin/swift-*-test +lib/libsourcekitdInProc.so +lib/swift/clang/lib/linux/* +lib/swift_static/linux/* +lib/swift/linux/x86_64/* +lib/swift/linux/*" +for i in $filestoremove +do + echo $basepath/$i + rm $basepath/$i +done +# Mac only +rm -r $basepath/lib/swift/macosx $basepath/lib/sourcekitd.framework diff --git a/utils/webassembly/remove-wasi-extra-files.sh b/utils/webassembly/remove-wasi-extra-files.sh new file mode 100755 index 0000000000000..19ac34009874f --- /dev/null +++ b/utils/webassembly/remove-wasi-extra-files.sh @@ -0,0 +1,10 @@ +#!/bin/bash +basepath="compiler/wasi-sdk" +filestoremove="bin/clang* +bin/llvm* +bin/llc" +for i in $filestoremove +do + echo $basepath/$i + rm $basepath/$i +done diff --git a/utils/webassembly/sdkroot/README.md b/utils/webassembly/sdkroot/README.md new file mode 100644 index 0000000000000..db8048d2a504d --- /dev/null +++ b/utils/webassembly/sdkroot/README.md @@ -0,0 +1,87 @@ +SwiftWasm: Getting started +========================== + +Thank you for trying SwiftWasm! Here's how to get started. + +Please visit our website at https://swiftwasm.org for the latest updates. + + +Install dependencies +==================== + +Before running SwiftWasm, you will need to install some dependencies. + +Ubuntu: + +``` +sudo apt-get install libatomic1 +``` + +macOS: + +(No dependencies needed.) + +Windows: + +Install Windows Subsystem for Linux, then follow the Ubuntu instructions. + + + + +Compile SwiftWasm +================= + +Run + +``` +./swiftwasm example/hello.swift hello.wasm +``` + +To compile example/hello.swift to hello.wasm. + + + + +Running Wasm files +================== + +To run the resulting hello.wasm file: + +- Visit https://swiftwasm.org/polyfill/ +- select "Browse", and choose the hello.wasm file +- you should get output in the textbox. + +This polyfill should work in Firefox 66, Chrome 74, and Safari 12.1. + +You can also run the file outside a browser with: + +- Wasmtime https://github.com/CraneStation/wasmtime +- Lucet https://github.com/swiftwasm/lucet/tree/swiftwasm +- or any other WASI-compatible WebAssembly runtime. + + + + +Questions and support +===================== + +If you have any questions, please open an issue on + +https://github.com/swiftwasm/swift + + + +Third-party licenses +==================== + +This package contains components with their own license requirements. + +Swift compiler: https://github.com/apple/swift/blob/master/LICENSE.txt + +LLVM/Clang: https://github.com/llvm/llvm-project/blob/master/lld/LICENSE.TXT + +WASI sysroot: https://github.com/CraneStation/wasi-sysroot/blob/master/LICENSE + +ICU: https://github.com/unicode-org/icu/blob/master/icu4c/LICENSE + +WASI polyfill: https://github.com/CraneStation/wasmtime/blob/master/wasmtime-wasi/LICENSE diff --git a/utils/webassembly/sdkroot/example/hello.swift b/utils/webassembly/sdkroot/example/hello.swift new file mode 100644 index 0000000000000..e61506705879c --- /dev/null +++ b/utils/webassembly/sdkroot/example/hello.swift @@ -0,0 +1 @@ +print("Hello, 🌐!") diff --git a/utils/webassembly/sdkroot/extra_objs/fakelocaltime.o b/utils/webassembly/sdkroot/extra_objs/fakelocaltime.o new file mode 100644 index 0000000000000..904d3a6dedc61 Binary files /dev/null and b/utils/webassembly/sdkroot/extra_objs/fakelocaltime.o differ diff --git a/utils/webassembly/sdkroot/extra_objs/fakepthread.o b/utils/webassembly/sdkroot/extra_objs/fakepthread.o new file mode 100644 index 0000000000000..d95d0e77611b8 Binary files /dev/null and b/utils/webassembly/sdkroot/extra_objs/fakepthread.o differ diff --git a/utils/webassembly/sdkroot/extra_utils/generateModulemap.sh b/utils/webassembly/sdkroot/extra_utils/generateModulemap.sh new file mode 100755 index 0000000000000..940e5a413339b --- /dev/null +++ b/utils/webassembly/sdkroot/extra_utils/generateModulemap.sh @@ -0,0 +1,2 @@ +#!/bin/sh +exec sed -e "s@\"/include@\"$1/include@g" "$(dirname $0)/glibc.modulemap" diff --git a/utils/webassembly/sdkroot/swiftwasm b/utils/webassembly/sdkroot/swiftwasm new file mode 100755 index 0000000000000..278ce7dbc256a --- /dev/null +++ b/utils/webassembly/sdkroot/swiftwasm @@ -0,0 +1,40 @@ +#!/bin/bash +set -e + +if [ "$#" -lt 2 ] +then + echo "usage: swiftwasm file1.swift file2.swift.... output.wasm" + exit 1 +fi +sdk="$(dirname $0)" +tmpobj="$(mktemp -t swiftwasm-XXXXXXXX)" +outputfile="${@: -1}" +if [[ "$outputfile" != *.wasm ]] +then + echo "output should end in .wasm" + exit 1 +fi +sysroot="$(dirname $0)/wasi-sdk/share/sysroot" +abssysroot="$(cd "$(dirname "$sysroot")" && pwd)/$(basename "$sysroot")" + +"$sdk/extra_utils/generateModulemap.sh" "$abssysroot" >"$sdk/opt/swiftwasm-sdk/lib/swift/wasi/wasm32/glibc.modulemap" + +"$sdk/opt/swiftwasm-sdk/bin/swiftc" -target wasm32-unknown-unknown-wasi \ + -sdk "$sysroot" -O -c \ + -o "$tmpobj" \ + "${@:1:$#-1}" +"$sdk/wasi-sdk/bin/wasm-ld" --error-limit=0 -o "$outputfile" \ + "$sysroot/lib/wasm32-wasi/crt1.o" \ + "$sdk/opt/swiftwasm-sdk/lib/swift_static/wasi/wasm32/swiftrt.o" \ + "$tmpobj" \ + "-L$sdk/opt/swiftwasm-sdk/lib/swift_static/wasi" \ + "-L$sysroot/lib/wasm32-wasi" \ + "-L$sdk/icu_out/lib" \ + -lswiftCore \ + -lc -lc++ -lc++abi -lswiftImageInspectionShared \ + -licuuc -licudata \ + "$sdk/wasi-sdk/lib/clang/9.0.0/lib/wasi/libclang_rt.builtins-wasm32.a" \ + "$sdk/extra_objs/fakepthread.o" \ + --no-gc-sections \ + --no-threads +rm "$tmpobj" diff --git a/utils/webassembly/static-executable-args.lnk b/utils/webassembly/static-executable-args.lnk new file mode 100644 index 0000000000000..d80b4a58a272c --- /dev/null +++ b/utils/webassembly/static-executable-args.lnk @@ -0,0 +1,16 @@ +-static +-lswiftCore +-lswiftImageInspectionShared +-lswiftSwiftOnoneSupport +-lswiftWasiPthread +-licui18n +-licuuc +-licudata +-ldl +-lstdc++ +-lm +-lwasi-emulated-mman +-Xlinker --error-limit=0 +-Xlinker --no-gc-sections +-Xlinker --no-threads +-D_WASI_EMULATED_MMAN diff --git a/utils/webassembly/static-stdlib-args.lnk b/utils/webassembly/static-stdlib-args.lnk new file mode 100644 index 0000000000000..af390c6413bd2 --- /dev/null +++ b/utils/webassembly/static-stdlib-args.lnk @@ -0,0 +1,15 @@ +-ldl +-latomic +-lswiftWasiPthread +-lswiftCore +-latomic +-lswiftImageInspectionShared +-licui18n +-licuuc +-licudata +-lstdc++ +-lm +-Xlinker +--exclude-libs +-Xlinker +ALL