diff --git a/CMakeLists.txt b/CMakeLists.txt index ddfd8670c75cd..197ea538bc25a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -695,10 +695,6 @@ option(SWIFT_IMPLICIT_CONCURRENCY_IMPORT "Implicitly import the Swift concurrency module" TRUE) -option(SWIFT_IMPLICIT_BACKTRACING_IMPORT - "Implicitly import the Swift backtracing module" - FALSE) - option(SWIFT_ENABLE_EXPERIMENTAL_CONCURRENCY "Enable build of the Swift concurrency module" FALSE) @@ -731,6 +727,10 @@ option(SWIFT_ENABLE_SYNCHRONIZATION "Enable build of the Swift Synchronization module" FALSE) +option(SWIFT_ENABLE_RUNTIME_MODULE + "Build the Swift Runtime module" + FALSE) + option(SWIFT_ENABLE_VOLATILE "Enable build of the Swift Volatile module" FALSE) @@ -865,11 +865,6 @@ if (CMAKE_Swift_COMPILER) SWIFT_SUPPORTS_DISABLE_IMPLICIT_STRING_PROCESSING_MODULE_IMPORT) message(STATUS " Implicit 'string-processing' import: ${SWIFT_SUPPORTS_DISABLE_IMPLICIT_STRING_PROCESSING_MODULE_IMPORT}") - # Same for _Backtracing. - swift_supports_implicit_module("backtracing" - SWIFT_SUPPORTS_DISABLE_IMPLICIT_BACKTRACING_MODULE_IMPORT) - message(STATUS " Implicit 'backtracing' import: ${SWIFT_SUPPORTS_DISABLE_IMPLICIT_BACKTRACING_MODULE_IMPORT}") - swift_get_package_cmo_support( Swift_COMPILER_PACKAGE_CMO_SUPPORT) message(STATUS " Package CMO: ${Swift_COMPILER_PACKAGE_CMO_SUPPORT}") @@ -1087,6 +1082,9 @@ endif() # swift_common_cxx_warnings() +# Set sanitizer options for Swift compiler. +swift_common_sanitizer_config() + # Check if we're build with MSVC or Clang-cl, as these compilers have similar command line arguments. if("${CMAKE_C_COMPILER_ID}" STREQUAL "MSVC" OR "${CMAKE_CXX_SIMULATE_ID}" STREQUAL "MSVC") set(SWIFT_COMPILER_IS_MSVC_LIKE TRUE) @@ -1393,6 +1391,8 @@ if(SWIFT_BUILD_STDLIB OR SWIFT_BUILD_SDK_OVERLAY) message(STATUS "Observation Support: ${SWIFT_ENABLE_EXPERIMENTAL_OBSERVATION}") message(STATUS "Synchronization Support: ${SWIFT_ENABLE_SYNCHRONIZATION}") message(STATUS "Volatile Support: ${SWIFT_ENABLE_VOLATILE}") + message(STATUS "Pointer Bounds Support: ${SWIFT_ENABLE_EXPERIMENTAL_POINTER_BOUNDS}") + message(STATUS "Runtime Support: ${SWIFT_ENABLE_RUNTIME_MODULE}") message(STATUS "") else() message(STATUS "Not building Swift standard library, SDK overlays, and runtime") diff --git a/Runtimes/Core/CMakeLists.txt b/Runtimes/Core/CMakeLists.txt index 2c86181104435..54c25b0bbb5aa 100644 --- a/Runtimes/Core/CMakeLists.txt +++ b/Runtimes/Core/CMakeLists.txt @@ -92,7 +92,6 @@ defaulted_option(SwiftCore_ENABLE_RUNTIME_FUNCTION_COUNTERS "Enable runtime func defaulted_option(SwiftCore_ENABLE_STDIN "Enable functions that use stdin support") defaulted_option(SwiftCore_ENABLE_ENVIRONMENT "Enable environment variable support") defaulted_option(SwiftCore_ENABLE_OVERRIDABLE_RETAIN_RELEASE "Enable override hooks for retain/release") -defaulted_option(SwiftCore_ENABLE_MALLOC_TYPE "Enable malloc type information") defaulted_option(SwiftCore_ENABLE_RUNTIME_OS_VERSIONING "Enable runtime OS version detection") defaulted_option(SwiftCore_ENABLE_STATIC_PRINT "Disable full print") defaulted_option(SwiftCore_ENABLE_COMPACT_ABSOLUTE_FUNCTION_POINTERS "Resolve absolute function pointer as identity") @@ -102,6 +101,7 @@ option(SwiftCore_ENABLE_UNICODE_DATA "Include unicode data in Swift runtimes" ON option(SwiftCore_ENABLE_SHORT_MANGLING_LOOKUPS "Build with fast-path context descriptor lookups based on well-known short manglings." ON) option(SwiftCore_ENABLE_FILESYSTEM_SUPPORT "Build for systems that have a filesystem" ON) option(SwiftCore_ENABLE_OS_TRACE_LAZY_INIT "Use os_trace call to check if lazy init has been completed before making os_signpost calls." ${SwiftCore_HAS_OS_TRACE}) +option(SwiftCore_HAS_DARWIN_LIBMALLOC "Use Darwin malloc features" ${APPLE}) defaulted_option(SwiftCore_ENABLE_BACKTRACING "Enable backtracing runtime support") defaulted_set(SwiftCore_BACKTRACER_PATH STRING "Set a fixed path to the Swift backtracer") @@ -135,6 +135,7 @@ add_compile_definitions( $<$:-DSWIFT_STDLIB_ENABLE_UNICODE_DATA> # Stubs $<$:-DSWIFT_STDLIB_HAS_ENVIRON> # Concurrency, runtime, shims, platform overlay $<$:-DSWIFT_STDLIB_SUPPORT_BACK_DEPLOYMENT> # Concurrency, Compatibility override, magic symbols + $<$:-DSWIFT_STDLIB_HAS_DARWIN_LIBMALLOC> # Anything that includes include/swift/Runtime/Config.h $<$:-DSWIFT_THREADING_${SwiftCore_THREADING_PACKAGE}> $<$:-DSWIFT_RUNTIME_ENABLE_LEAK_CHECKER=$> $<$:-DSWIFT_RUNTIME_CLOBBER_FREED_OBJECTS=$>) @@ -173,7 +174,6 @@ add_compile_options( "$<$:SHELL:-Xfrontend -enable-experimental-concise-pound-file>" "$<$:SHELL:-Xfrontend -enable-lexical-lifetimes=false>" "$<$:SHELL:-Xfrontend -disable-implicit-concurrency-module-import>" - "$<$:SHELL:-Xfrontend -disable-implicit-backtracing-module-import>" "$<$:SHELL:-Xfrontend -disable-implicit-string-processing-module-import>" "$<$:SHELL:-Xfrontend -enforce-exclusivity=unchecked>" "$<$:SHELL:-Xfrontend -enable-ossa-modules>" diff --git a/Runtimes/Core/runtime/CMakeLists.txt b/Runtimes/Core/runtime/CMakeLists.txt index b16b780e259f5..9342c53e0c697 100644 --- a/Runtimes/Core/runtime/CMakeLists.txt +++ b/Runtimes/Core/runtime/CMakeLists.txt @@ -86,11 +86,10 @@ endif() target_compile_definitions(swiftRuntime PRIVATE -DSWIFT_RUNTIME - -DSWIFT_TARGET_LIBRARY_NAME=swiftRuntime + -DSWIFT_TARGET_LIBRARY_NAME=swiftRuntimeCore $<$:-DswiftCore_EXPORTS> $<$:-DSWIFT_ENABLE_BACKTRACING> $<$:-DSWIFT_STDLIB_OVERRIDABLE_RETAIN_RELEASE> - $<$:-DSWIFT_STDLIB_HAS_MALLOC_TYPE> $<$:-DSWIFT_RUNTIME_FIXED_BACKTRACER_PATH="${SwiftCore_BACKTRACER_PATH}"> $<$:-DSWIFT_STDLIB_TRACING> $<$:-DSWIFT_STDLIB_SHORT_MANGLING_LOOKUPS> diff --git a/cmake/caches/Windows-aarch64.cmake b/cmake/caches/Windows-aarch64.cmake index 089caa349eaa6..1eb8b6e432646 100644 --- a/cmake/caches/Windows-aarch64.cmake +++ b/cmake/caches/Windows-aarch64.cmake @@ -26,22 +26,6 @@ set(LLVM_DEFAULT_TARGET_TRIPLE aarch64-unknown-windows-msvc CACHE STRING "") set(LLVM_APPEND_VC_REV NO CACHE BOOL "") set(LLVM_ENABLE_PER_TARGET_RUNTIME_DIR YES CACHE BOOL "") set(LLVM_ENABLE_PYTHON YES CACHE BOOL "") -set(LLVM_RUNTIME_TARGETS - aarch64-unknown-windows-msvc - CACHE STRING "") -foreach(target ${LLVM_RUNTIME_TARGETS}) - set(RUNTIMES_${target}_LLVM_ENABLE_RUNTIMES - compiler-rt - CACHE STRING "") - set(RUNTIMES_${target}_CMAKE_MT mt CACHE STRING "") - set(RUNTIMES_${target}_CMAKE_SYSTEM_NAME Windows CACHE STRING "") - set(RUNTIMES_${target}_CMAKE_BUILD_TYPE Release CACHE STRING "") - set(RUNTIMES_${target}_COMPILER_RT_BUILD_CRT NO CACHE BOOL "") - set(RUNTIMES_${target}_COMPILER_RT_BUILD_LIBFUZZER NO CACHE BOOL "") - set(RUNTIMES_${target}_COMPILER_RT_BUILD_PROFILE YES CACHE BOOL "") - set(RUNTIMES_${target}_COMPILER_RT_BUILD_SANITIZERS NO CACHE BOOL "") - set(RUNTIMES_${target}_COMPILER_RT_BUILD_XRAY NO CACHE BOOL "") -endforeach() set(LLVM_TARGETS_TO_BUILD AArch64 ARM WebAssembly X86 CACHE STRING "") @@ -167,7 +151,6 @@ set(LLVM_DISTRIBUTION_COMPONENTS libclang libclang-headers LTO - runtimes ${LLVM_TOOLCHAIN_TOOLS} ${CLANG_TOOLS} ${LLD_TOOLS} diff --git a/cmake/caches/Windows-x86_64.cmake b/cmake/caches/Windows-x86_64.cmake index 71396be127fa8..0074813978d94 100644 --- a/cmake/caches/Windows-x86_64.cmake +++ b/cmake/caches/Windows-x86_64.cmake @@ -27,62 +27,6 @@ set(LLVM_APPEND_VC_REV NO CACHE BOOL "") set(LLVM_ENABLE_PER_TARGET_RUNTIME_DIR YES CACHE BOOL "") set(LLVM_ENABLE_PYTHON YES CACHE BOOL "") -set(DEFAULT_BUILTIN_TARGETS - x86_64-unknown-windows-msvc - aarch64-unknown-windows-msvc) -# Build the android builtins if NDK path is provided. -if(NOT "$ENV{NDKPATH}" STREQUAL "") - list(APPEND DEFAULT_BUILTIN_TARGETS - aarch64-unknown-linux-android - x86_64-unknown-linux-android) -endif() - -# The builtin targets are used to build the compiler-rt builtins. -set(LLVM_BUILTIN_TARGETS ${DEFAULT_BUILTIN_TARGETS} CACHE STRING "") - -# The runtime targets are used to build the compiler-rt profile library. -set(LLVM_RUNTIME_TARGETS - x86_64-unknown-windows-msvc - aarch64-unknown-windows-msvc - CACHE STRING "") - -foreach(target ${LLVM_RUNTIME_TARGETS}) - set(RUNTIMES_${target}_LLVM_ENABLE_RUNTIMES - compiler-rt - CACHE STRING "") - set(RUNTIMES_${target}_CMAKE_MT mt CACHE STRING "") - set(RUNTIMES_${target}_CMAKE_SYSTEM_NAME Windows CACHE STRING "") - set(RUNTIMES_${target}_CMAKE_BUILD_TYPE Release CACHE STRING "") - set(RUNTIMES_${target}_COMPILER_RT_BUILD_BUILTINS NO CACHE BOOL "") - set(RUNTIMES_${target}_COMPILER_RT_BUILD_CRT NO CACHE BOOL "") - set(RUNTIMES_${target}_COMPILER_RT_BUILD_LIBFUZZER NO CACHE BOOL "") - set(RUNTIMES_${target}_COMPILER_RT_BUILD_ORC NO CACHE BOOL "") - set(RUNTIMES_${target}_COMPILER_RT_BUILD_PROFILE YES CACHE BOOL "") - set(RUNTIMES_${target}_COMPILER_RT_BUILD_SANITIZERS NO CACHE BOOL "") - set(RUNTIMES_${target}_COMPILER_RT_BUILD_XRAY NO CACHE BOOL "") -endforeach() - -foreach(target ${LLVM_BUILTIN_TARGETS}) - set(BUILTINS_${target}_CMAKE_MT mt CACHE STRING "") - if(${target} MATCHES windows-msvc) - set(BUILTINS_${target}_CMAKE_SYSTEM_NAME Windows CACHE STRING "") - elseif(${target} MATCHES linux-android) - # Use a single 'linux' directory and arch-based lib names on Android. - set(BUILTINS_${target}_LLVM_ENABLE_PER_TARGET_RUNTIME_DIR NO CACHE BOOL "") - set(BUILTINS_${target}_CMAKE_SYSTEM_NAME Android CACHE STRING "") - if(${target} MATCHES aarch64) - set(BUILTINS_${target}_CMAKE_ANDROID_ARCH_ABI arm64-v8a CACHE STRING "") - else() - set(BUILTINS_${target}_CMAKE_ANDROID_ARCH_ABI x86_64 CACHE STRING "") - endif() - set(BUILTINS_${target}_CMAKE_ANDROID_NDK $ENV{NDKPATH} CACHE PATH "") - set(BUILTINS_${target}_CMAKE_ANDROID_API 21 CACHE STRING "") - set(BUILTINS_${target}_CMAKE_C_COMPILER_TARGET "${target}21" CACHE STRING "") - set(BUILTINS_${target}_CMAKE_CXX_COMPILER_TARGET "${target}21" CACHE STRING "") - endif() - set(BUILTINS_${target}_CMAKE_BUILD_TYPE Release CACHE STRING "") -endforeach() - set(LLVM_TARGETS_TO_BUILD AArch64 ARM WebAssembly X86 CACHE STRING "") # Disable certain targets to reduce the configure time or to avoid configuration @@ -207,8 +151,6 @@ set(LLVM_DISTRIBUTION_COMPONENTS libclang libclang-headers LTO - builtins - runtimes ${LLVM_TOOLCHAIN_TOOLS} ${CLANG_TOOLS} ${LLD_TOOLS} diff --git a/cmake/modules/AddPureSwift.cmake b/cmake/modules/AddPureSwift.cmake index 28e496a1ba406..52cdfc3f66e7e 100644 --- a/cmake/modules/AddPureSwift.cmake +++ b/cmake/modules/AddPureSwift.cmake @@ -28,13 +28,7 @@ function(_add_host_swift_compile_options name) "$<$:SHELL:-Xfrontend -disable-implicit-string-processing-module-import>") endif() - # Same for backtracing - if (SWIFT_SUPPORTS_DISABLE_IMPLICIT_BACKTRACING_MODULE_IMPORT) - target_compile_options(${name} PRIVATE - "$<$:SHELL:-Xfrontend -disable-implicit-backtracing-module-import>") - endif() - - if(SWIFT_ANALYZE_CODE_COVERAGE) + if(SWIFT_ANALYZE_CODE_COVERAGE) set(_cov_flags $<$:-profile-generate -profile-coverage-mapping>) target_compile_options(${name} PRIVATE ${_cov_flags}) target_link_options(${name} PRIVATE ${_cov_flags}) @@ -69,7 +63,6 @@ function(_add_host_swift_compile_options name) target_compile_options(${name} PRIVATE $<$:-tools-directory;${tools_path};>) endif() endif() - _add_host_variant_swift_sanitizer_flags(${name}) target_compile_options(${name} PRIVATE $<$:-color-diagnostics> diff --git a/cmake/modules/AddSwift.cmake b/cmake/modules/AddSwift.cmake index 909a8fb84990d..b8e9a9d41d1c1 100644 --- a/cmake/modules/AddSwift.cmake +++ b/cmake/modules/AddSwift.cmake @@ -82,36 +82,6 @@ function(_set_target_prefix_and_suffix target kind sdk) endif() endfunction() -function(_add_host_variant_swift_sanitizer_flags target) - if(LLVM_USE_SANITIZER) - if(LLVM_USE_SANITIZER STREQUAL "Address") - set(_Swift_SANITIZER_FLAGS "-sanitize=address" "-Xclang-linker" "-fsanitize=address") - elseif(LLVM_USE_SANITIZER STREQUAL "HWAddress") - # Not supported? - elseif(LLVM_USE_SANITIZER MATCHES "Memory(WithOrigins)?") - # Not supported - if(LLVM_USE_SANITIZER STREQUAL "MemoryWithOrigins") - # Not supported - endif() - elseif(LLVM_USE_SANITIZER STREQUAL "Undefined") - set(_Swift_SANITIZER_FLAGS "-sanitize=undefined" "-Xclang-linker" "-fsanitize=undefined") - elseif(LLVM_USE_SANITIZER STREQUAL "Thread") - set(_Swift_SANITIZER_FLAGS "-sanitize=thread" "-Xclang-linker" "-fsanitize=thread") - elseif(LLVM_USE_SANITIZER STREQUAL "DataFlow") - # Not supported - elseif(LLVM_USE_SANITIZER STREQUAL "Address;Undefined" OR - LLVM_USE_SANITIZER STREQUAL "Undefined;Address") - set(_Swift_SANITIZER_FLAGS "-sanitize=address" "-sanitize=undefined" "-Xclang-linker" "-fsanitize=address" "-Xclang-linker" "-fsanitize=undefined") - elseif(LLVM_USE_SANITIZER STREQUAL "Leaks") - # Not supported - else() - message(SEND_ERROR "unsupported value for LLVM_USE_SANITIZER: ${LLVM_USE_SANITIZER}") - endif() - - target_compile_options(${name} PRIVATE $<$:${_Swift_SANITIZER_FLAGS}>) - endif() -endfunction() - function(swift_get_host_triple out_var) if(SWIFT_HOST_VARIANT_SDK IN_LIST SWIFT_DARWIN_PLATFORMS) set(DEPLOYMENT_VERSION "${SWIFT_SDK_${SWIFT_HOST_VARIANT_SDK}_DEPLOYMENT_VERSION}") @@ -145,8 +115,6 @@ function(_add_host_variant_c_compile_link_flags name) if (CMAKE_Swift_COMPILER) target_compile_options(${name} PRIVATE $<$:-target;${SWIFT_HOST_TRIPLE}>) - - _add_host_variant_swift_sanitizer_flags(${name}) endif() set(_sysroot diff --git a/cmake/modules/SwiftSharedCMakeConfig.cmake b/cmake/modules/SwiftSharedCMakeConfig.cmake index b2cd838e41912..c2f1f81bfe708 100644 --- a/cmake/modules/SwiftSharedCMakeConfig.cmake +++ b/cmake/modules/SwiftSharedCMakeConfig.cmake @@ -377,3 +377,35 @@ function(swift_common_llvm_config target) llvm_config("${target}" ${ARGN}) endif() endfunction() + +# Set sanitizer options to all Swift compiler flags. Similar options are added to C/CXX compiler in 'HandleLLVMOptions' +macro(swift_common_sanitizer_config) + if(LLVM_USE_SANITIZER) + if(LLVM_USE_SANITIZER STREQUAL "Address") + set(_Swift_SANITIZER_FLAGS "-sanitize=address -Xclang-linker -fsanitize=address") + elseif(LLVM_USE_SANITIZER STREQUAL "HWAddress") + # Not supported? + elseif(LLVM_USE_SANITIZER MATCHES "Memory(WithOrigins)?") + # Not supported + if(LLVM_USE_SANITIZER STREQUAL "MemoryWithOrigins") + # Not supported + endif() + elseif(LLVM_USE_SANITIZER STREQUAL "Undefined") + set(_Swift_SANITIZER_FLAGS "-sanitize=undefined -Xclang-linker -fsanitize=undefined") + elseif(LLVM_USE_SANITIZER STREQUAL "Thread") + set(_Swift_SANITIZER_FLAGS "-sanitize=thread -Xclang-linker -fsanitize=thread") + elseif(LLVM_USE_SANITIZER STREQUAL "DataFlow") + # Not supported + elseif(LLVM_USE_SANITIZER STREQUAL "Address;Undefined" OR + LLVM_USE_SANITIZER STREQUAL "Undefined;Address") + set(_Swift_SANITIZER_FLAGS "-sanitize=address -sanitize=undefined -Xclang-linker -fsanitize=address -Xclang-linker -fsanitize=undefined") + elseif(LLVM_USE_SANITIZER STREQUAL "Leaks") + # Not supported + else() + message(SEND_ERROR "unsupported value for LLVM_USE_SANITIZER: ${LLVM_USE_SANITIZER}") + endif() + + set(CMAKE_Swift_FLAGS "${CMAKE_Swift_FLAGS} ${_Swift_SANITIZER_FLAGS}") + + endif() +endmacro() diff --git a/docs/Backtracing.rst b/docs/Backtracing.rst index 352e7b0999772..7543ceadbaf1e 100644 --- a/docs/Backtracing.rst +++ b/docs/Backtracing.rst @@ -319,3 +319,14 @@ of the backtracer using If the runtime is unable to locate the backtracer, it will allow your program to crash as it would have done anyway. + +Backtrace Storage +----------------- + +Backtraces are stored internally in a format called :download:`Compact Backtrace +Format `. This provides us with a way to store a +large number of frames in a much smaller space than would otherwise be possible. + +Similarly, where we need to store address to image mappings, we +use :download:`Compact ImageMap Format ` to minimise +storage requirements. diff --git a/docs/CompactBacktraceFormat.md b/docs/CompactBacktraceFormat.md new file mode 100644 index 0000000000000..eef81c3a8891d --- /dev/null +++ b/docs/CompactBacktraceFormat.md @@ -0,0 +1,167 @@ +Compact Backtrace Format +======================== + +We would like to be able to efficiently store and access backtraces, +but we also wish to minimise the memory used to store them. Since +backtraces typically contain a good deal of redundancy, it should be +possible to compress the data. + +Compact Backtrace Format (CBF) is a binary format for holding a +backtrace; this specification addresses only the storage of the actual +stack backtrace, and it does not consider storage of ancillary data +(register contents, image lists and so on). Those will be dealt with +separately elsewhere. + +## General Format + +Compact Backtrace Format data is byte aligned and starts with an +information byte: + +~~~ + 7 6 5 4 3 2 1 0 + ┌───────────────────────┬───────┐ + │ version │ size │ + └───────────────────────┴───────┘ +~~~ + +The `version` field identifies the version of CBF that is in use; this +document describes version `0`. The `size` field is encqoded as +follows: + +| `size` | Machine word size | +| :----: | :---------------- | +| 00 | 16-bit | +| 01 | 32-bit | +| 10 | 64-bit | +| 11 | Reserved | + +This is followed by a series of instructions that tell the reader how +to decode subsequent data. + +The first instruction that computes an address _must_ specify an +absolute address (the `a` bit must be set). + +## Instructions + +The following instructions are currently defined + +| `opcode` | Mnemonic | Meaning | +| :--------: | :------- | :---------------------------------------- | +| `00000000` | `end` | Marks the end of the backtrace | +| `00000001` | `trunc` | As above, but the backtrace was truncated | +| `0000xxxx` | reserved | Reserved for future expansion | +| `0001axxx` | `pc` | A program counter value follows | +| `0010axxx` | `ra` | A return address value follows | +| `0011axxx` | `async` | An async resume point follows | +| `01xxxxxx` | `omit` | Indicates frames have been omitted | +| `1000xxxx` | `rep` | Repeat the previous frame | +| `1xxxxxxx` | reserved | Reserved for future expansion | + +If the bit labelled `a` is set, it means that the address computation +is absolute rather than being relative to the previously computed +address. + +### `end`/`trunc` + +#### Encoding + +~~~ + 7 6 5 4 3 2 1 0 + ┌───────────────────────────┬───┐ + │ 0 0 0 0 0 0 0 │ t │ end (or trunc if t is 1) + └───────────────────────────┴───┘ +~~~ + +#### Meaning + +Marks the end of the backtrace data. If `t` is set, it indicates that +the backtrace was truncated at this point (for instance because we hit +a frame limit while capturing). + +It is not strictly necessary to use the `end` instruction if the +CBF data is of a known length. + +### `pc`, `ra`, `async` + +#### Encoding + +~~~ + 7 6 5 4 3 2 1 0 + ┌────────────────┬───┬──────────┐ + │ 0 0 0 1 │ a │ count │ pc + └────────────────┴───┴──────────┘ + ┌────────────────┬───┬──────────┐ + │ 0 0 1 0 │ a │ count │ ra + └────────────────┴───┴──────────┘ + ┌────────────────┬───┬──────────┐ + │ 0 0 1 1 │ a │ count │ async + └────────────────┴───┴──────────┘ +~~~ + +#### Meaning + +Each of these instructions represents a frame on the stack. For `pc` +frames, the computed address is an actual program counter (aka +instruction pointer) value. `ra` instructions instead represent a +_return address_, the difference being that the program has not yet +executed that instruction. `async` instructions point at the entry +point of an async resume function, and are used when walking stacks on +systems that support `async`/`await` primitives that are implemented +by function splitting (typically an `async` instruction will point at +the start of a function containing the code immediately following an +`await`). + +The next `count + 1` bytes following the instruction are an address +value. If `a` is set, the computed address is equal to the address +value. If `a` is not set, the computed address is equal to the +preceding computed address *plus* the address value. + +Address values are sign-extended to the machine word width before +processing. Thus a single address byte with value `0xff` on a 32-bit +backtrace represents the address value `0xffffffff`. + +### `omit` + +#### Encoding + +~~~ + 7 6 5 4 3 2 1 0 + ┌───────┬───┬───────────────────┐ + │ 0 1 │ x │ count │ omit + └───────┴───┴───────────────────┘ +~~~ + +#### Meaning + +Indicates that a number of frames were skipped when capturing the +backtrace. This is used to allow a backtrace to include both the top +and bottom of the stack, without carrying every intervening frame, and +is useful to prevent the data from exploding where recursion has taken +place. + +If `x` is `1`, the instruction is followed by `count + 1` bytes (up to the +machine word length) that are zero-extended to machine word length and +that represent a count of the number of frames that were omitted. + +If `x` is `0`, `count + 1` is the number of frames that were omitted. + +### `rep` + +#### Encoding + +~~~ + 7 6 5 4 3 2 1 0 + ┌────────────────┬───┬──────────┐ + │ 1 0 0 0 │ x │ count │ repeat + └────────────────┴───┴──────────┘ +~~~ + +#### Meaning + +Repeat the previous frame. + +If `x` is `1`, the instruction is followed by `count + 1` bytes that are zero +extended to machine word length and that represent a count of the number of +times to repeat the preceding frame. + +If `x` is `0`, the previous frame should be repeated `count + 1` times. diff --git a/docs/CompactImageMapFormat.md b/docs/CompactImageMapFormat.md new file mode 100644 index 0000000000000..a7a92bff85dd9 --- /dev/null +++ b/docs/CompactImageMapFormat.md @@ -0,0 +1,230 @@ +Compact ImageMap Format +======================= + +A process' address space contains (among other things) the set of +dynamically loaded images that have been mapped into that address +space. When generating crash logs or symbolicating backtraces, we +need to be able to capture and potentially store the list of images +that has been loaded, as well as some of the attributes of those +images, including each image's + +- Path +- Build ID (aka UUID) +- Base address +- End-of-text address + +Compact ImageMap Format (CIF) is a binary format for holding this +information. + +### General Format + +Compact ImageMap Format data is byte aligned and starts with an +information byte: + +~~~ + 7 6 5 4 3 2 1 0 + ┌───────────────────────┬───────┐ + │ version │ size │ + └───────────────────────┴───────┘ +~~~ + +The `version` field identifies the version of CIF that is in use; this +document describes version `0`. The `size` field is encoded as +follows: + +| `size` | Machine word size | +| :----: | :---------------- | +| 00 | 16-bit | +| 01 | 32-bit | +| 10 | 64-bit | +| 11 | Reserved | + +This is followed immediately by a field containing the name of the platform +that generated this image map. This field consists of a single byte length +followed by a UTF-8 string of that length. + +After that is a field encoding the number of images in the image map; +this field is encoded as a sequence of bytes, each holding seven bits +of data, with the top bit clear for the final byte. The most +significant byte is the first. e.g. + +| `count` | Encoding | +| ------: | :---------- | +| 0 | 00 | +| 1 | 01 | +| 127 | 7f | +| 128 | 81 00 | +| 129 | 81 01 | +| 700 | 85 3c | +| 1234 | 89 52 | +| 16384 | 81 80 00 | +| 65535 | 83 ff 7f | +| 2097152 | 81 80 80 00 | + +This in turn is followed by the list of images, stored in order of +increasing base address. For each image, we start with a header byte: + +~~~ + 7 6 5 4 3 2 1 0 + ┌───┬───┬───────────┬───────────┐ + │ r │ 0 │ acount │ ecount │ + └───┴───┴───────────┴───────────┘ +~~~ + +If `r` is set, then the base address is understood to be relative to +the previously computed base address. + +This byte is followed by `acount + 1` bytes of base address, then +`ecount + 1` bytes of offset to the end of text. + +Following this is an encoded count of bytes in the build ID, +encoded using the 7-bit scheme we used to encode the image count, and +then after that come the build ID bytes themselves. + +Finally, we encode the path string using the scheme below. + +### String Encoding + +Image paths contain a good deal of redundancy; paths are therefore +encoded using a prefix compression scheme. The basic idea here is +that while generating or reading the data, we maintain a mapping from +small integers to path prefix segments. + +The mapping is initialised with the following fixed list that never +need to be stored in CIF data: + +| code | Path prefix | +| :--: | :---------------------------------- | +| 0 | `/lib` | +| 1 | `/usr/lib` | +| 2 | `/usr/local/lib` | +| 3 | `/opt/lib` | +| 4 | `/System/Library/Frameworks` | +| 5 | `/System/Library/PrivateFrameworks` | +| 6 | `/System/iOSSupport` | +| 7 | `/Library/Frameworks` | +| 8 | `/System/Applications` | +| 9 | `/Applications` | +| 10 | `C:\Windows\System32` | +| 11 | `C:\Program Files\` | + +Codes below 32 are reserved for future expansion of the fixed list. + +Strings are encoded as a sequence of bytes, as follows: + +| `opcode` | Mnemonic | Meaning | +| :--------: | :-------- | :---------------------------------------- | +| `00000000` | `end` | Marks the end of the string | +| `00xxxxxx` | `str` | Raw string data | +| `01xxxxxx` | `framewk` | Names a framework | +| `1exxxxxx` | `expand` | Identifies a prefix in the table | + +#### `end` + +##### Encoding + +~~~ + 7 6 5 4 3 2 1 0 + ┌───────────────────────────────┐ + │ 0 0 0 0 0 0 0 0 │ end + └───────────────────────────────┘ +~~~ + +#### Meaning + +Marks the end of the string + +#### `str` + +##### Encoding + +~~~ + 7 6 5 4 3 2 1 0 + ┌───────┬───────────────────────┐ + │ 0 0 │ count │ str + └───────┴───────────────────────┘ +~~~ + +##### Meaning + +The next `count` bytes are included in the string verbatim. +Additionally, all path prefixes of this string data will be added to +the current prefix table. For instance, if the string data is +`/swift/linux/x86_64/libfoo.so`, then the prefix `/swift` will be +assigned the next available code, `/swift/linux` the code after that, +and `/swift/linux/x86_64` the code following that one. + +#### `framewk` + +##### Encoding + +~~~ + 7 6 5 4 3 2 1 0 + ┌───────┬───────────────────────┐ + │ 0 1 │ count │ framewk + └───────┴───────────────────────┘ +~~~ + +##### Meaning + +The next byte is a version character (normally `A`, but some +frameworks use higher characters), after which there are `count + 1` +bytes of name. + +This is expanded using the pattern +`/.framework/Versions//`. This also marks the +end of the string. + +#### `expand` + +##### Encoding + +~~~ + 7 6 5 4 3 2 1 0 + ┌───┬───┬───────────────────────┐ + │ 1 │ e │ code │ expand + └───┴───┴───────────────────────┘ +~~~ + +##### Meaning + +If `e` is `0`, `code` is the index into the prefix table for the +prefix that should be appended to the string at this point. + +If `e` is `1`, this opcode is followed by `code + 1` bytes that give +a value `v` such that `v + 64` is the index into the prefix table for +the prefix that should be appended to the string at this point. + +#### Example + +Let's say we wish to encode the following strings: + + /System/Library/Frameworks/AppKit.framework/Versions/C/AppKit + /System/Library/Frameworks/Photos.framework/Versions/A/Photos + /usr/lib/libobjc.A.dylib + /usr/lib/libz.1.dylib + /usr/lib/swift/libswiftCore.dylib + /usr/lib/libSystem.B.dylib + /usr/lib/libc++.1.dylib + +We would encode + + <84> <45> CAppKit <00> + +We then follow with + + <84> <45> APhotos <00> + +Next we have + + <81> <10> /libobjc.A.dylib <00> + <81> <0d> /libz.1.dylib <00> + <81> <19> /swift/libswiftCore.dylib <00> + +assigning code 32 to `/swift`, then + + <81> <12> /libSystem.B.dylib <00> + <81> <0f> /libc++.1.dylib <00> + +In total the original data would have taken up 256 bytes. Instead, we +have used 122 bytes, a saving of over 50%. diff --git a/include/swift/AST/DeclContext.h b/include/swift/AST/DeclContext.h index bd29db7c2f550..0c4d6f4db5f42 100644 --- a/include/swift/AST/DeclContext.h +++ b/include/swift/AST/DeclContext.h @@ -576,6 +576,11 @@ class alignas(1 << DeclContextAlignInBits) DeclContext LLVM_READONLY SourceFile *getOutermostParentSourceFile() const; + /// Returns true if the source file that contains the context is a + /// `.swiftinterface` file. + LLVM_READONLY + bool isInSwiftinterface() const; + /// Determine whether this declaration context is generic, meaning that it or /// any of its parents have generic parameters. bool isGenericContext() const; diff --git a/include/swift/AST/DiagnosticsFrontend.def b/include/swift/AST/DiagnosticsFrontend.def index b5c6c481c4cfc..95be9de0ff065 100644 --- a/include/swift/AST/DiagnosticsFrontend.def +++ b/include/swift/AST/DiagnosticsFrontend.def @@ -188,8 +188,6 @@ WARNING(warn_implicit_concurrency_import_failed,none, "unable to perform implicit import of \"_Concurrency\" module: no such module found", ()) REMARK(warn_implicit_string_processing_import_failed,none, "unable to perform implicit import of \"_StringProcessing\" module: no such module found", ()) -REMARK(warn_implicit_backtracing_import_failed,none, - "unable to perform implicit import of \"_Backtracing\" module: no such module found", ()) ERROR(error_bad_module_name,none, "module name \"%0\" is not a valid identifier" diff --git a/include/swift/AST/DiagnosticsSema.def b/include/swift/AST/DiagnosticsSema.def index 0fb3ff1f3c744..6ed29b22b8d0a 100644 --- a/include/swift/AST/DiagnosticsSema.def +++ b/include/swift/AST/DiagnosticsSema.def @@ -4544,7 +4544,8 @@ ERROR(try_assign_rhs_noncovering,none, "'" TRY_KIND_SELECT(0) "' following assignment operator does not cover " "everything to its right", (unsigned)) -ERROR(broken_bool,none, "type 'Bool' is broken", ()) +ERROR(broken_stdlib_type,none, + "standard library type '%0' is missing or broken; this is a compiler bug", (StringRef)) WARNING(inject_forced_downcast,none, "treating a forced downcast to %0 as optional will never produce 'nil'", diff --git a/include/swift/Basic/LangOptions.h b/include/swift/Basic/LangOptions.h index f7ec4f155383a..68a3f61c03dc8 100644 --- a/include/swift/Basic/LangOptions.h +++ b/include/swift/Basic/LangOptions.h @@ -421,10 +421,6 @@ namespace swift { /// Disable the implicit import of the _StringProcessing module. bool DisableImplicitStringProcessingModuleImport = false; - /// Disable the implicit import of the _Backtracing module. - bool DisableImplicitBacktracingModuleImport = - !SWIFT_IMPLICIT_BACKTRACING_IMPORT; - /// Disable the implicit import of the Cxx module. bool DisableImplicitCxxModuleImport = false; @@ -852,7 +848,7 @@ namespace swift { /// If non-zero, abort the expression type checker if it takes more /// than this many seconds. - unsigned ExpressionTimeoutThreshold = 600; + unsigned ExpressionTimeoutThreshold = 0; /// The upper bound, in bytes, of temporary data that can be /// allocated by the constraint solver. diff --git a/include/swift/Config.h.in b/include/swift/Config.h.in index b0e8282aac0bf..1884d0f95bcca 100644 --- a/include/swift/Config.h.in +++ b/include/swift/Config.h.in @@ -10,8 +10,6 @@ #cmakedefine01 SWIFT_IMPLICIT_CONCURRENCY_IMPORT -#cmakedefine01 SWIFT_IMPLICIT_BACKTRACING_IMPORT - #cmakedefine01 SWIFT_ENABLE_EXPERIMENTAL_DISTRIBUTED #cmakedefine01 SWIFT_ENABLE_GLOBAL_ISEL_ARM64 diff --git a/include/swift/Frontend/Frontend.h b/include/swift/Frontend/Frontend.h index 83386ce3275c5..6918fb89cbc1b 100644 --- a/include/swift/Frontend/Frontend.h +++ b/include/swift/Frontend/Frontend.h @@ -425,10 +425,6 @@ class CompilerInvocation { /// imported. bool shouldImportSwiftStringProcessing() const; - /// Whether the Swift Backtracing support library should be implicitly - /// imported. - bool shouldImportSwiftBacktracing() const; - /// Whether the CXX module should be implicitly imported. bool shouldImportCxx() const; @@ -679,14 +675,6 @@ class CompilerInstance { /// i.e. if it can be found. bool canImportSwiftStringProcessing() const; - /// Verify that if an implicit import of the `Backtracing` module if - /// expected, it can actually be imported. Emit a warning, otherwise. - void verifyImplicitBacktracingImport(); - - /// Whether the Swift Backtracing support library can be imported - /// i.e. if it can be found. - bool canImportSwiftBacktracing() const; - /// Whether the Cxx library can be imported bool canImportCxx() const; diff --git a/include/swift/Option/FrontendOptions.td b/include/swift/Option/FrontendOptions.td index 382151cae858b..85f1c9faf76fc 100644 --- a/include/swift/Option/FrontendOptions.td +++ b/include/swift/Option/FrontendOptions.td @@ -527,14 +527,6 @@ def disable_implicit_string_processing_module_import : Flag<["-"], "disable-implicit-string-processing-module-import">, HelpText<"Disable the implicit import of the _StringProcessing module.">; -def enable_implicit_backtracing_module_import : Flag<["-"], - "enable-implicit-backtracing-module-import">, - HelpText<"Enable the implicit import of the _Backtracing module.">; - -def disable_implicit_backtracing_module_import : Flag<["-"], - "disable-implicit-backtracing-module-import">, - HelpText<"Disable the implicit import of the _Backtracing module.">; - def disable_implicit_cxx_module_import : Flag<["-"], "disable-implicit-cxx-module-import">, HelpText<"Disable the implicit import of the C++ Standard Library module.">; diff --git a/include/swift/Runtime/Enum.h b/include/swift/Runtime/Enum.h index 80b5a50f4bfbf..28c85c0014d48 100644 --- a/include/swift/Runtime/Enum.h +++ b/include/swift/Runtime/Enum.h @@ -47,6 +47,11 @@ void swift_initEnumMetadataSingleCase(EnumMetadata *enumType, EnumLayoutFlags flags, const TypeLayout *payload); +SWIFT_RUNTIME_EXPORT +void swift_cvw_initEnumMetadataSingleCaseWithLayoutString( + EnumMetadata *self, EnumLayoutFlags layoutFlags, + const Metadata *payloadType); + SWIFT_RUNTIME_EXPORT void swift_initEnumMetadataSingleCaseWithLayoutString( EnumMetadata *self, EnumLayoutFlags layoutFlags, @@ -65,6 +70,11 @@ void swift_initEnumMetadataSinglePayload(EnumMetadata *enumType, const TypeLayout *payload, unsigned emptyCases); +SWIFT_RUNTIME_EXPORT +void swift_cvw_initEnumMetadataSinglePayloadWithLayoutString( + EnumMetadata *enumType, EnumLayoutFlags flags, const Metadata *payload, + unsigned emptyCases); + SWIFT_RUNTIME_EXPORT void swift_initEnumMetadataSinglePayloadWithLayoutString( EnumMetadata *enumType, EnumLayoutFlags flags, const Metadata *payload, @@ -123,6 +133,11 @@ void swift_initEnumMetadataMultiPayload(EnumMetadata *enumType, unsigned numPayloads, const TypeLayout * const *payloadTypes); +SWIFT_RUNTIME_EXPORT +void swift_cvw_initEnumMetadataMultiPayloadWithLayoutString( + EnumMetadata *enumType, EnumLayoutFlags flags, unsigned numPayloads, + const Metadata *const *payloadTypes); + SWIFT_RUNTIME_EXPORT void swift_initEnumMetadataMultiPayloadWithLayoutString(EnumMetadata *enumType, EnumLayoutFlags flags, diff --git a/include/swift/Runtime/Metadata.h b/include/swift/Runtime/Metadata.h index efa8701a2c993..d26d625d269cf 100644 --- a/include/swift/Runtime/Metadata.h +++ b/include/swift/Runtime/Metadata.h @@ -307,6 +307,12 @@ swift_allocateGenericClassMetadata(const ClassDescriptor *description, const void *arguments, const GenericClassMetadataPattern *pattern); +SWIFT_EXTERN_C SWIFT_RETURNS_NONNULL SWIFT_NODISCARD + SWIFT_RUNTIME_EXPORT_ATTRIBUTE ClassMetadata * + swift_cvw_allocateGenericClassMetadataWithLayoutString( + const ClassDescriptor *description, const void *arguments, + const GenericClassMetadataPattern *pattern); + SWIFT_EXTERN_C SWIFT_RETURNS_NONNULL SWIFT_NODISCARD SWIFT_RUNTIME_EXPORT_ATTRIBUTE ClassMetadata * swift_allocateGenericClassMetadataWithLayoutString( @@ -324,6 +330,12 @@ swift_allocateGenericValueMetadata(const ValueTypeDescriptor *description, const GenericValueMetadataPattern *pattern, size_t extraDataSize); +SWIFT_EXTERN_C SWIFT_RETURNS_NONNULL SWIFT_NODISCARD + SWIFT_RUNTIME_EXPORT_ATTRIBUTE ValueMetadata * + swift_cvw_allocateGenericValueMetadataWithLayoutString( + const ValueTypeDescriptor *description, const void *arguments, + const GenericValueMetadataPattern *pattern, size_t extraDataSize); + SWIFT_EXTERN_C SWIFT_RETURNS_NONNULL SWIFT_NODISCARD SWIFT_RUNTIME_EXPORT_ATTRIBUTE ValueMetadata * swift_allocateGenericValueMetadataWithLayoutString( @@ -662,6 +674,12 @@ void swift_initStructMetadata(StructMetadata *self, const TypeLayout * const *fieldTypes, uint32_t *fieldOffsets); +SWIFT_RUNTIME_EXPORT +void swift_cvw_initStructMetadataWithLayoutString( + StructMetadata *self, StructLayoutFlags flags, size_t numFields, + const uint8_t *const *fieldTypes, const uint8_t *fieldTags, + uint32_t *fieldOffsets); + SWIFT_RUNTIME_EXPORT void swift_initStructMetadataWithLayoutString(StructMetadata *self, StructLayoutFlags flags, diff --git a/include/swift/Runtime/RuntimeFunctions.def b/include/swift/Runtime/RuntimeFunctions.def index aac0a55597a2f..c6d5d17d2f60a 100644 --- a/include/swift/Runtime/RuntimeFunctions.def +++ b/include/swift/Runtime/RuntimeFunctions.def @@ -1027,12 +1027,12 @@ FUNCTION(AllocateGenericClassMetadata, Swift, swift_allocateGenericClassMetadata EFFECT(MetaData), UNKNOWN_MEMEFFECTS) -// Metadata *swift_allocateGenericClassMetadataWithLayoutString( +// Metadata *swift_cvw_allocateGenericClassMetadataWithLayoutString( // ClassDescriptor *type, // const void * const *arguments, // const void *template); FUNCTION(AllocateGenericClassMetadataWithLayoutString, - Swift, swift_allocateGenericClassMetadataWithLayoutString, + Swift, swift_cvw_allocateGenericClassMetadataWithLayoutString, C_CC, AlwaysAvailable, RETURNS(TypeMetadataPtrTy), ARGS(TypeContextDescriptorPtrTy, Int8PtrPtrTy, Int8PtrTy), @@ -1052,13 +1052,13 @@ FUNCTION(AllocateGenericValueMetadata, Swift, swift_allocateGenericValueMetadata EFFECT(MetaData), UNKNOWN_MEMEFFECTS) -// Metadata *swift_allocateGenericValueMetadataWithLayoutString( +// Metadata *swift_cvw_allocateGenericValueMetadataWithLayoutString( // ValueTypeDescriptor *type, // const void * const *arguments, // const void *template, // size_t extraSize); FUNCTION(AllocateGenericValueMetadataWithLayoutString, - Swift, swift_allocateGenericValueMetadataWithLayoutString, + Swift, swift_cvw_allocateGenericValueMetadataWithLayoutString, C_CC, AlwaysAvailable, RETURNS(TypeMetadataPtrTy), ARGS(TypeContextDescriptorPtrTy, Int8PtrPtrTy, Int8PtrTy, SizeTy), @@ -1489,14 +1489,14 @@ FUNCTION(InitStructMetadata, EFFECT(MetaData), UNKNOWN_MEMEFFECTS) -// void swift_initStructMetadataWithLayoutString(Metadata *structType, +// void swift_cvw_initStructMetadataWithLayoutString(Metadata *structType, // StructLayoutFlags flags, // size_t numFields, // uint8_t * const *fieldTypes, // const uint8_t *fieldTags // uint32_t *fieldOffsets); FUNCTION(InitStructMetadataWithLayoutString, - Swift, swift_initStructMetadataWithLayoutString, C_CC, AlwaysAvailable, + Swift, swift_cvw_initStructMetadataWithLayoutString, C_CC, AlwaysAvailable, RETURNS(VoidTy), ARGS(TypeMetadataPtrTy, SizeTy, SizeTy, Int8PtrPtrTy->getPointerTo(0), @@ -1518,11 +1518,11 @@ FUNCTION(InitEnumMetadataSingleCase, EFFECT(MetaData), UNKNOWN_MEMEFFECTS) -// void swift_initEnumMetadataSingleCaseWithLayoutString(Metadata *enumType, +// void swift_cvw_initEnumMetadataSingleCaseWithLayoutString(Metadata *enumType, // EnumLayoutFlags flags, // Metadata *payload); FUNCTION(InitEnumMetadataSingleCaseWithLayoutString, - Swift, swift_initEnumMetadataSingleCaseWithLayoutString, + Swift, swift_cvw_initEnumMetadataSingleCaseWithLayoutString, C_CC, AlwaysAvailable, RETURNS(VoidTy), ARGS(TypeMetadataPtrTy, SizeTy, TypeMetadataPtrTy), @@ -1543,12 +1543,12 @@ FUNCTION(InitEnumMetadataSinglePayload, EFFECT(MetaData), UNKNOWN_MEMEFFECTS) -// void swift_initEnumMetadataSinglePayloadWithLayoutString(Metadata *enumType, +// void swift_cvw_initEnumMetadataSinglePayloadWithLayoutString(Metadata *enumType, // EnumLayoutFlags flags, // Metadata *payload, // unsigned num_empty_cases); FUNCTION(InitEnumMetadataSinglePayloadWithLayoutString, - Swift, swift_initEnumMetadataSinglePayloadWithLayoutString, + Swift, swift_cvw_initEnumMetadataSinglePayloadWithLayoutString, C_CC, AlwaysAvailable, RETURNS(VoidTy), ARGS(TypeMetadataPtrTy, SizeTy, TypeMetadataPtrTy, Int32Ty), @@ -1570,12 +1570,12 @@ FUNCTION(InitEnumMetadataMultiPayload, UNKNOWN_MEMEFFECTS) // void -// swift_initEnumMetadataMultiPayloadWithLayoutString(Metadata *enumType, +// swift_cvw_initEnumMetadataMultiPayloadWithLayoutString(Metadata *enumType, // EnumLayoutFlags layoutFlags, // size_t numPayloads, // Metadata * const *payloadTypes); FUNCTION(InitEnumMetadataMultiPayloadWithLayoutString, - Swift, swift_initEnumMetadataMultiPayloadWithLayoutString, + Swift, swift_cvw_initEnumMetadataMultiPayloadWithLayoutString, C_CC, AlwaysAvailable, RETURNS(VoidTy), ARGS(TypeMetadataPtrTy, SizeTy, SizeTy, TypeMetadataPtrPtrTy), @@ -2684,9 +2684,9 @@ FUNCTION(StoreMultiPayloadEnumTagSinglePayload, EFFECT(NoEffect), UNKNOWN_MEMEFFECTS) -// void swift_generic_destroy(opaque*, const Metadata* type); +// void swift_cvw_destroy(opaque*, const Metadata* type); FUNCTION(GenericDestroy, - Swift, swift_generic_destroy, + Swift, swift_cvw_destroy, C_CC, AlwaysAvailable, RETURNS(VoidTy), ARGS(Int8PtrTy, TypeMetadataPtrTy), @@ -2695,9 +2695,9 @@ FUNCTION(GenericDestroy, UNKNOWN_MEMEFFECTS) -// void *swift_generic_assignWithCopy(opaque* dest, opaque* src, const Metadata* type); +// void *swift_cvw_assignWithCopy(opaque* dest, opaque* src, const Metadata* type); FUNCTION(GenericAssignWithCopy, - Swift, swift_generic_assignWithCopy, + Swift, swift_cvw_assignWithCopy, C_CC, AlwaysAvailable, RETURNS(Int8PtrTy), ARGS(Int8PtrTy, Int8PtrTy, TypeMetadataPtrTy), @@ -2705,9 +2705,9 @@ FUNCTION(GenericAssignWithCopy, EFFECT(RefCounting, Deallocating), UNKNOWN_MEMEFFECTS) -// void *swift_generic_assignWithTake(opaque* dest, opaque* src, const Metadata* type); +// void *swift_cvw_assignWithTake(opaque* dest, opaque* src, const Metadata* type); FUNCTION(GenericAssignWithTake, - Swift, swift_generic_assignWithTake, + Swift, swift_cvw_assignWithTake, C_CC, AlwaysAvailable, RETURNS(Int8PtrTy), ARGS(Int8PtrTy, Int8PtrTy, TypeMetadataPtrTy), @@ -2715,9 +2715,9 @@ FUNCTION(GenericAssignWithTake, EFFECT(RefCounting, Deallocating), UNKNOWN_MEMEFFECTS) -// void *swift_generic_initWithCopy(opaque* dest, opaque* src, const Metadata* type); +// void *swift_cvw_initWithCopy(opaque* dest, opaque* src, const Metadata* type); FUNCTION(GenericInitWithCopy, - Swift, swift_generic_initWithCopy, + Swift, swift_cvw_initWithCopy, C_CC, AlwaysAvailable, RETURNS(Int8PtrTy), ARGS(Int8PtrTy, Int8PtrTy, TypeMetadataPtrTy), @@ -2725,9 +2725,9 @@ FUNCTION(GenericInitWithCopy, EFFECT(RefCounting), UNKNOWN_MEMEFFECTS) -// void *swift_generic_initWithTake(opaque* dest, opaque* src, const Metadata* type); +// void *swift_cvw_initWithTake(opaque* dest, opaque* src, const Metadata* type); FUNCTION(GenericInitWithTake, - Swift, swift_generic_initWithTake, + Swift, swift_cvw_initWithTake, C_CC, AlwaysAvailable, RETURNS(Int8PtrTy), ARGS(Int8PtrTy, Int8PtrTy, TypeMetadataPtrTy), @@ -2735,9 +2735,9 @@ FUNCTION(GenericInitWithTake, EFFECT(RefCounting), UNKNOWN_MEMEFFECTS) -// void *swift_generic_initializeBufferWithCopyOfBuffer(ValueBuffer* dest, ValueBuffer* src, const Metadata* type); +// void *swift_cvw_initializeBufferWithCopyOfBuffer(ValueBuffer* dest, ValueBuffer* src, const Metadata* type); FUNCTION(GenericInitializeBufferWithCopyOfBuffer, - Swift, swift_generic_initializeBufferWithCopyOfBuffer, + Swift, swift_cvw_initializeBufferWithCopyOfBuffer, C_CC, AlwaysAvailable, RETURNS(Int8PtrTy), ARGS(getFixedBufferTy()->getPointerTo(), @@ -2747,10 +2747,10 @@ FUNCTION(GenericInitializeBufferWithCopyOfBuffer, EFFECT(RefCounting), UNKNOWN_MEMEFFECTS) -// unsigned swift_singletonEnum_getEnumTag(swift::OpaqueValue *address, +// unsigned swift_cvw_singletonEnum_getEnumTag(swift::OpaqueValue *address, // const Metadata *metadata); FUNCTION(SingletonEnumGetEnumTag, - Swift, swift_singletonEnum_getEnumTag, + Swift, swift_cvw_singletonEnum_getEnumTag, C_CC, AlwaysAvailable, RETURNS(Int32Ty), ARGS(Int8PtrTy, TypeMetadataPtrTy), @@ -2758,11 +2758,11 @@ FUNCTION(SingletonEnumGetEnumTag, EFFECT(NoEffect), UNKNOWN_MEMEFFECTS) -// void swift_singletonEnum_destructiveInjectEnumTag(swift::OpaqueValue *address, +// void swift_cvw_singletonEnum_destructiveInjectEnumTag(swift::OpaqueValue *address, // unsigned tag, // const Metadata *metadata) FUNCTION(SingletonEnumDestructiveInjectEnumTag, - Swift, swift_singletonEnum_destructiveInjectEnumTag, + Swift, swift_cvw_singletonEnum_destructiveInjectEnumTag, C_CC, AlwaysAvailable, RETURNS(VoidTy), ARGS(Int8PtrTy, Int32Ty, TypeMetadataPtrTy), @@ -2770,10 +2770,10 @@ FUNCTION(SingletonEnumDestructiveInjectEnumTag, EFFECT(NoEffect), UNKNOWN_MEMEFFECTS) -// unsigned swift_enumSimple_getEnumTag(swift::OpaqueValue *address, +// unsigned swift_cvw_enumSimple_getEnumTag(swift::OpaqueValue *address, // const Metadata *metadata); FUNCTION(EnumSimpleGetEnumTag, - Swift, swift_enumSimple_getEnumTag, + Swift, swift_cvw_enumSimple_getEnumTag, C_CC, AlwaysAvailable, RETURNS(Int32Ty), ARGS(Int8PtrTy, TypeMetadataPtrTy), @@ -2781,11 +2781,11 @@ FUNCTION(EnumSimpleGetEnumTag, EFFECT(NoEffect), UNKNOWN_MEMEFFECTS) -// unsigned swift_enumSimple_destructiveInjectEnumTag(swift::OpaqueValue *address, +// unsigned swift_cvw_enumSimple_destructiveInjectEnumTag(swift::OpaqueValue *address, // unsigned tag, // const Metadata *metadata) FUNCTION(EnumSimpleDestructiveInjectEnumTag, - Swift, swift_enumSimple_destructiveInjectEnumTag, + Swift, swift_cvw_enumSimple_destructiveInjectEnumTag, C_CC, AlwaysAvailable, RETURNS(VoidTy), ARGS(Int8PtrTy, Int32Ty, TypeMetadataPtrTy), @@ -2793,10 +2793,10 @@ FUNCTION(EnumSimpleDestructiveInjectEnumTag, EFFECT(NoEffect), UNKNOWN_MEMEFFECTS) -// unsigned swift_enumFn_getEnumTag(swift::OpaqueValue *address, +// unsigned swift_cvw_enumFn_getEnumTag(swift::OpaqueValue *address, // const Metadata *metadata); FUNCTION(EnumFnGetEnumTag, - Swift, swift_enumFn_getEnumTag, + Swift, swift_cvw_enumFn_getEnumTag, C_CC, AlwaysAvailable, RETURNS(Int32Ty), ARGS(Int8PtrTy, TypeMetadataPtrTy), @@ -2804,10 +2804,10 @@ FUNCTION(EnumFnGetEnumTag, EFFECT(NoEffect), UNKNOWN_MEMEFFECTS) -// unsigned swift_multiPayloadEnumGeneric_getEnumTag(opaque* address, +// unsigned swift_cvw_multiPayloadEnumGeneric_getEnumTag(opaque* address, // const Metadata *type); FUNCTION(MultiPayloadEnumGenericGetEnumTag, - Swift, swift_multiPayloadEnumGeneric_getEnumTag, + Swift, swift_cvw_multiPayloadEnumGeneric_getEnumTag, C_CC, AlwaysAvailable, RETURNS(Int32Ty), ARGS(Int8PtrTy, TypeMetadataPtrTy), @@ -2815,11 +2815,11 @@ FUNCTION(MultiPayloadEnumGenericGetEnumTag, EFFECT(NoEffect), UNKNOWN_MEMEFFECTS) -// void swift_multiPayloadEnumGeneric_destructiveInjectEnumTag(swift::OpaqueValue *address, +// void swift_cvw_multiPayloadEnumGeneric_destructiveInjectEnumTag(swift::OpaqueValue *address, // unsigned tag, // const Metadata *metadata) FUNCTION(MultiPayloadEnumGenericDestructiveInjectEnumTag, - Swift, swift_multiPayloadEnumGeneric_destructiveInjectEnumTag, + Swift, swift_cvw_multiPayloadEnumGeneric_destructiveInjectEnumTag, C_CC, AlwaysAvailable, RETURNS(VoidTy), ARGS(Int8PtrTy, Int32Ty, TypeMetadataPtrTy), @@ -2827,10 +2827,10 @@ FUNCTION(MultiPayloadEnumGenericDestructiveInjectEnumTag, EFFECT(NoEffect), UNKNOWN_MEMEFFECTS) -// unsigned swift_singlePayloadEnumGeneric_getEnumTag(swift::OpaqueValue *address, +// unsigned swift_cvw_singlePayloadEnumGeneric_getEnumTag(swift::OpaqueValue *address, // const Metadata *metadata); FUNCTION(SinglePayloadEnumGenericGetEnumTag, - Swift, swift_singlePayloadEnumGeneric_getEnumTag, + Swift, swift_cvw_singlePayloadEnumGeneric_getEnumTag, C_CC, AlwaysAvailable, RETURNS(Int32Ty), ARGS(Int8PtrTy, TypeMetadataPtrTy), @@ -2838,11 +2838,11 @@ FUNCTION(SinglePayloadEnumGenericGetEnumTag, EFFECT(NoEffect), UNKNOWN_MEMEFFECTS) -// void swift_singlePayloadEnumGeneric_destructiveInjectEnumTag(swift::OpaqueValue *address, +// void swift_cvw_singlePayloadEnumGeneric_destructiveInjectEnumTag(swift::OpaqueValue *address, // unsigned tag, // const Metadata *metadata) FUNCTION(SinglePayloadEnumGenericDestructiveInjectEnumTag, - Swift, swift_singlePayloadEnumGeneric_destructiveInjectEnumTag, + Swift, swift_cvw_singlePayloadEnumGeneric_destructiveInjectEnumTag, C_CC, AlwaysAvailable, RETURNS(VoidTy), ARGS(Int8PtrTy, Int32Ty, TypeMetadataPtrTy), @@ -2850,10 +2850,10 @@ FUNCTION(SinglePayloadEnumGenericDestructiveInjectEnumTag, EFFECT(NoEffect), UNKNOWN_MEMEFFECTS) -// void swift_generic_instantiateLayoutString(const uint8_t* layoutStr, +// void swift_cvw_instantiateLayoutString(const uint8_t* layoutStr, // Metadata* type); FUNCTION(GenericInstantiateLayoutString, - Swift, swift_generic_instantiateLayoutString, + Swift, swift_cvw_instantiateLayoutString, C_CC, AlwaysAvailable, RETURNS(VoidTy), ARGS(Int8PtrTy, TypeMetadataPtrTy), diff --git a/include/swift/Sema/CSTrail.def b/include/swift/Sema/CSTrail.def index a2ccbb36de963..c43207619fece 100644 --- a/include/swift/Sema/CSTrail.def +++ b/include/swift/Sema/CSTrail.def @@ -54,7 +54,6 @@ LOCATOR_CHANGE(RecordedOpenedExistentialType, OpenedExistentialTypes) LOCATOR_CHANGE(RecordedPackExpansionEnvironment, PackExpansionEnvironments) LOCATOR_CHANGE(RecordedDefaultedConstraint, DefaultedConstraints) LOCATOR_CHANGE(ResolvedOverload, ResolvedOverloads) -LOCATOR_CHANGE(RecordedImplicitValueConversion, ImplicitValueConversions) LOCATOR_CHANGE(RecordedArgumentList, ArgumentLists) LOCATOR_CHANGE(RecordedImplicitCallAsFunctionRoot, ImplicitCallAsFunctionRoots) LOCATOR_CHANGE(RecordedSynthesizedConformance, SynthesizedConformances) diff --git a/include/swift/Sema/ConstraintSystem.h b/include/swift/Sema/ConstraintSystem.h index 1d435e6059f74..6047ae928796c 100644 --- a/include/swift/Sema/ConstraintSystem.h +++ b/include/swift/Sema/ConstraintSystem.h @@ -1580,10 +1580,6 @@ class Solution { /// The locators of \c Defaultable constraints whose defaults were used. llvm::DenseSet DefaultedConstraints; - /// Implicit value conversions applied for a given locator. - std::vector> - ImplicitValueConversions; - /// The node -> type mappings introduced by this solution. llvm::DenseMap nodeTypes; @@ -2368,11 +2364,6 @@ class ConstraintSystem { llvm::DenseMap argumentMatchingChoices; - /// The set of implicit value conversions performed by the solver on - /// a current path to reach a solution. - llvm::SmallDenseMap - ImplicitValueConversions; - /// The worklist of "active" constraints that should be revisited /// due to a change. ConstraintList ActiveConstraints; @@ -4608,16 +4599,15 @@ class ConstraintSystem { inline bool isFailure() const { return Kind == SolutionKind::Error; } inline bool isAmbiguous() const { return Kind == SolutionKind::Unsolved; } - static TypeMatchResult success(ConstraintSystem &cs) { + static TypeMatchResult success() { return {SolutionKind::Solved}; } - static TypeMatchResult failure(ConstraintSystem &cs, - ConstraintLocatorBuilder location) { + static TypeMatchResult failure() { return {SolutionKind::Error}; } - static TypeMatchResult ambiguous(ConstraintSystem &cs) { + static TypeMatchResult ambiguous() { return {SolutionKind::Unsolved}; } @@ -4722,15 +4712,15 @@ class ConstraintSystem { ConstraintLocatorBuilder locator); TypeMatchResult getTypeMatchSuccess() { - return TypeMatchResult::success(*this); + return TypeMatchResult::success(); } TypeMatchResult getTypeMatchFailure(ConstraintLocatorBuilder locator) { - return TypeMatchResult::failure(*this, locator); + return TypeMatchResult::failure(); } TypeMatchResult getTypeMatchAmbiguous() { - return TypeMatchResult::ambiguous(*this); + return TypeMatchResult::ambiguous(); } public: @@ -5047,10 +5037,6 @@ class ConstraintSystem { TypeMatchOptions flags, ConstraintLocatorBuilder locator); - /// Update ImplicitValueConversions and record a change in the trail. - void recordImplicitValueConversion(ConstraintLocator *locator, - ConversionRestrictionKind restriction); - /// Simplify a conversion constraint by applying the given /// reduction rule, which is known to apply at the outermost level. SolutionKind simplifyRestrictedConstraint( diff --git a/include/swift/Strings.h b/include/swift/Strings.h index be4791f9a31d7..f1c2dba3461ed 100644 --- a/include/swift/Strings.h +++ b/include/swift/Strings.h @@ -33,8 +33,6 @@ constexpr static const StringLiteral SWIFT_MODULE_ABI_NAME_PREFIX = "Compiler"; constexpr static const StringLiteral SWIFT_DISTRIBUTED_NAME = "Distributed"; /// The name of the StringProcessing module, which supports that extension. constexpr static const StringLiteral SWIFT_STRING_PROCESSING_NAME = "_StringProcessing"; -/// The name of the Backtracing module, which supports that extension. -constexpr static const StringLiteral SWIFT_BACKTRACING_NAME = "_Backtracing"; /// The name of the SwiftShims module, which contains private stdlib decls. constexpr static const StringLiteral SWIFT_SHIMS_NAME = "SwiftShims"; /// The name of the CxxShim module, which contains a cxx casting utility. diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp index 65e8ca162848f..3b4e433c679c6 100644 --- a/lib/AST/Decl.cpp +++ b/lib/AST/Decl.cpp @@ -8626,7 +8626,7 @@ static DefaultArgumentKind computeDefaultArgumentKind(DeclContext *dc, // expected to include them explicitly in subclasses. A default argument of // '= super' in a parameter of such initializer indicates that the default // argument is inherited. - if (dc->getParentSourceFile()->Kind == SourceFileKind::Interface) { + if (dc->isInSwiftinterface()) { return DefaultArgumentKind::Inherited; } else { return DefaultArgumentKind::Normal; diff --git a/lib/AST/DeclContext.cpp b/lib/AST/DeclContext.cpp index d2d651ccbdb2b..f001d927414f2 100644 --- a/lib/AST/DeclContext.cpp +++ b/lib/AST/DeclContext.cpp @@ -413,6 +413,11 @@ SourceFile *DeclContext::getOutermostParentSourceFile() const { return sf; } +bool DeclContext::isInSwiftinterface() const { + auto sf = getParentSourceFile(); + return sf && sf->Kind == SourceFileKind::Interface; +} + DeclContext *DeclContext::getModuleScopeContext() const { // If the current context is PackageUnit, return the module // decl context pointing to the current context. This check diff --git a/lib/AST/DiagnosticEngine.cpp b/lib/AST/DiagnosticEngine.cpp index 478fb78b9e8e6..599ff14369719 100644 --- a/lib/AST/DiagnosticEngine.cpp +++ b/lib/AST/DiagnosticEngine.cpp @@ -457,8 +457,7 @@ InFlightDiagnostic::warnUntilSwiftVersion(unsigned majorVersion) { InFlightDiagnostic & InFlightDiagnostic::warnInSwiftInterface(const DeclContext *context) { - auto sourceFile = context->getParentSourceFile(); - if (sourceFile && sourceFile->Kind == SourceFileKind::Interface) { + if (context->isInSwiftinterface()) { return limitBehavior(DiagnosticBehavior::Warning); } diff --git a/lib/AST/NameLookup.cpp b/lib/AST/NameLookup.cpp index f5e7e36b79cdb..ef8d3c0232221 100644 --- a/lib/AST/NameLookup.cpp +++ b/lib/AST/NameLookup.cpp @@ -651,22 +651,6 @@ static void recordShadowedDeclsAfterTypeMatch( } } - // Next, prefer any other module over the _Backtracing module. - if (auto spModule = ctx.getLoadedModule(ctx.Id_Backtracing)) { - if ((firstModule == spModule) != (secondModule == spModule)) { - // If second module is _StringProcessing, then it is shadowed by - // first. - if (secondModule == spModule) { - shadowed.insert(secondDecl); - continue; - } - - // Otherwise, the first declaration is shadowed by the second. - shadowed.insert(firstDecl); - break; - } - } - // Next, prefer any other module over the Observation module. if (auto obsModule = ctx.getLoadedModule(ctx.Id_Observation)) { if ((firstModule == obsModule) != (secondModule == obsModule)) { diff --git a/lib/ClangImporter/ImportDecl.cpp b/lib/ClangImporter/ImportDecl.cpp index 2ed671347aea1..fb63e02a75899 100644 --- a/lib/ClangImporter/ImportDecl.cpp +++ b/lib/ClangImporter/ImportDecl.cpp @@ -1166,14 +1166,6 @@ namespace { decl->getOwningModule() && decl->getOwningModule()->getTopLevelModuleName() == "os") return nullptr; - // Workaround for simd module declaring `namespace simd` on Darwin, - // causing name lookup issues. That namespace declares C++ overlays of - // types that are already refined for Swift, so let's not import the - // namespace (rdar://143007477). - if (decl->getIdentifier() && decl->getName() == "simd" && - decl->getOwningModule() && - decl->getOwningModule()->getTopLevelModuleName() == "simd") - return nullptr; // If this is a top-level namespace, don't put it in the module we're // importing, put it in the "__ObjC" module that is implicitly imported. if (!decl->getParent()->isNamespace()) @@ -4124,6 +4116,7 @@ namespace { // annotated nor is it marked noescape. auto attr = new (ASTContext) UnsafeAttr(/*implicit=*/true); result->getAttrs().add(attr); + break; } } Impl.diagnoseTargetDirectly(decl); diff --git a/lib/DriverTool/autolink_extract_main.cpp b/lib/DriverTool/autolink_extract_main.cpp index 79d63e6ea5d74..7bcc1251d82ad 100644 --- a/lib/DriverTool/autolink_extract_main.cpp +++ b/lib/DriverTool/autolink_extract_main.cpp @@ -230,9 +230,9 @@ int autolink_extract_main(ArrayRef Args, const char *Argv0, "-lswift_StringProcessing", "-lswiftRegexBuilder", "-lswift_RegexParser", - "-lswift_Backtracing", "-lswift_Builtin_float", "-lswift_math", + "-lswiftRuntime", "-lswiftSynchronization", "-lswiftGlibc", "-lswiftAndroid", diff --git a/lib/Frontend/CompilerInvocation.cpp b/lib/Frontend/CompilerInvocation.cpp index e53a1d5abc5d4..f4a904b54a9a1 100644 --- a/lib/Frontend/CompilerInvocation.cpp +++ b/lib/Frontend/CompilerInvocation.cpp @@ -948,11 +948,6 @@ static bool ParseLangArgs(LangOptions &Opts, ArgList &Args, Opts.DisableImplicitCxxModuleImport |= Args.hasArg(OPT_disable_implicit_cxx_module_import); - Opts.DisableImplicitBacktracingModuleImport = - Args.hasFlag(OPT_disable_implicit_backtracing_module_import, - OPT_enable_implicit_backtracing_module_import, - true); - if (Args.hasArg(OPT_enable_experimental_async_top_level)) Diags.diagnose(SourceLoc(), diag::warn_flag_deprecated, "-enable-experimental-async-top-level"); diff --git a/lib/Frontend/Frontend.cpp b/lib/Frontend/Frontend.cpp index efb0685d8500b..530bbc74f8b09 100644 --- a/lib/Frontend/Frontend.cpp +++ b/lib/Frontend/Frontend.cpp @@ -1109,20 +1109,6 @@ bool CompilerInvocation::shouldImportSwiftStringProcessing() const { FrontendOptions::ParseInputMode::SwiftModuleInterface; } -/// Enable Swift backtracing on a per-target basis -static bool shouldImportSwiftBacktracingByDefault(const llvm::Triple &target) { - if (target.isOSDarwin() || target.isOSWindows() || target.isOSLinux()) - return true; - return false; -} - -bool CompilerInvocation::shouldImportSwiftBacktracing() const { - return shouldImportSwiftBacktracingByDefault(getLangOptions().Target) && - !getLangOptions().DisableImplicitBacktracingModuleImport && - getFrontendOptions().InputMode != - FrontendOptions::ParseInputMode::SwiftModuleInterface; -} - bool CompilerInvocation::shouldImportCxx() const { // C++ Interop is disabled if (!getLangOptions().EnableCXXInterop) @@ -1209,21 +1195,6 @@ bool CompilerInstance::canImportSwiftStringProcessing() const { return getASTContext().testImportModule(modulePath); } -void CompilerInstance::verifyImplicitBacktracingImport() { - if (Invocation.shouldImportSwiftBacktracing() && - !canImportSwiftBacktracing()) { - Diagnostics.diagnose(SourceLoc(), - diag::warn_implicit_backtracing_import_failed); - } -} - -bool CompilerInstance::canImportSwiftBacktracing() const { - ImportPath::Module::Builder builder( - getASTContext().getIdentifier(SWIFT_BACKTRACING_NAME)); - auto modulePath = builder.get(); - return getASTContext().testImportModule(modulePath); -} - bool CompilerInstance::canImportCxx() const { ImportPath::Module::Builder builder( getASTContext().getIdentifier(CXX_MODULE_NAME)); @@ -1321,19 +1292,6 @@ ImplicitImportInfo CompilerInstance::getImplicitImportInfo() const { } } - if (Invocation.shouldImportSwiftBacktracing()) { - switch (imports.StdlibKind) { - case ImplicitStdlibKind::Builtin: - case ImplicitStdlibKind::None: - break; - - case ImplicitStdlibKind::Stdlib: - if (canImportSwiftBacktracing()) - pushImport(SWIFT_BACKTRACING_NAME); - break; - } - } - if (Invocation.getLangOptions().EnableCXXInterop) { if (Invocation.shouldImportCxx() && canImportCxx()) pushImport(CXX_MODULE_NAME); diff --git a/lib/IRGen/GenCall.cpp b/lib/IRGen/GenCall.cpp index 55b5a713af93b..b06e51a8e978c 100644 --- a/lib/IRGen/GenCall.cpp +++ b/lib/IRGen/GenCall.cpp @@ -83,12 +83,10 @@ static Size getCoroutineContextSize(IRGenModule &IGM, case SILCoroutineKind::None: llvm_unreachable("expand a coroutine"); case SILCoroutineKind::YieldOnce2: - if (IGM.IRGen.Opts.EmitYieldOnce2AsYieldOnce) { - LLVM_FALLTHROUGH; - } else { + if (!IGM.IRGen.Opts.EmitYieldOnce2AsYieldOnce) llvm::report_fatal_error( "callee allocated coroutines do not have fixed-size buffers"); - } + LLVM_FALLTHROUGH; case SILCoroutineKind::YieldOnce: return getYieldOnceCoroutineBufferSize(IGM); case SILCoroutineKind::YieldMany: @@ -1912,11 +1910,9 @@ void SignatureExpansion::expandParameters( case SILCoroutineKind::None: break; case SILCoroutineKind::YieldOnce2: - if (IGM.IRGen.Opts.EmitYieldOnce2AsYieldOnce) { - LLVM_FALLTHROUGH; - } else { + if (!IGM.IRGen.Opts.EmitYieldOnce2AsYieldOnce) break; - } + LLVM_FALLTHROUGH; case SILCoroutineKind::YieldOnce: case SILCoroutineKind::YieldMany: @@ -2720,12 +2716,9 @@ class SyncCallEmission final : public CallEmission { // Pass along the coroutine buffer. switch (origCalleeType->getCoroutineKind()) { case SILCoroutineKind::YieldOnce2: - if (IGF.IGM.IRGen.Opts.EmitYieldOnce2AsYieldOnce) { - LLVM_FALLTHROUGH; - } else { + if (!IGF.IGM.IRGen.Opts.EmitYieldOnce2AsYieldOnce) llvm::report_fatal_error("unimplemented"); - break; - } + LLVM_FALLTHROUGH; case SILCoroutineKind::YieldOnce: case SILCoroutineKind::YieldMany: original.transferInto(adjusted, 1); @@ -4810,12 +4803,10 @@ irgen::getCoroutineResumeFunctionPointerAuth(IRGenModule &IGM, return { IGM.getOptions().PointerAuth.YieldManyResumeFunctions, PointerAuthEntity::forYieldTypes(fnType) }; case SILCoroutineKind::YieldOnce2: - if (IGM.IRGen.Opts.EmitYieldOnce2AsYieldOnce) { - LLVM_FALLTHROUGH; - } else { + if (!IGM.IRGen.Opts.EmitYieldOnce2AsYieldOnce) return {IGM.getOptions().PointerAuth.YieldOnce2ResumeFunctions, PointerAuthEntity::forYieldTypes(fnType)}; - } + LLVM_FALLTHROUGH; case SILCoroutineKind::YieldOnce: return { IGM.getOptions().PointerAuth.YieldOnceResumeFunctions, PointerAuthEntity::forYieldTypes(fnType) }; diff --git a/lib/IRGen/GenReflection.cpp b/lib/IRGen/GenReflection.cpp index 4179acae0a841..dee0bc7cd6bed 100644 --- a/lib/IRGen/GenReflection.cpp +++ b/lib/IRGen/GenReflection.cpp @@ -944,18 +944,35 @@ class FieldTypeMetadataBuilder : public ReflectionMetadataBuilder { B.addInt16(uint16_t(kind)); B.addInt16(FieldRecordSize); - B.addInt32(getNumFields(NTD)); + // Filter to select which fields we'll export FieldDescriptors for. + auto exportable_field = + [](Field field) { + // Don't export private C++ fields that were imported as private Swift fields. + // The type of a private field might not have all the type witness + // operations that Swift requires, for instance, + // `std::unique_ptr` would not have a destructor. + if (field.getKind() == Field::Kind::Var && + field.getVarDecl()->getClangDecl() && + field.getVarDecl()->getFormalAccess() == AccessLevel::Private) + return false; + // All other fields are exportable + return true; + }; + + // Count exportable fields + int exportableFieldCount = 0; forEachField(IGM, NTD, [&](Field field) { - // Skip private C++ fields that were imported as private Swift fields. - // The type of a private field might not have all the type witness - // operations that Swift requires, for instance, - // `std::unique_ptr` would not have a destructor. - if (field.getKind() == Field::Kind::Var && - field.getVarDecl()->getClangDecl() && - field.getVarDecl()->getFormalAccess() == AccessLevel::Private) - return; + if (exportable_field(field)) { + ++exportableFieldCount; + } + }); - addField(field); + // Emit exportable fields, prefixed with a count + B.addInt32(exportableFieldCount); + forEachField(IGM, NTD, [&](Field field) { + if (exportable_field(field)) { + addField(field); + } }); } diff --git a/lib/SILOptimizer/Analysis/BasicCalleeAnalysis.cpp b/lib/SILOptimizer/Analysis/BasicCalleeAnalysis.cpp index 32bb4d7890468..c83ce9b7c0d02 100644 --- a/lib/SILOptimizer/Analysis/BasicCalleeAnalysis.cpp +++ b/lib/SILOptimizer/Analysis/BasicCalleeAnalysis.cpp @@ -75,7 +75,7 @@ getMemoryBehavior(FullApplySite as, bool observeRetains) { bool swift::isDeinitBarrier(SILInstruction *const instruction, BasicCalleeAnalysis *bca) { - if (!instructionIsDeinitBarrierFunction) { + if (!instructionIsDeinitBarrierFunction || !bca) { return mayBeDeinitBarrierNotConsideringSideEffects(instruction); } BridgedInstruction inst = { diff --git a/lib/SILOptimizer/IPO/CrossModuleOptimization.cpp b/lib/SILOptimizer/IPO/CrossModuleOptimization.cpp index 7a3dbcc5cfea4..447fba1e56b8e 100644 --- a/lib/SILOptimizer/IPO/CrossModuleOptimization.cpp +++ b/lib/SILOptimizer/IPO/CrossModuleOptimization.cpp @@ -431,6 +431,15 @@ void CrossModuleOptimization::serializeWitnessTablesInModule() { } void CrossModuleOptimization::serializeVTablesInModule() { + if (everything) { + for (SILVTable *vt : M.getVTables()) { + vt->setSerializedKind(IsSerialized); + for (auto &entry : vt->getEntries()) { + makeFunctionUsableFromInline(entry.getImplementation()); + } + } + return; + } if (!isPackageCMOEnabled(M.getSwiftModule())) return; diff --git a/lib/Sema/CSApply.cpp b/lib/Sema/CSApply.cpp index 563dbf4017523..2867c515a7cea 100644 --- a/lib/Sema/CSApply.cpp +++ b/lib/Sema/CSApply.cpp @@ -4162,7 +4162,7 @@ namespace { // SIL-generation magically turns this into a Bool; make sure it can. if (!ctx.getBoolBuiltinInitDecl()) { - ctx.Diags.diagnose(expr->getLoc(), diag::broken_bool); + ctx.Diags.diagnose(expr->getLoc(), diag::broken_stdlib_type, "Bool"); // Continue anyway. } @@ -4200,7 +4200,7 @@ namespace { auto boolDecl = ctx.getBoolDecl(); if (!boolDecl) { - ctx.Diags.diagnose(SourceLoc(), diag::broken_bool); + ctx.Diags.diagnose(SourceLoc(), diag::broken_stdlib_type, "Bool"); } cs.setType(isSomeExpr, boolDecl ? ctx.getBoolType() : Type()); @@ -5868,6 +5868,9 @@ static unsigned getOptionalEvaluationDepth(Expr *expr, Expr *target) { depth += getOptionalEvaluationDepth(open->getSubExpr(), open->getOpaqueValue()); expr = open->getExistentialValue(); + } else if (auto call = dyn_cast(expr)) { + // CGFloat <-> Double conversions lower to constructor calls. + expr = call->getArgs()->getExpr(0); // Otherwise, look through implicit conversions. } else { @@ -7262,77 +7265,46 @@ Expr *ExprRewriter::coerceToType(Expr *expr, Type toType, case ConversionRestrictionKind::CGFloatToDouble: case ConversionRestrictionKind::DoubleToCGFloat: { - auto conversionKind = knownRestriction->second; - - auto shouldUseCoercedExpr = [&]() { - // If conversion wraps the whole body of a single-expression closure, - // let's use the passed-in expression since the closure itself doesn't - // get updated until coercion is done. - if (locator.endsWith()) - return true; - - // Contextual type locator always uses the original version of - // expression (before any coercions have been applied) because - // otherwise it wouldn't be possible to find the overload choice. - if (locator.endsWith()) - return true; - - // In all other cases use the expression associated with locator. - return false; - }; - - auto *argExpr = - shouldUseCoercedExpr() ? expr : locator.trySimplifyToExpr(); - assert(argExpr); - - // Source requires implicit conversion to match destination - // type but the conversion itself is recorded on assignment. - if (auto *assignment = dyn_cast(argExpr)) - argExpr = assignment->getSrc(); - - // Load the value for conversion. - argExpr = cs.coerceToRValue(argExpr); - - auto *argList = ArgumentList::forImplicitUnlabeled(ctx, {argExpr}); - auto *implicitInit = CallExpr::createImplicit( - ctx, TypeExpr::createImplicit(toType, ctx), argList); - - cs.cacheExprTypes(implicitInit->getFn()); - cs.setType(argExpr, fromType); - - auto *callLocator = cs.getConstraintLocator( - implicitInit, LocatorPathElt::ImplicitConversion(conversionKind)); - - // HACK: Temporarily push the call expr onto the expr stack to make sure - // we don't try to prematurely close an existential when applying the - // curried member ref. This can be removed once existential opening is - // refactored not to rely on the shape of the AST prior to rewriting. - ExprStack.push_back(implicitInit); - SWIFT_DEFER { ExprStack.pop_back(); }; - - // We need to take information recorded for all conversions of this - // kind and move it to a specific location where restriction is applied. - { - auto *memberLoc = solution.getConstraintLocator( - callLocator, {ConstraintLocator::ApplyFunction, - ConstraintLocator::ConstructorMember}); - - ConstraintLocator *baseLoc = - cs.getImplicitValueConversionLocator(locator, conversionKind); + DeclName name(ctx, DeclBaseName::createConstructor(), Identifier()); + + ConstructorDecl *decl = nullptr; + SmallVector candidates; + dc->lookupQualified(toType->getAnyNominal(), + DeclNameRef(name), SourceLoc(), + NL_QualifiedDefault, candidates); + for (auto *candidate : candidates) { + auto *ctor = cast(candidate); + auto fnType = ctor->getMethodInterfaceType()->castTo(); + if (fnType->getNumParams() == 1 && + fnType->getParams()[0].getPlainType()->isEqual(fromType) && + fnType->getResult()->isEqual(toType)) { + decl = ctor; + break; + } + } - auto overload = - solution.getOverloadChoice(solution.getConstraintLocator( - baseLoc, {ConstraintLocator::ApplyFunction, - ConstraintLocator::ConstructorMember})); + if (decl == nullptr) { + ctx.Diags.diagnose(expr->getLoc(), diag::broken_stdlib_type, + toType->getAnyNominal()->getName().str()); + auto *errorExpr = new (ctx) ErrorExpr(SourceRange(), toType); + cs.setType(errorExpr, toType); - solution.overloadChoices.insert({memberLoc, overload}); + return errorExpr; } - // Record the implicit call's parameter bindings and match direction. - solution.recordSingleArgMatchingChoice(callLocator); + auto *ctorRefExpr = new (ctx) DeclRefExpr(decl, DeclNameLoc(), /*Implicit=*/true); + ctorRefExpr->setType(decl->getInterfaceType()); + auto *typeExpr = TypeExpr::createImplicit(toType, ctx); + auto *innerCall = ConstructorRefCallExpr::create(ctx, ctorRefExpr, typeExpr, + decl->getMethodInterfaceType()); + cs.cacheExprTypes(innerCall); + + auto *argList = ArgumentList::forImplicitUnlabeled(ctx, {cs.coerceToRValue(expr)}); + auto *outerCall = CallExpr::createImplicit(ctx, innerCall, argList); + outerCall->setType(toType); + cs.setType(outerCall, toType); - finishApply(implicitInit, toType, callLocator, callLocator); - return implicitInit; + return outerCall; } } } diff --git a/lib/Sema/CSGen.cpp b/lib/Sema/CSGen.cpp index d8608b2e9dd82..45373b637cd7f 100644 --- a/lib/Sema/CSGen.cpp +++ b/lib/Sema/CSGen.cpp @@ -2683,7 +2683,7 @@ namespace { auto boolDecl = ctx.getBoolDecl(); if (!boolDecl) { - ctx.Diags.diagnose(SourceLoc(), diag::broken_bool); + ctx.Diags.diagnose(SourceLoc(), diag::broken_stdlib_type, "Bool"); return Type(); } diff --git a/lib/Sema/CSOptimizer.cpp b/lib/Sema/CSOptimizer.cpp index 54cec0224e60f..77f8ffaebd578 100644 --- a/lib/Sema/CSOptimizer.cpp +++ b/lib/Sema/CSOptimizer.cpp @@ -370,9 +370,23 @@ static void determineBestChoicesInContext( FunctionType::relabelParams(argsWithLabels, argumentList); } - SmallVector, 2>, 2> - candidateArgumentTypes; - candidateArgumentTypes.resize(argFuncType->getNumParams()); + struct ArgumentCandidate { + Type type; + // The candidate type is derived from a literal expression. + bool fromLiteral : 1; + // The candidate type is derived from a call to an + // initializer i.e. `Double(...)`. + bool fromInitializerCall : 1; + + ArgumentCandidate(Type type, bool fromLiteral = false, + bool fromInitializerCall = false) + : type(type), fromLiteral(fromLiteral), + fromInitializerCall(fromInitializerCall) {} + }; + + SmallVector, 2> + argumentCandidates; + argumentCandidates.resize(argFuncType->getNumParams()); llvm::TinyPtrVector resultTypes; @@ -380,12 +394,12 @@ static void determineBestChoicesInContext( const auto ¶m = argFuncType->getParams()[i]; auto argType = cs.simplifyType(param.getPlainType()); - SmallVector, 2> types; + SmallVector types; if (auto *typeVar = argType->getAs()) { auto bindingSet = cs.getBindingsFor(typeVar); for (const auto &binding : bindingSet.Bindings) { - types.push_back({binding.BindingType, /*fromLiteral=*/false}); + types.push_back({binding.BindingType}); } for (const auto &literal : bindingSet.Literals) { @@ -408,7 +422,8 @@ static void determineBestChoicesInContext( if (auto *typeExpr = dyn_cast(call->getFn())) { auto instanceTy = cs.getType(typeExpr)->getMetatypeInstanceType(); if (instanceTy->isDouble() || instanceTy->isCGFloat()) - types.push_back({instanceTy, /*fromLiteral=*/false}); + types.push_back({instanceTy, /*fromLiteral=*/false, + /*fromInitializerCall=*/true}); } } } @@ -416,7 +431,7 @@ static void determineBestChoicesInContext( types.push_back({argType, /*fromLiteral=*/false}); } - candidateArgumentTypes[i].append(types); + argumentCandidates[i].append(types); } auto resultType = cs.simplifyType(argFuncType->getResult()); @@ -437,9 +452,9 @@ static void determineBestChoicesInContext( argFuncType->getNumParams() > 0 && llvm::none_of( indices(argFuncType->getParams()), [&](const unsigned argIdx) { - auto &candidates = candidateArgumentTypes[argIdx]; + auto &candidates = argumentCandidates[argIdx]; return llvm::any_of(candidates, [&](const auto &candidate) { - return !candidate.second; + return !candidate.fromLiteral; }); }); @@ -846,7 +861,7 @@ static void determineBestChoicesInContext( auto argIdx = argIndices.front(); // Looks like there is nothing know about the argument. - if (candidateArgumentTypes[argIdx].empty()) + if (argumentCandidates[argIdx].empty()) continue; const auto paramFlags = param.getParameterFlags(); @@ -873,32 +888,25 @@ static void determineBestChoicesInContext( // at this parameter position and remove the overload choice // from consideration. double bestCandidateScore = 0; - llvm::BitVector mismatches(candidateArgumentTypes[argIdx].size()); + llvm::BitVector mismatches(argumentCandidates[argIdx].size()); for (unsigned candidateIdx : - indices(candidateArgumentTypes[argIdx])) { + indices(argumentCandidates[argIdx])) { // If one of the candidates matched exactly there is no reason // to continue checking. if (bestCandidateScore == 1) break; - Type candidateType; - bool isLiteralDefault; - - std::tie(candidateType, isLiteralDefault) = - candidateArgumentTypes[argIdx][candidateIdx]; + auto candidate = argumentCandidates[argIdx][candidateIdx]; // `inout` parameter accepts only l-value argument. - if (paramFlags.isInOut() && !candidateType->is()) { + if (paramFlags.isInOut() && !candidate.type->is()) { mismatches.set(candidateIdx); continue; } - // The specifier only matters for `inout` check. - candidateType = candidateType->getWithoutSpecifierType(); - MatchOptions options(MatchFlag::OnParam); - if (isLiteralDefault) + if (candidate.fromLiteral) options |= MatchFlag::Literal; if (favorExactMatchesOnly) options |= MatchFlag::ExactOnly; @@ -913,8 +921,16 @@ static void determineBestChoicesInContext( if (n == 1 && decl->isOperator()) options |= MatchFlag::DisableCGFloatDoubleConversion; + // Disable implicit CGFloat -> Double widening conversion if + // argument is an explicit call to `CGFloat` initializer. + if (candidate.type->isCGFloat() && + candidate.fromInitializerCall) + options |= MatchFlag::DisableCGFloatDoubleConversion; + + // The specifier for a candidate only matters for `inout` check. auto candidateScore = scoreCandidateMatch( - genericSig, decl, candidateType, paramType, options); + genericSig, decl, candidate.type->getWithoutSpecifierType(), + paramType, options); if (!candidateScore) continue; @@ -928,7 +944,7 @@ static void determineBestChoicesInContext( // Only established arguments could be considered mismatches, // literal default types should be regarded as holes if they // didn't match. - if (!isLiteralDefault && !candidateType->hasTypeVariable()) + if (!candidate.fromLiteral && !candidate.type->hasTypeVariable()) mismatches.set(candidateIdx); } diff --git a/lib/Sema/CSSimplify.cpp b/lib/Sema/CSSimplify.cpp index dbb0de6034d2c..e84c27bde5389 100644 --- a/lib/Sema/CSSimplify.cpp +++ b/lib/Sema/CSSimplify.cpp @@ -7646,6 +7646,22 @@ ConstraintSystem::matchTypes(Type type1, Type type2, ConstraintKind kind, } } + if (kind == ConstraintKind::BindToPointerType) { + if (desugar2->isEqual(getASTContext().TheEmptyTupleType)) + return getTypeMatchSuccess(); + } + + if (kind == ConstraintKind::BindParam) { + if (auto *iot = dyn_cast(desugar1)) { + if (auto *lvt = dyn_cast(desugar2)) { + return matchTypes(iot->getObjectType(), lvt->getObjectType(), + ConstraintKind::Bind, subflags, + locator.withPathElement( + ConstraintLocator::LValueConversion)); + } + } + } + if (kind >= ConstraintKind::Conversion) { // An lvalue of type T1 can be converted to a value of type T2 so long as // T1 is convertible to T2 (by loading the value). Note that we cannot get @@ -7777,7 +7793,7 @@ ConstraintSystem::matchTypes(Type type1, Type type2, ConstraintKind kind, } // Special implicit nominal conversions. - if (!type1->is() && kind >= ConstraintKind::Subtype) { + if (!type1->is()) { // Array -> Array. if (desugar1->isArray() && desugar2->isArray()) { conversionsOrFixes.push_back(ConversionRestrictionKind::ArrayUpcast); @@ -7793,11 +7809,6 @@ ConstraintSystem::matchTypes(Type type1, Type type2, ConstraintKind kind, } } - if (kind == ConstraintKind::BindToPointerType) { - if (desugar2->isEqual(getASTContext().TheEmptyTupleType)) - return getTypeMatchSuccess(); - } - if (kind >= ConstraintKind::Conversion) { // It is never legal to form an autoclosure that results in these // implicit conversions to pointer types. @@ -8054,17 +8065,6 @@ ConstraintSystem::matchTypes(Type type1, Type type2, ConstraintKind kind, } } - if (kind == ConstraintKind::BindParam) { - if (auto *iot = dyn_cast(desugar1)) { - if (auto *lvt = dyn_cast(desugar2)) { - return matchTypes(iot->getObjectType(), lvt->getObjectType(), - ConstraintKind::Bind, subflags, - locator.withPathElement( - ConstraintLocator::LValueConversion)); - } - } - } - // Matching types where one side is a pack expansion and the other is not // means a pack expansion was used where it isn't supported. if (type1->is() != type2->is()) { @@ -14263,17 +14263,6 @@ void ConstraintSystem::addRestrictedConstraint( TMF_GenerateConstraints, locator); } -void ConstraintSystem::recordImplicitValueConversion( - ConstraintLocator *locator, - ConversionRestrictionKind restriction) { - bool inserted = ImplicitValueConversions.insert( - {getConstraintLocator(locator), restriction}).second; - ASSERT(inserted); - - if (solverState) - recordChange(SolverTrail::Change::RecordedImplicitValueConversion(locator)); -} - /// Given that we have a conversion constraint between two types, and /// that the given constraint-reduction rule applies between them at /// the top level, apply it and generate any necessary recursive @@ -14850,45 +14839,6 @@ ConstraintSystem::simplifyRestrictedConstraintImpl( if (worseThanBestSolution()) return SolutionKind::Error; - auto *conversionLoc = - getImplicitValueConversionLocator(locator, restriction); - - auto *applicationLoc = - getConstraintLocator(conversionLoc, ConstraintLocator::ApplyFunction); - - auto *memberLoc = getConstraintLocator( - applicationLoc, ConstraintLocator::ConstructorMember); - - // Allocate a single argument info to cover all possible - // Double <-> CGFloat conversion locations. - auto *argumentsLoc = - getConstraintLocator(conversionLoc, ConstraintLocator::ApplyArgument); - - if (!ArgumentLists.count(argumentsLoc)) { - auto *argList = ArgumentList::createImplicit( - getASTContext(), {Argument(SourceLoc(), Identifier(), nullptr)}, - /*firstTrailingClosureIndex=*/std::nullopt, - AllocationArena::ConstraintSolver); - recordArgumentList(argumentsLoc, argList); - } - - auto *memberTypeLoc = getConstraintLocator( - applicationLoc, LocatorPathElt::ConstructorMemberType()); - - auto *memberTy = createTypeVariable(memberTypeLoc, TVO_CanBindToNoEscape); - - addValueMemberConstraint(MetatypeType::get(type2, getASTContext()), - DeclNameRef(DeclBaseName::createConstructor()), - memberTy, DC, - FunctionRefInfo::doubleBaseNameApply(), - /*outerAlternatives=*/{}, memberLoc); - - addConstraint(ConstraintKind::ApplicableFunction, - FunctionType::get({FunctionType::Param(type1)}, type2), - memberTy, applicationLoc); - - ImplicitValueConversions.insert( - {getConstraintLocator(locator), restriction}); return SolutionKind::Solved; } } diff --git a/lib/Sema/CSSolver.cpp b/lib/Sema/CSSolver.cpp index ebf9d57ea7ae2..ccbecb4247e0a 100644 --- a/lib/Sema/CSSolver.cpp +++ b/lib/Sema/CSSolver.cpp @@ -243,11 +243,6 @@ Solution ConstraintSystem::finalize() { solution.appliedPropertyWrappers.insert(appliedWrapper); } - // Remember implicit value conversions. - for (const auto &valueConversion : ImplicitValueConversions) { - solution.ImplicitValueConversions.push_back(valueConversion); - } - // Remember argument lists. for (const auto &argListMapping : ArgumentLists) { solution.argumentLists.insert(argListMapping); @@ -445,13 +440,6 @@ void ConstraintSystem::replaySolution(const Solution &solution, } } - for (auto &valueConversion : solution.ImplicitValueConversions) { - if (ImplicitValueConversions.count(valueConversion.first) == 0) { - recordImplicitValueConversion(valueConversion.first, - valueConversion.second); - } - } - // Register the argument lists. for (auto &argListMapping : solution.argumentLists) { if (ArgumentLists.count(argListMapping.first) == 0) diff --git a/lib/Sema/CodeSynthesis.cpp b/lib/Sema/CodeSynthesis.cpp index 8b06ce3dcd2fe..f58c2c189954a 100644 --- a/lib/Sema/CodeSynthesis.cpp +++ b/lib/Sema/CodeSynthesis.cpp @@ -1335,9 +1335,8 @@ static bool shouldAttemptInitializerSynthesis(const NominalTypeDecl *decl) { return false; // Don't add implicit constructors in module interfaces. - if (auto *SF = decl->getParentSourceFile()) - if (SF->Kind == SourceFileKind::Interface) - return false; + if (decl->getDeclContext()->isInSwiftinterface()) + return false; // Don't attempt if we know the decl is invalid. if (decl->isInvalid()) diff --git a/lib/Sema/TypeCheckAttr.cpp b/lib/Sema/TypeCheckAttr.cpp index 41a01b99b8ac2..d2ae23fed19da 100644 --- a/lib/Sema/TypeCheckAttr.cpp +++ b/lib/Sema/TypeCheckAttr.cpp @@ -2396,8 +2396,7 @@ void AttributeChecker::visitAvailableAttr(AvailableAttr *parsedAttr) { // Skip the remaining diagnostics in swiftinterfaces. auto *DC = D->getDeclContext(); - auto *SF = DC->getParentSourceFile(); - if (SF && SF->Kind == SourceFileKind::Interface) + if (DC->isInSwiftinterface()) return; // The remaining diagnostics are only for attributes that are active. @@ -4549,8 +4548,7 @@ void AttributeChecker::visitCustomAttr(CustomAttr *attr) { // Module interfaces don't print bodies for all getters, so allow getters // that don't have a body if we're compiling a module interface. // Within a protocol definition, there will never be a body. - SourceFile *parent = storage->getDeclContext()->getParentSourceFile(); - bool isInInterface = parent && parent->Kind == SourceFileKind::Interface; + bool isInInterface = storage->getDeclContext()->isInSwiftinterface(); if (!isInInterface && !getter->hasBody() && !isa(storage->getDeclContext())) return true; @@ -5262,9 +5260,7 @@ TypeChecker::diagnosticIfDeclCannotBePotentiallyUnavailable(const Decl *D) { // An enum element with an associated value cannot be potentially // unavailable. if (EED->hasAssociatedValues()) { - auto *SF = DC->getParentSourceFile(); - - if (SF->Kind == SourceFileKind::Interface) { + if (DC->isInSwiftinterface()) { return diag::availability_enum_element_no_potential_warn; } else { return diag::availability_enum_element_no_potential; @@ -7885,8 +7881,7 @@ void AttributeChecker::visitMacroRoleAttr(MacroRoleAttr *attr) { break; case MacroRole::Conformance: { // Suppress the conformance macro error in swiftinterfaces. - SourceFile *file = D->getDeclContext()->getParentSourceFile(); - if (file && file->Kind == SourceFileKind::Interface) + if (D->getDeclContext()->isInSwiftinterface()) break; diagnoseAndRemoveAttr(attr, diag::conformance_macro) diff --git a/lib/Sema/TypeCheckConcurrency.cpp b/lib/Sema/TypeCheckConcurrency.cpp index 224d110a7a764..8b12bdfe763a1 100644 --- a/lib/Sema/TypeCheckConcurrency.cpp +++ b/lib/Sema/TypeCheckConcurrency.cpp @@ -4821,9 +4821,7 @@ getIsolationFromAttributes(const Decl *decl, bool shouldDiagnose = true, bool isUnsafe = attr->isArgUnsafe(); if (attr->hasArgs()) { if (isUnsafe) { - SourceFile *file = decl->getDeclContext()->getParentSourceFile(); - bool inSwiftinterface = - file && file->Kind == SourceFileKind::Interface; + bool inSwiftinterface = decl->getDeclContext()->isInSwiftinterface(); ctx.Diags.diagnose( attr->getLocation(), diag::unsafe_global_actor) diff --git a/lib/Sema/TypeCheckDecl.cpp b/lib/Sema/TypeCheckDecl.cpp index 49cadfc8507ca..2c67dcc76f4f8 100644 --- a/lib/Sema/TypeCheckDecl.cpp +++ b/lib/Sema/TypeCheckDecl.cpp @@ -1201,8 +1201,7 @@ EnumRawValuesRequest::evaluate(Evaluator &eval, EnumDecl *ED, // values are intentionally omitted from them (unless the enum is @objc). // Without bailing here, incorrect raw values can be automatically generated // and incorrect diagnostics may be omitted for some decls. - SourceFile *Parent = ED->getDeclContext()->getParentSourceFile(); - if (Parent && Parent->Kind == SourceFileKind::Interface && !ED->isObjC()) + if (ED->getDeclContext()->isInSwiftinterface() && !ED->isObjC()) return std::make_tuple<>(); if (!computeAutomaticEnumValueKind(ED)) { diff --git a/lib/Sema/TypeCheckDeclObjC.cpp b/lib/Sema/TypeCheckDeclObjC.cpp index 283dbde74adfb..abc16df173137 100644 --- a/lib/Sema/TypeCheckDeclObjC.cpp +++ b/lib/Sema/TypeCheckDeclObjC.cpp @@ -936,7 +936,7 @@ bool swift::isRepresentableInObjC( boolDecl = ctx.getBoolDecl(); if (boolDecl == nullptr) { - AFD->diagnose(diag::broken_bool); + AFD->diagnose(diag::broken_stdlib_type, "Bool"); return false; } diff --git a/lib/Sema/TypeCheckDeclPrimary.cpp b/lib/Sema/TypeCheckDeclPrimary.cpp index ebac87e9b9fd9..334f15f6b690d 100644 --- a/lib/Sema/TypeCheckDeclPrimary.cpp +++ b/lib/Sema/TypeCheckDeclPrimary.cpp @@ -1152,8 +1152,7 @@ static void checkInheritedDefaultValueRestrictions(ParamDecl *PD) { assert(PD->getDefaultArgumentKind() == DefaultArgumentKind::Inherited); auto *DC = PD->getInnermostDeclContext(); - const SourceFile *SF = DC->getParentSourceFile(); - assert((SF && SF->Kind == SourceFileKind::Interface || PD->isImplicit()) && + assert((DC->isInSwiftinterface() || PD->isImplicit()) && "explicit inherited default argument outside of a module interface?"); // The containing decl should be a designated initializer. @@ -1807,7 +1806,7 @@ static void diagnoseRetroactiveConformances( } // Don't warn for this if we see it in module interfaces. - if (ext->getParentSourceFile()->Kind == SourceFileKind::Interface) { + if (ext->getDeclContext()->isInSwiftinterface()) { return; } @@ -2557,9 +2556,8 @@ class DeclChecker : public DeclVisitor { // This allows the compiler to process existing .swiftinterface // files that contain this issue. if (resultType->isVoid()) { - if (auto sourceFile = MD->getParentSourceFile()) - if (sourceFile->Kind == SourceFileKind::Interface) - diag.limitBehavior(DiagnosticBehavior::Warning); + if (MD->getDeclContext()->isInSwiftinterface()) + diag.limitBehavior(DiagnosticBehavior::Warning); } } @@ -3332,8 +3330,7 @@ class DeclChecker : public DeclVisitor { void checkRequiredInClassInits(ClassDecl *cd) { // Initializers may be omitted from property declarations in module // interface files so don't diagnose in them. - SourceFile *sourceFile = cd->getDeclContext()->getParentSourceFile(); - if (sourceFile && sourceFile->Kind == SourceFileKind::Interface) + if (cd->getDeclContext()->isInSwiftinterface()) return; ClassDecl *source = nullptr; diff --git a/lib/Sema/TypeCheckDistributed.cpp b/lib/Sema/TypeCheckDistributed.cpp index aa470639a7532..319d14b3ac8f7 100644 --- a/lib/Sema/TypeCheckDistributed.cpp +++ b/lib/Sema/TypeCheckDistributed.cpp @@ -669,16 +669,16 @@ bool swift::checkDistributedActorProperty(VarDecl *var, bool diagnose) { void swift::checkDistributedActorProperties(const NominalTypeDecl *decl) { auto &C = decl->getASTContext(); - if (auto sourceFile = decl->getDeclContext()->getParentSourceFile()) { - if (sourceFile->Kind == SourceFileKind::Interface) { - // Don't diagnose properties in swiftinterfaces. - return; - } - } else { + if (!decl->getDeclContext()->getParentSourceFile()) { // Don't diagnose when checking without source file (e.g. from module, importer etc). return; } + if (decl->getDeclContext()->isInSwiftinterface()) { + // Don't diagnose properties in swiftinterfaces. + return; + } + if (isa(decl)) { // protocols don't matter for stored property checking return; diff --git a/lib/Sema/TypeCheckProtocol.cpp b/lib/Sema/TypeCheckProtocol.cpp index 5b735118056ce..c8051ad0aed73 100644 --- a/lib/Sema/TypeCheckProtocol.cpp +++ b/lib/Sema/TypeCheckProtocol.cpp @@ -1670,16 +1670,14 @@ bool WitnessChecker::findBestWitness( // interface can be treated as opaque. // FIXME: ...but we should do something better about types. if (conformance && !conformance->isInvalid()) { - if (auto *SF = DC->getParentSourceFile()) { - if (SF->Kind == SourceFileKind::Interface) { - auto match = matchWitness(ReqEnvironmentCache, Proto, - conformance, DC, requirement, requirement); - if (match.isViable()) { - numViable = 1; - bestIdx = matches.size(); - matches.push_back(std::move(match)); - return true; - } + if (DC->isInSwiftinterface()) { + auto match = matchWitness(ReqEnvironmentCache, Proto, conformance, DC, + requirement, requirement); + if (match.isViable()) { + numViable = 1; + bestIdx = matches.size(); + matches.push_back(std::move(match)); + return true; } } } @@ -4651,8 +4649,7 @@ ResolveWitnessResult ConformanceChecker::resolveWitnessViaDerivation( ValueDecl *requirement) { assert(!isa(requirement) && "Use resolveTypeWitnessVia*"); - auto *SF = DC->getParentSourceFile(); - if (SF != nullptr && SF->Kind == SourceFileKind::Interface) + if (DC->isInSwiftinterface()) return ResolveWitnessResult::Missing; // Find the declaration that derives the protocol conformance. diff --git a/lib/Sema/TypeCheckStorage.cpp b/lib/Sema/TypeCheckStorage.cpp index 0f652782fc86d..e1cea39078dfb 100644 --- a/lib/Sema/TypeCheckStorage.cpp +++ b/lib/Sema/TypeCheckStorage.cpp @@ -478,11 +478,8 @@ const PatternBindingEntry *PatternBindingEntryRequest::evaluate( if (isReq) { continue; } - auto varSourceFile = binding->getDeclContext()->getParentSourceFile(); - auto isVarInInterfaceFile = - varSourceFile && varSourceFile->Kind == SourceFileKind::Interface; // Don't diagnose too strictly for textual interfaces. - if (isVarInInterfaceFile) { + if (binding->getDeclContext()->isInSwiftinterface()) { continue; } // var is only allowed in a protocol. @@ -3625,14 +3622,12 @@ static void finishNSManagedImplInfo(VarDecl *var, if (var->isLet()) diagnoseAttrWithRemovalFixIt(var, attr, diag::attr_NSManaged_let_property); - SourceFile *parentFile = var->getDeclContext()->getParentSourceFile(); - auto diagnoseNotStored = [&](unsigned kind) { // Skip diagnosing @NSManaged declarations in module interfaces. They are // properties that are stored, but have specially synthesized observers // and we should allow them to have getters and setters in a module // interface. - if (parentFile && parentFile->Kind == SourceFileKind::Interface) + if (var->getDeclContext()->isInSwiftinterface()) return; diagnoseAttrWithRemovalFixIt(var, attr, diag::attr_NSManaged_not_stored, kind); diff --git a/lib/Sema/TypeCheckType.cpp b/lib/Sema/TypeCheckType.cpp index 9e9d658a5e87a..f76321d16242f 100644 --- a/lib/Sema/TypeCheckType.cpp +++ b/lib/Sema/TypeCheckType.cpp @@ -2266,8 +2266,7 @@ namespace { } bool isInterfaceFile() const { - auto SF = getDeclContext()->getParentSourceFile(); - return (SF && SF->Kind == SourceFileKind::Interface); + return getDeclContext()->isInSwiftinterface(); } /// Short-hand to query the current stage of type resolution. @@ -6464,8 +6463,7 @@ void TypeChecker::checkExistentialTypes(Decl *decl) { return; // Skip diagnosing existential `any` requirements in swiftinterfaces. - auto sourceFile = decl->getDeclContext()->getParentSourceFile(); - if (sourceFile && sourceFile->Kind == SourceFileKind::Interface) + if (decl->getDeclContext()->isInSwiftinterface()) return; auto &ctx = decl->getASTContext(); @@ -6513,8 +6511,7 @@ void TypeChecker::checkExistentialTypes(ASTContext &ctx, Stmt *stmt, return; // Skip diagnosing existential `any` requirements in swiftinterfaces. - auto sourceFile = DC->getParentSourceFile(); - if (sourceFile && sourceFile->Kind == SourceFileKind::Interface) + if (DC->isInSwiftinterface()) return; // Previously we missed this diagnostic on 'catch' statements, downgrade diff --git a/lib/Serialization/Serialization.cpp b/lib/Serialization/Serialization.cpp index 644a794057f95..acb5dd09da641 100644 --- a/lib/Serialization/Serialization.cpp +++ b/lib/Serialization/Serialization.cpp @@ -3599,9 +3599,7 @@ class Serializer::DeclSerializer : public DeclVisitor { // Everything should be safe in a swiftinterface. So, don't emit any safety // record when building a swiftinterface in release builds. Debug builds // instead print inconsistencies. - auto parentSF = DC->getParentSourceFile(); - bool fromModuleInterface = parentSF && - parentSF->Kind == SourceFileKind::Interface; + bool fromModuleInterface = DC->isInSwiftinterface(); #if NDEBUG if (fromModuleInterface) return; diff --git a/stdlib/CMakeLists.txt b/stdlib/CMakeLists.txt index 1d8e818e793f4..9768a59a21ff1 100644 --- a/stdlib/CMakeLists.txt +++ b/stdlib/CMakeLists.txt @@ -228,12 +228,6 @@ swift_create_stdlib_targets("swift-test-stdlib" "" FALSE) swift_create_stdlib_targets("swift-libexec" "" TRUE) swift_create_stdlib_targets("swift-test-libexec" "" FALSE) -# Check whether the Swift compiler we're using supports -# -disable-implicit-backtracing-module-import -include(SwiftCompilerCapability) - -swift_supports_implicit_module("backtracing" SWIFT_COMPILER_SUPPORTS_BACKTRACING) - # FIXME: Include the toolchain directory before the public directory. Otherwise # the clang resource directory symlink stops installing correctly. add_subdirectory(toolchain) diff --git a/stdlib/cmake/modules/AddSwiftStdlib.cmake b/stdlib/cmake/modules/AddSwiftStdlib.cmake index 130a1470393be..c76cf96aa9152 100644 --- a/stdlib/cmake/modules/AddSwiftStdlib.cmake +++ b/stdlib/cmake/modules/AddSwiftStdlib.cmake @@ -2091,11 +2091,6 @@ function(add_swift_target_library name) # Turn off implicit import of _StringProcessing when building libraries list(APPEND SWIFTLIB_SWIFT_COMPILE_FLAGS "-Xfrontend;-disable-implicit-string-processing-module-import") - # Turn off implicit import of _Backtracing when building libraries - if(SWIFT_COMPILER_SUPPORTS_BACKTRACING) - list(APPEND SWIFTLIB_SWIFT_COMPILE_FLAGS "-Xfrontend;-disable-implicit-backtracing-module-import") - endif() - if(SWIFTLIB_IS_STDLIB AND SWIFT_STDLIB_ENABLE_PRESPECIALIZATION) list(APPEND SWIFTLIB_SWIFT_COMPILE_FLAGS "-Xfrontend;-prespecialize-generic-metadata") endif() @@ -3126,10 +3121,6 @@ function(add_swift_target_executable name) "-Xfrontend;-disable-implicit-string-processing-module-import") endif() - if(SWIFT_IMPLICIT_BACKTRACING_IMPORT) - list(APPEND SWIFTEXE_TARGET_COMPILE_FLAGS "-Xfrontend;-disable-implicit-backtracing-module-import") - endif() - if(SWIFT_BUILD_STDLIB) # All Swift executables depend on the standard library. list(APPEND SWIFTEXE_TARGET_SWIFT_MODULE_DEPENDS Core) diff --git a/stdlib/public/Backtracing/ArrayImageSource.swift b/stdlib/public/Backtracing/ArrayImageSource.swift deleted file mode 100644 index e9266806cb243..0000000000000 --- a/stdlib/public/Backtracing/ArrayImageSource.swift +++ /dev/null @@ -1,48 +0,0 @@ -//===--- ArrayImageSource.swift - An image source backed by an Array -------===// -// -// This source file is part of the Swift.org open source project -// -// Copyright (c) 2023 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 -// -//===----------------------------------------------------------------------===// -// -// Defines ArrayImageSource, an image source that is backed by a Swift Array. -// -//===----------------------------------------------------------------------===// - -import Swift - -enum ArrayImageSourceError: Error { - case outOfBoundsRead(UInt64, UInt64) -} - -struct ArrayImageSource: ImageSource { - private var array: Array - - public init(array: Array) { - self.array = array - } - - public var isMappedImage: Bool { return false } - public var path: String? { return nil } - public var bounds: Bounds? { - return Bounds(base: 0, size: Size(array.count * MemoryLayout.stride)) - } - - public func fetch(from addr: Address, - into buffer: UnsafeMutableRawBufferPointer) throws { - try array.withUnsafeBytes{ - let size = Size($0.count) - let requested = Size(buffer.count) - if addr > size || requested > size - addr { - throw ArrayImageSourceError.outOfBoundsRead(addr, requested) - } - - buffer.copyBytes(from: $0[Int(addr).. String { - switch self { - case let .programCounter(addr): - return "\(hex(addr, width: width))" - case let .returnAddress(addr): - return "\(hex(addr, width: width)) [ra]" - case let .asyncResumePoint(addr): - return "\(hex(addr, width: width)) [async]" - case .omittedFrames(_), .truncated: - return "..." - } - } - - /// A textual description of this frame. - public var description: String { - return description(width: MemoryLayout
.size * 2) - } - } - - /// Represents an image loaded in the process's address space - public struct Image: CustomStringConvertible, Sendable { - /// The name of the image (e.g. libswiftCore.dylib). - public var name: String - - /// The full path to the image (e.g. /usr/lib/swift/libswiftCore.dylib). - public var path: String - - /// The build ID of the image, as a byte array (note that the exact number - /// of bytes may vary, and that some images may not have a build ID). - public var buildID: [UInt8]? - - /// The base address of the image. - public var baseAddress: Backtrace.Address - - /// The end of the text segment in this image. - public var endOfText: Backtrace.Address - - /// Provide a textual description of an Image. - public func description(width: Int) -> String { - if let buildID = self.buildID { - return "\(hex(baseAddress, width: width))-\(hex(endOfText, width: width)) \(hex(buildID)) \(name) \(path)" - } else { - return "\(hex(baseAddress, width: width))-\(hex(endOfText, width: width)) \(name) \(path)" - } - } - - /// A textual description of an Image. - public var description: String { - return description(width: MemoryLayout
.size * 2) - } - } - - /// The architecture of the system that captured this backtrace. - public var architecture: String - - /// The width of an address in this backtrace, in bits. - public var addressWidth: Int - - /// A list of captured frame information. - public var frames: [Frame] - - /// A list of captured images. - /// - /// Some backtracing algorithms may require this information, in which case - /// it will be filled in by the `capture()` method. Other algorithms may - /// not, in which case it will be `nil` and you can capture an image list - /// separately yourself using `captureImages()`. - public var images: [Image]? - - /// Holds information about the shared cache. - public struct SharedCacheInfo: Sendable { - /// The UUID from the shared cache. - public var uuid: [UInt8] - - /// The base address of the shared cache. - public var baseAddress: Backtrace.Address - - /// Says whether there is in fact a shared cache. - public var noCache: Bool - } - - /// Information about the shared cache. - /// - /// Holds information about the shared cache. On Darwin only, this is - /// required for symbolication. On non-Darwin platforms it will always - /// be `nil`. - public var sharedCacheInfo: SharedCacheInfo? - - /// Format an address according to the addressWidth. - /// - /// @param address The address to format. - /// @param prefix Whether to include a "0x" prefix. - /// - /// @returns A String containing the formatted Address. - public func formatAddress(_ address: Address, - prefix: Bool = true) -> String { - return hex(address, prefix: prefix, width: (addressWidth + 3) / 4) - } - - /// Capture a backtrace from the current program location. - /// - /// The `capture()` method itself will not be included in the backtrace; - /// i.e. the first frame will be the one in which `capture()` was called, - /// and its programCounter value will be the return address for the - /// `capture()` method call. - /// - /// @param algorithm Specifies which unwind mechanism to use. If this - /// is set to `.auto`, we will use the platform default. - /// @param limit The backtrace will include at most this number of - /// frames; you can set this to `nil` to remove the - /// limit completely if required. - /// @param offset Says how many frames to skip; this makes it easy to - /// wrap this API without having to inline things and - /// without including unnecessary frames in the backtrace. - /// @param top Sets the minimum number of frames to capture at the - /// top of the stack. - /// - /// @returns A new `Backtrace` struct. - @inline(never) - @_semantics("use_frame_pointer") - public static func capture(algorithm: UnwindAlgorithm = .auto, - limit: Int? = 64, - offset: Int = 0, - top: Int = 16) throws -> Backtrace { - #if os(Linux) - let images = captureImages() - #else - let images: [Image]? = nil - #endif - - // N.B. We use offset+1 here to skip this frame, rather than inlining - // this code into the client. - return try HostContext.withCurrentContext { ctx in - try capture(from: ctx, - using: UnsafeLocalMemoryReader(), - images: images, - algorithm: algorithm, - limit: limit, - offset: offset + 1, - top: top) - } - } - - @_spi(Internal) - public static func capture( - from context: Ctx, - using memoryReader: Rdr, - images: [Image]?, - algorithm: UnwindAlgorithm = .auto, - limit: Int? = 64, - offset: Int = 0, - top: Int = 16 - ) throws -> Backtrace { - let addressWidth = 8 * MemoryLayout.size - - switch algorithm { - // All of them, for now, use the frame pointer unwinder. In the long - // run, we should be using DWARF EH frame data for .precise. - case .auto, .fast, .precise: - let unwinder = - FramePointerUnwinder(context: context, - images: images, - memoryReader: memoryReader) - .dropFirst(offset) - - if let limit = limit { - if limit <= 0 { - return Backtrace(architecture: context.architecture, - addressWidth: addressWidth, - frames: [.truncated]) - } - - let realTop = top < limit ? top : limit - 1 - var iterator = unwinder.makeIterator() - var frames: [Frame] = [] - - // Capture frames normally until we hit limit - while let frame = iterator.next() { - if frames.count < limit { - frames.append(frame) - if frames.count == limit { - break - } - } - } - - if realTop == 0 { - if let _ = iterator.next() { - // More frames than we were asked for; replace the last - // one with a discontinuity - frames[limit - 1] = .truncated - } - - return Backtrace(architecture: context.architecture, - addressWidth: addressWidth, - frames: frames) - } else { - - // If we still have frames at this point, start tracking the - // last `realTop` frames in a circular buffer. - if let frame = iterator.next() { - let topSection = limit - realTop - var topFrames: [Frame] = [] - var topNdx = 0 - var omittedFrames = 0 - - topFrames.reserveCapacity(realTop) - topFrames.insert(contentsOf: frames.suffix(realTop - 1), at: 0) - topFrames.append(frame) - - while let frame = iterator.next() { - topFrames[topNdx] = frame - topNdx += 1 - omittedFrames += 1 - if topNdx >= realTop { - topNdx = 0 - } - } - - // Fix the backtrace to include a discontinuity followed by - // the contents of the circular buffer. - let firstPart = realTop - topNdx - let secondPart = topNdx - frames[topSection - 1] = .omittedFrames(omittedFrames) - - frames.replaceSubrange(topSection..<(topSection+firstPart), - with: topFrames.suffix(firstPart)) - frames.replaceSubrange((topSection+firstPart).. [Image] { - #if os(macOS) || os(iOS) || os(watchOS) || os(tvOS) - return captureImages(for: mach_task_self()) - #else - return captureImages(using: UnsafeLocalMemoryReader()) - #endif - } - - #if os(macOS) || os(iOS) || os(watchOS) || os(tvOS) - private static func withDyldProcessInfo(for task: task_t, - fn: (OpaquePointer?) throws -> T) - rethrows -> T { - var kret = kern_return_t(KERN_SUCCESS) - let dyldInfo = _dyld_process_info_create(task, 0, &kret) - - if kret != KERN_SUCCESS { - fatalError("error: cannot create dyld process info") - } - - defer { - _dyld_process_info_release(dyldInfo) - } - - return try fn(dyldInfo) - } - #endif - - #if os(macOS) || os(iOS) || os(watchOS) || os(tvOS) - @_spi(Internal) - public static func captureImages(for process: Any) -> [Image] { - var images: [Image] = [] - let task = process as! task_t - - withDyldProcessInfo(for: task) { dyldInfo in - _dyld_process_info_for_each_image(dyldInfo) { - (machHeaderAddress, uuid, path) in - - if let path = path, let uuid = uuid { - let pathString = String(cString: path) - let theUUID = Array(UnsafeBufferPointer(start: uuid, - count: MemoryLayout.size)) - let name: String - if let slashIndex = pathString.lastIndex(of: "/") { - name = String(pathString.suffix(from: - pathString.index(after:slashIndex))) - } else { - name = pathString - } - - // Find the end of the __TEXT segment - var endOfText = machHeaderAddress + 4096 - - _dyld_process_info_for_each_segment(dyldInfo, machHeaderAddress) { - address, size, name in - - if let name = String(validatingCString: name!), name == "__TEXT" { - endOfText = address + size - } - } - - images.append(Image(name: name, - path: pathString, - buildID: theUUID, - baseAddress: Address(machHeaderAddress), - endOfText: Address(endOfText))) - } - } - } - - return images.sorted(by: { $0.baseAddress < $1.baseAddress }) - } - #else // !(os(macOS) || os(iOS) || os(tvOS) || os(watchOS)) - private struct AddressRange { - var low: Address = 0 - var high: Address = 0 - } - - @_spi(Internal) - public static func captureImages(using reader: M, - forProcess pid: Int? = nil) -> [Image] { - var images: [Image] = [] - - #if os(Linux) - let path: String - if let pid = pid { - path = "/proc/\(pid)/maps" - } else { - path = "/proc/self/maps" - } - - guard let procMaps = readString(from: path) else { - return [] - } - - // Find all the mapped files and get high/low ranges - var mappedFiles: [Substring:AddressRange] = [:] - for match in ProcMapsScanner(procMaps) { - let path = stripWhitespace(match.pathname) - if match.inode == "0" || path == "" { - continue - } - guard let start = Address(match.start, radix: 16), - let end = Address(match.end, radix: 16) else { - continue - } - - if let range = mappedFiles[path] { - mappedFiles[path] = AddressRange(low: min(start, range.low), - high: max(end, range.high)) - } else { - mappedFiles[path] = AddressRange(low: start, - high: end) - } - } - - // Look for ELF headers in the process' memory - typealias Source = MemoryImageSource - let source = Source(with: reader) - for match in ProcMapsScanner(procMaps) { - let path = stripWhitespace(match.pathname) - if match.inode == "0" || path == "" { - continue - } - - guard let start = Address(match.start, radix: 16), - let end = Address(match.end, radix: 16), - let offset = Address(match.offset, radix: 16) else { - continue - } - - if offset != 0 || end - start < EI_NIDENT { - continue - } - - // Extract the filename from path - let name: Substring - if let slashIndex = path.lastIndex(of: "/") { - name = path.suffix(from: path.index(after: slashIndex)) - } else { - name = path - } - - // Inspect the image and extract the UUID and end of text - let range = mappedFiles[path]! - let subSource = SubImageSource(parent: source, - baseAddress: Source.Address(range.low), - length: Source.Size(range.high - - range.low)) - var theUUID: [UInt8]? = nil - var endOfText: Address = range.low - - if let image = try? Elf32Image(source: subSource) { - theUUID = image.uuid - - for hdr in image.programHeaders { - if hdr.p_type == .PT_LOAD && (hdr.p_flags & PF_X) != 0 { - endOfText = max(endOfText, range.low + Address(hdr.p_vaddr - + hdr.p_memsz)) - } - } - } else if let image = try? Elf64Image(source: subSource) { - theUUID = image.uuid - - for hdr in image.programHeaders { - if hdr.p_type == .PT_LOAD && (hdr.p_flags & PF_X) != 0 { - endOfText = max(endOfText, range.low + Address(hdr.p_vaddr - + hdr.p_memsz)) - } - } - } else { - // Not a valid ELF image - continue - } - - let image = Image(name: String(name), - path: String(path), - buildID: theUUID, - baseAddress: range.low, - endOfText: endOfText) - - images.append(image) - } - #endif - - return images.sorted(by: { $0.baseAddress < $1.baseAddress }) - } - #endif - - /// Capture shared cache information. - /// - /// @returns A `SharedCacheInfo`. - public static func captureSharedCacheInfo() -> SharedCacheInfo? { - #if os(macOS) || os(iOS) || os(watchOS) || os(tvOS) - return captureSharedCacheInfo(for: mach_task_self()) - #else - return nil - #endif - } - - @_spi(Internal) - public static func captureSharedCacheInfo(for t: Any) -> SharedCacheInfo? { - #if os(macOS) || os(iOS) || os(watchOS) || os(tvOS) - let task = t as! task_t - return withDyldProcessInfo(for: task) { dyldInfo in - var cacheInfo = dyld_process_cache_info() - _dyld_process_info_get_cache(dyldInfo, &cacheInfo) - let theUUID = withUnsafePointer(to: cacheInfo.cacheUUID) { - Array(UnsafeRawBufferPointer(start: $0, - count: MemoryLayout.size)) - } - return SharedCacheInfo(uuid: theUUID, - baseAddress: Address(cacheInfo.cacheBaseAddress), - noCache: cacheInfo.noCache) - } - #else // !os(Darwin) - return nil - #endif - } - - /// Return a symbolicated version of the backtrace. - /// - /// @param images Specifies the set of images to use for symbolication. - /// If `nil`, the function will look to see if the `Backtrace` - /// has already captured images. If it has, those will be - /// used; otherwise we will capture images at this point. - /// - /// @param sharedCacheInfo Provides information about the location and - /// identity of the shared cache, if applicable. - /// - /// @param showInlineFrames If `true` and we know how on the platform we're - /// running on, add virtual frames to show inline - /// function calls. - /// - /// @param showSourceLocation If `true`, look up the source location for - /// each address. - /// - /// @param useSymbolCache If the system we are on has a symbol cache, - /// says whether or not to use it. - /// - /// @returns A new `SymbolicatedBacktrace`. - public func symbolicated(with images: [Image]? = nil, - sharedCacheInfo: SharedCacheInfo? = nil, - showInlineFrames: Bool = true, - showSourceLocations: Bool = true, - useSymbolCache: Bool = true) - -> SymbolicatedBacktrace? { - return SymbolicatedBacktrace.symbolicate( - backtrace: self, - images: images, - sharedCacheInfo: sharedCacheInfo, - showInlineFrames: showInlineFrames, - showSourceLocations: showSourceLocations, - useSymbolCache: useSymbolCache - ) - } - - /// Provide a textual version of the backtrace. - public var description: String { - var lines: [String] = [] - let addressChars = (addressWidth + 3) / 4 - - var n = 0 - for frame in frames { - lines.append("\(n)\t\(frame.description(width: addressChars))") - switch frame { - case let .omittedFrames(count): - n += count - default: - n += 1 - } - } - - if let images = images { - lines.append("") - lines.append("Images:") - lines.append("") - for (n, image) in images.enumerated() { - lines.append("\(n)\t\(image.description(width: addressChars))") - } - } - - #if os(macOS) || os(iOS) || os(tvOS) || os(watchOS) - if let sharedCacheInfo = sharedCacheInfo { - lines.append("") - lines.append("Shared Cache:") - lines.append("") - lines.append(" UUID: \(hex(sharedCacheInfo.uuid))") - lines.append(" Base: \(hex(sharedCacheInfo.baseAddress, width: addressChars))") - lines.append(" Active: \(!sharedCacheInfo.noCache)") - } - #endif - - return lines.joined(separator: "\n") - } -} diff --git a/stdlib/public/Backtracing/FileImageSource.swift b/stdlib/public/Backtracing/FileImageSource.swift deleted file mode 100644 index 7a5e36709e211..0000000000000 --- a/stdlib/public/Backtracing/FileImageSource.swift +++ /dev/null @@ -1,81 +0,0 @@ -//===--- FileImageSource.swift - An image source that reads from a file ---===// -// -// This source file is part of the Swift.org open source project -// -// Copyright (c) 2023 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 -// -//===----------------------------------------------------------------------===// -// -// Defines FileImageSource, an image source that reads data from a file. -// -//===----------------------------------------------------------------------===// - -import Swift - -#if os(macOS) || os(iOS) || os(tvOS) || os(watchOS) -internal import Darwin -#elseif os(Windows) -internal import ucrt -#elseif canImport(Glibc) -internal import Glibc -#elseif canImport(Musl) -internal import Musl -#endif - -enum FileImageSourceError: Error { - case posixError(Int32) - case outOfRangeRead -} - -class FileImageSource: ImageSource { - private var _mapping: UnsafeRawBufferPointer - - public var isMappedImage: Bool { return false } - - private var _path: String - public var path: String? { return _path } - - public var bounds: Bounds? { - return Bounds(base: 0, size: Size(_mapping.count)) - } - - public init(path: String) throws { - _path = path - let fd = open(path, O_RDONLY, 0) - if fd < 0 { - throw FileImageSourceError.posixError(errno) - } - defer { close(fd) } - let size = lseek(fd, 0, SEEK_END) - if size < 0 { - throw FileImageSourceError.posixError(errno) - } - let base = mmap(nil, Int(size), PROT_READ, MAP_FILE|MAP_PRIVATE, fd, 0) - if base == nil || base! == UnsafeRawPointer(bitPattern: -1)! { - throw FileImageSourceError.posixError(errno) - } - _mapping = UnsafeRawBufferPointer(start: base, count: Int(size)) - } - - deinit { - munmap(UnsafeMutableRawPointer(mutating: _mapping.baseAddress), - _mapping.count) - } - - public func fetch(from addr: Address, - into buffer: UnsafeMutableRawBufferPointer) throws { - let start = Int(addr) - guard _mapping.indices.contains(start) else { - throw FileImageSourceError.outOfRangeRead - } - let slice = _mapping[start...] - guard slice.count >= buffer.count else { - throw FileImageSourceError.outOfRangeRead - } - buffer.copyBytes(from: slice[start.. { - var base: Address - var size: Size - var end: Address { - return base + Address(size) - } - - func adjusted(by offset: some FixedWidthInteger) -> Self { - return Self(base: base + Address(offset), size: size - Size(offset)) - } -} - -protocol ImageSource: MemoryReader { - typealias Bounds = ImageBounds - - /// Says whether we are looking at a loaded image in memory or not. - /// The layout in memory may differ from the on-disk layout; in particular, - /// some information may not be available when the image is mapped into - /// memory (an example is ELF section headers). - var isMappedImage: Bool { get } - - /// If this ImageSource knows its path, this will be non-nil. - var path: String? { get } - - /// If this ImageSource knows its bounds, this will be non-nil. - var bounds: Bounds? { get } -} - -struct ImageSourceCursor { - typealias Address = UInt64 - typealias Size = UInt64 - typealias Bounds = ImageBounds - - var source: any ImageSource - var pos: Address - - init(source: any ImageSource, offset: Address = 0) { - self.source = source - self.pos = offset - } - - public mutating func read(into buffer: UnsafeMutableRawBufferPointer) throws { - try source.fetch(from: pos, into: buffer) - pos += UInt64(buffer.count) - } - - public mutating func read(into buffer: UnsafeMutableBufferPointer) throws { - try source.fetch(from: pos, into: buffer) - pos += UInt64(MemoryLayout.stride * buffer.count) - } - - public mutating func read(into pointer: UnsafeMutablePointer) throws { - try source.fetch(from: pos, into: pointer) - pos += UInt64(MemoryLayout.stride) - } - - public mutating func read(as type: T.Type) throws -> T { - let stride = MemoryLayout.stride - let result = try source.fetch(from: pos, as: type) - pos += UInt64(stride) - return result - } - - public mutating func read(count: Int, as type: T.Type) throws -> [T] { - let stride = MemoryLayout.stride - let result = try source.fetch(from: pos, count: count, as: type) - pos += UInt64(stride * count) - return result - } - - public mutating func readString() throws -> String? { - var bytes: [UInt8] = [] - while true { - let ch = try read(as: UInt8.self) - if ch == 0 { - break - } - bytes.append(ch) - } - - return String(decoding: bytes, as: UTF8.self) - } - -} - -extension ImageSource { - /// Fetch all the data from this image source (which must be bounded) - func fetchAllBytes() -> [UInt8]? { - guard let bounds = self.bounds else { - return nil - } - if let data = try? fetch(from: bounds.base, - count: Int(bounds.size), - as: UInt8.self) { - return data - } - return nil - } -} - -enum SubImageSourceError: Error { - case outOfRangeFetch(UInt64, Int) -} - -struct SubImageSource: ImageSource { - var parent: S - var baseAddress: Address - var length: Size - var path: String? { return parent.path } - - var bounds: Bounds? { - return Bounds(base: 0, size: length) - } - - public init(parent: S, baseAddress: Address, length: Size) { - self.parent = parent - self.baseAddress = baseAddress - self.length = length - } - - public var isMappedImage: Bool { - return parent.isMappedImage - } - - public func fetch(from addr: Address, - into buffer: UnsafeMutableRawBufferPointer) throws { - let toFetch = buffer.count - if addr < 0 || addr > length { - throw SubImageSourceError.outOfRangeFetch(UInt64(addr), toFetch) - } - if Address(length) - addr < toFetch { - throw SubImageSourceError.outOfRangeFetch(UInt64(addr), toFetch) - } - - return try parent.fetch(from: baseAddress + addr, into: buffer) - } -} diff --git a/stdlib/public/Backtracing/MemoryImageSource.swift b/stdlib/public/Backtracing/MemoryImageSource.swift deleted file mode 100644 index c22bb27307ec3..0000000000000 --- a/stdlib/public/Backtracing/MemoryImageSource.swift +++ /dev/null @@ -1,35 +0,0 @@ -//===--- MemoryImageSource.swift - An image source that reads from a file ---===// -// -// This source file is part of the Swift.org open source project -// -// Copyright (c) 2023 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 -// -//===----------------------------------------------------------------------===// -// -// Defines MemoryImageSource, an image source that reads data using a -// MemoryReader. -// -//===----------------------------------------------------------------------===// - -import Swift - -class MemoryImageSource: ImageSource { - private var reader: M - - public var isMappedImage: Bool { return true } - public var path: String? { return nil } - public var bounds: Bounds? { return nil } - - public init(with reader: M) { - self.reader = reader - } - - public func fetch(from addr: Address, - into buffer: UnsafeMutableRawBufferPointer) throws { - try reader.fetch(from: addr, into: buffer) - } -} diff --git a/stdlib/public/CMakeLists.txt b/stdlib/public/CMakeLists.txt index a33c675ae2234..618de91625f48 100644 --- a/stdlib/public/CMakeLists.txt +++ b/stdlib/public/CMakeLists.txt @@ -301,8 +301,8 @@ if(SWIFT_BUILD_STDLIB AND NOT SWIFT_STDLIB_BUILD_ONLY_CORE_MODULES) add_subdirectory(Observation) endif() - if(SWIFT_ENABLE_BACKTRACING) - add_subdirectory(Backtracing) + if(SWIFT_ENABLE_RUNTIME_MODULE) + add_subdirectory(RuntimeModule) endif() if(SWIFT_ENABLE_SYNCHRONIZATION) diff --git a/stdlib/public/CompatibilityOverride/CompatibilityOverride.h b/stdlib/public/CompatibilityOverride/CompatibilityOverride.h index 3c2e7517c5e92..0e4517fdea3a0 100644 --- a/stdlib/public/CompatibilityOverride/CompatibilityOverride.h +++ b/stdlib/public/CompatibilityOverride/CompatibilityOverride.h @@ -123,7 +123,7 @@ namespace swift { // Include path computation. Code that includes this file can write `#include // "..CompatibilityOverride/CompatibilityOverrideIncludePath.h"` to include the // appropriate .def file for the current library. -#define COMPATIBILITY_OVERRIDE_INCLUDE_PATH_swiftRuntime \ +#define COMPATIBILITY_OVERRIDE_INCLUDE_PATH_swiftRuntimeCore \ "../CompatibilityOverride/CompatibilityOverrideRuntime.def" #define COMPATIBILITY_OVERRIDE_INCLUDE_PATH_swift_Concurrency \ "../CompatibilityOverride/CompatibilityOverrideConcurrency.def" @@ -155,7 +155,7 @@ namespace swift { // resolve to string literal containing the appropriate section name for the // current library. // Turns into '__swift_hooks' -#define COMPATIBILITY_OVERRIDE_SECTION_NAME_swiftRuntime "__swift" \ +#define COMPATIBILITY_OVERRIDE_SECTION_NAME_swiftRuntimeCore "__swift" \ SWIFT_VERSION_MAJOR \ SWIFT_VERSION_MINOR \ "_hooks" diff --git a/stdlib/public/CompatibilityOverride/CompatibilityOverrideRuntime.def b/stdlib/public/CompatibilityOverride/CompatibilityOverrideRuntime.def index 6bfbc69a1d99b..1ba6aeda98d78 100644 --- a/stdlib/public/CompatibilityOverride/CompatibilityOverrideRuntime.def +++ b/stdlib/public/CompatibilityOverride/CompatibilityOverrideRuntime.def @@ -79,6 +79,9 @@ # define OVERRIDE_PROTOCOLCONFORMANCE OVERRIDE # define OVERRIDE_KEYPATH OVERRIDE # define OVERRIDE_WITNESSTABLE OVERRIDE +# define OVERRIDE_CVW OVERRIDE +# define OVERRIDE_CVW_METADATA OVERRIDE +# define OVERRIDE_CVW_METADATA_ENUM OVERRIDE #else # ifndef OVERRIDE_METADATALOOKUP # define OVERRIDE_METADATALOOKUP(...) @@ -104,6 +107,15 @@ # ifndef OVERRIDE_WITNESSTABLE # define OVERRIDE_WITNESSTABLE(...) # endif +# ifndef OVERRIDE_CVW +# define OVERRIDE_CVW(...) +# endif +# ifndef OVERRIDE_CVW_METADATA +# define OVERRIDE_CVW_METADATA(...) +# endif +# ifndef OVERRIDE_CVW_METADATA_ENUM +# define OVERRIDE_CVW_METADATA_ENUM(...) +# endif #endif OVERRIDE_DYNAMICCASTING(dynamicCast, bool, , , swift::, @@ -217,6 +229,125 @@ OVERRIDE_WITNESSTABLE(getAssociatedConformanceWitnessSlow, const WitnessTable *, const ProtocolRequirement *assocConformance), (wtable, conformingType, assocType, reqBase, assocConformance)) + +OVERRIDE_CVW_METADATA(cvw_allocateGenericValueMetadataWithLayoutString, ValueMetadata *, + SWIFT_RUNTIME_EXPORT, , swift::, + (const ValueTypeDescriptor *description, + const void *arguments, + const GenericValueMetadataPattern *pattern, + size_t extraDataSize), + (description, arguments, pattern, extraDataSize)) + +OVERRIDE_CVW_METADATA(cvw_initStructMetadataWithLayoutString, void, SWIFT_RUNTIME_EXPORT, + , swift::, (StructMetadata *structType, + StructLayoutFlags layoutFlags, + size_t numFields, + const uint8_t *const *fieldTypes, + const uint8_t *fieldTags, + uint32_t *fieldOffsets), + (structType, layoutFlags, numFields, fieldTypes, + fieldTags, fieldOffsets)) + +OVERRIDE_CVW_METADATA(cvw_allocateGenericClassMetadataWithLayoutString, ClassMetadata *, + SWIFT_RUNTIME_EXPORT, , swift::, + (const ClassDescriptor *description, + const void *arguments, + const GenericClassMetadataPattern *pattern), + (description, arguments, pattern)) + +OVERRIDE_CVW_METADATA_ENUM(cvw_initEnumMetadataSingleCaseWithLayoutString, void, + SWIFT_RUNTIME_EXPORT, , swift::, + (EnumMetadata *self, EnumLayoutFlags layoutFlags, + const Metadata *payloadType), + (self, layoutFlags, payloadType)) + +OVERRIDE_CVW_METADATA_ENUM(cvw_initEnumMetadataSinglePayloadWithLayoutString, void, + SWIFT_RUNTIME_EXPORT, , swift::, + (EnumMetadata *self, EnumLayoutFlags layoutFlags, + const Metadata *payloadType, unsigned emptyCases), + (self, layoutFlags, payloadType, emptyCases)) + +OVERRIDE_CVW_METADATA_ENUM(cvw_initEnumMetadataMultiPayloadWithLayoutString, void, + SWIFT_RUNTIME_EXPORT, , swift::, + (EnumMetadata *self, EnumLayoutFlags layoutFlags, + unsigned numPayloads, + const Metadata * const *payloadLayouts), + (self, layoutFlags, numPayloads, payloadLayouts)) + +OVERRIDE_CVW(cvw_destroy, void, SWIFT_RUNTIME_EXPORT, + , swift::, (swift::OpaqueValue *address, + const Metadata *metadata), + (address, metadata)) + +OVERRIDE_CVW(cvw_assignWithCopy, swift::OpaqueValue *, SWIFT_RUNTIME_EXPORT, + , swift::, (swift::OpaqueValue *dest, + swift::OpaqueValue *src, + const Metadata *metadata), + (dest, src, metadata)) + +OVERRIDE_CVW(cvw_assignWithTake, swift::OpaqueValue *, SWIFT_RUNTIME_EXPORT, + , swift::, (swift::OpaqueValue *dest, + swift::OpaqueValue *src, + const Metadata *metadata), + (dest, src, metadata)) + +OVERRIDE_CVW(cvw_initWithCopy, swift::OpaqueValue *, SWIFT_RUNTIME_EXPORT, + , swift::, (swift::OpaqueValue *dest, + swift::OpaqueValue *src, + const Metadata *metadata), + (dest, src, metadata)) + +OVERRIDE_CVW(cvw_initWithTake, swift::OpaqueValue *, SWIFT_RUNTIME_EXPORT, + , swift::, (swift::OpaqueValue *dest, + swift::OpaqueValue *src, + const Metadata *metadata), + (dest, src, metadata)) + +OVERRIDE_CVW(cvw_initializeBufferWithCopyOfBuffer, swift::OpaqueValue *, + SWIFT_RUNTIME_EXPORT, + , swift::, (swift::ValueBuffer *dest, + swift::ValueBuffer *src, + const Metadata *metadata), + (dest, src, metadata)) + +OVERRIDE_CVW(cvw_enumSimple_getEnumTag, unsigned, SWIFT_RUNTIME_EXPORT, + , swift::, (swift::OpaqueValue *address, + const Metadata *metadata), + (address, metadata)) + +OVERRIDE_CVW(cvw_enumSimple_destructiveInjectEnumTag, void, SWIFT_RUNTIME_EXPORT, + , swift::, (swift::OpaqueValue *address, + unsigned tag, + const Metadata *metadata), + (address, tag, metadata)) + +OVERRIDE_CVW(cvw_enumFn_getEnumTag, unsigned, SWIFT_RUNTIME_EXPORT, + , swift::, (swift::OpaqueValue *address, + const Metadata *metadata), + (address, metadata)) + +OVERRIDE_CVW(cvw_multiPayloadEnumGeneric_getEnumTag, unsigned, SWIFT_RUNTIME_EXPORT, + , swift::, (swift::OpaqueValue *address, + const Metadata *metadata), + (address, metadata)) + +OVERRIDE_CVW(cvw_multiPayloadEnumGeneric_destructiveInjectEnumTag, void, SWIFT_RUNTIME_EXPORT, + , swift::, (swift::OpaqueValue *address, + unsigned tag, + const Metadata *metadata), + (address, tag, metadata)) + +OVERRIDE_CVW(cvw_singlePayloadEnumGeneric_getEnumTag, unsigned, SWIFT_RUNTIME_EXPORT, + , swift::, (swift::OpaqueValue *address, + const Metadata *metadata), + (address, metadata)) + +OVERRIDE_CVW(cvw_singlePayloadEnumGeneric_destructiveInjectEnumTag, void, SWIFT_RUNTIME_EXPORT, + , swift::, (swift::OpaqueValue *address, + unsigned tag, + const Metadata *metadata), + (address, tag, metadata)) + #if SWIFT_OBJC_INTEROP OVERRIDE_OBJC(dynamicCastObjCClass, const void *, , , swift::, @@ -265,3 +396,6 @@ OVERRIDE_FOREIGN(dynamicCastForeignClassUnconditional, const void *, , , swift:: #undef OVERRIDE_PROTOCOLCONFORMANCE #undef OVERRIDE_KEYPATH #undef OVERRIDE_WITNESSTABLE +#undef OVERRIDE_CVW +#undef OVERRIDE_CVW_METADATA +#undef OVERRIDE_CVW_METADATA_ENUM diff --git a/stdlib/public/Concurrency/AsyncLet.cpp b/stdlib/public/Concurrency/AsyncLet.cpp index 0edbacd14759c..d31592fe97649 100644 --- a/stdlib/public/Concurrency/AsyncLet.cpp +++ b/stdlib/public/Concurrency/AsyncLet.cpp @@ -35,6 +35,28 @@ #include +#if __cplusplus < 202002l || !defined(__cpp_lib_bit_cast) +namespace std { +template +std::enable_if_t && + std::is_trivially_copyable_v, Destination> +bit_cast(const Source &src) noexcept { + static_assert(std::is_trivially_constructible_v, + "The destination type must be trivially constructible"); + Destination dst; + if constexpr (std::is_pointer_v || std::is_pointer_v) + std::memcpy(reinterpret_cast(&dst), + reinterpret_cast(&src), sizeof(Destination)); + else + std::memcpy(&dst, &src, sizeof(Destination)); + return dst; +} +} +#else +#include +#endif + using namespace swift; namespace { @@ -287,8 +309,8 @@ static void _asyncLet_get_throwing_continuation( } // Continue the caller's execution. - auto throwingResume - = reinterpret_cast(callContext->ResumeParent); + auto throwingResume = + std::bit_cast(callContext->ResumeParent); return throwingResume(callContext->Parent, error); } @@ -305,8 +327,8 @@ static void swift_asyncLet_get_throwingImpl( } auto aletContext = static_cast(callContext); - aletContext->ResumeParent - = reinterpret_cast(resumeFunction); + aletContext->ResumeParent = + std::bit_cast(resumeFunction); aletContext->Parent = callerContext; aletContext->alet = alet; auto futureContext = asImpl(alet)->getFutureContext(); @@ -376,7 +398,7 @@ static void asyncLet_finish_after_task_completion(SWIFT_ASYNC_CONTEXT AsyncConte swift_task_dealloc(task); } - return reinterpret_cast(resumeFunction) + return std::bit_cast(resumeFunction) (callerContext, error); } @@ -528,14 +550,14 @@ static void swift_asyncLet_consume_throwingImpl( if (asImpl(alet)->hasResultInBuffer()) { return asyncLet_finish_after_task_completion(callerContext, alet, - reinterpret_cast(resumeFunction), + std::bit_cast(resumeFunction), callContext, nullptr); } auto aletContext = static_cast(callContext); - aletContext->ResumeParent - = reinterpret_cast(resumeFunction); + aletContext->ResumeParent = + std::bit_cast(resumeFunction); aletContext->Parent = callerContext; aletContext->alet = alet; auto futureContext = asImpl(alet)->getFutureContext(); diff --git a/stdlib/public/Concurrency/DispatchGlobalExecutor.cpp b/stdlib/public/Concurrency/DispatchGlobalExecutor.cpp index fee1a5f646dd9..f87a0de73f027 100644 --- a/stdlib/public/Concurrency/DispatchGlobalExecutor.cpp +++ b/stdlib/public/Concurrency/DispatchGlobalExecutor.cpp @@ -54,6 +54,28 @@ #include "ExecutorImpl.h" #include "TaskPrivate.h" +#if __cplusplus < 202002l || !defined(__cpp_lib_bit_cast) +namespace std { +template +std::enable_if_t && + std::is_trivially_copyable_v, Destination> +bit_cast(const Source &src) noexcept { + static_assert(std::is_trivially_constructible_v, + "The destination type must be trivially constructible"); + Destination dst; + if constexpr (std::is_pointer_v || std::is_pointer_v) + std::memcpy(reinterpret_cast(&dst), + reinterpret_cast(&src), sizeof(Destination)); + else + std::memcpy(&dst, &src, sizeof(Destination)); + return dst; +} +} +#else +#include +#endif + using namespace swift; // Ensure that Job's layout is compatible with what Dispatch expects. @@ -119,11 +141,11 @@ static void initializeDispatchEnqueueFunc(dispatch_queue_t queue, void *obj, if (SWIFT_RUNTIME_WEAK_CHECK(dispatch_async_swift_job)) func = SWIFT_RUNTIME_WEAK_USE(dispatch_async_swift_job); #elif defined(_WIN32) - func = reinterpret_cast( + func = std::bit_cast( GetProcAddress(LoadLibraryW(L"dispatch.dll"), "dispatch_async_swift_job")); #else - func = reinterpret_cast( + func = std::bit_cast( dlsym(RTLD_NEXT, "dispatch_async_swift_job")); #endif #endif diff --git a/stdlib/public/Concurrency/TaskGroup.cpp b/stdlib/public/Concurrency/TaskGroup.cpp index 399564c966073..1ab17926877d7 100644 --- a/stdlib/public/Concurrency/TaskGroup.cpp +++ b/stdlib/public/Concurrency/TaskGroup.cpp @@ -61,6 +61,28 @@ #include #endif +#if __cplusplus < 202002l || !defined(__cpp_lib_bit_cast) +namespace std { +template +std::enable_if_t && + std::is_trivially_copyable_v, Destination> +bit_cast(const Source &src) noexcept { + static_assert(std::is_trivially_constructible_v, + "The destination type must be trivially constructible"); + Destination dst; + if constexpr (std::is_pointer_v || std::is_pointer_v) + std::memcpy(reinterpret_cast(&dst), + reinterpret_cast(&src), sizeof(Destination)); + else + std::memcpy(&dst, &src, sizeof(Destination)); + return dst; +} +} +#else +#include +#endif + using namespace swift; #if 0 @@ -1653,7 +1675,7 @@ task_group_wait_resume_adapter(SWIFT_ASYNC_CONTEXT AsyncContext *_context) { auto context = static_cast(_context); auto resumeWithError = - reinterpret_cast(context->ResumeParent); + std::bit_cast(context->ResumeParent); return resumeWithError(context->Parent, context->errorResult); } @@ -1705,7 +1727,7 @@ static void swift_taskGroup_wait_next_throwingImpl( auto context = static_cast(rawContext); context->ResumeParent = - reinterpret_cast(resumeFunction); + std::bit_cast(resumeFunction); context->Parent = callerContext; context->errorResult = nullptr; context->successResultPointer = resultPointer; @@ -1937,7 +1959,7 @@ void TaskGroupBase::waitAll(SwiftError* bodyError, AsyncTask *waitingTask, auto context = static_cast(rawContext); context->ResumeParent = - reinterpret_cast(resumeFunction); + std::bit_cast(resumeFunction); context->Parent = callerContext; context->errorResult = nullptr; context->successResultPointer = resultPointer; diff --git a/stdlib/public/RuntimeModule/Address.swift b/stdlib/public/RuntimeModule/Address.swift new file mode 100644 index 0000000000000..24a8a0a7557ae --- /dev/null +++ b/stdlib/public/RuntimeModule/Address.swift @@ -0,0 +1,258 @@ +//===--- Address.swift ----------------------------------------*- swift -*-===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2023 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 +// +//===----------------------------------------------------------------------===// +// +// Defines the `Backtrace.Address` struct that represents addresses in a +// captured backtrace. This type is *not* used for storage; rather, it's +// used as an interface type. +// +//===----------------------------------------------------------------------===// + +import Swift + +// .. Comparable ............................................................. + +extension Backtrace.Address { + fileprivate var widestRepresentation: UInt64 { + switch representation { + case .null: + return 0 + case let .sixteenBit(addr): + return UInt64(addr) + case let .thirtyTwoBit(addr): + return UInt64(addr) + case let .sixtyFourBit(addr): + return addr + } + } +} + +extension Backtrace.Address: Comparable { + /// Return true if `lhs` is lower than `rhs` + public static func < (lhs: Backtrace.Address, rhs: Backtrace.Address) -> Bool { + return lhs.widestRepresentation < rhs.widestRepresentation + } + /// Return true if `lhs` is equal to `rhs` + public static func == (lhs: Backtrace.Address, rhs: Backtrace.Address) -> Bool { + return lhs.widestRepresentation == rhs.widestRepresentation + } +} + +// .. LosslessStringConvertible .............................................. + +extension Backtrace.Address: LosslessStringConvertible { + /// Create an Backtrace.Address from its string representation + public init?(_ s: String) { + self.init(s[...]) + } + + public init?(_ s: Substring) { + let unprefixed: Substring + + // Explicit support for null + if s == "null" { + self.representation = .null + return + } + + // Drop the prefix, if any + if s.hasPrefix("0x") { + unprefixed = s[s.index(s.startIndex, offsetBy: 2)...] + } else { + unprefixed = Substring(s) + } + + // Work out whether it's 64-bit or 32-bit and parse it + if unprefixed.count > 8 && unprefixed.count <= 16 { + guard let addr = UInt64(unprefixed, radix: 16) else { + return nil + } + if addr == 0 { + self.representation = .null + } else { + self.representation = .sixtyFourBit(addr) + } + } else if unprefixed.count <= 8 { + guard let addr = UInt32(unprefixed, radix: 16) else { + return nil + } + if addr == 0 { + self.representation = .null + } else { + self.representation = .thirtyTwoBit(addr) + } + } else { + return nil + } + } + + /// A textual representation of this address + public var description: String { + switch representation { + case .null: + return "null" + case let .sixteenBit(addr): + if addr == 0 { + return "null" + } + return hex(addr) + case let .thirtyTwoBit(addr): + if addr == 0 { + return "null" + } + return hex(addr) + case let .sixtyFourBit(addr): + if addr == 0 { + return "null" + } + return hex(addr) + } + } +} + +// .. ExpressibleByIntegerLiteral ............................................ + +extension Backtrace.Address: ExpressibleByIntegerLiteral { + public typealias IntegerLiteralType = UInt64 + + /// Convert from an integer literal. + public init(integerLiteral: Self.IntegerLiteralType) { + if integerLiteral == 0 { + self.representation = .null + } else if integerLiteral < 0x10000 { + self.representation = .sixteenBit(UInt16(truncatingIfNeeded: integerLiteral)) + } else if integerLiteral < 0x100000000 { + self.representation = .thirtyTwoBit(UInt32(truncatingIfNeeded: integerLiteral)) + } else { + self.representation = .sixtyFourBit(integerLiteral) + } + } +} + +// .. FixedWidthInteger conversions .......................................... + +extension Backtrace.Address { + fileprivate func toFixedWidth( + type: T.Type = T.self + ) -> T? { + switch representation { + case .null: + return T(0) + case let .sixteenBit(addr): + guard T.bitWidth >= 16 else { return nil } + return T(truncatingIfNeeded: addr) + case let .thirtyTwoBit(addr): + guard T.bitWidth >= 32 else { return nil } + return T(truncatingIfNeeded: addr) + case let .sixtyFourBit(addr): + guard T.bitWidth >= 64 else { return nil } + return T(truncatingIfNeeded: addr) + } + } +} + +extension FixedWidthInteger { + /// Convert from an Backtrace.Address. + /// + /// This initializer will return nil if the address width is larger than the + /// type you are attempting to convert into. + public init?(_ address: Backtrace.Address) { + guard let result = address.toFixedWidth(type: Self.self) else { + return nil + } + self = result + } +} + +extension Backtrace.Address { + /// Convert from a UInt16. + public init(_ value: UInt16) { + if value == 0 { + self.representation = .null + return + } + self.representation = .sixteenBit(value) + } + + /// Convert from a UInt32. + public init(_ value: UInt32) { + if value == 0 { + self.representation = .null + return + } + self.representation = .thirtyTwoBit(value) + } + + /// Convert from a UInt64. + public init(_ value: UInt64) { + if value == 0 { + self.representation = .null + return + } + self.representation = .sixtyFourBit(value) + } + + /// Convert from a FixedWidthInteger + public init?(_ value: T) { + switch T.bitWidth { + case 16: + self.init(UInt16(truncatingIfNeeded: value)) + case 32: + self.init(UInt32(truncatingIfNeeded: value)) + case 64: + self.init(UInt64(truncatingIfNeeded: value)) + default: + return nil + } + } +} + +// -- Arithmetic ------------------------------------------------------------- + +extension Backtrace.Address { + static func - (lhs: Backtrace.Address, rhs: Backtrace.Address) -> Int64 { + let ulhs = UInt64(lhs)! + let urhs = UInt64(rhs)! + return Int64(bitPattern: ulhs - urhs) + } + + static func - (lhs: Backtrace.Address, rhs: Int64) -> Backtrace.Address { + switch lhs.representation { + case .null: + return Backtrace.Address(0) + case let .sixteenBit(addr): + let newAddr = addr &- UInt16(bitPattern: Int16(truncatingIfNeeded: rhs)) + return Backtrace.Address(newAddr) + case let .thirtyTwoBit(addr): + let newAddr = addr &- UInt32(bitPattern: Int32(truncatingIfNeeded: rhs)) + return Backtrace.Address(newAddr) + case let .sixtyFourBit(addr): + let newAddr = addr &- UInt64(bitPattern: rhs) + return Backtrace.Address(newAddr) + } + } + + static func + (lhs: Backtrace.Address, rhs: Int64) -> Backtrace.Address { + switch lhs.representation { + case .null: + return Backtrace.Address(0) + case let .sixteenBit(addr): + let newAddr = addr &+ UInt16(bitPattern: Int16(truncatingIfNeeded: rhs)) + return Backtrace.Address(newAddr) + case let .thirtyTwoBit(addr): + let newAddr = addr &+ UInt32(bitPattern: Int32(truncatingIfNeeded: rhs)) + return Backtrace.Address(newAddr) + case let .sixtyFourBit(addr): + let newAddr = addr &+ UInt64(bitPattern: rhs) + return Backtrace.Address(newAddr) + } + } +} diff --git a/stdlib/public/RuntimeModule/Backtrace+Codable.swift b/stdlib/public/RuntimeModule/Backtrace+Codable.swift new file mode 100644 index 0000000000000..6a7df75e710b3 --- /dev/null +++ b/stdlib/public/RuntimeModule/Backtrace+Codable.swift @@ -0,0 +1,69 @@ +//===--- Backtrace+Codable.swift ------------------------------*- swift -*-===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2023 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 +// +//===----------------------------------------------------------------------===// +// +// Defines the Codable conformance for Backtrace. +// +//===----------------------------------------------------------------------===// + +import Swift + +func stringFrom(sequence: some Sequence) -> String? { + if #available(macOS 15.0, *) { + return String(validating: sequence, as: UTF8.self) + } else { + let bytes = Array(sequence) + return String(decoding: bytes, as: UTF8.self) + } +} + +@available(macOS 15.0, *) +extension Backtrace: Codable { + + enum CodingKeys: CodingKey { + case architecture + case backtrace + case imageMap + } + + public init(from decoder: any Decoder) throws { + let values = try decoder.container(keyedBy: CodingKeys.self) + self.architecture = try values.decode(String.self, forKey: .architecture) + + let backtraceB64 = try values.decode(String.self, forKey: .backtrace) + self.representation = Array(Base64Decoder(source: backtraceB64.utf8)) + + if let imageMapB64 = try values.decodeIfPresent(String.self, + forKey: .imageMap) { + self.images = ImageMap(compactImageMapData: + Base64Decoder(source: imageMapB64.utf8)) + } else { + self.images = nil + } + } + + public func encode(to encoder: any Encoder) throws { + var values = encoder.container(keyedBy: CodingKeys.self) + try values.encode(architecture, forKey: .architecture) + + let backtraceB64 = stringFrom(sequence: + Base64Encoder(source: self.representation)) + try values.encode(backtraceB64, forKey: .backtrace) + + if let imageMap = self.images { + let encoder = CompactImageMapFormat.Encoder(imageMap) + let imageMapB64 = stringFrom(sequence: + Base64Encoder(source: encoder)) + try values.encode(imageMapB64, forKey: .imageMap) + } + } + +} diff --git a/stdlib/public/RuntimeModule/Backtrace.swift b/stdlib/public/RuntimeModule/Backtrace.swift new file mode 100644 index 0000000000000..a6e682e576ddf --- /dev/null +++ b/stdlib/public/RuntimeModule/Backtrace.swift @@ -0,0 +1,433 @@ +//===--- Backtrace.swift --------------------------------------*- swift -*-===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2023 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 +// +//===----------------------------------------------------------------------===// +// +// Defines the `Backtrace` struct that represents a captured backtrace. +// +//===----------------------------------------------------------------------===// + +import Swift + +// #if os(macOS) || os(iOS) || os(tvOS) || os(watchOS) +// internal import Darwin +// #elseif os(Windows) +// internal import ucrt +// #elseif canImport(Glibc) +// internal import Glibc +// #elseif canImport(Musl) +// internal import Musl +// #endif + +/// Holds a backtrace. +public struct Backtrace: CustomStringConvertible, Sendable { + /// The type of an address. + /// + /// This is used as an opaque type; if you have some Address, you + /// can ask if it's NULL, and you can attempt to convert it to a + /// FixedWidthInteger. + /// + /// This is intentionally _not_ a pointer, because you shouldn't be + /// dereferencing them; they may refer to some other process, for + /// example. + public struct Address: Hashable, Sendable { + enum Representation: Hashable, Sendable { + case null + case sixteenBit(UInt16) + case thirtyTwoBit(UInt32) + case sixtyFourBit(UInt64) + } + + var representation: Representation + + /// The width of this address, in bits + public var bitWidth: Int { + switch representation { + case .null: + return 0 + case .sixteenBit(_): + return 16 + case .thirtyTwoBit(_): + return 32 + case .sixtyFourBit(_): + return 64 + } + } + + /// True if this address is a NULL pointer + public var isNull: Bool { + switch representation { + case .null: + return true + case let .sixteenBit(addr): + return addr == 0 + case let .thirtyTwoBit(addr): + return addr == 0 + case let .sixtyFourBit(addr): + return addr == 0 + } + } + } + + /// The unwind algorithm to use. + public enum UnwindAlgorithm { + /// Choose the most appropriate for the platform. + case auto + + /// Use the fastest viable method. + /// + /// Typically this means walking the frame pointers. + case fast + + /// Use the most precise available method. + /// + /// On Darwin and on ELF platforms, this will use EH unwind + /// information. On Windows, it will use Win32 API functions. + case precise + } + + /// Represents an individual frame in a backtrace. + public enum Frame: CustomStringConvertible, Sendable { + /// A program counter value. + /// + /// This might come from a signal handler, or an exception or some + /// other situation in which we have captured the actual program counter. + /// + /// These can be directly symbolicated, as-is, with no adjustment. + case programCounter(Address) + + /// A return address. + /// + /// Corresponds to a normal function call. + /// + /// Requires adjustment when symbolicating for a backtrace, because it + /// points at the address after the one that triggered the child frame. + case returnAddress(Address) + + /// An async resume point. + /// + /// Corresponds to an `await` in an async task. + /// + /// Can be directly symbolicated, as-is. + case asyncResumePoint(Address) + + /// Indicates a discontinuity in the backtrace. + /// + /// This occurs when you set a limit and a minimum number of frames at + /// the top. For example, if you set a limit of 10 frames and a minimum + /// of 4 top frames, but the backtrace generated 100 frames, you will see + /// + /// 0: frame 100 <----- bottom of call stack + /// 1: frame 99 + /// 2: frame 98 + /// 3: frame 97 + /// 4: frame 96 + /// 5: ... <----- omittedFrames(92) + /// 6: frame 3 + /// 7: frame 2 + /// 8: frame 1 + /// 9: frame 0 <----- top of call stack + /// + /// Note that the limit *includes* the discontinuity. + /// + /// This is good for handling cases involving deep recursion. + case omittedFrames(Int) + + /// Indicates a discontinuity of unknown length. + /// + /// This can only be present at the end of a backtrace; in other cases + /// we will know how many frames we have omitted. For instance, + /// + /// 0: frame 100 <----- bottom of call stack + /// 1: frame 99 + /// 2: frame 98 + /// 3: frame 97 + /// 4: frame 96 + /// 5: ... <----- truncated + case truncated + + /// The program counter, without any adjustment. + public var originalProgramCounter: Address { + switch self { + case let .returnAddress(addr): + return addr + case let .programCounter(addr): + return addr + case let .asyncResumePoint(addr): + return addr + case .omittedFrames(_), .truncated: + return 0 + } + } + + /// The adjusted program counter to use for symbolication. + public var adjustedProgramCounter: Address { + switch self { + case let .returnAddress(addr): + return addr - 1 + case let .programCounter(addr): + return addr + case let .asyncResumePoint(addr): + return addr + case .omittedFrames(_), .truncated: + return 0 + } + } + + /// A textual description of this frame. + public var description: String { + switch self { + case let .programCounter(addr): + return "\(addr)" + case let .returnAddress(addr): + return "\(addr) [ra]" + case let .asyncResumePoint(addr): + return "\(addr) [async]" + case .omittedFrames(_), .truncated: + return "..." + } + } + } + + /// Represents an image loaded in the process's address space + public struct Image: CustomStringConvertible, Sendable { + /// The name of the image (e.g. libswiftCore.dylib). + private(set) public var name: String? + + /// The full path to the image (e.g. /usr/lib/swift/libswiftCore.dylib). + private(set) public var path: String? + + /// The unique ID of the image, as a byte array (note that the exact number + /// of bytes may vary, and that some images may not have a unique ID). + /// + /// On Darwin systems, this is the LC_UUID value; on Linux this is the + /// build ID, which may take one of a number of forms or may not even + /// be present. + private(set) public var uniqueID: [UInt8]? + + /// The base address of the image. + private(set) public var baseAddress: Backtrace.Address + + /// The end of the text segment in this image. + private(set) public var endOfText: Backtrace.Address + + /// Provide a textual description of an Image. + public var description: String { + if let uniqueID = self.uniqueID { + return "\(baseAddress)-\(endOfText) \(hex(uniqueID)) \(name ?? "") \(path ?? "")" + } else { + return "\(baseAddress)-\(endOfText) \(name ?? "") \(path ?? "")" + } + } + } + + /// The architecture of the system that captured this backtrace. + public internal(set) var architecture: String + + /// The actual backtrace data, stored in Compact Backtrace Format. + var representation: [UInt8] + + /// A list of captured frame information. + @available(macOS 10.15, *) + public var frames: some Sequence { + return CompactBacktraceFormat.Decoder(representation) + } + + /// A list of captured images. + /// + /// Some backtracing algorithms may require this information, in which case + /// it will be filled in by the `capture()` method. Other algorithms may + /// not, in which case it will be `nil` and you can capture an image list + /// separately yourself using `ImageMap.capture()`. + public var images: ImageMap? + + /// Capture a backtrace from the current program location. + /// + /// The `capture()` method itself will not be included in the backtrace; + /// i.e. the first frame will be the one in which `capture()` was called, + /// and its programCounter value will be the return address for the + /// `capture()` method call. + /// + /// Parameters: + /// + /// - algorithm: Specifies which unwind mechanism to use. If this + /// is set to `.auto`, we will use the platform default. + /// - limit: The backtrace will include at most this number of + /// frames; you can set this to `nil` to remove the + /// limit completely if required. + /// - offset: Says how many frames to skip; this makes it easy to + /// wrap this API without having to inline things and + /// without including unnecessary frames in the backtrace. + /// - top: Sets the minimum number of frames to capture at the + /// top of the stack. + /// - images: (Optional) A list of captured images. This allows you + /// to capture images once, and then generate multiple + /// backtraces using a single set of captured images. + @inline(never) + @_semantics("use_frame_pointer") + public static func capture(algorithm: UnwindAlgorithm = .auto, + limit: Int? = 64, + offset: Int = 0, + top: Int = 16, + images: ImageMap? = nil) throws -> Backtrace { + #if os(Linux) + // On Linux, we need the captured images to resolve async functions + let theImages = images ?? ImageMap.capture() + #else + let theImages = images + #endif + + // N.B. We use offset+1 here to skip this frame, rather than inlining + // this code into the client. + return try HostContext.withCurrentContext { ctx in + try capture(from: ctx, + using: UnsafeLocalMemoryReader(), + images: theImages, + algorithm: algorithm, + limit: limit, + offset: offset + 1, + top: top) + } + } + + /// Specifies options for the `symbolicated` method. + public struct SymbolicationOptions: OptionSet { + public let rawValue: Int + + /// Add virtual frames to show inline function calls. + public static let showInlineFrames: SymbolicationOptions = + SymbolicationOptions(rawValue: 1 << 0) + + /// Look up source locations. + /// + /// This may be expensive in some cases; it may be desirable to turn + /// this off e.g. in Kubernetes so that pods restart promptly on crash. + public static let showSourceLocations: SymbolicationOptions = + SymbolicationOptions(rawValue: 1 << 1) + + /// Use a symbol cache, if one is available. + public static let useSymbolCache: SymbolicationOptions = + SymbolicationOptions(rawValue: 1 << 2) + + public static let `default`: SymbolicationOptions = [.showInlineFrames, + .showSourceLocations, + .useSymbolCache] + + public init(rawValue: Int) { + self.rawValue = rawValue + } + } + + /// Return a symbolicated version of the backtrace. + /// + /// - images: Specifies the set of images to use for symbolication. + /// If `nil`, the function will look to see if the `Backtrace` + /// has already captured images. If it has, those will be + /// used; otherwise we will capture images at this point. + /// + /// - options: Symbolication options; see `SymbolicationOptions`. + public func symbolicated(with images: ImageMap? = nil, + options: SymbolicationOptions = .default) + -> SymbolicatedBacktrace? { + return SymbolicatedBacktrace.symbolicate( + backtrace: self, + images: images, + options: options + ) + } + + /// Provide a textual version of the backtrace. + public var description: String { + var lines: [String] = ["Architecture: \(architecture)", ""] + + var n = 0 + for frame in frames { + lines.append("\(n)\t\(frame.description)") + switch frame { + case let .omittedFrames(count): + n += count + default: + n += 1 + } + } + + if let images = images { + lines.append("") + lines.append("Images:") + lines.append("") + for (n, image) in images.enumerated() { + lines.append("\(n)\t\(image.description)") + } + } + + return lines.joined(separator: "\n") + } + + /// Initialise a Backtrace from a sequence of `RichFrame`s + @_spi(Internal) + public init(architecture: String, + frames: some Sequence>, + images: ImageMap?) { + self.architecture = architecture + self.representation = Array(CompactBacktraceFormat.Encoder(frames)) + self.images = images + } +} + +// -- Capture Implementation ------------------------------------------------- + +extension Backtrace { + + // ###FIXME: There is a problem with @_specialize here that results in the + // arguments not lining up properly when this gets used from + // swift-backtrace. + + @_spi(Internal) + //@_specialize(exported: true, kind: full, where Ctx == HostContext, Rdr == UnsafeLocalMemoryReader) + //@_specialize(exported: true, kind: full, where Ctx == HostContext, Rdr == RemoteMemoryReader) + //#if os(Linux) + //@_specialize(exported: true, kind: full, where Ctx == HostContext, Rdr == MemserverMemoryReader) + //#endif + @inlinable + public static func capture( + from context: Ctx, + using memoryReader: Rdr, + images: ImageMap?, + algorithm: UnwindAlgorithm, + limit: Int? = 64, + offset: Int = 0, + top: Int = 16 + ) throws -> Backtrace { + switch algorithm { + // All of them, for now, use the frame pointer unwinder. In the long + // run, we should be using DWARF EH frame data for .precise. + case .auto, .fast, .precise: + let unwinder = + FramePointerUnwinder(context: context, + images: images, + memoryReader: memoryReader) + + if let limit = limit { + let limited = LimitSequence(unwinder, + limit: limit, + offset: offset, + top: top) + + return Backtrace(architecture: context.architecture, + frames: limited, + images: images) + } + + return Backtrace(architecture: context.architecture, + frames: unwinder.dropFirst(offset), + images: images) + } + } +} diff --git a/stdlib/public/Backtracing/BacktraceFormatter.swift b/stdlib/public/RuntimeModule/BacktraceFormatter.swift similarity index 91% rename from stdlib/public/Backtracing/BacktraceFormatter.swift rename to stdlib/public/RuntimeModule/BacktraceFormatter.swift index cfa6cd886fbf1..71a6fa87195ce 100644 --- a/stdlib/public/Backtracing/BacktraceFormatter.swift +++ b/stdlib/public/RuntimeModule/BacktraceFormatter.swift @@ -527,24 +527,22 @@ public struct BacktraceFormatter { /// Format an individual frame into a list of columns. /// /// @param frame The frame to format. - /// @param addressWidth The width, in characters, of an address. /// @param index The frame index, if required. /// /// @result An array of strings, one per column. public func formatColumns(frame: Backtrace.Frame, - addressWidth: Int, index: Int? = nil) -> [String] { let pc: String var attrs: [String] = [] switch frame { case let .programCounter(address): - pc = "\(hex(address, width: addressWidth))" + pc = "\(address)" case let .returnAddress(address): - pc = "\(hex(address, width: addressWidth))" + pc = "\(address)" attrs.append("ra") case let .asyncResumePoint(address): - pc = "\(hex(address, width: addressWidth))" + pc = "\(address)" attrs.append("async") case .omittedFrames(_), .truncated: pc = "..." @@ -567,30 +565,24 @@ public struct BacktraceFormatter { /// Format a frame into a list of rows. /// /// @param frame The frame to format. - /// @param addressWidth The width, in characters, of an address. /// @param index The frame index, if required. /// /// @result An array of table rows. public func formatRows(frame: Backtrace.Frame, - addressWidth: Int, index: Int? = nil) -> [TableRow] { return [.columns(formatColumns(frame: frame, - addressWidth: addressWidth, index: index))] } /// Format just one frame. /// /// @param frame The frame to format. - /// @param addressWidth The width, in characters, of an address. /// @param index The frame index, if required. /// /// @result A `String` containing the formatted data. public func format(frame: Backtrace.Frame, - addressWidth: Int, index: Int? = nil) -> String { let rows = formatRows(frame: frame, - addressWidth: addressWidth, index: index) return BacktraceFormatter.formatTable(rows, alignments: [.right]) } @@ -598,16 +590,14 @@ public struct BacktraceFormatter { /// Format the frame list from a backtrace. /// /// @param frames The frames to format. - /// @param addressWidth The width, in characters, of an address. /// /// @result A `String` containing the formatted data. - public func format(frames: some Sequence, - addressWidth: Int) -> String { + public func format(frames: some Sequence) -> String { var rows: [TableRow] = [] var n = 0 for frame in frames { - rows += formatRows(frame: frame, addressWidth: addressWidth, index: n) + rows += formatRows(frame: frame, index: n) if case let .omittedFrames(count) = frame { n += count @@ -625,8 +615,7 @@ public struct BacktraceFormatter { /// /// @result A `String` containing the formatted data. public func format(backtrace: Backtrace) -> String { - return format(frames: backtrace.frames, - addressWidth: (backtrace.addressWidth + 3) / 4) + return format(frames: backtrace.frames) } /// Grab source lines for a symbolicated backtrace. @@ -743,19 +732,18 @@ public struct BacktraceFormatter { /// /// @result An array of strings, one per column. public func formatColumns(frame: SymbolicatedBacktrace.Frame, - addressWidth: Int, index: Int? = nil) -> [String] { let pc: String var attrs: [String] = [] switch frame.captured { case let .programCounter(address): - pc = "\(hex(address, width: addressWidth))" + pc = "\(address)" case let .returnAddress(address): - pc = "\(hex(address, width: addressWidth))" + pc = "\(address)" attrs.append("ra") case let .asyncResumePoint(address): - pc = "\(hex(address, width: addressWidth))" + pc = "\(address)" attrs.append("async") case .omittedFrames(_), .truncated: pc = "" @@ -855,16 +843,13 @@ public struct BacktraceFormatter { /// Format a frame into a list of rows. /// /// @param frame The frame to format. - /// @param addressWidth The width, in characters, of an address. /// @param index The frame index, if required. /// /// @result An array of table rows. public func formatRows(frame: SymbolicatedBacktrace.Frame, - addressWidth: Int, index: Int? = nil, showSource: Bool = true) -> [TableRow] { let columns = formatColumns(frame: frame, - addressWidth: addressWidth, index: index) var rows: [TableRow] = [.columns(columns)] @@ -884,16 +869,13 @@ public struct BacktraceFormatter { /// Format just one frame. /// /// @param frame The frame to format. - /// @param addressWidth The width, in characters, of an address. /// @param index The frame index, if required. /// /// @result A `String` containing the formatted data. public func format(frame: SymbolicatedBacktrace.Frame, - addressWidth: Int, index: Int? = nil, showSource: Bool = true) -> String { - let rows = formatRows(frame: frame, addressWidth: addressWidth, - index: index, showSource: showSource) + let rows = formatRows(frame: frame, index: index, showSource: showSource) return BacktraceFormatter.formatTable(rows, alignments: [.right]) } @@ -907,11 +889,11 @@ public struct BacktraceFormatter { /// Format the frame list from a symbolicated backtrace. /// /// @param frames The frames to format. - /// @param addressWidth The width, in characters, of an address. /// /// @result A `String` containing the formatted data. - public func format(frames: some Sequence, - addressWidth: Int) -> String { + public func format( + frames: some Sequence + ) -> String { var rows: [TableRow] = [] var sourceLocationsShown = Set() @@ -931,8 +913,7 @@ public struct BacktraceFormatter { } } - rows += formatRows(frame: frame, addressWidth: addressWidth, - index: n, showSource: showSource) + rows += formatRows(frame: frame, index: n, showSource: showSource) if case let .omittedFrames(count) = frame.captured { n += count @@ -950,16 +931,14 @@ public struct BacktraceFormatter { /// /// @result A `String` containing the formatted data. public func format(backtrace: SymbolicatedBacktrace) -> String { - let addressChars = (backtrace.addressWidth + 3) / 4 - var result = format(frames: backtrace.frames, addressWidth: addressChars) + var result = format(frames: backtrace.frames) switch options._showImages { case .none: break case .all: result += "\n\nImages:\n" - result += format(images: backtrace.images, - addressWidth: addressChars) + result += format(images: backtrace.images) case .mentioned: var mentionedImages = Set() for frame in backtrace.frames { @@ -978,7 +957,7 @@ public struct BacktraceFormatter { } else { result += "\n\nImages (only mentioned):\n" } - result += format(images: images, addressWidth: addressChars) + result += format(images: images) } return result @@ -987,28 +966,31 @@ public struct BacktraceFormatter { /// Format a `Backtrace.Image` into a list of columns. /// /// @param image The `Image` object to format. - /// @param addressWidth The width of an address, in characters. /// /// @result An array of strings, one per column. - public func formatColumns(image: Backtrace.Image, - addressWidth: Int) -> [String] { - let addressRange = "\(hex(image.baseAddress, width: addressWidth))–\(hex(image.endOfText, width: addressWidth))" + public func formatColumns(image: Backtrace.Image) -> [String] { + let addressRange = "\(image.baseAddress)–\(image.endOfText)" let buildID: String - if let bytes = image.buildID { + if let bytes = image.uniqueID { buildID = hex(bytes) } else { buildID = "" } let imagePath: String - if options._sanitizePaths { - imagePath = sanitizePath(image.path) + if let path = image.path { + if options._sanitizePaths { + imagePath = sanitizePath(path) + } else { + imagePath = path + } } else { - imagePath = image.path + imagePath = "" } + let imageName = image.name ?? "" return [ options._theme.imageAddressRange(addressRange), options._theme.imageBuildID(buildID), - options._theme.imageName(image.name), + options._theme.imageName(imageName), options._theme.imagePath(imagePath) ] } @@ -1016,15 +998,12 @@ public struct BacktraceFormatter { /// Format an array of `Backtrace.Image`s. /// /// @param images The array of `Image` objects to format. - /// @param addressWidth The width of an address, in characters. /// /// @result A string containing the formatted data. - public func format(images: some Sequence, - addressWidth: Int) -> String { + public func format(images: some Sequence) -> String { let rows = images.map{ TableRow.columns( - formatColumns(image: $0, - addressWidth: addressWidth) + formatColumns(image: $0) ) } diff --git a/stdlib/public/RuntimeModule/Base64.swift b/stdlib/public/RuntimeModule/Base64.swift new file mode 100644 index 0000000000000..608ce60eb9947 --- /dev/null +++ b/stdlib/public/RuntimeModule/Base64.swift @@ -0,0 +1,333 @@ +//===--- Base64.swift -----------------------------------------*- swift -*-===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2024 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 +// +//===----------------------------------------------------------------------===// +// +// Encode and decode sequences of bytes as base64. +// +//===----------------------------------------------------------------------===// + +import Swift + +// Forward mapping (we encode normal base64) +fileprivate let forwardMapping: ( + UTF8.CodeUnit, UTF8.CodeUnit, UTF8.CodeUnit, UTF8.CodeUnit, + UTF8.CodeUnit, UTF8.CodeUnit, UTF8.CodeUnit, UTF8.CodeUnit, + UTF8.CodeUnit, UTF8.CodeUnit, UTF8.CodeUnit, UTF8.CodeUnit, + UTF8.CodeUnit, UTF8.CodeUnit, UTF8.CodeUnit, UTF8.CodeUnit, + UTF8.CodeUnit, UTF8.CodeUnit, UTF8.CodeUnit, UTF8.CodeUnit, + UTF8.CodeUnit, UTF8.CodeUnit, UTF8.CodeUnit, UTF8.CodeUnit, + UTF8.CodeUnit, UTF8.CodeUnit, UTF8.CodeUnit, UTF8.CodeUnit, + UTF8.CodeUnit, UTF8.CodeUnit, UTF8.CodeUnit, UTF8.CodeUnit, + UTF8.CodeUnit, UTF8.CodeUnit, UTF8.CodeUnit, UTF8.CodeUnit, + UTF8.CodeUnit, UTF8.CodeUnit, UTF8.CodeUnit, UTF8.CodeUnit, + UTF8.CodeUnit, UTF8.CodeUnit, UTF8.CodeUnit, UTF8.CodeUnit, + UTF8.CodeUnit, UTF8.CodeUnit, UTF8.CodeUnit, UTF8.CodeUnit, + UTF8.CodeUnit, UTF8.CodeUnit, UTF8.CodeUnit, UTF8.CodeUnit, + UTF8.CodeUnit, UTF8.CodeUnit, UTF8.CodeUnit, UTF8.CodeUnit, + UTF8.CodeUnit, UTF8.CodeUnit, UTF8.CodeUnit, UTF8.CodeUnit, + UTF8.CodeUnit, UTF8.CodeUnit, UTF8.CodeUnit, UTF8.CodeUnit +) = ( + // A B C D E F G H + 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, + // I J K L M N O P + 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, 0x50, + // Q R S T U V W X + 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, + // Y Z a b c d e f + 0x59, 0x5a, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, + // g h i j k l m n + 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, + // o p q r s t u v + 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, + // w x y z 0 1 2 3 + 0x77, 0x78, 0x79, 0x7a, 0x30, 0x31, 0x32, 0x33, + // 4 5 6 7 8 9 + / + 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x2b, 0x2f +) + +fileprivate func forward(at ndx: Int) -> UTF8.CodeUnit { + precondition(ndx >= 0 && ndx < 64) + return withUnsafePointer(to: forwardMapping) { + $0.withMemoryRebound(to: UTF8.CodeUnit.self, + capacity: 64) { table in + return table[ndx] + } + } +} + +// Reverse (we support URL-safe and normal base64) +fileprivate let reverseMapping: ( + Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, + Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, + Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, + Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, + Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, + Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, + Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, + Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, + Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, + Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, + Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, + Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, + Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, + Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, + Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, + Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8 +) = ( +// + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, +// + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, +// + - / + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, 62, -1, 63, +// 0 1 2 3 4 5 6 7 8 9 + 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1, +// A B C D E F G H I J K L M N O + -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, +// P Q R S T U V W X Y Z _ + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, 63, +// a b c d e f g h i j k l m n o + -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, +// p q r s t u v w x y z + 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1 +) + +fileprivate func reverse(at char: UTF8.CodeUnit) -> UInt8? { + if char >= 128 { + return nil + } + return withUnsafePointer(to: reverseMapping) { + $0.withMemoryRebound(to: Int8.self, + capacity: 128) { + (table: UnsafePointer) -> UInt8? in + + let value = table[Int(char)] + guard value >= 0 else { + return nil + } + return UInt8(truncatingIfNeeded: value) + } + } +} + +@_spi(Base64) +public struct Base64Encoder: Sequence + where S.Element == UInt8 +{ + public typealias Element = UTF8.CodeUnit + + var source: S + + public init(source: S) { + self.source = source + } + + public func makeIterator() -> Iterator { + return Iterator(source: source) + } + + public struct Iterator: IteratorProtocol { + public typealias Element = UTF8.CodeUnit + + var sourceIterator: S.Iterator + var output: (UTF8.CodeUnit, UTF8.CodeUnit, UTF8.CodeUnit) + var ndx: Int + var buffer: UInt32 + var count: Int + + init(source: S) { + sourceIterator = source.makeIterator() + output = (0, 0, 0) + buffer = 0 + count = 0 + ndx = 3 + } + + public mutating func next() -> UTF8.CodeUnit? { + // If we have bytes, output those first + switch ndx { + case 0: + ndx += 1 + return output.0 + case 1: + ndx += 1 + return output.1 + case 2: + ndx += 1 + return output.2 + default: + break + } + + // Now try to refill the buffer with up to three bytes + buffer = 0 + count = 0 + while count < 3 { + if let byte = sourceIterator.next() { + buffer = (buffer << 8) | UInt32(truncatingIfNeeded: byte) + } else { + break + } + count += 1 + } + + switch count { + case 0: + return nil + case 1: + let first = Int(buffer >> 2) + let second = Int((buffer << 4) & 0x3f) + output.2 = forward(at: second) + ndx = 2 + return forward(at: first) + case 2: + let first = Int(buffer >> 10) + let second = Int((buffer >> 4) & 0x3f) + let third = Int((buffer << 2) & 0x3f) + output.1 = forward(at: second) + output.2 = forward(at: third) + ndx = 1 + return forward(at: first) + case 3: + let first = Int(buffer >> 18) + let second = Int((buffer >> 12) & 0x3f) + let third = Int((buffer >> 6) & 0x3f) + let fourth = Int(buffer & 0x3f) + output.0 = forward(at: second) + output.1 = forward(at: third) + output.2 = forward(at: fourth) + ndx = 0 + return forward(at: first) + default: + fatalError("count has an impossible value") + } + } + } +} + +@_spi(Base64) +public struct Base64Decoder: Sequence + where S.Element == UTF8.CodeUnit +{ + public typealias Element = UInt8 + + var source: S + + public init(source: S) { + self.source = source + } + + public func makeIterator() -> Iterator { + return Iterator(source: source) + } + + public struct Iterator: IteratorProtocol { + public typealias Element = UInt8 + + var sourceIterator: S.Iterator + var output: (UInt8, UInt8) + var ndx: Int + var buffer: UInt32 + var count: Int + var bad: Bool + var done: Bool + + init(source: S) { + sourceIterator = source.makeIterator() + output = (0, 0) + ndx = 2 + buffer = 0 + count = 0 + bad = false + done = false + } + + public mutating func next() -> UInt8? { + if bad { + return nil + } + + // If we have bytes, output those first + switch ndx { + case 0: + ndx += 1 + return output.0 + case 1: + ndx += 1 + return output.1 + default: + break + } + + // If we've finished, stop + if done { + return nil + } + + // Now try to refill the buffer + count = 0 + while count < 4 { + if let encoded = sourceIterator.next() { + if encoded >= 128 { + bad = true + return nil + } + + // '=' + if encoded == 0x3d { + break + } + + guard let value = reverse(at: encoded) else { + bad = true + return nil + } + + buffer = (buffer << 6) | UInt32(truncatingIfNeeded: value) + count += 1 + } else { + break + } + } + + switch count { + case 0: + return nil + case 1: + bad = true + return nil + case 2: + // 12 bits + done = true + return UInt8(truncatingIfNeeded: buffer >> 4) + case 3: + // 18 bits + done = true + let first = UInt8(truncatingIfNeeded: buffer >> 10) + let second = UInt8(truncatingIfNeeded: buffer >> 2) + output.1 = second + ndx = 1 + return first + case 4: + // 24 bits + let first = UInt8(truncatingIfNeeded: buffer >> 16) + let second = UInt8(truncatingIfNeeded: buffer >> 8) + let third = UInt8(truncatingIfNeeded: buffer) + output.0 = second + output.1 = third + ndx = 0 + return first + default: + fatalError("count has an impossible value") + } + } + } +} diff --git a/stdlib/public/Backtracing/ByteSwapping.swift b/stdlib/public/RuntimeModule/ByteSwapping.swift similarity index 100% rename from stdlib/public/Backtracing/ByteSwapping.swift rename to stdlib/public/RuntimeModule/ByteSwapping.swift diff --git a/stdlib/public/Backtracing/CMakeLists.txt b/stdlib/public/RuntimeModule/CMakeLists.txt similarity index 69% rename from stdlib/public/Backtracing/CMakeLists.txt rename to stdlib/public/RuntimeModule/CMakeLists.txt index 2a61525fb0181..dc72ae13c8e71 100644 --- a/stdlib/public/Backtracing/CMakeLists.txt +++ b/stdlib/public/RuntimeModule/CMakeLists.txt @@ -1,4 +1,4 @@ -#===--- CMakeLists.txt - Backtracing support library -----------------------===# +#===--- CMakeLists.txt - Runtime module ------------------------------------===# # # This source file is part of the Swift.org open source project # @@ -9,8 +9,10 @@ # See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors # #===------------------------------------------------------------------------===# - -set(swift_backtracing_link_libraries +# +# The Runtime module isn't the runtime itself; that lives in libswiftCore; +# rather, it's a high level Swift interface to things +set(swift_runtime_link_libraries swiftCore swift_Concurrency ) @@ -20,27 +22,37 @@ if(SWIFT_BUILD_STDLIB AND SWIFT_ENABLE_EXPERIMENTAL_CONCURRENCY) set(concurrency _Concurrency) endif() -set(BACKTRACING_SOURCES - ArrayImageSource.swift +set(RUNTIME_SOURCES + Address.swift Backtrace.swift + Backtrace+Codable.swift BacktraceFormatter.swift + Base64.swift ByteSwapping.swift CachingMemoryReader.swift - Context.swift + CompactBacktrace.swift + CompactImageMap.swift Compression.swift + Context.swift CoreSymbolication.swift Dwarf.swift + EightByteBuffer.swift Elf.swift - FileImageSource.swift + ElfImageCache.swift FramePointerUnwinder.swift Image.swift + ImageMap.swift + ImageMap+Darwin.swift + ImageMap+Linux.swift ImageSource.swift - MemoryImageSource.swift Libc.swift + LimitSequence.swift MemoryReader.swift + OSReleaseScanner.swift ProcMapsScanner.swift Registers.swift Runtime.swift + RichFrame.swift SymbolicatedBacktrace.swift Utils.swift Win32Extras.cpp @@ -48,24 +60,24 @@ set(BACKTRACING_SOURCES get-cpu-context.${SWIFT_ASM_EXT} ) -set(BACKTRACING_COMPILE_FLAGS +set(RUNTIME_COMPILE_FLAGS "-cxx-interoperability-mode=default" "-Xfrontend;-experimental-spi-only-imports" "-Xcc;-I${SWIFT_SOURCE_DIR}/include" "-Xcc;-I${CMAKE_BINARY_DIR}/include" - "-Xcc;-I${SWIFT_STDLIB_SOURCE_DIR}/public/Backtracing/modules" + "-Xcc;-I${SWIFT_STDLIB_SOURCE_DIR}/public/RuntimeModule/modules" "-disable-upcoming-feature;MemberImportVisibility") ###TODO: Add these when we add static linking support # -#list(APPEND BACKTRACING_COMPILE_FLAGS +#list(APPEND RUNTIME_COMPILE_FLAGS # "-Xcc;-I${SWIFT_PATH_TO_ZLIB_SOURCE}" # "-Xcc;-I${SWIFT_PATH_TO_ZSTD_SOURCE}/lib" # "-Xcc;-I${SWIFT_PATH_TO_LIBLZMA_SOURCE}/src/liblzma/api") if(SWIFT_ASM_AVAILABLE) - list(APPEND BACKTRACING_SOURCES get-cpu-context.${SWIFT_ASM_EXT}) - list(APPEND BACKTRACING_COMPILE_FLAGS "-DSWIFT_ASM_AVAILABLE") + list(APPEND RUNTIME_SOURCES get-cpu-context.${SWIFT_ASM_EXT}) + list(APPEND RUNTIME_COMPILE_FLAGS "-DSWIFT_ASM_AVAILABLE") else() message(warning "Assembly language not available on this platform; backtracing will fail.") endif() @@ -75,8 +87,8 @@ set(LLVM_OPTIONAL_SOURCES get-cpu-context.asm ) -add_swift_target_library(swift_Backtracing ${SWIFT_STDLIB_LIBRARY_BUILD_TYPES} IS_STDLIB - ${BACKTRACING_SOURCES} +add_swift_target_library(swiftRuntime ${SWIFT_STDLIB_LIBRARY_BUILD_TYPES} IS_STDLIB + ${RUNTIME_SOURCES} SWIFT_MODULE_DEPENDS ${concurrency} @@ -89,11 +101,11 @@ add_swift_target_library(swift_Backtracing ${SWIFT_STDLIB_LIBRARY_BUILD_TYPES} I SWIFT_MODULE_DEPENDS_HAIKU Glibc SWIFT_MODULE_DEPENDS_WINDOWS CRT - PRIVATE_LINK_LIBRARIES ${swift_backtracing_link_libraries} + PRIVATE_LINK_LIBRARIES ${swift_runtime_link_libraries} SWIFT_COMPILE_FLAGS ${SWIFT_STANDARD_LIBRARY_SWIFT_FLAGS} - ${BACKTRACING_COMPILE_FLAGS} + ${RUNTIME_COMPILE_FLAGS} -parse-stdlib LINK_FLAGS diff --git a/stdlib/public/Backtracing/CachingMemoryReader.swift b/stdlib/public/RuntimeModule/CachingMemoryReader.swift similarity index 64% rename from stdlib/public/Backtracing/CachingMemoryReader.swift rename to stdlib/public/RuntimeModule/CachingMemoryReader.swift index 967f3a5394b6c..33c8d10aeb89e 100644 --- a/stdlib/public/Backtracing/CachingMemoryReader.swift +++ b/stdlib/public/RuntimeModule/CachingMemoryReader.swift @@ -18,18 +18,17 @@ import Swift // The size of the pages in the page cache (must be a power of 2) fileprivate let pageSize = 4096 - fileprivate let pageMask = pageSize - 1 // The largest chunk we will try to cache data for fileprivate let maxCachedSize = pageSize * 8 @_spi(MemoryReaders) -public class CachingMemoryReader: MemoryReader { - private var reader: T +public class CachingMemoryReader: MemoryReader { + private var reader: Reader private var cache: [Address:UnsafeRawBufferPointer] - public init(for reader: T) { + public init(for reader: Reader) { self.reader = reader self.cache = [:] } @@ -40,7 +39,7 @@ public class CachingMemoryReader: MemoryReader { } } - private func getPage(at address: Address) throws -> UnsafeRawBufferPointer { + func getPage(at address: Address) throws -> UnsafeRawBufferPointer { precondition((address & Address(pageMask)) == 0) if let page = cache[address] { @@ -84,3 +83,39 @@ public class CachingMemoryReader: MemoryReader { } } } + +#if os(Linux) +@_spi(MemoryReaders) +public typealias MemserverMemoryReader + = CachingMemoryReader + +extension CachingMemoryReader where Reader == UncachedMemserverMemoryReader { + convenience public init(fd: CInt) { + self.init(for: UncachedMemserverMemoryReader(fd: fd)) + } +} +#endif + +@_spi(MemoryReaders) +public typealias RemoteMemoryReader = CachingMemoryReader + +extension CachingMemoryReader where Reader == UncachedRemoteMemoryReader { + #if os(macOS) + convenience public init(task: Any) { + self.init(for: UncachedRemoteMemoryReader(task: task)) + } + #elseif os(Linux) + convenience public init(pid: Any) { + self.init(for: UncachedRemoteMemoryReader(pid: pid)) + } + #endif +} + +@_spi(MemoryReaders) +public typealias LocalMemoryReader = CachingMemoryReader + +extension CachingMemoryReader where Reader == UncachedLocalMemoryReader { + convenience public init() { + self.init(for: UncachedLocalMemoryReader()) + } +} diff --git a/stdlib/public/RuntimeModule/CompactBacktrace.swift b/stdlib/public/RuntimeModule/CompactBacktrace.swift new file mode 100644 index 0000000000000..7a8fc3559a60c --- /dev/null +++ b/stdlib/public/RuntimeModule/CompactBacktrace.swift @@ -0,0 +1,660 @@ +//===--- CompactBacktrace.swift -------------------------------*- swift -*-===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2024 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 +// +//===----------------------------------------------------------------------===// +// +// Definitions for Compact Backtrace Format +// +//===----------------------------------------------------------------------===// + +import Swift + +enum CompactBacktraceFormat { + /// Tells us what size of machine words were used when generating the + /// backtrace. + enum WordSize: UInt8 { + case sixteenBit = 0 + case thirtyTwoBit = 1 + case sixtyFourBit = 2 + } + + // Instruction encodings + struct Instruction: RawRepresentable { + typealias RawValue = UInt8 + + private(set) var rawValue: UInt8 + + init?(rawValue: Self.RawValue) { + self.rawValue = rawValue + } + + static let end = Instruction(rawValue: 0b00000000)! + static let trunc = Instruction(rawValue: 0b00000001)! + + static let pc_first = Instruction(rawValue: 0b00010000)! + static let pc_last = Instruction(rawValue: 0b00011111)! + static let ra_first = Instruction(rawValue: 0b00100000)! + static let ra_last = Instruction(rawValue: 0b00101111)! + static let async_first = Instruction(rawValue: 0b00110000)! + static let async_last = Instruction(rawValue: 0b00111111)! + + static let omit_first = Instruction(rawValue: 0b01000000)! + static let omit_last = Instruction(rawValue: 0b01111111)! + + static let rep_first = Instruction(rawValue: 0b10000000)! + static let rep_last = Instruction(rawValue: 0b10001111)! + + private static func addressInstr( + _ code: UInt8, _ absolute: Bool, _ count: Int + ) -> Instruction { + return Instruction(rawValue: code + | (absolute ? 0b00001000 : 0) + | UInt8(count - 1))! + } + + static func pc(absolute: Bool, count: Int) -> Instruction { + return addressInstr(0b00010000, absolute, count) + } + static func ra(absolute: Bool, count: Int) -> Instruction { + return addressInstr(0b00100000, absolute, count) + } + static func `async`(absolute: Bool, count: Int) -> Instruction { + return addressInstr(0b00110000, absolute, count) + } + + static func omit(external: Bool, count: Int) -> Instruction { + return Instruction(rawValue: 0b01000000 + | (external ? 0b00100000 : 0) + | UInt8(count - 1))! + } + + static func rep(external: Bool, count: Int) -> Instruction { + return Instruction(rawValue: 0b10000000 + | (external ? 0b00001000 : 0) + | UInt8(count - 1))! + } + } + + // Represents a decoded instruction + enum DecodedInstruction { + case end + case trunc + case pc(absolute: Bool, count: Int) + case ra(absolute: Bool, count: Int) + case `async`(absolute: Bool, count: Int) + case omit(external: Bool, count: Int) + case rep(external: Bool, count: Int) + } + + + /// Accumulates bytes until the end of a Compact Backtrace Format + /// sequence is detected. + public struct Accumulator>: Sequence { + public typealias Element = UInt8 + typealias Source = S + + private var source: S + + public init(_ source: S) { + self.source = source + } + + public func makeIterator() -> Iterator { + return Iterator(source.makeIterator()) + } + + public struct Iterator: IteratorProtocol { + var iterator: Source.Iterator? + + enum State { + case infoByte + case instruction + case argumentData(Int) + } + + var state: State + + init(_ iterator: Source.Iterator?) { + self.iterator = iterator + self.state = .infoByte + } + + private mutating func finished() { + iterator = nil + } + + private mutating func fail() { + iterator = nil + } + + public mutating func next() -> UInt8? { + if iterator == nil { + return nil + } + + switch state { + case .infoByte: + guard let infoByte = iterator!.next() else { + fail() + return nil + } + let version = infoByte >> 2 + guard let _ = WordSize(rawValue: infoByte & 0x3) else { + fail() + return nil + } + guard version == 0 else { + fail() + return nil + } + + state = .instruction + + return infoByte + + case .instruction: + guard let instr = iterator!.next() else { + finished() + return nil + } + + guard let decoded = Instruction(rawValue: instr)?.decoded() else { + fail() + return nil + } + + switch decoded { + case .end, .trunc: + finished() + return instr + case let .pc(_, count), let .ra(_, count), let .async(_, count): + state = .argumentData(count) + return instr + case let .omit(external, count), let .rep(external, count): + if external { + state = .argumentData(count) + } + return instr + } + + case let .argumentData(count): + guard let byte = iterator!.next() else { + fail() + return nil + } + + let newCount = count - 1 + if newCount == 0 { + state = .instruction + } else { + state = .argumentData(newCount) + } + + return byte + } + } + } + } + + /// Adapts a Sequence containing Compact Backtrace Format data into a + /// Sequence of `Backtrace.Frame`s. + struct Decoder>: Sequence { + typealias Frame = Backtrace.Frame + typealias Address = Backtrace.Address + typealias Storage = S + + private var storage: Storage + + init(_ storage: S) { + self.storage = storage + } + + public func makeIterator() -> Iterator { + var iterator = storage.makeIterator() + guard let infoByte = iterator.next() else { + return Iterator(nil, .sixtyFourBit) + } + let version = infoByte >> 2 + guard let size = WordSize(rawValue: infoByte & 0x3) else { + return Iterator(nil, .sixtyFourBit) + } + guard version == 0 else { + return Iterator(nil, .sixtyFourBit) + } + return Iterator(iterator, size) + } + + struct Iterator: IteratorProtocol { + var iterator: Storage.Iterator? + let wordSize: WordSize + let wordMask: UInt64 + var lastAddress: UInt64 + var lastFrame: Backtrace.Frame? + var repeatCount: Int = 0 + + init(_ iterator: Storage.Iterator?, _ size: WordSize) { + self.iterator = iterator + self.wordSize = size + + switch size { + case .sixteenBit: + self.wordMask = 0xff00 + case .thirtyTwoBit: + self.wordMask = 0xffffff00 + case .sixtyFourBit: + self.wordMask = 0xffffffffffffff00 + } + + self.lastAddress = 0 + } + + private mutating func decodeAddress( + _ absolute: Bool, _ count: Int + ) -> Address? { + var word: UInt64 + guard let firstByte = iterator!.next() else { + return nil + } + if (firstByte & 0x80) != 0 { + word = wordMask | UInt64(firstByte) + } else { + word = UInt64(firstByte) + } + for _ in 1.. Int? { + var word: Int = 0 + for _ in 0.. Backtrace.Frame? { + if repeatCount > 0 { + repeatCount -= 1 + return lastFrame + } + + if iterator == nil { + return nil + } + + guard let instr = iterator!.next() else { + finished() + return .truncated + } + + guard let decoded = Instruction(rawValue: instr)?.decoded() else { + fail() + return .truncated + } + + let result: Backtrace.Frame + switch decoded { + case .end: + finished() + return nil + case .trunc: + finished() + return .truncated + case let .pc(absolute, count): + guard let addr = decodeAddress(absolute, count) else { + finished() + return .truncated + } + result = .programCounter(addr) + case let .ra(absolute, count): + guard let addr = decodeAddress(absolute, count) else { + finished() + return .truncated + } + result = .returnAddress(addr) + case let .async(absolute, count): + guard let addr = decodeAddress(absolute, count) else { + finished() + return .truncated + } + result = .asyncResumePoint(addr) + case let .omit(external, count): + if !external { + result = .omittedFrames(count) + } else { + guard let word = decodeWord(count) else { + finished() + return .truncated + } + result = .omittedFrames(word) + } + case let .rep(external, count): + if lastFrame == nil { + finished() + return .truncated + } + if !external { + repeatCount = count - 1 + } else { + guard let word = decodeWord(count) else { + finished() + return .truncated + } + repeatCount = word - 1 + } + result = lastFrame! + } + + lastFrame = result + + return result + } + } + + } + + /// Adapts a Sequence of RichFrames into a sequence containing Compact + /// Backtrace Format data. + struct Encoder>>: Sequence { + typealias Element = UInt8 + typealias Frame = Backtrace.Frame + typealias SourceFrame = RichFrame + typealias Address = A + typealias Source = S + + private var source: Source + + init(_ source: Source) { + self.source = source + } + + public func makeIterator() -> Iterator { + return Iterator(source.makeIterator()) + } + + struct Iterator: IteratorProtocol { + var iterator: Source.Iterator + var lastAddress: Address = 0 + + enum State { + case start + case ready + case emittingBytes(Int, SourceFrame?) + case stashedFrame(SourceFrame) + case done + } + var bytes = EightByteBuffer() + var state: State = .start + var lastFrame: SourceFrame? = nil + + init(_ iterator: Source.Iterator) { + self.iterator = iterator + } + + /// Set up to emit the bytes of `address`, returning the number of bytes + /// we will need to emit + private mutating func emitNext( + address: Address + ) -> (absolute: Bool, count: Int) { + let delta = address &- lastAddress + + let absCount: Int + if address & (1 << (Address.bitWidth - 1)) != 0 { + let ones = ((~address).leadingZeroBitCount - 1) >> 3 + absCount = (Address.bitWidth >> 3) - ones + } else { + let zeroes = (address.leadingZeroBitCount - 1) >> 3 + absCount = (Address.bitWidth >> 3) - zeroes + } + + let deltaCount: Int + if delta & (1 << (Address.bitWidth - 1)) != 0 { + let ones = ((~delta).leadingZeroBitCount - 1) >> 3 + deltaCount = (Address.bitWidth >> 3) - ones + } else { + let zeroes = (delta.leadingZeroBitCount - 1) >> 3 + deltaCount = (Address.bitWidth >> 3) - zeroes + } + + lastAddress = address + + if absCount < deltaCount { + bytes = EightByteBuffer(address) + state = .emittingBytes(8 - absCount, nil) + return (absolute: true, count: absCount) + } else { + bytes = EightByteBuffer(delta) + state = .emittingBytes(8 - deltaCount, nil) + return (absolute: false, count: deltaCount) + } + } + + /// Set up to emit the bytes of `count`, returning the number of bytes + /// we will need to emit + private mutating func emitNext( + externalCount count: Int + ) -> Int { + let ucount = UInt64(count) + let zeroes = ucount.leadingZeroBitCount >> 3 + let byteCount = 8 - zeroes + bytes = EightByteBuffer(ucount) + state = .emittingBytes(zeroes, nil) + return byteCount + } + + private mutating func emitNext( + frame: SourceFrame?, + externalCount count: Int? = nil + ) -> Int { + if let count { + let ucount = UInt64(count) + let zeroes = ucount.leadingZeroBitCount >> 3 + let byteCount = 8 - zeroes + bytes = EightByteBuffer(ucount) + state = .emittingBytes(zeroes, frame) + return byteCount + } else if let frame { + state = .stashedFrame(frame) + } else { + state = .ready + } + return 0 + } + + private mutating func emit(frame: SourceFrame) -> UInt8 { + lastFrame = frame + + switch frame { + case let .programCounter(addr): + let (absolute, count) = emitNext(address: addr) + return Instruction.pc(absolute: absolute, + count: count).rawValue + case let .returnAddress(addr): + let (absolute, count) = emitNext(address: addr) + return Instruction.ra(absolute: absolute, + count: count).rawValue + case let .asyncResumePoint(addr): + let (absolute, count) = emitNext(address: addr) + return Instruction.async(absolute: absolute, + count: count).rawValue + case let .omittedFrames(count): + if count <= 0x1f { + return Instruction.omit(external: false, + count: count).rawValue + } + let countCount = emitNext(externalCount: count) + return Instruction.omit(external: true, + count: countCount).rawValue + case .truncated: + self.state = .done + return Instruction.trunc.rawValue + } + } + + public mutating func next() -> UInt8? { + switch state { + case .done: + return nil + + case .start: + // The first thing we emit is the info byte + let size: WordSize + switch Address.bitWidth { + case 16: + size = .sixteenBit + case 32: + size = .thirtyTwoBit + case 64: + size = .sixtyFourBit + default: + state = .done + return nil + } + + state = .ready + + let version: UInt8 = 0 + let infoByte = (version << 2) | size.rawValue + return infoByte + + case let .emittingBytes(ndx, frame): + + let byte = bytes[ndx] + if ndx + 1 == 8 { + if let frame { + state = .stashedFrame(frame) + } else { + state = .ready + } + } else { + state = .emittingBytes(ndx + 1, frame) + } + return byte + + case .ready: + + // Grab a rich frame and encode it + guard let frame = iterator.next() else { + state = .done + return nil + } + + if let lastFrame, lastFrame == frame { + var count = 1 + var nextFrame: SourceFrame? = nil + while let frame = iterator.next() { + if frame != lastFrame { + nextFrame = frame + break + } else { + count += 1 + } + } + + if count <= 8 { + _ = emitNext(frame: nextFrame) + return Instruction.rep(external: false, + count: count).rawValue + } else { + let countCount = emitNext(frame: nextFrame, + externalCount: count) + return Instruction.rep(external: true, + count: countCount).rawValue + } + } + + return emit(frame: frame) + + case let .stashedFrame(frame): + + state = .ready + + return emit(frame: frame) + } + } + } + } +} + +extension CompactBacktraceFormat.Instruction: Comparable { + public static func < (lhs: Self, rhs: Self) -> Bool { + return lhs.rawValue < rhs.rawValue + } + public static func == (lhs: Self, rhs: Self) -> Bool { + return lhs.rawValue == rhs.rawValue + } +} + +extension CompactBacktraceFormat.Instruction { + func decoded() -> CompactBacktraceFormat.DecodedInstruction? { + switch self { + case .end: + return .end + case .trunc: + return .trunc + case .pc_first ... .pc_last: + let count = Int((self.rawValue & 0x7) + 1) + let absolute = (self.rawValue & 0x8) != 0 + return .pc(absolute: absolute, count: count) + case .ra_first ... .ra_last: + let count = Int((self.rawValue & 0x7) + 1) + let absolute = (self.rawValue & 0x8) != 0 + return .ra(absolute: absolute, count: count) + case .async_first ... .async_last: + let count = Int((self.rawValue & 0x7) + 1) + let absolute = (self.rawValue & 0x8) != 0 + return .async(absolute: absolute, count: count) + case .omit_first ... .omit_last: + let count = Int((self.rawValue & 0x1f) + 1) + let external = (self.rawValue & 0x20) != 0 + return .omit(external: external, count: count) + case .rep_first ... .rep_last: + let count = Int((self.rawValue & 0x7) + 1) + let external = (self.rawValue & 0x8) != 0 + return .rep(external: external, count: count) + default: + return nil + } + } +} diff --git a/stdlib/public/RuntimeModule/CompactImageMap.swift b/stdlib/public/RuntimeModule/CompactImageMap.swift new file mode 100644 index 0000000000000..f76233ebbdd00 --- /dev/null +++ b/stdlib/public/RuntimeModule/CompactImageMap.swift @@ -0,0 +1,804 @@ +//===--- CompactImageMap.swift -------------------------------*- swift -*-===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2024 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 +// +//===----------------------------------------------------------------------===// +// +// Definitions for Compact ImageMap Format +// +//===----------------------------------------------------------------------===// + +import Swift + +private let slash = UInt8(ascii: "/") +private let backslash = UInt8(ascii: "\\") + +@_spi(Internal) +public enum CompactImageMapFormat { + + /// The list of fixed prefixes used to encode paths. + static let fixedPathPrefixes = [ + // Traditional UNIX + (0, "/lib"), + (1, "/usr/lib"), + (2, "/usr/local/lib"), + (3, "/opt/lib"), + + // NeXT/Darwin + (4, "/System/Library/Frameworks"), + (5, "/System/Library/PrivateFrameworks"), + (6, "/System/iOSSupport"), + (7, "/Library/Frameworks"), + (8, "/System/Applications"), + (9, "/Applications"), + + // Windows + (10, "C:\\Windows\\System32"), + (11, "C:\\Program Files") + ] + + /// Tells us what size of machine words were used when generating the + /// image map. + enum WordSize: UInt8 { + case sixteenBit = 0 + case thirtyTwoBit = 1 + case sixtyFourBit = 2 + } + + /// Run a closure for each prefix of the specified string + static func forEachPrefix(of str: String.UTF8View.SubSequence, + body: (String) -> ()) { + let base = str.startIndex + let end = str.endIndex + var pos = base + + while pos < end { + let ch = str[pos] + + if pos > base && (ch == slash || ch == backslash) { + let range = base..> { + var sequence: S + var iterator: S.Iterator + var imageCount: Int = 0 + var wordSize: WordSize = .sixtyFourBit + var wordMask: UInt64 = 0 + var pathPrefixes = Dictionary(uniqueKeysWithValues: fixedPathPrefixes) + var nextCode = 32 + + public init(_ sequence: S) { + self.sequence = sequence + self.iterator = sequence.makeIterator() + } + + mutating func decodeCount() -> Int? { + var value: Int = 0 + while true { + guard let byte = iterator.next() else { + return nil + } + + value = (value << 7) | Int(byte & 0x7f) + + if (byte & 0x80) == 0 { + break + } + } + return value + } + + mutating func decodeString() -> String? { + guard let utf8Length = iterator.next() else { + return nil + } + + var bytes: [UInt8] = [] + bytes.reserveCapacity(Int(utf8Length)) + + for _ in 0.. UInt64? { + var word: UInt64 + guard let firstByte = iterator.next() else { + return nil + } + + // Sign extend + if (firstByte & 0x80) != 0 { + word = wordMask | UInt64(firstByte) + } else { + word = UInt64(firstByte) + } + + for _ in 1.. String? { + var byte: UInt8 + + guard let b = iterator.next() else { + return nil + } + + byte = b + + // `end` here means no string at all + if byte == 0x00 { + return nil + } + + var resultBytes: [UInt8] = [] + var stringBase: Int? = nil + + while true { + if byte == 0x00 { + // `end` + #if DEBUG_COMPACT_IMAGE_MAP + print("end") + #endif + return String(decoding: resultBytes, as: UTF8.self) + } else if byte < 0x40 { + // `str` + let count = Int(byte) + resultBytes.reserveCapacity(resultBytes.count + count) + let base = resultBytes.count + if stringBase == nil { + stringBase = base + } + for n in 0.. stringBase! && (char == slash + || char == backslash) { + let prefix = String(decoding: resultBytes[stringBase!.. (String, [ImageMap.Image], ImageMap.WordSize)? { + // Check the version and decode the size + guard let infoByte = iterator.next() else { + return nil + } + let version = infoByte >> 2 + guard let size = WordSize(rawValue: infoByte & 0x3) else { + return nil + } + wordSize = size + guard version == 0 else { + return nil + } + + // Set up the word mask + switch wordSize { + case .sixteenBit: + wordMask = 0xff00 + case .thirtyTwoBit: + wordMask = 0xffffff00 + case .sixtyFourBit: + wordMask = 0xffffffffffffff00 + } + + // Now decode the platform + guard let platform = decodeString() else { + return nil + } + + // Next is the image count + guard let count = decodeCount() else { + return nil + } + + imageCount = count + + // Now decode all of the images + var images: [ImageMap.Image] = [] + var lastAddress: UInt64 = 0 + + images.reserveCapacity(count) + + for _ in 0..> 3) & 0x7) + 1) + let ecount = Int((header & 0x7) + 1) + + #if DEBUG_COMPACT_IMAGE_MAP + print("r = \(relative), acount = \(acount), ecount = \(ecount)") + #endif + + // Now the base and end of text addresses + guard let address = decodeAddress(acount) else { + return nil + } + let baseAddress: UInt64 + if relative { + baseAddress = lastAddress &+ address + } else { + baseAddress = address + } + + lastAddress = baseAddress + + guard let eotOffset = decodeAddress(ecount) else { + return nil + } + let endOfText = baseAddress &+ eotOffset + + #if DEBUG_COMPACT_IMAGE_MAP + print("address = \(hex(address)), eotOffset = \(hex(eotOffset))") + print("baseAddress = \(hex(baseAddress)), endOfText = \(hex(endOfText))") + #endif + + // Next, get the build ID byte count + guard let buildIdBytes = decodeCount() else { + return nil + } + + #if DEBUG_COMPACT_IMAGE_MAP + print("buildIdBytes = \(buildIdBytes)") + #endif + + // Read the build ID + var buildId: [UInt8]? = nil + + if buildIdBytes > 0 { + buildId = [] + buildId!.reserveCapacity(buildIdBytes) + + for _ in 0.. + @_spi(Internal) + public struct Encoder: Sequence { + public typealias Element = UInt8 + + private var source: ImageMap + + public init(_ source: ImageMap) { + self.source = source + } + + public func makeIterator() -> Iterator { + return Iterator(source) + } + + public struct Iterator: IteratorProtocol { + enum State { + case start + case platform(Int) + case count(Int) + case image + case baseAddress(Int) + case endOfText(Int) + case uniqueID(Int) + case uniqueIDBytes(Int) + case path + case pathCode(Int) + case pathString + case pathStringChunk(Int) + case version + case framework + case done + } + + var abytes = EightByteBuffer() + var ebytes = EightByteBuffer() + var acount: Int = 0 + var ecount: Int = 0 + var version: UInt8 = 0 + var lastAddress: UInt64 = 0 + var ndx: Int = 0 + var state: State = .start + var source: ImageMap + var pathPrefixes = fixedPathPrefixes + var nextCode = 32 + var remainingPath: String.UTF8View.SubSequence? + + func signExtend(_ value: UInt64) -> UInt64 { + let mask: UInt64 + let topBit: UInt64 + switch source.wordSize { + case .sixteenBit: + topBit = 0x8000 + mask = 0xffffffffffff0000 + case .thirtyTwoBit: + topBit = 0x80000000 + mask = 0xffffffff00000000 + case .sixtyFourBit: + return value + } + + if (value & topBit) != 0 { + return value | mask + } + return value + } + + init(_ source: ImageMap) { + self.source = source + } + + public mutating func next() -> UInt8? { + switch state { + case .done: + return nil + + case .start: + // The first thing we emit is the info byte + let size: WordSize + switch source.wordSize { + case .sixteenBit: + size = .sixteenBit + case .thirtyTwoBit: + size = .thirtyTwoBit + case .sixtyFourBit: + size = .sixtyFourBit + } + + state = .platform(-1) + + let version: UInt8 = 0 + let infoByte = (version << 2) | size.rawValue + return infoByte + + case let .platform(ndx): + let length = UInt8(source.platform.utf8.count) + let byte: UInt8 + + if ndx == -1 { + // The length byte comes first + byte = length + } else { + byte = source.platform.utf8[ + source.platform.utf8.index( + source.platform.utf8.startIndex, + offsetBy: ndx + ) + ] + } + + // If we're done, move to the .count state + if ndx + 1 == length { + let count = source.images.count + let bits = Int.bitWidth - count.leadingZeroBitCount + state = .count(7 * (bits / 7)) + } else { + state = .platform(ndx + 1) + } + + return byte + + case let .count(ndx): + let count = source.images.count + let byte = UInt8(truncatingIfNeeded:(count >> ndx) & 0x7f) + if ndx == 0 { + state = .image + return byte + } else { + state = .count(ndx - 7) + return 0x80 | byte + } + + case .image: + if ndx == source.images.count { + state = .done + return nil + } + + let baseAddress = signExtend(source.images[ndx].baseAddress) + let delta = baseAddress &- lastAddress + + let endOfText = signExtend(source.images[ndx].endOfText) + let endOfTextOffset = endOfText - baseAddress + + let eotCount: Int + if endOfTextOffset & (1 << 63) != 0 { + let ones = ((~endOfTextOffset).leadingZeroBitCount - 1) >> 3 + eotCount = 8 - ones + } else { + let zeroes = (endOfTextOffset.leadingZeroBitCount - 1) >> 3 + eotCount = 8 - zeroes + } + + ebytes = EightByteBuffer(endOfTextOffset) + ecount = eotCount + + let absCount: Int + if baseAddress & (1 << 63) != 0 { + let ones = ((~baseAddress).leadingZeroBitCount - 1) >> 3 + absCount = 8 - ones + } else { + let zeroes = (baseAddress.leadingZeroBitCount - 1) >> 3 + absCount = 8 - zeroes + } + + let deltaCount: Int + if delta & (1 << 63) != 0 { + let ones = ((~delta).leadingZeroBitCount - 1) >> 3 + deltaCount = 8 - ones + } else { + let zeroes = (delta.leadingZeroBitCount - 1) >> 3 + deltaCount = 8 - zeroes + } + + lastAddress = baseAddress + + let relativeFlag: UInt8 + if absCount <= deltaCount { + abytes = EightByteBuffer(baseAddress) + acount = absCount + relativeFlag = 0 + } else { + abytes = EightByteBuffer(delta) + acount = deltaCount + relativeFlag = 0x80 + } + + state = .baseAddress(8 - acount) + return relativeFlag + | UInt8(truncatingIfNeeded: (acount - 1) << 3) + | UInt8(truncatingIfNeeded: ecount - 1) + + case let .baseAddress(ndx): + let byte = abytes[ndx] + if ndx + 1 == 8 { + state = .endOfText(8 - ecount) + } else { + state = .baseAddress(ndx + 1) + } + return byte + + case let .endOfText(ndx): + let byte = ebytes[ndx] + if ndx + 1 == 8 { + let count = source.images[self.ndx].uniqueID?.count ?? 0 + let bits = Int.bitWidth - count.leadingZeroBitCount + state = .uniqueID(7 * (bits / 7)) + } else { + state = .endOfText(ndx + 1) + } + return byte + + case let .uniqueID(cndx): + guard let count = source.images[self.ndx].uniqueID?.count else { + state = .path + if let path = source.images[self.ndx].path { + remainingPath = path.utf8[...] + } else { + remainingPath = nil + } + return 0 + } + let byte = UInt8(truncatingIfNeeded: (count >> cndx) & 0x7f) + if cndx == 0 { + state = .uniqueIDBytes(0) + return byte + } else { + state = .uniqueID(cndx - 7) + return 0x80 | byte + } + + case let .uniqueIDBytes(byteNdx): + let uniqueID = source.images[self.ndx].uniqueID! + let byte = uniqueID[byteNdx] + if byteNdx + 1 == uniqueID.count { + state = .path + if let path = source.images[self.ndx].path { + remainingPath = path.utf8[...] + } else { + remainingPath = nil + } + } else { + state = .uniqueIDBytes(byteNdx + 1) + } + return byte + + case .path: + guard let remainingPath = remainingPath, + remainingPath.count > 0 else { + ndx += 1 + state = .image + return 0x00 + } + + // Find the longest prefix match + var longestMatchLen = 0 + var matchedPrefix: Int? = nil + for (ndx, (_, prefix)) in pathPrefixes.enumerated() { + let prefixUTF8 = prefix.utf8 + if prefixUTF8.count > remainingPath.count { + continue + } + if prefixUTF8.count > longestMatchLen + && remainingPath.starts(with: prefixUTF8) { + longestMatchLen = prefixUTF8.count + matchedPrefix = ndx + } + } + + if let ndx = matchedPrefix { + let (code, prefix) = pathPrefixes[ndx] + self.remainingPath = remainingPath.dropFirst(prefix.utf8.count) + if code <= 0x3f { + return 0x80 | UInt8(exactly: code)! + } + + let theCode = UInt64(exactly: code - 0x40)! + abytes = EightByteBuffer(theCode) + + let codeBytes = Swift.max( + (64 - theCode.leadingZeroBitCount) >> 3, 1 + ) + + state = .pathCode(8 - codeBytes) + + return 0xc0 | UInt8(exactly: codeBytes - 1)! + } + + // Check for /.framework/Versions// + if let name = source.images[ndx].name, !name.isEmpty { + let nameCount = name.utf8.count + let expectedLen = 1 // '/' + + nameCount // + + 20 // .framework/Versions/ + + 1 // + + 1 // '/' + + nameCount // + if remainingPath.count == expectedLen { + let framework = "/\(name).framework/Versions/" + if remainingPath.starts(with: framework.utf8) { + var verNdx = remainingPath.startIndex + remainingPath.formIndex(&verNdx, offsetBy: framework.utf8.count) + + version = remainingPath[verNdx] + + let slashNdx = remainingPath.index(after: verNdx) + if remainingPath[slashNdx] == slash { + let nameNdx = remainingPath.index(after: slashNdx) + if remainingPath[nameNdx...].elementsEqual(name.utf8) { + self.remainingPath = remainingPath[nameNdx...] + + state = .version + return 0x40 | UInt8(exactly: nameCount - 1)! + } + } + } + } + } + + // Add any new prefixes + forEachPrefix(of: remainingPath) { prefix in + #if DEBUG_COMPACT_IMAGE_MAP + print("defining \(nextCode) as \"\(prefix)\"") + #endif + pathPrefixes.append((nextCode, prefix)) + nextCode += 1 + } + + fallthrough + + case .pathString: + if remainingPath!.count == 0 { + ndx += 1 + state = .image + return 0x00 + } + + let chunkLength = Swift.min(remainingPath!.count, 0x3f) + state = .pathStringChunk(chunkLength) + return UInt8(truncatingIfNeeded: chunkLength) + + case let .pathStringChunk(length): + let byte = remainingPath!.first! + remainingPath = remainingPath!.dropFirst() + if length == 1 { + state = .pathString + } else { + state = .pathStringChunk(length - 1) + } + return byte + + case .version: + state = .framework + return version + + case .framework: + let byte = remainingPath!.first! + remainingPath = remainingPath!.dropFirst() + if remainingPath!.count == 0 { + ndx += 1 + state = .image + } + return byte + + case let .pathCode(ndx): + let byte = abytes[ndx] + if ndx + 1 == 8 { + state = .path + } else { + state = .pathCode(ndx + 1) + } + return byte + } + } + } + } + +} diff --git a/stdlib/public/Backtracing/Compression.swift b/stdlib/public/RuntimeModule/Compression.swift similarity index 57% rename from stdlib/public/Backtracing/Compression.swift rename to stdlib/public/RuntimeModule/Compression.swift index 0b0f0c0e7e209..575e7b7a58ffd 100644 --- a/stdlib/public/Backtracing/Compression.swift +++ b/stdlib/public/RuntimeModule/Compression.swift @@ -25,8 +25,6 @@ // //===----------------------------------------------------------------------===// -#if os(Linux) - import Swift #if os(macOS) || os(iOS) || os(tvOS) || os(watchOS) @@ -56,18 +54,26 @@ let lzma_stream_init = swift.runtime.lzma_stream_init // .. CompressedStream ......................................................... protocol CompressedStream { - typealias InputSource = () throws -> UnsafeBufferPointer + typealias InputSource = () throws -> UnsafeRawBufferPointer typealias OutputSink = (_ used: UInt, _ done: Bool) throws - -> UnsafeMutableBufferPointer? + -> UnsafeMutableRawBufferPointer? func decompress(input: InputSource, output: OutputSink) throws -> UInt } // .. Compression library bindings ............................................. +#if os(macOS) || os(iOS) || os(tvOS) || os(watchOS) +private var lzmaHandle = dlopen("liblzma.dylib", RTLD_LAZY) +private var zlibHandle = dlopen("libz.dylib", RTLD_LAZY) +private var zstdHandle = dlopen("libzstd.dylib", RTLD_LAZY) +#elseif os(Linux) private var lzmaHandle = dlopen("liblzma.so.5", RTLD_LAZY) private var zlibHandle = dlopen("libz.so.1", RTLD_LAZY) private var zstdHandle = dlopen("libzstd.so.1", RTLD_LAZY) +#elseif os(Windows) +// ###TODO +#endif private func symbol(_ handle: UnsafeMutableRawPointer?, _ name: String) -> T? { guard let handle = handle, let result = dlsym(handle, name) else { @@ -152,7 +158,9 @@ struct ZLibStream: CompressedStream { let buffer = try input() // Not really mutable; this is just an issue with z_const - stream.next_in = UnsafeMutablePointer(mutating: buffer.baseAddress) + stream.next_in = UnsafeMutablePointer( + mutating: buffer.baseAddress?.assumingMemoryBound(to: UInt8.self) + ) stream.avail_in = CUnsignedInt(buffer.count) } @@ -161,7 +169,7 @@ struct ZLibStream: CompressedStream { throw CompressedImageSourceError.outputOverrun } - stream.next_out = buffer.baseAddress + stream.next_out = buffer.baseAddress?.assumingMemoryBound(to: UInt8.self) stream.avail_out = CUnsignedInt(buffer.count) outputBufferSize = UInt(buffer.count) } @@ -211,7 +219,7 @@ struct ZStdStream: CompressedStream { if inBuffer.size == inBuffer.pos { let buffer = try input() - inBuffer.src = UnsafeRawPointer(buffer.baseAddress) + inBuffer.src = buffer.baseAddress inBuffer.size = buffer.count inBuffer.pos = 0 } @@ -225,7 +233,7 @@ struct ZStdStream: CompressedStream { throw CompressedImageSourceError.outputOverrun } - outBuffer.dst = UnsafeMutableRawPointer(buffer.baseAddress) + outBuffer.dst = buffer.baseAddress outBuffer.size = buffer.count outBuffer.pos = 0 } @@ -280,7 +288,7 @@ struct LZMAStream: CompressedStream { while true { if stream.avail_in == 0 { let buffer = try input() - stream.next_in = buffer.baseAddress + stream.next_in = buffer.baseAddress?.assumingMemoryBound(to: UInt8.self) stream.avail_in = buffer.count } @@ -289,7 +297,7 @@ struct LZMAStream: CompressedStream { throw CompressedImageSourceError.outputOverrun } - stream.next_out = buffer.baseAddress + stream.next_out = buffer.baseAddress?.assumingMemoryBound(to: UInt8.self) stream.avail_out = buffer.count outputBufferSize = UInt(buffer.count) } @@ -310,230 +318,130 @@ struct LZMAStream: CompressedStream { // .. Image Sources ............................................................ -fileprivate func decompress( - stream: S, source: I, dataBounds: I.Bounds, uncompressedSize: UInt? = nil) - throws -> [UInt8] { - - var pos = dataBounds.base - var remaining = dataBounds.size - - let bufSize = 65536 - - if let uncompressedSize = uncompressedSize { - // If we know the uncompressed size, we can decompress directly into the - // array. - - let inputBuffer - = UnsafeMutableBufferPointer.allocate(capacity: bufSize) - defer { - inputBuffer.deallocate() - } - - return try [UInt8].init(unsafeUninitializedCapacity: Int(uncompressedSize)) { - (outputBuffer: inout UnsafeMutableBufferPointer, - count: inout Int) in - - count = Int(try stream.decompress( - input: { () throws -> UnsafeBufferPointer in - - let chunkSize = min(Int(remaining), inputBuffer.count) - let slice = inputBuffer[0.. UnsafeMutableBufferPointer? in - - if used == 0 { - return outputBuffer - } else { - return nil - } - } - )) - } - } else { - // Otherwise, we decompress in chunks and append them to the array. - - let buffer - = UnsafeMutableBufferPointer.allocate(capacity: 2 * bufSize) - defer { - buffer.deallocate() +fileprivate func decompress( + stream: S, + source: ImageSource, + offset: Int, + output: inout ImageSource +) throws { + let totalBytes = try stream.decompress( + input: { + () throws -> UnsafeRawBufferPointer in + + return UnsafeRawBufferPointer(rebasing: source.bytes[offset...]) + }, + output: { + (used: UInt, done: Bool) throws -> UnsafeMutableRawBufferPointer? in + + if used == 0 { + return output.unusedBytes + } else { + return nil + } } + ) + output.used(bytes: Int(totalBytes)) +} - let inputBuffer = UnsafeMutableBufferPointer(rebasing: buffer[0.. UnsafeBufferPointer in - - let chunkSize = min(Int(remaining), inputBuffer.count) - let slice = inputBuffer[0.. UnsafeMutableBufferPointer? in +fileprivate func decompressChunked( + stream: S, + source: ImageSource, + offset: Int, + output: inout ImageSource +) throws { + let bufSize = 65536 + let outputBuffer = UnsafeMutableRawBufferPointer.allocate(byteCount: bufSize, + alignment: 16) + defer { + outputBuffer.deallocate() + } - data.append(contentsOf: outputBuffer[.. UnsafeRawBufferPointer in + + return UnsafeRawBufferPointer(rebasing: source.bytes[offset...]) + }, + output: { + (used: UInt, done: Bool) throws -> UnsafeMutableRawBufferPointer? in + + output.append( + bytes: UnsafeRawBufferPointer(rebasing: outputBuffer[..: ImageSource { - - private var data: [UInt8] - - var isMappedImage: Bool { return false } - var path: String? { return nil } - var bounds: Bounds? { return Bounds(base: Address(0), size: Size(data.count)) } - - init(source: some ImageSource) throws { - guard let bounds = source.bounds else { - throw CompressedImageSourceError.unboundedImageSource +extension ImageSource { + @_specialize(kind: full, where Traits == Elf32Traits) + @_specialize(kind: full, where Traits == Elf64Traits) + init(elfCompressedImageSource source: ImageSource, + traits: Traits.Type) throws { + if source.bytes.count < MemoryLayout.size { + throw CompressedImageSourceError.badCompressedData } - if bounds.size < MemoryLayout.size { - throw CompressedImageSourceError.badCompressedData + let rawChdr = try source.fetch(from: 0, as: Traits.Chdr.self) + let chdr: Traits.Chdr + switch rawChdr.ch_type { + case .ELFCOMPRESS_ZLIB.byteSwapped, .ELFCOMPRESS_ZSTD.byteSwapped: + chdr = rawChdr.byteSwapped + default: + chdr = rawChdr } - let chdr = try source.fetch(from: bounds.base, - as: Traits.Chdr.self) - let dataBounds = bounds.adjusted(by: MemoryLayout.stride) let uncompressedSize = UInt(chdr.ch_size) + self.init(capacity: Int(uncompressedSize), isMappedImage: false, path: nil) + switch chdr.ch_type { case .ELFCOMPRESS_ZLIB: - data = try decompress(stream: ZLibStream(), - source: source, dataBounds: dataBounds, - uncompressedSize: uncompressedSize) + try decompress(stream: ZLibStream(), + source: source, offset: MemoryLayout.stride, + output: &self) case .ELFCOMPRESS_ZSTD: - data = try decompress(stream: ZStdStream(), - source: source, dataBounds: dataBounds, - uncompressedSize: uncompressedSize) + try decompress(stream: ZStdStream(), + source: source, offset: MemoryLayout.stride, + output: &self) default: throw CompressedImageSourceError.unsupportedFormat } } - public func fetch(from addr: Address, - into buffer: UnsafeMutableRawBufferPointer) throws { - let toFetch = buffer.count - if addr < 0 || addr > data.count || data.count - Int(addr) < toFetch { - throw CompressedImageSourceError.outOfRangeFetch(addr, toFetch) - } - - buffer.withMemoryRebound(to: UInt8.self) { outBuf in - for n in 0.. data.count || data.count - Int(addr) < toFetch { - throw CompressedImageSourceError.outOfRangeFetch(addr, toFetch) - } - - buffer.withMemoryRebound(to: UInt8.self) { outBuf in - for n in 0.. data.count || data.count - Int(addr) < toFetch { - throw CompressedImageSourceError.outOfRangeFetch(addr, toFetch) - } + init(lzmaCompressedImageSource source: ImageSource) throws { + self.init(isMappedImage: false, path: nil) - buffer.withMemoryRebound(to: UInt8.self) { outBuf in - for n in 0..(_ handle: UnsafeMutableRawPointer, _ name: String) -> T { return unsafeBitCast(result, to: T.self) } +// Define UniChar +typealias UniChar = UInt16 + private enum Sym { // CRCopySanitizedPath static let CRCopySanitizedPath: @convention(c) (CFString, CFIndex) -> CFString = @@ -130,6 +133,9 @@ private enum Sym { UnsafeMutableRawPointer?, CFIndex, UnsafeMutablePointer?) -> CFIndex = symbol(coreFoundationHandle, "CFStringGetBytes") + static let CFStringGetCharactersPtr: + @convention(c) (CFString) -> UnsafePointer? = + symbol(coreFoundationHandle, "CFStringGetCharactersPtr") } // .. Core Foundation miscellany ............................................... @@ -161,6 +167,11 @@ internal func CFStringGetCStringPtr(_ s: CFString, return Sym.CFStringGetCStringPtr(s, encoding) } +internal func CFStringGetCharactersPtr(_ s: CFString) + -> UnsafePointer? { + return Sym.CFStringGetCharactersPtr(s); +} + internal func CFStringGetBytes(_ s: CFString, _ range: CFRange, _ encoding: CFStringEncoding, @@ -199,8 +210,15 @@ private func fromCFString(_ cf: CFString) -> String { if let ptr = CFStringGetCStringPtr(cf, CFStringBuiltInEncodings.ASCII.rawValue) { - return String(decoding: UnsafeRawBufferPointer(start: ptr, count: length), - as: UTF8.self) + let buffer = UnsafeRawBufferPointer(start: ptr, count: length) + return String(decoding: buffer, as: UTF8.self) + } else if let ptr = CFStringGetCharactersPtr(cf) { + let buffer = UnsafeBufferPointer(start: ptr, count: length) + return String(decoding: buffer, as: UTF16.self) + } else if let ptr = CFStringGetCStringPtr(cf, + CFStringBuiltInEncodings.UTF8.rawValue) { + let buffer = UnsafeRawBufferPointer(start: ptr, count: length) + return String(decoding: buffer, as: UTF8.self) } else { var byteLen = CFIndex(0) diff --git a/stdlib/public/Backtracing/Dwarf.swift b/stdlib/public/RuntimeModule/Dwarf.swift similarity index 86% rename from stdlib/public/Backtracing/Dwarf.swift rename to stdlib/public/RuntimeModule/Dwarf.swift index 15a5e0f30a2d2..85d8082f4496b 100644 --- a/stdlib/public/Backtracing/Dwarf.swift +++ b/stdlib/public/RuntimeModule/Dwarf.swift @@ -15,8 +15,6 @@ // //===----------------------------------------------------------------------===// -#if os(Linux) - import Swift internal import BacktracingImpl.ImageFormats.Dwarf @@ -500,7 +498,7 @@ enum DwarfSection { protocol DwarfSource { - func getDwarfSection(_ section: DwarfSection) -> (any ImageSource)? + func getDwarfSection(_ section: DwarfSection) -> ImageSource? } @@ -523,14 +521,14 @@ struct DwarfReader { var attributes: [(Dwarf_Attribute, Dwarf_Form, Int64?)] } - var infoSection: any ImageSource - var abbrevSection: any ImageSource - var lineSection: (any ImageSource)? - var addrSection: (any ImageSource)? - var strSection: (any ImageSource)? - var lineStrSection: (any ImageSource)? - var strOffsetsSection: (any ImageSource)? - var rangesSection: (any ImageSource)? + var infoSection: ImageSource + var abbrevSection: ImageSource + var lineSection: ImageSource? + var addrSection: ImageSource? + var strSection: ImageSource? + var lineStrSection: ImageSource? + var strOffsetsSection: ImageSource? + var rangesSection: ImageSource? var shouldSwap: Bool typealias DwarfAbbrev = UInt64 @@ -557,263 +555,9 @@ struct DwarfReader { var attributes: [Dwarf_Attribute:DwarfValue] = [:] } - struct FileInfo { - var path: String - var directoryIndex: Int? - var timestamp: Int? - var size: UInt64? - var md5sum: [UInt8]? - } - - struct LineNumberState: CustomStringConvertible { - var address: Address - var opIndex: UInt - var file: Int - var path: String - var line: Int - var column: Int - var isStmt: Bool - var basicBlock: Bool - var endSequence: Bool - var prologueEnd: Bool - var epilogueBegin: Bool - var isa: UInt - var discriminator: UInt - - var description: String { - var flags: [String] = [] - if isStmt { - flags.append("is_stmt") - } - if basicBlock { - flags.append("basic_block") - } - if endSequence { - flags.append("end_sequence") - } - if prologueEnd { - flags.append("prologue_end") - } - if epilogueBegin { - flags.append("epilogue_begin") - } - - let flagsString = flags.joined(separator:" ") - - return """ - \(hex(address)) \(pad(line, 6)) \(pad(column, 6)) \(pad(file, 6)) \ - \(pad(isa, 3)) \(pad(discriminator, 13)) \(flagsString) - """ - } - } - - struct LineNumberInfo { - var baseOffset: Address - var version: Int - var addressSize: Int? - var selectorSize: Int? - var headerLength: UInt64 - var minimumInstructionLength: UInt - var maximumOpsPerInstruction: UInt - var defaultIsStmt: Bool - var lineBase: Int8 - var lineRange: UInt8 - var opcodeBase: UInt8 - var standardOpcodeLengths: [UInt64] - var directories: [String] = [] - var files: [FileInfo] = [] - var program: [UInt8] = [] - var shouldSwap: Bool - - /// Compute the full path for a file, given its index in the file table. - func fullPathForFile(index: Int) -> String { - if index >= files.count { - return "" - } - - let info = files[index] - if info.path.hasPrefix("/") { - return info.path - } - - let dirName: String - if let dirIndex = info.directoryIndex, - dirIndex < directories.count { - dirName = directories[dirIndex] - } else { - dirName = "" - } - - return "\(dirName)/\(info.path)" - } - - /// Execute the line number program, calling a closure for every line - /// table entry. - mutating func executeProgram( - line: (LineNumberState, inout Bool) -> () - ) throws { - let source = ArrayImageSource(array: program) - let bounds = source.bounds! - var cursor = ImageSourceCursor(source: source) - - func maybeSwap(_ x: T) -> T { - if shouldSwap { - return x.byteSwapped - } - return x - } - - // Table 6.4: Line number program initial state - let initialState = LineNumberState( - address: 0, - opIndex: 0, - file: 1, - path: fullPathForFile(index: 1), - line: 1, - column: 0, - isStmt: defaultIsStmt, - basicBlock: false, - endSequence: false, - prologueEnd: false, - epilogueBegin: false, - isa: 0, - discriminator: 0 - ) - - var state = initialState - - // Flag to allow fast exit - var done = false - - while !done && cursor.pos < bounds.end { - let opcode = try cursor.read(as: Dwarf_LNS_Opcode.self) - - if opcode.rawValue >= opcodeBase { - // Special opcode - let adjustedOpcode = UInt(opcode.rawValue - opcodeBase) - let advance = adjustedOpcode / UInt(lineRange) - let lineAdvance = adjustedOpcode % UInt(lineRange) - let instrAdvance - = (state.opIndex + advance) / maximumOpsPerInstruction - let newOp = (state.opIndex + advance) % maximumOpsPerInstruction - state.address += Address(instrAdvance) - state.opIndex = newOp - state.line += Int(lineBase) + Int(lineAdvance) - - line(state, &done) - - state.discriminator = 0 - state.basicBlock = false - state.prologueEnd = false - state.epilogueBegin = false - } else if opcode == .DW_LNS_extended { - // Extended opcode - let length = try cursor.readULEB128() - let opcode = try cursor.read(as: Dwarf_LNE_Opcode.self) - - switch opcode { - case .DW_LNE_end_sequence: - state.endSequence = true - line(state, &done) - state = initialState - case .DW_LNE_set_address: - let address: UInt64 - guard let addressSize = addressSize else { - throw DwarfError.unspecifiedAddressSize - } - switch addressSize { - case 4: - address = UInt64(maybeSwap(try cursor.read(as: UInt32.self))) - case 8: - address = maybeSwap(try cursor.read(as: UInt64.self)) - default: - throw DwarfError.badAddressSize(addressSize) - } - state.address = Address(address) - case .DW_LNE_define_file: - guard let path = try cursor.readString() else { - throw DwarfError.badString - } - let directoryIndex = try cursor.readULEB128() - let timestamp = try cursor.readULEB128() - let size = try cursor.readULEB128() - files.append(FileInfo( - path: path, - directoryIndex: Int(directoryIndex), - timestamp: timestamp != 0 ? Int(timestamp) : nil, - size: size != 0 ? size : nil, - md5sum: nil - )) - case .DW_LNE_set_discriminator: - let discriminator = try cursor.readULEB128() - state.discriminator = UInt(discriminator) - default: - cursor.pos += length - 1 - } - } else { - // Standard opcode - switch opcode { - case .DW_LNS_copy: - line(state, &done) - state.discriminator = 0 - state.basicBlock = false - state.prologueEnd = false - state.epilogueBegin = false - case .DW_LNS_advance_pc: - let advance = UInt(try cursor.readULEB128()) - let instrAdvance - = (state.opIndex + advance) / maximumOpsPerInstruction - let newOp = (state.opIndex + advance) % maximumOpsPerInstruction - state.address += Address(instrAdvance) - state.opIndex = newOp - case .DW_LNS_advance_line: - let advance = try cursor.readSLEB128() - state.line += Int(advance) - case .DW_LNS_set_file: - let file = Int(try cursor.readULEB128()) - state.file = file - state.path = fullPathForFile(index: state.file) - case .DW_LNS_set_column: - let column = Int(try cursor.readULEB128()) - state.column = column - case .DW_LNS_negate_stmt: - state.isStmt = !state.isStmt - case .DW_LNS_set_basic_block: - state.basicBlock = true - case .DW_LNS_const_add_pc: - let adjustedOpcode = UInt(255 - opcodeBase) - let advance = adjustedOpcode / UInt(lineRange) - let instrAdvance - = (state.opIndex + advance) / maximumOpsPerInstruction - let newOp = (state.opIndex + advance) % maximumOpsPerInstruction - state.address += Address(instrAdvance) - state.opIndex = newOp - case .DW_LNS_fixed_advance_pc: - let advance = try cursor.read(as: Dwarf_Half.self) - state.address += Address(advance) - state.opIndex = 0 - case .DW_LNS_set_prologue_end: - state.prologueEnd = true - case .DW_LNS_set_epilogue_begin: - state.epilogueBegin = true - case .DW_LNS_set_isa: - let isa = UInt(try cursor.readULEB128()) - state.isa = isa - default: - // Skip this unknown opcode - let length = standardOpcodeLengths[Int(opcode.rawValue)] - for _ in 0.. { var rangeListInfo: RangeListInfo? + @_specialize(kind: full, where S == Elf32Image) + @_specialize(kind: full, where S == Elf64Image) init(source: Source, shouldSwap: Bool = false) throws { // ###TODO: This should be optional, because we can have just line number // information. We should test that, too. @@ -873,7 +619,7 @@ struct DwarfReader { } lineNumberInfo[n].directories[0] = dirname - lineNumberInfo[n].files[0] = FileInfo( + lineNumberInfo[n].files[0] = DwarfFileInfo( path: filename, directoryIndex: 0, timestamp: nil, @@ -896,14 +642,11 @@ struct DwarfReader { } private func readUnits() throws -> [Unit] { - guard let bounds = infoSection.bounds else { - return [] - } - + let end = infoSection.bytes.count var units: [Unit] = [] var cursor = ImageSourceCursor(source: infoSection) - while cursor.pos < bounds.end { + while cursor.pos < end { // See 7.5.1.1 Full and Partial Compilation Unit Headers let base = cursor.pos @@ -1053,16 +796,16 @@ struct DwarfReader { return units } - private func readLineNumberInfo() throws -> [LineNumberInfo] { - guard let lineSection = lineSection, - let bounds = lineSection.bounds else { + private func readLineNumberInfo() throws -> [DwarfLineNumberInfo] { + guard let lineSection = lineSection else { return [] } - var result: [LineNumberInfo] = [] + let end = lineSection.bytes.count + var result: [DwarfLineNumberInfo] = [] var cursor = ImageSourceCursor(source: lineSection, offset: 0) - while cursor.pos < bounds.end { + while cursor.pos < end { // 6.2.4 The Line Number Program Header // .1 unit_length @@ -1127,7 +870,7 @@ struct DwarfReader { } var dirNames: [String] = [] - var fileInfo: [FileInfo] = [] + var fileInfo: [DwarfFileInfo] = [] if version == 3 || version == 4 { // .11 include_directories @@ -1152,7 +895,7 @@ struct DwarfReader { // Prior to version 5, the compilation unit's filename is not included; // put a placeholder here for now, which we'll fix up later. - fileInfo.append(FileInfo( + fileInfo.append(DwarfFileInfo( path: "", directoryIndex: 0, timestamp: nil, @@ -1172,7 +915,7 @@ struct DwarfReader { let timestamp = try cursor.readULEB128() let size = try cursor.readULEB128() - fileInfo.append(FileInfo( + fileInfo.append(DwarfFileInfo( path: path, directoryIndex: Int(dirIndex), timestamp: timestamp != 0 ? Int(timestamp) : nil, @@ -1275,7 +1018,7 @@ struct DwarfReader { md5sum = nil } - fileInfo.append(FileInfo( + fileInfo.append(DwarfFileInfo( path: path, directoryIndex: dirIndex, timestamp: timestamp, @@ -1285,12 +1028,10 @@ struct DwarfReader { } // The actual program comes next - let program = try cursor.read(count: Int(nextOffset - cursor.pos), - as: UInt8.self) - + let program = cursor.source[cursor.pos.. { if tag != .DW_TAG_subprogram { return } - + refAttrs = try readDieAttributes( at: &cursor, unit: unit, @@ -2005,11 +1746,268 @@ struct DwarfReader { } +struct DwarfFileInfo { + var path: String + var directoryIndex: Int? + var timestamp: Int? + var size: UInt64? + var md5sum: [UInt8]? +} + +struct DwarfLineNumberState: CustomStringConvertible { + typealias Address = UInt64 + + var address: Address + var opIndex: UInt + var file: Int + var path: String + var line: Int + var column: Int + var isStmt: Bool + var basicBlock: Bool + var endSequence: Bool + var prologueEnd: Bool + var epilogueBegin: Bool + var isa: UInt + var discriminator: UInt + + var description: String { + var flags: [String] = [] + if isStmt { + flags.append("is_stmt") + } + if basicBlock { + flags.append("basic_block") + } + if endSequence { + flags.append("end_sequence") + } + if prologueEnd { + flags.append("prologue_end") + } + if epilogueBegin { + flags.append("epilogue_begin") + } + + let flagsString = flags.joined(separator:" ") + + return """ + \(hex(address)) \(pad(line, 6)) \(pad(column, 6)) \(pad(file, 6)) \ + \(pad(isa, 3)) \(pad(discriminator, 13)) \(flagsString) + """ + } +} + +struct DwarfLineNumberInfo { + typealias Address = UInt64 + + var baseOffset: Address + var version: Int + var addressSize: Int? + var selectorSize: Int? + var headerLength: UInt64 + var minimumInstructionLength: UInt + var maximumOpsPerInstruction: UInt + var defaultIsStmt: Bool + var lineBase: Int8 + var lineRange: UInt8 + var opcodeBase: UInt8 + var standardOpcodeLengths: [UInt64] + var directories: [String] = [] + var files: [DwarfFileInfo] = [] + var program: ImageSource + var shouldSwap: Bool + + /// Compute the full path for a file, given its index in the file table. + func fullPathForFile(index: Int) -> String { + if index >= files.count { + return "" + } + + let info = files[index] + if info.path.hasPrefix("/") { + return info.path + } + + let dirName: String + if let dirIndex = info.directoryIndex, + dirIndex < directories.count { + dirName = directories[dirIndex] + } else { + dirName = "" + } + + return "\(dirName)/\(info.path)" + } + + /// Execute the line number program, calling a closure for every line + /// table entry. + mutating func executeProgram( + line: (DwarfLineNumberState, inout Bool) -> () + ) throws { + let end = program.bytes.count + var cursor = ImageSourceCursor(source: program) + + func maybeSwap(_ x: T) -> T { + if shouldSwap { + return x.byteSwapped + } + return x + } + + // Table 6.4: Line number program initial state + let initialState = DwarfLineNumberState( + address: 0, + opIndex: 0, + file: 1, + path: fullPathForFile(index: 1), + line: 1, + column: 0, + isStmt: defaultIsStmt, + basicBlock: false, + endSequence: false, + prologueEnd: false, + epilogueBegin: false, + isa: 0, + discriminator: 0 + ) + + var state = initialState + + // Flag to allow fast exit + var done = false + + while !done && cursor.pos < end { + let opcode = try cursor.read(as: Dwarf_LNS_Opcode.self) + + if opcode.rawValue >= opcodeBase { + // Special opcode + let adjustedOpcode = UInt(opcode.rawValue - opcodeBase) + let advance = adjustedOpcode / UInt(lineRange) + let lineAdvance = adjustedOpcode % UInt(lineRange) + let instrAdvance + = (state.opIndex + advance) / maximumOpsPerInstruction + let newOp = (state.opIndex + advance) % maximumOpsPerInstruction + state.address += Address(instrAdvance) + state.opIndex = newOp + state.line += Int(lineBase) + Int(lineAdvance) + + line(state, &done) + + state.discriminator = 0 + state.basicBlock = false + state.prologueEnd = false + state.epilogueBegin = false + } else if opcode == .DW_LNS_extended { + // Extended opcode + let length = try cursor.readULEB128() + let opcode = try cursor.read(as: Dwarf_LNE_Opcode.self) + + switch opcode { + case .DW_LNE_end_sequence: + state.endSequence = true + line(state, &done) + state = initialState + case .DW_LNE_set_address: + let address: UInt64 + guard let addressSize = addressSize else { + throw DwarfError.unspecifiedAddressSize + } + switch addressSize { + case 4: + address = UInt64(maybeSwap(try cursor.read(as: UInt32.self))) + case 8: + address = maybeSwap(try cursor.read(as: UInt64.self)) + default: + throw DwarfError.badAddressSize(addressSize) + } + state.address = Address(address) + case .DW_LNE_define_file: + guard let path = try cursor.readString() else { + throw DwarfError.badString + } + let directoryIndex = try cursor.readULEB128() + let timestamp = try cursor.readULEB128() + let size = try cursor.readULEB128() + files.append(DwarfFileInfo( + path: path, + directoryIndex: Int(directoryIndex), + timestamp: timestamp != 0 ? Int(timestamp) : nil, + size: size != 0 ? size : nil, + md5sum: nil + )) + case .DW_LNE_set_discriminator: + let discriminator = try cursor.readULEB128() + state.discriminator = UInt(discriminator) + default: + cursor.pos += length - 1 + } + } else { + // Standard opcode + switch opcode { + case .DW_LNS_copy: + line(state, &done) + state.discriminator = 0 + state.basicBlock = false + state.prologueEnd = false + state.epilogueBegin = false + case .DW_LNS_advance_pc: + let advance = UInt(try cursor.readULEB128()) + let instrAdvance + = (state.opIndex + advance) / maximumOpsPerInstruction + let newOp = (state.opIndex + advance) % maximumOpsPerInstruction + state.address += Address(instrAdvance) + state.opIndex = newOp + case .DW_LNS_advance_line: + let advance = try cursor.readSLEB128() + state.line += Int(advance) + case .DW_LNS_set_file: + let file = Int(try cursor.readULEB128()) + state.file = file + state.path = fullPathForFile(index: state.file) + case .DW_LNS_set_column: + let column = Int(try cursor.readULEB128()) + state.column = column + case .DW_LNS_negate_stmt: + state.isStmt = !state.isStmt + case .DW_LNS_set_basic_block: + state.basicBlock = true + case .DW_LNS_const_add_pc: + let adjustedOpcode = UInt(255 - opcodeBase) + let advance = adjustedOpcode / UInt(lineRange) + let instrAdvance + = (state.opIndex + advance) / maximumOpsPerInstruction + let newOp = (state.opIndex + advance) % maximumOpsPerInstruction + state.address += Address(instrAdvance) + state.opIndex = newOp + case .DW_LNS_fixed_advance_pc: + let advance = try cursor.read(as: Dwarf_Half.self) + state.address += Address(advance) + state.opIndex = 0 + case .DW_LNS_set_prologue_end: + state.prologueEnd = true + case .DW_LNS_set_epilogue_begin: + state.epilogueBegin = true + case .DW_LNS_set_isa: + let isa = UInt(try cursor.readULEB128()) + state.isa = isa + default: + // Skip this unknown opcode + let length = standardOpcodeLengths[Int(opcode.rawValue)] + for _ in 0.. Bool { - guard let source = try? FileImageSource(path: path) else { + guard let source = try? ImageSource(path: path) else { print("\(path) was not accessible") return false } @@ -2017,7 +2015,7 @@ public func testDwarfReaderFor(path: String) -> Bool { if let elfImage = try? Elf32Image(source: source) { print("\(path) is a 32-bit ELF image") - var reader: DwarfReader> + var reader: DwarfReader do { reader = try DwarfReader(source: elfImage) } catch { @@ -2034,7 +2032,7 @@ public func testDwarfReaderFor(path: String) -> Bool { } else if let elfImage = try? Elf64Image(source: source) { print("\(path) is a 64-bit ELF image") - var reader: DwarfReader> + var reader: DwarfReader do { reader = try DwarfReader(source: elfImage) } catch { @@ -2060,5 +2058,3 @@ public func testDwarfReaderFor(path: String) -> Bool { return false } } - -#endif // os(Linux) diff --git a/stdlib/public/RuntimeModule/EightByteBuffer.swift b/stdlib/public/RuntimeModule/EightByteBuffer.swift new file mode 100644 index 0000000000000..e1cfcc8ba4292 --- /dev/null +++ b/stdlib/public/RuntimeModule/EightByteBuffer.swift @@ -0,0 +1,60 @@ +//===--- EightByteBuffer.swift --------------------------------*- swift -*-===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2024 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 +// +//===----------------------------------------------------------------------===// +// +// A statically allocated buffer for holding a small number of bytes. +// +//===----------------------------------------------------------------------===// + +import Swift + +struct EightByteBuffer { + var word: UInt64 + + init() { + word = 0 + } + + init(_ qword: UInt64) { + word = qword.bigEndian + } + + init(_ qword: Int64) { + self.init(UInt64(bitPattern: qword)) + } + + init(_ value: T) where T: SignedInteger { + self.init(Int64(value)) + } + + init(_ value: T) { + self.init(UInt64(value)) + } + + subscript(ndx: Int) -> UInt8 { + get { + if ndx < 0 || ndx >= 8 { + fatalError("Index out of range") + } + return withUnsafeBytes(of: word) { buffer in + return buffer[ndx] + } + } + set(newValue) { + if ndx < 0 || ndx >= 8 { + fatalError("Index out of range") + } + withUnsafeMutableBytes(of: &word) { buffer in + buffer[ndx] = newValue + } + } + } +} diff --git a/stdlib/public/Backtracing/Elf.swift b/stdlib/public/RuntimeModule/Elf.swift similarity index 71% rename from stdlib/public/Backtracing/Elf.swift rename to stdlib/public/RuntimeModule/Elf.swift index 3c37ad47c0d07..d2501b33d25a0 100644 --- a/stdlib/public/Backtracing/Elf.swift +++ b/stdlib/public/RuntimeModule/Elf.swift @@ -17,8 +17,6 @@ // ###FIXME: We shouldn't really use String for paths. -#if os(Linux) - import Swift #if os(macOS) || os(iOS) || os(tvOS) || os(watchOS) @@ -75,7 +73,6 @@ let EI_VERSION = swift.runtime.EI_VERSION let EI_OSABI = swift.runtime.EI_OSABI let EI_ABIVERSION = swift.runtime.EI_ABIVERSION let EI_PAD = swift.runtime.EI_PAD -let EI_NIDENT = BacktracingImpl.EI_NIDENT let ELFMAG0 = swift.runtime.ELFMAG0 let ELFMAG1 = swift.runtime.ELFMAG1 @@ -83,109 +80,105 @@ let ELFMAG2 = swift.runtime.ELFMAG2 let ELFMAG3 = swift.runtime.ELFMAG3 typealias Elf_Ehdr_Class = swift.runtime.Elf_Ehdr_Class -typealias Elf_Ehdr_Data = swift.runtime.Elf_Ehdr_Data +typealias Elf_Ehdr_Data = swift.runtime.Elf_Ehdr_Data typealias Elf_Ehdr_OsAbi = swift.runtime.Elf_Ehdr_OsAbi -let SHN_UNDEF = swift.runtime.SHN_UNDEF +let SHN_UNDEF = swift.runtime.SHN_UNDEF let SHN_LORESERVE = swift.runtime.SHN_LORESERVE -let SHN_LOPROC = swift.runtime.SHN_LOPROC -let SHN_HIPROC = swift.runtime.SHN_HIPROC -let SHN_LOOS = swift.runtime.SHN_LOOS -let SHN_HIOS = swift.runtime.SHN_HIOS -let SHN_ABS = swift.runtime.SHN_ABS -let SHN_COMMON = swift.runtime.SHN_COMMON -let SHN_XINDEX = swift.runtime.SHN_XINDEX +let SHN_LOPROC = swift.runtime.SHN_LOPROC +let SHN_HIPROC = swift.runtime.SHN_HIPROC +let SHN_LOOS = swift.runtime.SHN_LOOS +let SHN_HIOS = swift.runtime.SHN_HIOS +let SHN_ABS = swift.runtime.SHN_ABS +let SHN_COMMON = swift.runtime.SHN_COMMON +let SHN_XINDEX = swift.runtime.SHN_XINDEX let SHN_HIRESERVE = swift.runtime.SHN_HIRESERVE typealias Elf_Shdr_Type = swift.runtime.Elf_Shdr_Type -let SHF_WRITE = swift.runtime.SHF_WRITE -let SHF_ALLOC = swift.runtime.SHF_ALLOC -let SHF_EXECINSTR = swift.runtime.SHF_EXECINSTR -let SHF_MERGE = swift.runtime.SHF_MERGE -let SHF_STRINGS = swift.runtime.SHF_STRINGS -let SHF_INFO_LINK = swift.runtime.SHF_INFO_LINK -let SHF_LINK_ORDER = swift.runtime.SHF_LINK_ORDER +let SHF_WRITE = swift.runtime.SHF_WRITE +let SHF_ALLOC = swift.runtime.SHF_ALLOC +let SHF_EXECINSTR = swift.runtime.SHF_EXECINSTR +let SHF_MERGE = swift.runtime.SHF_MERGE +let SHF_STRINGS = swift.runtime.SHF_STRINGS +let SHF_INFO_LINK = swift.runtime.SHF_INFO_LINK +let SHF_LINK_ORDER = swift.runtime.SHF_LINK_ORDER let SHF_OS_NONCONFORMING = swift.runtime.SHF_OS_NONCONFORMING -let SHF_GROUP = swift.runtime.SHF_GROUP -let SHF_TLS = swift.runtime.SHF_TLS -let SHF_COMPRESSED = swift.runtime.SHF_COMPRESSED -let SHF_MASKOS = swift.runtime.SHF_MASKOS -let SHF_MASKPROC = swift.runtime.SHF_MASKPROC - -let GRP_COMDAT = swift.runtime.GRP_COMDAT -let GRP_MASKOS = swift.runtime.GRP_MASKOS +let SHF_GROUP = swift.runtime.SHF_GROUP +let SHF_TLS = swift.runtime.SHF_TLS +let SHF_COMPRESSED = swift.runtime.SHF_COMPRESSED +let SHF_MASKOS = swift.runtime.SHF_MASKOS +let SHF_MASKPROC = swift.runtime.SHF_MASKPROC + +let GRP_COMDAT = swift.runtime.GRP_COMDAT +let GRP_MASKOS = swift.runtime.GRP_MASKOS let GRP_MASKPROC = swift.runtime.GRP_MASKPROC typealias Elf_Chdr_Type = swift.runtime.Elf_Chdr_Type -typealias Elf_Sym_Binding = swift.runtime.Elf_Sym_Binding -typealias Elf_Sym_Type = swift.runtime.Elf_Sym_Type +typealias Elf_Sym_Binding = swift.runtime.Elf_Sym_Binding +typealias Elf_Sym_Type = swift.runtime.Elf_Sym_Type typealias Elf_Sym_Visibility = swift.runtime.Elf_Sym_Visibility -typealias Elf_Phdr_Type = swift.runtime.Elf_Phdr_Type +typealias Elf_Phdr_Type = swift.runtime.Elf_Phdr_Type typealias Elf_Phdr_Flags = swift.runtime.Elf_Phdr_Flags let PF_X = swift.runtime.PF_X let PF_W = swift.runtime.PF_W let PF_R = swift.runtime.PF_R -let PF_MASKOS = swift.runtime.PF_MASKOS +let PF_MASKOS = swift.runtime.PF_MASKOS let PF_MASKPROC = swift.runtime.PF_MASKPROC -let DT_NULL = swift.runtime.DT_NULL -let DT_NEEDED = swift.runtime.DT_NEEDED -let DT_PLTRELSZ = swift.runtime.DT_PLTRELSZ -let DT_PLTGOT = swift.runtime.DT_PLTGOT -let DT_HASH = swift.runtime.DT_HASH -let DT_STRTAB = swift.runtime.DT_STRTAB -let DT_SYMTAB = swift.runtime.DT_SYMTAB -let DT_RELA = swift.runtime.DT_RELA -let DT_RELASZ = swift.runtime.DT_RELASZ -let DT_RELAENT = swift.runtime.DT_RELAENT -let DT_STRSZ = swift.runtime.DT_STRSZ -let DT_SYMENT = swift.runtime.DT_SYMENT -let DT_INIT = swift.runtime.DT_INIT -let DT_FINI = swift.runtime.DT_FINI -let DT_SONAME = swift.runtime.DT_SONAME -let DT_RPATH = swift.runtime.DT_RPATH -let DT_SYMBOLIC = swift.runtime.DT_SYMBOLIC -let DT_REL = swift.runtime.DT_REL -let DT_RELSZ = swift.runtime.DT_RELSZ -let DT_RELENT = swift.runtime.DT_RELENT -let DT_PLTREL = swift.runtime.DT_PLTREL -let DT_DEBUG = swift.runtime.DT_DEBUG -let DT_TEXTREL = swift.runtime.DT_TEXTREL -let DT_JMPREL = swift.runtime.DT_JMPREL -let DT_BIND_NOW = swift.runtime.DT_BIND_NOW -let DT_INIT_ARRAY = swift.runtime.DT_INIT_ARRAY -let DT_FINI_ARRAY = swift.runtime.DT_FINI_ARRAY -let DT_INIT_ARRAYSZ = swift.runtime.DT_INIT_ARRAYSZ -let DT_FINI_ARRAYSZ = swift.runtime.DT_FINI_ARRAYSZ -let DT_RUNPATH = swift.runtime.DT_RUNPATH -let DT_FLAGS = swift.runtime.DT_FLAGS - -let DT_ENCODING = swift.runtime.DT_ENCODING - -let DT_PREINIT_ARRAY = swift.runtime.DT_PREINIT_ARRAY +let DT_NULL = swift.runtime.DT_NULL +let DT_NEEDED = swift.runtime.DT_NEEDED +let DT_PLTRELSZ = swift.runtime.DT_PLTRELSZ +let DT_PLTGOT = swift.runtime.DT_PLTGOT +let DT_HASH = swift.runtime.DT_HASH +let DT_STRTAB = swift.runtime.DT_STRTAB +let DT_SYMTAB = swift.runtime.DT_SYMTAB +let DT_RELA = swift.runtime.DT_RELA +let DT_RELASZ = swift.runtime.DT_RELASZ +let DT_RELAENT = swift.runtime.DT_RELAENT +let DT_STRSZ = swift.runtime.DT_STRSZ +let DT_SYMENT = swift.runtime.DT_SYMENT +let DT_INIT = swift.runtime.DT_INIT +let DT_FINI = swift.runtime.DT_FINI +let DT_SONAME = swift.runtime.DT_SONAME +let DT_RPATH = swift.runtime.DT_RPATH +let DT_SYMBOLIC = swift.runtime.DT_SYMBOLIC +let DT_REL = swift.runtime.DT_REL +let DT_RELSZ = swift.runtime.DT_RELSZ +let DT_RELENT = swift.runtime.DT_RELENT +let DT_PLTREL = swift.runtime.DT_PLTREL +let DT_DEBUG = swift.runtime.DT_DEBUG +let DT_TEXTREL = swift.runtime.DT_TEXTREL +let DT_JMPREL = swift.runtime.DT_JMPREL +let DT_BIND_NOW = swift.runtime.DT_BIND_NOW +let DT_INIT_ARRAY = swift.runtime.DT_INIT_ARRAY +let DT_FINI_ARRAY = swift.runtime.DT_FINI_ARRAY +let DT_INIT_ARRAYSZ = swift.runtime.DT_INIT_ARRAYSZ +let DT_FINI_ARRAYSZ = swift.runtime.DT_FINI_ARRAYSZ +let DT_RUNPATH = swift.runtime.DT_RUNPATH +let DT_FLAGS = swift.runtime.DT_FLAGS +let DT_ENCODING = swift.runtime.DT_ENCODING +let DT_PREINIT_ARRAY = swift.runtime.DT_PREINIT_ARRAY let DT_PREINIT_ARRAYSZ = swift.runtime.DT_PREINIT_ARRAYSZ - -let DT_LOOS = swift.runtime.DT_LOOS -let DT_HIOS = swift.runtime.DT_HIOS - -let DT_LOPROC = swift.runtime.DT_LOPROC -let DT_HIPROC = swift.runtime.DT_HIPROC - -let DF_ORIGIN = swift.runtime.DF_ORIGIN -let DF_SYMBOLIC = swift.runtime.DF_SYMBOLIC -let DF_TEXTREL = swift.runtime.DF_TEXTREL -let DF_BIND_NOW = swift.runtime.DF_BIND_NOW +let DT_LOOS = swift.runtime.DT_LOOS +let DT_HIOS = swift.runtime.DT_HIOS +let DT_LOPROC = swift.runtime.DT_LOPROC +let DT_HIPROC = swift.runtime.DT_HIPROC + +let DF_ORIGIN = swift.runtime.DF_ORIGIN +let DF_SYMBOLIC = swift.runtime.DF_SYMBOLIC +let DF_TEXTREL = swift.runtime.DF_TEXTREL +let DF_BIND_NOW = swift.runtime.DF_BIND_NOW let DF_STATIC_TLS = swift.runtime.DF_STATIC_TLS -let NT_GNU_ABI_TAG = swift.runtime.NT_GNU_ABI_TAG -let NT_GNU_HWCAP = swift.runtime.NT_GNU_HWCAP -let NT_GNU_BUILD_ID = swift.runtime.NT_GNU_BUILD_ID -let NT_GNU_GOLD_VERSION = swift.runtime.NT_GNU_GOLD_VERSION +let NT_GNU_ABI_TAG = swift.runtime.NT_GNU_ABI_TAG +let NT_GNU_HWCAP = swift.runtime.NT_GNU_HWCAP +let NT_GNU_BUILD_ID = swift.runtime.NT_GNU_BUILD_ID +let NT_GNU_GOLD_VERSION = swift.runtime.NT_GNU_GOLD_VERSION let NT_GNU_PROPERTY_TYPE_0 = swift.runtime.NT_GNU_PROPERTY_TYPE_0 typealias Elf32_Ehdr = swift.runtime.Elf32_Ehdr @@ -200,32 +193,35 @@ typealias Elf64_Chdr = swift.runtime.Elf64_Chdr typealias Elf32_Sym = swift.runtime.Elf32_Sym typealias Elf64_Sym = swift.runtime.Elf64_Sym -let ELF32_ST_BIND = swift.runtime.ELF32_ST_BIND -let ELF32_ST_TYPE = swift.runtime.ELF32_ST_TYPE -let ELF32_ST_INFO = swift.runtime.ELF32_ST_INFO +let ELF32_ST_BIND = swift.runtime.ELF32_ST_BIND +let ELF32_ST_TYPE = swift.runtime.ELF32_ST_TYPE +let ELF32_ST_INFO = swift.runtime.ELF32_ST_INFO let ELF32_ST_VISIBILITY = swift.runtime.ELF32_ST_VISIBILITY -let ELF64_ST_BIND = swift.runtime.ELF64_ST_BIND -let ELF64_ST_TYPE = swift.runtime.ELF64_ST_TYPE -let ELF64_ST_INFO = swift.runtime.ELF64_ST_INFO +let ELF64_ST_BIND = swift.runtime.ELF64_ST_BIND +let ELF64_ST_TYPE = swift.runtime.ELF64_ST_TYPE +let ELF64_ST_INFO = swift.runtime.ELF64_ST_INFO let ELF64_ST_VISIBILITY = swift.runtime.ELF64_ST_VISIBILITY -typealias Elf32_Rel = swift.runtime.Elf32_Rel +typealias Elf32_Rel = swift.runtime.Elf32_Rel typealias Elf32_Rela = swift.runtime.Elf32_Rela -typealias Elf64_Rel = swift.runtime.Elf64_Rel +typealias Elf64_Rel = swift.runtime.Elf64_Rel typealias Elf64_Rela = swift.runtime.Elf64_Rela -let ELF32_R_SYM = swift.runtime.ELF32_R_SYM +let ELF32_R_SYM = swift.runtime.ELF32_R_SYM let ELF32_R_TYPE = swift.runtime.ELF32_R_TYPE let ELF32_R_INFO = swift.runtime.ELF32_R_INFO -let ELF64_R_SYM = swift.runtime.ELF64_R_SYM +let ELF64_R_SYM = swift.runtime.ELF64_R_SYM let ELF64_R_TYPE = swift.runtime.ELF64_R_TYPE let ELF64_R_INFO = swift.runtime.ELF64_R_INFO typealias Elf32_Phdr = swift.runtime.Elf32_Phdr typealias Elf64_Phdr = swift.runtime.Elf64_Phdr +typealias Elf32_Nhdr = swift.runtime.Elf32_Nhdr +typealias Elf64_Nhdr = swift.runtime.Elf64_Nhdr + typealias Elf32_Dyn = swift.runtime.Elf32_Dyn typealias Elf64_Dyn = swift.runtime.Elf64_Dyn @@ -302,7 +298,7 @@ private let crc32Table: [UInt32] = [ ] private func updateCrc(_ crc: UInt32, - _ bytes: UnsafeBufferPointer) -> UInt32 { + _ bytes: UnsafeRawBufferPointer) -> UInt32 { var theCrc = ~crc for byte in bytes { theCrc = crc32Table[Int(UInt8(truncatingIfNeeded: theCrc) @@ -420,6 +416,12 @@ extension Elf64_Chdr: Elf_Chdr { } } +extension Elf_Chdr_Type: ByteSwappable { + var byteSwapped: Self { + return Elf_Chdr_Type(rawValue: rawValue.byteSwapped)! + } +} + extension Elf32_Sym: ByteSwappable { var byteSwapped: Self { return Elf32_Sym( @@ -970,19 +972,17 @@ struct Elf64Traits: ElfTraits { // .. ElfStringSection ......................................................... struct ElfStringSection { - let bytes: [UInt8] + let source: ImageSource func getStringAt(index: Int) -> String? { - if index < 0 || index >= bytes.count { + if index < 0 || index >= source.bytes.count { return nil } - let slice = bytes[index...] + let slice = UnsafeRawBufferPointer(rebasing: source.bytes[index...]) var len: Int = 0 - slice.withUnsafeBufferPointer{ ptr in - len = strnlen(ptr.baseAddress!, ptr.count) - } - return String(decoding: bytes[index.. (any ImageSource)? - func getSection(_ name: String) -> (any ImageSource)? -} - -extension ElfGetSectionProtocol { - func getSection(_ name: String) -> (any ImageSource)? { - return getSection(name, debug: false) - } -} - protocol ElfSymbolProtocol: Equatable { associatedtype Address: FixedWidthInteger associatedtype Size: FixedWidthInteger @@ -1027,22 +1016,14 @@ protocol ElfSymbolTableProtocol { func lookupSymbol(address: Traits.Address) -> Symbol? } -protocol ElfImageProtocol: Image, ElfGetSectionProtocol, DwarfSource { +protocol ElfSymbolLookupProtocol { associatedtype Traits: ElfTraits - associatedtype SymbolTable: ElfSymbolTableProtocol - where SymbolTable.Traits == Traits - - var header: Traits.Ehdr { get } - var programHeaders: [Traits.Phdr] { get } - var sectionHeaders: [Traits.Shdr]? { get } - - var imageName: String { get } - var debugImage: (any ElfImageProtocol)? { get } - var debugLinkCRC: UInt32? { get } - - var symbolTable: SymbolTable { get } + typealias CallSiteInfo = DwarfReader>.CallSiteInfo + typealias SourceLocation = SymbolicatedBacktrace.SourceLocation - func _getSymbolTable(debug: Bool) -> SymbolTable + func lookupSymbol(address: Traits.Address) -> ImageSymbol? + func inlineCallSites(at address: Traits.Address) -> ArraySlice + func sourceLocation(for address: Traits.Address) throws -> SourceLocation? } struct ElfSymbolTable: ElfSymbolTableProtocol { @@ -1065,43 +1046,41 @@ struct ElfSymbolTable: ElfSymbolTableProtocol { init() {} - init?(image: ElfImage) { + @_specialize(kind: full, where SomeElfTraits == Elf32Traits) + @_specialize(kind: full, where SomeElfTraits == Elf64Traits) + init?(image: ElfImage) { guard let strtab = image.getSection(".strtab", debug: false), - let symtab = image.getSection(".symtab", debug: false), - let strings = strtab.fetchAllBytes(), - let symdata = symtab.fetchAllBytes() else { + let symtab = image.getSection(".symtab", debug: false) else { return nil } - let stringSect = ElfStringSection(bytes: strings) + let stringSect = ElfStringSection(source: strtab) // Extract all the data - symdata.withUnsafeBufferPointer{ - $0.withMemoryRebound(to: Traits.Sym.self) { symbols in - for symbol in symbols { - // Ignore things that are not functions - if symbol.st_type != .STT_FUNC { - continue - } + symtab.bytes.withMemoryRebound(to: Traits.Sym.self) { symbols in + for symbol in symbols { + // Ignore things that are not functions + if symbol.st_type != .STT_FUNC { + continue + } - // Ignore anything undefined - if symbol.st_shndx == SHN_UNDEF { - continue - } + // Ignore anything undefined + if symbol.st_shndx == SHN_UNDEF { + continue + } - _symbols.append( - Symbol( - name: (stringSect.getStringAt(index: Int(symbol.st_name)) - ?? ""), - value: symbol.st_value, - size: symbol.st_size, - sectionIndex: Int(symbol.st_shndx), - binding: symbol.st_binding, - type: symbol.st_type, - visibility: symbol.st_visibility - ) + _symbols.append( + Symbol( + name: (stringSect.getStringAt(index: Int(symbol.st_name)) + ?? ""), + value: symbol.st_value, + size: symbol.st_size, + sectionIndex: Int(symbol.st_shndx), + binding: symbol.st_binding, + type: symbol.st_type, + visibility: symbol.st_visibility ) - } + ) } } @@ -1117,6 +1096,8 @@ struct ElfSymbolTable: ElfSymbolTableProtocol { _symbols = sortedSymbols } + @_specialize(kind: full, where SomeElfTraits == Elf32Traits) + @_specialize(kind: full, where SomeElfTraits == Elf64Traits) public func merged(with other: ElfSymbolTable) -> ElfSymbolTable { var merged: [Symbol] = [] @@ -1159,6 +1140,8 @@ struct ElfSymbolTable: ElfSymbolTableProtocol { return ElfSymbolTable(sortedSymbols: merged) } + @_specialize(kind: full, where SomeElfTraits == Elf32Traits) + @_specialize(kind: full, where SomeElfTraits == Elf64Traits) public func lookupSymbol(address: Traits.Address) -> Symbol? { var min = 0 var max = _symbols.count @@ -1179,7 +1162,7 @@ struct ElfSymbolTable: ElfSymbolTableProtocol { ndx -= 1 } return _symbols[ndx] - } else if symbol.value < address { + } else if symbol.value <= address { min = mid + 1 } else if symbol.value > address { max = mid @@ -1190,27 +1173,28 @@ struct ElfSymbolTable: ElfSymbolTableProtocol { } } -class ElfImage: ElfImageProtocol { +final class ElfImage + : DwarfSource, ElfSymbolLookupProtocol { typealias Traits = SomeElfTraits - typealias Source = SomeImageSource typealias SymbolTable = ElfSymbolTable // This is arbitrary and it isn't in the spec let maxNoteNameLength = 256 - var baseAddress: Source.Address - var endAddress: Source.Address + var baseAddress: ImageSource.Address + var endAddress: ImageSource.Address - var source: SomeImageSource + var source: ImageSource var header: Traits.Ehdr var programHeaders: [Traits.Phdr] var sectionHeaders: [Traits.Shdr]? var shouldByteSwap: Bool { return header.shouldByteSwap } - required init(source: SomeImageSource, - baseAddress: Source.Address = 0, - endAddress: Source.Address = 0) throws { + @_specialize(kind: full, where SomeElfTraits == Elf32Traits) + @_specialize(kind: full, where SomeElfTraits == Elf64Traits) + required init(source: ImageSource, + baseAddress: ImageSource.Address = 0, + endAddress: ImageSource.Address = 0) throws { self.source = source self.baseAddress = baseAddress self.endAddress = endAddress @@ -1237,11 +1221,11 @@ class ElfImage + var image: ElfImage struct NoteIterator: IteratorProtocol { - var image: ElfImage + var image: ElfImage var hdrNdx = -1 - var noteAddr = Source.Address() - var noteEnd = Source.Address() + var noteAddr = ImageSource.Address() + var noteEnd = ImageSource.Address() - init(image: ElfImage) { + @_specialize(kind: full, where SomeElfTraits == Elf32Traits) + @_specialize(kind: full, where SomeElfTraits == Elf64Traits) + init(image: ElfImage) { self.image = image } @@ -1287,15 +1273,25 @@ class ElfImage Note? { + let byteSwap = image.shouldByteSwap + func maybeSwap(_ x: T) -> T { + if byteSwap { + return x.byteSwapped + } + return x + } + if hdrNdx >= image.programHeaders.count { return nil } @@ -1311,9 +1307,10 @@ class ElfImage.size) + noteAddr += ImageSource.Address(MemoryLayout.size) if noteEnd - noteAddr < nhdr.n_namesz { // The segment is probably corrupted @@ -1322,12 +1319,15 @@ class ElfImage 0 ? nhdr.n_namesz - 1 : 0 - let nameBytes = try image.fetch(from: noteAddr, - count: Int(nameLen), - as: UInt8.self) - let name = String(decoding: nameBytes, as: UTF8.self) + guard let name = try image.source.fetchString(from: noteAddr, + length: Int(nameLen)) + else { + // Bad note name + noteAddr = noteEnd + continue + } - noteAddr += Source.Address(nhdr.n_namesz) + noteAddr += ImageSource.Address(nhdr.n_namesz) if (noteAddr & 3) != 0 { noteAddr += 4 - (noteAddr & 3) } @@ -1338,11 +1338,11 @@ class ElfImage.allocate(capacity: bufSize) - defer { - buffer.deallocate() - } - - var pos = bounds.base - var remaining = bounds.size - var crc: UInt32 = 0 - do { - while remaining > 0 { - let todo = min(bufSize, Int(remaining)) - let slice = buffer[..(rebasing: slice) - - try fetch(from: pos, into: chunk) - - crc = updateCrc(crc, UnsafeBufferPointer(chunk)) - - remaining -= Source.Size(todo) - pos += Source.Address(todo) - } - } catch { - return nil - } - + let crc = updateCrc(0, source.bytes) + _debugLinkCRC = crc return crc } struct Range { - var base: Source.Address - var size: Source.Size + var base: ImageSource.Address + var size: ImageSource.Size } struct EHFrameInfo { @@ -1442,19 +1414,21 @@ class ElfImage.size) { continue } - guard let ehdr = try? fetch(from: Source.Address(ehFrameHdrRange.base), - as: EHFrameHdr.self) else { + guard let ehdr = try? source.fetch( + from: ImageSource.Address(ehFrameHdrRange.base), + as: EHFrameHdr.self + ) else { continue } @@ -1462,11 +1436,11 @@ class ElfImage.size) + let pc = ehFrameHdrRange.base + ImageSource.Address(MemoryLayout.size) guard let (_, eh_frame_ptr) = - try? source.fetchEHValue(from: Source.Address(pc), + try? source.fetchEHValue(from: ImageSource.Address(pc), with: ehdr.eh_frame_ptr_enc, - pc: Source.Address(pc)) else { + pc: ImageSource.Address(pc)) else { continue } @@ -1476,30 +1450,27 @@ class ElfImage? + var debugImage: ElfImage? { if let checked = _checkedDebugImage, checked { return _debugImage } - let tryPath = { [self] (_ path: String) -> (any ElfImageProtocol)? in + let tryPath = { [self] (_ path: String) -> ElfImage? in do { - let fileSource = try FileImageSource(path: path) - let image = try ElfImage(source: fileSource) + let fileSource = try ImageSource(path: path) + let image = try ElfImage(source: fileSource) _debugImage = image return image } catch { @@ -1562,7 +1533,7 @@ class ElfImage (any ElfImageProtocol)? in + let tryLink = { (_ link: String) -> ElfImage? in if let image = tryPath("\(imageDir)/\(link)") { return image } @@ -1592,9 +1563,8 @@ class ElfImage(source: source) + let source = try ImageSource(lzmaCompressedImageSource: debugData) + _debugImage = try ElfImage(source: source) _checkedDebugImage = true return _debugImage } catch let CompressedImageSourceError.libraryNotFound(library) { @@ -1617,15 +1587,17 @@ class ElfImage (any ImageSource)? { + @_specialize(kind: full, where SomeElfTraits == Elf32Traits) + @_specialize(kind: full, where SomeElfTraits == Elf64Traits) + func getSection(_ name: String, debug: Bool = false) -> ImageSource? { if let sectionHeaders = sectionHeaders { let zname = ".z" + name.dropFirst() let stringShdr = sectionHeaders[Int(header.e_shstrndx)] do { - let bytes = try source.fetch(from: Source.Address(stringShdr.sh_offset), - count: Int(stringShdr.sh_size), - as: UInt8.self) - let stringSect = ElfStringSection(bytes: bytes) + let base = ImageSource.Address(stringShdr.sh_offset) + let end = base + ImageSource.Size(stringShdr.sh_size) + let stringSource = source[base..(source: subSource) + return try ImageSource(elfCompressedImageSource: subSource, + traits: Traits.self) } else { return subSource } } if zname == sname { - let subSource = SubImageSource(parent: source, - baseAddress: Source.Address(shdr.sh_offset), - length: Source.Size(shdr.sh_size)) - return try ElfGNUCompressedImageSource(source: subSource) + let base = ImageSource.Address(shdr.sh_offset) + let end = base + ImageSource.Size(shdr.sh_size) + let subSource = source[base.. ImageSymbol? { - let relativeAddress = Traits.Address(address - baseAddress) + public func lookupSymbol(address: Traits.Address) -> ImageSymbol? { + let relativeAddress = address - Traits.Address(baseAddress) guard let symbol = symbolTable.lookupSymbol(address: relativeAddress) else { return nil } @@ -1800,7 +1766,7 @@ class ElfImage (any ImageSource)? { + func getDwarfSection(_ section: DwarfSection) -> ImageSource? { switch section { case .debugAbbrev: return getSection(".debug_abbrev") case .debugAddr: return getSection(".debug_addr") @@ -1832,7 +1798,9 @@ class ElfImage.CallSiteInfo - func inlineCallSites(at address: Address) -> ArraySlice { + func inlineCallSites( + at address: Traits.Address + ) -> ArraySlice { guard let callSiteInfo = dwarfReader?.inlineCallSites else { return [][0..<0] } @@ -1870,9 +1838,11 @@ class ElfImage SourceLocation? { + func sourceLocation( + for address: Traits.Address + ) throws -> SourceLocation? { var result: SourceLocation? = nil - var prevState: DwarfReader.LineNumberState? = nil + var prevState: DwarfLineNumberState? = nil guard let dwarfReader = dwarfReader else { return nil } @@ -1901,14 +1871,157 @@ class ElfImage = ElfImage -typealias Elf64Image = ElfImage +typealias Elf32Image = ElfImage +typealias Elf64Image = ElfImage + +// .. Checking for ELF images .................................................. + +/// Test if there is a valid ELF image at the specified address; if there is, +/// extract the address range for the text segment and the UUID, if any. +@_specialize(kind: full, where R == UnsafeLocalMemoryReader) +@_specialize(kind: full, where R == RemoteMemoryReader) +#if os(Linux) +@_specialize(kind: full, where R == MemserverMemoryReader) +#endif +func getElfImageInfo(at address: R.Address, + using reader: R) + -> (endOfText: R.Address, uuid: [UInt8]?)? +{ + do { + // Check the magic number first + let magic = try reader.fetch(from: address, as: Elf_Magic.self) + + if magic != ElfMagic { + return nil + } + + // Read the class from the next byte + let elfClass = Elf_Ehdr_Class(rawValue: try reader.fetch(from: address + 4, + as: UInt8.self)) + + if elfClass == .ELFCLASS32 { + return try getElfImageInfo(at: address, using: reader, + traits: Elf32Traits.self) + } else if elfClass == .ELFCLASS64 { + return try getElfImageInfo(at: address, using: reader, + traits: Elf64Traits.self) + } else { + return nil + } + } catch { + return nil + } +} + +@_specialize(kind: full, where R == UnsafeLocalMemoryReader, Traits == Elf32Traits) +@_specialize(kind: full, where R == UnsafeLocalMemoryReader, Traits == Elf64Traits) +@_specialize(kind: full, where R == RemoteMemoryReader, Traits == Elf32Traits) +@_specialize(kind: full, where R == RemoteMemoryReader, Traits == Elf64Traits) +#if os(Linux) +@_specialize(kind: full, where R == MemserverMemoryReader, Traits == Elf32Traits) +@_specialize(kind: full, where R == MemserverMemoryReader, Traits == Elf64Traits) +#endif +func getElfImageInfo( + at address: R.Address, + using reader: R, + traits: Traits.Type +) throws -> (endOfText: R.Address, uuid: [UInt8]?)? { + // Grab the whole 32-bit header + let unswappedHeader = try reader.fetch(from: address, as: Traits.Ehdr.self) + + let header: Traits.Ehdr + if unswappedHeader.shouldByteSwap { + header = unswappedHeader.byteSwapped + } else { + header = unswappedHeader + } + + let byteSwap = header.shouldByteSwap + func maybeSwap(_ x: T) -> T { + if byteSwap { + return x.byteSwapped + } + return x + } + + var endOfText = address + var uuid: [UInt8]? = nil + + // Find the last loadable executable segment, and scan for PT_NOTE + // segments that contain the UUID + var phAddr = ImageSource.Address(address) + ImageSource.Size(header.e_phoff) + for _ in 0...size) + + if noteEnd - noteAddr < nhdr.n_namesz { + // This segment is probably corrupted, so skip it + noteAddr = noteEnd + continue + } + + var isBuildId = false + let nameLen = nhdr.n_namesz > 0 ? nhdr.n_namesz - 1 : 0 + + // Test if this is a "GNU" NT_GNU_BUILD_ID note + if nameLen == 3 { + let byte0 = try reader.fetch(from: noteAddr, as: UInt8.self) + let byte1 = try reader.fetch(from: noteAddr + 1, as: UInt8.self) + let byte2 = try reader.fetch(from: noteAddr + 2, as: UInt8.self) + + if byte0 == 0x47 && byte1 == 0x4e && byte2 == 0x55 && + UInt32(nhdr.n_type) == NT_GNU_BUILD_ID { + isBuildId = true + } + } + + noteAddr += ImageSource.Size(nhdr.n_namesz) + if (noteAddr & 3) != 0 { + noteAddr += 4 - (noteAddr & 3) + } + + if noteEnd - noteAddr < nhdr.n_descsz { + // Corrupted segment, skip + noteAddr = noteEnd + continue + } + + if isBuildId { + uuid = try reader.fetch(from: noteAddr, + count: Int(nhdr.n_descsz), + as: UInt8.self) + } + + noteAddr += ImageSource.Size(nhdr.n_descsz) + if (noteAddr & 3) != 0 { + noteAddr += 4 - (noteAddr & 3) + } + } + } + + phAddr += ImageSource.Address(header.e_phentsize) + } + + return (endOfText: endOfText, uuid: uuid) +} // .. Testing .................................................................. @_spi(ElfTest) public func testElfImageAt(path: String) -> Bool { - guard let source = try? FileImageSource(path: path) else { + guard let source = try? ImageSource(path: path) else { print("\(path) was not accessible") return false } @@ -1978,5 +2091,3 @@ public func testElfImageAt(path: String) -> Bool { return false } } - -#endif // os(Linux) diff --git a/stdlib/public/RuntimeModule/ElfImageCache.swift b/stdlib/public/RuntimeModule/ElfImageCache.swift new file mode 100644 index 0000000000000..fb34adbd05c73 --- /dev/null +++ b/stdlib/public/RuntimeModule/ElfImageCache.swift @@ -0,0 +1,95 @@ +//===--- ElfImageCache.swift - ELF support for Swift ----------------------===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2024 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 +// +//===----------------------------------------------------------------------===// +// +// Provides a per-thread Elf image cache that improves efficiency when +// taking multiple backtraces by avoiding loading ELF images multiple times. +// +//===----------------------------------------------------------------------===// + +import Swift + +#if os(macOS) || os(iOS) || os(tvOS) || os(watchOS) +internal import Darwin +#elseif os(Windows) +internal import ucrt +#elseif canImport(Glibc) +internal import Glibc +#elseif canImport(Musl) +internal import Musl +#endif + +/// Provides a per-thread image cache for ELF image processing. This means +/// if you take multiple backtraces from a thread, you won't load the same +/// image multiple times. +final class ElfImageCache { + var elf32: [String: Elf32Image] = [:] + var elf64: [String: Elf64Image] = [:] + + func purge() { + elf32 = [:] + elf64 = [:] + } + + enum Result { + case elf32Image(Elf32Image) + case elf64Image(Elf64Image) + } + func lookup(path: String?) -> Result? { + guard let path = path else { + return nil + } + if let image = elf32[path] { + return .elf32Image(image) + } + if let image = elf64[path] { + return .elf64Image(image) + } + if let source = try? ImageSource(path: path) { + if let elfImage = try? Elf32Image(source: source) { + elf32[path] = elfImage + return .elf32Image(elfImage) + } + if let elfImage = try? Elf64Image(source: source) { + elf64[path] = elfImage + return .elf64Image(elfImage) + } + } + return nil + } + + private static var key: pthread_key_t = { + var theKey = pthread_key_t() + let err = pthread_key_create( + &theKey, + { rawPtr in + let ptr = Unmanaged.fromOpaque( + notMutable(notOptional(rawPtr)) + ) + ptr.release() + } + ) + if err != 0 { + fatalError("Unable to create TSD key for ElfImageCache") + } + return theKey + }() + + static var threadLocal: ElfImageCache { + guard let rawPtr = pthread_getspecific(key) else { + let cache = Unmanaged.passRetained(ElfImageCache()) + pthread_setspecific(key, cache.toOpaque()) + return cache.takeUnretainedValue() + } + let cache = Unmanaged.fromOpaque(rawPtr) + return cache.takeUnretainedValue() + } +} diff --git a/stdlib/public/Backtracing/FramePointerUnwinder.swift b/stdlib/public/RuntimeModule/FramePointerUnwinder.swift similarity index 51% rename from stdlib/public/Backtracing/FramePointerUnwinder.swift rename to stdlib/public/RuntimeModule/FramePointerUnwinder.swift index 9d5b502f35cfd..3b874bb9425fd 100644 --- a/stdlib/public/Backtracing/FramePointerUnwinder.swift +++ b/stdlib/public/RuntimeModule/FramePointerUnwinder.swift @@ -20,7 +20,7 @@ import Swift public struct FramePointerUnwinder: Sequence, IteratorProtocol { public typealias Context = C public typealias MemoryReader = M - public typealias Address = MemoryReader.Address + public typealias Address = Context.Address var pc: Address var fp: Address @@ -30,15 +30,18 @@ public struct FramePointerUnwinder: Sequence, Itera var done: Bool #if os(Linux) - var elf32Cache: [Int:Elf32Image] = [:] - var elf64Cache: [Int:Elf64Image] = [:] - var images: [Backtrace.Image]? + var images: ImageMap? #endif var reader: MemoryReader + @_specialize(exported: true, kind: full, where C == HostContext, M == UnsafeLocalMemoryReader) + @_specialize(exported: true, kind: full, where C == HostContext, M == RemoteMemoryReader) + #if os(Linux) + @_specialize(exported: true, kind: full, where C == HostContext, M == MemserverMemoryReader) + #endif public init(context: Context, - images: [Backtrace.Image]?, + images: ImageMap?, memoryReader: MemoryReader) { pc = Address(context.programCounter) @@ -73,42 +76,48 @@ public struct FramePointerUnwinder: Sequence, Itera return false } + @_specialize(exported: true, kind: full, where C == HostContext, M == UnsafeLocalMemoryReader) + @_specialize(exported: true, kind: full, where C == HostContext, M == RemoteMemoryReader) + #if os(Linux) + @_specialize(exported: true, kind: full, where C == HostContext, M == MemserverMemoryReader) + #endif private mutating func isAsyncPC(_ pc: Address) -> Bool { // On Linux, we need to examine the PC to see if this is an async frame #if os(Linux) - let address = FileImageSource.Address(pc) + let address = MemoryReader.Address(pc) if let images = images, - let imageNdx = images.firstIndex( - where: { address >= $0.baseAddress && address < $0.endOfText } - ) { - let relativeAddress = address - FileImageSource.Address(images[imageNdx].baseAddress) - var elf32Image = elf32Cache[imageNdx] - var elf64Image = elf64Cache[imageNdx] - - if elf32Image == nil && elf64Image == nil { - if let source = try? FileImageSource(path: images[imageNdx].path) { - if let elfImage = try? Elf32Image(source: source) { - elf32Image = elfImage - elf32Cache[imageNdx] = elfImage - } else if let elfImage = try? Elf64Image(source: source) { - elf64Image = elfImage - elf64Cache[imageNdx] = elfImage - } + let imageNdx = images.indexOfImage(at: Backtrace.Address(address)) { + let base = MemoryReader.Address(images[imageNdx].baseAddress)! + let relativeAddress = address - base + let cache = ElfImageCache.threadLocal + + if let hit = cache.lookup(path: images[imageNdx].path) { + switch hit { + case let .elf32Image(image): + if let theSymbol = image.lookupSymbol( + address: Elf32Image.Traits.Address(relativeAddress) + ) { + return isAsyncSymbol(theSymbol.name) + } + case let .elf64Image(image): + if let theSymbol = image.lookupSymbol( + address: Elf64Image.Traits.Address(relativeAddress)) { + return isAsyncSymbol(theSymbol.name) + } } } - - if let theSymbol = elf32Image?.lookupSymbol(address: relativeAddress) { - return isAsyncSymbol(theSymbol.name) - } else if let theSymbol = elf64Image?.lookupSymbol(address: relativeAddress) { - return isAsyncSymbol(theSymbol.name) - } } #endif return false } + @_specialize(exported: true, kind: full, where C == HostContext, M == UnsafeLocalMemoryReader) + @_specialize(exported: true, kind: full, where C == HostContext, M == RemoteMemoryReader) + #if os(Linux) + @_specialize(exported: true, kind: full, where C == HostContext, M == MemserverMemoryReader) + #endif private func isAsyncFrame(_ storedFp: Address) -> Bool { #if (os(macOS) || os(iOS) || os(watchOS)) && (arch(arm64) || arch(arm64_32) || arch(x86_64)) // On Darwin, we borrow a bit of the frame pointer to indicate async @@ -119,15 +128,25 @@ public struct FramePointerUnwinder: Sequence, Itera #endif } + @_specialize(exported: true, kind: full, where C == HostContext, M == UnsafeLocalMemoryReader) + @_specialize(exported: true, kind: full, where C == HostContext, M == RemoteMemoryReader) + #if os(Linux) + @_specialize(exported: true, kind: full, where C == HostContext, M == MemserverMemoryReader) + #endif private func stripPtrAuth(_ address: Address) -> Address { - return Address(Context.stripPtrAuth(address: Context.Address(address))) + return Context.stripPtrAuth(address: address) } + @_specialize(exported: true, kind: full, where C == HostContext, M == UnsafeLocalMemoryReader) + @_specialize(exported: true, kind: full, where C == HostContext, M == RemoteMemoryReader) + #if os(Linux) + @_specialize(exported: true, kind: full, where C == HostContext, M == MemserverMemoryReader) + #endif private mutating func fetchAsyncContext() -> Bool { let strippedFp = stripPtrAuth(fp) do { - asyncContext = try reader.fetch(from: Address(strippedFp - 8), + asyncContext = try reader.fetch(from: MemoryReader.Address(strippedFp - 8), as: Address.self) return true } catch { @@ -135,7 +154,12 @@ public struct FramePointerUnwinder: Sequence, Itera } } - public mutating func next() -> Backtrace.Frame? { + @_specialize(exported: true, kind: full, where C == HostContext, M == UnsafeLocalMemoryReader) + @_specialize(exported: true, kind: full, where C == HostContext, M == RemoteMemoryReader) + #if os(Linux) + @_specialize(exported: true, kind: full, where C == HostContext, M == MemserverMemoryReader) + #endif + public mutating func next() -> RichFrame
? { if done { return nil } @@ -143,7 +167,7 @@ public struct FramePointerUnwinder: Sequence, Itera if first { first = false pc = stripPtrAuth(pc) - return .programCounter(Backtrace.Address(pc)) + return .programCounter(pc) } if !isAsync { @@ -153,17 +177,20 @@ public struct FramePointerUnwinder: Sequence, Itera let strippedFp = stripPtrAuth(fp) if strippedFp == 0 - || !Context.isAlignedForStack(framePointer: - Context.Address(strippedFp)) { + || !Context.isAlignedForStack(framePointer:strippedFp) { done = true return nil } do { - pc = stripPtrAuth(try reader.fetch(from: - strippedFp + Address(MemoryLayout
.size), - as: Address.self)) - next = try reader.fetch(from: Address(strippedFp), as: Address.self) + pc = stripPtrAuth(try reader.fetch( + from:MemoryReader.Address( + strippedFp + + Address(MemoryLayout
.size) + ), + as: Address.self)) + next = try reader.fetch(from: MemoryReader.Address(strippedFp), + as: Address.self) } catch { done = true return nil @@ -176,7 +203,7 @@ public struct FramePointerUnwinder: Sequence, Itera if !isAsyncFrame(next) { fp = next - return .returnAddress(Backtrace.Address(pc)) + return .returnAddress(pc) } } @@ -202,8 +229,10 @@ public struct FramePointerUnwinder: Sequence, Itera // On arm64_32, the two pointers at the start of the context are 32-bit, // although the stack layout is identical to vanilla arm64 do { - var next32 = try reader.fetch(from: strippedCtx, as: UInt32.self) - var pc32 = try reader.fetch(from: strippedCtx + 4, as: UInt32.self) + var next32 = try reader.fetch(from: MemoryReader.Address(strippedCtx), + as: UInt32.self) + var pc32 = try reader.fetch(from: MemoryReader.Address(strippedCtx + 4), + as: UInt32.self) next = Address(next32) pc = stripPtrAuth(Address(pc32)) @@ -215,8 +244,10 @@ public struct FramePointerUnwinder: Sequence, Itera // Otherwise it's two 64-bit words do { - next = try reader.fetch(from: strippedCtx, as: Address.self) - pc = stripPtrAuth(try reader.fetch(from: strippedCtx + 8, as: Address.self)) + next = try reader.fetch(from: MemoryReader.Address(strippedCtx), + as: Address.self) + pc = stripPtrAuth(try reader.fetch(from: MemoryReader.Address(strippedCtx + 8), + as: Address.self)) } catch { done = true return nil @@ -225,7 +256,6 @@ public struct FramePointerUnwinder: Sequence, Itera #endif asyncContext = next - - return .asyncResumePoint(Backtrace.Address(pc)) + return .asyncResumePoint(pc) } } diff --git a/stdlib/public/Backtracing/Image.swift b/stdlib/public/RuntimeModule/Image.swift similarity index 96% rename from stdlib/public/Backtracing/Image.swift rename to stdlib/public/RuntimeModule/Image.swift index 7f3d1ef6ebae1..e43b8f1626324 100644 --- a/stdlib/public/Backtracing/Image.swift +++ b/stdlib/public/RuntimeModule/Image.swift @@ -23,17 +23,15 @@ struct ImageSymbol { } internal protocol Image { - associatedtype Source: ImageSource - typealias UUID = [UInt8] - typealias Address = Source.Address + typealias Address = ImageSource.Address - init(source: Source, baseAddress: Address, endAddress: Address) throws + init(source: ImageSource, baseAddress: Address, endAddress: Address) throws var baseAddress: Address { get set } var endAddress: Address { get set } - var source: Source { get } + var source: ImageSource { get } var uuid: UUID? { get } var shouldByteSwap: Bool { get } diff --git a/stdlib/public/RuntimeModule/ImageMap+Darwin.swift b/stdlib/public/RuntimeModule/ImageMap+Darwin.swift new file mode 100644 index 0000000000000..ee0415f7378ac --- /dev/null +++ b/stdlib/public/RuntimeModule/ImageMap+Darwin.swift @@ -0,0 +1,131 @@ +//===--- ImageMap+Darwin.swift --------------------------------*- swift -*-===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2024 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 +// +//===----------------------------------------------------------------------===// +// +// Darwin specifics for ImageMap capture. +// +//===----------------------------------------------------------------------===// + +#if os(macOS) || os(iOS) || os(watchOS) || os(tvOS) + +import Swift + +internal import Darwin +internal import BacktracingImpl.OS.Darwin + +fileprivate func getSysCtlString(_ name: String) -> String? { + return withUnsafeTemporaryAllocation(byteCount: 256, alignment: 16) { + (buffer: UnsafeMutableRawBufferPointer) -> String? in + + var len = buffer.count + let ret = sysctlbyname(name, + buffer.baseAddress, &len, + nil, 0) + if ret != 0 { + return nil + } + + return String(validatingUTF8: + buffer.baseAddress!.assumingMemoryBound(to: CChar.self)) + } +} + +extension ImageMap { + + private static let platform = { + #if os(macOS) + var platform = "macOS" + #elseif os(iOS) + var platform = "iOS" + #elseif os(watchOS) + var platform = "watchOS" + #elseif os(tvOS) + var platform = "tvOS" + #elseif os(visionOS) + var platform = "visionOS" + #endif + + let osVersion = getSysCtlString("kern.osversion") ?? "" + let osProductVersion = getSysCtlString("kern.osproductversion") ?? "" + + return "\(platform) \(osProductVersion) (\(osVersion))" + }() + + private static func withDyldProcessInfo(for task: task_t, + fn: (OpaquePointer?) throws -> T) + rethrows -> T { + var kret = kern_return_t(KERN_SUCCESS) + let dyldInfo = _dyld_process_info_create(task, 0, &kret) + + if kret != KERN_SUCCESS { + fatalError("error: cannot create dyld process info") + } + + defer { + _dyld_process_info_release(dyldInfo) + } + + return try fn(dyldInfo) + } + + @_spi(Internal) + public static func capture(for process: Any) -> ImageMap { + var images: [Image] = [] + let task = process as! task_t + + withDyldProcessInfo(for: task) { dyldInfo in + _dyld_process_info_for_each_image(dyldInfo) { + (machHeaderAddress, uuid, path) in + + if let path = path, let uuid = uuid { + let pathString = String(cString: path) + let theUUID = Array(UnsafeBufferPointer(start: uuid, + count: MemoryLayout.size)) + let name: String + if let slashIndex = pathString.lastIndex(of: "/") { + name = String(pathString.suffix(from: + pathString.index(after:slashIndex))) + } else { + name = pathString + } + + // Find the end of the __TEXT segment + var endOfText = machHeaderAddress + 4096 + + _dyld_process_info_for_each_segment(dyldInfo, machHeaderAddress) { + address, size, name in + + if let name = String(validatingCString: name!), name == "__TEXT" { + endOfText = address + size + } + } + + images.append(Image(name: name, + path: pathString, + uniqueID: theUUID, + baseAddress: machHeaderAddress, + endOfText: endOfText)) + } + } + } + + images.sort(by: { $0.baseAddress < $1.baseAddress }) + + return ImageMap( + platform: ImageMap.platform, + images: images, + wordSize: .sixtyFourBit + ) + } + +} + +#endif // os(macOS) || os(iOS) || os(watchOS) || os(tvOS) diff --git a/stdlib/public/RuntimeModule/ImageMap+Linux.swift b/stdlib/public/RuntimeModule/ImageMap+Linux.swift new file mode 100644 index 0000000000000..6a565ddad95cc --- /dev/null +++ b/stdlib/public/RuntimeModule/ImageMap+Linux.swift @@ -0,0 +1,169 @@ +//===--- ImageMap+Linux.swift --------------------------------*- swift -*-===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2024 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 +// +//===----------------------------------------------------------------------===// +// +// Linux specifics for ImageMap capture. +// +//===----------------------------------------------------------------------===// + +#if os(Linux) + +import Swift + +#if canImport(Glibc) +internal import Glibc +#elseif canImport(Musl) +internal import Musl +#endif + +internal import BacktracingImpl.ImageFormats.Elf + +fileprivate func readOSRelease(fd: CInt) -> [String:String]? { + let len = lseek(fd, 0, SEEK_END) + guard len >= 0 else { + return nil + } + return withUnsafeTemporaryAllocation(byteCount: len, alignment: 16) { + (buffer: UnsafeMutableRawBufferPointer) -> [String:String]? in + + _ = lseek(fd, 0, SEEK_SET) + let bytesRead = read(fd, buffer.baseAddress, buffer.count) + guard bytesRead == buffer.count else { + return nil + } + + let asString = String(decoding: buffer, as: UTF8.self) + return Dictionary(OSReleaseScanner(asString), + uniquingKeysWith: { $1 }) + } +} + +fileprivate func readOSRelease() -> [String:String]? { + var fd = open("/etc/os-release", O_RDONLY) + if fd == -1 { + fd = open("/usr/lib/os-release", O_RDONLY) + } + if fd == -1 { + return nil + } + defer { + close(fd) + } + + return readOSRelease(fd: fd) +} + +extension ImageMap { + + private static var platform = { + guard let info = readOSRelease(), + let pretty = info["PRETTY_NAME"] else { + return "Linux (unknown)" + } + + return "Linux (\(pretty))" + }() + + private struct AddressRange { + var low: Address = 0 + var high: Address = 0 + } + + @_specialize(exported: true, kind: full, where M == UnsafeLocalMemoryReader) + @_specialize(exported: true, kind: full, where M == RemoteMemoryReader) + @_specialize(exported: true, kind: full, where M == LocalMemoryReader) + @_spi(Internal) + public static func capture( + using reader: M, + forProcess pid: Int? = nil + ) -> ImageMap { + var images: [Image] = [] + + let wordSize: WordSize + + #if arch(x86_64) || arch(arm64) || arch(arm64_32) + wordSize = .sixtyFourBit + #elseif arch(i386) || arch(arm) + wordSize = .thirtyTwoBit + #endif + + let path: String + if let pid = pid { + path = "/proc/\(pid)/maps" + } else { + path = "/proc/self/maps" + } + + guard let procMaps = readString(from: path) else { + return ImageMap(platform: ImageMap.platform, images: [], wordSize: wordSize) + } + + // Find all the mapped files and get high/low ranges + var mappedFiles: [Substring:AddressRange] = [:] + for match in ProcMapsScanner(procMaps) { + let path = stripWhitespace(match.pathname) + if match.inode == "0" || path == "" { + continue + } + guard let start = Address(match.start, radix: 16), + let end = Address(match.end, radix: 16) else { + continue + } + + if let range = mappedFiles[path] { + mappedFiles[path] = AddressRange(low: Swift.min(start, range.low), + high: Swift.max(end, range.high)) + } else { + mappedFiles[path] = AddressRange(low: start, + high: end) + } + } + + // Look at each mapped file to see if it's an ELF image + for (path, range) in mappedFiles { + // Extract the filename from path + let name: Substring + if let slashIndex = path.lastIndex(of: "/") { + name = path.suffix(from: path.index(after: slashIndex)) + } else { + name = path + } + + // Inspect the image and extract the UUID and end of text + guard let (endOfText, uuid) = getElfImageInfo( + at: M.Address(exactly: range.low)!, + using: reader + ) else { + // Not an ELF image + continue + } + + let image = Image(name: String(name), + path: String(path), + uniqueID: uuid, + baseAddress: range.low, + endOfText: Address(endOfText)) + + images.append(image) + } + + images.sort(by: { $0.baseAddress < $1.baseAddress }) + + return ImageMap( + platform: ImageMap.platform, + images: images, + wordSize: wordSize + ) + } + +} + +#endif // os(Linux) diff --git a/stdlib/public/RuntimeModule/ImageMap.swift b/stdlib/public/RuntimeModule/ImageMap.swift new file mode 100644 index 0000000000000..662267280ad39 --- /dev/null +++ b/stdlib/public/RuntimeModule/ImageMap.swift @@ -0,0 +1,211 @@ +//===--- ImageMap.swift ----------------------------------------*- swift -*-===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2024 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 +// +//===----------------------------------------------------------------------===// +// +// Defines the `ImageMap` struct that represents a captured list of loaded +// images. +// +//===----------------------------------------------------------------------===// + +import Swift + +#if os(macOS) || os(iOS) || os(watchOS) || os(tvOS) +internal import Darwin +internal import BacktracingImpl.OS.Darwin +#endif + +/// Holds a map of the process's address space. +public struct ImageMap: Collection, Sendable, Hashable { + + /// A type representing the sequence's elements. + public typealias Element = Backtrace.Image + + /// A type that represents a position in the collection. + public typealias Index = Int + + /// Tells us what size of machine words were used when capturing the + /// image map. + enum WordSize: Sendable { + case sixteenBit + case thirtyTwoBit + case sixtyFourBit + } + + /// We use UInt64s for addresses here. + typealias Address = UInt64 + + /// The internal representation of an image. + struct Image: Sendable, Hashable { + var name: String? + var path: String? + var uniqueID: [UInt8]? + var baseAddress: Address + var endOfText: Address + } + + /// The name of the platform that captured this image map. + public private(set) var platform: String + + /// The actual image storage. + var images: [Image] + + /// The size of words used when capturing. + var wordSize: WordSize + + /// Construct an ImageMap. + init(platform: String, images: [Image], wordSize: WordSize) { + self.platform = platform + self.images = images + self.wordSize = wordSize + } + + /// Construct an ImageMap from CompactImageMap data { + @_spi(Internal) + public init?(compactImageMapData: some Sequence) { + var decoder = CompactImageMapFormat.Decoder(compactImageMapData) + guard let (platform, images, wordSize) = decoder.decode() else { + return nil + } + self.init(platform: platform, images: images, wordSize: wordSize) + } + + /// The position of the first element in a non-empty collection. + public var startIndex: Self.Index { + return 0 + } + + /// The collection's "past the end" position---that is, the position one + /// greater than the last valid subscript argument. + public var endIndex: Self.Index { + return images.count + } + + /// Accesses the element at the specified position. + public subscript(_ ndx: Self.Index) -> Self.Element { + return Backtrace.Image(images[ndx], wordSize: wordSize) + } + + /// Look-up an image by address. + public func indexOfImage(at address: Backtrace.Address) -> Int? { + let addr = UInt64(address)! + var lo = 0, hi = images.count + while lo < hi { + let mid = (lo + hi) / 2 + if images[mid].baseAddress > addr { + hi = mid + } else if images[mid].endOfText <= addr { + lo = mid + 1 + } else { + return mid + } + } + + return nil + } + + /// Returns the position immediately after the given index. + public func index(after ndx: Self.Index) -> Self.Index { + return ndx + 1 + } + + /// Capture the image map for the current process. + public static func capture() -> ImageMap { + #if os(macOS) || os(iOS) || os(watchOS) || os(tvOS) + return capture(for: mach_task_self()) + #else + return capture(using: UnsafeLocalMemoryReader()) + #endif + } +} + +extension ImageMap: CustomStringConvertible { + /// Generate a description of an ImageMap + public var description: String { + var lines: [String] = ["Platform: \(platform)", ""] + let addressWidth: Int + switch wordSize { + case .sixteenBit: addressWidth = 4 + case .thirtyTwoBit: addressWidth = 8 + case .sixtyFourBit: addressWidth = 16 + } + + for image in images { + let hexBase = hex(image.baseAddress, width: addressWidth) + let hexEnd = hex(image.endOfText, width: addressWidth) + let buildId: String + if let bytes = image.uniqueID { + buildId = hex(bytes) + } else { + buildId = "" + } + let path = image.path ?? "" + let name = image.name ?? "" + + lines.append("\(hexBase)-\(hexEnd) \(buildId) \(name) \(path)") + } + + return lines.joined(separator: "\n") + } +} + +extension Backtrace.Image { + /// Convert an ImageMap.Image to a Backtrace.Image. + /// + /// Backtrace.Image is the public, user-visible type; ImageMap.Image + /// is an in-memory representation. + init(_ image: ImageMap.Image, wordSize: ImageMap.WordSize) { + let baseAddress: Backtrace.Address + let endOfText: Backtrace.Address + + switch wordSize { + case .sixteenBit: + baseAddress = Backtrace.Address( + UInt16(truncatingIfNeeded: image.baseAddress) + ) + endOfText = Backtrace.Address( + UInt16(truncatingIfNeeded: image.endOfText) + ) + case .thirtyTwoBit: + baseAddress = Backtrace.Address( + UInt32(truncatingIfNeeded: image.baseAddress) + ) + endOfText = Backtrace.Address( + UInt32(truncatingIfNeeded: image.endOfText) + ) + case .sixtyFourBit: + baseAddress = Backtrace.Address(image.baseAddress) + endOfText = Backtrace.Address(image.endOfText) + } + + self.init(name: image.name, + path: image.path, + uniqueID: image.uniqueID, + baseAddress: baseAddress, + endOfText: endOfText) + } +} + +extension ImageMap: Codable { + + public func encode(to encoder: any Encoder) throws { + var container = encoder.singleValueContainer() + let cimfEncoder = CompactImageMapFormat.Encoder(self) + let base64 = stringFrom(sequence: Base64Encoder(source: cimfEncoder)) + try container.encode(base64) + } + + public init(from decoder: any Decoder) throws { + let container = try decoder.singleValueContainer() + let base64 = try container.decode(String.self) + self.init(compactImageMapData: Base64Decoder(source: base64.utf8))! + } + +} diff --git a/stdlib/public/RuntimeModule/ImageSource.swift b/stdlib/public/RuntimeModule/ImageSource.swift new file mode 100644 index 0000000000000..9cd4da434969d --- /dev/null +++ b/stdlib/public/RuntimeModule/ImageSource.swift @@ -0,0 +1,436 @@ +//===--- ImageSource.swift - A place from which to read image data --------===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2024 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 +// +//===----------------------------------------------------------------------===// +// +// Defines ImageSource, which tells us where to look for image data. +// +//===----------------------------------------------------------------------===// + +import Swift + +#if os(macOS) || os(iOS) || os(tvOS) || os(watchOS) +internal import Darwin +#elseif os(Windows) +internal import ucrt +#elseif canImport(Glibc) +internal import Glibc +#elseif canImport(Musl) +internal import Musl +#endif + +enum ImageSourceError: Error { + case outOfBoundsRead + case posixError(Int32) +} + +struct ImageSource { + + private class Storage { + /// Says how we allocated the buffer. + private enum MemoryBufferKind { + /// Currently empty + case empty + + /// Allocated with UnsafeRawBufferPointer.allocate() + case allocated(Int) + + /// Allocated by mapping memory with mmap() or similar + case mapped + + /// A reference to a subordinate storage + case substorage(Storage) + + /// Not allocated (probably points to a loaded image) + case unowned + } + + private var kind: MemoryBufferKind + + /// The pointer to the actual memory + private(set) var bytes: UnsafeRawBufferPointer! + + /// Gets a mutable pointer to the actual memory + var mutableBytes: UnsafeMutableRawBufferPointer { + guard case let .allocated(count) = kind else { + fatalError("attempted to get mutable reference to immutable ImageSource") + } + return UnsafeMutableRawBufferPointer( + mutating: UnsafeRawBufferPointer(rebasing: bytes[0..= count { + fatalError("ImageSource access out of range") + } + } + + init() { + self.kind = .empty + self.bytes = nil + } + + init(unowned buffer: UnsafeRawBufferPointer) { + self.kind = .unowned + self.bytes = buffer + } + + init(mapped buffer: UnsafeRawBufferPointer) { + self.kind = .mapped + self.bytes = buffer + } + + init(allocated buffer: UnsafeMutableRawBufferPointer, count: Int? = nil) { + self.kind = .allocated(count ?? buffer.count) + self.bytes = UnsafeRawBufferPointer(buffer) + } + + convenience init(capacity: Int, alignment: Int = 0x4000) { + self.init(allocated: UnsafeMutableRawBufferPointer.allocate( + byteCount: capacity, + alignment: 0x1000 + ), + count: 0) + } + + init(parent: Storage, range: Range) { + let chunk = UnsafeRawBufferPointer(rebasing: parent.bytes[range]) + + self.kind = .substorage(parent) + self.bytes = chunk + } + + convenience init(path: String) throws { + let fd = open(path, O_RDONLY, 0) + if fd < 0 { + throw ImageSourceError.posixError(errno) + } + defer { close(fd) } + let size = lseek(fd, 0, SEEK_END) + if size < 0 { + throw ImageSourceError.posixError(errno) + } + let base = mmap(nil, Int(size), PROT_READ, MAP_FILE|MAP_PRIVATE, fd, 0) + if base == nil || base! == UnsafeRawPointer(bitPattern: -1)! { + throw ImageSourceError.posixError(errno) + } + + self.init(mapped: UnsafeRawBufferPointer( + start: base, count: Int(size))) + } + + deinit { + switch kind { + case .allocated: + mutableBytes.deallocate() + case .mapped: + munmap(UnsafeMutableRawPointer(mutating: bytes.baseAddress), + bytes.count) + case .substorage, .unowned, .empty: + break + } + } + + /// Subscripting (read-only, for subranges) + subscript(range: Range) -> Storage { + return Storage(parent: self, range: range) + } + + /// Resize the buffer; only supported for allocated or empty storage + func resize(newSize: Int) -> UnsafeMutableRawBufferPointer { + let newBuffer = UnsafeMutableRawBufferPointer.allocate( + byteCount: newSize, + alignment: 0x1000 + ) + switch kind { + case .empty: + kind = .allocated(0) + case let .allocated(count): + assert(newSize >= count) + + let oldPart = UnsafeMutableRawBufferPointer( + rebasing: newBuffer[0.. UnsafeMutableRawBufferPointer { + let capacity: Int + switch kind { + case .empty: + capacity = 0 + case .allocated: + capacity = bytes.count + default: + fatalError("Cannot resize immutable image source storage") + } + + if capacity >= byteCount { + return mutableBytes + } + + let extra = byteCount - capacity + + let increment: Int + if capacity < 1048576 { + let roundedExtra = (extra + 0xffff) & ~0xffff + increment = max(roundedExtra, capacity) + } else { + let roundedExtra = (extra + 0xfffff) & ~0xfffff + let topBit = capacity.bitWidth - capacity.leadingZeroBitCount + increment = max(roundedExtra, 1048576 * (topBit - 20)) + } + + return resize(newSize: capacity + increment) + } + + /// Mark a number of bytes in the mutable buffer as in use. This is + /// used when passing `unusedBytes` to some other code that fills in + /// part of the buffer. + func used(bytes: Int) { + guard bytes >= 0 else { + fatalError("Bytes should not be less than zero") + } + guard case let .allocated(count) = kind else { + fatalError("Cannot append to immutable image source storage") + } + guard mutableBytes.count - count <= bytes else { + fatalError("Buffer overrun detected") + } + kind = .allocated(count + bytes) + } + + /// Append bytes to the mutable buffer; this is only supported for + /// allocated or empty storage. + func append(bytes toAppend: UnsafeRawBufferPointer) { + // Short circuit, otherwise we get in a muddle in requireAtLeast() + if toAppend.count == 0 { + return + } + + let newCount = count + toAppend.count + + let mutableBytes = requireAtLeast(byteCount: newCount) + + guard case let .allocated(count) = kind else { + fatalError("Cannot append to immutable image source storage") + } + + let dest = UnsafeMutableRawBufferPointer( + rebasing: mutableBytes[count..) -> ImageSource { + let intRange = Int(range.lowerBound)..= buffer.count && + offset <= bytes.count - buffer.count else { + throw ImageSourceError.outOfBoundsRead + } + buffer.copyMemory(from: UnsafeRawBufferPointer( + rebasing: bytes[offset..(from address: Address, as type: T.Type) throws -> T { + let size = MemoryLayout.size + let offset = Int(address) + guard offset <= bytes.count - size else { + throw ImageSourceError.outOfBoundsRead + } + return bytes.loadUnaligned(fromByteOffset: offset, as: type) + } + + public func fetchString(from address: Address) throws -> String? { + let offset = Int(address) + let len = strnlen(bytes.baseAddress! + offset, bytes.count - offset) + let stringBytes = bytes[offset.. String? { + let offset = Int(address) + let stringBytes = bytes[offset..(into buffer: UnsafeMutableBufferPointer) throws { + try source.fetch(from: pos, into: buffer) + pos += Size(MemoryLayout.stride * buffer.count) + } + + mutating func read(into pointer: UnsafeMutablePointer) throws { + try source.fetch(from: pos, into: pointer) + pos += Size(MemoryLayout.stride) + } + + mutating func read(as type: T.Type) throws -> T { + let result = try source.fetch(from: pos, as: type) + pos += Size(MemoryLayout.stride) + return result + } + + mutating func read(count: Int, as type: T.Type) throws -> [T] { + let result = try source.fetch(from: pos, count: count, as: type) + pos += Size(MemoryLayout.stride * count) + return result + } + + mutating func readString() throws -> String? { + guard let result = try source.fetchString(from: pos) else { + return nil + } + pos += Size(result.utf8.count + 1) // +1 for the NUL + return result + } + + mutating func readString(length: Int) throws -> String? { + guard let result = try source.fetchString(from: pos, length: length) else { + return nil + } + pos += Size(length) + return result + } +} diff --git a/stdlib/public/Backtracing/Libc.swift b/stdlib/public/RuntimeModule/Libc.swift similarity index 100% rename from stdlib/public/Backtracing/Libc.swift rename to stdlib/public/RuntimeModule/Libc.swift diff --git a/stdlib/public/RuntimeModule/LimitSequence.swift b/stdlib/public/RuntimeModule/LimitSequence.swift new file mode 100644 index 0000000000000..0b608dc320fcb --- /dev/null +++ b/stdlib/public/RuntimeModule/LimitSequence.swift @@ -0,0 +1,237 @@ +//===--- LimitSequence.swift ----------------------------------*- swift -*-===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2024 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 +// +//===----------------------------------------------------------------------===// +// +// Defines a sequence adapter that implements the ability to limit the +// number of items in its output in various ways. +// +//===----------------------------------------------------------------------===// + +import Swift + +/// Sequences you wish to use with `LimitSequence` must use an element type +/// that implements this protocol, so that `LimitSequence` can indicate when +/// it omits or truncates the sequence. +@usableFromInline +protocol LimitableElement { + static func omitted(_: Int) -> Self + static var truncated: Self { get } +} + +/// A `Sequence` that adds the ability to limit the output of another sequence. +@usableFromInline +struct LimitSequence: Sequence + where S.Element == T +{ + /// The element type, which must conform to `LimitableElement` + @usableFromInline + typealias Element = T + + /// The source sequence + @usableFromInline + typealias Source = S + + var source: Source + + /// The maximum number of items that we want in the output of this sequence. + /// This includes `.omitted()` and `.truncated` items. + var limit: Int + + /// The number of items to drop from the head of the sequence. + var offset: Int + + /// The minimum number of items to capture at the tail end of the input + /// sequence. This can be _at most_ `limit - 1`. + var top: Int + + /// Initialise the `LimitSequence` + /// + /// - source: The sequence to draw items from. + /// - limit: The maximum number of items of output we desire. + /// - offset: The number of items to drop from the head of the input sequence. + /// - top: The minimum number of items to capture at the tail end of the + /// input sequence. + /// + /// A `LimitSequence` will read from `source` and emit at most `limit` items, + /// after discarding the first `offset` items from `source`, including a + /// minimum of `top` items. + /// + /// When `LimitSequence` omits items or truncates the sequence, it will + /// insert `.omitted(count)` or `.truncated` items into its output. + @usableFromInline + init(_ source: Source, limit: Int, offset: Int = 0, top: Int = 0) { + self.source = source + self.limit = limit + self.offset = offset + self.top = top + } + + /// Create an iterator for this sequence. + public func makeIterator() -> Iterator { + return Iterator(source.makeIterator(), limit: limit, offset: offset, top: top) + } + + /// The `LimitSequence` Iterator implementation. + /// + /// This works by buffering an element ahead of where we are in the input + /// sequence, so that it can tell whether or not there is more input to + /// follow at any given point. + @usableFromInline + struct Iterator: IteratorProtocol { + /// The iterator for the input sequence. + var iterator: Source.Iterator + + /// We read one element ahead in the input sequence; that element is + /// stored here. + var readAhead: Element? + + /// Tracks the number of items emitted before getting to `top`. + var count = 0 + + /// The maximum number of items to emit, including the `.truncated` + /// or `.omitted()` markers. + var limit: Int + + /// The minimum number of items to capture from the tail of the input + /// sequence. Must be strictly less than `limit`. + var top: Int + + /// A ring buffer that we use to capture the tail. + var topBuffer: [Element] + + /// Points at the first item in `topBuffer`. + var topBase: Int + + /// The index in `topBuffer` that we should output from the next + /// call to `next()`. + var topNdx: Int + + /// Tracks the iterator state. + var state: State + + enum State { + case normal + case outputTop + case done + } + + /// Fill `readAhead` with the next element from the input sequence. + private mutating func readNext() { + if let elt = self.iterator.next() { + readAhead = elt + } else { + readAhead = nil + } + } + + /// Initialise the iterator, and fill in the first read ahead element. + init(_ iterator: Source.Iterator, limit: Int, offset: Int, top: Int) { + self.iterator = iterator + + for _ in 0.. Element? { + switch state { + case .done: + return nil + case .outputTop: + let result = topBuffer[topNdx] + topNdx += 1 + if topNdx == top { + topNdx = 0 + } + if topNdx == topBase { + state = .done + } + return result + case .normal: + break + } + + guard let element = readAhead else { + state = .done + return nil + } + + readNext() + + // Capture the easy part + if count < limit - top - 1 { + count += 1 + return element + } + + if top == 0 && readAhead != nil { + state = .done + return .truncated + } + + let beforeTop = element + + // Fill the top buffer + while let elt = readAhead, topBuffer.count < top{ + topBuffer.append(elt) + + readNext() + } + + if readAhead == nil { + // No elements means we just output beforeTop and we're done + if topBuffer.count == 0 { + state = .done + return beforeTop + } + + // Otherwise, output beforeTop and then the top buffer + topNdx = 0 + if topBuffer.count < top { + topBase = topBuffer.count + } + state = .outputTop + return beforeTop + } + + // Use the top buffer as a circular buffer + var omitted = 1 + while let elt = readAhead { + topBuffer[topBase] = elt + topBase += 1 + omitted += 1 + if topBase == top { + topBase = 0 + } + + readNext() + } + + topNdx = topBase + state = .outputTop + return .omitted(omitted) + } + } +} diff --git a/stdlib/public/Backtracing/MemoryReader.swift b/stdlib/public/RuntimeModule/MemoryReader.swift similarity index 87% rename from stdlib/public/Backtracing/MemoryReader.swift rename to stdlib/public/RuntimeModule/MemoryReader.swift index 6df5073fa93aa..3dcbec58e50f0 100644 --- a/stdlib/public/Backtracing/MemoryReader.swift +++ b/stdlib/public/RuntimeModule/MemoryReader.swift @@ -57,6 +57,9 @@ internal import BacktracingImpl.OS.Darwin /// Fetch a NUL terminated string from the specified location in the source func fetchString(from addr: Address) throws -> String? + + /// Fetch a fixed-length string from the specified location in the source + func fetchString(from addr: Address, length: Int) throws -> String? } extension MemoryReader { @@ -106,6 +109,10 @@ extension MemoryReader { return String(decoding: bytes, as: UTF8.self) } + public func fetchString(from addr: Address, length: Int) throws -> String? { + let bytes = try fetch(from: addr, count: length, as: UInt8.self) + return String(decoding: bytes, as: UTF8.self) + } } @_spi(MemoryReaders) public struct UnsafeLocalMemoryReader: MemoryReader { @@ -118,6 +125,16 @@ extension MemoryReader { byteCount: buffer.count ) } + + public func fetch(from address: Address, as type: T.Type) throws -> T { + let ptr = UnsafeRawPointer(bitPattern: UInt(address))! + return ptr.loadUnaligned(fromByteOffset: 0, as: type) + } + + public func fetchString(from address: Address) throws -> String? { + let ptr = UnsafeRawPointer(bitPattern: UInt(address))! + return String(validatingUTF8: ptr.assumingMemoryBound(to: CChar.self)) + } } #if os(macOS) @@ -125,7 +142,8 @@ extension MemoryReader { var result: kern_return_t } -@_spi(MemoryReaders) public struct RemoteMemoryReader: MemoryReader { +@_spi(MemoryReaders) +public struct UncachedRemoteMemoryReader: MemoryReader { private var task: task_t // Sadly we can't expose the type of this argument @@ -151,13 +169,14 @@ extension MemoryReader { } } -@_spi(MemoryReaders) public struct LocalMemoryReader: MemoryReader { +@_spi(MemoryReaders) +public struct UncachedLocalMemoryReader: MemoryReader { public typealias Address = UInt64 public typealias Size = UInt64 public func fetch(from address: Address, into buffer: UnsafeMutableRawBufferPointer) throws { - let reader = RemoteMemoryReader(task: mach_task_self()) + let reader = UncachedRemoteMemoryReader(task: mach_task_self()) return try reader.fetch(from: address, into: buffer) } } @@ -172,7 +191,8 @@ extension MemoryReader { var message: String } -@_spi(MemoryReaders) public struct MemserverMemoryReader: MemoryReader { +@_spi(MemoryReaders) +public struct UncachedMemserverMemoryReader: MemoryReader { private var fd: CInt public init(fd: CInt) { @@ -267,7 +287,8 @@ extension MemoryReader { } } -@_spi(MemoryReaders) public struct RemoteMemoryReader: MemoryReader { +@_spi(MemoryReaders) +public struct UncachedRemoteMemoryReader: MemoryReader { private var pid: pid_t public init(pid: Any) { @@ -288,7 +309,8 @@ extension MemoryReader { } } -@_spi(MemoryReaders) public struct LocalMemoryReader: MemoryReader { +@_spi(MemoryReaders) +public struct UncachedLocalMemoryReader: MemoryReader { private var reader: RemoteMemoryReader init() { diff --git a/stdlib/public/RuntimeModule/OSReleaseScanner.swift b/stdlib/public/RuntimeModule/OSReleaseScanner.swift new file mode 100644 index 0000000000000..e5d1d1a76f34b --- /dev/null +++ b/stdlib/public/RuntimeModule/OSReleaseScanner.swift @@ -0,0 +1,186 @@ +//===--- OSReleaseScanner.swift --------------------------------*- swift -*-===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2023 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 +// +//===----------------------------------------------------------------------===// +// +// Defines OSReleaseScanner, which is for scanning the /etc/os-release +// file on Linux. +// +//===----------------------------------------------------------------------===// + +#if os(Linux) + +import Swift + +// Lines in /etc/os-release consist of KEY=VALUE pairs. +// +// The VALUE may be quoted with single quotes, in which case its contents +// are left alone. +// +// It may also be quoted with double quotes, in which case slash escapes +// are processed. +// +// If it is unquoted, whitespace will be stripped. + +struct OSReleaseScanner: Sequence, IteratorProtocol { + typealias SS = S.SubSequence + + private enum State { + case normal + case badLine + case comment + case key + case beforeEquals + case beforeValue + case value + case valueWhitespace + case singleQuote + case doubleQuote + case escape + case awaitingNewline + } + + private var asString: S + private var asUTF8: S.UTF8View + private var pos: S.UTF8View.Index + private var state: State + + init(_ string: S) { + asString = string + asUTF8 = string.utf8 + pos = asUTF8.startIndex + state = .normal + } + + mutating func next() -> (String, String)? { + var chunkStart = pos + var whitespaceStart = pos + var key: String = "" + var quotedValue: String = "" + + while pos < asUTF8.endIndex { + let ch = asUTF8[pos] + switch state { + case .normal: + if ch == 32 || ch == 9 || ch == 13 || ch == 10 { + break + } + if ch == UInt8(ascii: "#") { + state = .comment + break + } + chunkStart = pos + state = .key + case .badLine, .comment, .awaitingNewline: + if ch == 13 || ch == 10 { + state = .normal + } + case .key: + if ch == 32 || ch == 9 { + key = String(asString[chunkStart..: CustomStringConvertible, Equatable { + public typealias Address = T + + /// A program counter value. + /// + /// This might come from a signal handler, or an exception or some + /// other situation in which we have captured the actual program counter. + /// + /// These can be directly symbolicated, as-is, with no adjustment. + case programCounter(Address) + + /// A return address. + /// + /// Corresponds to a normal function call. + /// + /// Requires adjustment when symbolicating for a backtrace, because it + /// points at the address after the one that triggered the child frame. + case returnAddress(Address) + + /// An async resume point. + /// + /// Corresponds to an `await` in an async task. + /// + /// Can be directly symbolicated, as-is. + case asyncResumePoint(Address) + + /// Indicates a discontinuity in the backtrace. + /// + /// This occurs when you set a limit and a minimum number of frames at + /// the top. For example, if you set a limit of 10 frames and a minimum + /// of 4 top frames, but the backtrace generated 100 frames, you will see + /// + /// 0: frame 100 <----- bottom of call stack + /// 1: frame 99 + /// 2: frame 98 + /// 3: frame 97 + /// 4: frame 96 + /// 5: ... <----- omittedFrames(92) + /// 6: frame 3 + /// 7: frame 2 + /// 8: frame 1 + /// 9: frame 0 <----- top of call stack + /// + /// Note that the limit *includes* the discontinuity. + /// + /// This is good for handling cases involving deep recursion. + case omittedFrames(Int) + + /// Indicates a discontinuity of unknown length. + /// + /// This can only be present at the end of a backtrace; in other cases + /// we will know how many frames we have omitted. For instance, + /// + /// 0: frame 100 <----- bottom of call stack + /// 1: frame 99 + /// 2: frame 98 + /// 3: frame 97 + /// 4: frame 96 + /// 5: ... <----- truncated + case truncated + + /// The program counter, without any adjustment. + public var originalProgramCounter: Address { + switch self { + case let .returnAddress(addr): + return addr + case let .programCounter(addr): + return addr + case let .asyncResumePoint(addr): + return addr + case .omittedFrames, .truncated: + return 0 + } + } + + /// The adjusted program counter to use for symbolication. + public var adjustedProgramCounter: Address { + switch self { + case let .returnAddress(addr): + return addr - 1 + case let .programCounter(addr): + return addr + case let .asyncResumePoint(addr): + return addr + case .omittedFrames, .truncated: + return 0 + } + } + + /// A textual description of this frame. + public var description: String { + switch self { + case let .programCounter(addr): + return "\(hex(addr))" + case let .returnAddress(addr): + return "\(hex(addr)) [ra]" + case let .asyncResumePoint(addr): + return "\(hex(addr)) [async]" + case .omittedFrames, .truncated: + return "..." + } + } +} + +extension RichFrame: LimitableElement { + // LimitableElement wants to call this "omitted" + public static func omitted(_ count: Int) -> Self { + return .omittedFrames(count) + } +} + +extension Backtrace.Frame { + init(_ frame: RichFrame) { + switch frame { + case let .returnAddress(addr): + self = .returnAddress(Backtrace.Address(addr)!) + case let .programCounter(addr): + self = .programCounter(Backtrace.Address(addr)!) + case let .asyncResumePoint(addr): + self = .asyncResumePoint(Backtrace.Address(addr)!) + case let .omittedFrames(count): + self = .omittedFrames(count) + case .truncated: + self = .truncated + } + } +} diff --git a/stdlib/public/Backtracing/Runtime.swift b/stdlib/public/RuntimeModule/Runtime.swift similarity index 100% rename from stdlib/public/Backtracing/Runtime.swift rename to stdlib/public/RuntimeModule/Runtime.swift diff --git a/stdlib/public/Backtracing/SymbolicatedBacktrace.swift b/stdlib/public/RuntimeModule/SymbolicatedBacktrace.swift similarity index 71% rename from stdlib/public/Backtracing/SymbolicatedBacktrace.swift rename to stdlib/public/RuntimeModule/SymbolicatedBacktrace.swift index 0e194bc949824..214231cdc284f 100644 --- a/stdlib/public/Backtracing/SymbolicatedBacktrace.swift +++ b/stdlib/public/RuntimeModule/SymbolicatedBacktrace.swift @@ -92,20 +92,15 @@ public struct SymbolicatedBacktrace: CustomStringConvertible { } /// A textual description of this frame. - public func description(width: Int) -> String { + public var description: String { if let symbol = symbol { let isInlined = inlined ? " [inlined]" : "" let isThunk = isSwiftThunk ? " [thunk]" : "" - return "\(captured.description(width: width))\(isInlined)\(isThunk) \(symbol)" + return "\(captured.description)\(isInlined)\(isThunk) \(symbol)" } else { - return captured.description(width: width) + return captured.description } } - - /// A textual description of this frame. - public var description: String { - return description(width: MemoryLayout.size * 2) - } } /// Represents a symbol we've located @@ -218,8 +213,8 @@ public struct SymbolicatedBacktrace: CustomStringConvertible { if stringLen > 0 { return demangled.withMemoryRebound(to: UInt8.self, capacity: stringLen) { - let demangledBytes = UnsafeBufferPointer(start: $0, - count: stringLen) + let demangledBytes = UnsafeBufferPointer(start: $0, + count: stringLen) return String(decoding: demangledBytes, as: UTF8.self) } } @@ -250,19 +245,14 @@ public struct SymbolicatedBacktrace: CustomStringConvertible { } } - /// The width, in bits, of an address in this backtrace. - public var addressWidth: Int { - return backtrace.addressWidth - } + /// The architecture on which this backtrace was captured. + public var architecture: String { return backtrace.architecture } /// A list of captured frame information. - public var frames: [Frame] + public private(set) var frames: [Frame] /// A list of images found in the process. - public var images: [Backtrace.Image] - - /// Shared cache information. - public var sharedCacheInfo: Backtrace.SharedCacheInfo? + public private(set) var images: ImageMap /// True if this backtrace is a Swift runtime failure. public var isSwiftRuntimeFailure: Bool { @@ -283,12 +273,9 @@ public struct SymbolicatedBacktrace: CustomStringConvertible { } /// Construct a SymbolicatedBacktrace from a backtrace and a list of images. - private init(backtrace: Backtrace, images: [Backtrace.Image], - sharedCacheInfo: Backtrace.SharedCacheInfo?, - frames: [Frame]) { + private init(backtrace: Backtrace, images: ImageMap, frames: [Frame]) { self.backtrace = backtrace self.images = images - self.sharedCacheInfo = sharedCacheInfo self.frames = frames } @@ -306,21 +293,20 @@ public struct SymbolicatedBacktrace: CustomStringConvertible { } /// Create a symbolicator. - private static func withSymbolicator(images: [Backtrace.Image], - sharedCacheInfo: Backtrace.SharedCacheInfo?, + private static func withSymbolicator(images: ImageMap, useSymbolCache: Bool, fn: (CSSymbolicatorRef) throws -> T) rethrows -> T { let binaryImageList = images.map{ image in BinaryImageInformation( - base: vm_address_t(image.baseAddress), - extent: vm_address_t(image.endOfText), - uuid: uuidBytesFromBuildID(image.buildID!), + base: vm_address_t(image.baseAddress)!, + extent: vm_address_t(image.endOfText)!, + uuid: uuidBytesFromBuildID(image.uniqueID!), arch: HostContext.coreSymbolicationArchitecture, - path: image.path, + path: image.path ?? "", relocations: [ BinaryRelocationInformation( - base: vm_address_t(image.baseAddress), - extent: vm_address_t(image.endOfText), + base: vm_address_t(image.baseAddress)!, + extent: vm_address_t(image.endOfText)!, name: "__TEXT" ) ], @@ -345,7 +331,7 @@ public struct SymbolicatedBacktrace: CustomStringConvertible { isInline: Bool, symbol: CSSymbolRef, sourceInfo: CSSourceInfoRef?, - images: [Backtrace.Image]) -> Frame { + images: ImageMap) -> Frame { if CSIsNull(symbol) { return Frame(captured: capturedFrame, symbol: nil) } @@ -375,9 +361,9 @@ public struct SymbolicatedBacktrace: CustomStringConvertible { var imageIndex = -1 var imageName = "" for (ndx, image) in images.enumerated() { - if image.baseAddress == imageBase { + if vm_address_t(image.baseAddress) == imageBase { imageIndex = ndx - imageName = image.name + imageName = image.name ?? "" break } } @@ -385,7 +371,7 @@ public struct SymbolicatedBacktrace: CustomStringConvertible { let theSymbol = Symbol(imageIndex: imageIndex, imageName: imageName, rawName: rawName, - offset: Int(address - UInt64(range.location)), + offset: Int(UInt64(address)! - UInt64(range.location)), sourceLocation: location) theSymbol.name = name @@ -395,43 +381,31 @@ public struct SymbolicatedBacktrace: CustomStringConvertible { /// Actually symbolicate. internal static func symbolicate(backtrace: Backtrace, - images: [Backtrace.Image]?, - sharedCacheInfo: Backtrace.SharedCacheInfo?, - showInlineFrames: Bool, - showSourceLocations: Bool, - useSymbolCache: Bool) + images: ImageMap?, + options: Backtrace.SymbolicationOptions) -> SymbolicatedBacktrace? { - let theImages: [Backtrace.Image] + let theImages: ImageMap if let images = images { theImages = images } else if let images = backtrace.images { theImages = images } else { - theImages = Backtrace.captureImages() - } - - let theCacheInfo: Backtrace.SharedCacheInfo? - if let sharedCacheInfo = sharedCacheInfo { - theCacheInfo = sharedCacheInfo - } else if let sharedCacheInfo = backtrace.sharedCacheInfo { - theCacheInfo = sharedCacheInfo - } else { - theCacheInfo = Backtrace.captureSharedCacheInfo() + theImages = ImageMap.capture() } var frames: [Frame] = [] #if os(macOS) || os(iOS) || os(watchOS) || os(tvOS) withSymbolicator(images: theImages, - sharedCacheInfo: theCacheInfo, - useSymbolCache: useSymbolCache) { symbolicator in + useSymbolCache: options.contains(.useSymbolCache)) { + symbolicator in for frame in backtrace.frames { switch frame { case .omittedFrames(_), .truncated: frames.append(Frame(captured: frame, symbol: nil)) default: - let address = vm_address_t(frame.adjustedProgramCounter) + let address = vm_address_t(frame.adjustedProgramCounter)! let owner = CSSymbolicatorGetSymbolOwnerWithAddressAtTime(symbolicator, address, @@ -439,7 +413,7 @@ public struct SymbolicatedBacktrace: CustomStringConvertible { if CSIsNull(owner) { frames.append(Frame(captured: frame, symbol: nil)) - } else if showInlineFrames { + } else if options.contains(.showInlineFrames) { // These present in *reverse* order (i.e. the real one first, // then the inlined frames from callee to caller). let pos = frames.count @@ -458,7 +432,7 @@ public struct SymbolicatedBacktrace: CustomStringConvertible { first = false } - } else if showSourceLocations { + } else if options.contains(.showSourceLocations) { let symbol = CSSymbolOwnerGetSymbolWithAddress(owner, address) let sourceInfo = CSSymbolOwnerGetSourceInfoWithAddress(owner, address) @@ -483,84 +457,53 @@ public struct SymbolicatedBacktrace: CustomStringConvertible { } } #elseif os(Linux) - var elf32Cache: [Int:Elf32Image] = [:] - var elf64Cache: [Int:Elf64Image] = [:] + let cache = ElfImageCache.threadLocal // This could be more efficient; at the moment we execute the line // number programs once per frame, whereas we could just run them once // for all the addresses we're interested in. for frame in backtrace.frames { - let address = FileImageSource.Address(frame.adjustedProgramCounter) - if let imageNdx = theImages.firstIndex( - where: { address >= $0.baseAddress - && address < $0.endOfText } - ) { - let relativeAddress = address - FileImageSource.Address(theImages[imageNdx].baseAddress) + let address = frame.adjustedProgramCounter + if let imageNdx = theImages.indexOfImage(at: address) { + let relativeAddress = ImageSource.Address( + address - theImages[imageNdx].baseAddress + ) + let name = theImages[imageNdx].name ?? "" var symbol: Symbol = Symbol(imageIndex: imageNdx, - imageName: theImages[imageNdx].name, + imageName: name, rawName: "", offset: 0, sourceLocation: nil) - var elf32Image = elf32Cache[imageNdx] - var elf64Image = elf64Cache[imageNdx] - - if elf32Image == nil && elf64Image == nil { - if let source = try? FileImageSource(path: theImages[imageNdx].path) { - if let elfImage = try? Elf32Image(source: source) { - elf32Image = elfImage - elf32Cache[imageNdx] = elfImage - } else if let elfImage = try? Elf64Image(source: source) { - elf64Image = elfImage - elf64Cache[imageNdx] = elfImage - } - } - } - if let theSymbol = elf32Image?.lookupSymbol(address: relativeAddress) { - var location: SourceLocation? + func lookupSymbol( + image: ElfImage?, + at imageNdx: Int, + named name: String, + address imageAddr: ImageSource.Address + ) -> Symbol? { + let address = ElfImage.Traits.Address(imageAddr) - if showSourceLocations || showInlineFrames { - location = try? elf32Image!.sourceLocation(for: relativeAddress) - } else { - location = nil + guard let image = image else { + return nil } - - if showInlineFrames { - for inline in elf32Image!.inlineCallSites(at: relativeAddress) { - let fakeSymbol = Symbol(imageIndex: imageNdx, - imageName: theImages[imageNdx].name, - rawName: inline.rawName ?? "", - offset: 0, - sourceLocation: location) - frames.append(Frame(captured: frame, - symbol: fakeSymbol, - inlined: true)) - - location = SourceLocation(path: inline.filename, - line: inline.line, - column: inline.column) - } + guard let theSymbol = image.lookupSymbol(address: address) else { + return nil } - symbol = Symbol(imageIndex: imageNdx, - imageName: theImages[imageNdx].name, - rawName: theSymbol.name, - offset: theSymbol.offset, - sourceLocation: location) - } else if let theSymbol = elf64Image?.lookupSymbol(address: relativeAddress) { var location: SourceLocation? - if showSourceLocations || showInlineFrames { - location = try? elf64Image!.sourceLocation(for: relativeAddress) + if options.contains(.showSourceLocations) + || options.contains(.showInlineFrames) { + location = try? image.sourceLocation(for: address) } else { location = nil } - if showInlineFrames { - for inline in elf64Image!.inlineCallSites(at: relativeAddress) { + if options.contains(.showInlineFrames) { + for inline in image.inlineCallSites(at: address) { let fakeSymbol = Symbol(imageIndex: imageNdx, - imageName: theImages[imageNdx].name, + imageName: name, rawName: inline.rawName ?? "", offset: 0, sourceLocation: location) @@ -574,17 +517,30 @@ public struct SymbolicatedBacktrace: CustomStringConvertible { } } - symbol = Symbol(imageIndex: imageNdx, - imageName: theImages[imageNdx].name, - rawName: theSymbol.name, - offset: theSymbol.offset, - sourceLocation: location) - } else { - symbol = Symbol(imageIndex: imageNdx, - imageName: theImages[imageNdx].name, - rawName: "", - offset: 0, - sourceLocation: nil) + return Symbol(imageIndex: imageNdx, + imageName: name, + rawName: theSymbol.name, + offset: theSymbol.offset, + sourceLocation: location) + } + + if let hit = cache.lookup(path: theImages[imageNdx].path) { + switch hit { + case let .elf32Image(image): + if let theSymbol = lookupSymbol(image: image, + at: imageNdx, + named: name, + address: relativeAddress) { + symbol = theSymbol + } + case let .elf64Image(image): + if let theSymbol = lookupSymbol(image: image, + at: imageNdx, + named: name, + address: relativeAddress) { + symbol = theSymbol + } + } } frames.append(Frame(captured: frame, symbol: symbol)) @@ -599,18 +555,16 @@ public struct SymbolicatedBacktrace: CustomStringConvertible { return SymbolicatedBacktrace(backtrace: backtrace, images: theImages, - sharedCacheInfo: theCacheInfo, frames: frames) } /// Provide a textual version of the backtrace. public var description: String { var lines: [String] = [] - let addressChars = (backtrace.addressWidth + 3) / 4 var n = 0 for frame in frames { - lines.append("\(n)\t\(frame.description(width: addressChars))") + lines.append("\(n)\t\(frame.description)") switch frame.captured { case let .omittedFrames(count): n += count @@ -623,16 +577,7 @@ public struct SymbolicatedBacktrace: CustomStringConvertible { lines.append("Images:") lines.append("") for (n, image) in images.enumerated() { - lines.append("\(n)\t\(image.description(width: addressChars))") - } - - if let sharedCacheInfo = sharedCacheInfo { - lines.append("") - lines.append("Shared Cache:") - lines.append("") - lines.append(" UUID: \(hex(sharedCacheInfo.uuid))") - lines.append(" Base: \(hex(sharedCacheInfo.baseAddress, width: addressChars))") - lines.append(" Active: \(!sharedCacheInfo.noCache)") + lines.append("\(n)\t\(image.description)") } return lines.joined(separator: "\n") diff --git a/stdlib/public/Backtracing/Utils.swift b/stdlib/public/RuntimeModule/Utils.swift similarity index 76% rename from stdlib/public/Backtracing/Utils.swift rename to stdlib/public/RuntimeModule/Utils.swift index 50a2a571d9c2e..e986f2a38825d 100644 --- a/stdlib/public/Backtracing/Utils.swift +++ b/stdlib/public/RuntimeModule/Utils.swift @@ -95,3 +95,32 @@ public func stripWhitespace(_ s: S) let lastNonWhitespace = s.lastIndex(where: { !$0.isWhitespace })! return s[firstNonWhitespace...lastNonWhitespace] } + +/// Strip any Optional from a value. +/// +/// This is useful when interfacing with the system C library, because some +/// C libraries have nullability annotations while others do not. +func notOptional(_ optional: T?) -> T { + return optional! +} + +func notOptional(_ value: T) -> T { + return value +} + +/// Convert mutable pointers to non-mutable +/// +/// This is useful when interfacing with the system C library, because some +/// C libraries have const annotations in places others do not. +func notMutable(_ mutable: UnsafeMutablePointer) -> UnsafePointer { + return UnsafePointer(mutable) +} +func notMutable(_ immutable: UnsafePointer) -> UnsafePointer { + return immutable +} +func notMutable(_ mutable: UnsafeMutableRawPointer) -> UnsafeRawPointer { + return UnsafeRawPointer(mutable) +} +func notMutable(_ immutable: UnsafeRawPointer) -> UnsafeRawPointer { + return immutable +} diff --git a/stdlib/public/Backtracing/Win32Extras.cpp b/stdlib/public/RuntimeModule/Win32Extras.cpp similarity index 100% rename from stdlib/public/Backtracing/Win32Extras.cpp rename to stdlib/public/RuntimeModule/Win32Extras.cpp diff --git a/stdlib/public/Backtracing/get-cpu-context.S b/stdlib/public/RuntimeModule/get-cpu-context.S similarity index 100% rename from stdlib/public/Backtracing/get-cpu-context.S rename to stdlib/public/RuntimeModule/get-cpu-context.S diff --git a/stdlib/public/Backtracing/get-cpu-context.asm b/stdlib/public/RuntimeModule/get-cpu-context.asm similarity index 100% rename from stdlib/public/Backtracing/get-cpu-context.asm rename to stdlib/public/RuntimeModule/get-cpu-context.asm diff --git a/stdlib/public/Backtracing/modules/Compression.h b/stdlib/public/RuntimeModule/modules/Compression.h similarity index 100% rename from stdlib/public/Backtracing/modules/Compression.h rename to stdlib/public/RuntimeModule/modules/Compression.h diff --git a/stdlib/public/Backtracing/modules/FixedLayout.h b/stdlib/public/RuntimeModule/modules/FixedLayout.h similarity index 100% rename from stdlib/public/Backtracing/modules/FixedLayout.h rename to stdlib/public/RuntimeModule/modules/FixedLayout.h diff --git a/stdlib/public/Backtracing/modules/ImageFormats/Dwarf/dwarf.h b/stdlib/public/RuntimeModule/modules/ImageFormats/Dwarf/dwarf.h similarity index 100% rename from stdlib/public/Backtracing/modules/ImageFormats/Dwarf/dwarf.h rename to stdlib/public/RuntimeModule/modules/ImageFormats/Dwarf/dwarf.h diff --git a/stdlib/public/Backtracing/modules/ImageFormats/Dwarf/eh_frame_hdr.h b/stdlib/public/RuntimeModule/modules/ImageFormats/Dwarf/eh_frame_hdr.h similarity index 100% rename from stdlib/public/Backtracing/modules/ImageFormats/Dwarf/eh_frame_hdr.h rename to stdlib/public/RuntimeModule/modules/ImageFormats/Dwarf/eh_frame_hdr.h diff --git a/stdlib/public/Backtracing/modules/ImageFormats/Elf/elf.h b/stdlib/public/RuntimeModule/modules/ImageFormats/Elf/elf.h similarity index 100% rename from stdlib/public/Backtracing/modules/ImageFormats/Elf/elf.h rename to stdlib/public/RuntimeModule/modules/ImageFormats/Elf/elf.h diff --git a/stdlib/public/Backtracing/modules/ImageFormats/ImageFormats.modulemap b/stdlib/public/RuntimeModule/modules/ImageFormats/ImageFormats.modulemap similarity index 100% rename from stdlib/public/Backtracing/modules/ImageFormats/ImageFormats.modulemap rename to stdlib/public/RuntimeModule/modules/ImageFormats/ImageFormats.modulemap diff --git a/stdlib/public/Backtracing/modules/OS/Darwin.h b/stdlib/public/RuntimeModule/modules/OS/Darwin.h similarity index 100% rename from stdlib/public/Backtracing/modules/OS/Darwin.h rename to stdlib/public/RuntimeModule/modules/OS/Darwin.h diff --git a/stdlib/public/Backtracing/modules/OS/Libc.h b/stdlib/public/RuntimeModule/modules/OS/Libc.h similarity index 100% rename from stdlib/public/Backtracing/modules/OS/Libc.h rename to stdlib/public/RuntimeModule/modules/OS/Libc.h diff --git a/stdlib/public/Backtracing/modules/OS/Linux.h b/stdlib/public/RuntimeModule/modules/OS/Linux.h similarity index 100% rename from stdlib/public/Backtracing/modules/OS/Linux.h rename to stdlib/public/RuntimeModule/modules/OS/Linux.h diff --git a/stdlib/public/Backtracing/modules/OS/OS.modulemap b/stdlib/public/RuntimeModule/modules/OS/OS.modulemap similarity index 100% rename from stdlib/public/Backtracing/modules/OS/OS.modulemap rename to stdlib/public/RuntimeModule/modules/OS/OS.modulemap diff --git a/stdlib/public/Backtracing/modules/OS/Windows.h b/stdlib/public/RuntimeModule/modules/OS/Windows.h similarity index 100% rename from stdlib/public/Backtracing/modules/OS/Windows.h rename to stdlib/public/RuntimeModule/modules/OS/Windows.h diff --git a/stdlib/public/Backtracing/modules/Runtime/Runtime.h b/stdlib/public/RuntimeModule/modules/Runtime/Runtime.h similarity index 70% rename from stdlib/public/Backtracing/modules/Runtime/Runtime.h rename to stdlib/public/RuntimeModule/modules/Runtime/Runtime.h index c6e830d7ee7eb..0cda2acc68493 100644 --- a/stdlib/public/Backtracing/modules/Runtime/Runtime.h +++ b/stdlib/public/RuntimeModule/modules/Runtime/Runtime.h @@ -23,21 +23,23 @@ #include "swift/Runtime/CrashInfo.h" #ifdef __cplusplus -#define EXTERN_C extern "C" -#else -#define EXTERN_C +extern "C" { #endif // Can't import swift/Runtime/Debug.h because it assumes C++ -EXTERN_C void swift_reportWarning(uint32_t flags, const char *message); +void swift_reportWarning(uint32_t flags, const char *message); // Returns true if the given function is a thunk function -EXTERN_C bool _swift_backtrace_isThunkFunction(const char *rawName); +bool _swift_backtrace_isThunkFunction(const char *rawName); // Demangle the given raw name (supports Swift and C++) -EXTERN_C char *_swift_backtrace_demangle(const char *rawName, - size_t rawNameLength, - char *outputBuffer, - size_t *outputBufferSize); +char *_swift_backtrace_demangle(const char *rawName, + size_t rawNameLength, + char *outputBuffer, + size_t *outputBufferSize); + +#ifdef __cplusplus +} +#endif #endif // SWIFT_BACKTRACING_RUNTIME_H diff --git a/stdlib/public/Backtracing/modules/module.modulemap b/stdlib/public/RuntimeModule/modules/module.modulemap similarity index 100% rename from stdlib/public/Backtracing/modules/module.modulemap rename to stdlib/public/RuntimeModule/modules/module.modulemap diff --git a/stdlib/public/core/CMakeLists.txt b/stdlib/public/core/CMakeLists.txt index eb9547e7491dd..c706fe53f6a58 100644 --- a/stdlib/public/core/CMakeLists.txt +++ b/stdlib/public/core/CMakeLists.txt @@ -335,7 +335,7 @@ endif() list(APPEND swift_stdlib_compile_flags "-plugin-path" "${swift_lib_dir}/swift/host/plugins") set(swift_core_incorporate_object_libraries) -list(APPEND swift_core_incorporate_object_libraries swiftRuntime) +list(APPEND swift_core_incorporate_object_libraries swiftRuntimeCore) list(APPEND swift_core_incorporate_object_libraries swiftLLVMSupport) list(APPEND swift_core_incorporate_object_libraries swiftDemangling) list(APPEND swift_core_incorporate_object_libraries swiftStdlibStubs) diff --git a/stdlib/public/core/EmbeddedRuntime.swift b/stdlib/public/core/EmbeddedRuntime.swift index 187e9ab55be95..d80da94e88ec4 100644 --- a/stdlib/public/core/EmbeddedRuntime.swift +++ b/stdlib/public/core/EmbeddedRuntime.swift @@ -272,11 +272,22 @@ public func swift_dynamicCastClass(object: UnsafeMutableRawPointer, targetMetada public func swift_dynamicCastClassUnconditional(object: UnsafeMutableRawPointer, targetMetadata: UnsafeRawPointer, file: UnsafePointer, line: CUnsignedInt, column: CUnsignedInt) -> UnsafeMutableRawPointer { guard let result = swift_dynamicCastClass(object: object, targetMetadata: targetMetadata) else { - Builtin.int_trap() + fatalError("failed cast") } return result } +@_cdecl("swift_isEscapingClosureAtFileLocation") +public func swift_isEscapingClosureAtFileLocation(object: Builtin.RawPointer, filename: UnsafePointer, filenameLength: Int32, line: Int32, column: Int32, verificationType: CUnsignedInt) -> Bool { + let objectBits = UInt(Builtin.ptrtoint_Word(object)) + if objectBits == 0 { return false } + + guard swift_isUniquelyReferenced_native(object: object) else { + fatalError("non-escaping closure escaped") + } + return false +} + @_cdecl("swift_isUniquelyReferenced_native") public func swift_isUniquelyReferenced_native(object: Builtin.RawPointer) -> Bool { if !isValidPointerForNativeRetain(object: object) { return false } diff --git a/stdlib/public/libexec/swift-backtrace/CMakeLists.txt b/stdlib/public/libexec/swift-backtrace/CMakeLists.txt index 7a354cabe3c88..ed4bb13dc0fa7 100644 --- a/stdlib/public/libexec/swift-backtrace/CMakeLists.txt +++ b/stdlib/public/libexec/swift-backtrace/CMakeLists.txt @@ -12,11 +12,11 @@ if(SWIFT_BUILD_SDK_OVERLAY) set(musl Musl) endif() -# Similarly, we only want the _Backtracing dependency if we're building +# Similarly, we only want the Runtime dependency if we're building # with the stdlib. -set(backtracing) -if(SWIFT_BUILD_STDLIB AND SWIFT_ENABLE_BACKTRACING) - set(backtracing _Backtracing) +set(runtime) +if(SWIFT_BUILD_STDLIB AND SWIFT_ENABLE_RUNTIME_MODULE) + set(runtime Runtime) endif() if(NOT SWIFT_BUILD_STDLIB) @@ -25,7 +25,7 @@ endif() set(BACKTRACING_COMPILE_FLAGS "-cxx-interoperability-mode=default" - "-I${SWIFT_STDLIB_SOURCE_DIR}/public/Backtracing/modules" + "-I${SWIFT_STDLIB_SOURCE_DIR}/public/RuntimeModule/modules" "-Xcc;-I${SWIFT_SOURCE_DIR}/include" "-Xcc;-I${CMAKE_BINARY_DIR}/include" "-disable-upcoming-feature;MemberImportVisibility") @@ -51,7 +51,7 @@ endif() add_swift_target_executable(swift-backtrace BUILD_WITH_LIBEXEC ${BACKTRACING_SOURCES} - SWIFT_MODULE_DEPENDS ${backtracing} + SWIFT_MODULE_DEPENDS ${runtime} SWIFT_MODULE_DEPENDS_OSX ${darwin} SWIFT_MODULE_DEPENDS_WINDOWS ${wincrt_sdk} @@ -80,7 +80,7 @@ if(static_target_sdks) ${BACKTRACING_SOURCES} - SWIFT_MODULE_DEPENDS ${backtracing} + SWIFT_MODULE_DEPENDS ${runtime} SWIFT_MODULE_DEPENDS_OSX ${darwin} SWIFT_MODULE_DEPENDS_WINDOWS ${wincrt_sdk} diff --git a/stdlib/public/libexec/swift-backtrace/TargetLinux.swift b/stdlib/public/libexec/swift-backtrace/TargetLinux.swift index d681b724de80f..5ef68a494843c 100644 --- a/stdlib/public/libexec/swift-backtrace/TargetLinux.swift +++ b/stdlib/public/libexec/swift-backtrace/TargetLinux.swift @@ -23,11 +23,11 @@ import Glibc import Musl #endif -import _Backtracing -@_spi(Internal) import _Backtracing -@_spi(Contexts) import _Backtracing -@_spi(MemoryReaders) import _Backtracing -@_spi(Utils) import _Backtracing +import Runtime +@_spi(Internal) import Runtime +@_spi(Contexts) import Runtime +@_spi(MemoryReaders) import Runtime +@_spi(Utils) import Runtime enum SomeBacktrace { case raw(Backtrace) @@ -52,7 +52,7 @@ class Target { var faultAddress: Address var crashingThread: TargetThread.ThreadID - var images: [Backtrace.Image] = [] + var images: ImageMap var threads: [TargetThread] = [] var crashingThreadNdx: Int = -1 @@ -84,7 +84,7 @@ class Target { } } - var reader: CachingMemoryReader + var reader: MemserverMemoryReader // Get the name of a process private static func getProcessName(pid: pid_t) -> String { @@ -118,7 +118,7 @@ class Target { let memserverFd: CInt = 4 pid = getppid() - reader = CachingMemoryReader(for: MemserverMemoryReader(fd: memserverFd)) + reader = MemserverMemoryReader(fd: memserverFd) name = Self.getProcessName(pid: pid) let crashInfo: CrashInfo @@ -133,8 +133,7 @@ class Target { signal = crashInfo.signal faultAddress = crashInfo.fault_address - images = Backtrace.captureImages(using: reader, - forProcess: Int(pid)) + images = ImageMap.capture(using: reader, forProcess: Int(pid)) do { try fetchThreads(threadListHead: Address(crashInfo.thread_list), @@ -172,34 +171,34 @@ class Target { let backtrace = try Backtrace.capture(from: context, using: reader, images: images, + algorithm: .auto, limit: limit, + offset: 0, top: top) let shouldSymbolicate: Bool - let showInlineFrames: Bool - let showSourceLocations: Bool + var options: Backtrace.SymbolicationOptions switch symbolicate { case .off: shouldSymbolicate = false - showInlineFrames = false - showSourceLocations = false + options = [] case .fast: shouldSymbolicate = true - showInlineFrames = false - showSourceLocations = false + options = [ .showSourceLocations ] case .full: shouldSymbolicate = true - showInlineFrames = true - showSourceLocations = true + options = [ .showInlineFrames, .showSourceLocations ] + } + + if cache { + options.insert(.useSymbolCache) } if shouldSymbolicate { - guard let symbolicated - = backtrace.symbolicated(with: images, - sharedCacheInfo: nil, - showInlineFrames: showInlineFrames, - showSourceLocations: showSourceLocations, - useSymbolCache: cache) else { + guard let symbolicated = backtrace.symbolicated( + with: images, + options: options + ) else { print("unable to symbolicate backtrace for thread \(t.tid)") exit(1) } @@ -243,37 +242,37 @@ class Target { guard let backtrace = try? Backtrace.capture(from: context, using: reader, images: images, + algorithm: .auto, limit: limit, + offset: 0, top: top) else { print("unable to capture backtrace from context for thread \(ndx)") continue } let shouldSymbolicate: Bool - let showInlineFrames: Bool - let showSourceLocations: Bool + var options: Backtrace.SymbolicationOptions switch symbolicate { case .off: shouldSymbolicate = false - showInlineFrames = false - showSourceLocations = false + options = [] case .fast: shouldSymbolicate = true - showInlineFrames = false - showSourceLocations = false + options = [ .showSourceLocations ] case .full: shouldSymbolicate = true - showInlineFrames = true - showSourceLocations = true + options = [ .showInlineFrames, .showSourceLocations ] + } + + if cache { + options.insert(.useSymbolCache) } if shouldSymbolicate { guard let symbolicated = backtrace.symbolicated( with: images, - sharedCacheInfo: nil, - showInlineFrames: showInlineFrames, - showSourceLocations: showSourceLocations, - useSymbolCache: cache) else { + options: options + ) else { print("unable to symbolicate backtrace from context for thread \(ndx)") continue } diff --git a/stdlib/public/libexec/swift-backtrace/TargetMacOS.swift b/stdlib/public/libexec/swift-backtrace/TargetMacOS.swift index fba4f76300ce2..fe7f445a0d82c 100644 --- a/stdlib/public/libexec/swift-backtrace/TargetMacOS.swift +++ b/stdlib/public/libexec/swift-backtrace/TargetMacOS.swift @@ -20,12 +20,13 @@ import Darwin import Darwin.Mach -import _Backtracing -@_spi(Internal) import _Backtracing -@_spi(Contexts) import _Backtracing -@_spi(MemoryReaders) import _Backtracing +import Runtime +@_spi(Internal) import Runtime +@_spi(Contexts) import Runtime +@_spi(MemoryReaders) import Runtime internal import BacktracingImpl.OS.Darwin +internal import BacktracingImpl.Runtime #if arch(x86_64) typealias MContext = darwin_x86_64_mcontext @@ -69,8 +70,7 @@ class Target { var crashingThread: TargetThread.ThreadID var task: task_t - var images: [Backtrace.Image] = [] - var sharedCacheInfo: Backtrace.SharedCacheInfo? + var images: ImageMap var threads: [TargetThread] = [] var crashingThreadNdx: Int = -1 @@ -102,7 +102,7 @@ class Target { } } - var reader: CachingMemoryReader + var reader: RemoteMemoryReader var mcontext: MContext @@ -170,7 +170,7 @@ class Target { task = parentTask - reader = CachingMemoryReader(for: RemoteMemoryReader(task: task_t(task))) + reader = RemoteMemoryReader(task: task_t(task)) name = Self.getProcessName(pid: pid) @@ -194,8 +194,7 @@ class Target { mcontext = mctx - images = Backtrace.captureImages(for: task) - sharedCacheInfo = Backtrace.captureSharedCacheInfo(for: task) + images = ImageMap.capture(for: task) fetchThreads(limit: limit, top: top, cache: cache, symbolicate: symbolicate) } @@ -269,7 +268,9 @@ class Target { guard let backtrace = try? Backtrace.capture(from: ctx, using: reader, images: nil, + algorithm: .auto, limit: limit, + offset: 0, top: top) else { print("swift-backtrace: unable to capture backtrace from context for thread \(ndx)", to: &standardError) @@ -277,30 +278,28 @@ class Target { } let shouldSymbolicate: Bool - let showInlineFrames: Bool - let showSourceLocations: Bool + var options: Backtrace.SymbolicationOptions switch symbolicate { case .off: shouldSymbolicate = false - showInlineFrames = false - showSourceLocations = false + options = [] case .fast: shouldSymbolicate = true - showInlineFrames = false - showSourceLocations = false + options = [ .showSourceLocations ] case .full: shouldSymbolicate = true - showInlineFrames = true - showSourceLocations = true + options = [ .showInlineFrames, .showSourceLocations ] + } + + if cache { + options.insert(.useSymbolCache) } if shouldSymbolicate { guard let symbolicated = backtrace.symbolicated( with: images, - sharedCacheInfo: sharedCacheInfo, - showInlineFrames: showInlineFrames, - showSourceLocations: showSourceLocations, - useSymbolCache: cache) else { + options: options + ) else { print("unable to symbolicate backtrace from context for thread \(ndx)", to: &standardError) exit(1) @@ -334,7 +333,9 @@ class Target { guard let backtrace = try? Backtrace.capture(from: context, using: reader, images: nil, + algorithm: .auto, limit: limit, + offset: 0, top: top) else { print("swift-backtrace: unable to capture backtrace from context for thread \(ndx)", to: &standardError) @@ -342,30 +343,28 @@ class Target { } let shouldSymbolicate: Bool - let showInlineFrames: Bool - let showSourceLocations: Bool + var options: Backtrace.SymbolicationOptions switch symbolicate { case .off: shouldSymbolicate = false - showInlineFrames = false - showSourceLocations = false + options = [] case .fast: shouldSymbolicate = true - showInlineFrames = false - showSourceLocations = false + options = [ .showSourceLocations ] case .full: shouldSymbolicate = true - showInlineFrames = true - showSourceLocations = true + options = [ .showInlineFrames, .showSourceLocations ] + } + + if cache { + options.insert(.useSymbolCache) } if shouldSymbolicate { guard let symbolicated = backtrace.symbolicated( with: images, - sharedCacheInfo: sharedCacheInfo, - showInlineFrames: showInlineFrames, - showSourceLocations: showSourceLocations, - useSymbolCache: cache) else { + options: options + ) else { print("swift-backtrace: unable to symbolicate backtrace from context for thread \(ndx)", to: &standardError) continue diff --git a/stdlib/public/libexec/swift-backtrace/Themes.swift b/stdlib/public/libexec/swift-backtrace/Themes.swift index f9addbc90287f..d26f67ee07045 100644 --- a/stdlib/public/libexec/swift-backtrace/Themes.swift +++ b/stdlib/public/libexec/swift-backtrace/Themes.swift @@ -14,7 +14,7 @@ // //===----------------------------------------------------------------------===// -@_spi(Formatting) import _Backtracing +@_spi(Formatting) import Runtime protocol ErrorAndWarningTheme { func crashReason(_ s: String) -> String @@ -38,6 +38,16 @@ extension PromptTheme { public func prompt(_ s: String) -> String { return s } } +protocol PlatformArchTheme { + func platform(_ s: String) -> String + func architecture(_ s: String) -> String +} + +extension PlatformArchTheme { + public func platform(_ s: String) -> String { return s } + public func architecture(_ s: String) -> String { return s } +} + protocol MemoryDumpTheme { func address(_ s: String) -> String func data(_ s: String) -> String @@ -67,7 +77,7 @@ extension RegisterDumpTheme { } typealias Theme = BacktraceFormattingTheme & ErrorAndWarningTheme & - PromptTheme & MemoryDumpTheme & RegisterDumpTheme + PromptTheme & MemoryDumpTheme & RegisterDumpTheme & PlatformArchTheme enum Themes { @@ -164,6 +174,13 @@ enum Themes { public func info(_ s: String) -> String { return "ℹ️ \(s)" } + + public func platform(_ s: String) -> String { + return "\(fg: .white)\(s)\(fg: .normal)" + } + public func architecture(_ s: String) -> String { + return "\(fg: .white)\(s)\(fg: .normal)" + } } static let plain = Plain() diff --git a/stdlib/public/libexec/swift-backtrace/Utils.swift b/stdlib/public/libexec/swift-backtrace/Utils.swift index 2fa492bbb0976..20e164d5b08c3 100644 --- a/stdlib/public/libexec/swift-backtrace/Utils.swift +++ b/stdlib/public/libexec/swift-backtrace/Utils.swift @@ -26,7 +26,7 @@ import CRT import Swift -import BacktracingImpl.Runtime +internal import BacktracingImpl.Runtime typealias CrashInfo = swift.runtime.backtrace.CrashInfo @@ -151,6 +151,18 @@ internal func spawn(_ path: String, args: [String]) throws { #endif // os(macOS) +extension Sequence { + /// Return the first element in a Sequence. + /// + /// This is not, in general, a safe thing to do, because the sequence might + /// not be restartable. For the cases where we're using it here, it's OK + /// though. + public var unsafeFirst: Element? { + var iterator = makeIterator() + return iterator.next() + } +} + struct CFileStream: TextOutputStream { var fp: UnsafeMutablePointer diff --git a/stdlib/public/libexec/swift-backtrace/main.swift b/stdlib/public/libexec/swift-backtrace/main.swift index 5c5db1800604b..e8c8000f61ee4 100644 --- a/stdlib/public/libexec/swift-backtrace/main.swift +++ b/stdlib/public/libexec/swift-backtrace/main.swift @@ -22,10 +22,10 @@ import Musl import CRT #endif -@_spi(Formatting) import _Backtracing -@_spi(Contexts) import _Backtracing -@_spi(Registers) import _Backtracing -@_spi(MemoryReaders) import _Backtracing +@_spi(Formatting) import Runtime +@_spi(Contexts) import Runtime +@_spi(Registers) import Runtime +@_spi(MemoryReaders) import Runtime @main internal struct SwiftBacktrace { @@ -144,8 +144,8 @@ internal struct SwiftBacktrace { } static func measureDuration(_ body: () -> ()) -> timespec { - var startTime = timespec() - var endTime = timespec() + var startTime = timespec(tv_sec: 0, tv_nsec: 0) + var endTime = timespec(tv_sec: 0, tv_nsec: 0) clock_gettime(CLOCK_MONOTONIC, &startTime) body() @@ -719,6 +719,17 @@ Generate a backtrace for the parent process. var mentionedImages = Set() let formatter = backtraceFormatter() + let platform = target.images.platform + let architecture: String + switch crashingThread.backtrace { + case let .raw(backtrace): + architecture = backtrace.architecture + case let .symbolicated(backtrace): + architecture = backtrace.architecture + } + + writeln("\nPlatform: \(theme.architecture(architecture)) \(theme.platform(target.images.platform))") + func dump(ndx: Int, thread: TargetThread) { let crashed = thread.id == target.crashingThread ? " crashed" : "" let name = !thread.name.isEmpty ? " \"\(thread.name)\"" : "" @@ -786,13 +797,6 @@ Generate a backtrace for the parent process. } } - let addressWidthInChars: Int - switch crashingThread.backtrace { - case let .raw(backtrace): - addressWidthInChars = (backtrace.addressWidth + 3) / 4 - case let .symbolicated(backtrace): - addressWidthInChars = (backtrace.addressWidth + 3) / 4 - } switch args.showImages! { case .none: break @@ -804,12 +808,10 @@ Generate a backtrace for the parent process. } else { writeln("\n\nImages:\n") } - writeln(formatter.format(images: images, - addressWidth: addressWidthInChars)) + writeln(formatter.format(images: images)) case .all: writeln("\n\nImages:\n") - writeln(formatter.format(images: target.images, - addressWidth: addressWidthInChars)) + writeln(formatter.format(images: target.images)) } } @@ -891,20 +893,15 @@ Generate a backtrace for the parent process. let formatter = backtraceFormatter() switch thread.backtrace { case let .raw(backtrace): - let addressWidthInChars = (backtrace.addressWidth + 3) / 4 - if let frame = backtrace.frames.first { - let formatted = formatter.format(frame: frame, - addressWidth: addressWidthInChars) + if let frame = backtrace.frames.unsafeFirst { + let formatted = formatter.format(frame: frame) writeln("\(formatted)") } case let .symbolicated(backtrace): - let addressWidthInChars = (backtrace.addressWidth + 3) / 4 - if let frame = backtrace.frames.drop(while: { $0.isSwiftRuntimeFailure - }).first { - let formatted = formatter.format(frame: frame, - addressWidth: addressWidthInChars) + }).unsafeFirst { + let formatted = formatter.format(frame: frame) writeln("\(formatted)") } } @@ -975,12 +972,10 @@ Generate a backtrace for the parent process. switch thread.backtrace { case let .raw(backtrace): - let addressWidthInChars = (backtrace.addressWidth + 3) / 4 - - if let frame = backtrace.frames.first { + if let frame = backtrace.frames.unsafeFirst { rows += formatter.formatRows( - frame: frame, - addressWidth: addressWidthInChars).map{ row in + frame: frame + ).map{ row in switch row { case let .columns(columns): @@ -991,14 +986,12 @@ Generate a backtrace for the parent process. } } case let .symbolicated(backtrace): - let addressWidthInChars = (backtrace.addressWidth + 3) / 4 - if let frame = backtrace.frames.drop(while: { $0.isSwiftRuntimeFailure - }).first { + }).unsafeFirst { rows += formatter.formatRows( - frame: frame, - addressWidth: addressWidthInChars).map{ row in + frame: frame + ).map{ row in switch row { case let .columns(columns): @@ -1020,15 +1013,7 @@ Generate a backtrace for the parent process. case "images": let formatter = backtraceFormatter() let images = target.images - let addressWidthInChars: Int - switch target.threads[currentThread].backtrace { - case let .raw(backtrace): - addressWidthInChars = (backtrace.addressWidth + 3) / 4 - case let .symbolicated(backtrace): - addressWidthInChars = (backtrace.addressWidth + 3) / 4 - } - let output = formatter.format(images: images, - addressWidth: addressWidthInChars) + let output = formatter.format(images: images) writeln(output) case "set": diff --git a/stdlib/public/runtime/Array.cpp b/stdlib/public/runtime/Array.cpp index d89a6060aa55a..ee94d7c60f5b3 100644 --- a/stdlib/public/runtime/Array.cpp +++ b/stdlib/public/runtime/Array.cpp @@ -113,12 +113,12 @@ static void array_copy_operation(OpaqueValue *dest, OpaqueValue *src, if (copyKind == ArrayCopy::NoAlias || copyKind == ArrayCopy::FrontToBack) { if (self->hasLayoutString() && destOp == ArrayDest::Init && srcOp == ArraySource::Copy) { - return swift_generic_arrayInitWithCopy(dest, src, count, stride, self); + return swift_cvw_arrayInitWithCopy(dest, src, count, stride, self); } if (self->hasLayoutString() && destOp == ArrayDest::Assign && srcOp == ArraySource::Copy) { - return swift_generic_arrayAssignWithCopy(dest, src, count, stride, self); + return swift_cvw_arrayAssignWithCopy(dest, src, count, stride, self); } auto copy = get_witness_function(wtable); @@ -214,7 +214,7 @@ void swift_arrayDestroy(OpaqueValue *begin, size_t count, const Metadata *self) auto stride = wtable->getStride(); if (self->hasLayoutString()) { - return swift_generic_arrayDestroy(begin, count, stride, self); + return swift_cvw_arrayDestroy(begin, count, stride, self); } for (size_t i = 0; i < count; ++i) { diff --git a/stdlib/public/runtime/BytecodeLayouts.cpp b/stdlib/public/runtime/BytecodeLayouts.cpp index 79a6ca9e0346f..5a11d323427a5 100644 --- a/stdlib/public/runtime/BytecodeLayouts.cpp +++ b/stdlib/public/runtime/BytecodeLayouts.cpp @@ -38,6 +38,8 @@ #include #endif +#include "../CompatibilityOverride/CompatibilityOverride.h" + using namespace swift; static Metadata *getExistentialTypeMetadata(OpaqueValue *object) { @@ -897,8 +899,8 @@ static void handleRefCountsDestroy(const Metadata *metadata, } } -extern "C" void -swift_generic_destroy(swift::OpaqueValue *address, const Metadata *metadata) { +static void swift_cvw_destroyImpl(swift::OpaqueValue *address, + const Metadata *metadata) { const uint8_t *layoutStr = metadata->getLayoutString(); LayoutStringReader1 reader{layoutStr + layoutStringHeaderSize}; uintptr_t addrOffset = 0; @@ -912,7 +914,8 @@ swift_generic_destroy(swift::OpaqueValue *address, const Metadata *metadata) { #endif } -void swift::swift_generic_arrayDestroy(swift::OpaqueValue *address, size_t count, size_t stride, const Metadata *metadata) { +void swift::swift_cvw_arrayDestroy(swift::OpaqueValue *address, size_t count, + size_t stride, const Metadata *metadata) { const uint8_t *layoutStr = metadata->getLayoutString(); uint8_t *addr = (uint8_t *)address; for (size_t i = 0; i < count; i++) { @@ -1157,8 +1160,8 @@ static void handleRefCountsInitWithCopy(const Metadata *metadata, } } -extern "C" swift::OpaqueValue * -swift_generic_initWithCopy(swift::OpaqueValue *_dest, swift::OpaqueValue *_src, +static swift::OpaqueValue * +swift_cvw_initWithCopyImpl(swift::OpaqueValue *_dest, swift::OpaqueValue *_src, const Metadata *metadata) { const uint8_t *layoutStr = metadata->getLayoutString(); LayoutStringReader1 reader{layoutStr + layoutStringHeaderSize}; @@ -1178,10 +1181,10 @@ swift_generic_initWithCopy(swift::OpaqueValue *_dest, swift::OpaqueValue *_src, return _dest; } -void swift::swift_generic_arrayInitWithCopy(swift::OpaqueValue *_dest, - swift::OpaqueValue *_src, - size_t count, size_t stride, - const Metadata *metadata) { +void swift::swift_cvw_arrayInitWithCopy(swift::OpaqueValue *_dest, + swift::OpaqueValue *_src, size_t count, + size_t stride, + const Metadata *metadata) { const uint8_t *layoutStr = metadata->getLayoutString(); uint8_t *dest = (uint8_t *)_dest; uint8_t *src = (uint8_t *)_src; @@ -1315,8 +1318,8 @@ static void handleRefCountsInitWithTake(const Metadata *metadata, } } -extern "C" swift::OpaqueValue * -swift_generic_initWithTake(swift::OpaqueValue *_dest, swift::OpaqueValue *_src, +static swift::OpaqueValue * +swift_cvw_initWithTakeImpl(swift::OpaqueValue *_dest, swift::OpaqueValue *_src, const Metadata *metadata) { if (SWIFT_LIKELY(metadata->getValueWitnesses()->isBitwiseTakable())) { size_t size = metadata->vw_size(); @@ -2067,8 +2070,8 @@ static void multiPayloadEnumFNAssignWithCopy(const Metadata *metadata, addrOffset += enumSize; } -extern "C" swift::OpaqueValue * -swift_generic_assignWithCopy(swift::OpaqueValue *_dest, +static swift::OpaqueValue * +swift_cvw_assignWithCopyImpl(swift::OpaqueValue *_dest, swift::OpaqueValue *_src, const Metadata *metadata) { uint8_t *dest = (uint8_t *)_dest; @@ -2089,10 +2092,10 @@ swift_generic_assignWithCopy(swift::OpaqueValue *_dest, return _dest; } -void swift::swift_generic_arrayAssignWithCopy(swift::OpaqueValue *_dest, - swift::OpaqueValue *_src, - size_t count, size_t stride, - const Metadata *metadata) { +void swift::swift_cvw_arrayAssignWithCopy(swift::OpaqueValue *_dest, + swift::OpaqueValue *_src, + size_t count, size_t stride, + const Metadata *metadata) { uint8_t *dest = (uint8_t *)_dest; uint8_t *src = (uint8_t *)_src; const uint8_t *layoutStr = metadata->getLayoutString(); @@ -2109,19 +2112,20 @@ void swift::swift_generic_arrayAssignWithCopy(swift::OpaqueValue *_dest, } } -extern "C" swift::OpaqueValue * -swift_generic_assignWithTake(swift::OpaqueValue *dest, swift::OpaqueValue *src, +static swift::OpaqueValue * +swift_cvw_assignWithTakeImpl(swift::OpaqueValue *dest, swift::OpaqueValue *src, const Metadata *metadata) { - swift_generic_destroy(dest, metadata); - return swift_generic_initWithTake(dest, src, metadata); + swift_cvw_destroy(dest, metadata); + return swift_cvw_initWithTake(dest, src, metadata); } -extern "C" unsigned swift_singletonEnum_getEnumTag(swift::OpaqueValue *address, - const Metadata *metadata) { +extern "C" unsigned +swift_cvw_singletonEnum_getEnumTag(swift::OpaqueValue *address, + const Metadata *metadata) { return 0; } -extern "C" void swift_singletonEnum_destructiveInjectEnumTag( +extern "C" void swift_cvw_singletonEnum_destructiveInjectEnumTag( swift::OpaqueValue *address, unsigned tag, const Metadata *metadata) { return; } @@ -2154,8 +2158,8 @@ static inline T handleSinglePayloadEnumSimpleTag( xiTagBytesOffset, payloadSize, numExtraTagBytes); } -extern "C" unsigned swift_enumSimple_getEnumTag(swift::OpaqueValue *address, - const Metadata *metadata) { +static unsigned swift_cvw_enumSimple_getEnumTagImpl(swift::OpaqueValue *address, + const Metadata *metadata) { auto addr = reinterpret_cast(address); LayoutStringReader reader{metadata->getLayoutString(), layoutStringHeaderSize + sizeof(uint64_t)}; @@ -2197,7 +2201,7 @@ extern "C" unsigned swift_enumSimple_getEnumTag(swift::OpaqueValue *address, reader, addr, extraTagBytesHandler, xihandler); } -extern "C" void swift_enumSimple_destructiveInjectEnumTag( +static void swift_cvw_enumSimple_destructiveInjectEnumTagImpl( swift::OpaqueValue *address, unsigned tag, const Metadata *metadata) { auto addr = reinterpret_cast(address); LayoutStringReader reader{metadata->getLayoutString(), @@ -2255,9 +2259,8 @@ extern "C" void swift_enumSimple_destructiveInjectEnumTag( xihandler); } -extern "C" -unsigned swift_enumFn_getEnumTag(swift::OpaqueValue *address, - const Metadata *metadata) { +static unsigned swift_cvw_enumFn_getEnumTagImpl(swift::OpaqueValue *address, + const Metadata *metadata) { auto addr = reinterpret_cast(address); LayoutStringReader reader{metadata->getLayoutString(), layoutStringHeaderSize + sizeof(uint64_t)}; @@ -2266,9 +2269,9 @@ unsigned swift_enumFn_getEnumTag(swift::OpaqueValue *address, return getEnumTag(addr); } -extern "C" unsigned -swift_multiPayloadEnumGeneric_getEnumTag(swift::OpaqueValue *address, - const Metadata *metadata) { +static unsigned +swift_cvw_multiPayloadEnumGeneric_getEnumTagImpl(swift::OpaqueValue *address, + const Metadata *metadata) { auto addr = reinterpret_cast(address); LayoutStringReader1 reader{metadata->getLayoutString() + layoutStringHeaderSize + sizeof(uint64_t)}; @@ -2295,7 +2298,7 @@ swift_multiPayloadEnumGeneric_getEnumTag(swift::OpaqueValue *address, } } -extern "C" void swift_multiPayloadEnumGeneric_destructiveInjectEnumTag( +static void swift_cvw_multiPayloadEnumGeneric_destructiveInjectEnumTagImpl( swift::OpaqueValue *address, unsigned tag, const Metadata *metadata) { auto addr = reinterpret_cast(address); LayoutStringReader reader{metadata->getLayoutString(), @@ -2358,9 +2361,9 @@ static inline T handleSinglePayloadEnumGenericTag( numExtraTagBytes); } -extern "C" unsigned -swift_singlePayloadEnumGeneric_getEnumTag(swift::OpaqueValue *address, - const Metadata *metadata) { +static unsigned +swift_cvw_singlePayloadEnumGeneric_getEnumTagImpl(swift::OpaqueValue *address, + const Metadata *metadata) { auto addr = reinterpret_cast(address); LayoutStringReader reader{metadata->getLayoutString(), layoutStringHeaderSize + sizeof(uint64_t)}; @@ -2400,7 +2403,7 @@ swift_singlePayloadEnumGeneric_getEnumTag(swift::OpaqueValue *address, reader, addr, extraTagBytesHandler, xihandler); } -extern "C" void swift_singlePayloadEnumGeneric_destructiveInjectEnumTag( +static void swift_cvw_singlePayloadEnumGeneric_destructiveInjectEnumTagImpl( swift::OpaqueValue *address, unsigned tag, const Metadata *metadata) { auto addr = reinterpret_cast(address); LayoutStringReader reader{metadata->getLayoutString(), @@ -2458,13 +2461,13 @@ extern "C" void swift_singlePayloadEnumGeneric_destructiveInjectEnumTag( xihandler); } -extern "C" swift::OpaqueValue * -swift_generic_initializeBufferWithCopyOfBuffer(swift::ValueBuffer *dest, +static swift::OpaqueValue * +swift_cvw_initializeBufferWithCopyOfBufferImpl(swift::ValueBuffer *dest, swift::ValueBuffer *src, const Metadata *metadata) { if (metadata->getValueWitnesses()->isValueInline()) { - return swift_generic_initWithCopy((swift::OpaqueValue *)dest, - (swift::OpaqueValue *)src, metadata); + return swift_cvw_initWithCopy((swift::OpaqueValue *)dest, + (swift::OpaqueValue *)src, metadata); } else { memcpy(dest, src, sizeof(swift::HeapObject *)); swift_retain(*(swift::HeapObject **)src); @@ -2472,10 +2475,10 @@ swift_generic_initializeBufferWithCopyOfBuffer(swift::ValueBuffer *dest, } } -void swift::swift_resolve_resilientAccessors(uint8_t *layoutStr, - size_t layoutStrOffset, - const uint8_t *fieldLayoutStr, - const Metadata *fieldType) { +void swift::swift_cvw_resolve_resilientAccessors(uint8_t *layoutStr, + size_t layoutStrOffset, + const uint8_t *fieldLayoutStr, + const Metadata *fieldType) { LayoutStringWriter writer{layoutStr, layoutStrOffset}; LayoutStringReader reader{fieldLayoutStr, 0}; while (true) { @@ -2554,9 +2557,9 @@ void swift::swift_resolve_resilientAccessors(uint8_t *layoutStr, size_t caseOffset = reader.readBytes(); const uint8_t *caseLayoutString = fieldCasesBeginOffset + caseOffset; - swift_resolve_resilientAccessors(layoutStr, - casesBeginOffset + caseOffset, - caseLayoutString, fieldType); + swift_cvw_resolve_resilientAccessors(layoutStr, + casesBeginOffset + caseOffset, + caseLayoutString, fieldType); } reader.skip(refCountBytes); break; @@ -2586,8 +2589,102 @@ void swift::swift_resolve_resilientAccessors(uint8_t *layoutStr, } } -extern "C" -void swift_generic_instantiateLayoutString(const uint8_t* layoutStr, - Metadata* type) { +extern "C" void swift_cvw_instantiateLayoutString(const uint8_t *layoutStr, + Metadata *type) { type->setLayoutString(layoutStr); } + +// Forwarders for compatibility reasons + +extern "C" void swift_generic_destroy(swift::OpaqueValue *address, + const Metadata *metadata) { + swift_cvw_destroy(address, metadata); +} + +extern "C" swift::OpaqueValue * +swift_generic_assignWithCopy(swift::OpaqueValue *dest, swift::OpaqueValue *src, + const Metadata *metadata) { + return swift_cvw_assignWithCopy(dest, src, metadata); +} + +extern "C" swift::OpaqueValue * +swift_generic_assignWithTake(swift::OpaqueValue *dest, swift::OpaqueValue *src, + const Metadata *metadata) { + return swift_cvw_assignWithTake(dest, src, metadata); +} + +extern "C" swift::OpaqueValue * +swift_generic_initWithCopy(swift::OpaqueValue *dest, swift::OpaqueValue *src, + const Metadata *metadata) { + return swift_cvw_initWithCopy(dest, src, metadata); +} + +extern "C" swift::OpaqueValue * +swift_generic_initWithTake(swift::OpaqueValue *dest, swift::OpaqueValue *src, + const Metadata *metadata) { + return swift_cvw_initWithTake(dest, src, metadata); +} + +extern "C" swift::OpaqueValue * +swift_generic_initializeBufferWithCopyOfBuffer(swift::ValueBuffer *dest, + swift::ValueBuffer *src, + const Metadata *metadata) { + return swift_cvw_initializeBufferWithCopyOfBuffer(dest, src, metadata); +} + +extern "C" unsigned swift_enumSimple_getEnumTag(swift::OpaqueValue *address, + const Metadata *metadata) { + return swift_cvw_enumSimple_getEnumTag(address, metadata); +} + +extern "C" void swift_enumSimple_destructiveInjectEnumTag( + swift::OpaqueValue *address, unsigned tag, const Metadata *metadata) { + swift_cvw_enumSimple_destructiveInjectEnumTag(address, tag, metadata); +} + +extern "C" unsigned swift_enumFn_getEnumTag(swift::OpaqueValue *address, + const Metadata *metadata) { + return swift_cvw_enumFn_getEnumTag(address, metadata); +} + +extern "C" unsigned +swift_multiPayloadEnumGeneric_getEnumTag(swift::OpaqueValue *address, + const Metadata *metadata) { + return swift_cvw_multiPayloadEnumGeneric_getEnumTag(address, metadata); +} + +extern "C" void swift_multiPayloadEnumGeneric_destructiveInjectEnumTag( + swift::OpaqueValue *address, unsigned tag, const Metadata *metadata) { + swift_cvw_multiPayloadEnumGeneric_destructiveInjectEnumTag(address, tag, + metadata); +} + +extern "C" unsigned +swift_singlePayloadEnumGeneric_getEnumTag(swift::OpaqueValue *address, + const Metadata *metadata) { + return swift_cvw_singlePayloadEnumGeneric_getEnumTagImpl(address, metadata); +} + +extern "C" void swift_singlePayloadEnumGeneric_destructiveInjectEnumTag( + swift::OpaqueValue *address, unsigned tag, const Metadata *metadata) { + swift_cvw_singlePayloadEnumGeneric_destructiveInjectEnumTag(address, tag, + metadata); +} + +extern "C" unsigned swift_singletonEnum_getEnumTag(swift::OpaqueValue *address, + const Metadata *metadata) { + return 0; +} + +extern "C" void swift_singletonEnum_destructiveInjectEnumTag( + swift::OpaqueValue *address, unsigned tag, const Metadata *metadata) { + return; +} + +extern "C" void swift_generic_instantiateLayoutString(const uint8_t *layoutStr, + Metadata *type) { + swift_cvw_instantiateLayoutString(layoutStr, type); +} + +#define OVERRIDE_CVW COMPATIBILITY_OVERRIDE +#include "../CompatibilityOverride/CompatibilityOverrideIncludePath.h" diff --git a/stdlib/public/runtime/BytecodeLayouts.h b/stdlib/public/runtime/BytecodeLayouts.h index 03974387db555..51dbb3ed22082 100644 --- a/stdlib/public/runtime/BytecodeLayouts.h +++ b/stdlib/public/runtime/BytecodeLayouts.h @@ -172,6 +172,81 @@ struct LayoutStringWriter { inline void skip(size_t n) { offset += n; } }; +SWIFT_RUNTIME_EXPORT +void swift_cvw_destroy(swift::OpaqueValue *address, const Metadata *metadata); +SWIFT_RUNTIME_EXPORT +swift::OpaqueValue *swift_cvw_assignWithCopy(swift::OpaqueValue *dest, + swift::OpaqueValue *src, + const Metadata *metadata); +SWIFT_RUNTIME_EXPORT +swift::OpaqueValue *swift_cvw_assignWithTake(swift::OpaqueValue *dest, + swift::OpaqueValue *src, + const Metadata *metadata); +SWIFT_RUNTIME_EXPORT +swift::OpaqueValue *swift_cvw_initWithCopy(swift::OpaqueValue *dest, + swift::OpaqueValue *src, + const Metadata *metadata); +SWIFT_RUNTIME_EXPORT +swift::OpaqueValue *swift_cvw_initWithTake(swift::OpaqueValue *dest, + swift::OpaqueValue *src, + const Metadata *metadata); +SWIFT_RUNTIME_EXPORT +swift::OpaqueValue * +swift_cvw_initializeBufferWithCopyOfBuffer(swift::ValueBuffer *dest, + swift::ValueBuffer *src, + const Metadata *metadata); +SWIFT_RUNTIME_EXPORT +unsigned swift_cvw_singletonEnum_getEnumTag(swift::OpaqueValue *address, + const Metadata *metadata); +SWIFT_RUNTIME_EXPORT +void swift_cvw_singletonEnum_destructiveInjectEnumTag( + swift::OpaqueValue *address, unsigned tag, const Metadata *metadata); +SWIFT_RUNTIME_EXPORT +unsigned swift_cvw_enumSimple_getEnumTag(swift::OpaqueValue *address, + const Metadata *metadata); +SWIFT_RUNTIME_EXPORT +void swift_cvw_enumSimple_destructiveInjectEnumTag(swift::OpaqueValue *address, + unsigned tag, + const Metadata *metadata); +SWIFT_RUNTIME_EXPORT +unsigned swift_cvw_enumFn_getEnumTag(swift::OpaqueValue *address, + const Metadata *metadata); +SWIFT_RUNTIME_EXPORT +unsigned +swift_cvw_multiPayloadEnumGeneric_getEnumTag(swift::OpaqueValue *address, + const Metadata *metadata); +SWIFT_RUNTIME_EXPORT +void swift_cvw_multiPayloadEnumGeneric_destructiveInjectEnumTag( + swift::OpaqueValue *address, unsigned tag, const Metadata *metadata); +SWIFT_RUNTIME_EXPORT +unsigned +swift_cvw_singlePayloadEnumGeneric_getEnumTag(swift::OpaqueValue *address, + const Metadata *metadata); +SWIFT_RUNTIME_EXPORT +void swift_cvw_singlePayloadEnumGeneric_destructiveInjectEnumTag( + swift::OpaqueValue *address, unsigned tag, const Metadata *metadata); +SWIFT_RUNTIME_EXPORT +void swift_cvw_instantiateLayoutString(const uint8_t *layoutStr, + Metadata *type); + +void swift_cvw_resolve_resilientAccessors(uint8_t *layoutStr, + size_t layoutStrOffset, + const uint8_t *fieldLayoutStr, + const Metadata *fieldType); + +void swift_cvw_arrayDestroy(swift::OpaqueValue *addr, size_t count, + size_t stride, const Metadata *metadata); + +void swift_cvw_arrayInitWithCopy(swift::OpaqueValue *dest, + swift::OpaqueValue *src, size_t count, + size_t stride, const Metadata *metadata); + +extern "C" void swift_cvw_arrayAssignWithCopy(swift::OpaqueValue *dest, + swift::OpaqueValue *src, + size_t count, size_t stride, + const Metadata *metadata); + +// For backwards compatibility SWIFT_RUNTIME_EXPORT void swift_generic_destroy(swift::OpaqueValue *address, const Metadata *metadata); @@ -226,29 +301,7 @@ SWIFT_RUNTIME_EXPORT void swift_singlePayloadEnumGeneric_destructiveInjectEnumTag( swift::OpaqueValue *address, unsigned tag, const Metadata *metadata); SWIFT_RUNTIME_EXPORT -void swift_generic_instantiateLayoutString(const uint8_t *layoutStr, - Metadata *type); - -void swift_resolve_resilientAccessors(uint8_t *layoutStr, - size_t layoutStrOffset, - const uint8_t *fieldLayoutStr, - const Metadata *fieldType); - -void swift_generic_arrayDestroy(swift::OpaqueValue *addr, - size_t count, - size_t stride, - const Metadata *metadata); - -void swift_generic_arrayInitWithCopy(swift::OpaqueValue *dest, - swift::OpaqueValue *src, - size_t count, - size_t stride, - const Metadata *metadata); - -extern "C" void swift_generic_arrayAssignWithCopy(swift::OpaqueValue *dest, - swift::OpaqueValue *src, - size_t count, size_t stride, - const Metadata *metadata); +void swift_generic_instantiateLayoutString(const uint8_t *layoutStr, Metadata *type); constexpr size_t layoutStringHeaderSize = sizeof(uint64_t) + sizeof(size_t); diff --git a/stdlib/public/runtime/CMakeLists.txt b/stdlib/public/runtime/CMakeLists.txt index be5bb9e352be7..407382ff6b38a 100644 --- a/stdlib/public/runtime/CMakeLists.txt +++ b/stdlib/public/runtime/CMakeLists.txt @@ -144,7 +144,11 @@ foreach(sdk ${SWIFT_SDKS}) endif() endforeach() -add_swift_target_library(swiftRuntime OBJECT_LIBRARY +# In modern CMake, we would be able to use the previous name `swiftRuntime` +# without clashing with the `Runtime` module, but the current build system +# is architected in such a way that we had to rename this to `swiftRuntimeCore` +# in order to avoid a clash with the new Swift module. +add_swift_target_library(swiftRuntimeCore OBJECT_LIBRARY ${swift_runtime_sources} ${swift_runtime_objc_sources} ${swift_runtime_leaks_sources} @@ -323,4 +327,3 @@ if(static_binary_lnk_file_list) add_dependencies(stdlib ${static_binary_lnk_file_list}) add_custom_target(static_binary_magic ALL DEPENDS ${static_binary_lnk_file_list}) endif() - diff --git a/stdlib/public/runtime/Enum.cpp b/stdlib/public/runtime/Enum.cpp index 4e5f81fa6872d..ce7ed5aff1c3f 100644 --- a/stdlib/public/runtime/Enum.cpp +++ b/stdlib/public/runtime/Enum.cpp @@ -24,6 +24,8 @@ #include #include +#include "../CompatibilityOverride/CompatibilityOverride.h" + using namespace swift; // So remote inspection/debugging tools can obtain @@ -65,7 +67,7 @@ swift::swift_initEnumMetadataSingleCase(EnumMetadata *self, vwtable->publishLayout(layout); } -void swift::swift_initEnumMetadataSingleCaseWithLayoutString( +static void swift_cvw_initEnumMetadataSingleCaseWithLayoutStringImpl( EnumMetadata *self, EnumLayoutFlags layoutFlags, const Metadata *payloadType) { assert(self->hasLayoutString()); @@ -106,12 +108,6 @@ void swift::swift_initEnumMetadataSingleCaseWithLayoutString( writer.writeBytes(((uint64_t)flags) & ~((uint64_t)LayoutStringFlags::HasRelativePointers)); - vwtable->destroy = swift_generic_destroy; - vwtable->initializeWithCopy = swift_generic_initWithCopy; - vwtable->initializeWithTake = swift_generic_initWithTake; - vwtable->assignWithCopy = swift_generic_assignWithCopy; - vwtable->assignWithTake = swift_generic_assignWithTake; - installCommonValueWitnesses(layout, vwtable); self->setLayoutString(layoutStr); @@ -119,6 +115,13 @@ void swift::swift_initEnumMetadataSingleCaseWithLayoutString( vwtable->publishLayout(layout); } +void swift::swift_initEnumMetadataSingleCaseWithLayoutString( + EnumMetadata *self, EnumLayoutFlags layoutFlags, + const Metadata *payloadType) { + swift_cvw_initEnumMetadataSingleCaseWithLayoutString(self, layoutFlags, + payloadType); +} + void swift::swift_initEnumMetadataSinglePayload(EnumMetadata *self, EnumLayoutFlags layoutFlags, @@ -218,7 +221,7 @@ XIElement findXIElement(const Metadata *type) { } } // namespace -void swift::swift_initEnumMetadataSinglePayloadWithLayoutString( +static void swift_cvw_initEnumMetadataSinglePayloadWithLayoutStringImpl( EnumMetadata *self, EnumLayoutFlags layoutFlags, const Metadata *payloadType, unsigned emptyCases) { assert(self->hasLayoutString()); @@ -317,11 +320,6 @@ void swift::swift_initEnumMetadataSinglePayloadWithLayoutString( ~((uint64_t)LayoutStringFlags::HasRelativePointers)); self->setLayoutString(layoutStr); - vwtable->destroy = swift_generic_destroy; - vwtable->initializeWithCopy = swift_generic_initWithCopy; - vwtable->initializeWithTake = swift_generic_initWithTake; - vwtable->assignWithCopy = swift_generic_assignWithCopy; - vwtable->assignWithTake = swift_generic_assignWithTake; // Substitute in better common value witnesses if we have them. // If the payload type is a single-refcounted pointer, and the enum has @@ -352,6 +350,13 @@ void swift::swift_initEnumMetadataSinglePayloadWithLayoutString( vwtable->publishLayout(layout); } +void swift::swift_initEnumMetadataSinglePayloadWithLayoutString( + EnumMetadata *self, EnumLayoutFlags layoutFlags, + const Metadata *payloadType, unsigned emptyCases) { + return swift_cvw_initEnumMetadataSinglePayloadWithLayoutString( + self, layoutFlags, payloadType, emptyCases); +} + unsigned swift::swift_getEnumTagSinglePayloadGeneric(const OpaqueValue *value, unsigned emptyCases, @@ -437,11 +442,9 @@ swift::swift_initEnumMetadataMultiPayload(EnumMetadata *enumType, vwtable->publishLayout(layout); } -void swift::swift_initEnumMetadataMultiPayloadWithLayoutString( - EnumMetadata *enumType, - EnumLayoutFlags layoutFlags, - unsigned numPayloads, - const Metadata * const *payloadLayouts) { +static void swift_cvw_initEnumMetadataMultiPayloadWithLayoutStringImpl( + EnumMetadata *enumType, EnumLayoutFlags layoutFlags, unsigned numPayloads, + const Metadata *const *payloadLayouts) { assert(enumType->hasLayoutString()); // Accumulate the layout requirements of the payloads. @@ -545,12 +548,6 @@ void swift::swift_initEnumMetadataMultiPayloadWithLayoutString( ~((uint64_t)LayoutStringFlags::HasRelativePointers)); enumType->setLayoutString(layoutStr); - - vwtable->destroy = swift_generic_destroy; - vwtable->initializeWithCopy = swift_generic_initWithCopy; - vwtable->initializeWithTake = swift_generic_initWithTake; - vwtable->assignWithCopy = swift_generic_assignWithCopy; - vwtable->assignWithTake = swift_generic_assignWithTake; } // Set up the layout info in the vwtable. @@ -578,6 +575,13 @@ void swift::swift_initEnumMetadataMultiPayloadWithLayoutString( vwtable->publishLayout(layout); } +void swift::swift_initEnumMetadataMultiPayloadWithLayoutString( + EnumMetadata *enumType, EnumLayoutFlags layoutFlags, unsigned numPayloads, + const Metadata *const *payloadLayouts) { + swift_cvw_initEnumMetadataMultiPayloadWithLayoutString( + enumType, layoutFlags, numPayloads, payloadLayouts); +} + namespace { struct MultiPayloadLayout { size_t payloadSize; @@ -719,3 +723,6 @@ swift::swift_getEnumCaseMultiPayload(const OpaqueValue *value, } } } + +#define OVERRIDE_CVW_METADATA_ENUM COMPATIBILITY_OVERRIDE +#include "../CompatibilityOverride/CompatibilityOverrideIncludePath.h" diff --git a/stdlib/public/runtime/Metadata.cpp b/stdlib/public/runtime/Metadata.cpp index 3b2c23f1d41e0..13e71dea6622f 100644 --- a/stdlib/public/runtime/Metadata.cpp +++ b/stdlib/public/runtime/Metadata.cpp @@ -756,16 +756,22 @@ swift::swift_allocateGenericClassMetadata(const ClassDescriptor *description, return metadata; } -ClassMetadata * -swift::swift_allocateGenericClassMetadataWithLayoutString( - const ClassDescriptor *description, - const void *arguments, +static ClassMetadata * +swift_cvw_allocateGenericClassMetadataWithLayoutStringImpl( + const ClassDescriptor *description, const void *arguments, const GenericClassMetadataPattern *pattern) { return swift::swift_allocateGenericClassMetadata(description, arguments, pattern); } +ClassMetadata *swift::swift_allocateGenericClassMetadataWithLayoutString( + const ClassDescriptor *description, const void *arguments, + const GenericClassMetadataPattern *pattern) { + return swift_cvw_allocateGenericClassMetadataWithLayoutString( + description, arguments, pattern); +} + static void initializeValueMetadataFromPattern(ValueMetadata *metadata, const ValueTypeDescriptor *description, @@ -837,18 +843,23 @@ swift::swift_allocateGenericValueMetadata(const ValueTypeDescriptor *description return metadata; } -ValueMetadata * -swift::swift_allocateGenericValueMetadataWithLayoutString( - const ValueTypeDescriptor *description, - const void *arguments, - const GenericValueMetadataPattern *pattern, - size_t extraDataSize) { +static ValueMetadata * +swift_cvw_allocateGenericValueMetadataWithLayoutStringImpl( + const ValueTypeDescriptor *description, const void *arguments, + const GenericValueMetadataPattern *pattern, size_t extraDataSize) { return swift::swift_allocateGenericValueMetadata(description, arguments, pattern, extraDataSize); } +ValueMetadata *swift::swift_allocateGenericValueMetadataWithLayoutString( + const ValueTypeDescriptor *description, const void *arguments, + const GenericValueMetadataPattern *pattern, size_t extraDataSize) { + return swift_cvw_allocateGenericValueMetadataWithLayoutString( + description, arguments, pattern, extraDataSize); +} + // Look into the canonical prespecialized metadata attached to the type // descriptor and add them to the metadata cache. static void @@ -3081,7 +3092,7 @@ void swift::swift_initStructMetadata(StructMetadata *structType, vwtable->publishLayout(layout); } -void swift::swift_initStructMetadataWithLayoutString( +static void swift_cvw_initStructMetadataWithLayoutStringImpl( StructMetadata *structType, StructLayoutFlags layoutFlags, size_t numFields, const uint8_t *const *fieldTypes, const uint8_t *fieldTags, uint32_t *fieldOffsets) { @@ -3191,11 +3202,6 @@ void swift::swift_initStructMetadataWithLayoutString( structType->setLayoutString(layoutStr); auto *vwtable = getMutableVWTableForInit(structType, layoutFlags); - vwtable->destroy = swift_generic_destroy; - vwtable->initializeWithCopy = swift_generic_initWithCopy; - vwtable->initializeWithTake = swift_generic_initWithTake; - vwtable->assignWithCopy = swift_generic_assignWithCopy; - vwtable->assignWithTake = swift_generic_assignWithTake; layout.extraInhabitantCount = extraInhabitantCount; @@ -3205,6 +3211,14 @@ void swift::swift_initStructMetadataWithLayoutString( vwtable->publishLayout(layout); } +void swift::swift_initStructMetadataWithLayoutString( + StructMetadata *structType, StructLayoutFlags layoutFlags, size_t numFields, + const uint8_t *const *fieldTypes, const uint8_t *fieldTags, + uint32_t *fieldOffsets) { + swift_cvw_initStructMetadataWithLayoutString( + structType, layoutFlags, numFields, fieldTypes, fieldTags, fieldOffsets); +} + size_t swift::_swift_refCountBytesForMetatype(const Metadata *type) { auto *vwt = type->getValueWitnesses(); if (type->vw_size() == 0 || vwt->isPOD()) { @@ -3302,8 +3316,9 @@ void swift::_swift_addRefCountStringForMetatype(LayoutStringWriter &writer, reader.layoutStr + layoutStringHeaderSize, fieldRefCountBytes); if (fieldFlags & LayoutStringFlags::HasRelativePointers) { - swift_resolve_resilientAccessors(writer.layoutStr, writer.offset, - reader.layoutStr + layoutStringHeaderSize, fieldType); + swift_cvw_resolve_resilientAccessors( + writer.layoutStr, writer.offset, + reader.layoutStr + layoutStringHeaderSize, fieldType); } if (offset) { @@ -8242,6 +8257,7 @@ const HeapObject *swift_getKeyPathImpl(const void *pattern, #define OVERRIDE_KEYPATH COMPATIBILITY_OVERRIDE #define OVERRIDE_WITNESSTABLE COMPATIBILITY_OVERRIDE +#define OVERRIDE_CVW_METADATA COMPATIBILITY_OVERRIDE #include "../CompatibilityOverride/CompatibilityOverrideIncludePath.h" // Autolink with libc++, for cases where libswiftCore is linked statically. diff --git a/test/Backtracing/BacktraceWithLimit.swift b/test/Backtracing/BacktraceWithLimit.swift index c91cd29d60c68..8c4963eb013f1 100644 --- a/test/Backtracing/BacktraceWithLimit.swift +++ b/test/Backtracing/BacktraceWithLimit.swift @@ -9,7 +9,7 @@ // REQUIRES: backtracing // REQUIRES: OS=macosx || OS=linux-gnu -import _Backtracing +import Runtime func doFrames(_ count: Int) { if count <= 0 { diff --git a/test/Backtracing/BacktraceWithLimitAndTop.swift b/test/Backtracing/BacktraceWithLimitAndTop.swift index ccd067d1346b9..618e24606e347 100644 --- a/test/Backtracing/BacktraceWithLimitAndTop.swift +++ b/test/Backtracing/BacktraceWithLimitAndTop.swift @@ -9,7 +9,7 @@ // REQUIRES: backtracing // REQUIRES: OS=macosx || OS=linux-gnu -import _Backtracing +import Runtime func doFrames(_ count: Int, limit: Int, top: Int) { if count <= 0 { diff --git a/test/Backtracing/CodableBacktrace.swift b/test/Backtracing/CodableBacktrace.swift new file mode 100644 index 0000000000000..47e4a4ba79083 --- /dev/null +++ b/test/Backtracing/CodableBacktrace.swift @@ -0,0 +1,67 @@ +// RUN: %empty-directory(%t) +// RUN: %target-build-swift %s -target %target-cpu-macos15.0 -Xfrontend -parse-as-library -Onone -o %t/CodableBacktrace +// RUN: %target-codesign %t/CodableBacktrace +// RUN: %target-run %t/CodableBacktrace | %FileCheck %s + +// REQUIRES: executable_test +// REQUIRES: backtracing +// REQUIRES: OS=macosx + +// UNSUPPORTED: use_os_stdlib +// UNSUPPORTED: back_deployment_runtime + +import Runtime +import Foundation + +func level1() { + level2() +} + +func level2() { + level3() +} + +func level3() { + level4() +} + +func level4() { + level5() +} + +func level5() { + let backtrace = try! Backtrace.capture() + + let encoder = JSONEncoder() + encoder.outputFormatting = [.prettyPrinted,.sortedKeys,.withoutEscapingSlashes] + + let data = try! encoder.encode(backtrace) + let json = String(data: data, encoding: .utf8)! + + print(json) + + // CHECK: { + // CHECK: "architecture" : "{{.*}}", + // CHECK: "backtrace" : "{{[A-Za-z0-9+/]*}}" + // CHECK: } + + let decoder = JSONDecoder() + + let bt2 = try! decoder.decode(Backtrace.self, from: data) + + print(bt2) + + // CHECK: 0{{[ \t]+}}0x{{[0-9a-f]+}} [ra] + // CHECK-NEXT: 1{{[ \t]+}}0x{{[0-9a-f]+}} [ra] + // CHECK-NEXT: 2{{[ \t]+}}0x{{[0-9a-f]+}} [ra] + // CHECK-NEXT: 3{{[ \t]+}}0x{{[0-9a-f]+}} [ra] + // CHECK-NEXT: 4{{[ \t]+}}0x{{[0-9a-f]+}} [ra] + // CHECK-NEXT: 5{{[ \t]+}}0x{{[0-9a-f]+}} [ra] +} + +@main +struct CodableBacktrace { + static func main() { + level1() + } +} diff --git a/test/Backtracing/CompactImageMap.swift b/test/Backtracing/CompactImageMap.swift new file mode 100644 index 0000000000000..226a1c48d19e4 --- /dev/null +++ b/test/Backtracing/CompactImageMap.swift @@ -0,0 +1,64 @@ +// RUN: %empty-directory(%t) +// RUN: %target-build-swift %s -parse-as-library -Onone -o %t/ImageMap +// RUN: %target-codesign %t/ImageMap +// RUN: %target-run %t/ImageMap | tee %t/ImageMap.out +// RUN: cat %t/ImageMap.out | %FileCheck %s + +// UNSUPPORTED: use_os_stdlib +// UNSUPPORTED: back_deployment_runtime +// REQUIRES: executable_test +// REQUIRES: backtracing +// REQUIRES: OS=macosx || OS=linux-gnu + +import Runtime +@_spi(Internal) import Runtime + +@main +struct ImageMapTest { + static func main() { + let map = ImageMap.capture() + let encoder = CompactImageMapFormat.Encoder(map) + let encoded = Array(encoder) + + print(map) + + print("Encoded \(map.count) images in \(encoded.count) bytes") + + for (ndx, byte) in encoded.enumerated() { + let separator: String + if ((ndx + 1) & 0xf) == 0 { + separator = "\n" + } else { + separator = " " + } + + var hex = String(byte, radix: 16) + if hex.count < 2 { + hex = "0" + hex + } + print(hex, terminator: separator) + } + print("") + + guard let decodedMap = ImageMap(compactImageMapData: encoded) else { + print("Unable to decode") + return + } + + print("Decoded \(decodedMap.count) images") + + print(decodedMap) + + if map.description != decodedMap.description { + print("Maps do not match") + } else { + print("Maps match") + } + + // CHECK: Encoded [[COUNT:[0-9]+]] images in [[BYTES:[0-9]+]] bytes + // CHECK-NOT: Unable to decode + // CHECK: Decoded [[COUNT]] images + // CHECK-NOT: Maps do not match + // CHECK: Maps match + } +} diff --git a/test/Backtracing/DwarfReader.swift b/test/Backtracing/DwarfReader.swift index 53ac43b45d8fe..6c1d71fc3f0b2 100644 --- a/test/Backtracing/DwarfReader.swift +++ b/test/Backtracing/DwarfReader.swift @@ -6,7 +6,7 @@ // REQUIRES: OS=linux-gnu // REQUIRES: backtracing -@_spi(DwarfTest) import _Backtracing +@_spi(DwarfTest) import Runtime #if canImport(Darwin) import Darwin #elseif canImport(SwiftWASILibc) diff --git a/test/Backtracing/ElfReader.swift b/test/Backtracing/ElfReader.swift index dbd8b5b68c6fe..0d011617bd946 100644 --- a/test/Backtracing/ElfReader.swift +++ b/test/Backtracing/ElfReader.swift @@ -15,7 +15,7 @@ // REQUIRES: OS=linux-gnu // REQUIRES: backtracing -@_spi(ElfTest) import _Backtracing +@_spi(ElfTest) import Runtime #if canImport(Darwin) import Darwin #elseif canImport(SwiftWASILibc) diff --git a/test/Backtracing/ImageMap.swift b/test/Backtracing/ImageMap.swift new file mode 100644 index 0000000000000..d8e0c9e98c4a8 --- /dev/null +++ b/test/Backtracing/ImageMap.swift @@ -0,0 +1,27 @@ +// RUN: %empty-directory(%t) +// RUN: %target-build-swift %s -parse-as-library -Onone -o %t/ImageMap +// RUN: %target-codesign %t/ImageMap +// RUN: %target-run %t/ImageMap | %FileCheck %s + +// UNSUPPORTED: use_os_stdlib +// UNSUPPORTED: back_deployment_runtime +// REQUIRES: executable_test +// REQUIRES: backtracing +// REQUIRES: OS=macosx || OS=linux-gnu + +import Runtime + +@main +struct ImageMapTest { + static func main() { + let map = ImageMap.capture() + + // We expect ImageMap, followed by one or more additional lines + + // CHECK: {{0x[0-9a-f]*-0x[0-9a-f]*}} {{(|[0-9a-f]*)}} ImageMap {{.*}}/ImageMap + // CHECK-NEXT: {{0x[0-9a-f]*-0x[0-9a-f]*}} {{(|[0-9a-f]*)}} [[NAME:[^ ]*]] {{.*}}/[[NAME]] + print(map) + } +} + + diff --git a/test/Backtracing/SimpleAsyncBacktrace.swift b/test/Backtracing/SimpleAsyncBacktrace.swift index 592a080fba9e6..941466aae1782 100644 --- a/test/Backtracing/SimpleAsyncBacktrace.swift +++ b/test/Backtracing/SimpleAsyncBacktrace.swift @@ -12,7 +12,7 @@ // UNSUPPORTED: use_os_stdlib // UNSUPPORTED: back_deployment_runtime -import _Backtracing +import Runtime @available(SwiftStdlib 5.1, *) func level1() async { diff --git a/test/Backtracing/SimpleBacktrace.swift b/test/Backtracing/SimpleBacktrace.swift index 1695ff896b7f1..acccd40c75a04 100644 --- a/test/Backtracing/SimpleBacktrace.swift +++ b/test/Backtracing/SimpleBacktrace.swift @@ -1,5 +1,5 @@ // RUN: %empty-directory(%t) -// RUN: %target-build-swift %s -Xfrontend -enable-implicit-backtracing-module-import -parse-as-library -Onone -o %t/SimpleBacktrace +// RUN: %target-build-swift %s -Xfrontend -parse-as-library -Onone -o %t/SimpleBacktrace // RUN: %target-codesign %t/SimpleBacktrace // RUN: %target-run %t/SimpleBacktrace | %FileCheck %s @@ -10,6 +10,8 @@ // UNSUPPORTED: use_os_stdlib // UNSUPPORTED: back_deployment_runtime +import Runtime + func level1() { level2() } diff --git a/test/Backtracing/SymbolicatedBacktrace.swift b/test/Backtracing/SymbolicatedBacktrace.swift index f1251b82df6ba..0d11b30ff5d9e 100644 --- a/test/Backtracing/SymbolicatedBacktrace.swift +++ b/test/Backtracing/SymbolicatedBacktrace.swift @@ -9,7 +9,7 @@ // REQUIRES: backtracing // REQUIRES: OS=macosx || OS=linux-gnu -import _Backtracing +import Runtime func kablam() { kerpow() @@ -32,7 +32,9 @@ func splat() { } func pow() { - let backtrace = try! Backtrace.capture().symbolicated(useSymbolCache: false)! + let backtrace = try! Backtrace.capture().symbolicated( + options: [ .showInlineFrames, .showSourceLocations ] + )! // CHECK: 0{{[ \t]+}}0x{{[0-9a-f]+}} [ra] [0] SymbolicatedBacktrace pow() // CHECK: 1{{[ \t]+}}0x{{[0-9a-f]+}} [ra] [0] SymbolicatedBacktrace splat() diff --git a/test/Backtracing/SymbolicatedBacktraceInline.swift b/test/Backtracing/SymbolicatedBacktraceInline.swift index 3f7065dd0e769..2990bb6f029e1 100644 --- a/test/Backtracing/SymbolicatedBacktraceInline.swift +++ b/test/Backtracing/SymbolicatedBacktraceInline.swift @@ -13,7 +13,7 @@ // which presumably doesn't have a frame pointer. When we add the Dwarf EH // unwinder, we should be able to turn this test on. -import _Backtracing +import Runtime func kablam() { kerpow() @@ -36,7 +36,9 @@ func splat() { } func pow() { - let backtrace = try! Backtrace.capture().symbolicated(useSymbolCache: false)! + let backtrace = try! Backtrace.capture().symbolicated( + options: [ .showInlineFrames, .showSourceLocations ] + )! // CHECK: 0{{[ \t]+}}0x{{[0-9a-f]+}} [ra] [0] SymbolicatedBacktraceInline pow() // CHECK: 1{{[ \t]+}}0x{{[0-9a-f]+}} [ra] [inlined] [0] SymbolicatedBacktraceInline splat() diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index b8ca503f601e6..503a8748ae64b 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -82,6 +82,14 @@ function(get_test_dependencies SDK result_var_name) set(deps_binaries) + if (SWIFT_BUILD_LIBEXEC AND SWIFT_ENABLE_BACKTRACING) + # Only add if `swift-backtrace` builds for this SDK + if (TARGET "swift-backtrace-${SDK}") + list(APPEND deps_binaries + "swift-backtrace-${SDK}") + endif() + endif() + if (SWIFT_INCLUDE_TOOLS) list(APPEND deps_binaries libMockPlugin @@ -251,6 +259,7 @@ normalize_boolean_spelling(SWIFT_STDLIB_ENABLE_UNICODE_DATA) normalize_boolean_spelling(SWIFT_ENABLE_DISPATCH) normalize_boolean_spelling(SWIFT_STDLIB_ENABLE_OBJC_INTEROP) normalize_boolean_spelling(SWIFT_ENABLE_BACKTRACING) +normalize_boolean_spelling(SWIFT_ENABLE_RUNTIME_MODULE) normalize_boolean_spelling(SWIFT_BUILD_SWIFT_SYNTAX) normalize_boolean_spelling(SWIFT_ENABLE_SYNCHRONIZATION) normalize_boolean_spelling(SWIFT_ENABLE_VOLATILE) @@ -473,6 +482,10 @@ foreach(SDK ${SWIFT_SDKS}) list(APPEND LIT_ARGS "--param" "volatile") endif() + if(SWIFT_ENABLE_RUNTIME_MODULE) + list(APPEND LIT_ARGS "--param" "runtime_module") + endif() + if(SWIFT_BUILD_REMOTE_MIRROR) list(APPEND LIT_ARGS "--param" "remote_mirror") endif() diff --git a/test/Concurrency/sendable_checking_captures_swift5.swift b/test/Concurrency/sendable_checking_captures_swift5.swift index 6006bb1ab6940..41eea0915089f 100644 --- a/test/Concurrency/sendable_checking_captures_swift5.swift +++ b/test/Concurrency/sendable_checking_captures_swift5.swift @@ -69,3 +69,28 @@ func testPreconcurrencyDowngrade(ns: NotSendable) { // expected-complete-warning@-1 {{mutation of captured var 'x' in concurrently-executing code}} } } + +// rdar://136766795 +do { + class Class { + static func test() -> @Sendable () -> Void { + { + // OK, an unbound reference is sendable. + let _ = Class.method + } + } + + func method() {} + } +} + +do { + class Class {} + // expected-complete-note@-1 {{class 'Class' does not conform to the 'Sendable' protocol}} + + func test(_: @autoclosure @Sendable () -> Class) {} + + let c: Class + test(c) + // expected-complete-warning@-1:8 {{implicit capture of 'c' requires that 'Class' conforms to `Sendable`; this is an error in the Swift 6 language mode}} +} diff --git a/test/Constraints/implicit_double_cgfloat_conversion.swift b/test/Constraints/implicit_double_cgfloat_conversion.swift index 83c6955851b58..b34d8a88e566d 100644 --- a/test/Constraints/implicit_double_cgfloat_conversion.swift +++ b/test/Constraints/implicit_double_cgfloat_conversion.swift @@ -366,3 +366,18 @@ func test_cgfloat_operator_is_attempted_with_literal_arguments(v: CGFloat?) { let ratio = v ?? (2.0 / 16.0) let _: CGFloat = ratio // Ok } + +// Make sure that optimizer doesn't favor CGFloat -> Double conversion +// in presence of CGFloat initializer, otherwise it could lead to ambiguities. +func test_explicit_cgfloat_use_avoids_ambiguity(v: Int) { + func test(_: CGFloat) -> CGFloat { 0 } + func test(_: Double) -> Double { 0 } + + func hasCGFloatElement(_: C) where C.Element == CGFloat {} + + let arr = [test(CGFloat(v))] + hasCGFloatElement(arr) // Ok + + var total = 0.0 // This is Double by default + total += test(CGFloat(v)) + CGFloat(v) // Ok +} diff --git a/test/Constraints/overload_filtering_objc.swift b/test/Constraints/overload_filtering_objc.swift index df7f1e55bf40e..6826c6a3cdaa1 100644 --- a/test/Constraints/overload_filtering_objc.swift +++ b/test/Constraints/overload_filtering_objc.swift @@ -23,23 +23,3 @@ func testOptional(obj: P) { _ = obj.opt?(1) } - -func test_double_cgfloat_conversion_filtering(d: Double, cgf: CGFloat) { - // CHECK: [favored] $T{{.*}} bound to decl CoreGraphics.(file).CGFloat.init(_:)@{{.*}} : (CGFloat.Type) -> (Double) -> CGFloat - let _: CGFloat = d - - // CHECK: [favored] $T{{.*}} bound to decl CoreGraphics.(file).Double extension.init(_:)@{{.*}} : (Double.Type) -> (CGFloat) -> Double - let _: Double = cgf - - func test_optional_cgf(_: CGFloat??) { - } - - func test_optional_double(_: Double??) { - } - - // CHECK: [favored] $T{{.*}} bound to decl CoreGraphics.(file).CGFloat.init(_:)@{{.*}} : (CGFloat.Type) -> (Double) -> CGFloat - test_optional_cgf(d) - - // CHECK: [favored] $T{{.*}} bound to decl CoreGraphics.(file).Double extension.init(_:)@{{.*}} : (Double.Type) -> (CGFloat) -> Double - test_optional_double(cgf) -} diff --git a/test/Driver/sanitize_coverage.swift b/test/Driver/sanitize_coverage.swift index e41562a7a4c2f..5953c6f97c2f5 100644 --- a/test/Driver/sanitize_coverage.swift +++ b/test/Driver/sanitize_coverage.swift @@ -1,3 +1,5 @@ +// XFAIL: OS=windows-msvc + // Different sanitizer coverage types // RUN: %swiftc_driver -driver-print-jobs -sanitize-coverage=func -sanitize=address %s | %FileCheck -check-prefix=SANCOV_FUNC %s // RUN: %swiftc_driver -driver-print-jobs -sanitize-coverage=bb -sanitize=address %s | %FileCheck -check-prefix=SANCOV_BB %s diff --git a/test/IRGen/address_sanitizer_use_odr_indicator.swift b/test/IRGen/address_sanitizer_use_odr_indicator.swift index 1ed723e25c08e..298e5cc7c8e90 100644 --- a/test/IRGen/address_sanitizer_use_odr_indicator.swift +++ b/test/IRGen/address_sanitizer_use_odr_indicator.swift @@ -1,3 +1,4 @@ +// XFAIL: OS=windows-msvc // REQUIRES: asan_runtime // Default instrumentation that does not use ODR indicators diff --git a/test/IRGen/layout_string_witnesses_noncopyable.swift b/test/IRGen/layout_string_witnesses_noncopyable.swift index 4d37ddcc6d5f1..8919be8852914 100644 --- a/test/IRGen/layout_string_witnesses_noncopyable.swift +++ b/test/IRGen/layout_string_witnesses_noncopyable.swift @@ -3,31 +3,31 @@ // REQUIRES: swift_feature_LayoutStringValueWitnesses // REQUIRES: swift_feature_LayoutStringValueWitnessesInstantiation -// CHECK-NOT: @"$s3Foo7GenericVWV" = {{.*}}ptr @swift_generic{{.*$}} +// CHECK-NOT: @"$s3Foo7GenericVWV" = {{.*}}ptr @swift_cvw{{.*$}} struct Generic: ~Copyable { let x: T let y: Int } -// CHECK-NOT: @"$s3Foo13SinglePayloadOWV" = {{.*}}ptr @swift_generic{{.*$}} +// CHECK-NOT: @"$s3Foo13SinglePayloadOWV" = {{.*}}ptr @swift_cvw{{.*$}} enum SinglePayload: ~Copyable { case x(AnyObject) case y } -// CHECK-NOT: @"$s3Foo12MultiPayloadOWV" = {{.*}}ptr @swift_generic{{.*$}} +// CHECK-NOT: @"$s3Foo12MultiPayloadOWV" = {{.*}}ptr @swift_cvw{{.*$}} enum MultiPayload: ~Copyable { case x(AnyObject) case y(AnyObject) } -// CHECK-NOT: @"$s3Foo20SinglePayloadGenericOWV" = {{.*}}ptr @swift_generic{{.*$}} +// CHECK-NOT: @"$s3Foo20SinglePayloadGenericOWV" = {{.*}}ptr @swift_cvw{{.*$}} enum SinglePayloadGeneric: ~Copyable { case x(T) case y } -// CHECK-NOT: @"$s3Foo19MultiPayloadGenericOWV" = {{.*}}ptr @swift_generic{{.*$}} +// CHECK-NOT: @"$s3Foo19MultiPayloadGenericOWV" = {{.*}}ptr @swift_cvw{{.*$}} enum MultiPayloadGeneric: ~Copyable { case x(T) case y(T) diff --git a/test/Interop/Cxx/objc-correctness/simd_quatf.swift b/test/Interop/Cxx/objc-correctness/simd_quatf.swift deleted file mode 100644 index 67adb004f0f0f..0000000000000 --- a/test/Interop/Cxx/objc-correctness/simd_quatf.swift +++ /dev/null @@ -1,8 +0,0 @@ -// RUN: %target-swift-frontend -typecheck -verify -I %S/Inputs -cxx-interoperability-mode=default %s - -// REQUIRES: objc_interop -// REQUIRES: VENDOR=apple - -import simd - -var _: simd.simd_quatf! = nil diff --git a/test/Interpreter/indirect_enum.swift b/test/Interpreter/indirect_enum.swift index 3f5359ed360a7..c96ba96730c61 100644 --- a/test/Interpreter/indirect_enum.swift +++ b/test/Interpreter/indirect_enum.swift @@ -1,3 +1,5 @@ +// XFAIL: OS=windows-msvc + // RUN: %target-swiftc_driver %s -g -sanitize=address -o %t_asan-binary // RUN: %target-codesign %t_asan-binary // RUN: env ASAN_OPTIONS=detect_leaks=0 %target-run %t_asan-binary diff --git a/test/Reflection/typeref_decoding_asan.swift b/test/Reflection/typeref_decoding_asan.swift index 2bd6be187db44..0e7d4498a3619 100644 --- a/test/Reflection/typeref_decoding_asan.swift +++ b/test/Reflection/typeref_decoding_asan.swift @@ -1,4 +1,5 @@ // UNSUPPORTED: OS=linux-gnu && CPU=aarch64 +// XFAIL: OS=windows-msvc // rdar://100805115 // UNSUPPORTED: CPU=arm64e diff --git a/test/Sanitizers/asan/asan.swift b/test/Sanitizers/asan/asan.swift index 3b2005523a009..b6e38598a4636 100644 --- a/test/Sanitizers/asan/asan.swift +++ b/test/Sanitizers/asan/asan.swift @@ -1,3 +1,5 @@ +// XFAIL: OS=windows-msvc + // RUN: %target-swiftc_driver %s -g -sanitize=address -o %t_asan-binary // RUN: %target-codesign %t_asan-binary // RUN: env %env-ASAN_OPTIONS=abort_on_error=0 not %target-run %t_asan-binary 2>&1 | %FileCheck %s diff --git a/test/Sanitizers/sanitizer_coverage.swift b/test/Sanitizers/sanitizer_coverage.swift index 8044beeb37033..ee0abeb62397c 100644 --- a/test/Sanitizers/sanitizer_coverage.swift +++ b/test/Sanitizers/sanitizer_coverage.swift @@ -9,6 +9,7 @@ // For now restrict this test to platforms where we know this test will pass // REQUIRES: CPU=x86_64 // UNSUPPORTED: remote_run +// XFAIL: OS=windows-msvc func sayHello() { print("Hello") diff --git a/test/abi/macOS/arm64/stdlib.swift b/test/abi/macOS/arm64/stdlib.swift index fccd9770665e4..3231db22b0b68 100644 --- a/test/abi/macOS/arm64/stdlib.swift +++ b/test/abi/macOS/arm64/stdlib.swift @@ -845,3 +845,27 @@ Added: _$ss4SlabVsRi__rlE8_storagexq_BVvr // Shared string creation for Foundation Added: _$ss40_SwiftCreateImmortalString_ForFoundation6buffer7isASCIISSSgSRys5UInt8VG_SbtF + +// Compact value witnesses +Added: _swift_cvw_allocateGenericClassMetadataWithLayoutString +Added: _swift_cvw_allocateGenericValueMetadataWithLayoutString +Added: _swift_cvw_assignWithCopy +Added: _swift_cvw_assignWithTake +Added: _swift_cvw_destroy +Added: _swift_cvw_enumFn_getEnumTag +Added: _swift_cvw_enumSimple_destructiveInjectEnumTag +Added: _swift_cvw_enumSimple_getEnumTag +Added: _swift_cvw_initEnumMetadataMultiPayloadWithLayoutString +Added: _swift_cvw_initEnumMetadataSingleCaseWithLayoutString +Added: _swift_cvw_initEnumMetadataSinglePayloadWithLayoutString +Added: _swift_cvw_initStructMetadataWithLayoutString +Added: _swift_cvw_initWithCopy +Added: _swift_cvw_initWithTake +Added: _swift_cvw_initializeBufferWithCopyOfBuffer +Added: _swift_cvw_instantiateLayoutString +Added: _swift_cvw_multiPayloadEnumGeneric_destructiveInjectEnumTag +Added: _swift_cvw_multiPayloadEnumGeneric_getEnumTag +Added: _swift_cvw_singlePayloadEnumGeneric_destructiveInjectEnumTag +Added: _swift_cvw_singlePayloadEnumGeneric_getEnumTag +Added: _swift_cvw_singletonEnum_destructiveInjectEnumTag +Added: _swift_cvw_singletonEnum_getEnumTag diff --git a/test/abi/macOS/x86_64/stdlib.swift b/test/abi/macOS/x86_64/stdlib.swift index 98c531f72cde8..40b7487f8d46d 100644 --- a/test/abi/macOS/x86_64/stdlib.swift +++ b/test/abi/macOS/x86_64/stdlib.swift @@ -846,3 +846,27 @@ Added: _$ss4SlabVsRi__rlE8_storagexq_BVvr // Shared string creation for Foundation Added: _$ss40_SwiftCreateImmortalString_ForFoundation6buffer7isASCIISSSgSRys5UInt8VG_SbtF + +// Compact value witnesses +Added: _swift_cvw_allocateGenericClassMetadataWithLayoutString +Added: _swift_cvw_allocateGenericValueMetadataWithLayoutString +Added: _swift_cvw_assignWithCopy +Added: _swift_cvw_assignWithTake +Added: _swift_cvw_destroy +Added: _swift_cvw_enumFn_getEnumTag +Added: _swift_cvw_enumSimple_destructiveInjectEnumTag +Added: _swift_cvw_enumSimple_getEnumTag +Added: _swift_cvw_initEnumMetadataMultiPayloadWithLayoutString +Added: _swift_cvw_initEnumMetadataSingleCaseWithLayoutString +Added: _swift_cvw_initEnumMetadataSinglePayloadWithLayoutString +Added: _swift_cvw_initStructMetadataWithLayoutString +Added: _swift_cvw_initWithCopy +Added: _swift_cvw_initWithTake +Added: _swift_cvw_initializeBufferWithCopyOfBuffer +Added: _swift_cvw_instantiateLayoutString +Added: _swift_cvw_multiPayloadEnumGeneric_destructiveInjectEnumTag +Added: _swift_cvw_multiPayloadEnumGeneric_getEnumTag +Added: _swift_cvw_singlePayloadEnumGeneric_destructiveInjectEnumTag +Added: _swift_cvw_singlePayloadEnumGeneric_getEnumTag +Added: _swift_cvw_singletonEnum_destructiveInjectEnumTag +Added: _swift_cvw_singletonEnum_getEnumTag diff --git a/test/embedded/import-vtables.swift b/test/embedded/import-vtables.swift new file mode 100644 index 0000000000000..2007d75f02797 --- /dev/null +++ b/test/embedded/import-vtables.swift @@ -0,0 +1,57 @@ +// RUN: %empty-directory(%t) +// RUN: %{python} %utils/split_file.py -o %t %s + +// RUN: %target-swift-frontend -emit-module -o %t/MyModule.swiftmodule %t/MyModule.swift -enable-experimental-feature Embedded -parse-as-library +// RUN: %target-swift-frontend -c -I %t %t/Main.swift -enable-experimental-feature Embedded -o %t/a.o +// RUN: %target-clang -x c -c %S/Inputs/print.c -o %t/print.o +// RUN: %target-clang %t/a.o %t/print.o -o %t/a.out +// RUN: %target-run %t/a.out | %FileCheck %s + +// REQUIRES: swift_in_compiler +// REQUIRES: executable_test +// REQUIRES: OS=macosx || OS=linux-gnu +// REQUIRES: swift_feature_Embedded + +// BEGIN MyModule.swift + +public enum MyEnum { + case aCase +} + +open class BaseClass { + open var type: MyEnum? { nil } +} + +public final class DerivedClass: BaseClass { + public override var type: MyEnum { .aCase } + + public override init() { + } +} + +open class BaseGenericClass { + open var type: MyEnum? { nil } +} + +public final class DerivedGenericClass: BaseGenericClass { + public override var type: MyEnum { .aCase } + + public override init() { + } +} + +public func createGenClass() -> BaseGenericClass { + return DerivedGenericClass() +} + +// BEGIN Main.swift + +import MyModule + +let dc = DerivedClass() +let dgc = DerivedGenericClass() +let gc = createGenClass() +print("OK!") + +// CHECK: OK! + diff --git a/test/embedded/without-actually-escaping.swift b/test/embedded/without-actually-escaping.swift new file mode 100644 index 0000000000000..48e1cd9adc6b5 --- /dev/null +++ b/test/embedded/without-actually-escaping.swift @@ -0,0 +1,42 @@ +// RUN: %empty-directory(%t) +// RUN: %target-clang -x c -c %S/Inputs/unbuffered-putchar.c -o %t/unbuffered-putchar.o + +// RUN: %target-build-swift -enable-experimental-feature Embedded -wmo %s -Xlinker %t/unbuffered-putchar.o -o %t/a.out +// RUN: not --crash %t/a.out 2>&1 | %FileCheck %s + +// REQUIRES: swift_in_compiler +// REQUIRES: executable_test +// REQUIRES: swift_test_mode_optimize_none +// REQUIRES: swift_feature_Embedded + +var sink: ()->() = {} + +func dontEscape(f: () -> ()) { + withoutActuallyEscaping(f) { + $0() + } +} + +func dontEscape2(f: () -> ()) { + withoutActuallyEscaping(f) { + sink = $0 + sink() + sink = {} + } +} + +func letEscape(f: () -> ()) { + withoutActuallyEscaping(f) { + sink = $0 + sink() + } +} + +dontEscape(f: { print("A") }) +dontEscape2(f: { print("B") }) +letEscape(f: { print("C") }) + +// CHECK: A +// CHECK: B +// CHECK: C +// CHECK: non-escaping closure escaped diff --git a/test/lit.cfg b/test/lit.cfg index dcb96fded8c20..cd6931963bc61 100644 --- a/test/lit.cfg +++ b/test/lit.cfg @@ -1326,7 +1326,7 @@ if run_vendor == 'apple': "swiftDarwin", "swiftSwiftPrivateThreadExtras", "swiftSwiftOnoneSupport", "swift_Concurrency"] if backtracing is not None: - libraries.append('swift_Backtracing') + libraries.append('swiftRuntime') for library in libraries: swift_execution_tests_extra_flags += ' -Xlinker -l%s'% library @@ -2208,12 +2208,12 @@ config.substitutions.append(('%concurrency_module', concurrency_module)) config.substitutions.append(('%/concurrency_module', '/'.join(os.path.normpath(concurrency_module).split(os.sep)))) -# Add 'backtracing_module' as the path to the _Backtracing .swiftmodule file -backtracing_module = os.path.join(stdlib_dir, "_Backtracing.swiftmodule", +# Add 'runtime_module' as the path to the Runtime .swiftmodule file +runtime_module = os.path.join(stdlib_dir, "Runtime.swiftmodule", target_specific_module_triple + ".swiftmodule") -config.substitutions.append(('%backtracing_module', backtracing_module)) -config.substitutions.append(('%/backtracing_module', - '/'.join(os.path.normpath(backtracing_module).split(os.sep)))) +config.substitutions.append(('%runtime_module', runtime_module)) +config.substitutions.append(('%/runtime_module', + '/'.join(os.path.normpath(runtime_module).split(os.sep)))) # Add 'distributed_module' as the path to the Distributed .swiftmodule file distributed_module = os.path.join(stdlib_dir, "Distributed.swiftmodule", diff --git a/tools/SourceKit/tools/sourcekitd-test/Options.td b/tools/SourceKit/tools/sourcekitd-test/Options.td index ef2f8c6926eb5..774bfa04c6b38 100644 --- a/tools/SourceKit/tools/sourcekitd-test/Options.td +++ b/tools/SourceKit/tools/sourcekitd-test/Options.td @@ -116,14 +116,6 @@ def disable_implicit_string_processing_module_import : Flag<["-"], "disable-implicit-string-processing-module-import">, HelpText<"Disable implicit import of the _StringProcessing module">; -def enable_implicit_backtracing_module_import : Flag<["-"], - "enable-implicit-backtracing-module-import">, - HelpText<"Enable implicit import of the _Backtracing module">; - -def disable_implicit_backtracing_module_import : Flag<["-"], - "disable-implicit-backtracing-module-import">, - HelpText<"Disable implicit import of the _Backtracing module">; - def end_pos : Separate<["-"], "end-pos">, HelpText<"line:col">; def end_pos_EQ : Joined<["-"], "end-pos=">, Alias; diff --git a/tools/SourceKit/tools/sourcekitd-test/TestOptions.cpp b/tools/SourceKit/tools/sourcekitd-test/TestOptions.cpp index 2fc43eade84f2..14345dfbb40f6 100644 --- a/tools/SourceKit/tools/sourcekitd-test/TestOptions.cpp +++ b/tools/SourceKit/tools/sourcekitd-test/TestOptions.cpp @@ -464,10 +464,6 @@ bool TestOptions::parseArgs(llvm::ArrayRef Args) { DisableImplicitStringProcessingModuleImport = true; break; - case OPT_disable_implicit_backtracing_module_import: - DisableImplicitBacktracingModuleImport = true; - break; - case OPT_UNKNOWN: llvm::errs() << "error: unknown argument: " << InputArg->getAsString(ParsedArgs) << '\n' diff --git a/tools/SourceKit/tools/sourcekitd-test/TestOptions.h b/tools/SourceKit/tools/sourcekitd-test/TestOptions.h index 9f85fab2b764a..a962e3128253c 100644 --- a/tools/SourceKit/tools/sourcekitd-test/TestOptions.h +++ b/tools/SourceKit/tools/sourcekitd-test/TestOptions.h @@ -135,8 +135,6 @@ struct TestOptions { bool measureInstructions = false; bool DisableImplicitConcurrencyModuleImport = false; bool DisableImplicitStringProcessingModuleImport = false; - bool EnableImplicitBacktracingModuleImport = false; - bool DisableImplicitBacktracingModuleImport = false; std::optional CompletionCheckDependencyInterval; unsigned repeatRequest = 1; struct VFSFile { diff --git a/tools/SourceKit/tools/sourcekitd-test/sourcekitd-test.cpp b/tools/SourceKit/tools/sourcekitd-test/sourcekitd-test.cpp index b2468cc232319..c79a8f297c03e 100644 --- a/tools/SourceKit/tools/sourcekitd-test/sourcekitd-test.cpp +++ b/tools/SourceKit/tools/sourcekitd-test/sourcekitd-test.cpp @@ -1222,20 +1222,6 @@ static int handleTestInvocation(TestOptions Opts, TestOptions &InitOpts) { sourcekitd_request_array_set_string(Args, SOURCEKITD_ARRAY_APPEND, "-disable-implicit-string-processing-module-import"); } - if (Opts.EnableImplicitBacktracingModuleImport && - !compilerArgsAreClang) { - sourcekitd_request_array_set_string(Args, SOURCEKITD_ARRAY_APPEND, - "-Xfrontend"); - sourcekitd_request_array_set_string(Args, SOURCEKITD_ARRAY_APPEND, - "-enable-implicit-backtracing-module-import"); - } - if (Opts.DisableImplicitBacktracingModuleImport && - !compilerArgsAreClang) { - sourcekitd_request_array_set_string(Args, SOURCEKITD_ARRAY_APPEND, - "-Xfrontend"); - sourcekitd_request_array_set_string(Args, SOURCEKITD_ARRAY_APPEND, - "-disable-implicit-backtracing-module-import"); - } for (auto Arg : Opts.CompilerArgs) sourcekitd_request_array_set_string(Args, SOURCEKITD_ARRAY_APPEND, Arg); diff --git a/tools/swift-ide-test/swift-ide-test.cpp b/tools/swift-ide-test/swift-ide-test.cpp index 2ff77fb1193ab..c8ce3eb92ce82 100644 --- a/tools/swift-ide-test/swift-ide-test.cpp +++ b/tools/swift-ide-test/swift-ide-test.cpp @@ -833,16 +833,6 @@ DisableImplicitStringProcessingImport("disable-implicit-string-processing-module llvm::cl::desc("Disable implicit import of _StringProcessing module"), llvm::cl::init(false)); -static llvm::cl::opt -EnableImplicitBacktracingImport("enable-implicit-backtracing-module-import", - llvm::cl::desc("Enable implicit import of _Backtracing module"), - llvm::cl::init(false)); - -static llvm::cl::opt -DisableImplicitBacktracingImport("disable-implicit-backtracing-module-import", - llvm::cl::desc("Disable implicit import of _Backtracing module"), - llvm::cl::init(false)); - static llvm::cl::opt EnableExperimentalNamedOpaqueTypes( "enable-experimental-named-opaque-types", llvm::cl::desc("Enable experimental support for named opaque result types"), @@ -4470,13 +4460,6 @@ int main(int argc, char *argv[]) { if (options::DisableImplicitStringProcessingImport) { InitInvok.getLangOptions().DisableImplicitStringProcessingModuleImport = true; } - if (options::DisableImplicitBacktracingImport) { - InitInvok.getLangOptions().DisableImplicitBacktracingModuleImport = true; - } else if (options::EnableImplicitBacktracingImport) { - InitInvok.getLangOptions().DisableImplicitBacktracingModuleImport = false; - } else { - InitInvok.getLangOptions().DisableImplicitBacktracingModuleImport = true; - } if (options::EnableExperimentalNamedOpaqueTypes) { InitInvok.getLangOptions().enableFeature(Feature::NamedOpaqueTypes); diff --git a/unittests/runtime/CMakeLists.txt b/unittests/runtime/CMakeLists.txt index 4a9d32e5e2491..920452c17fe7d 100644 --- a/unittests/runtime/CMakeLists.txt +++ b/unittests/runtime/CMakeLists.txt @@ -116,7 +116,7 @@ if(("${SWIFT_HOST_VARIANT_SDK}" STREQUAL "${SWIFT_PRIMARY_VARIANT_SDK}") AND # The runtime tests link to internal runtime symbols, which aren't exported # from the swiftCore dylib, so we need to link to both the runtime archive # and the stdlib. - $ + $ $ $ ) diff --git a/unittests/runtime/LongTests/CMakeLists.txt b/unittests/runtime/LongTests/CMakeLists.txt index e16bc0d540b4e..74709e914cd18 100644 --- a/unittests/runtime/LongTests/CMakeLists.txt +++ b/unittests/runtime/LongTests/CMakeLists.txt @@ -42,7 +42,7 @@ if(("${SWIFT_HOST_VARIANT_SDK}" STREQUAL "${SWIFT_PRIMARY_VARIANT_SDK}") AND # The runtime tests link to internal runtime symbols, which aren't exported # from the swiftCore dylib, so we need to link to both the runtime archive # and the stdlib. - $ + $ $ $ ) diff --git a/utils/build-windows-toolchain.bat b/utils/build-windows-toolchain.bat index 2c2012786b142..131c283eddc1e 100644 --- a/utils/build-windows-toolchain.bat +++ b/utils/build-windows-toolchain.bat @@ -60,7 +60,7 @@ set TMPDIR=%BuildRoot%\tmp set NINJA_STATUS=[%%f/%%t][%%p][%%es] :: Build the -Test argument, if any, by subtracting skipped tests -set TestArg=-Test lld,swift,dispatch,foundation,xctest,swift-format,sourcekit-lsp, +set TestArg=-Test lld,lldb,swift,dispatch,foundation,xctest,swift-format,sourcekit-lsp, for %%I in (%SKIP_TESTS%) do (call set TestArg=%%TestArg:%%I,=%%) if "%TestArg:~-1%"=="," (set TestArg=%TestArg:~0,-1%) else (set TestArg= ) @@ -105,7 +105,6 @@ set "args=%args% --skip-repository swift" set "args=%args% --skip-repository ninja" set "args=%args% --skip-repository swift-integration-tests" set "args=%args% --skip-repository swift-stress-tester" -set "args=%args% --skip-repository swift-xcode-playground-support" call "%SourceRoot%\swift\utils\update-checkout.cmd" %args% --clone --skip-history --reset-to-remote --github-comment "%ghprbCommentBody%" diff --git a/utils/build.ps1 b/utils/build.ps1 index 260d8700c89c2..464b24352885c 100644 --- a/utils/build.ps1 +++ b/utils/build.ps1 @@ -423,6 +423,8 @@ enum TargetComponent { Foundation XCTest Testing + ClangBuiltins + ClangRuntime } function Get-TargetProjectBinaryCache($Arch, [TargetComponent]$Project) { @@ -725,6 +727,14 @@ function Fetch-Dependencies { DownloadAndVerify $PinnedBuild "$BinaryCache\$PinnedToolchain.exe" $PinnedSHA256 + if ($Test -contains "lldb") { + # The make tool isn't part of MSYS + $GnuWin32MakeURL = "https://downloads.sourceforge.net/project/ezwinports/make-4.4.1-without-guile-w32-bin.zip" + $GnuWin32MakeHash = "fb66a02b530f7466f6222ce53c0b602c5288e601547a034e4156a512dd895ee7" + DownloadAndVerify $GnuWin32MakeURL "$BinaryCache\GnuWin32Make-4.4.1.zip" $GnuWin32MakeHash + Extract-ZipFile GnuWin32Make-4.4.1.zip $BinaryCache GnuWin32Make-4.4.1 + } + # TODO(compnerd) stamp/validate that we need to re-extract New-Item -ItemType Directory -ErrorAction Ignore $BinaryCache\toolchains | Out-Null Extract-Toolchain "$PinnedToolchain.exe" $BinaryCache $PinnedToolchain @@ -772,6 +782,28 @@ function Fetch-Dependencies { Write-Output "Installing 'setuptools-75.1.0-py3-none-any.whl' ..." Invoke-Program -OutNull $Python '-I' -m pip install "$BinaryCache\python\setuptools-75.1.0-py3-none-any.whl" --disable-pip-version-check } + if ($Test -contains "lldb") { + # 'psutil' is required for testing LLDB + try { + Invoke-Program -OutNull $Python -c 'import psutil' *> $null + } catch { + $WheelURL = "https://files.pythonhosted.org/packages/11/91/87fa6f060e649b1e1a7b19a4f5869709fbf750b7c8c262ee776ec32f3028/psutil-6.1.0-cp37-abi3-win_amd64.whl" + $WheelHash = "a8fb3752b491d246034fa4d279ff076501588ce8cbcdbb62c32fd7a377d996be" + DownloadAndVerify $WheelURL "$BinaryCache\python\psutil-6.1.0-cp37-abi3-win_amd64.whl" $WheelHash + Write-Output "Installing 'psutil-6.1.0-cp37-abi3-win_amd64.whl' ..." + Invoke-Program -OutNull $Python '-I' -m pip install "$BinaryCache\python\psutil-6.1.0-cp37-abi3-win_amd64.whl" --disable-pip-version-check + } + # 'unittest2' is required for testing LLDB + try { + Invoke-Program -OutNull $Python -c 'import unittest2' *> $null + } catch { + $WheelURL = "https://files.pythonhosted.org/packages/72/20/7f0f433060a962200b7272b8c12ba90ef5b903e218174301d0abfd523813/unittest2-1.1.0-py2.py3-none-any.whl" + $WheelHash = "13f77d0875db6d9b435e1d4f41e74ad4cc2eb6e1d5c824996092b3430f088bb8" + DownloadAndVerify $WheelURL "$BinaryCache\python\unittest2-1.1.0-py2.py3-none-any.whl" $WheelHash + Write-Output "Installing 'unittest2-1.1.0-py2.py3-none-any.whl' ..." + Invoke-Program -OutNull $Python '-I' -m pip install "$BinaryCache\python\unittest2-1.1.0-py2.py3-none-any.whl" --disable-pip-version-check + } + } } Download-Python $HostArchName @@ -1215,6 +1247,13 @@ function Build-CMakeProject { } elseif ($UsePinnedCompilers.Contains("Swift")) { $env:Path = "$(Get-PinnedToolchainRuntime);${env:Path}" } + + if ($ToBatch) { + Write-Output "" + Write-Output "echo cmake.exe $cmakeGenerateArgs" + } else { + Write-Host "cmake.exe $cmakeGenerateArgs" + } Invoke-Program cmake.exe @cmakeGenerateArgs # Build all requested targets @@ -1471,11 +1510,50 @@ function Build-Compilers() { SWIFT_NATIVE_SWIFT_TOOLS_PATH = ""; } + if ($TestLLVM) { $Targets += @("check-llvm") } if ($TestClang) { $Targets += @("check-clang") } if ($TestLLD) { $Targets += @("check-lld") } - if ($TestLLDB) { $Targets += @("check-lldb") } - if ($TestLLVM) { $Targets += @("check-llvm") } if ($TestSwift) { $Targets += @("check-swift", "SwiftCompilerPlugin") } + if ($TestLLDB) { + $Targets += @("check-lldb") + + function Select-LitTestOverrides { + param([string] $TestStatus) + + $MatchingLines=(Get-Content $PSScriptRoot/windows-llvm-lit-test-overrides.txt | Select-String -Pattern "`^${TestStatus}.*$") + $TestNames=$MatchingLines | ForEach-Object { ($_ -replace $TestStatus,"").Trim() } + return $TestNames + } + + # Override some test results with llvm-lit. + $TestsToXFail=Select-LitTestOverrides "xfail" + $TestsToSkip=Select-LitTestOverrides "skip" + $env:LIT_XFAIL=$TestsToXFail -join ";" + $env:LIT_FILTER_OUT="($($TestsToSkip -join '|'))" + + # Transitive dependency of _lldb.pyd + $RuntimeBinaryCache = Get-TargetProjectBinaryCache $Arch Runtime + cp $RuntimeBinaryCache\bin\swiftCore.dll "$CompilersBinaryCache\lib\site-packages\lldb" + + # Runtime dependencies of repl_swift.exe + $SwiftRTSubdir = "lib\swift\windows" + Write-Host "Copying '$RuntimeBinaryCache\$SwiftRTSubdir\$($Arch.LLVMName)\swiftrt.obj' to '$CompilersBinaryCache\$SwiftRTSubdir'" + cp "$RuntimeBinaryCache\$SwiftRTSubdir\$($Arch.LLVMName)\swiftrt.obj" "$CompilersBinaryCache\$SwiftRTSubdir" + Write-Host "Copying '$RuntimeBinaryCache\bin\swiftCore.dll' to '$CompilersBinaryCache\bin'" + cp "$RuntimeBinaryCache\bin\swiftCore.dll" "$CompilersBinaryCache\bin" + + $TestingDefines += @{ + LLDB_INCLUDE_TESTS = "YES"; + # Check for required Python modules in CMake + LLDB_ENFORCE_STRICT_TEST_REQUIREMENTS = "YES"; + # No watchpoint support on windows: https://github.com/llvm/llvm-project/issues/24820 + LLDB_TEST_USER_ARGS = "--skip-category=watchpoint"; + # gtest sharding breaks llvm-lit's --xfail and LIT_XFAIL inputs: https://github.com/llvm/llvm-project/issues/102264 + LLVM_LIT_ARGS = "-v --no-gtest-sharding --show-xfail"; + # LLDB Unit tests link against this library + LLVM_UNITTEST_LINK_FLAGS = "$($Arch.SDKInstallRoot)\usr\lib\swift\windows\$($Arch.LLVMName)\swiftCore.lib"; + } + } } else { $Targets = @("distribution", "install-distribution") $TestingDefines = @{ @@ -1517,9 +1595,11 @@ function Build-Compilers() { LLDB_PYTHON_EXT_SUFFIX = ".pyd"; LLDB_PYTHON_RELATIVE_PATH = "lib/site-packages"; LLDB_TABLEGEN = (Join-Path -Path $BuildTools -ChildPath "lldb-tblgen.exe"); + LLDB_TEST_MAKE = "$BinaryCache\GnuWin32Make-4.4.1\bin\make.exe"; LLVM_CONFIG_PATH = (Join-Path -Path $BuildTools -ChildPath "llvm-config.exe"); LLVM_EXTERNAL_SWIFT_SOURCE_DIR = "$SourceCache\swift"; LLVM_NATIVE_TOOL_DIR = $BuildTools; + LLVM_HOST_TRIPLE = $BuildArch.LLVMTarget; LLVM_TABLEGEN = (Join-Path $BuildTools -ChildPath "llvm-tblgen.exe"); LLVM_USE_HOST_TOOLS = "NO"; Python3_EXECUTABLE = (Get-PythonExecutable); @@ -1612,13 +1692,61 @@ function Build-LLVM([Platform]$Platform, $Arch) { -Bin (Get-TargetProjectBinaryCache $Arch LLVM) ` -Arch $Arch ` -Platform $Platform ` - -UseMSVCCompilers C,CXX ` + -UseBuiltCompilers C,CXX ` -Defines @{ CMAKE_SYSTEM_NAME = $Platform.ToString(); LLVM_HOST_TRIPLE = $Arch.LLVMTarget; } } +function Build-Sanitizers([Platform]$Platform, $Arch) { + $LLVMTargetCache = $(Get-TargetProjectBinaryCache $Arch LLVM) + $LITVersionStr = $(Invoke-Program $(Get-PythonExecutable) "$LLVMTargetCache\bin\llvm-lit.py" --version) + if (-not ($LITVersionStr -match "lit (\d+)\.\d+\.\d+.*")) { + throw "Unexpected version string output from llvm-lit.py" + } + $LLVMVersionMajor = $Matches.1 + $InstallTo = "$($HostArch.ToolchainInstallRoot)\usr\lib\clang\$LLVMVersionMajor" + Write-Host "Sanitizers SDK directory: $InstallTo" + + Build-CMakeProject ` + -Src $SourceCache\llvm-project\compiler-rt\lib\builtins ` + -Bin "$(Get-TargetProjectBinaryCache $Arch ClangBuiltins)" ` + -InstallTo $InstallTo ` + -Arch $Arch ` + -Platform $Platform ` + -UseBuiltCompilers ASM,C,CXX ` + -BuildTargets "install-compiler-rt" ` + -Defines (@{ + CMAKE_SYSTEM_NAME = $Platform.ToString(); + LLVM_DIR = "$LLVMTargetCache\lib\cmake\llvm"; + LLVM_ENABLE_PER_TARGET_RUNTIME_DIR = "YES"; + COMPILER_RT_DEFAULT_TARGET_ONLY = "YES"; + }) + + Build-CMakeProject ` + -Src $SourceCache\llvm-project\compiler-rt ` + -Bin "$(Get-TargetProjectBinaryCache $Arch ClangRuntime)" ` + -InstallTo $InstallTo ` + -Arch $Arch ` + -Platform $Platform ` + -UseBuiltCompilers ASM,C,CXX ` + -BuildTargets "install-compiler-rt" ` + -Defines (@{ + CMAKE_SYSTEM_NAME = $Platform.ToString(); + LLVM_DIR = "$LLVMTargetCache\lib\cmake\llvm"; + LLVM_ENABLE_PER_TARGET_RUNTIME_DIR = "YES"; + COMPILER_RT_DEFAULT_TARGET_ONLY = "YES"; + COMPILER_RT_BUILD_BUILTINS = "NO"; + COMPILER_RT_BUILD_CRT = "NO"; + COMPILER_RT_BUILD_LIBFUZZER = "NO"; + COMPILER_RT_BUILD_ORC = "NO"; + COMPILER_RT_BUILD_XRAY = "NO"; + COMPILER_RT_BUILD_PROFILE = "YES"; + COMPILER_RT_BUILD_SANITIZERS = "YES"; + }) +} + function Build-ZLib([Platform]$Platform, $Arch) { $ArchName = $Arch.LLVMName @@ -2841,6 +2969,7 @@ if (-not $SkipBuild) { Invoke-BuildStep Build-FoundationMacros -Build Windows $BuildArch Invoke-BuildStep Build-TestingMacros -Build Windows $BuildArch Invoke-BuildStep Build-Foundation Windows $Arch + Invoke-BuildStep Build-Sanitizers Windows $Arch Invoke-BuildStep Build-XCTest Windows $Arch Invoke-BuildStep Build-Testing Windows $Arch Invoke-BuildStep Write-SDKSettingsPlist Windows $Arch @@ -2860,6 +2989,7 @@ if (-not $SkipBuild) { Invoke-BuildStep Build-Runtime Android $Arch Invoke-BuildStep Build-Dispatch Android $Arch Invoke-BuildStep Build-Foundation Android $Arch + Invoke-BuildStep Build-Sanitizers Android $Arch Invoke-BuildStep Build-XCTest Android $Arch Invoke-BuildStep Build-Testing Android $Arch Invoke-BuildStep Write-SDKSettingsPlist Android $Arch diff --git a/utils/build_swift/build_swift/driver_arguments.py b/utils/build_swift/build_swift/driver_arguments.py index e53dccb61bb9b..71042e53dc16f 100644 --- a/utils/build_swift/build_swift/driver_arguments.py +++ b/utils/build_swift/build_swift/driver_arguments.py @@ -1493,6 +1493,10 @@ def create_argument_parser(): default=True, help='Enable Volatile module.') + option('--enable-runtime-module', toggle_true, + default=True, + help='Enable Runtime module.') + option('--enable-experimental-parser-validation', toggle_true, default=True, help='Enable experimental Swift Parser validation by default.') diff --git a/utils/build_swift/tests/expected_options.py b/utils/build_swift/tests/expected_options.py index 5c37377c30b83..1b906115dc049 100644 --- a/utils/build_swift/tests/expected_options.py +++ b/utils/build_swift/tests/expected_options.py @@ -188,6 +188,7 @@ 'swift_enable_backtracing': True, 'enable_synchronization': True, 'enable_volatile': True, + 'enable_runtime_module': True, 'enable_lsan': False, 'enable_sanitize_coverage': False, 'disable_guaranteed_normal_arguments': False, @@ -629,6 +630,7 @@ class BuildScriptImplOption(_BaseOption): EnableOption('--enable-experimental-observation'), EnableOption('--enable-experimental-parser-validation'), EnableOption('--enable-lsan'), + EnableOption('--enable-runtime-module'), EnableOption('--enable-sanitize-coverage'), EnableOption('--enable-tsan'), EnableOption('--enable-tsan-runtime'), diff --git a/utils/swift_build_support/swift_build_support/products/swift.py b/utils/swift_build_support/swift_build_support/products/swift.py index ba36cf4edaab0..d649c8d6bf4e5 100644 --- a/utils/swift_build_support/swift_build_support/products/swift.py +++ b/utils/swift_build_support/swift_build_support/products/swift.py @@ -74,6 +74,9 @@ def __init__(self, args, toolchain, source_dir, build_dir): # Add volatile flag. self.cmake_options.extend(self._enable_volatile) + # Add runtime module flag. + self.cmake_options.extend(self._enable_runtime_module) + # Add static vprintf flag self.cmake_options.extend(self._enable_stdlib_static_vprintf) @@ -235,6 +238,11 @@ def _enable_volatile(self): return [('SWIFT_ENABLE_VOLATILE:BOOL', self.args.enable_volatile)] + @property + def _enable_runtime_module(self): + return [('SWIFT_ENABLE_RUNTIME_MODULE:BOOL', + self.args.enable_runtime_module)] + @property def _enable_stdlib_static_vprintf(self): return [('SWIFT_STDLIB_STATIC_PRINT', diff --git a/utils/swift_build_support/tests/products/test_swift.py b/utils/swift_build_support/tests/products/test_swift.py index 2d690aaa631bf..6a7ea32f2418b 100644 --- a/utils/swift_build_support/tests/products/test_swift.py +++ b/utils/swift_build_support/tests/products/test_swift.py @@ -63,6 +63,7 @@ def setUp(self): swift_enable_backtracing=False, enable_synchronization=False, enable_volatile=False, + enable_runtime_module=False, build_early_swiftsyntax=False, build_swift_stdlib_static_print=False, build_swift_stdlib_unicode_data=True, @@ -112,6 +113,7 @@ def test_by_default_no_cmake_options(self): '-DSWIFT_ENABLE_BACKTRACING:BOOL=FALSE', '-DSWIFT_ENABLE_SYNCHRONIZATION:BOOL=FALSE', '-DSWIFT_ENABLE_VOLATILE:BOOL=FALSE', + '-DSWIFT_ENABLE_RUNTIME_MODULE:BOOL=FALSE', '-DSWIFT_STDLIB_STATIC_PRINT=FALSE', '-DSWIFT_FREESTANDING_IS_DARWIN:BOOL=FALSE', '-DSWIFT_STDLIB_BUILD_PRIVATE:BOOL=TRUE', @@ -146,6 +148,7 @@ def test_swift_runtime_tsan(self): '-DSWIFT_ENABLE_BACKTRACING:BOOL=FALSE', '-DSWIFT_ENABLE_SYNCHRONIZATION:BOOL=FALSE', '-DSWIFT_ENABLE_VOLATILE:BOOL=FALSE', + '-DSWIFT_ENABLE_RUNTIME_MODULE:BOOL=FALSE', '-DSWIFT_STDLIB_STATIC_PRINT=FALSE', '-DSWIFT_FREESTANDING_IS_DARWIN:BOOL=FALSE', '-DSWIFT_STDLIB_BUILD_PRIVATE:BOOL=TRUE', @@ -470,6 +473,19 @@ def test_volatile_flags(self): [x for x in swift.cmake_options if 'DSWIFT_ENABLE_VOLATILE' in x]) + def test_runtime_module_flags(self): + self.args.enable_runtime_module = True + swift = Swift( + args=self.args, + toolchain=self.toolchain, + source_dir='/path/to/src', + build_dir='/path/to/build') + self.assertEqual( + ['-DSWIFT_ENABLE_RUNTIME_MODULE:BOOL=' + 'TRUE'], + [x for x in swift.cmake_options + if 'DSWIFT_ENABLE_RUNTIME_MODULE' in x]) + def test_freestanding_is_darwin_flags(self): self.args.swift_freestanding_is_darwin = True swift = Swift( diff --git a/utils/update_checkout/update-checkout-config.json b/utils/update_checkout/update-checkout-config.json index af4dc95386a13..b01cb5aee0854 100644 --- a/utils/update_checkout/update-checkout-config.json +++ b/utils/update_checkout/update-checkout-config.json @@ -55,7 +55,9 @@ "swift-integration-tests": { "remote": { "id": "swiftlang/swift-integration-tests" } }, "swift-xcode-playground-support": { - "remote": { "id": "apple/swift-xcode-playground-support" } }, + "remote": { "id": "apple/swift-xcode-playground-support" }, + "platforms": [ "Darwin" ] + }, "ninja": { "remote": { "id": "ninja-build/ninja" } }, "yams": { @@ -113,6 +115,10 @@ }, "zlib": { "remote": { "id": "madler/zlib" } + }, + "mimalloc": { + "remote": { "id": "microsoft/mimalloc" }, + "platforms": [ "Windows" ] } }, "default-branch-scheme": "main", @@ -167,7 +173,8 @@ "wasmkit": "0.1.2", "curl": "curl-8_9_1", "libxml2": "v2.11.5", - "zlib": "v1.3.1" + "zlib": "v1.3.1", + "mimalloc": "v3.0.1" } }, "release/6.1": { @@ -374,7 +381,8 @@ "wasmkit": "0.1.2", "curl": "curl-8_9_1", "libxml2": "v2.11.5", - "zlib": "v1.3.1" + "zlib": "v1.3.1", + "mimalloc": "v3.0.1" } }, "next" : { @@ -421,9 +429,9 @@ "wasi-libc": "wasi-sdk-24", "wasmkit": "0.1.2", "curl": "curl-8_9_1", - "icu": "maint/maint-69", "libxml2": "v2.11.5", - "zlib": "v1.3.1" + "zlib": "v1.3.1", + "mimalloc": "v3.0.1" } } } diff --git a/utils/windows-llvm-lit-test-overrides.txt b/utils/windows-llvm-lit-test-overrides.txt new file mode 100644 index 0000000000000..196195b0850b0 --- /dev/null +++ b/utils/windows-llvm-lit-test-overrides.txt @@ -0,0 +1,184 @@ +# build.ps1 overrides the status of each test in this file when LLVM tests are run with lit. +# +# Prefer `xfail` for tests that fail reliably. Use `skip` for flaky tests. +# Test summaries call them "excluded". Please find the right "Tests that ..." +# category for new entries. + +### Tests that fail reliably ### + +xfail lldb-api :: lang/cpp/unique-types4/TestUniqueTypes4.py +xfail lldb-shell :: Recognizer/verbose_trap.test +xfail lldb-shell :: Settings/TestEchoCommands.test +xfail lldb-shell :: Swift/MissingVFSOverlay.test +xfail lldb-shell :: Swift/No.swiftmodule.test +xfail lldb-shell :: Swift/ToolchainMismatch.test +xfail lldb-shell :: Swift/global.test +xfail lldb-shell :: Swift/runtime-initialization.test +xfail lldb-shell :: SwiftREPL/BreakpointSimple.test +xfail lldb-shell :: SwiftREPL/ClosureScope.test +xfail lldb-shell :: SwiftREPL/ExistentialTypes.test +xfail lldb-shell :: SwiftREPL/LookupAfterImport.test +xfail lldb-shell :: SwiftREPL/LookupWithAttributedImport.test +xfail lldb-shell :: SwiftREPL/OpenClass.test +xfail lldb-shell :: SwiftREPL/OptionalUnowned.test +xfail lldb-shell :: SwiftREPL/RedirectInputUnreadable.test +xfail lldb-shell :: SwiftREPL/SwiftInterface.test +xfail lldb-shell :: SymbolFile/DWARF/x86/dead-code-filtering.yaml + +### Tests that pass locally, but fail in CI reliably ### + +# https://github.com/swiftlang/llvm-project/issues/9539 +xfail lldb-shell :: SwiftREPL/Basic.test +xfail lldb-shell :: SwiftREPL/Class.test +xfail lldb-shell :: SwiftREPL/ComputedProperties.test +xfail lldb-shell :: SwiftREPL/Deadlock.test +xfail lldb-shell :: SwiftREPL/DiagnosticOptions.test +xfail lldb-shell :: SwiftREPL/Dict.test +xfail lldb-shell :: SwiftREPL/ErrorReturn.test +xfail lldb-shell :: SwiftREPL/ExclusivityREPL.test +xfail lldb-shell :: SwiftREPL/GenericTypealias.test +xfail lldb-shell :: SwiftREPL/Generics.test +xfail lldb-shell :: SwiftREPL/ImportError.test +xfail lldb-shell :: SwiftREPL/MetatypeRepl.test +xfail lldb-shell :: SwiftREPL/Optional.test +xfail lldb-shell :: SwiftREPL/PropertyWrapperTopLevel.test +xfail lldb-shell :: SwiftREPL/RecursiveClass.test +xfail lldb-shell :: SwiftREPL/Redefinition.test +xfail lldb-shell :: SwiftREPL/RedirectInput.test +xfail lldb-shell :: SwiftREPL/RedirectInputNoSuchFile.test +xfail lldb-shell :: SwiftREPL/Regex.test +xfail lldb-shell :: SwiftREPL/SimpleExpressions.test +xfail lldb-shell :: SwiftREPL/Struct.test +xfail lldb-shell :: SwiftREPL/Subclassing.test +xfail lldb-shell :: SwiftREPL/SwiftInterfaceForceModuleLoadMode.test +xfail lldb-shell :: SwiftREPL/SwiftTypeLookup.test +xfail lldb-shell :: SwiftREPL/SyntaxError.test +xfail lldb-shell :: SwiftREPL/UninitVariables.test +xfail lldb-shell :: SwiftREPL/ZeroSizeStruct.test +xfail lldb-shell :: SwiftREPL/enum-singlecase.test +xfail lldb-shell :: SwiftREPL/one-char-string.test + +xfail lldb-api :: commands/apropos/with-process/TestAproposWithProcess.py +xfail lldb-api :: commands/command/nested_alias/TestNestedAlias.py +xfail lldb-api :: commands/expression/entry-bp/TestExprEntryBP.py +xfail lldb-api :: commands/memory/write/TestMemoryWrite.py +xfail lldb-api :: functionalities/breakpoint/address_breakpoints/TestAddressBreakpoints.py +xfail lldb-api :: functionalities/breakpoint/auto_continue/TestBreakpointAutoContinue.py +xfail lldb-api :: functionalities/breakpoint/breakpoint_conditions/TestBreakpointConditions.py +xfail lldb-api :: functionalities/breakpoint/breakpoint_options/TestBreakpointOptions.py +xfail lldb-api :: functionalities/breakpoint/step_over_breakpoint/TestStepOverBreakpoint.py +xfail lldb-api :: functionalities/conditional_break/TestConditionalBreak.py +xfail lldb-api :: functionalities/memory/find/TestMemoryFind.py +xfail lldb-api :: lang/c/anonymous/TestAnonymous.py +xfail lldb-api :: lang/c/array_types/TestArrayTypes.py +xfail lldb-api :: lang/c/enum_types/TestEnumTypes.py +xfail lldb-api :: lang/c/forward/TestForwardDeclaration.py +xfail lldb-api :: lang/c/function_types/TestFunctionTypes.py +xfail lldb-api :: lang/c/register_variables/TestRegisterVariables.py +xfail lldb-api :: lang/c/set_values/TestSetValues.py +xfail lldb-api :: lang/c/shared_lib/TestSharedLib.py +xfail lldb-api :: lang/cpp/class_types/TestClassTypes.py +xfail lldb-api :: lang/cpp/inlines/TestInlines.py +xfail lldb-api :: python_api/compile_unit/TestCompileUnitAPI.py +xfail lldb-api :: python_api/thread/TestThreadAPI.py +xfail lldb-api :: source-manager/TestSourceManager.py +xfail lldb-shell :: Driver/TestConvenienceVariables.test + +# https://github.com/swiftlang/llvm-project/issues/9620 +xfail lldb-shell :: Swift/expression-diagnostics.test + +# https://github.com/swiftlang/llvm-project/issues/9540 +xfail lldb-shell :: SymbolFile/NativePDB/local-variables.cpp +xfail lldb-shell :: SymbolFile/NativePDB/stack_unwinding01.cpp +xfail lldb-api :: lang/c/local_variables/TestLocalVariables.py + +# https://github.com/swiftlang/llvm-project/issues/9637 +xfail lldb-api :: python_api/address_range/TestAddressRange.py + +# https://github.com/swiftlang/llvm-project/issues/9643 +xfail lldb-shell :: Commands/command-process-launch-user-entry.test + +# Skip SymbolTests because we cannot xfail unittests by name. We would need to +# specify their indexes, but these are subject to change. Right now, failures +# are: +# FAIL: lldb-unit :: Symbol/./SymbolTests.exe/24/27 (1 of 27) +# FAIL: lldb-unit :: Symbol/./SymbolTests.exe/21/27 (3 of 27) +# FAIL: lldb-unit :: Symbol/./SymbolTests.exe/22/27 (9 of 27) +# FAIL: lldb-unit :: Symbol/./SymbolTests.exe/25/27 (11 of 27) +# +# Respective tests are: +# lldb-unit :: Symbol/./SymbolTests.exe/ClangArgs/UniquingCollisionWithAddedFlags +# lldb-unit :: Symbol/./SymbolTests.exe/ClangArgs/UniquingCollisionWithExistingFlags +# lldb-unit :: Symbol/./SymbolTests.exe/TestSwiftASTContext/ApplyWorkingDir +# lldb-unit :: Symbol/./SymbolTests.exe/TestSwiftASTContext/PluginPath +# +skip lldb-unit :: Symbol/./SymbolTests.exe + +### Tests that fail occasionally ### + +# https://github.com/swiftlang/llvm-project/issues/9705 +skip lldb-api :: python_api/section/TestSectionAPI.py + +# Passes upstream in bot lldb-aarch64-windows; it fails in swiftlang +# since https://github.com/swiftlang/llvm-project/pull/9493 relanded +skip lldb-api :: functionalities/breakpoint/same_cu_name/TestFileBreakpoinsSameCUName.py + +# Disable 37 tests: 17 unsupported, 6 usually failed, 14 usually passed (but flaky) +# https://github.com/swiftlang/llvm-project/issues/9099 +# https://github.com/swiftlang/llvm-project/issues/9100 +# https://github.com/swiftlang/llvm-project/issues/9101 +skip lldb-api :: tools/lldb-server + +### Tests that time out occasionally ### + +skip lldb-api :: commands/dwim-print/TestDWIMPrint.py +skip lldb-api :: commands/thread/backtrace/TestThreadBacktraceRepeat.py +skip lldb-api :: functionalities/inferior-crashing/TestInferiorCrashing.py +skip lldb-api :: functionalities/step_scripted/TestStepScripted.py + +### Tests that pass occasionally ### + +# Fixed upstream: https://github.com/llvm/llvm-project/commit/ec009994a06338995dfb6431c943b299f9327fd2 +# But patches don't apply on stable branch due to downstream changes. +skip lldb-api :: functionalities/archives/TestBSDArchives.py +skip lldb-api :: macosx/duplicate-archive-members/TestDuplicateMembers.py + +### Tests that pass accidentally ### + +https://github.com/llvm/llvm-project/issues/116972 +skip lldb-api :: api/command-return-object/TestSBCommandReturnObject.py +skip lldb-api :: api/multiple-targets/TestMultipleTargets.py + +### Tests that fail during setup and thus show up as UNRESOLVED *** + +# https://github.com/swiftlang/llvm-project/issues/9887 +skip lldb-api :: lang/swift/async/tasks/TestSwiftTaskBacktrace.py +skip lldb-api :: lang/swift/async/tasks/TestSwiftTaskSelect.py + +skip lldb-api :: functionalities/breakpoint/breakpoint_command/TestBreakpointCommandsFromPython.py +skip lldb-api :: tools/lldb-dap/instruction-breakpoint/TestDAP_instruction_breakpoint.py +skip lldb-api :: tools/lldb-dap/output/TestDAP_output.py + +### Untriaged ### + +skip lldb-api :: commands/statistics/basic/TestStats.py +skip lldb-api :: lang/BoundsSafety/array_of_ptrs/TestArrayOfBoundsSafetyPointers.py +skip lldb-api :: lang/BoundsSafety/out_of_bounds_pointer/TestOutOfBoundsPointer.py +skip lldb-shell :: Commands/command-expr-diagnostics.test +skip lldb-unit :: Host/./HostTests.exe + +# https://github.com/llvm/llvm-project/issues/62983 +skip lldb-api :: functionalities/var_path/TestVarPath.py + +# https://github.com/swiftlang/llvm-project/issues/9073 +skip lldb-api :: lang/c/trampoline_stepping/TestTrampolineStepping.py + +# https://github.com/swiftlang/llvm-project/issues/9072 +skip lldb-api :: lang/cpp/bitfields/TestCppBitfields.py + +skip lldb-shell :: Swift/astcontext_error.test +skip lldb-shell :: Swift/cond-breakpoint.test + +skip lldb-api :: functionalities/data-formatter/data-formatter-cpp/TestDataFormatterCpp.py +skip lldb-api :: lang/cpp/frame-var-depth-and-elem-count/TestFrameVarDepthAndElemCount.py +skip lldb-api :: functionalities/inferior-crashing/recursive-inferior/TestRecursiveInferiorStep.py diff --git a/validation-test/IRGen/rdar127535274.swift b/validation-test/IRGen/rdar127535274.swift index 2b7b20edbe1f6..4239b4aa8a262 100644 --- a/validation-test/IRGen/rdar127535274.swift +++ b/validation-test/IRGen/rdar127535274.swift @@ -4,8 +4,8 @@ // REQUIRES: swift_feature_LayoutStringValueWitnessesInstantiation // CHECK: define internal ptr @"$s13rdar1275352744TestVMi" -// CHECK: [[METADATA:%.*]] = call ptr @swift_allocateGenericValueMetadataWithLayoutString -// CHECK: call void @swift_generic_instantiateLayoutString(ptr @"type_layout_string l13rdar1275352744TestVyxG", ptr [[METADATA]]) +// CHECK: [[METADATA:%.*]] = call ptr @swift_cvw_allocateGenericValueMetadataWithLayoutString +// CHECK: call void @swift_cvw_instantiateLayoutString(ptr @"type_layout_string l13rdar1275352744TestVyxG", ptr [[METADATA]]) // CHECK: ret ptr [[METADATA]] // CHECK: } public struct Test { diff --git a/validation-test/SIL/verify_all_overlays.py b/validation-test/SIL/verify_all_overlays.py index 5f9a244f7805d..c2b3441f250f5 100755 --- a/validation-test/SIL/verify_all_overlays.py +++ b/validation-test/SIL/verify_all_overlays.py @@ -39,9 +39,9 @@ if module_name == "DifferentiationUnittest": continue # Backtracing needs its own additional modules in the module path - if module_name == "_Backtracing": + if module_name == "Runtime": extra_args = ["-I", os.path.join(source_dir, "stdlib", - "public", "Backtracing", "modules"), + "public", "RuntimeModule", "modules"), "-I", os.path.join(source_dir, "include")] # _Concurrency needs its own additional modules in the module path if module_name == "_Concurrency":